celluloid_pubsub 0.3.3 → 0.4.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0d8a66626deefeec22f4ab76d4c1193522c0fcd6
4
- data.tar.gz: c34497b740e353741c4f8d4f4ef847769edfce54
3
+ metadata.gz: ef1607ef65dd326efbf983675c21f745babab415
4
+ data.tar.gz: fbcfed23005b8d5b22232396fb5106ef13b69877
5
5
  SHA512:
6
- metadata.gz: d66edfa90a6a35e17cc345bb68131b8f18636c04b7ce4f0a56bffa7a009f9cd73bed2596c08fa3a06dbd2097ad2638fb6fca16e96363d1c683fdaa16a9b5a4ce
7
- data.tar.gz: a225985eb7278dda9f4c08b30bf19dd38e2d13b06488c8aa8207fcae3b29c1b49cc293fa90f9fcdda6a1f9ad28b075850ee4e9201c85afabe2376ef3a1eb9570
6
+ metadata.gz: 081ee9751029919561347195180494667039584a58d71bb4b2d107582b9f26af0e9b8001bb7bcdae6e86ab2d150c1c4bd4b876879ad9797d8762e130c131fbd5
7
+ data.tar.gz: 64492820b1123719845b670a22d58314164604319a341af2d7f24c27e015f55f3a75b1da28f4a1d2c270449f4e008b76970cf8cee17752ff5154ecfbee89cf69
@@ -7,41 +7,29 @@ module CelluloidPubsub
7
7
  # @!attribute actor
8
8
  # @return [Celluloid::Actor] actor to which callbacks will be delegated to
9
9
  #
10
- # @!attribute connect_blk
11
- # @return [Proc] Block that will execute after the connection is opened
12
- #
13
- # @!attribute connection
14
- # @return [Celluloid::WebSocket::Client] A websocket connection that is used to chat witht the webserver
15
- #
16
10
  # @!attribute options
17
11
  # @return [Hash] the options that can be used to connect to webser and send additional data
18
12
  #
19
- # @!attribute hostname
20
- # @return [String] The hostname on which the webserver runs on
21
- #
22
- # @!attribute port
23
- # @return [String] The port on which the webserver runs on
24
- #
25
- # @!attribute path
26
- # @return [String] The hostname on which the webserver runs on
13
+ # @!attribute channel
14
+ # @return [String] The channel to which the client will subscribe to
27
15
  class Client
28
16
  include Celluloid
29
17
  include Celluloid::Logger
30
18
  include CelluloidPubsub::Helper
31
19
 
32
- attr_reader :actor, :connection, :options, :hostname, :port, :path, :channel
20
+ attr_accessor :actor, :options, :channel
33
21
  finalizer :shutdown
34
22
  # receives a list of options that are used to connect to the webserver and an actor to which the callbacks are delegated to
35
23
  # when receiving messages from a channel
36
24
  #
37
25
  # @param [Hash] options the options that can be used to connect to webser and send additional data
38
26
  # @option options [String] :actor The actor that made the connection
27
+ # @option options [String] :channel The channel to which the client will subscribe to once the connection is open
28
+ # @option options [String] :log_file_path The path to the log file where debug messages will be printed, otherwise will use STDOUT
39
29
  # @option options [String]:hostname The hostname on which the webserver runs on
40
30
  # @option options [String] :port The port on which the webserver runs on
41
31
  # @option options [String] :path The request path that the webserver accepts
42
32
  #
43
- # @param [Proc] connect_blk Block that will execute after the connection is opened
44
- #
45
33
  # @return [void]
46
34
  #
47
35
  # @api public
@@ -50,11 +38,15 @@ module CelluloidPubsub
50
38
  @actor ||= @options.fetch('actor', nil)
51
39
  @channel ||= @options.fetch('channel', nil)
52
40
  raise "#{self}: Please provide an actor in the options list!!!" if @actor.blank?
53
- raise "#{self}: Please provide an channel in the options list!!!" if @channel.blank?
54
41
  supervise_actors
55
42
  setup_celluloid_logger
56
43
  end
57
44
 
45
+ # the method will return the path to the log file where debug messages will be printed
46
+ #
47
+ # @return [String, nil] return the path to the log file where debug messages will be printed
48
+ #
49
+ # @api public
58
50
  def log_file_path
59
51
  @log_file_path ||= @options.fetch('log_file_path', nil)
60
52
  end
@@ -80,14 +72,32 @@ module CelluloidPubsub
80
72
  @connection ||= Celluloid::WebSocket::Client.new("ws://#{hostname}:#{port}#{path}", Actor.current)
81
73
  end
82
74
 
75
+ # the method will return the hostname of the server
76
+ #
77
+ #
78
+ # @return [String] the hostname where the server runs on
79
+ #
80
+ # @api public
83
81
  def hostname
84
82
  @hostname ||= @options.fetch('hostname', CelluloidPubsub::WebServer::HOST)
85
83
  end
86
84
 
85
+ # the method will return the port on which the server accepts connections
86
+ #
87
+ #
88
+ # @return [String] the port on which the server accepts connections
89
+ #
90
+ # @api public
87
91
  def port
88
92
  @port ||= @options.fetch('port', CelluloidPubsub::WebServer::PORT)
89
93
  end
90
94
 
95
+ # the method will return the path of the URL on which the servers acccepts the connection
96
+ #
97
+ #
98
+ # @return [String] the URL path that the server is mounted on
99
+ #
100
+ # @api public
91
101
  def path
92
102
  @path ||= @options.fetch('path', CelluloidPubsub::WebServer::PATH)
93
103
  end
@@ -175,11 +185,7 @@ module CelluloidPubsub
175
185
  # @api public
176
186
  def on_open
177
187
  log_debug("#{@actor.class} websocket connection opened")
178
- async.subscribe(@channel)
179
- end
180
-
181
- def log_debug(message)
182
- debug message if debug_enabled?
188
+ async.subscribe(@channel) if @channel.present?
183
189
  end
184
190
 
185
191
  # callback executes when actor receives a message from a subscribed channel
@@ -3,9 +3,9 @@ module CelluloidPubsub
3
3
  module Helper
4
4
  # checks if the message has the successfull subscription action
5
5
  #
6
- # @param [string] message
6
+ # @param [string] message The message that will be checked
7
7
  #
8
- # @return [void]
8
+ # @return [Boolean] return true if message contains key client_action with value 'succesfull_subscription'
9
9
  #
10
10
  # @api public
11
11
  def succesfull_subscription?(message)
@@ -14,6 +14,21 @@ module CelluloidPubsub
14
14
 
15
15
  module_function
16
16
 
17
+ # method used to determine if a action is a subsribe action
18
+ # @param [string] action The action that will be checked
19
+ #
20
+ # @return [Boolean] Returns true if the action equals to 'subscribe'
21
+ #
22
+ # @api public
23
+ def action_subscribe?(action)
24
+ action == 'subscribe'
25
+ end
26
+
27
+ # sets the celluloid logger and the celluloid exception handler
28
+ #
29
+ # @return [void]
30
+ #
31
+ # @api private
17
32
  def setup_celluloid_logger
18
33
  return if !debug_enabled? || (respond_to?(:log_file_path) && log_file_path.blank?)
19
34
  setup_log_file
@@ -21,6 +36,11 @@ module CelluloidPubsub
21
36
  setup_celluloid_exception_handler
22
37
  end
23
38
 
39
+ # sets the celluloid exception handler
40
+ #
41
+ # @return [void]
42
+ #
43
+ # @api private
24
44
  def setup_celluloid_exception_handler
25
45
  Celluloid.task_class = Celluloid::TaskThread
26
46
  Celluloid.exception_handler do |ex|
@@ -28,6 +48,11 @@ module CelluloidPubsub
28
48
  end
29
49
  end
30
50
 
51
+ # creates the log file where the debug messages will be printed
52
+ #
53
+ # @return [void]
54
+ #
55
+ # @api private
31
56
  def setup_log_file
32
57
  return if !debug_enabled? || (respond_to?(:log_file_path) && log_file_path.blank?)
33
58
  FileUtils.mkdir_p(File.dirname(log_file_path)) unless File.directory?(log_file_path)
@@ -35,28 +60,39 @@ module CelluloidPubsub
35
60
  log_file.sync = true
36
61
  end
37
62
 
63
+ # checks if a given error needs to be filtered
64
+ #
65
+ # @param [Exception::Error] error
66
+ #
67
+ # @return [Boolean] returns true if the error should be filtered otherwise false
68
+ #
69
+ # @api private
38
70
  def filtered_error?(error)
39
71
  [Interrupt].any? { |class_name| error.is_a?(class_name) }
40
72
  end
41
73
 
42
- # receives a list of options that are used to configure the webserver
74
+ # receives a list of options that need to be parsed
75
+ # if it is an Array will return the first element , otherwise if it is
76
+ # an Hash will return the hash with string keys, otherwise an empty hash
43
77
  #
44
- # @param [Hash] options the options that can be used to connect to webser and send additional data
45
- # @option options [String]:hostname The hostname on which the webserver runs on
46
- # @option options [Integer] :port The port on which the webserver runs on
47
- # @option options [String] :path The request path that the webserver accepts
48
- # @option options [Boolean] :spy Enable this only if you want to enable debugging for the webserver
49
- # @option options [Integer]:backlog How many connections the server accepts
78
+ # @param [Hash, Array] options the options that need to be parsed
50
79
  #
51
- # @return [void]
80
+ # @return [Hash]
52
81
  #
53
- # @api public
82
+ # @api private
54
83
  def parse_options(options)
55
84
  options = options.is_a?(Array) ? options.first : options
56
85
  options = options.is_a?(Hash) ? options.stringify_keys : {}
57
86
  options
58
87
  end
59
88
 
89
+ # receives a message, and logs it to the log file if debug is enabled
90
+ #
91
+ # @param [Object] message
92
+ #
93
+ # @return [void]
94
+ #
95
+ # @api private
60
96
  def log_debug(message)
61
97
  debug message if respond_to?(:debug_enabled?) && debug_enabled?
62
98
  end
@@ -36,6 +36,12 @@ module CelluloidPubsub
36
36
  async.run
37
37
  end
38
38
 
39
+ # the method will return true if debug is enabled
40
+ #
41
+ #
42
+ # @return [Boolean] returns true if debug is enabled otherwise false
43
+ #
44
+ # @api public
39
45
  def debug_enabled?
40
46
  @server.debug_enabled?
41
47
  end
@@ -71,12 +77,16 @@ module CelluloidPubsub
71
77
  nil
72
78
  end
73
79
 
80
+ # the method will return the reactor's class name used in debug messages
81
+ #
82
+ #
83
+ # @return [Class] returns the reactor's class name used in debug messages
84
+ #
85
+ # @api public
74
86
  def reactor_class
75
87
  self.class
76
88
  end
77
89
 
78
- # :nocov:
79
-
80
90
  # method used to parse a JSON object into a Hash object
81
91
  #
82
92
  # @param [JSON] message
@@ -145,7 +155,8 @@ module CelluloidPubsub
145
155
  # @option json_data [String] :client_action The action based on which the reactor will decide what action should make
146
156
  #
147
157
  # Possible values are:
148
- # unsubscribe_client
158
+ # unsubscribe_all
159
+ # unsubscribe_clients
149
160
  # unsubscribe
150
161
  # subscribe
151
162
  # publish
@@ -166,7 +177,7 @@ module CelluloidPubsub
166
177
  when 'subscribe'
167
178
  async.start_subscriber(channel, json_data)
168
179
  when 'publish'
169
- @server.publish_event(channel, json_data['data'].to_json)
180
+ async.publish_event(channel, json_data['data'].to_json)
170
181
  else
171
182
  handle_unknown_action(json_data)
172
183
  end
@@ -185,6 +196,14 @@ module CelluloidPubsub
185
196
  @server.async.handle_dispatched_message(Actor.current, json_data)
186
197
  end
187
198
 
199
+ # if the reactor has unsubscribed from all his channels will close the websocket connection,
200
+ # otherwise will delete the channel from his channel list
201
+ #
202
+ # @param [String] channel The channel that needs to be deleted from the reactor's list of subscribed channels
203
+ #
204
+ # @return [void]
205
+ #
206
+ # @api public
188
207
  def forget_channel(channel)
189
208
  if @channels.blank?
190
209
  @websocket.close
@@ -254,6 +273,14 @@ module CelluloidPubsub
254
273
  @websocket << message.merge('client_action' => 'successful_subscription', 'channel' => channel).to_json unless @server.redis_enabled?
255
274
  end
256
275
 
276
+ # this method will return a list of all subscribers to a particular channel or a empty array
277
+ #
278
+ #
279
+ # @param [String] channel The channel that will be used to fetch all subscribers from this channel
280
+ #
281
+ # @return [Array] returns a list of all subscribers to a particular channel or a empty array
282
+ #
283
+ # @api public
257
284
  def channel_subscribers(channel)
258
285
  @server.subscribers[channel] || []
259
286
  end
@@ -274,6 +301,23 @@ module CelluloidPubsub
274
301
  @server.subscribers[channel] = channel_subscribers(channel).push(reactor: Actor.current, message: message)
275
302
  end
276
303
 
304
+ # method for publishing data to a channel
305
+ #
306
+ # @param [String] current_topic The Channel to which the reactor instance {CelluloidPubsub::Reactor} will publish the message to
307
+ # @param [Object] message
308
+ #
309
+ # @return [void]
310
+ #
311
+ # @api public
312
+ def publish_event(current_topic, message)
313
+ return if current_topic.blank? || message.blank?
314
+ (@server.subscribers[current_topic] || []).each do |hash|
315
+ hash[:reactor].websocket << message
316
+ end
317
+ rescue => exception
318
+ log_debug("could not publish message #{message} into topic #{current_topic} because of #{exception.inspect}")
319
+ end
320
+
277
321
  # unsubscribes all actors from all channels and terminates the curent actor
278
322
  #
279
323
  # @return [void]
@@ -0,0 +1,274 @@
1
+ require_relative './reactor'
2
+ require_relative './helper'
3
+ module CelluloidPubsub
4
+ # reactor used for redis pubsub
5
+ # @!attribute connected
6
+ # @return [Boolean] returns true if already connected to redis
7
+ # @!attribute connection
8
+ # @return [EM::Hiredis] The connection used for redis
9
+ class RedisReactor < CelluloidPubsub::Reactor
10
+ include Celluloid
11
+ include Celluloid::IO
12
+ include Celluloid::Logger
13
+ include CelluloidPubsub::Helper
14
+
15
+ attr_accessor :connected, :connection
16
+
17
+ alias_method :connected?, :connected
18
+
19
+ # returns true if already connected to redis otherwise false
20
+ #
21
+ # @return [Boolean] returns true if already connected to redis otherwise false
22
+ #
23
+ # @api public
24
+ def connected
25
+ @connected ||= false
26
+ end
27
+
28
+ # method used to unsubscribe from a channel
29
+ # @see #redis_action
30
+ #
31
+ # @return [void]
32
+ #
33
+ # @api public
34
+ def unsubscribe(channel)
35
+ super
36
+ async.redis_action('unsubscribe', channel)
37
+ end
38
+
39
+ # method used to subscribe to a channel
40
+ # @see #redis_action
41
+ #
42
+ # @return [void]
43
+ #
44
+ # @api public
45
+ def add_subscriber_to_channel(channel, message)
46
+ super
47
+ async.redis_action('subscribe', channel, message)
48
+ end
49
+
50
+ # method used to unsubscribe from a channel
51
+ # @see #redis_action
52
+ #
53
+ # @return [void]
54
+ #
55
+ # @api public
56
+ def unsubscribe_from_channel(channel)
57
+ super
58
+ async.redis_action('unsubscribe', channel)
59
+ end
60
+
61
+ # method used to unsubscribe from all channels
62
+ # @see #redis_action
63
+ #
64
+ # @return [void]
65
+ #
66
+ # @api public
67
+ def unsubscribe_all
68
+ @channels.each do |channel|
69
+ async.redis_action('unsubscribe', channel)
70
+ end
71
+ info 'clearing connections'
72
+ shutdown
73
+ end
74
+
75
+ # method used to shutdown the reactor and unsubscribe from all channels
76
+ # @see #redis_action
77
+ #
78
+ # @return [void]
79
+ #
80
+ # @api public
81
+ def shutdown
82
+ @channels.each do |channel|
83
+ redis_action('unsubscribe', channel)
84
+ end if @channels.present?
85
+ super
86
+ end
87
+
88
+ # method used to publish event using redis
89
+ #
90
+ # @return [void]
91
+ #
92
+ # @api public
93
+ def publish_event(topic, data)
94
+ return if topic.blank? || data.blank?
95
+ connect_to_redis do |connection|
96
+ connection.publish(topic, data)
97
+ end
98
+ rescue => exception
99
+ log_debug("could not publish message #{message} into topic #{current_topic} because of #{exception.inspect}")
100
+ end
101
+
102
+ private
103
+
104
+ # method used to run the enventmachine and setup the exception handler
105
+ # @see #run_the_eventmachine
106
+ # @see #setup_em_exception_handler
107
+ #
108
+ # @param [Proc] block the block that will use the connection
109
+ #
110
+ # @return [void]
111
+ #
112
+ # @api private
113
+ def connect_to_redis(&block)
114
+ require 'eventmachine'
115
+ require 'em-hiredis'
116
+ run_the_eventmachine(&block)
117
+ setup_em_exception_handler
118
+ end
119
+
120
+ # method used to connect to redis and yield the connection
121
+ #
122
+ # @param [Proc] block the block that will use the connection
123
+ #
124
+ # @return [void]
125
+ #
126
+ # @api private
127
+ def run_the_eventmachine(&block)
128
+ EM.run do
129
+ @connection ||= EM::Hiredis.connect
130
+ @connected = true
131
+ block.call @connection
132
+ end
133
+ end
134
+
135
+ # method used to setup the eventmachine exception handler
136
+ #
137
+ # @return [void]
138
+ #
139
+ # @api private
140
+ def setup_em_exception_handler
141
+ EM.error_handler do |error|
142
+ debug error unless filtered_error?(error)
143
+ end
144
+ end
145
+
146
+ # method used to fetch the pubsub client from the connection and yield it
147
+ #
148
+ # @return [void]
149
+ #
150
+ # @api private
151
+ def fetch_pubsub
152
+ connect_to_redis do |connection|
153
+ @pubsub ||= connection.pubsub
154
+ yield @pubsub if block_given?
155
+ end
156
+ end
157
+
158
+ # method used to fetch the pubsub client from the connection and yield it
159
+ # @see #action_subscribe
160
+ #
161
+ # @param [string] action The action that will be checked
162
+ # @param [string] channel The channel that reactor has subscribed to
163
+ # @param [string] message The initial message used to subscribe
164
+ #
165
+ # @return [void]
166
+ #
167
+ # @api private
168
+ def action_success(action, channel, message)
169
+ action_subscribe?(action) ? message.merge('client_action' => 'successful_subscription', 'channel' => channel) : nil
170
+ end
171
+
172
+ # method used execute an action (subscribe or unsubscribe ) to redis
173
+ # @see #prepare_redis_action
174
+ # @see #action_success
175
+ # @see #register_subscription_callbacks
176
+ #
177
+ # @param [string] action The action that will be checked
178
+ # @param [string] channel The channel that reactor has subscribed to
179
+ # @param [string] message The initial message used to subscribe
180
+ #
181
+ # @return [void]
182
+ #
183
+ # @api private
184
+ def redis_action(action, channel = nil, message = {})
185
+ fetch_pubsub do |pubsub|
186
+ callback = prepare_redis_action(action)
187
+ success_message = action_success(action, channel, message)
188
+ subscription = pubsub.send(action, channel, callback)
189
+ register_subscription_callbacks(subscription, action, success_message)
190
+ end
191
+ end
192
+
193
+ # method used check if the action is subscribe and write the incoming message to be websocket or log the message otherwise
194
+ # @see #log_unsubscriptions
195
+ # @see #action_subscribe
196
+ #
197
+ # @param [String] action The action that will be checked if it is subscribed
198
+ #
199
+ # @return [void]
200
+ #
201
+ # @api private
202
+ def prepare_redis_action(action)
203
+ log_unsubscriptions(pubsub)
204
+ proc do |subscribed_message|
205
+ action_subscribe?(action) ? (@websocket << subscribed_message) : log_debug(message)
206
+ end
207
+ end
208
+
209
+ # method used to listen to unsubscriptions and log them to log file
210
+ # @see #register_redis_callback
211
+ # @see #register_redis_error_callback
212
+ #
213
+ # @param [EM::Hiredis::PubsubClient] pubsub The pubsub client that will be used to listen to unsubscriptions
214
+ #
215
+ # @return [void]
216
+ #
217
+ # @api private
218
+ def log_unsubscriptions(pubsub)
219
+ pubsub.on(:unsubscribe) do |subscribed_channel, remaining_subscriptions|
220
+ log_debug [:unsubscribe_happened, subscribed_channel, remaining_subscriptions].inspect
221
+ end
222
+ end
223
+
224
+ # method used registers the sucess and error callabacks
225
+ # @see #register_redis_callback
226
+ # @see #register_redis_error_callback
227
+ #
228
+ # @param [EM::DefaultDeferrable] subscription The subscription object
229
+ # @param [string] action The action that will be checked
230
+ # @param [string] sucess_message The initial message used to subscribe
231
+ #
232
+ # @return [void]
233
+ #
234
+ # @api private
235
+ def register_subscription_callbacks(subscription, action, sucess_message = nil)
236
+ register_redis_callback(subscription, sucess_message)
237
+ register_redis_error_callback(subscription, action)
238
+ end
239
+
240
+ # method used to register a success callback and if action is subscribe will write
241
+ # back to the websocket a message that will say it is a successful_subscription
242
+ # If action is something else, will log the incoming message
243
+ # @see #log_debug
244
+ #
245
+ # @param [EM::DefaultDeferrable] subscription The subscription object
246
+ # @param [string] sucess_message The initial message used to subscribe
247
+ #
248
+ # @return [void]
249
+ #
250
+ # @api private
251
+ def register_redis_callback(subscription, sucess_message = nil)
252
+ subscription.callback do |subscriptions_ids|
253
+ if sucess_message.present?
254
+ @websocket << sucess_message.merge('subscriptions' => subscriptions_ids).to_json
255
+ else
256
+ log_debug "#{action} success #{success_response.inspect}"
257
+ end
258
+ end
259
+ end
260
+
261
+ # Register an error callback on the deferrable object and logs to file the incoming message
262
+ # @see #log_debug
263
+ #
264
+ # @param [EM::DefaultDeferrable] subscription The subscription object
265
+ # @param [string] action The action that will be checked
266
+ #
267
+ # @return [void]
268
+ #
269
+ # @api private
270
+ def register_redis_error_callback(subscription, action)
271
+ subscription.errback { |reply| log_debug "#{action} error #{reply.inspect}" }
272
+ end
273
+ end
274
+ end
@@ -15,9 +15,9 @@ module CelluloidPubsub
15
15
  # major release version
16
16
  MAJOR = 0
17
17
  # minor release version
18
- MINOR = 3
18
+ MINOR = 4
19
19
  # tiny release version
20
- TINY = 3
20
+ TINY = 1
21
21
  # prelease version ( set this only if it is a prelease)
22
22
  PRE = nil
23
23
 
@@ -13,22 +13,6 @@ module CelluloidPubsub
13
13
  #
14
14
  # @!attribute subscribers
15
15
  # @return [Hash] The hostname on which the webserver runs on
16
- #
17
- # @!attribute backlog
18
- # @return [Integer] Determines how many connections can be used
19
- # Defaults to 1024
20
- #
21
- # @!attribute hostname
22
- # @return [String] The hostname on which the webserver runs on
23
- #
24
- # @!attribute port
25
- # @return [String] The port on which the webserver runs on
26
- #
27
- # @!attribute path
28
- # @return [String] The hostname on which the webserver runs on
29
- #
30
- # @!attribute spy
31
- # @return [Boolean] Enable this only if you want to enable debugging for the webserver
32
16
  class WebServer < Reel::Server::HTTP
33
17
  include Celluloid::Logger
34
18
  include CelluloidPubsub::Helper
@@ -40,7 +24,7 @@ module CelluloidPubsub
40
24
  # The request path that the webserver accepts by default
41
25
  PATH = '/ws'
42
26
 
43
- attr_accessor :options, :subscribers, :backlog, :hostname, :port, :path, :spy, :use_redis, :debug_enabled
27
+ attr_accessor :options, :subscribers
44
28
  finalizer :shutdown
45
29
  # receives a list of options that are used to configure the webserver
46
30
  #
@@ -64,10 +48,22 @@ module CelluloidPubsub
64
48
  super(hostname, port, { spy: spy, backlog: backlog }, &method(:on_connection))
65
49
  end
66
50
 
51
+ # the method will return true if redis can be used otherwise false
52
+ #
53
+ #
54
+ # @return [Boolean] return true if redis can be used otherwise false
55
+ #
56
+ # @api public
67
57
  def use_redis
68
58
  @use_redis ||= @options.fetch('use_redis', false)
69
59
  end
70
60
 
61
+ # the method will return true if debug is enabled otherwise false
62
+ #
63
+ #
64
+ # @return [Boolean] returns true if debug is enabled otherwise false
65
+ #
66
+ # @api public
71
67
  def debug_enabled?
72
68
  @debug_enabled = @options.fetch('enable_debug', false)
73
69
  @debug_enabled == true
@@ -84,66 +80,74 @@ module CelluloidPubsub
84
80
  terminate
85
81
  end
86
82
 
83
+ # the method will return the file path of the log file where debug messages will be printed
84
+ #
85
+ #
86
+ # @return [String] returns the file path of the log file where debug messages will be printed
87
+ #
88
+ # @api public
87
89
  def log_file_path
88
90
  @log_file_path ||= @options.fetch('log_file_path', nil)
89
91
  end
90
92
 
93
+ # the method will return the hostname on which the server is running on
94
+ #
95
+ #
96
+ # @return [String] returns the hostname on which the server is running on
97
+ #
98
+ # @api public
91
99
  def hostname
92
100
  @hostname ||= @options.fetch('hostname', CelluloidPubsub::WebServer::HOST)
93
101
  end
94
102
 
103
+ # the method will return the port on which will accept connections
104
+ #
105
+ #
106
+ # @return [String] returns the port on which will accept connections
107
+ #
108
+ # @api public
95
109
  def port
96
110
  @port ||= @options.fetch('port', CelluloidPubsub::WebServer::PORT)
97
111
  end
98
112
 
113
+ # the method will return the URL path on which will acceept connections
114
+ #
115
+ #
116
+ # @return [String] returns the URL path on which will acceept connections
117
+ #
118
+ # @api public
99
119
  def path
100
120
  @path ||= @options.fetch('path', CelluloidPubsub::WebServer::PATH)
101
121
  end
102
122
 
123
+ # the method will return true if connection to the server should be spied upon
124
+ #
125
+ #
126
+ # @return [Boolean] returns true if connection to the server should be spied upon, otherwise false
127
+ #
128
+ # @api public
103
129
  def spy
104
130
  @spy ||= @options.fetch('spy', false)
105
131
  end
106
132
 
133
+ # the method will return the number of connections allowed to the server
134
+ #
135
+ #
136
+ # @return [Integer] returns the number of connections allowed to the server
137
+ #
138
+ # @api public
107
139
  def backlog
108
140
  @backlog = @options.fetch('backlog', 1024)
109
141
  end
110
142
 
111
- # :nocov:
112
-
113
- def redis_enabled?
114
- use_redis.to_s.downcase == 'true'
115
- end
116
-
117
- # method for publishing data to a channel
143
+ # the method will return true if redis is enabled otherwise false
118
144
  #
119
- # @param [String] current_topic The Channel to which the reactor instance {CelluloidPubsub::Rector} will publish the message to
120
- # @param [Object] message
121
145
  #
122
- # @return [void]
146
+ # @return [Boolean] returns true if redis is enabled otherwise false
123
147
  #
124
148
  # @api public
125
- def publish_event(current_topic, message)
126
- if redis_enabled?
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
146
- end
149
+ def redis_enabled?
150
+ use_redis.to_s.downcase == 'true'
147
151
  end
148
152
 
149
153
  # callback that will execute when receiving new conections
@@ -180,10 +184,24 @@ module CelluloidPubsub
180
184
  end
181
185
  end
182
186
 
187
+ # returns the reactor class that will handle the connection depending if redis is enabled or not
188
+ # @see #redis_enabled?
189
+ #
190
+ # @return [Class] returns the reactor class that will handle the connection depending if redis is enabled or not
191
+ #
192
+ # @api public
183
193
  def reactor_class
184
194
  redis_enabled? ? CelluloidPubsub::RedisReactor : CelluloidPubsub::Reactor
185
195
  end
186
196
 
197
+ # method will instantiate a new reactor object, will link the reactor to the current actor and will dispatch the request to the reactor
198
+ # @see #route_websocket
199
+ #
200
+ # @param [Reel::WebSocket] request The request that was made to the webserver
201
+ #
202
+ # @return [void]
203
+ #
204
+ # @api public
187
205
  def dispatch_websocket_request(request)
188
206
  reactor = reactor_class.new
189
207
  Actor.current.link reactor
@@ -110,7 +110,7 @@ describe CelluloidPubsub::Reactor do
110
110
 
111
111
  it 'publish' do
112
112
  data = { 'client_action' => 'publish', 'channel' => 'some channel', 'data' => 'some data' }
113
- server.expects(:publish_event).with(data['channel'], data['data'].to_json)
113
+ subject.expects(:publish_event).with(data['channel'], data['data'].to_json)
114
114
  subject.delegate_action(data)
115
115
  end
116
116
 
@@ -196,7 +196,7 @@ describe CelluloidPubsub::Reactor do
196
196
  describe '#add_subscriber_to_channel' do
197
197
  let(:channel) { 'some channel' }
198
198
  let(:message) { { a: 'b' } }
199
- let(:subscribers) {mock}
199
+ let(:subscribers) { mock }
200
200
 
201
201
  it 'adds subscribed' do
202
202
  CelluloidPubsub::Registry.channels.stubs(:include?).with(channel).returns(false)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: celluloid_pubsub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - bogdanRada
@@ -419,8 +419,7 @@ files:
419
419
  - lib/celluloid_pubsub/client.rb
420
420
  - lib/celluloid_pubsub/helper.rb
421
421
  - lib/celluloid_pubsub/reactor.rb
422
- - lib/celluloid_pubsub/redis/redis.rb
423
- - lib/celluloid_pubsub/redis/redis_reactor.rb
422
+ - lib/celluloid_pubsub/redis_reactor.rb
424
423
  - lib/celluloid_pubsub/registry.rb
425
424
  - lib/celluloid_pubsub/version.rb
426
425
  - lib/celluloid_pubsub/web_server.rb
@@ -1,38 +0,0 @@
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
@@ -1,96 +0,0 @@
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
- def prepare_redis_action(action)
65
- log_unsubscriptions(pubsub)
66
- proc do |subscribed_message|
67
- action_subscribe?(action) ? (@websocket << subscribed_message) : log_debug(message)
68
- end
69
- end
70
-
71
- def log_unsubscriptions(pubsub)
72
- pubsub.on(:unsubscribe) do |subscribed_channel, remaining_subscriptions|
73
- log_debug [:unsubscribe_happened, subscribed_channel, remaining_subscriptions].inspect
74
- end
75
- end
76
-
77
- def handle_redis_action(subscription, action, sucess_message = nil)
78
- register_redis_callback(subscription, sucess_message)
79
- register_redis_error_callback(subscription, action)
80
- end
81
-
82
- def register_redis_callback(subscription, sucess_message = nil)
83
- subscription.callback do |subscriptions_ids|
84
- if sucess_message.present?
85
- @websocket << sucess_message.merge('subscriptions' => subscriptions_ids).to_json
86
- else
87
- log_debug "#{action} success #{success_response.inspect}"
88
- end
89
- end
90
- end
91
-
92
- def register_redis_error_callback(subscription, action)
93
- subscription.errback { |reply| log_debug "#{action} error #{reply.inspect}" }
94
- end
95
- end
96
- end