pomelo-citrus 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,32 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 17 July 2014
|
4
|
+
|
5
|
+
require 'citrus/common/service/backend_session_service'
|
6
|
+
require 'citrus/components/component'
|
7
|
+
|
8
|
+
module Citrus
|
9
|
+
# Components
|
10
|
+
#
|
11
|
+
#
|
12
|
+
module Components
|
13
|
+
# BackendSession
|
14
|
+
#
|
15
|
+
#
|
16
|
+
class BackendSession < Component
|
17
|
+
@name = 'backend_session'
|
18
|
+
|
19
|
+
attr_reader :service
|
20
|
+
|
21
|
+
# Initialize the component
|
22
|
+
#
|
23
|
+
# @param [Object] app
|
24
|
+
def initialize app
|
25
|
+
@service = Common::Service::BackendSessionService.new app
|
26
|
+
|
27
|
+
this = self
|
28
|
+
@app.define_singleton_method :backend_session_service, proc{ this.service }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 17 July 2014
|
4
|
+
|
5
|
+
require 'citrus/common/service/channel_service'
|
6
|
+
require 'citrus/components/component'
|
7
|
+
|
8
|
+
module Citrus
|
9
|
+
# Components
|
10
|
+
#
|
11
|
+
#
|
12
|
+
module Components
|
13
|
+
# Channel
|
14
|
+
#
|
15
|
+
#
|
16
|
+
class Channel < Component
|
17
|
+
@name = 'channel'
|
18
|
+
|
19
|
+
attr_reader :service
|
20
|
+
|
21
|
+
# Initialize the component
|
22
|
+
#
|
23
|
+
# @param [Object] app
|
24
|
+
# @param [Hash] args
|
25
|
+
def initialize app, args={}
|
26
|
+
@service = Common::Service::ChannelService.new app, args
|
27
|
+
|
28
|
+
this = self
|
29
|
+
@app.define_singleton_method :channel_service, proc{ this.service }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 21 July 2014
|
4
|
+
|
5
|
+
module Citrus
|
6
|
+
# Components
|
7
|
+
#
|
8
|
+
#
|
9
|
+
module Components
|
10
|
+
# Component
|
11
|
+
#
|
12
|
+
#
|
13
|
+
class Component
|
14
|
+
class << self
|
15
|
+
attr_reader :name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 17 July 2014
|
4
|
+
|
5
|
+
require 'citrus/common/service/connection_service'
|
6
|
+
require 'citrus/components/component'
|
7
|
+
|
8
|
+
module Citrus
|
9
|
+
# Components
|
10
|
+
#
|
11
|
+
#
|
12
|
+
module Components
|
13
|
+
# Connection
|
14
|
+
#
|
15
|
+
#
|
16
|
+
class Connection < Component
|
17
|
+
@name = 'connection'
|
18
|
+
|
19
|
+
DELEGATED_METHODS = [
|
20
|
+
:add_logined_user,
|
21
|
+
:increase_conn_count,
|
22
|
+
:remove_logined_user,
|
23
|
+
:decrease_conn_count,
|
24
|
+
:get_statistics_info
|
25
|
+
]
|
26
|
+
|
27
|
+
# Initialize the component
|
28
|
+
#
|
29
|
+
# @param [Object] app
|
30
|
+
# @param [Hash] args
|
31
|
+
def initialize app, args={}
|
32
|
+
@app = app
|
33
|
+
@service = Common::Service::ConnectionService.new app
|
34
|
+
end
|
35
|
+
|
36
|
+
# Proxy for connection service
|
37
|
+
#
|
38
|
+
# @param [String] name
|
39
|
+
def method_missing name, *args
|
40
|
+
if DELEGATED_METHODS.include? name
|
41
|
+
@service.send name, *args
|
42
|
+
else
|
43
|
+
super
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,265 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 17 July 2014
|
4
|
+
|
5
|
+
require 'citrus/components/component'
|
6
|
+
|
7
|
+
module Citrus
|
8
|
+
# Components
|
9
|
+
#
|
10
|
+
#
|
11
|
+
module Components
|
12
|
+
# Connector
|
13
|
+
#
|
14
|
+
#
|
15
|
+
class Connector < Component
|
16
|
+
@name = 'connector'
|
17
|
+
|
18
|
+
# Initialize the component
|
19
|
+
#
|
20
|
+
# @param [Object] app
|
21
|
+
# @param [Hash] args
|
22
|
+
def initialize app, args={}
|
23
|
+
@app = app
|
24
|
+
@connector = get_connector args
|
25
|
+
|
26
|
+
@encode = args[:encode]
|
27
|
+
@decode = args[:decode]
|
28
|
+
|
29
|
+
@blacklist_cb = args[:black_list_cb]
|
30
|
+
@black_lists = []
|
31
|
+
|
32
|
+
@server = nil
|
33
|
+
@session = nil
|
34
|
+
@connection = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
# Start the component
|
38
|
+
def start &block
|
39
|
+
@server = @app.components['server']
|
40
|
+
@session = @app.components['session']
|
41
|
+
@connection = @app.components['connection']
|
42
|
+
|
43
|
+
unless @server
|
44
|
+
EM.next_tick {
|
45
|
+
block_given? and yield Exception.new 'failed to start connector component for server component not loaded'
|
46
|
+
}
|
47
|
+
return
|
48
|
+
end
|
49
|
+
|
50
|
+
unless @session
|
51
|
+
EM.next_tick {
|
52
|
+
block_given? and yield Exception.new 'failed to start connector component for session component not loaded'
|
53
|
+
}
|
54
|
+
return
|
55
|
+
end
|
56
|
+
|
57
|
+
EM.next_tick { block_given? and yield }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Component lifecycle callback
|
61
|
+
def after_start &block
|
62
|
+
@connector.start &block
|
63
|
+
@connector.on(:connection) { |socket| host_filter socket }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Stop the component
|
67
|
+
def stop force=false, &block
|
68
|
+
if @connector
|
69
|
+
@connector.stop force, &block
|
70
|
+
@connector = nil
|
71
|
+
end
|
72
|
+
EM.next_tick { block_given? and yield }
|
73
|
+
end
|
74
|
+
|
75
|
+
# Send message to the client
|
76
|
+
#
|
77
|
+
# @param [Integer] req_id
|
78
|
+
# @param [String] route
|
79
|
+
# @param [Hash] msg
|
80
|
+
# @param [Array] recvs
|
81
|
+
# @param [Hash] args
|
82
|
+
def send req_id, route, msg, recvs, args, &block
|
83
|
+
if @encode
|
84
|
+
# use customized encode
|
85
|
+
msg = @encode.call self, req_id, route, msg
|
86
|
+
elsif @connector.respond_to? :encode
|
87
|
+
# use connector default encode
|
88
|
+
msg = @connector.encode req_id, route, msg
|
89
|
+
end
|
90
|
+
|
91
|
+
if msg.empty?
|
92
|
+
EM.next_tick {
|
93
|
+
block_given? and yield Exception.new 'failed to send message for encode result is empty'
|
94
|
+
}
|
95
|
+
return
|
96
|
+
end
|
97
|
+
|
98
|
+
@app.components['push_scheduler'].schedule req_id, route, msg, recvs, args, &block
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# Get the connector
|
104
|
+
#
|
105
|
+
# @param [Hash] args
|
106
|
+
#
|
107
|
+
# @private
|
108
|
+
def get_connector args={}
|
109
|
+
unless connector = args[:connector]
|
110
|
+
return get_default_connector args
|
111
|
+
end
|
112
|
+
|
113
|
+
port = @app.cur_server[:client_port]
|
114
|
+
host = @app.cur_server[:host]
|
115
|
+
|
116
|
+
connector.new port, host, args
|
117
|
+
end
|
118
|
+
|
119
|
+
# Get the default connector
|
120
|
+
#
|
121
|
+
# @param [Hash] args
|
122
|
+
#
|
123
|
+
# @private
|
124
|
+
def get_default_connector args={}
|
125
|
+
require 'citrus/connectors/ws_connector'
|
126
|
+
|
127
|
+
port = @app.cur_server[:client_port]
|
128
|
+
host = @app.cur_server[:host]
|
129
|
+
|
130
|
+
Connectors::WsConnector.new port, host, args
|
131
|
+
end
|
132
|
+
|
133
|
+
# Host filter
|
134
|
+
#
|
135
|
+
# @param [Object] socket
|
136
|
+
#
|
137
|
+
# @private
|
138
|
+
def host_filter socket
|
139
|
+
bind_events socket
|
140
|
+
end
|
141
|
+
|
142
|
+
# Bind events
|
143
|
+
#
|
144
|
+
# @param [Object] socket
|
145
|
+
#
|
146
|
+
# @private
|
147
|
+
def bind_events socket
|
148
|
+
if @connection
|
149
|
+
@connection.increase_conn_count
|
150
|
+
|
151
|
+
conn_count = @connection.get_statistics_info[:conn_count]
|
152
|
+
max_conns = @app.cur_server[:max_conns]
|
153
|
+
|
154
|
+
socket.disconnect; return if conn_count > max_conns
|
155
|
+
end
|
156
|
+
|
157
|
+
# Create session for connection
|
158
|
+
session = get_session socket
|
159
|
+
closed = false
|
160
|
+
|
161
|
+
socket.on(:disconnect) {
|
162
|
+
return if closed
|
163
|
+
closed = true
|
164
|
+
if @connection
|
165
|
+
@connection.decrease_conn_count session.uid
|
166
|
+
end
|
167
|
+
}
|
168
|
+
|
169
|
+
socket.on(:error) {
|
170
|
+
return if closed
|
171
|
+
closed = true
|
172
|
+
if @connection
|
173
|
+
@connection.decrease_conn_count session.uid
|
174
|
+
end
|
175
|
+
}
|
176
|
+
|
177
|
+
socket.on(:message) { |msg|
|
178
|
+
if @decode
|
179
|
+
msg = @decode.call msg
|
180
|
+
elsif @connector.decode
|
181
|
+
msg = @connector.decode msg
|
182
|
+
end
|
183
|
+
# discard invalid message
|
184
|
+
return unless msg
|
185
|
+
|
186
|
+
handle_message session, msg
|
187
|
+
}
|
188
|
+
end
|
189
|
+
|
190
|
+
# Get session
|
191
|
+
#
|
192
|
+
# @param [Object] socket
|
193
|
+
#
|
194
|
+
# @private
|
195
|
+
def get_session socket
|
196
|
+
sid = socket.id
|
197
|
+
session = @session.get sid
|
198
|
+
return session if session
|
199
|
+
|
200
|
+
session = @session.create sid, @app.server_id, socket
|
201
|
+
|
202
|
+
socket.on(:disconnect) { session.closed }
|
203
|
+
socket.on(:error) { session.closed }
|
204
|
+
|
205
|
+
session.on(:closed) { |session, reason|
|
206
|
+
@app.emit :close_session, reason
|
207
|
+
}
|
208
|
+
|
209
|
+
session.on(:bind) { |uid|
|
210
|
+
if @connection
|
211
|
+
@connection.add_logined_user(uid, {
|
212
|
+
:login_time => Time.now.to_f,
|
213
|
+
:uid => uid,
|
214
|
+
:address => socket.remote_address[:ip] + ':' + socket.remote_address[:port]
|
215
|
+
})
|
216
|
+
end
|
217
|
+
|
218
|
+
@app.emit :bind_session, session
|
219
|
+
}
|
220
|
+
|
221
|
+
session.on(:unbind) { |uid|
|
222
|
+
@app.emit :unbind_session, session
|
223
|
+
}
|
224
|
+
|
225
|
+
session
|
226
|
+
end
|
227
|
+
|
228
|
+
# Handle message
|
229
|
+
#
|
230
|
+
# @param [Object] session
|
231
|
+
# @param [Hash] msg
|
232
|
+
#
|
233
|
+
# @private
|
234
|
+
def handle_message session, msg
|
235
|
+
type = check_server_type msg['route']
|
236
|
+
unless type
|
237
|
+
return
|
238
|
+
end
|
239
|
+
|
240
|
+
@server.global_handle(msg, session.to_frontend_session) { |err, resp, args|
|
241
|
+
unless msg['id']
|
242
|
+
return
|
243
|
+
end
|
244
|
+
|
245
|
+
resp = {} unless resp
|
246
|
+
resp['code'] = 500 if err
|
247
|
+
|
248
|
+
args = { :type => 'response', :user_args => args || {} }
|
249
|
+
send(msg['id'], msg['route'], resp, session.id, args) {}
|
250
|
+
}
|
251
|
+
end
|
252
|
+
|
253
|
+
# Get server type from the request message
|
254
|
+
#
|
255
|
+
# @param [String] route
|
256
|
+
#
|
257
|
+
# @private
|
258
|
+
def check_server_type route
|
259
|
+
return nil unless route
|
260
|
+
return nil unless (idx = route.index '.')
|
261
|
+
route[0..idx-1]
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 17 July 2014
|
4
|
+
|
5
|
+
require 'citrus/components/component'
|
6
|
+
require 'citrus/master/master'
|
7
|
+
|
8
|
+
module Citrus
|
9
|
+
# Components
|
10
|
+
#
|
11
|
+
#
|
12
|
+
module Components
|
13
|
+
# Master
|
14
|
+
#
|
15
|
+
#
|
16
|
+
class Master < Component
|
17
|
+
@name = 'master'
|
18
|
+
|
19
|
+
# Initialize the component
|
20
|
+
#
|
21
|
+
# @param [Object] app
|
22
|
+
# @param [Hash] args
|
23
|
+
def initialize app, args={}
|
24
|
+
@master = Citrus::Master::Master.new app, args
|
25
|
+
end
|
26
|
+
|
27
|
+
# Start the component
|
28
|
+
def start &block
|
29
|
+
@master.start &block
|
30
|
+
end
|
31
|
+
|
32
|
+
# Stop the component
|
33
|
+
#
|
34
|
+
# @param [Boolean] force
|
35
|
+
def stop force=false, &block
|
36
|
+
@master.stop &block
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# Author:: MinixLi (gmail: MinixLi1986)
|
2
|
+
# Homepage:: http://citrus.inspawn.com
|
3
|
+
# Date:: 17 July 2014
|
4
|
+
|
5
|
+
require 'citrus/components/component'
|
6
|
+
require 'citrus/monitor/monitor'
|
7
|
+
|
8
|
+
module Citrus
|
9
|
+
# Components
|
10
|
+
#
|
11
|
+
#
|
12
|
+
module Components
|
13
|
+
# Monitor
|
14
|
+
#
|
15
|
+
#
|
16
|
+
class Monitor < Component
|
17
|
+
@name = 'monitor'
|
18
|
+
|
19
|
+
# Initialize the component
|
20
|
+
#
|
21
|
+
# @param [Object] app
|
22
|
+
# @param [Hash] args
|
23
|
+
def initialize app, args={}
|
24
|
+
@monitor = Citrus::Monitor::Monitor.new app, args
|
25
|
+
end
|
26
|
+
|
27
|
+
# Start the component
|
28
|
+
def start &block
|
29
|
+
@monitor.start &block
|
30
|
+
end
|
31
|
+
|
32
|
+
# Stop the component
|
33
|
+
#
|
34
|
+
# @param [Boolean] force
|
35
|
+
def stop force=false, &block
|
36
|
+
@monitor.stop &block
|
37
|
+
end
|
38
|
+
|
39
|
+
# Reconnect the master
|
40
|
+
#
|
41
|
+
# @param [Hash] master_info
|
42
|
+
def reconnect master_info
|
43
|
+
@monitor.reconnect master_info
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|