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,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
|
+
|