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.
- checksums.yaml +7 -0
- data/README.md +20 -0
- data/Rakefile +0 -0
- data/citrus.gemspec +35 -0
- data/lib/citrus.rb +18 -0
- data/lib/citrus/application.rb +237 -0
- data/lib/citrus/citrus.rb +27 -0
- data/lib/citrus/common/remote/backend/msg_remote.rb +57 -0
- data/lib/citrus/common/remote/frontend/channel_remote.rb +73 -0
- data/lib/citrus/common/remote/frontend/session_remote.rb +108 -0
- data/lib/citrus/common/service/backend_session_service.rb +265 -0
- data/lib/citrus/common/service/channel_service.rb +485 -0
- data/lib/citrus/common/service/connection_service.rb +71 -0
- data/lib/citrus/common/service/filter_service.rb +92 -0
- data/lib/citrus/common/service/handler_service.rb +63 -0
- data/lib/citrus/common/service/session_service.rb +446 -0
- data/lib/citrus/components/backend_session.rb +32 -0
- data/lib/citrus/components/channel.rb +33 -0
- data/lib/citrus/components/component.rb +19 -0
- data/lib/citrus/components/connection.rb +48 -0
- data/lib/citrus/components/connector.rb +265 -0
- data/lib/citrus/components/master.rb +40 -0
- data/lib/citrus/components/monitor.rb +48 -0
- data/lib/citrus/components/proxy.rb +195 -0
- data/lib/citrus/components/push_scheduler.rb +74 -0
- data/lib/citrus/components/remote.rb +71 -0
- data/lib/citrus/components/server.rb +61 -0
- data/lib/citrus/components/session.rb +41 -0
- data/lib/citrus/connectors/commands/handshake.rb +22 -0
- data/lib/citrus/connectors/commands/heartbeat.rb +22 -0
- data/lib/citrus/connectors/commands/kick.rb +22 -0
- data/lib/citrus/connectors/common/coder.rb +21 -0
- data/lib/citrus/connectors/common/handler.rb +21 -0
- data/lib/citrus/connectors/ws_connector.rb +110 -0
- data/lib/citrus/connectors/ws_socket.rb +75 -0
- data/lib/citrus/filters/handler/handler_filter.rb +19 -0
- data/lib/citrus/filters/handler/too_busy.rb +16 -0
- data/lib/citrus/filters/rpc/rpc_filter.rb +19 -0
- data/lib/citrus/filters/rpc/too_busy.rb +16 -0
- data/lib/citrus/master/master.rb +60 -0
- data/lib/citrus/master/starter.rb +73 -0
- data/lib/citrus/master/watchdog.rb +83 -0
- data/lib/citrus/modules/console.rb +45 -0
- data/lib/citrus/modules/console_module.rb +35 -0
- data/lib/citrus/modules/master_watcher.rb +88 -0
- data/lib/citrus/modules/monitor_watcher.rb +86 -0
- data/lib/citrus/monitor/monitor.rb +61 -0
- data/lib/citrus/push_schedulers/buffer.rb +16 -0
- data/lib/citrus/push_schedulers/direct.rb +76 -0
- data/lib/citrus/server/server.rb +327 -0
- data/lib/citrus/util/app_util.rb +203 -0
- data/lib/citrus/util/constants.rb +19 -0
- data/lib/citrus/util/countdown_latch.rb +42 -0
- data/lib/citrus/util/events.rb +14 -0
- data/lib/citrus/util/module_util.rb +68 -0
- data/lib/citrus/util/path_util.rb +50 -0
- data/lib/citrus/util/utils.rb +49 -0
- data/lib/citrus/version.rb +7 -0
- 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
|