message_bus 2.1.6 → 2.2.0.pre

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.

Potentially problematic release.


This version of message_bus might be problematic. Click here for more details.

Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +13 -92
  3. data/.rubocop_todo.yml +659 -0
  4. data/.travis.yml +1 -1
  5. data/CHANGELOG +61 -0
  6. data/Dockerfile +18 -0
  7. data/Gemfile +3 -1
  8. data/Guardfile +0 -1
  9. data/README.md +188 -101
  10. data/Rakefile +12 -1
  11. data/assets/message-bus.js +1 -1
  12. data/docker-compose.yml +46 -0
  13. data/examples/bench/config.ru +8 -9
  14. data/examples/bench/unicorn.conf.rb +1 -1
  15. data/examples/chat/chat.rb +150 -153
  16. data/examples/minimal/config.ru +2 -3
  17. data/lib/message_bus.rb +224 -36
  18. data/lib/message_bus/backends.rb +7 -0
  19. data/lib/message_bus/backends/base.rb +184 -0
  20. data/lib/message_bus/backends/memory.rb +304 -226
  21. data/lib/message_bus/backends/postgres.rb +359 -318
  22. data/lib/message_bus/backends/redis.rb +380 -337
  23. data/lib/message_bus/client.rb +99 -41
  24. data/lib/message_bus/connection_manager.rb +29 -21
  25. data/lib/message_bus/diagnostics.rb +50 -41
  26. data/lib/message_bus/distributed_cache.rb +5 -7
  27. data/lib/message_bus/message.rb +2 -2
  28. data/lib/message_bus/rack/diagnostics.rb +65 -55
  29. data/lib/message_bus/rack/middleware.rb +64 -44
  30. data/lib/message_bus/rack/thin_ext.rb +13 -9
  31. data/lib/message_bus/rails/railtie.rb +2 -0
  32. data/lib/message_bus/timer_thread.rb +2 -2
  33. data/lib/message_bus/version.rb +2 -1
  34. data/message_bus.gemspec +3 -2
  35. data/spec/assets/support/jasmine_helper.rb +1 -1
  36. data/spec/lib/fake_async_middleware.rb +1 -6
  37. data/spec/lib/message_bus/assets/asset_encoding_spec.rb +3 -3
  38. data/spec/lib/message_bus/backend_spec.rb +409 -0
  39. data/spec/lib/message_bus/client_spec.rb +8 -11
  40. data/spec/lib/message_bus/connection_manager_spec.rb +8 -14
  41. data/spec/lib/message_bus/distributed_cache_spec.rb +0 -4
  42. data/spec/lib/message_bus/multi_process_spec.rb +6 -7
  43. data/spec/lib/message_bus/rack/middleware_spec.rb +47 -43
  44. data/spec/lib/message_bus/timer_thread_spec.rb +0 -2
  45. data/spec/lib/message_bus_spec.rb +59 -43
  46. data/spec/spec_helper.rb +16 -4
  47. metadata +12 -9
  48. data/spec/lib/message_bus/backends/postgres_spec.rb +0 -221
  49. data/spec/lib/message_bus/backends/redis_spec.rb +0 -271
@@ -1,7 +1,6 @@
1
1
  require 'message_bus'
2
2
 
3
- #MessageBus.long_polling_interval = 1000 * 2
3
+ # MessageBus.long_polling_interval = 1000 * 2
4
4
 
5
5
  use MessageBus::Rack::Middleware
6
- run lambda { |env| [200, {"Content-Type" => "text/html"}, ["Howdy"]] }
7
-
6
+ run lambda { |_env| [200, { "Content-Type" => "text/html" }, ["Howdy"]] }
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "monitor"
3
4
  require "set"
4
5
  require "message_bus/version"
@@ -15,13 +16,16 @@ if defined?(::Rails)
15
16
  require 'message_bus/rails/railtie'
16
17
  end
17
18
 
19
+ # @see MessageBus::Implementation
18
20
  module MessageBus; end
19
21
  MessageBus::BACKENDS = {}
20
22
  class MessageBus::InvalidMessage < StandardError; end
21
23
  class MessageBus::BusDestroyed < StandardError; end
22
24
 
25
+ # The main server-side interface to a message bus for the purposes of
26
+ # configuration, publishing and subscribing
23
27
  module MessageBus::Implementation
24
- # Configuration options hash
28
+ # @return [Hash<Symbol => Object>] Configuration options hash
25
29
  attr_reader :config
26
30
 
27
31
  # Like Mutex but safe for recursive calls
@@ -34,10 +38,13 @@ module MessageBus::Implementation
34
38
  @mutex = Synchronizer.new
35
39
  end
36
40
 
41
+ # @param [Boolean] val whether or not to cache static assets for the diagnostics pages
42
+ # @return [void]
37
43
  def cache_assets=(val)
38
44
  configure(cache_assets: val)
39
45
  end
40
46
 
47
+ # @return [Boolean] whether or not to cache static assets for the diagnostics pages
41
48
  def cache_assets
42
49
  if defined? @config[:cache_assets]
43
50
  @config[:cache_assets]
@@ -46,12 +53,17 @@ module MessageBus::Implementation
46
53
  end
47
54
  end
48
55
 
56
+ # @param [Logger] logger a logger object to be used by the bus
57
+ # @return [void]
49
58
  def logger=(logger)
50
59
  configure(logger: logger)
51
60
  end
52
61
 
62
+ # @return [Logger] the logger used by the bus. If not explicitly set,
63
+ # is configured to log to STDOUT at INFO level.
53
64
  def logger
54
65
  return @config[:logger] if @config[:logger]
66
+
55
67
  require 'logger'
56
68
  logger = Logger.new(STDOUT)
57
69
  logger.level = Logger::INFO
@@ -59,32 +71,47 @@ module MessageBus::Implementation
59
71
  logger
60
72
  end
61
73
 
74
+ # @return [Boolean] whether or not chunked encoding is enabled. If not
75
+ # explicitly set, defaults to true.
62
76
  def chunked_encoding_enabled?
63
77
  @config[:chunked_encoding_enabled] == false ? false : true
64
78
  end
65
79
 
80
+ # @param [Boolean] val whether or not to enable chunked encoding
81
+ # @return [void]
66
82
  def chunked_encoding_enabled=(val)
67
83
  configure(chunked_encoding_enabled: val)
68
84
  end
69
85
 
86
+ # @return [Boolean] whether or not long polling is enabled. If not explicitly
87
+ # set, defaults to true.
70
88
  def long_polling_enabled?
71
89
  @config[:long_polling_enabled] == false ? false : true
72
90
  end
73
91
 
92
+ # @param [Boolean] val whether or not to enable long polling
93
+ # @return [void]
74
94
  def long_polling_enabled=(val)
75
95
  configure(long_polling_enabled: val)
76
96
  end
77
97
 
78
- # The number of simultanuous clients we can service
79
- # will revert to polling if we are out of slots
98
+ # @param [Integer] val The number of simultanuous clients we can service;
99
+ # will revert to polling if we are out of slots
100
+ # @return [void]
80
101
  def max_active_clients=(val)
81
102
  configure(max_active_clients: val)
82
103
  end
83
104
 
105
+ # @return [Integer] The number of simultanuous clients we can service;
106
+ # will revert to polling if we are out of slots. Defaults to 1000 if not
107
+ # explicitly set.
84
108
  def max_active_clients
85
109
  @config[:max_active_clients] || 1000
86
110
  end
87
111
 
112
+ # @return [Boolean] whether or not Rack Hijack is enabled. If not explicitly
113
+ # set, will default to true, unless we're on Passenger without the ability
114
+ # to set the advertised_concurrency_level to 0.
88
115
  def rack_hijack_enabled?
89
116
  if @config[:rack_hijack_enabled].nil?
90
117
  enable = true
@@ -104,62 +131,107 @@ module MessageBus::Implementation
104
131
  @config[:rack_hijack_enabled]
105
132
  end
106
133
 
134
+ # @param [Boolean] val whether or not to enable Rack Hijack
135
+ # @return [void]
107
136
  def rack_hijack_enabled=(val)
108
137
  configure(rack_hijack_enabled: val)
109
138
  end
110
139
 
140
+ # @param [Integer] millisecs the long-polling interval in milliseconds
141
+ # @return [void]
111
142
  def long_polling_interval=(millisecs)
112
143
  configure(long_polling_interval: millisecs)
113
144
  end
114
145
 
146
+ # @return [Integer] the long-polling interval in milliseconds. If not
147
+ # explicitly set, defaults to 25,000.
115
148
  def long_polling_interval
116
149
  @config[:long_polling_interval] || 25 * 1000
117
150
  end
118
151
 
152
+ # @return [Boolean] whether the bus is disabled or not
153
+ def off?
154
+ @off
155
+ end
156
+
157
+ # Disables publication to the bus
158
+ # @return [void]
119
159
  def off
120
160
  @off = true
121
161
  end
122
162
 
163
+ # Enables publication to the bus
164
+ # @return [void]
123
165
  def on
124
- @off = false
166
+ @destroyed = @off = false
125
167
  end
126
168
 
169
+ # Overrides existing configuration
170
+ # @param [Hash<Symbol => Object>] config values to merge into existing config
171
+ # @return [void]
127
172
  def configure(config)
128
173
  @config.merge!(config)
129
174
  end
130
175
 
131
- # Allow us to inject a redis db
176
+ # Overrides existing configuration, explicitly enabling the redis backend
177
+ # @param [Hash<Symbol => Object>] config values to merge into existing config
178
+ # @return [void]
132
179
  def redis_config=(config)
133
180
  configure(config.merge(backend: :redis))
134
181
  end
135
182
 
136
183
  alias redis_config config
137
184
 
185
+ # @yield [env] a routine to determine the site ID for a subscriber
186
+ # @yieldparam [optional, Rack::Request::Env] env the subscriber request environment
187
+ # @yieldreturn [optional, String] the site ID for the subscriber
188
+ # @return [void]
138
189
  def site_id_lookup(&blk)
139
190
  configure(site_id_lookup: blk) if blk
140
191
  @config[:site_id_lookup]
141
192
  end
142
193
 
194
+ # @yield [env] a routine to determine the user ID for a subscriber (authenticate)
195
+ # @yieldparam [optional, Rack::Request::Env] env the subscriber request environment
196
+ # @yieldreturn [optional, String, Integer] the user ID for the subscriber
197
+ # @return [void]
143
198
  def user_id_lookup(&blk)
144
199
  configure(user_id_lookup: blk) if blk
145
200
  @config[:user_id_lookup]
146
201
  end
147
202
 
203
+ # @yield [env] a routine to determine the group IDs for a subscriber
204
+ # @yieldparam [optional, Rack::Request::Env] env the subscriber request environment
205
+ # @yieldreturn [optional, Array<String,Integer>] the group IDs for the subscriber
206
+ # @return [void]
148
207
  def group_ids_lookup(&blk)
149
208
  configure(group_ids_lookup: blk) if blk
150
209
  @config[:group_ids_lookup]
151
210
  end
152
211
 
212
+ # @yield [env] a routine to determine if a request comes from an admin user
213
+ # @yieldparam [Rack::Request::Env] env the subscriber request environment
214
+ # @yieldreturn [Boolean] whether or not the request is from an admin user
215
+ # @return [void]
153
216
  def is_admin_lookup(&blk)
154
217
  configure(is_admin_lookup: blk) if blk
155
218
  @config[:is_admin_lookup]
156
219
  end
157
220
 
221
+ # @yield [env, e] a routine to handle exceptions raised when handling a subscriber request
222
+ # @yieldparam [Rack::Request::Env] env the subscriber request environment
223
+ # @yieldparam [Exception] e the exception that was raised
224
+ # @yieldreturn [optional, Array<(Integer,Hash,Array)>] a Rack response to be delivered
225
+ # @return [void]
158
226
  def on_middleware_error(&blk)
159
227
  configure(on_middleware_error: blk) if blk
160
228
  @config[:on_middleware_error]
161
229
  end
162
230
 
231
+ # @yield [env] a routine to determine extra headers to be set on a subscriber response
232
+ # @yieldparam [Rack::Request::Env] env the subscriber request environment
233
+ # @yieldreturn [Hash<String => String>] the extra headers to set on the response
234
+ # @return [void]
163
235
  def extra_response_headers_lookup(&blk)
164
236
  configure(extra_response_headers_lookup: blk) if blk
165
237
  @config[:extra_response_headers_lookup]
@@ -175,10 +247,14 @@ module MessageBus::Implementation
175
247
  @config[:on_disconnect]
176
248
  end
177
249
 
250
+ # @param [Boolean] val whether or not to allow broadcasting (debugging)
251
+ # @return [void]
178
252
  def allow_broadcast=(val)
179
253
  configure(allow_broadcast: val)
180
254
  end
181
255
 
256
+ # @return [Boolean] whether or not broadcasting is allowed. If not explicitly
257
+ # set, defaults to false unless we're in Rails test or development mode.
182
258
  def allow_broadcast?
183
259
  @config[:allow_broadcast] ||=
184
260
  if defined? ::Rails
@@ -188,10 +264,14 @@ module MessageBus::Implementation
188
264
  end
189
265
  end
190
266
 
267
+ # @param [MessageBus::Backend::Base] pub_sub a configured backend
268
+ # @return [void]
191
269
  def reliable_pub_sub=(pub_sub)
192
270
  configure(reliable_pub_sub: pub_sub)
193
271
  end
194
272
 
273
+ # @return [MessageBus::Backend::Base] the configured backend. If not
274
+ # explicitly set, will be loaded based on the configuration provided.
195
275
  def reliable_pub_sub
196
276
  @mutex.synchronize do
197
277
  return nil if @destroyed
@@ -208,16 +288,37 @@ module MessageBus::Implementation
208
288
  end
209
289
  end
210
290
 
291
+ # @return [Symbol] the name of the backend implementation configured
211
292
  def backend
212
293
  @config[:backend] || :redis
213
294
  end
214
295
 
296
+ # Enables diagnostics tracking
297
+ # @return [void]
215
298
  def enable_diagnostics
216
299
  MessageBus::Diagnostics.enable(self)
217
300
  end
218
301
 
302
+ # Publishes a message to a channel
303
+ #
304
+ # @param [String] channel the name of the channel to which the message should be published
305
+ # @param [JSON] data some data to publish to the channel. Must be an object that can be encoded as JSON
306
+ # @param [Hash] opts
307
+ # @option opts [Array<String>] :client_ids (`nil`) the unique client IDs to which the message should be available. If nil, available to all.
308
+ # @option opts [Array<String,Integer>] :user_ids (`nil`) the user IDs to which the message should be available. If nil, available to all.
309
+ # @option opts [Array<String,Integer>] :group_ids (`nil`) the group IDs to which the message should be available. If nil, available to all.
310
+ # @option opts [String] :site_id (`nil`) the site ID to scope the message to; used for hosting multiple
311
+ # applications or instances of an application against a single message_bus
312
+ # @option opts [nil,Integer] :max_backlog_age the longest amount of time a message may live in a backlog before beging removed, in seconds
313
+ # @option opts [nil,Integer] :max_backlog_size the largest permitted size (number of messages) for the channel backlog; beyond this capacity, old messages will be dropped
314
+ #
315
+ # @return [Integer] the channel-specific ID the message was given
316
+ #
317
+ # @raise [MessageBus::BusDestroyed] if the bus is destroyed
318
+ # @raise [MessageBus::InvalidMessage] if attempting to put permission restrictions on a globally-published message
219
319
  def publish(channel, data, opts = nil)
220
320
  return if @off
321
+
221
322
  @mutex.synchronize do
222
323
  raise ::MessageBus::BusDestroyed if @destroyed
223
324
  end
@@ -256,6 +357,17 @@ module MessageBus::Implementation
256
357
  reliable_pub_sub.publish(encoded_channel_name, encoded_data, channel_opts)
257
358
  end
258
359
 
360
+ # Subscribe to messages. Each message will be delivered by yielding to the
361
+ # passed block as soon as it is available. This will block until subscription
362
+ # is terminated.
363
+ #
364
+ # @param [String,nil] channel the name of the channel to which we should
365
+ # subscribe. If `nil`, messages on every channel will be provided.
366
+ #
367
+ # @yield [message] a message-handler block
368
+ # @yieldparam [MessageBus::Message] message each message as it is delivered
369
+ #
370
+ # @return [void]
259
371
  def blocking_subscribe(channel = nil, &blk)
260
372
  if channel
261
373
  reliable_pub_sub.subscribe(encode_channel_name(channel), &blk)
@@ -264,45 +376,78 @@ module MessageBus::Implementation
264
376
  end
265
377
  end
266
378
 
267
- ENCODE_SITE_TOKEN = "$|$"
268
-
269
- # encode channel name to include site
270
- def encode_channel_name(channel, site_id = nil)
271
- if (site_id || site_id_lookup) && !global?(channel)
272
- raise ArgumentError.new channel if channel.include? ENCODE_SITE_TOKEN
273
- "#{channel}#{ENCODE_SITE_TOKEN}#{site_id || site_id_lookup.call}"
274
- else
275
- channel
276
- end
277
- end
278
-
279
- def decode_channel_name(channel)
280
- channel.split(ENCODE_SITE_TOKEN)
281
- end
282
-
379
+ # Subscribe to messages on a particular channel. Each message since the
380
+ # last ID specified will be delivered by yielding to the passed block as
381
+ # soon as it is available. This will not block, but instead the callbacks
382
+ # will be executed asynchronously in a dedicated subscriber thread.
383
+ #
384
+ # @param [String] channel the name of the channel to which we should subscribe
385
+ # @param [#to_i] last_id the channel-specific ID of the last message that the caller received on the specified channel
386
+ #
387
+ # @yield [message] a message-handler block
388
+ # @yieldparam [MessageBus::Message] message each message as it is delivered
389
+ #
390
+ # @return [Proc] the callback block that will be executed
283
391
  def subscribe(channel = nil, last_id = -1, &blk)
284
392
  subscribe_impl(channel, nil, last_id, &blk)
285
393
  end
286
394
 
287
- # subscribe only on current site
395
+ # Subscribe to messages on a particular channel, filtered by the current site
396
+ # (@see #site_id_lookup). Each message since the last ID specified will be
397
+ # delivered by yielding to the passed block as soon as it is available. This
398
+ # will not block, but instead the callbacks will be executed asynchronously
399
+ # in a dedicated subscriber thread.
400
+ #
401
+ # @param [String] channel the name of the channel to which we should subscribe
402
+ # @param [#to_i] last_id the channel-specific ID of the last message that the caller received on the specified channel
403
+ #
404
+ # @yield [message] a message-handler block
405
+ # @yieldparam [MessageBus::Message] message each message as it is delivered
406
+ #
407
+ # @return [Proc] the callback block that will be executed
288
408
  def local_subscribe(channel = nil, last_id = -1, &blk)
289
- site_id = site_id_lookup.call if site_id_lookup && ! global?(channel)
409
+ site_id = site_id_lookup.call if site_id_lookup && !global?(channel)
290
410
  subscribe_impl(channel, site_id, last_id, &blk)
291
411
  end
292
412
 
413
+ # Removes a subscription to a particular channel.
414
+ #
415
+ # @param [String] channel the name of the channel from which we should unsubscribe
416
+ # @param [Proc,nil] blk the callback which should be removed. If `nil`, removes all.
417
+ #
418
+ # @return [void]
293
419
  def unsubscribe(channel = nil, &blk)
294
420
  unsubscribe_impl(channel, nil, &blk)
295
421
  end
296
422
 
423
+ # Removes a subscription to a particular channel, filtered by the current site
424
+ # (@see #site_id_lookup).
425
+ #
426
+ # @param [String] channel the name of the channel from which we should unsubscribe
427
+ # @param [Proc,nil] blk the callback which should be removed. If `nil`, removes all.
428
+ #
429
+ # @return [void]
297
430
  def local_unsubscribe(channel = nil, &blk)
298
431
  site_id = site_id_lookup.call if site_id_lookup
299
432
  unsubscribe_impl(channel, site_id, &blk)
300
433
  end
301
434
 
435
+ # Get messages from the global backlog since the last ID specified
436
+ #
437
+ # @param [#to_i] last_id the global ID of the last message that the caller received
438
+ #
439
+ # @return [Array<MessageBus::Message>] all messages published on any channel since the specified last ID
302
440
  def global_backlog(last_id = nil)
303
441
  backlog(nil, last_id)
304
442
  end
305
443
 
444
+ # Get messages from a channel backlog since the last ID specified, filtered by site
445
+ #
446
+ # @param [String] channel the name of the channel in question
447
+ # @param [#to_i] last_id the channel-specific ID of the last message that the caller received on the specified channel
448
+ # @param [String] site_id the ID of the site by which to filter
449
+ #
450
+ # @return [Array<MessageBus::Message>] all messages published to the specified channel since the specified last ID
306
451
  def backlog(channel = nil, last_id = nil, site_id = nil)
307
452
  old =
308
453
  if channel
@@ -317,10 +462,21 @@ module MessageBus::Implementation
317
462
  old
318
463
  end
319
464
 
320
- def last_id(channel , site_id = nil)
465
+ # Get the ID of the last message published on a channel, filtered by site
466
+ #
467
+ # @param [String] channel the name of the channel in question
468
+ # @param [String] site_id the ID of the site by which to filter
469
+ #
470
+ # @return [Integer] the channel-specific ID of the last message published to the given channel
471
+ def last_id(channel, site_id = nil)
321
472
  reliable_pub_sub.last_id(encode_channel_name(channel, site_id))
322
473
  end
323
474
 
475
+ # Get the last message published on a channel
476
+ #
477
+ # @param [String] channel the name of the channel in question
478
+ #
479
+ # @return [MessageBus::Message] the last message published to the given channel
324
480
  def last_message(channel)
325
481
  if last_id = last_id(channel)
326
482
  messages = backlog(channel, last_id - 1)
@@ -330,12 +486,17 @@ module MessageBus::Implementation
330
486
  end
331
487
  end
332
488
 
333
- # mostly used in tests to detroy entire bus
489
+ # Stops listening for publications and stops executing scheduled tasks.
490
+ # Mostly used in tests to detroy entire bus.
491
+ # @return [void]
334
492
  def destroy
335
493
  return if @destroyed
494
+
336
495
  reliable_pub_sub.global_unsubscribe
337
496
 
338
497
  @mutex.synchronize do
498
+ return if @destroyed
499
+
339
500
  @subscriptions ||= {}
340
501
  @destroyed = true
341
502
  end
@@ -343,6 +504,11 @@ module MessageBus::Implementation
343
504
  timer.stop
344
505
  end
345
506
 
507
+ # Performs routines that are necessary after a process fork, typically
508
+ # triggered by a forking webserver. Performs whatever the backend requires
509
+ # and ensures the server is listening for publications and running
510
+ # scheduled tasks.
511
+ # @return [void]
346
512
  def after_fork
347
513
  reliable_pub_sub.after_fork
348
514
  ensure_subscriber_thread
@@ -350,17 +516,22 @@ module MessageBus::Implementation
350
516
  timer.queue {}
351
517
  end
352
518
 
519
+ # @return [Boolean] whether or not the server is actively listening for
520
+ # publications on the bus
353
521
  def listening?
354
522
  @subscriber_thread && @subscriber_thread.alive?
355
523
  end
356
524
 
357
- # will reset all keys
525
+ # (see MessageBus::Backend::Base#reset!)
358
526
  def reset!
359
- reliable_pub_sub.reset!
527
+ reliable_pub_sub.reset! if reliable_pub_sub
360
528
  end
361
529
 
530
+ # @return [MessageBus::TimerThread] the timer thread used for triggering
531
+ # scheduled routines at specific times/intervals.
362
532
  def timer
363
533
  return @timer_thread if @timer_thread
534
+
364
535
  @timer_thread ||= begin
365
536
  t = MessageBus::TimerThread.new
366
537
  t.on_error do |e|
@@ -370,18 +541,37 @@ module MessageBus::Implementation
370
541
  end
371
542
  end
372
543
 
373
- # set to 0 to disable, anything higher and
374
- # a keepalive will run every N seconds, if it fails
375
- # process is killed
544
+ # @param [Integer] interval the keepalive interval in seconds.
545
+ # Set to 0 to disable; anything higher and a keepalive will run every N
546
+ # seconds. If it fails, the process is killed.
376
547
  def keepalive_interval=(interval)
377
548
  configure(keepalive_interval: interval)
378
549
  end
379
550
 
551
+ # @return [Integer] the keepalive interval in seconds. If not explicitly set,
552
+ # defaults to `60`.
380
553
  def keepalive_interval
381
554
  @config[:keepalive_interval] || 60
382
555
  end
383
556
 
384
- protected
557
+ private
558
+
559
+ ENCODE_SITE_TOKEN = "$|$"
560
+
561
+ # encode channel name to include site
562
+ def encode_channel_name(channel, site_id = nil)
563
+ if (site_id || site_id_lookup) && !global?(channel)
564
+ raise ArgumentError.new channel if channel.include? ENCODE_SITE_TOKEN
565
+
566
+ "#{channel}#{ENCODE_SITE_TOKEN}#{site_id || site_id_lookup.call}"
567
+ else
568
+ channel
569
+ end
570
+ end
571
+
572
+ def decode_channel_name(channel)
573
+ channel.split(ENCODE_SITE_TOKEN)
574
+ end
385
575
 
386
576
  def global?(channel)
387
577
  channel && channel.start_with?('/global/'.freeze)
@@ -410,7 +600,6 @@ module MessageBus::Implementation
410
600
  end
411
601
 
412
602
  def subscribe_impl(channel, site_id, last_id, &blk)
413
-
414
603
  raise MessageBus::BusDestroyed if @destroyed
415
604
 
416
605
  if last_id >= 0
@@ -450,11 +639,11 @@ module MessageBus::Implementation
450
639
  end
451
640
 
452
641
  raise MessageBus::BusDestroyed if @destroyed
642
+
453
643
  blk
454
644
  end
455
645
 
456
646
  def unsubscribe_impl(channel, site_id, &blk)
457
-
458
647
  @mutex.synchronize do
459
648
  if blk
460
649
  @subscriptions[site_id][channel].delete blk
@@ -462,12 +651,12 @@ module MessageBus::Implementation
462
651
  @subscriptions[site_id][channel] = []
463
652
  end
464
653
  end
465
-
466
654
  end
467
655
 
468
656
  def ensure_subscriber_thread
469
657
  @mutex.synchronize do
470
658
  return if (@subscriber_thread && @subscriber_thread.alive?) || @destroyed
659
+
471
660
  @subscriber_thread = new_subscriber_thread
472
661
  end
473
662
  end
@@ -475,7 +664,6 @@ module MessageBus::Implementation
475
664
  MIN_KEEPALIVE = 20
476
665
 
477
666
  def new_subscriber_thread
478
-
479
667
  thread = Thread.new do
480
668
  begin
481
669
  global_subscribe_thread unless @destroyed
@@ -569,7 +757,6 @@ module MessageBus::Implementation
569
757
  a.each(&block) if a
570
758
  end
571
759
  end
572
-
573
760
  end
574
761
 
575
762
  module MessageBus
@@ -578,6 +765,7 @@ module MessageBus
578
765
  end
579
766
 
580
767
  # allows for multiple buses per app
768
+ # @see MessageBus::Implementation
581
769
  class MessageBus::Instance
582
770
  include MessageBus::Implementation
583
771
  end