celluloid_pubsub 1.0.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/.reek +2 -0
- data/.rubocop.yml +107 -25
- data/.rubocop_todo.yml +7 -0
- data/.travis.yml +52 -11
- data/Appraisals +10 -2
- data/Gemfile +1 -6
- data/Rakefile +7 -2
- data/celluloid_pubsub.gemspec +15 -13
- 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/cell_0.17.4.gemfile +7 -0
- 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 +38 -1
- 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 +20 -2
- 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 +76 -11
- metadata +62 -81
data/init.rb
CHANGED
data/lib/celluloid_pubsub.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
require 'rubygems'
|
4
5
|
require 'bundler'
|
5
6
|
require 'bundler/setup'
|
6
7
|
require 'celluloid/io'
|
7
|
-
require 'reel'
|
8
8
|
require 'celluloid/websocket/client'
|
9
9
|
require 'active_support/all'
|
10
10
|
require 'json'
|
11
11
|
require 'thread'
|
12
12
|
require 'celluloid/pmap'
|
13
13
|
require 'celluloid_pubsub/base_actor'
|
14
|
+
require 'reel'
|
14
15
|
Gem.find_files('celluloid_pubsub/initializers/**/*.rb').each { |path| require path }
|
15
16
|
Gem.find_files('celluloid_pubsub/**/*.rb').each { |path| require path }
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
require_relative './helper'
|
4
5
|
module CelluloidPubsub
|
5
6
|
# base actor used for compatibility between celluloid versions
|
@@ -39,6 +40,7 @@ module CelluloidPubsub
|
|
39
40
|
# @return [Class] returns the logger class from celluloid depending on version
|
40
41
|
#
|
41
42
|
# @api public
|
43
|
+
# :nocov:
|
42
44
|
def celluloid_logger_class
|
43
45
|
if version_less_than_seventeen?
|
44
46
|
Celluloid::Logger
|
@@ -46,6 +48,7 @@ module CelluloidPubsub
|
|
46
48
|
Celluloid::Internals::Logger
|
47
49
|
end
|
48
50
|
end
|
51
|
+
# :nocov:
|
49
52
|
|
50
53
|
# returns the celluloid version loaded
|
51
54
|
# @return [String] returns the celluloid version loaded
|
@@ -63,12 +66,34 @@ module CelluloidPubsub
|
|
63
66
|
verify_gem_version(celluloid_version, '0.17', operator: '<')
|
64
67
|
end
|
65
68
|
|
69
|
+
# returns true if celluloid version less than 0.18, otherwise false
|
70
|
+
# @return [Boolean] returns true if celluloid version less than 0.17, otherwise false
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
def version_less_than_eigthteen?
|
74
|
+
verify_gem_version(celluloid_version, '0.18', operator: '<')
|
75
|
+
end
|
76
|
+
|
77
|
+
# tries to boot up Celluloid if it is not running
|
78
|
+
# @return [Boolean] returns true if Celluloid started false otherwise
|
79
|
+
#
|
80
|
+
# @api public
|
81
|
+
def boot_up
|
82
|
+
celluloid_running = begin
|
83
|
+
Celluloid.running?
|
84
|
+
rescue StandardError
|
85
|
+
false
|
86
|
+
end
|
87
|
+
Celluloid.boot unless celluloid_running
|
88
|
+
end
|
89
|
+
|
66
90
|
# sets up the actor supervision based on celluloid version
|
67
91
|
# @param [Class] class_name The class that will be used to supervise the actor
|
68
92
|
# @param [Hash] options Additional options needed for supervision
|
69
93
|
# @return [void]
|
70
94
|
#
|
71
95
|
# @api public
|
96
|
+
# :nocov:
|
72
97
|
def setup_actor_supervision(class_name, options)
|
73
98
|
actor_name, args = options.slice(:actor_name, :args).values
|
74
99
|
if version_less_than_seventeen?
|
@@ -77,12 +102,24 @@ module CelluloidPubsub
|
|
77
102
|
class_name.supervise(as: actor_name, args: [args].compact)
|
78
103
|
end
|
79
104
|
end
|
105
|
+
# :nocov:
|
80
106
|
end
|
81
107
|
end
|
82
108
|
end
|
83
109
|
|
110
|
+
# :nocov:
|
84
111
|
if CelluloidPubsub::BaseActor.version_less_than_seventeen?
|
112
|
+
require 'celluloid'
|
85
113
|
require 'celluloid/autostart'
|
86
|
-
|
114
|
+
elsif CelluloidPubsub::BaseActor.version_less_than_eigthteen?
|
87
115
|
require 'celluloid/current'
|
116
|
+
CelluloidPubsub::BaseActor.boot_up
|
117
|
+
require 'celluloid'
|
118
|
+
else
|
119
|
+
require 'celluloid'
|
120
|
+
require 'celluloid/pool'
|
121
|
+
require 'celluloid/fsm'
|
122
|
+
require 'celluloid/supervision'
|
123
|
+
CelluloidPubsub::BaseActor.boot_up
|
88
124
|
end
|
125
|
+
# :nocov:
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
require_relative './helper'
|
5
|
+
require_relative './client_connection'
|
4
6
|
module CelluloidPubsub
|
5
7
|
# worker that subscribes to a channel or publishes to a channel
|
6
8
|
# if it used to subscribe to a channel the worker will dispatch the messages to the actor that made the
|
@@ -30,6 +32,7 @@ module CelluloidPubsub
|
|
30
32
|
attr_accessor :channel
|
31
33
|
|
32
34
|
finalizer :shutdown
|
35
|
+
trap_exit :actor_died
|
33
36
|
# receives a list of options that are used to connect to the webserver and an actor to which the callbacks are delegated to
|
34
37
|
# when receiving messages from a channel
|
35
38
|
#
|
@@ -48,9 +51,21 @@ module CelluloidPubsub
|
|
48
51
|
@options = options.stringify_keys!
|
49
52
|
@actor ||= @options.fetch('actor', nil)
|
50
53
|
@channel ||= @options.fetch('channel', nil)
|
54
|
+
@shutting_down = false
|
51
55
|
raise "#{self}: Please provide an actor in the options list!!!" if @actor.blank?
|
52
|
-
supervise_actors
|
53
56
|
setup_celluloid_logger
|
57
|
+
log_debug "#{@actor.class} starting on #{hostname}:#{port}"
|
58
|
+
supervise_actors
|
59
|
+
end
|
60
|
+
|
61
|
+
# the method will return true if the actor is shutting down
|
62
|
+
#
|
63
|
+
#
|
64
|
+
# @return [Boolean] returns true if the actor is shutting down
|
65
|
+
#
|
66
|
+
# @api public
|
67
|
+
def shutting_down?
|
68
|
+
@shutting_down == true
|
54
69
|
end
|
55
70
|
|
56
71
|
# the method will return the path to the log file where debug messages will be printed
|
@@ -62,6 +77,15 @@ module CelluloidPubsub
|
|
62
77
|
@log_file_path ||= @options.fetch('log_file_path', nil)
|
63
78
|
end
|
64
79
|
|
80
|
+
# the method will return the log level of the logger
|
81
|
+
#
|
82
|
+
# @return [Integer, nil] return the log level used by the logger ( default is 1 - info)
|
83
|
+
#
|
84
|
+
# @api public
|
85
|
+
def log_level
|
86
|
+
@log_level ||= @options['log_level'] || ::Logger::Severity::INFO
|
87
|
+
end
|
88
|
+
|
65
89
|
# the method will link the current actor to the actor that is attached to, and the connection to the current actor
|
66
90
|
#
|
67
91
|
# @return [void]
|
@@ -80,7 +104,7 @@ module CelluloidPubsub
|
|
80
104
|
#
|
81
105
|
# @api public
|
82
106
|
def connection
|
83
|
-
@connection ||=
|
107
|
+
@connection ||= CelluloidPubsub::ClientConnection.new("ws://#{hostname}:#{port}#{path}", Actor.current)
|
84
108
|
end
|
85
109
|
|
86
110
|
# the method will return the hostname of the server
|
@@ -120,7 +144,8 @@ module CelluloidPubsub
|
|
120
144
|
#
|
121
145
|
# @api public
|
122
146
|
def shutdown
|
123
|
-
|
147
|
+
@shutting_down = true
|
148
|
+
log_debug "#{self.class} tries to 'shutdown'"
|
124
149
|
terminate
|
125
150
|
end
|
126
151
|
|
@@ -228,17 +253,19 @@ module CelluloidPubsub
|
|
228
253
|
#
|
229
254
|
# @api public
|
230
255
|
def on_close(code, reason)
|
231
|
-
|
232
|
-
terminate
|
233
|
-
log_debug("#{@actor.class} dispatching on close #{code} #{reason}")
|
256
|
+
log_debug("#{self.class} dispatching on close #{code} #{reason}")
|
234
257
|
if @actor.respond_to?(:async)
|
235
258
|
@actor.async.on_close(code, reason)
|
236
259
|
else
|
237
260
|
@actor.on_close(code, reason)
|
238
261
|
end
|
262
|
+
ensure
|
263
|
+
log_debug("#{self.class} closing the connection on close and terminating")
|
264
|
+
connection.terminate unless actor_dead?(connection)
|
265
|
+
terminate
|
239
266
|
end
|
240
267
|
|
241
|
-
|
268
|
+
private
|
242
269
|
|
243
270
|
# method used to send an action to the webserver reactor , to a chanel and with data
|
244
271
|
#
|
@@ -269,5 +296,18 @@ module CelluloidPubsub
|
|
269
296
|
log_debug("#{@actor.class} sends JSON #{final_message}")
|
270
297
|
connection.text final_message
|
271
298
|
end
|
299
|
+
|
300
|
+
# method called when the actor is exiting
|
301
|
+
#
|
302
|
+
# @param [actor] actor - the current actor
|
303
|
+
# @param [Hash] reason - the reason it crashed
|
304
|
+
#
|
305
|
+
# @return [void]
|
306
|
+
#
|
307
|
+
# @api public
|
308
|
+
def actor_died(actor, reason)
|
309
|
+
@shutting_down = true
|
310
|
+
log_debug "Oh no! #{actor.inspect} has died because of a #{reason.class}"
|
311
|
+
end
|
272
312
|
end
|
273
313
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'celluloid/websocket/client/connection'
|
2
|
+
require 'websocket/driver'
|
3
|
+
require_relative './helper'
|
4
|
+
module CelluloidPubsub
|
5
|
+
class ClientConnection < ::Celluloid::WebSocket::Client::Connection
|
6
|
+
include CelluloidPubsub::Helper
|
7
|
+
|
8
|
+
finalizer :shutdown
|
9
|
+
trap_exit :actor_died
|
10
|
+
|
11
|
+
def initialize(url, handler)
|
12
|
+
@shutting_down = false
|
13
|
+
super(url, handler)
|
14
|
+
end
|
15
|
+
|
16
|
+
def run
|
17
|
+
super
|
18
|
+
rescue EOFError, Errno::ECONNRESET, StandardError
|
19
|
+
@client.emit(:close, ::WebSocket::Driver::CloseEvent.new(1001, 'server closed connection'))
|
20
|
+
end
|
21
|
+
|
22
|
+
# the method will return true if the actor is shutting down
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# @return [Boolean] returns true if the actor is shutting down
|
26
|
+
#
|
27
|
+
# @api public
|
28
|
+
def shutting_down?
|
29
|
+
@shutting_down == true
|
30
|
+
end
|
31
|
+
|
32
|
+
# the method will terminate the current actor
|
33
|
+
#
|
34
|
+
#
|
35
|
+
# @return [void]
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def shutdown
|
39
|
+
@shutting_down = true
|
40
|
+
log_debug "#{self.class} tries to 'shutdown'"
|
41
|
+
terminate
|
42
|
+
end
|
43
|
+
|
44
|
+
# method called when the actor is exiting
|
45
|
+
#
|
46
|
+
# @param [actor] actor - the current actor
|
47
|
+
# @param [Hash] reason - the reason it crashed
|
48
|
+
#
|
49
|
+
# @return [void]
|
50
|
+
#
|
51
|
+
# @api public
|
52
|
+
def actor_died(actor, reason)
|
53
|
+
@shutting_down = true
|
54
|
+
log_debug "Oh no! #{actor.inspect} has died because of a #{reason.class}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module CelluloidPubsub
|
3
4
|
# class used for parsing gem versions
|
4
5
|
# @!attribute [r] version
|
@@ -7,8 +8,7 @@ module CelluloidPubsub
|
|
7
8
|
# @!attribute [r] options
|
8
9
|
# @return [Hash] The additional options for parsing the version
|
9
10
|
class GemVersionParser
|
10
|
-
attr_reader :version
|
11
|
-
attr_reader :options
|
11
|
+
attr_reader :version, :options
|
12
12
|
|
13
13
|
# receives the version and the additional options
|
14
14
|
#
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
|
+
|
3
4
|
require_relative './gem_version_parser'
|
4
5
|
module CelluloidPubsub
|
5
6
|
# class that holds the options that are configurable for this gem
|
@@ -15,7 +16,39 @@ module CelluloidPubsub
|
|
15
16
|
message.is_a?(Hash) && message['client_action'] == 'successful_subscription'
|
16
17
|
end
|
17
18
|
|
18
|
-
|
19
|
+
# the method try to decide if an actor is dead
|
20
|
+
# In Celluloid 0.18 there is no `dead?` method anymore
|
21
|
+
# So we are trying to be backward-compatible with older versions
|
22
|
+
#
|
23
|
+
# @param [Celluloid::Actor] actor
|
24
|
+
# @return [Boolean] returns true if the actor is dead, otherwise false
|
25
|
+
#
|
26
|
+
# @api public
|
27
|
+
def actor_dead?(actor)
|
28
|
+
raise actor.class.inspect if !actor.respond_to?(:dead?) && !actor.respond_to?(:alive?)
|
29
|
+
(actor.respond_to?(:dead?) && actor.dead?) ||
|
30
|
+
(actor.respond_to?(:alive?) && !actor.alive?)
|
31
|
+
end
|
32
|
+
|
33
|
+
# returns the instance of the class that includes the actor, this is useful in tests
|
34
|
+
#
|
35
|
+
# @return [Object] returns the object
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def own_self
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
# returns the current actor
|
43
|
+
#
|
44
|
+
# @return [::Celluloid::Actor] returns the current actor
|
45
|
+
#
|
46
|
+
# @api public
|
47
|
+
def cell_actor
|
48
|
+
::Celluloid::Actor.current
|
49
|
+
end
|
50
|
+
|
51
|
+
module_function
|
19
52
|
|
20
53
|
# returns the gem's property from its speification or nil
|
21
54
|
# @param [String] name the name of the gem
|
@@ -91,36 +124,48 @@ module CelluloidPubsub
|
|
91
124
|
# @return [void]
|
92
125
|
#
|
93
126
|
# @api private
|
127
|
+
# :nocov:
|
94
128
|
def setup_celluloid_logger
|
95
129
|
return if !debug_enabled? || (respond_to?(:log_file_path) && log_file_path.blank?)
|
96
130
|
setup_log_file
|
97
|
-
Celluloid.logger = ::Logger.new(log_file_path.
|
131
|
+
Celluloid.logger = ::Logger.new(log_file_path).tap do |logger|
|
132
|
+
logger.level = respond_to?(:log_level) ? log_level : ::Logger::Severity::INFO
|
133
|
+
end
|
98
134
|
setup_celluloid_exception_handler
|
99
135
|
end
|
136
|
+
# :nocov:
|
100
137
|
|
101
138
|
# sets the celluloid exception handler
|
102
139
|
#
|
103
140
|
# @return [void]
|
104
141
|
#
|
105
142
|
# @api private
|
143
|
+
# :nocov:
|
106
144
|
def setup_celluloid_exception_handler
|
107
145
|
Celluloid.task_class = defined?(Celluloid::TaskThread) ? Celluloid::TaskThread : Celluloid::Task::Threaded
|
108
146
|
Celluloid.exception_handler do |ex|
|
109
|
-
|
147
|
+
unless filtered_error?(ex)
|
148
|
+
puts ex
|
149
|
+
puts ex.backtrace
|
150
|
+
puts ex.cause
|
151
|
+
end
|
110
152
|
end
|
111
153
|
end
|
154
|
+
# :nocov:
|
112
155
|
|
113
156
|
# creates the log file where the debug messages will be printed
|
114
157
|
#
|
115
158
|
# @return [void]
|
116
159
|
#
|
117
160
|
# @api private
|
161
|
+
# :nocov:
|
118
162
|
def setup_log_file
|
119
163
|
return if !debug_enabled? || (respond_to?(:log_file_path) && log_file_path.blank?)
|
120
164
|
FileUtils.mkdir_p(File.dirname(log_file_path)) unless File.directory?(log_file_path)
|
121
|
-
log_file = File.open(log_file_path, '
|
165
|
+
log_file = File.open(log_file_path, 'wb')
|
122
166
|
log_file.sync = true
|
123
167
|
end
|
168
|
+
# :nocov:
|
124
169
|
|
125
170
|
# checks if a given error needs to be filtered
|
126
171
|
#
|
@@ -143,9 +188,8 @@ module CelluloidPubsub
|
|
143
188
|
#
|
144
189
|
# @api private
|
145
190
|
def parse_options(options)
|
146
|
-
options = options.is_a?(Array) ? options.
|
147
|
-
options
|
148
|
-
options
|
191
|
+
options = options.is_a?(Array) ? options.last : options
|
192
|
+
options.is_a?(Hash) ? options.deep_stringify_keys : {}
|
149
193
|
end
|
150
194
|
|
151
195
|
# receives a message, and logs it to the log file if debug is enabled
|
@@ -155,8 +199,12 @@ module CelluloidPubsub
|
|
155
199
|
# @return [void]
|
156
200
|
#
|
157
201
|
# @api private
|
202
|
+
# :nocov:
|
158
203
|
def log_debug(message)
|
159
|
-
|
204
|
+
return unless respond_to?(:debug_enabled?)
|
205
|
+
return if Celluloid.logger.blank? || !debug_enabled?
|
206
|
+
Celluloid.logger.debug(message)
|
160
207
|
end
|
208
|
+
# :nocov:
|
161
209
|
end
|
162
210
|
end
|