pomelo-citrus 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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