celluloid_pubsub 1.1.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.hound.yml +10 -0
- data/.rubocop.yml +107 -25
- data/.rubocop_todo.yml +7 -0
- data/.travis.yml +50 -13
- data/Appraisals +8 -4
- data/Gemfile +1 -1
- data/Rakefile +2 -2
- data/celluloid_pubsub.gemspec +5 -4
- data/examples/simple_test.rb +30 -8
- data/gemfiles/{celluloid_0.16.0.gemfile → cell_0.16.0.gemfile} +1 -1
- data/gemfiles/{celluloid_0.17.3.gemfile → cell_0.17.3.gemfile} +1 -1
- data/gemfiles/{celluloid_0.18.0.pre.gemfile → cell_0.17.4.gemfile} +2 -2
- data/gemfiles/cell_0.18.0.gemfile +7 -0
- data/init.rb +1 -0
- data/lib/celluloid_pubsub.rb +2 -1
- data/lib/celluloid_pubsub/base_actor.rb +36 -4
- data/lib/celluloid_pubsub/client.rb +47 -7
- data/lib/celluloid_pubsub/client_connection.rb +57 -0
- data/lib/celluloid_pubsub/gem_version_parser.rb +2 -2
- data/lib/celluloid_pubsub/helper.rb +56 -8
- data/lib/celluloid_pubsub/initializers/reel_colors.rb +6 -1
- data/lib/celluloid_pubsub/reactor.rb +154 -22
- data/lib/celluloid_pubsub/registry.rb +28 -2
- data/lib/celluloid_pubsub/version.rb +21 -3
- data/lib/celluloid_pubsub/web_server.rb +84 -6
- data/spec/lib/celluloid_pubsub/base_actor_spec.rb +78 -0
- data/spec/lib/celluloid_pubsub/client_pubsub_spec.rb +168 -37
- data/spec/lib/celluloid_pubsub/reactor_spec.rb +373 -98
- data/spec/lib/celluloid_pubsub/registry_spec.rb +19 -1
- data/spec/lib/celluloid_pubsub/version_spec.rb +21 -0
- data/spec/lib/celluloid_pubsub/web_server_spec.rb +2 -2
- data/spec/spec_helper.rb +74 -10
- metadata +32 -52
@@ -1,17 +1,22 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
require 'reel/spy'
|
4
5
|
Reel::Spy::Colors.class_eval do
|
5
6
|
alias_method :original_colorize, :colorize
|
6
7
|
|
7
|
-
|
8
|
+
# :nocov:
|
9
|
+
def colorize(_var, str)
|
8
10
|
force_utf8_encoding(str)
|
9
11
|
end
|
12
|
+
# :nocov:
|
10
13
|
|
11
14
|
# Returns utf8 encoding of the msg
|
12
15
|
# @param [String] msg
|
13
16
|
# @return [String] ReturnsReturns utf8 encoding of the msg
|
17
|
+
# :nocov:
|
14
18
|
def force_utf8_encoding(msg)
|
15
19
|
msg.respond_to?(:force_encoding) && msg.encoding.name != 'UTF-8' ? msg.force_encoding('UTF-8') : msg
|
16
20
|
end
|
21
|
+
# :nocov:
|
17
22
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
require_relative './registry'
|
4
5
|
require_relative './helper'
|
5
6
|
module CelluloidPubsub
|
@@ -18,7 +19,7 @@ module CelluloidPubsub
|
|
18
19
|
include CelluloidPubsub::BaseActor
|
19
20
|
|
20
21
|
# available actions that can be delegated
|
21
|
-
AVAILABLE_ACTIONS = %w
|
22
|
+
AVAILABLE_ACTIONS = %w[unsubscribe_clients unsubscribe subscribe publish unsubscribe_all].freeze
|
22
23
|
|
23
24
|
# The websocket connection received from the server
|
24
25
|
# @return [Reel::WebSocket] websocket connection
|
@@ -32,7 +33,13 @@ module CelluloidPubsub
|
|
32
33
|
# @return [Array] array of channels to which the current reactor has subscribed to
|
33
34
|
attr_accessor :channels
|
34
35
|
|
36
|
+
# The same options passed to the server are available on the reactor too
|
37
|
+
# @return [Hash] Hash with all the options passed to the server
|
38
|
+
attr_reader :options
|
39
|
+
|
35
40
|
finalizer :shutdown
|
41
|
+
trap_exit :actor_died
|
42
|
+
|
36
43
|
# rececives a new socket connection from the server
|
37
44
|
# and listens for messages
|
38
45
|
#
|
@@ -42,11 +49,68 @@ module CelluloidPubsub
|
|
42
49
|
#
|
43
50
|
# @api public
|
44
51
|
def work(websocket, server)
|
52
|
+
initialize_data(websocket, server)
|
53
|
+
server.reactors << Actor.current
|
54
|
+
async.run
|
55
|
+
end
|
56
|
+
|
57
|
+
# initializes the actor
|
58
|
+
#
|
59
|
+
# @param [Reel::WebSocket] websocket
|
60
|
+
# @param [CelluloidPubsub::WebServer] server
|
61
|
+
#
|
62
|
+
# @return [Celluloid::Actor] returns the actor
|
63
|
+
#
|
64
|
+
# @api public
|
65
|
+
def initialize_data(websocket, server)
|
66
|
+
@websocket = websocket
|
45
67
|
@server = server
|
68
|
+
@options = @server.server_options
|
46
69
|
@channels = []
|
47
|
-
@
|
48
|
-
|
49
|
-
|
70
|
+
@shutting_down = false
|
71
|
+
setup_celluloid_logger
|
72
|
+
log_debug "#{self.class} Streaming changes for #{websocket.url} #{websocket.class.name}"
|
73
|
+
yield(websocket, server) if block_given?
|
74
|
+
cell_actor
|
75
|
+
end
|
76
|
+
|
77
|
+
# the method will return the file path of the log file where debug messages will be printed
|
78
|
+
#
|
79
|
+
#
|
80
|
+
# @return [String] returns the file path of the log file where debug messages will be printed
|
81
|
+
#
|
82
|
+
# @api public
|
83
|
+
def log_file_path
|
84
|
+
@log_file_path ||= options.fetch('log_file_path', nil)
|
85
|
+
end
|
86
|
+
|
87
|
+
# the method will return the log level of the logger
|
88
|
+
#
|
89
|
+
# @return [Integer, nil] return the log level used by the logger ( default is 1 - info)
|
90
|
+
#
|
91
|
+
# @api public
|
92
|
+
def log_level
|
93
|
+
@log_level ||= options['log_level'] || ::Logger::Severity::INFO
|
94
|
+
end
|
95
|
+
|
96
|
+
# the method will return options needed when configuring an adapter
|
97
|
+
# @see celluloid_pubsub_redis_adapter for more information
|
98
|
+
#
|
99
|
+
# @return [Hash] returns options needed by the adapter
|
100
|
+
#
|
101
|
+
# @api public
|
102
|
+
def adapter_options
|
103
|
+
@adapter_options ||= options['adapter_options'] || {}
|
104
|
+
end
|
105
|
+
|
106
|
+
# the method will return true if the actor is shutting down
|
107
|
+
#
|
108
|
+
#
|
109
|
+
# @return [Boolean] returns true if the actor is shutting down
|
110
|
+
#
|
111
|
+
# @api public
|
112
|
+
def shutting_down?
|
113
|
+
@shutting_down == true
|
50
114
|
end
|
51
115
|
|
52
116
|
# the method will return true if debug is enabled
|
@@ -56,7 +120,8 @@ module CelluloidPubsub
|
|
56
120
|
#
|
57
121
|
# @api public
|
58
122
|
def debug_enabled?
|
59
|
-
|
123
|
+
@debug_enabled = options.fetch('enable_debug', false)
|
124
|
+
@debug_enabled == true
|
60
125
|
end
|
61
126
|
|
62
127
|
# reads from the socket the message
|
@@ -70,11 +135,12 @@ module CelluloidPubsub
|
|
70
135
|
# :nocov:
|
71
136
|
def run
|
72
137
|
loop do
|
73
|
-
break if Actor.current
|
138
|
+
break if shutting_down? || actor_dead?(Actor.current) || @websocket.closed? || actor_dead?(@server)
|
74
139
|
message = try_read_websocket
|
75
140
|
handle_websocket_message(message) if message.present?
|
76
141
|
end
|
77
142
|
end
|
143
|
+
# :nocov:
|
78
144
|
|
79
145
|
# will try to read the message from the websocket
|
80
146
|
# and if it fails will log the exception if debug is enabled
|
@@ -83,10 +149,9 @@ module CelluloidPubsub
|
|
83
149
|
#
|
84
150
|
# @api public
|
85
151
|
#
|
86
|
-
# :nocov:
|
87
152
|
def try_read_websocket
|
88
153
|
@websocket.closed? ? nil : @websocket.read
|
89
|
-
rescue
|
154
|
+
rescue StandardError
|
90
155
|
nil
|
91
156
|
end
|
92
157
|
|
@@ -108,9 +173,10 @@ module CelluloidPubsub
|
|
108
173
|
#
|
109
174
|
# @api public
|
110
175
|
def parse_json_data(message)
|
176
|
+
log_debug "#{reactor_class} received #{message}"
|
111
177
|
JSON.parse(message)
|
112
|
-
rescue =>
|
113
|
-
log_debug "#{reactor_class} could not parse #{message} because of #{
|
178
|
+
rescue StandardError => e
|
179
|
+
log_debug "#{reactor_class} could not parse #{message} because of #{e.inspect}"
|
114
180
|
message
|
115
181
|
end
|
116
182
|
|
@@ -147,7 +213,7 @@ module CelluloidPubsub
|
|
147
213
|
#
|
148
214
|
# @api public
|
149
215
|
def handle_parsed_websocket_message(json_data)
|
150
|
-
data =
|
216
|
+
data = json_data.is_a?(Hash) ? json_data.stringify_keys : {}
|
151
217
|
if CelluloidPubsub::Reactor::AVAILABLE_ACTIONS.include?(data['client_action'].to_s)
|
152
218
|
log_debug "#{self.class} finds actions for #{json_data}"
|
153
219
|
delegate_action(data) if data['client_action'].present?
|
@@ -183,7 +249,7 @@ module CelluloidPubsub
|
|
183
249
|
end
|
184
250
|
|
185
251
|
# the method will delegate the message to the server in an asyncronous way by sending the current actor and the message
|
186
|
-
# @see
|
252
|
+
# @see CelluloidPubsub::WebServer#handle_dispatched_message
|
187
253
|
#
|
188
254
|
# @param [Hash] json_data
|
189
255
|
#
|
@@ -262,7 +328,8 @@ module CelluloidPubsub
|
|
262
328
|
#
|
263
329
|
# @api public
|
264
330
|
def shutdown
|
265
|
-
|
331
|
+
@shutting_down = true
|
332
|
+
log_debug "#{self.class} tries to 'shutdown'"
|
266
333
|
@websocket.close if @websocket.present? && !@websocket.closed?
|
267
334
|
terminate
|
268
335
|
end
|
@@ -285,6 +352,42 @@ module CelluloidPubsub
|
|
285
352
|
@websocket << message.merge('client_action' => 'successful_subscription', 'channel' => channel).to_json if @server.adapter == CelluloidPubsub::WebServer::CLASSIC_ADAPTER
|
286
353
|
end
|
287
354
|
|
355
|
+
# this method will write to the socket all messages that were published
|
356
|
+
# to that channel before the actor subscribed
|
357
|
+
#
|
358
|
+
# @param [String] channel
|
359
|
+
# @return [void]
|
360
|
+
#
|
361
|
+
# @api public
|
362
|
+
def send_unpublished(channel)
|
363
|
+
return if (messages = unpublished_messages(channel)).blank?
|
364
|
+
messages.each do |msg|
|
365
|
+
@websocket << msg.to_json
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
# the method clears all the messages left unpublished in a channel
|
370
|
+
#
|
371
|
+
# @param [String] channel
|
372
|
+
#
|
373
|
+
# @return [void]
|
374
|
+
#
|
375
|
+
# @api public
|
376
|
+
def clear_unpublished_messages(channel)
|
377
|
+
CelluloidPubsub::Registry.messages[channel] = []
|
378
|
+
end
|
379
|
+
|
380
|
+
# the method will return a list of all unpublished messages in a channel
|
381
|
+
#
|
382
|
+
# @param [String] channel
|
383
|
+
#
|
384
|
+
# @return [Array] the list of messages that were not published
|
385
|
+
#
|
386
|
+
# @api public
|
387
|
+
def unpublished_messages(channel)
|
388
|
+
(messages = CelluloidPubsub::Registry.messages[channel]).present? ? messages : []
|
389
|
+
end
|
390
|
+
|
288
391
|
# this method will return a list of all subscribers to a particular channel or a empty array
|
289
392
|
#
|
290
393
|
#
|
@@ -326,9 +429,9 @@ module CelluloidPubsub
|
|
326
429
|
def publish(current_topic, json_data)
|
327
430
|
message = json_data['data'].to_json
|
328
431
|
return if current_topic.blank? || message.blank?
|
329
|
-
|
330
|
-
rescue =>
|
331
|
-
log_debug("could not publish message #{message} into topic #{current_topic} because of #{
|
432
|
+
server_publish_event(current_topic, message)
|
433
|
+
rescue StandardError => e
|
434
|
+
log_debug("could not publish message #{message} into topic #{current_topic} because of #{e.inspect}")
|
332
435
|
end
|
333
436
|
|
334
437
|
# the method will publish to all subsribers of a channel a message
|
@@ -339,18 +442,34 @@ module CelluloidPubsub
|
|
339
442
|
# @return [void]
|
340
443
|
#
|
341
444
|
# @api public
|
342
|
-
def
|
343
|
-
@server.
|
344
|
-
|
445
|
+
def server_publish_event(current_topic, message)
|
446
|
+
if (subscribers = @server.subscribers[current_topic]).present?
|
447
|
+
subscribers.dup.pmap do |hash|
|
345
448
|
hash[:reactor].websocket << message
|
346
449
|
end
|
450
|
+
else
|
451
|
+
save_unpublished_message(current_topic, message)
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
# the method save the message for a specific channel if there are no subscribers
|
456
|
+
#
|
457
|
+
# @param [String] current_topic
|
458
|
+
# @param [#to_s] message
|
459
|
+
#
|
460
|
+
# @return [void]
|
461
|
+
#
|
462
|
+
# @api public
|
463
|
+
def save_unpublished_message(current_topic, message)
|
464
|
+
@server.timers_mutex.synchronize do
|
465
|
+
(CelluloidPubsub::Registry.messages[current_topic] ||= []) << message
|
347
466
|
end
|
348
467
|
end
|
349
468
|
|
350
|
-
# unsubscribes all actors from all channels and terminates the
|
469
|
+
# unsubscribes all actors from all channels and terminates the current actor
|
351
470
|
#
|
352
471
|
# @param [String] _channel NOT USED - needed to maintain compatibility with the other methods
|
353
|
-
# @param [Object]
|
472
|
+
# @param [Object] json_data NOT USED - needed to maintain compatibility with the other methods
|
354
473
|
#
|
355
474
|
# @return [void]
|
356
475
|
#
|
@@ -383,12 +502,25 @@ module CelluloidPubsub
|
|
383
502
|
# @api public
|
384
503
|
def server_kill_reactors(channel)
|
385
504
|
@server.mutex.synchronize do
|
386
|
-
(@server.subscribers[channel]
|
505
|
+
(@server.subscribers[channel] || []).dup.pmap do |hash|
|
387
506
|
reactor = hash[:reactor]
|
388
507
|
reactor.websocket.close
|
389
508
|
Celluloid::Actor.kill(reactor)
|
390
509
|
end
|
391
510
|
end
|
392
511
|
end
|
512
|
+
|
513
|
+
# method called when the actor is exiting
|
514
|
+
#
|
515
|
+
# @param [actor] actor - the current actor
|
516
|
+
# @param [Hash] reason - the reason it crashed
|
517
|
+
#
|
518
|
+
# @return [void]
|
519
|
+
#
|
520
|
+
# @api public
|
521
|
+
def actor_died(actor, reason)
|
522
|
+
@shutting_down = true
|
523
|
+
log_debug "Oh no! #{actor.inspect} has died because of a #{reason.class}"
|
524
|
+
end
|
393
525
|
end
|
394
526
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
module CelluloidPubsub
|
4
5
|
# class used to register new channels and save them in memory
|
5
6
|
# @attr channels
|
@@ -8,8 +9,33 @@ module CelluloidPubsub
|
|
8
9
|
class << self
|
9
10
|
# The channels that the server can handle
|
10
11
|
# @return [Array] array of channels to which actors have subscribed to
|
11
|
-
|
12
|
+
attr_writer :channels
|
13
|
+
|
14
|
+
# Messages that are published before any clients being subscribed to those channels
|
15
|
+
# will be kept here until a client subscribes to that channel
|
16
|
+
# @return [Hash] key-value pairs containing the channel and the messages that were published
|
17
|
+
attr_writer :messages
|
18
|
+
|
19
|
+
# holds a list of all messages sent by clients that were not published
|
20
|
+
# to a channel because there were no subscribers at that time
|
21
|
+
#
|
22
|
+
# The keys are the channel names and the values are arrays of messages
|
23
|
+
#
|
24
|
+
# @return [Hash<String, Array<Hash>>]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
def messages
|
28
|
+
@messages ||= {}
|
29
|
+
end
|
30
|
+
|
31
|
+
# holds a list of all known channels
|
32
|
+
#
|
33
|
+
# @return [Array<String>]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
def channels
|
37
|
+
@channels ||= []
|
38
|
+
end
|
12
39
|
end
|
13
|
-
@channels = []
|
14
40
|
end
|
15
41
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
# Returns the version of the gem as a <tt>Gem::Version</tt>
|
4
5
|
module CelluloidPubsub
|
5
6
|
# it prints the gem version as a string
|
@@ -7,23 +8,40 @@ module CelluloidPubsub
|
|
7
8
|
# @return [String]
|
8
9
|
#
|
9
10
|
# @api public
|
11
|
+
# :nocov:
|
10
12
|
def self.gem_version
|
11
13
|
Gem::Version.new VERSION::STRING
|
12
14
|
end
|
15
|
+
# :nocov:
|
13
16
|
|
14
17
|
# module used to generate the version string
|
15
18
|
# provides a easy way of getting the major, minor and tiny
|
19
|
+
# :nocov:
|
16
20
|
module VERSION
|
17
21
|
# major release version
|
18
|
-
|
22
|
+
# :nocov:
|
23
|
+
MAJOR = 2
|
24
|
+
# :nocov:
|
25
|
+
|
19
26
|
# minor release version
|
20
|
-
|
27
|
+
# :nocov:
|
28
|
+
MINOR = 0
|
29
|
+
# :nocov:
|
30
|
+
|
21
31
|
# tiny release version
|
22
|
-
|
32
|
+
# :nocov:
|
33
|
+
TINY = 0
|
34
|
+
# :nocov:
|
35
|
+
|
23
36
|
# prelease version ( set this only if it is a prelease)
|
37
|
+
# :nocov:
|
24
38
|
PRE = nil
|
39
|
+
# :nocov:
|
25
40
|
|
26
41
|
# generates the version string
|
42
|
+
# :nocov:
|
27
43
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
|
44
|
+
# :nocov:
|
28
45
|
end
|
46
|
+
# :nocov:
|
29
47
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
require_relative './reactor'
|
4
5
|
require_relative './helper'
|
5
6
|
module CelluloidPubsub
|
@@ -17,6 +18,8 @@ module CelluloidPubsub
|
|
17
18
|
# @return [Hash] The hostname on which the webserver runs on
|
18
19
|
# @attr mutex
|
19
20
|
# @return [Mutex] The mutex that will synchronize actions on subscribers
|
21
|
+
# @attr timers_mutex
|
22
|
+
# @return [Mutex] The mutex that will synchronize actions on registry messages
|
20
23
|
class WebServer < Reel::Server::HTTP
|
21
24
|
include CelluloidPubsub::BaseActor
|
22
25
|
|
@@ -27,8 +30,12 @@ module CelluloidPubsub
|
|
27
30
|
# The name of the default adapter
|
28
31
|
CLASSIC_ADAPTER = 'classic'
|
29
32
|
|
30
|
-
attr_accessor :server_options, :subscribers, :mutex
|
33
|
+
attr_accessor :server_options, :subscribers, :mutex, :timers_mutex
|
34
|
+
|
35
|
+
attr_reader :reactors
|
36
|
+
|
31
37
|
finalizer :shutdown
|
38
|
+
trap_exit :actor_died
|
32
39
|
# receives a list of options that are used to configure the webserver
|
33
40
|
#
|
34
41
|
# @param [Hash] options the options that can be used to connect to webser and send additional data
|
@@ -47,8 +54,11 @@ module CelluloidPubsub
|
|
47
54
|
@server_options = parse_options(options)
|
48
55
|
@subscribers = {}
|
49
56
|
@mutex = Mutex.new
|
57
|
+
@timers_mutex = Mutex.new
|
58
|
+
@shutting_down = false
|
59
|
+
@reactors = []
|
50
60
|
setup_celluloid_logger
|
51
|
-
|
61
|
+
log_debug "CelluloidPubsub::WebServer example starting on #{hostname}:#{port}"
|
52
62
|
super(hostname, port, { spy: spy, backlog: backlog }, &method(:on_connection))
|
53
63
|
end
|
54
64
|
|
@@ -80,7 +90,7 @@ module CelluloidPubsub
|
|
80
90
|
# @return [Hash] return the socket families available as keys in the hash
|
81
91
|
#
|
82
92
|
# @api public
|
83
|
-
# rubocop:disable ClassVars
|
93
|
+
# rubocop:disable Style/ClassVars
|
84
94
|
def self.socket_families
|
85
95
|
@@socket_families ||= Hash[*socket_infos.map { |af, *_| af }.uniq.zip([]).flatten]
|
86
96
|
end
|
@@ -99,7 +109,7 @@ module CelluloidPubsub
|
|
99
109
|
port
|
100
110
|
end
|
101
111
|
end
|
102
|
-
# rubocop:enable ClassVars
|
112
|
+
# rubocop:enable Style/ClassVars
|
103
113
|
|
104
114
|
# this method is overriden from the Reel::Server::HTTP in order to set the spy to the celluloid logger
|
105
115
|
# before the connection is accepted.
|
@@ -107,9 +117,24 @@ module CelluloidPubsub
|
|
107
117
|
# @api public
|
108
118
|
def run
|
109
119
|
@spy = Celluloid.logger if spy
|
120
|
+
async.bind_timers
|
110
121
|
loop { async.handle_connection @server.accept }
|
111
122
|
end
|
112
123
|
|
124
|
+
# the method will run indefinitely and will check if are there
|
125
|
+
# any unpublished messages that can be send to new subscribers
|
126
|
+
#
|
127
|
+
# @param [Boolean] run FLag to control if the server should try checking
|
128
|
+
# if there are any unpublished messages that need to be sent
|
129
|
+
#
|
130
|
+
# @return [void]
|
131
|
+
#
|
132
|
+
# @api public
|
133
|
+
def bind_timers(run = false)
|
134
|
+
try_sending_unpublished if run
|
135
|
+
after(0.1) { bind_timers(true) }
|
136
|
+
end
|
137
|
+
|
113
138
|
# the method will return true if redis can be used otherwise false
|
114
139
|
#
|
115
140
|
#
|
@@ -121,6 +146,16 @@ module CelluloidPubsub
|
|
121
146
|
@adapter.present? ? @adapter : CelluloidPubsub::WebServer::CLASSIC_ADAPTER
|
122
147
|
end
|
123
148
|
|
149
|
+
# the method will return true if the actor is shutting down
|
150
|
+
#
|
151
|
+
#
|
152
|
+
# @return [Boolean] returns true if the actor is shutting down
|
153
|
+
#
|
154
|
+
# @api public
|
155
|
+
def shutting_down?
|
156
|
+
@shutting_down == true
|
157
|
+
end
|
158
|
+
|
124
159
|
# the method will return true if debug is enabled otherwise false
|
125
160
|
#
|
126
161
|
#
|
@@ -139,7 +174,11 @@ module CelluloidPubsub
|
|
139
174
|
#
|
140
175
|
# @api public
|
141
176
|
def shutdown
|
142
|
-
|
177
|
+
@shutting_down = true
|
178
|
+
log_debug "#{self.class} tries to 'shutdown'"
|
179
|
+
reactors.each do |reactor|
|
180
|
+
reactor.terminate unless actor_dead?(reactor)
|
181
|
+
end
|
143
182
|
terminate
|
144
183
|
end
|
145
184
|
|
@@ -153,6 +192,15 @@ module CelluloidPubsub
|
|
153
192
|
@log_file_path = @server_options.fetch('log_file_path', nil)
|
154
193
|
end
|
155
194
|
|
195
|
+
# the method will return the log level of the logger
|
196
|
+
#
|
197
|
+
# @return [Integer, nil] return the log level used by the logger ( default is 1 - info)
|
198
|
+
#
|
199
|
+
# @api public
|
200
|
+
def log_level
|
201
|
+
@log_level ||= @server_options['log_level'] || ::Logger::Severity::INFO
|
202
|
+
end
|
203
|
+
|
156
204
|
# the method will return the hostname on which the server is running on
|
157
205
|
#
|
158
206
|
#
|
@@ -219,7 +267,7 @@ module CelluloidPubsub
|
|
219
267
|
def on_connection(connection)
|
220
268
|
while request = connection.request
|
221
269
|
if request.websocket?
|
222
|
-
log_debug "#{self.class} Received a WebSocket connection"
|
270
|
+
log_debug "#{self.class} Received a WebSocket connection #{request.websocket.url}"
|
223
271
|
|
224
272
|
# We're going to hand off this connection to another actor (Writer/Reader)
|
225
273
|
# However, initially Reel::Connections are "attached" to the
|
@@ -294,6 +342,23 @@ module CelluloidPubsub
|
|
294
342
|
end
|
295
343
|
end
|
296
344
|
|
345
|
+
# this method will know when a client has successfully registered
|
346
|
+
# and will write to the socket all messages that were published
|
347
|
+
# to that channel before the actor subscribed
|
348
|
+
#
|
349
|
+
# @return [void]
|
350
|
+
#
|
351
|
+
# @api publicsCelluloidPubsub::Registry.messages
|
352
|
+
def try_sending_unpublished
|
353
|
+
CelluloidPubsub::Registry.messages.each_key do |channel|
|
354
|
+
next if (clients = subscribers[channel]).blank?
|
355
|
+
clients.dup.pmap do |hash|
|
356
|
+
hash[:reactor].send_unpublished(channel)
|
357
|
+
end
|
358
|
+
clients.last[:reactor].clear_unpublished_messages(channel)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
297
362
|
# If the message can be parsed into a Hash it will respond to the reactor's websocket connection with the same message in JSON format
|
298
363
|
# otherwise will try send the message how it is and escaped into JSON format
|
299
364
|
#
|
@@ -309,5 +374,18 @@ module CelluloidPubsub
|
|
309
374
|
final_data = message.present? && message.is_a?(Hash) ? message.to_json : data.to_json
|
310
375
|
reactor.websocket << final_data
|
311
376
|
end
|
377
|
+
|
378
|
+
# method called when the actor is exiting
|
379
|
+
#
|
380
|
+
# @param [actor] actor - the current actor
|
381
|
+
# @param [Hash] reason - the reason it crashed
|
382
|
+
#
|
383
|
+
# @return [void]
|
384
|
+
#
|
385
|
+
# @api public
|
386
|
+
def actor_died(actor, reason)
|
387
|
+
@shutting_down = true
|
388
|
+
log_debug "Oh no! #{actor.inspect} has died because of a #{reason.class}"
|
389
|
+
end
|
312
390
|
end
|
313
391
|
end
|