pomelo-citrus 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +20 -0
  3. data/Rakefile +0 -0
  4. data/citrus.gemspec +35 -0
  5. data/lib/citrus.rb +18 -0
  6. data/lib/citrus/application.rb +237 -0
  7. data/lib/citrus/citrus.rb +27 -0
  8. data/lib/citrus/common/remote/backend/msg_remote.rb +57 -0
  9. data/lib/citrus/common/remote/frontend/channel_remote.rb +73 -0
  10. data/lib/citrus/common/remote/frontend/session_remote.rb +108 -0
  11. data/lib/citrus/common/service/backend_session_service.rb +265 -0
  12. data/lib/citrus/common/service/channel_service.rb +485 -0
  13. data/lib/citrus/common/service/connection_service.rb +71 -0
  14. data/lib/citrus/common/service/filter_service.rb +92 -0
  15. data/lib/citrus/common/service/handler_service.rb +63 -0
  16. data/lib/citrus/common/service/session_service.rb +446 -0
  17. data/lib/citrus/components/backend_session.rb +32 -0
  18. data/lib/citrus/components/channel.rb +33 -0
  19. data/lib/citrus/components/component.rb +19 -0
  20. data/lib/citrus/components/connection.rb +48 -0
  21. data/lib/citrus/components/connector.rb +265 -0
  22. data/lib/citrus/components/master.rb +40 -0
  23. data/lib/citrus/components/monitor.rb +48 -0
  24. data/lib/citrus/components/proxy.rb +195 -0
  25. data/lib/citrus/components/push_scheduler.rb +74 -0
  26. data/lib/citrus/components/remote.rb +71 -0
  27. data/lib/citrus/components/server.rb +61 -0
  28. data/lib/citrus/components/session.rb +41 -0
  29. data/lib/citrus/connectors/commands/handshake.rb +22 -0
  30. data/lib/citrus/connectors/commands/heartbeat.rb +22 -0
  31. data/lib/citrus/connectors/commands/kick.rb +22 -0
  32. data/lib/citrus/connectors/common/coder.rb +21 -0
  33. data/lib/citrus/connectors/common/handler.rb +21 -0
  34. data/lib/citrus/connectors/ws_connector.rb +110 -0
  35. data/lib/citrus/connectors/ws_socket.rb +75 -0
  36. data/lib/citrus/filters/handler/handler_filter.rb +19 -0
  37. data/lib/citrus/filters/handler/too_busy.rb +16 -0
  38. data/lib/citrus/filters/rpc/rpc_filter.rb +19 -0
  39. data/lib/citrus/filters/rpc/too_busy.rb +16 -0
  40. data/lib/citrus/master/master.rb +60 -0
  41. data/lib/citrus/master/starter.rb +73 -0
  42. data/lib/citrus/master/watchdog.rb +83 -0
  43. data/lib/citrus/modules/console.rb +45 -0
  44. data/lib/citrus/modules/console_module.rb +35 -0
  45. data/lib/citrus/modules/master_watcher.rb +88 -0
  46. data/lib/citrus/modules/monitor_watcher.rb +86 -0
  47. data/lib/citrus/monitor/monitor.rb +61 -0
  48. data/lib/citrus/push_schedulers/buffer.rb +16 -0
  49. data/lib/citrus/push_schedulers/direct.rb +76 -0
  50. data/lib/citrus/server/server.rb +327 -0
  51. data/lib/citrus/util/app_util.rb +203 -0
  52. data/lib/citrus/util/constants.rb +19 -0
  53. data/lib/citrus/util/countdown_latch.rb +42 -0
  54. data/lib/citrus/util/events.rb +14 -0
  55. data/lib/citrus/util/module_util.rb +68 -0
  56. data/lib/citrus/util/path_util.rb +50 -0
  57. data/lib/citrus/util/utils.rb +49 -0
  58. data/lib/citrus/version.rb +7 -0
  59. metadata +241 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fc960252d9f68592e4bc7a8152333a82d3fa84c2
4
+ data.tar.gz: 4801ee7597600f2dc7bcab9497503521f0bc99e5
5
+ SHA512:
6
+ metadata.gz: 833b2b49945dd1623c678ccc0bae9428b36acccb4d6ce4ca031ad142fe02dff5934c0bb0efc31a39bfff4752417241fb1b37c911183e6924d673c13f9cf64c9b
7
+ data.tar.gz: 770c1e3795f3d5b8dcac4ceb6a412366a0216c99df0eab6dcb24983d77bbbdad335c18723430fc45ed9186ab3d48c090ee6c1b0f0197d649ee71fed4a32cfba9
@@ -0,0 +1,20 @@
1
+ ## Welcome to pomelo-citrus
2
+
3
+ pomelo-citrus is a simple clone of pomelo written in Ruby using EventMachine.
4
+
5
+ ## Motivation
6
+
7
+ Since NodeJS is influenced by Ruby EventMachine and Python's Twisted model, Ruby should also be able to have its own game server framework like pomelo.
8
+
9
+ Ruby is a very expressive and eloquent programming language. I was an RoR programmer before and I really like Ruby, When developing this project, I have used many skills like meta-programming and they give me the real pleasures.
10
+
11
+ Recently, I would focus on my daily work, so I open source this project and hope to have more people participate in this project.
12
+
13
+ ## Todo
14
+
15
+ This gem is under development now, remaining about 30% of the workload to do including the tests.
16
+
17
+ ## Links
18
+
19
+ * [EventMachine](https://github.com/eventmachine/eventmachine)
20
+ * [pomelo](https://github.com/NetEase/pomelo)
File without changes
@@ -0,0 +1,35 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 16 July 2014
4
+
5
+ $:.push File.expand_path('../lib', __FILE__)
6
+ require 'citrus/version'
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = 'pomelo-citrus'
10
+ spec.version = Citrus::VERSION
11
+ spec.platform = Gem::Platform::RUBY
12
+ spec.authors = ['MinixLi']
13
+ spec.email = 'MinixLi1986@gmail.com'
14
+ spec.description = %q{pomelo-citrus is a simple clone of pomelo, it provides a fast, scalable and distributed game server framework for Ruby}
15
+ spec.summary = %q{pomelo clone written in Ruby using EventMachine}
16
+ spec.homepage = 'https://github.com/minixli/pomelo-citrus'
17
+ spec.license = 'MIT'
18
+
19
+ spec.files = `git ls-files`.split($/)
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_dependency('digest-crc', '~> 0')
25
+ spec.add_dependency('eventmachine', '~> 0')
26
+ spec.add_dependency('websocket-eventmachine-server', '~> 0')
27
+
28
+ spec.add_dependency('pomelo-citrus-admin', '~> 0')
29
+ spec.add_dependency('pomelo-citrus-loader', '~> 0')
30
+ spec.add_dependency('pomelo-citrus-logger', '~> 0')
31
+ spec.add_dependency('pomelo-citrus-protobuf', '~> 0')
32
+ spec.add_dependency('pomelo-citrus-protocol', '~> 0')
33
+ spec.add_dependency('pomelo-citrus-rpc', '~> 0')
34
+ spec.add_dependency('pomelo-citrus-scheduler', '~> 0')
35
+ end
@@ -0,0 +1,18 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 16 July 2014
4
+
5
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
6
+
7
+ require 'eventmachine'
8
+
9
+ require 'pomelo-citrus-admin'
10
+ require 'pomelo-citrus-loader'
11
+ require 'pomelo-citrus-protobuf'
12
+ require 'pomelo-citrus-protocol'
13
+ require 'pomelo-citrus-rpc'
14
+ require 'pomelo-citrus-scheduler'
15
+
16
+ require 'citrus/util/constants'
17
+ require 'citrus/util/utils'
18
+ require 'citrus/citrus'
@@ -0,0 +1,237 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 16 July 2014
4
+
5
+ require 'citrus/util/app_util'
6
+
7
+ module Citrus
8
+ # Application
9
+ #
10
+ #
11
+ class Application
12
+ include Utils::AppUtil
13
+ include Utils::EventEmitter
14
+
15
+ attr_reader :env, :base, :type, :start_id
16
+ attr_reader :cur_server, :server_id, :server_type
17
+ attr_reader :master, :servers_map
18
+ attr_reader :components, :modules_registered
19
+
20
+ # Initialize the application
21
+ #
22
+ # @param [Hash] args Option
23
+ def initialize args={}
24
+ @env = nil
25
+ @type = nil
26
+ @start_id = nil
27
+
28
+ @base = args[:base] || Dir.pwd
29
+ @settings = {}
30
+
31
+ # current server info
32
+ @cur_server = nil
33
+ @server_id = nil
34
+ @server_type = nil
35
+ @start_time = nil
36
+
37
+ # global server info
38
+ @master = nil
39
+ @servers = {}
40
+ @servers_map = {}
41
+ @server_types = []
42
+ @server_type_maps = {}
43
+
44
+ # lifecycle callbacks
45
+ @lifecycle_cbs = {}
46
+
47
+ @components = {}
48
+ @modules_registered = {}
49
+
50
+ default_configuration
51
+
52
+ @state = :state_inited
53
+
54
+ # singleton pattern
55
+ eval %Q{
56
+ class ::Citrus::Application
57
+ private_class_method :new
58
+ end
59
+ }
60
+ end
61
+
62
+ # Start the application
63
+ def start &block
64
+ @start_time = Time.now.to_f
65
+ if @state != :state_inited
66
+ block_given? and yield Exception.new 'application double start'
67
+ return
68
+ end
69
+
70
+ if @start_id
71
+ if @start_id != 'master'
72
+ Starter.run_servers self
73
+ return
74
+ end
75
+ else
76
+ if @type && @type != :all && @type != :master
77
+ Starter.run_servers self
78
+ return
79
+ end
80
+ end
81
+
82
+ load_default_components
83
+
84
+ if before_cb = @lifecycle_cbs[:before_startup]
85
+ before_cb.call self, &proc{
86
+ start_up &block
87
+ }
88
+ else
89
+ start_up &block
90
+ end
91
+ end
92
+
93
+ # Start up
94
+ def start_up &block
95
+ opt_components(@components.values, :start) { |err|
96
+ @state = :state_started
97
+ if err
98
+ block_given? and yield err
99
+ else
100
+ after_start &block
101
+ end
102
+ }
103
+ end
104
+
105
+ # Lifecycle callback for after start
106
+ def after_start &block
107
+ if @state != :state_started
108
+ block_given? and yield RuntimeError.new 'application is not running now'
109
+ return
110
+ end
111
+
112
+ opt_components(@components.values, :after_start) { |err|
113
+ if after_cb = @lifecycle_cbs[:after_start]
114
+ after_cb.call self, &proc{
115
+ block_given? and yield err
116
+ }
117
+ else
118
+ block_given? and yield err
119
+ end
120
+ }
121
+ puts used_time = Time.now.to_f - @start_time
122
+ end
123
+
124
+ # Stop components
125
+ #
126
+ #
127
+ def stop force=false
128
+ end
129
+
130
+ # Assign `setting` to `value`
131
+ #
132
+ # @param [Symbol] setting
133
+ # @param [Object] value
134
+ def set setting, value
135
+ @settings[setting] = value
136
+ return self
137
+ end
138
+
139
+ # Get property from setting
140
+ #
141
+ # @param [Symbol] setting
142
+ def get setting
143
+ @settings[setting]
144
+ end
145
+
146
+ # Configure callback for the specified env and server type
147
+ def configure *args, &block
148
+ args.length > 0 ? env = args[0].to_s : env = 'all'
149
+ args.length > 1 ? server_type = args[1].to_s : server_type = 'all'
150
+ if env == 'all' || contains(@env.to_s, env)
151
+ if server_type == 'all' || contains(@server_type, server_type)
152
+ instance_eval &block if block
153
+ end
154
+ end
155
+ return self
156
+ end
157
+
158
+ # Get server infos by server type
159
+ #
160
+ # @param [String] type
161
+ def get_servers_by_type type
162
+ @server_type_maps[type]
163
+ end
164
+
165
+ # Check whether a server is a frontend
166
+ #
167
+ # @param [Object] server
168
+ def frontend? server=nil
169
+ server ? server[:frontend] == true : @cur_server[:frontend] == true
170
+ end
171
+
172
+ # Check whether a server is a backend
173
+ #
174
+ # @param [Object] server
175
+ def backend? server=nil
176
+ not frontend? server
177
+ end
178
+
179
+ # Check whether a server is a master
180
+ def master?
181
+ @server_type == 'master'
182
+ end
183
+
184
+ # Add new servers at runtime
185
+ #
186
+ # @param [Array] sinfos
187
+ def add_servers sinfos
188
+ return unless sinfos && !sinfos.empty?
189
+ sinfos.each { |sinfo|
190
+ # update global server map
191
+ @servers[sinfo[:server_id]] = sinfo
192
+
193
+ # update global server type map
194
+ slist = @server_type_maps[sinfo[:server_type]] ||= []
195
+ replace_server slist, sinfo
196
+
197
+ # update global server type list
198
+ if !@server_types.member? sinfo[:server_type]
199
+ @server_types << sinfo[:server_type]
200
+ end
201
+ }
202
+ emit 'add_servers', sinfos
203
+ end
204
+
205
+ # Remove servers at runtime
206
+ #
207
+ # @param [Array] server_ids
208
+ def remove_servers server_ids
209
+ end
210
+
211
+ # Replace servers at runtime
212
+ #
213
+ # @param [Array] sinfos
214
+ def replace_servers sinfos
215
+ end
216
+
217
+ # Remove server at runtime
218
+ #
219
+ # @param [String] server_id
220
+ def remove_server server_id
221
+ end
222
+
223
+ # Replace server at runtime
224
+ #
225
+ # @param [Array] slist
226
+ # @param [Hash] server_info
227
+ def replace_server slist, sinfo
228
+ slist.each_with_index { |s, index|
229
+ if s[:server_id] == sinfo[:server_id]
230
+ slist[index] = sinfo
231
+ return
232
+ end
233
+ }
234
+ slist << sinfo
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,27 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 16 July 2014
4
+
5
+ require 'citrus/application'
6
+ require 'citrus/util/events'
7
+
8
+ module Citrus
9
+ # Create a citrus application
10
+ #
11
+ # @param [Hash] args
12
+ def self.create_app args={}
13
+ app = Application.new args
14
+
15
+ Object.class_eval {
16
+ def app
17
+ return app
18
+ end
19
+ }
20
+ return app
21
+ end
22
+
23
+ # Load all the components
24
+ Dir.glob(File.expand_path('../../citrus/components/*.rb', __FILE__)).each { |filepath|
25
+ require filepath
26
+ }
27
+ end
@@ -0,0 +1,57 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 24 July 2014
4
+
5
+ module Citrus
6
+ # Common
7
+ #
8
+ #
9
+ module Common
10
+ # Remote
11
+ #
12
+ #
13
+ module Remote
14
+ # Backend
15
+ #
16
+ #
17
+ module Backend
18
+ # MsgRemote
19
+ #
20
+ #
21
+ class MsgRemote
22
+ # Create a new remote message service
23
+ #
24
+ # @param [Object] app
25
+ def initialize app
26
+ @app = app
27
+ end
28
+
29
+ # Forward message from frontend server
30
+ #
31
+ # @param [Hash] msg
32
+ # @param [Object] session
33
+ def forwardMessage msg, session, &block
34
+ server = @app.components['server']
35
+ session_service = @app.components['backend_session'].service
36
+
37
+ unless server
38
+ block_given? and yield Exception.new 'server component not enabled'
39
+ return
40
+ end
41
+
42
+ unless session_service
43
+ block_given? and yield Exception.new 'backend session component not enabled'
44
+ return
45
+ end
46
+
47
+ backend_session = session_service.create session
48
+
49
+ server.handle(msg, backend_session) { |err, resp, args|
50
+ block_given? and yield err, resp, args
51
+ }
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,73 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 24 July 2014
4
+
5
+ module Citrus
6
+ # Common
7
+ #
8
+ #
9
+ module Common
10
+ # Remote
11
+ #
12
+ #
13
+ module Remote
14
+ # Frontend
15
+ #
16
+ #
17
+ module Frontend
18
+ # ChannelRemote
19
+ #
20
+ #
21
+ class ChannelRemote
22
+ # Create a new remote channel service
23
+ #
24
+ # @param [Object] app
25
+ def initialize app
26
+ @app = app
27
+ end
28
+
29
+ # Push message to client by uids
30
+ #
31
+ # @param [String] route
32
+ # @param [Hash] msg
33
+ # @param [Array] uids
34
+ # @param [Hash] args
35
+ def pushMessage route, msg, uids, args, &block
36
+ if msg.empty?
37
+ block_given? and yield Exception.new 'can not send empty message'
38
+ return
39
+ end
40
+
41
+ connector = @app.components['connector']
42
+
43
+ session_service = @app.session_service
44
+ sids = []; fails = []
45
+ uids.each { |uid|
46
+ sessions = session_service.get_by_uid uid
47
+ if sessions
48
+ sessions.each { |session|
49
+ sids << session.id
50
+ }
51
+ else
52
+ fails << uid
53
+ end
54
+ }
55
+ connector.send(nil, route, msg, sids, args) { |err|
56
+ block_given? and yield err, fails
57
+ }
58
+ end
59
+
60
+ # Broadcast to all the clients connected with current frontend server
61
+ #
62
+ # @param [String] route
63
+ # @param [Hash] msg
64
+ # @param [Hash] args
65
+ def broadcast route, msg, args, &block
66
+ connector = @app.components['connector']
67
+ connector.send nil, route, msg, nil, args, &block
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end