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,327 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 29 July 2014
4
+
5
+ require 'citrus/common/service/filter_service'
6
+ require 'citrus/common/service/handler_service'
7
+ require 'citrus/util/path_util'
8
+
9
+ module Citrus
10
+ # Server
11
+ #
12
+ #
13
+ module Server
14
+ # Server
15
+ #
16
+ #
17
+ class Server
18
+ include CitrusLoader
19
+ include Utils::PathUtil
20
+
21
+ # Create a new server
22
+ #
23
+ # @param [Object] app
24
+ def initialize app
25
+ @app = app
26
+
27
+ @global_filter_service = nil
28
+ @filter_service = nil
29
+ @handler_service = nil
30
+
31
+ @crons = []
32
+ @jobs = {}
33
+ @state = :state_inited
34
+
35
+ @app.on(:add_crons) { |crons| add_crons crons }
36
+ @app.on(:remove_crons) { |crons| remove_crons crons }
37
+ end
38
+
39
+ # Start the server
40
+ def start
41
+ return unless @state == :state_inited
42
+
43
+ @global_filter_service = init_filter true
44
+ @filter_service = init_filter false
45
+ @handler_service = init_handler
46
+
47
+ @state = :state_started
48
+ end
49
+
50
+ # After the sever start
51
+ def after_start
52
+ end
53
+
54
+ # Stop the server
55
+ def stop
56
+ @state = :state_stoped
57
+ end
58
+
59
+ # Global handler
60
+ #
61
+ # @param [Hash] msg
62
+ # @param [Object] session
63
+ def global_handle msg, session, &block
64
+ unless @state == :state_started
65
+ block_given? and yield Exception.new 'server not started'
66
+ return
67
+ end
68
+
69
+ route_record = parse_route msg['route']
70
+ unless route_record
71
+ block_given? and yield Exception.new 'meet unknown route message'
72
+ return
73
+ end
74
+
75
+ dispatch = Proc.new { |err, resp, args|
76
+ if err
77
+ handle_error(true, err, msg, session, resp, args) { |err, resp, args|
78
+ response true, err, msg, session, resp, args, &block
79
+ }
80
+ return
81
+ end
82
+
83
+ unless @app.server_type == route_record['server_type']
84
+ do_forward(msg, session, route_record) { |err, resp, args|
85
+ response true, err, msg, session, resp, args, &block
86
+ }
87
+ else
88
+ do_handle(msg, session, route_record) { |err, resp, args|
89
+ response true, err, msg, session, resp, args, &block
90
+ }
91
+ end
92
+ }
93
+ before_filter true, msg, session, &dispatch
94
+ end
95
+
96
+ # Handle request
97
+ #
98
+ # @param [Hash] msg
99
+ # @param [Object] session
100
+ def handle msg, session, &block
101
+ unless @state == :state_started
102
+ block_given? and yield Exception.new 'server not started'
103
+ return
104
+ end
105
+
106
+ route_record = parse_route msg['route']
107
+ do_handle msg, session, route_record, &block
108
+ end
109
+
110
+ # Add crons at runtime
111
+ #
112
+ # @param [Array] crons
113
+ def add_crons crons
114
+ end
115
+
116
+ # Remove crons at runtime
117
+ #
118
+ # @param [Array] crons
119
+ def remove_crons crons
120
+ end
121
+
122
+ private
123
+
124
+ # Init filter service
125
+ #
126
+ # @param [Boolean] is_global
127
+ #
128
+ # @private
129
+ def init_filter is_global
130
+ service = Common::Service::FilterService.new
131
+
132
+ if is_global
133
+ befores = @app.global_befores
134
+ afters = @app.global_afters
135
+ else
136
+ befores = @app.befores
137
+ afters = @app.afters
138
+ end
139
+
140
+ befores.each { |before| service.before before }
141
+ afters.each { |after| service.after after }
142
+
143
+ service
144
+ end
145
+
146
+ # Init handler service
147
+ #
148
+ # @private
149
+ def init_handler
150
+ Common::Service::HandlerService.new @app, load_handlers
151
+ end
152
+
153
+ # Load handlers from current application
154
+ #
155
+ # @private
156
+ def load_handlers
157
+ handlers = {}
158
+ path = get_handler_path @app.base, @app.server_type
159
+ if path
160
+ klasses = load_app_handler path
161
+ klasses.each { |klass|
162
+ handler = klass.name
163
+ handler[0] = handler[0].downcase
164
+ handlers[handler] = klass.new @app
165
+ }
166
+ end
167
+ handlers
168
+ end
169
+
170
+ # Fire before filter chain if any
171
+ #
172
+ # @param [Boolean] is_global
173
+ # @param [Hash] msg
174
+ # @param [Object] session
175
+ #
176
+ # @private
177
+ def before_filter is_global, msg, session, &block
178
+ if is_global
179
+ fm = @global_filter_service
180
+ else
181
+ fm = @filter_service
182
+ end
183
+ if fm
184
+ fm.before_filter msg, session, &block
185
+ else
186
+ block_given? and yield
187
+ end
188
+ end
189
+
190
+ # Fire after filter chain if any
191
+ #
192
+ # @param [Boolean] is_global
193
+ # @param [Object] err
194
+ # @param [Hash] msg
195
+ # @param [Object] session
196
+ # @param [Hash] resp
197
+ # @param [Hash] args
198
+ #
199
+ # @private
200
+ def after_filter is_global, err, msg, session, resp, args, &block
201
+ if is_global
202
+ fm = @global_filter_service
203
+ else
204
+ fm = @filter_service
205
+ end
206
+ if fm
207
+ if is_global
208
+ fm.after_filter(err, msg, session, resp) {}
209
+ else
210
+ fm.after_filter(err, msg, session, resp) {
211
+ block_given? and yield err, resp, args
212
+ }
213
+ end
214
+ end
215
+ end
216
+
217
+ # Pass err to the global error handler if specified
218
+ #
219
+ # @param [Boolean] is_global
220
+ # @param [Object] err
221
+ # @param [Hash] msg
222
+ # @param [Object] session
223
+ # @param [Hash] resp
224
+ # @param [Hash] args
225
+ #
226
+ # @private
227
+ def handle_error is_global, err, msg, session, resp, args, &block
228
+ if is_global
229
+ handler = :global_error_handler
230
+ else
231
+ handler = :err_handler
232
+ end
233
+ unless @app.respond_to? handler
234
+ block_given? and yield err, resp, args
235
+ else
236
+ @app.send handler err, msg, resp, session, args, &block
237
+ end
238
+ end
239
+
240
+ # Send response to the client and fire after filter chain if any
241
+ #
242
+ # @param [Boolean] is_global
243
+ # @param [Object] err
244
+ # @param [Hash] msg
245
+ # @param [Object] session
246
+ # @param [Hash] resp
247
+ # @param [Hash] args
248
+ #
249
+ # @private
250
+ def response is_global, err, msg, session, resp, args, &block
251
+ if is_global
252
+ block_given? and yield err, resp, args
253
+ # after filter should not interfere response
254
+ after_filter is_global, err, msg, session, resp, args, &block
255
+ else
256
+ after_filter is_global, err, msg, session, resp, args, &block
257
+ end
258
+ end
259
+
260
+ # Parse route string
261
+ #
262
+ # @param [String] route
263
+ #
264
+ # @private
265
+ def parse_route route
266
+ return nil unless route
267
+ return nil unless (ts = route.split '.').length == 3
268
+ {
269
+ 'route' => route,
270
+ 'server_type' => ts[0],
271
+ 'handler' => ts[1],
272
+ 'method' => ts[2]
273
+ }
274
+ end
275
+
276
+ # Forward message
277
+ #
278
+ # @param [Hash] msg
279
+ # @param [Object] session
280
+ # @param [Hash] route_record
281
+ #
282
+ # @private
283
+ def do_forward msg, session, route_record, &block
284
+ finished = false
285
+ begin
286
+ @app.sysrpc[route_record['server_type']].msgRemote.forwardMessage(
287
+ session, msg, session.export
288
+ ) { |err, resp, args|
289
+ finished = true
290
+ block_given? and yield err, resp, args
291
+ }
292
+ rescue => err
293
+ block_given? and yield err unless finished
294
+ end
295
+ end
296
+
297
+ # Handle message
298
+ #
299
+ # @param [Hash] msg
300
+ # @param [Object] session
301
+ # @param [Hash] route_record
302
+ #
303
+ # @private
304
+ def do_handle msg, session, route_record, &block
305
+ handle = Proc.new { |err, resp, args|
306
+ if err
307
+ handle_error(false, err, msg, session, resp, args) { |err, resp, args|
308
+ response false, err, msg, session, resp, args, &block
309
+ }
310
+ return
311
+ end
312
+
313
+ @handler_service.handle(route_record, msg, session) { |err, resp, args|
314
+ if err
315
+ handle_error(false, err, msg, session, resp, args) { |err, resp, args|
316
+ response false, err, msg, session, resp, args, &block
317
+ }
318
+ return
319
+ end
320
+ response false, err, msg, session, resp, args, &block
321
+ }
322
+ }
323
+ before_filter false, msg, session, &handle
324
+ end
325
+ end
326
+ end
327
+ end
@@ -0,0 +1,203 @@
1
+ # Author:: MinixLi (gmail: MinixLi1986)
2
+ # Homepage:: http://citrus.inspawn.com
3
+ # Date:: 16 July 2014
4
+
5
+ require 'citrus/util/constants'
6
+
7
+ module Citrus
8
+ # Utils
9
+ #
10
+ #
11
+ module Utils
12
+ # AppUtil
13
+ #
14
+ #
15
+ module AppUtil
16
+ # Initialize application configuration
17
+ def default_configuration
18
+ args = parse_args
19
+ setup_env args
20
+ load_master
21
+ load_servers
22
+ process_args args
23
+ config_logger
24
+ load_lifecycle
25
+ end
26
+
27
+ # Parse command line arguments
28
+ def parse_args
29
+ args_map = {:main => $0}
30
+ ARGV.each { |arg|
31
+ sep = arg.index('=')
32
+
33
+ key = arg[0..sep-1].to_sym
34
+ val = arg[sep+1..-1]
35
+
36
+ if val == 'true'
37
+ val = true
38
+ end
39
+ if val == 'false'
40
+ val = false
41
+ end
42
+ args_map[key] = val
43
+ }
44
+ return args_map
45
+ end
46
+
47
+ # Setup enviroment
48
+ #
49
+ # @param [Hash] args
50
+ def setup_env args={}
51
+ @env = args[:env] ? args[:env].to_sym : :development
52
+ end
53
+
54
+ # Load master info from config/master.json
55
+ def load_master
56
+ @master = load_config_file Constants::Filepath::MASTER
57
+ end
58
+
59
+ # Load server info from config/servers.json
60
+ def load_servers
61
+ servers = load_config_file Constants::Filepath::SERVER
62
+ servers.each { |server_type, servers|
63
+ servers.each { |server|
64
+ server[:server_type] = server_type.to_s
65
+ @servers_map[server[:server_id]] = server
66
+ }
67
+ }
68
+ end
69
+
70
+ # Process server start command
71
+ #
72
+ # @param [Hash] args
73
+ def process_args args={}
74
+ @type = args[:type] ? args[:type].to_sym : :all
75
+ @server_type = args[:server_type] ? args[:server_type] : 'master'
76
+ @server_id = args[:server_id] || @master[:server_id]
77
+ @start_id = args[:start_id]
78
+
79
+ if @server_type == 'master'
80
+ @cur_server = @master
81
+ else
82
+ @cur_server = args
83
+ end
84
+ end
85
+
86
+ # Configure logger
87
+ def config_logger
88
+ end
89
+
90
+ # Load life cycle
91
+ def load_lifecycle
92
+ end
93
+
94
+ # Load config file
95
+ #
96
+ # @param [String] filename
97
+ def load_config_file filename
98
+ origin_path = File.join @base, filename
99
+ present_path = File.join @base, Constants::Filepath::CONFIG_DIR, @env.to_s, File.basename(filename)
100
+ unless File.exists?(origin_path) && file_path = origin_path
101
+ unless File.exists? present_path && file_path = present_path
102
+ end
103
+ end
104
+ config = {}
105
+ instance_eval %Q{
106
+ config = #{File.read file_path}
107
+ }
108
+ if file_path == origin_path && config[@env]
109
+ config = config[@env]
110
+ end
111
+ return config
112
+ end
113
+
114
+ # Load default components for application
115
+ def load_default_components
116
+ if @server_type == 'master'
117
+ load Components::Master
118
+ else
119
+ load Components::Proxy
120
+ load Components::Remote if @cur_server[:port]
121
+ load Components::Connection if frontend?
122
+ load Components::Connector if frontend?
123
+ load Components::Session if frontend?
124
+ load Components::PushScheduler if frontend?
125
+ load Components::BackendSession
126
+ load Components::Channel
127
+ load Components::Server
128
+ end
129
+ load Components::Monitor
130
+ end
131
+
132
+ # Load component
133
+ #
134
+ # @param [Class] component
135
+ def load component
136
+ name = component.name
137
+ instance_eval %Q{
138
+ @components[name] = #{component}.new self, @settings[:#{name}_config] || {}
139
+ }
140
+ end
141
+
142
+ # Stop components
143
+ #
144
+ # @param [Array] components
145
+ # @param [Integer] index
146
+ # @param [Boolean] force
147
+ def stop_components components, index, force, &block
148
+ end
149
+
150
+ # Apply command to loaded components
151
+ #
152
+ # @param [Array] components
153
+ # @param [Symbol] method
154
+ def opt_components components, method, &block
155
+ opt_component nil, components, method, 0, &block
156
+ end
157
+
158
+ # Apply command to loaded component
159
+ #
160
+ # @param [Object] err
161
+ # @param [Array] components
162
+ # @param [Symbol] method
163
+ # @param [Integer] index
164
+ def opt_component err, components, method, index, &block
165
+ if err || index >= components.length
166
+ block_given? and yield err
167
+ return
168
+ end
169
+ component = components[index]
170
+ if component && component.respond_to?(method)
171
+ component.send method, &proc{ |err|
172
+ opt_component err, components, method, (index + 1), &block
173
+ }
174
+ else
175
+ opt_component err, components, method, (index + 1), &block
176
+ end
177
+ end
178
+
179
+ # Register console module
180
+ #
181
+ # @param [Class] module_klass
182
+ # @param [Hash] args
183
+ def register module_klass, args={}
184
+ module_id = module_klass.module_id
185
+ @modules_registered[module_id] = {
186
+ :module_id => module_id,
187
+ :module_klass => module_klass,
188
+ :args => args
189
+ }
190
+ end
191
+
192
+ # Check whether a string is contained in the settings
193
+ #
194
+ # @param [String] str
195
+ # @param [String] settings
196
+ def contains str, settings
197
+ return false unless settings.instance_of? String
198
+ return false if settings.empty?
199
+ settings.split('|').inject(false) { |r, t| true if str == t }
200
+ end
201
+ end
202
+ end
203
+ end