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