celluloid_pubsub 0.2.0 → 0.3.0
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 +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)
|