celluloid_pubsub 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.reek +11 -0
- data/.rubocop.yml +4 -0
- data/Rakefile +3 -23
- data/celluloid_pubsub.gemspec +1 -5
- data/examples/redis_test.rb +1 -1
- data/examples/shared_classes.rb +14 -33
- data/examples/simple_test.rb +1 -1
- data/lib/celluloid_pubsub/client.rb +59 -49
- data/lib/celluloid_pubsub/helper.rb +64 -0
- data/lib/celluloid_pubsub/reactor.rb +60 -49
- data/lib/celluloid_pubsub/redis/redis.rb +38 -0
- data/lib/celluloid_pubsub/redis/redis_reactor.rb +97 -0
- data/lib/celluloid_pubsub/version.rb +1 -1
- data/lib/celluloid_pubsub/web_server.rb +78 -57
- data/spec/lib/celluloid_pubsub/client_pubsub_spec.rb +6 -6
- data/spec/lib/celluloid_pubsub/reactor_spec.rb +2 -0
- data/spec/spec_helper.rb +0 -8
- metadata +10 -88
- data/lib/celluloid_pubsub/redis.rb +0 -25
- data/lib/celluloid_pubsub/redis_reactor.rb +0 -78
@@ -1,6 +1,6 @@
|
|
1
1
|
require_relative './registry'
|
2
|
+
require_relative './helper'
|
2
3
|
module CelluloidPubsub
|
3
|
-
# rubocop:disable ClassLength
|
4
4
|
# The reactor handles new connections. Based on what the client sends it either subscribes to a channel
|
5
5
|
# or will publish to a channel or just dispatch to the server if command is neither subscribe, publish or unsubscribe
|
6
6
|
#
|
@@ -16,6 +16,7 @@ module CelluloidPubsub
|
|
16
16
|
include Celluloid
|
17
17
|
include Celluloid::IO
|
18
18
|
include Celluloid::Logger
|
19
|
+
include CelluloidPubsub::Helper
|
19
20
|
|
20
21
|
attr_accessor :websocket, :server, :channels
|
21
22
|
finalizer :shutdown
|
@@ -31,10 +32,14 @@ module CelluloidPubsub
|
|
31
32
|
@server = server
|
32
33
|
@channels = []
|
33
34
|
@websocket = websocket
|
34
|
-
|
35
|
+
log_debug "#{self.class} Streaming changes for #{websocket.url}"
|
35
36
|
async.run
|
36
37
|
end
|
37
38
|
|
39
|
+
def debug_enabled?
|
40
|
+
@server.debug_enabled?
|
41
|
+
end
|
42
|
+
|
38
43
|
# reads from the socket the message
|
39
44
|
# and dispatches it to the handle_websocket_message method
|
40
45
|
# @see #handle_websocket_message
|
@@ -45,8 +50,10 @@ module CelluloidPubsub
|
|
45
50
|
#
|
46
51
|
# :nocov:
|
47
52
|
def run
|
48
|
-
|
49
|
-
|
53
|
+
loop do
|
54
|
+
break if !Actor.current.alive? || @websocket.closed? || !@server.alive?
|
55
|
+
message = try_read_websocket
|
56
|
+
handle_websocket_message(message) if message.present?
|
50
57
|
end
|
51
58
|
end
|
52
59
|
|
@@ -59,13 +66,13 @@ module CelluloidPubsub
|
|
59
66
|
#
|
60
67
|
# :nocov:
|
61
68
|
def try_read_websocket
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
+
@websocket.closed? ? nil : @websocket.read
|
70
|
+
rescue Reel::SocketError
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def reactor_class
|
75
|
+
self.class
|
69
76
|
end
|
70
77
|
|
71
78
|
# :nocov:
|
@@ -78,16 +85,10 @@ module CelluloidPubsub
|
|
78
85
|
#
|
79
86
|
# @api public
|
80
87
|
def parse_json_data(message)
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
rescue => e
|
86
|
-
debug "#{self.class} could not parse #{message} because of #{e.inspect}" if @server.debug_enabled?
|
87
|
-
# do nothing
|
88
|
-
end
|
89
|
-
json_data = message if json_data.nil?
|
90
|
-
json_data
|
88
|
+
JSON.parse(message)
|
89
|
+
rescue => exception
|
90
|
+
log_debug "#{reactor_class} could not parse #{message} because of #{exception.inspect}"
|
91
|
+
message
|
91
92
|
end
|
92
93
|
|
93
94
|
# method that handles the message received from the websocket connection
|
@@ -104,6 +105,7 @@ module CelluloidPubsub
|
|
104
105
|
#
|
105
106
|
# @api public
|
106
107
|
def handle_websocket_message(message)
|
108
|
+
log_debug "#{reactor_class} read message #{message}"
|
107
109
|
json_data = parse_json_data(message)
|
108
110
|
handle_parsed_websocket_message(json_data)
|
109
111
|
end
|
@@ -124,7 +126,7 @@ module CelluloidPubsub
|
|
124
126
|
def handle_parsed_websocket_message(json_data)
|
125
127
|
if json_data.is_a?(Hash)
|
126
128
|
json_data = json_data.stringify_keys
|
127
|
-
|
129
|
+
log_debug "#{self.class} finds actions for #{json_data}"
|
128
130
|
delegate_action(json_data) if json_data['client_action'].present?
|
129
131
|
else
|
130
132
|
handle_unknown_action(json_data)
|
@@ -153,17 +155,18 @@ module CelluloidPubsub
|
|
153
155
|
#
|
154
156
|
# @api public
|
155
157
|
def delegate_action(json_data)
|
158
|
+
channel = json_data.fetch('channel', nil)
|
156
159
|
case json_data['client_action']
|
157
160
|
when 'unsubscribe_all'
|
158
161
|
unsubscribe_all
|
159
162
|
when 'unsubscribe_clients'
|
160
|
-
async.unsubscribe_clients(
|
163
|
+
async.unsubscribe_clients(channel)
|
161
164
|
when 'unsubscribe'
|
162
|
-
async.unsubscribe(
|
165
|
+
async.unsubscribe(channel)
|
163
166
|
when 'subscribe'
|
164
|
-
async.start_subscriber(
|
167
|
+
async.start_subscriber(channel, json_data)
|
165
168
|
when 'publish'
|
166
|
-
@server.publish_event(
|
169
|
+
@server.publish_event(channel, json_data['data'].to_json)
|
167
170
|
else
|
168
171
|
handle_unknown_action(json_data)
|
169
172
|
end
|
@@ -178,10 +181,17 @@ module CelluloidPubsub
|
|
178
181
|
#
|
179
182
|
# @api public
|
180
183
|
def handle_unknown_action(json_data)
|
181
|
-
|
184
|
+
log_debug "Trying to dispatch to server #{json_data}"
|
182
185
|
@server.async.handle_dispatched_message(Actor.current, json_data)
|
183
186
|
end
|
184
187
|
|
188
|
+
def forget_channel
|
189
|
+
if @channels.blank?
|
190
|
+
@websocket.close
|
191
|
+
else
|
192
|
+
@channels.delete(channel)
|
193
|
+
end
|
194
|
+
end
|
185
195
|
# the method will unsubscribe a client by closing the websocket connection if has unscribed from all channels
|
186
196
|
# and deleting the reactor from the channel list on the server
|
187
197
|
#
|
@@ -191,13 +201,12 @@ module CelluloidPubsub
|
|
191
201
|
#
|
192
202
|
# @api public
|
193
203
|
def unsubscribe(channel)
|
194
|
-
|
204
|
+
log_debug "#{self.class} runs 'unsubscribe' method with #{channel}"
|
195
205
|
return unless channel.present?
|
196
|
-
|
197
|
-
@
|
198
|
-
@server.subscribers[channel].delete_if do |hash|
|
206
|
+
forget_channel
|
207
|
+
(@server.subscribers[channel] || []).delete_if do |hash|
|
199
208
|
hash[:reactor] == Actor.current
|
200
|
-
end
|
209
|
+
end
|
201
210
|
end
|
202
211
|
|
203
212
|
# the method will unsubscribe all clients subscribed to a channel by closing the
|
@@ -208,8 +217,8 @@ module CelluloidPubsub
|
|
208
217
|
#
|
209
218
|
# @api public
|
210
219
|
def unsubscribe_clients(channel)
|
211
|
-
|
212
|
-
return if channel.blank?
|
220
|
+
log_debug "#{self.class} runs 'unsubscribe_clients' method with #{channel}"
|
221
|
+
return if channel.blank?
|
213
222
|
unsubscribe_from_channel(channel)
|
214
223
|
@server.subscribers[channel] = []
|
215
224
|
end
|
@@ -222,6 +231,7 @@ module CelluloidPubsub
|
|
222
231
|
# @api public
|
223
232
|
def shutdown
|
224
233
|
debug "#{self.class} tries to 'shudown'"
|
234
|
+
@websocket.close if @websocket.present? && !@websocket.closed?
|
225
235
|
terminate
|
226
236
|
end
|
227
237
|
|
@@ -239,10 +249,14 @@ module CelluloidPubsub
|
|
239
249
|
def start_subscriber(channel, message)
|
240
250
|
return unless channel.present?
|
241
251
|
add_subscriber_to_channel(channel, message)
|
242
|
-
|
252
|
+
log_debug "#{self.class} subscribed to #{channel} with #{message}"
|
243
253
|
@websocket << message.merge('client_action' => 'successful_subscription', 'channel' => channel).to_json unless @server.redis_enabled?
|
244
254
|
end
|
245
255
|
|
256
|
+
def channel_subscribers(channel)
|
257
|
+
@server.subscribers[channel] || []
|
258
|
+
end
|
259
|
+
|
246
260
|
# adds the curent actor the list of the subscribers for a particular channel
|
247
261
|
# and registers the new channel
|
248
262
|
#
|
@@ -253,11 +267,10 @@ module CelluloidPubsub
|
|
253
267
|
#
|
254
268
|
# @api public
|
255
269
|
def add_subscriber_to_channel(channel, message)
|
270
|
+
registry_channels = CelluloidPubsub::Registry.channels
|
256
271
|
@channels << channel
|
257
|
-
|
258
|
-
@server.subscribers[channel]
|
259
|
-
@server.subscribers[channel] << { reactor: Actor.current, message: message }
|
260
|
-
|
272
|
+
registry_channels << channel unless registry_channels.include?(channel)
|
273
|
+
@server.subscribers[channel] = channel_subscribers(channel).push(reactor: Actor.current, message: message)
|
261
274
|
end
|
262
275
|
|
263
276
|
# unsubscribes all actors from all channels and terminates the curent actor
|
@@ -266,13 +279,11 @@ module CelluloidPubsub
|
|
266
279
|
#
|
267
280
|
# @api public
|
268
281
|
def unsubscribe_all
|
269
|
-
|
282
|
+
log_debug "#{self.class} runs 'unsubscribe_all' method"
|
270
283
|
CelluloidPubsub::Registry.channels.map do |channel|
|
271
|
-
|
272
|
-
@server.subscribers[channel] = []
|
284
|
+
unsubscribe_clients(channel)
|
273
285
|
end
|
274
|
-
|
275
|
-
info 'clearing connections' if @server.debug_enabled?
|
286
|
+
log_debug 'clearing connections'
|
276
287
|
shutdown
|
277
288
|
end
|
278
289
|
|
@@ -283,11 +294,11 @@ module CelluloidPubsub
|
|
283
294
|
#
|
284
295
|
# @api public
|
285
296
|
def unsubscribe_from_channel(channel)
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
Celluloid::Actor.kill(
|
297
|
+
log_debug "#{self.class} runs 'unsubscribe_from_channel' method with #{channel}"
|
298
|
+
(@server.subscribers[channel] || []).each do |hash|
|
299
|
+
reactor = hash[:reactor]
|
300
|
+
reactor.websocket.close
|
301
|
+
Celluloid::Actor.kill(reactor)
|
291
302
|
end
|
292
303
|
end
|
293
304
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
module CelluloidPubsub
|
3
|
+
# class that handles redis connection
|
4
|
+
class Redis
|
5
|
+
class << self
|
6
|
+
include Celluloid::Logger
|
7
|
+
include CelluloidPubsub::Helper
|
8
|
+
|
9
|
+
@connected ||= false
|
10
|
+
attr_accessor :connected, :connection
|
11
|
+
|
12
|
+
alias_method :connected?, :connected
|
13
|
+
|
14
|
+
def connect(&block)
|
15
|
+
require 'eventmachine'
|
16
|
+
require 'em-hiredis'
|
17
|
+
run_the_eventmachine(&block)
|
18
|
+
setup_em_exception_handler
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def run_the_eventmachine(&block)
|
24
|
+
EM.run do
|
25
|
+
@connection = EM::Hiredis.connect
|
26
|
+
@connected = true
|
27
|
+
block.call @connection
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_em_exception_handler
|
32
|
+
EM.error_handler do |error|
|
33
|
+
debug error unless filtered_error?(error)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require_relative '../reactor'
|
2
|
+
module CelluloidPubsub
|
3
|
+
# reactor used for redis pubsub
|
4
|
+
class RedisReactor < CelluloidPubsub::Reactor
|
5
|
+
include Celluloid
|
6
|
+
include Celluloid::IO
|
7
|
+
include Celluloid::Logger
|
8
|
+
|
9
|
+
def unsubscribe(channel)
|
10
|
+
super
|
11
|
+
async.redis_action('unsubscribe', channel)
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_subscriber_to_channel(channel, message)
|
15
|
+
super
|
16
|
+
async.redis_action('subscribe', channel, message)
|
17
|
+
end
|
18
|
+
|
19
|
+
def unsubscribe_from_channel(channel)
|
20
|
+
super
|
21
|
+
async.redis_action('unsubscribe', channel)
|
22
|
+
end
|
23
|
+
|
24
|
+
def unsubscribe_all
|
25
|
+
CelluloidPubsub::Registry.channels.map do |channel|
|
26
|
+
async.redis_action('unsubscribe', channel)
|
27
|
+
end
|
28
|
+
info 'clearing connections'
|
29
|
+
shutdown
|
30
|
+
end
|
31
|
+
|
32
|
+
def shutdown
|
33
|
+
@channels.each do |channel|
|
34
|
+
redis_action('unsubscribe', channel)
|
35
|
+
end if @channels.present?
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def fetch_pubsub
|
42
|
+
CelluloidPubsub::Redis.connect do |connection|
|
43
|
+
yield connection.pubsub
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def action_subscribe?(action)
|
48
|
+
action == 'subscribe'
|
49
|
+
end
|
50
|
+
|
51
|
+
def action_success(action, channel, message)
|
52
|
+
action_subscribe?(action) ? message.merge('client_action' => 'successful_subscription', 'channel' => channel) : nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def redis_action(action, channel = nil, message = {})
|
56
|
+
fetch_pubsub do |pubsub|
|
57
|
+
callback = prepare_redis_action(action)
|
58
|
+
success_message = action_success(action, channel, message)
|
59
|
+
subscription = pubsub.send(action, channel, callback)
|
60
|
+
handle_redis_action(subscription, action, success_message)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
def prepare_redis_action(action)
|
66
|
+
log_unsubscriptions(pubsub)
|
67
|
+
proc do |subscribed_message|
|
68
|
+
action_subscribe?(action) ? (@websocket << subscribed_message) : log_debug(message)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def log_unsubscriptions(pubsub)
|
73
|
+
pubsub.on(:unsubscribe) do |subscribed_channel, remaining_subscriptions|
|
74
|
+
log_debug [:unsubscribe_happened, subscribed_channel, remaining_subscriptions].inspect
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def handle_redis_action(subscription, action, sucess_message = nil)
|
79
|
+
register_redis_callback(subscription, sucess_message)
|
80
|
+
register_redis_error_callback(subscription, action)
|
81
|
+
end
|
82
|
+
|
83
|
+
def register_redis_callback(subscription, sucess_message = nil)
|
84
|
+
subscription.callback do |subscriptions_ids|
|
85
|
+
if sucess_message.present?
|
86
|
+
@websocket << sucess_message.merge('subscriptions' => subscriptions_ids).to_json
|
87
|
+
else
|
88
|
+
log_debug "#{action} success #{success_response.inspect}"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def register_redis_error_callback(subscription, action)
|
94
|
+
subscription.errback { |reply| log_debug "#{action} error #{reply.inspect}" }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative './reactor'
|
2
|
+
require_relative './helper'
|
2
3
|
module CelluloidPubsub
|
3
4
|
# webserver to which socket connects should connect to .
|
4
5
|
# the server will dispatch each request into a new Reactor
|
@@ -30,6 +31,7 @@ module CelluloidPubsub
|
|
30
31
|
# @return [Boolean] Enable this only if you want to enable debugging for the webserver
|
31
32
|
class WebServer < Reel::Server::HTTP
|
32
33
|
include Celluloid::Logger
|
34
|
+
include CelluloidPubsub::Helper
|
33
35
|
|
34
36
|
# The hostname on which the webserver runs on by default
|
35
37
|
HOST = '0.0.0.0'
|
@@ -54,11 +56,21 @@ module CelluloidPubsub
|
|
54
56
|
#
|
55
57
|
# :nocov:
|
56
58
|
def initialize(options = {})
|
57
|
-
|
58
|
-
parse_options(options)
|
59
|
+
Celluloid.boot unless Celluloid.running?
|
60
|
+
@options = parse_options(options)
|
59
61
|
@subscribers = {}
|
60
|
-
|
61
|
-
|
62
|
+
setup_celluloid_logger
|
63
|
+
log_debug "CelluloidPubsub::WebServer example starting on #{hostname}:#{port}"
|
64
|
+
super(hostname, port, { spy: spy, backlog: backlog }, &method(:on_connection))
|
65
|
+
end
|
66
|
+
|
67
|
+
def use_redis
|
68
|
+
@use_redis ||= @options.fetch('use_redis', false)
|
69
|
+
end
|
70
|
+
|
71
|
+
def debug_enabled?
|
72
|
+
@debug_enabled = @options.fetch('enable_debug', false)
|
73
|
+
@debug_enabled == true
|
62
74
|
end
|
63
75
|
|
64
76
|
# the method will terminate the current actor
|
@@ -72,44 +84,34 @@ module CelluloidPubsub
|
|
72
84
|
terminate
|
73
85
|
end
|
74
86
|
|
75
|
-
|
87
|
+
def log_file_path
|
88
|
+
@log_file_path ||= @options.fetch('log_file_path', nil)
|
89
|
+
end
|
76
90
|
|
77
|
-
|
78
|
-
|
79
|
-
# @param [Hash] options the options that can be used to connect to webser and send additional data
|
80
|
-
# @option options [String]:hostname The hostname on which the webserver runs on
|
81
|
-
# @option options [Integer] :port The port on which the webserver runs on
|
82
|
-
# @option options [String] :path The request path that the webserver accepts
|
83
|
-
# @option options [Boolean] :spy Enable this only if you want to enable debugging for the webserver
|
84
|
-
# @option options [Integer]:backlog How many connections the server accepts
|
85
|
-
#
|
86
|
-
# @return [void]
|
87
|
-
#
|
88
|
-
# @api public
|
89
|
-
def parse_options(options)
|
90
|
-
options = options.is_a?(Hash) ? options : {}
|
91
|
-
@options = options.stringify_keys
|
92
|
-
debug @options if debug_enabled?
|
93
|
-
@backlog = @options.fetch('backlog', 1024)
|
94
|
-
@hostname = @options.fetch('hostname', CelluloidPubsub::WebServer::HOST)
|
95
|
-
@port = @options.fetch('port', CelluloidPubsub::WebServer::PORT)
|
96
|
-
@path = @options.fetch('path', CelluloidPubsub::WebServer::PATH)
|
97
|
-
@spy = @options.fetch('spy', false)
|
98
|
-
@use_redis = @options.fetch('use_redis', false)
|
99
|
-
@debug_enabled = @options.fetch('enable_debug', false)
|
91
|
+
def hostname
|
92
|
+
@hostname ||= @options.fetch('hostname', CelluloidPubsub::WebServer::HOST)
|
100
93
|
end
|
101
94
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
95
|
+
def port
|
96
|
+
@port ||= @options.fetch('port', CelluloidPubsub::WebServer::PORT)
|
97
|
+
end
|
98
|
+
|
99
|
+
def path
|
100
|
+
@path ||= @options.fetch('path', CelluloidPubsub::WebServer::PATH)
|
101
|
+
end
|
102
|
+
|
103
|
+
def spy
|
104
|
+
@spy ||= @options.fetch('spy', false)
|
105
|
+
end
|
106
|
+
|
107
|
+
def backlog
|
108
|
+
@backlog = @options.fetch('backlog', 1024)
|
109
109
|
end
|
110
110
|
|
111
|
+
# :nocov:
|
112
|
+
|
111
113
|
def redis_enabled?
|
112
|
-
|
114
|
+
use_redis.to_s.downcase == 'true'
|
113
115
|
end
|
114
116
|
|
115
117
|
# method for publishing data to a channel
|
@@ -121,16 +123,27 @@ module CelluloidPubsub
|
|
121
123
|
#
|
122
124
|
# @api public
|
123
125
|
def publish_event(current_topic, message)
|
124
|
-
return if current_topic.blank? || message.blank?
|
125
126
|
if redis_enabled?
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
127
|
+
publish_redis_event(current_topic, message)
|
128
|
+
else
|
129
|
+
publish_clasic_event(current_topic, message)
|
130
|
+
end
|
131
|
+
rescue => exception
|
132
|
+
log_debug("could not publish message #{message} into topic #{current_topic} because of #{exception.inspect}")
|
133
|
+
end
|
134
|
+
|
135
|
+
def publish_redis_event(topic, data)
|
136
|
+
return if !redis_enabled? || topic.blank? || data.blank?
|
137
|
+
CelluloidPubsub::Redis.connect do |connection|
|
138
|
+
connection.publish(topic, data)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def publish_clasic_event(channel, data)
|
143
|
+
return if channel.blank? || data.blank?
|
144
|
+
(@subscribers[channel] || []).each do |hash|
|
145
|
+
hash[:reactor].websocket << data
|
131
146
|
end
|
132
|
-
rescue => e
|
133
|
-
debug("could not publish message #{message} into topic #{current_topic} because of #{e.inspect}") if debug_enabled?
|
134
147
|
end
|
135
148
|
|
136
149
|
# callback that will execute when receiving new conections
|
@@ -149,7 +162,7 @@ module CelluloidPubsub
|
|
149
162
|
def on_connection(connection)
|
150
163
|
while request = connection.request
|
151
164
|
if request.websocket?
|
152
|
-
|
165
|
+
log_debug "#{self.class} Received a WebSocket connection"
|
153
166
|
|
154
167
|
# We're going to hand off this connection to another actor (Writer/Reader)
|
155
168
|
# However, initially Reel::Connections are "attached" to the
|
@@ -159,7 +172,7 @@ module CelluloidPubsub
|
|
159
172
|
# If we want to hand this connection off to another actor, we first
|
160
173
|
# need to detach it from the Reel::Server (in this case, Reel::Server::HTTP)
|
161
174
|
connection.detach
|
162
|
-
|
175
|
+
dispatch_websocket_request(request)
|
163
176
|
return
|
164
177
|
else
|
165
178
|
route_request connection, request
|
@@ -167,6 +180,16 @@ module CelluloidPubsub
|
|
167
180
|
end
|
168
181
|
end
|
169
182
|
|
183
|
+
def reactor_class
|
184
|
+
redis_enabled? ? CelluloidPubsub::RedisReactor : CelluloidPubsub::Reactor
|
185
|
+
end
|
186
|
+
|
187
|
+
def dispatch_websocket_request(request)
|
188
|
+
reactor = reactor_class.new
|
189
|
+
Actor.current.link reactor
|
190
|
+
route_websocket(reactor, request.websocket)
|
191
|
+
end
|
192
|
+
|
170
193
|
# HTTP connections are not accepted so this method will show 404 message "Not Found"
|
171
194
|
#
|
172
195
|
# @param [Reel::WebSocket] connection The HTTP connection that was received
|
@@ -176,7 +199,7 @@ module CelluloidPubsub
|
|
176
199
|
#
|
177
200
|
# @api public
|
178
201
|
def route_request(connection, request)
|
179
|
-
|
202
|
+
log_debug "404 Not Found: #{request.path}"
|
180
203
|
connection.respond :not_found, 'Not found'
|
181
204
|
end
|
182
205
|
|
@@ -190,14 +213,12 @@ module CelluloidPubsub
|
|
190
213
|
# @return [void]
|
191
214
|
#
|
192
215
|
# @api public
|
193
|
-
def route_websocket(socket)
|
194
|
-
|
195
|
-
|
196
|
-
info "#{reactor.class} handles new socket connection" if debug_enabled?
|
197
|
-
Actor.current.link reactor
|
216
|
+
def route_websocket(reactor, socket)
|
217
|
+
url = socket.url
|
218
|
+
if url == path
|
198
219
|
reactor.async.work(socket, Actor.current)
|
199
220
|
else
|
200
|
-
|
221
|
+
log_debug "Received invalid WebSocket request for: #{url}"
|
201
222
|
socket.close
|
202
223
|
end
|
203
224
|
end
|
@@ -212,14 +233,14 @@ module CelluloidPubsub
|
|
212
233
|
#
|
213
234
|
# @api public
|
214
235
|
def handle_dispatched_message(reactor, data)
|
215
|
-
|
236
|
+
log_debug "#{self.class} trying to dispatch message #{data.inspect}"
|
216
237
|
message = reactor.parse_json_data(data)
|
217
238
|
if message.present? && message.is_a?(Hash)
|
218
|
-
|
239
|
+
final_data = message.to_json
|
219
240
|
else
|
220
|
-
|
241
|
+
final_data data.to_json
|
221
242
|
end
|
243
|
+
reactor.websocket << final_data
|
222
244
|
end
|
223
|
-
|
224
245
|
end
|
225
246
|
end
|
@@ -5,19 +5,19 @@ require 'spec_helper'
|
|
5
5
|
describe CelluloidPubsub::Client do
|
6
6
|
let(:blk) { proc { |a| puts a } }
|
7
7
|
let(:options) { {} }
|
8
|
-
let(:socket) { mock }
|
9
8
|
let(:actor) { mock }
|
10
9
|
let(:connection) { mock }
|
11
10
|
let(:channel) { 'some_channel' }
|
12
11
|
|
13
12
|
before(:each) do
|
14
|
-
|
15
|
-
|
16
|
-
@worker.
|
13
|
+
CelluloidPubsub::Client.any_instance.stubs(:supervise_actors).returns(true)
|
14
|
+
CelluloidPubsub::Client.any_instance.stubs(:connection).returns(connection)
|
15
|
+
@worker = CelluloidPubsub::Client.new(actor: actor, channel: channel, enable_debug: false)
|
17
16
|
@worker.stubs(:debug).returns(true)
|
18
17
|
@worker.stubs(:async).returns(@worker)
|
19
18
|
actor.stubs(:async).returns(actor)
|
20
|
-
|
19
|
+
actor.stubs(:respond_to?).returns(false)
|
20
|
+
actor.stubs(:terminate).returns(true)
|
21
21
|
connection.stubs(:terminate).returns(true)
|
22
22
|
connection.stubs(:text).returns(true)
|
23
23
|
end
|
@@ -56,7 +56,7 @@ describe CelluloidPubsub::Client do
|
|
56
56
|
describe '#debug_enabled?' do
|
57
57
|
it 'checks if debug is enabled' do
|
58
58
|
act = @worker.debug_enabled?
|
59
|
-
expect(act).to eq(
|
59
|
+
expect(act).to eq(false)
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -12,7 +12,9 @@ describe CelluloidPubsub::Reactor do
|
|
12
12
|
server.stubs(:async).returns(server)
|
13
13
|
server.stubs(:handle_dispatched_message)
|
14
14
|
server.stubs(:subscribers).returns({})
|
15
|
+
server.stubs(:redis_enabled?).returns(false)
|
15
16
|
websocket.stubs(:read)
|
17
|
+
websocket.stubs(:url)
|
16
18
|
subject.stubs(:inspect).returns(subject)
|
17
19
|
subject.stubs(:run)
|
18
20
|
subject.work(websocket, server)
|