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