message_bus 3.3.6 → 3.3.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.js +10 -2
  3. data/.github/workflows/ci.yml +36 -19
  4. data/CHANGELOG +15 -8
  5. data/DEV.md +0 -2
  6. data/Gemfile +0 -27
  7. data/LICENSE +1 -1
  8. data/README.md +10 -10
  9. data/Rakefile +12 -7
  10. data/assets/message-bus-ajax.js +3 -3
  11. data/bench/codecs/marshal.rb +1 -1
  12. data/bench/codecs/packed_string.rb +1 -1
  13. data/examples/bench/bench.lua +2 -2
  14. data/lib/message_bus/backends/base.rb +3 -3
  15. data/lib/message_bus/backends/postgres.rb +7 -3
  16. data/lib/message_bus/backends/redis.rb +1 -1
  17. data/lib/message_bus/client.rb +3 -7
  18. data/lib/message_bus/connection_manager.rb +1 -1
  19. data/lib/message_bus/distributed_cache.rb +2 -1
  20. data/lib/message_bus/http_client.rb +2 -2
  21. data/lib/message_bus/rack/diagnostics.rb +30 -8
  22. data/lib/message_bus/rack/middleware.rb +6 -0
  23. data/lib/message_bus/rack/thin_ext.rb +1 -1
  24. data/lib/message_bus/version.rb +1 -1
  25. data/lib/message_bus.rb +6 -6
  26. data/message_bus.gemspec +20 -5
  27. data/package-lock.json +1575 -23
  28. data/package.json +7 -2
  29. data/spec/assets/SpecHelper.js +6 -5
  30. data/spec/assets/message-bus.spec.js +9 -6
  31. data/spec/helpers.rb +17 -6
  32. data/spec/integration/http_client_spec.rb +1 -1
  33. data/spec/lib/message_bus/backend_spec.rb +12 -44
  34. data/spec/lib/message_bus/client_spec.rb +6 -6
  35. data/spec/lib/message_bus/distributed_cache_spec.rb +5 -7
  36. data/spec/lib/message_bus/multi_process_spec.rb +1 -1
  37. data/spec/lib/message_bus/rack/middleware_spec.rb +16 -5
  38. data/spec/lib/message_bus_spec.rb +10 -6
  39. data/spec/spec_helper.rb +8 -9
  40. data/spec/support/jasmine-browser.json +16 -0
  41. metadata +220 -14
  42. data/spec/assets/support/jasmine.yml +0 -126
  43. data/spec/assets/support/jasmine_helper.rb +0 -11
  44. data/vendor/assets/javascripts/message-bus-ajax.js +0 -38
  45. data/vendor/assets/javascripts/message-bus.js +0 -549
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52ac95c63b3775df984e4900aff333c2ea9f9bab7e79d16b85909048247fb709
4
- data.tar.gz: 879fd243f8947150fe8a31307d023b6ca719192568e0def45255dfdddaf1e34f
3
+ metadata.gz: 16601ac02268a477a94bf0347922162f66ce17dfdba1c4c655d576b46e78a79c
4
+ data.tar.gz: 746e2295f873d9cfe75c28b079b406bb42329a992146d414c63292c2148a8f48
5
5
  SHA512:
6
- metadata.gz: fe7252d6965628dd75027af80f775126394e6b3a81be01fd03f538f17fe5e7874e997cea552ee2e92d91b7ee47d17059755e7df995c5b8bab24049ce2746e0a8
7
- data.tar.gz: 2c4ef234bab5ee1701b5bb2d7362929128855dda113a2531dd35f025b9d2be11a2c18a287aa25731e73a9e8f82af898e2f7725a7c9ea4200a390eaff633b4098
6
+ metadata.gz: 3d048dde14c63d5abdda283571cb9c2be1b7fc809a94c7f0b4ec2eaa4785da03bc47535264741f65cfa1d66c75e1b0169ea0de39449456b9c791ba91518d62e9
7
+ data.tar.gz: 0cfbed1cab954e33805c94c7662c9094276615d5f338168da48d26f033da0f42685024b87aaee64d221e192d0592cd655fba7473da8d973616b218ce2858b045
data/.eslintrc.js CHANGED
@@ -4,10 +4,18 @@ module.exports = {
4
4
  browser: true,
5
5
  es2021: false,
6
6
  },
7
- extends: "eslint:recommended",
7
+ extends: 'eslint:recommended',
8
8
  parserOptions: {
9
9
  ecmaVersion: 2015,
10
- sourceType: "module",
10
+ sourceType: 'module',
11
11
  },
12
12
  rules: {},
13
+ ignorePatterns: [
14
+ '/vendor',
15
+ '/doc',
16
+ '/assets/babel.min.js',
17
+ '/assets/jquery-1.8.2.js',
18
+ '/assets/react-dom.js',
19
+ '/assets/react.js',
20
+ ],
13
21
  };
@@ -4,7 +4,7 @@ on:
4
4
  pull_request:
5
5
  push:
6
6
  branches:
7
- - master
7
+ - main
8
8
 
9
9
  env:
10
10
  PGHOST: localhost
@@ -15,40 +15,57 @@ env:
15
15
  jobs:
16
16
  build:
17
17
  runs-on: ubuntu-latest
18
- name: Ruby ${{ matrix.ruby }}
18
+ name: Ruby ${{ matrix.ruby }} (redis ${{ matrix.redis }})
19
+ timeout-minutes: 10
20
+
19
21
  services:
20
22
  postgres:
21
- image: postgres:9.4
23
+ image: postgres:14.0
22
24
  env:
23
25
  POSTGRES_PASSWORD: postgres
24
26
  ports:
25
27
  - 5432:5432
26
28
  options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
29
+ redis:
30
+ image: ${{ format('redis:{0}', matrix.redis) }}
31
+ ports:
32
+ - 6379:6379
33
+ options: >-
34
+ --health-cmd "redis-cli ping"
35
+ --health-interval 10s
36
+ --health-timeout 5s
37
+ --health-retries 5
38
+
27
39
  strategy:
40
+ fail-fast: false
28
41
  matrix:
29
- ruby: ["2.7", "2.6", "2.5"]
42
+ ruby: ["3.0", "2.7", "2.6"]
43
+ redis: ["5", "6"]
44
+
30
45
  steps:
31
46
  - uses: actions/checkout@v2
32
- - uses: actions/setup-ruby@v1
47
+
48
+ - uses: ruby/setup-ruby@v1
33
49
  with:
34
50
  ruby-version: ${{ matrix.ruby }}
35
- - name: Bundler cache
36
- uses: actions/cache@v2
51
+ bundler-cache: true # 'bundle install' and cache
52
+
53
+ - name: Set up Node.js
54
+ uses: actions/setup-node@v2
37
55
  with:
38
- path: vendor/bundle
39
- key: ${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles('**/Gemfile.lock') }}
40
- restore-keys: |
41
- ${{ runner.os }}-${{ matrix.ruby }}-gems-
56
+ node-version: 16
57
+ cache: npm
58
+
59
+ - name: Setup npm
60
+ run: npm install
61
+
42
62
  - name: Create Database
43
63
  run: |
44
64
  createdb message_bus_test
45
- - name: Setup redis
46
- uses: shogo82148/actions-setup-redis@v1
47
- with:
48
- redis-version: '5.x'
49
- - name: Setup gems
50
- run: |
51
- bundle config path vendor/bundle
52
- bundle install --jobs 4
65
+
53
66
  - name: Tests
54
67
  run: bundle exec rake
68
+ timeout-minutes: 3
69
+
70
+ - name: Linting
71
+ run: npx eslint .
data/CHANGELOG CHANGED
@@ -1,10 +1,17 @@
1
+ 15-12-2021
2
+
3
+ - Version 3.3.7
4
+
5
+ - FIX: Prevent simple polling from clobbering the session
6
+ - SECURITY: Fix path traversal on diagnostics route.
7
+
1
8
  31-05-2021
2
9
 
3
10
  - Version 3.3.6
4
11
 
5
12
  - FEATURE: Introduce support for transport codecs
6
13
  - FIX: event subscription leak in JS after start/stop/start sequence
7
- - FEATURE: MessageBus.onVisibilityChange() can be used to trigger a visiblity change check by hand
14
+ - FEATURE: MessageBus.onVisibilityChange() can be used to trigger a visibility change check by hand
8
15
 
9
16
  28-04-2021
10
17
 
@@ -62,7 +69,7 @@
62
69
 
63
70
  - Version 3.2.0
64
71
 
65
- - FIX: compatability with Rails 6.0.3, note: apps without ActionDispatch::Flash may stop working after this upgrade
72
+ - FIX: compatibility with Rails 6.0.3, note: apps without ActionDispatch::Flash may stop working after this upgrade
66
73
  to correct this disable middleware injection with `config.skip_message_bus_middleware = true` and configure middleware by hand with `app.middleware.use(MessageBus::Rack::Middleware)`
67
74
 
68
75
  28-04-2020
@@ -189,7 +196,7 @@
189
196
 
190
197
  - Version 2.1.6
191
198
 
192
- - FEATURE: `MesssageBus.publish` accepts option `site_id` to publish to a site
199
+ - FEATURE: `MessageBus.publish` accepts option `site_id` to publish to a site
193
200
  - FEATURE: Added MessageBus::DistributedCache for cross process caching
194
201
  - PERF: Use monotonic times in timer thread
195
202
  - FEATURE: min poll interval is now configurable client side
@@ -253,7 +260,7 @@
253
260
 
254
261
  - Version 2.0.6
255
262
 
256
- - Fix: correct after_fork so it correctly disconnnects redis
263
+ - Fix: correct after_fork so it correctly disconnects redis
257
264
  - Fix: correct message_bus #destroy used in tests to clean up spec (deadlock)
258
265
  - Fix: deliver backlog unconditionally when polling (and not long polling)
259
266
 
@@ -323,7 +330,7 @@
323
330
 
324
331
  - Version 2.0.0.beta.6
325
332
 
326
- - Feature: Support standalone opertion without depending on jQuery @nathanstitt
333
+ - Feature: Support standalone operation without depending on jQuery @nathanstitt
327
334
  - Feature: Support a noconflict mode @nathanstitt
328
335
  - Feature: Support JSON POST payload @nathanstitt
329
336
 
@@ -369,7 +376,7 @@
369
376
  - Version 1.1.0
370
377
  - Fix: keep track of client sequence on server, abandon old subscribes
371
378
  - Fix: rare concurrency issue when subscribing concurrently
372
- - Fature: remove most jQuery dependency from message-bus.js
379
+ - Feature: remove most jQuery dependency from message-bus.js
373
380
 
374
381
  09-07-2015
375
382
  - Version 1.0.16
@@ -393,7 +400,7 @@
393
400
 
394
401
  28-05-2015
395
402
  - Version 1.0.12
396
- - Feature: Support client_id targetted message
403
+ - Feature: Support client_id targeted message
397
404
 
398
405
  06-05-2015
399
406
  - Version 1.0.11
@@ -402,7 +409,7 @@
402
409
  01-05-2015
403
410
  - Version: 1.0.10
404
411
  - Feature: no longer depends on EventMachine (only used for Thin backend)
405
- - Feature: realiable pub sub will queue messages in memory if redis is readonly, configurable
412
+ - Feature: reliable pub sub will queue messages in memory if redis is readonly, configurable
406
413
  - Fix: if redis is flushed we will continue to deliver messages
407
414
 
408
415
  23-03-2015
data/DEV.md CHANGED
@@ -5,5 +5,3 @@
5
5
  2. Log in to npm `yarn login`
6
6
 
7
7
  3. Publish: `yarn publish`
8
-
9
-
data/Gemfile CHANGED
@@ -3,30 +3,3 @@ source 'https://rubygems.org'
3
3
 
4
4
  # Specify your gem's dependencies in message_bus.gemspec
5
5
  gemspec
6
-
7
- group :test do
8
- gem 'minitest'
9
- gem 'minitest-hooks'
10
- gem 'minitest-global_expectations'
11
- gem 'rake'
12
- gem 'http_parser.rb'
13
- gem 'thin'
14
- gem 'rack-test', require: 'rack/test'
15
- gem 'jasmine'
16
- gem 'puma'
17
- gem 'm'
18
- end
19
-
20
- group :test, :development do
21
- gem 'byebug'
22
- gem 'oj'
23
- end
24
-
25
- group :development do
26
- gem 'yard'
27
- gem 'rubocop-discourse', require: false
28
- gem 'rubocop-rspec', require: false
29
- end
30
-
31
- gem 'rack'
32
- gem 'concurrent-ruby' # for distributed-cache
data/LICENSE CHANGED
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -12,7 +12,7 @@ Read the generated docs: <https://www.rubydoc.info/gems/message_bus>
12
12
 
13
13
  ## Ruby version support
14
14
 
15
- MessageBus only support officially supported versions of Ruby; as of [2018-06-20](https://www.ruby-lang.org/en/news/2018/06/20/support-of-ruby-2-2-has-ended/) this means we only support Ruby version 2.3 and up.
15
+ MessageBus only support officially supported versions of Ruby; as of [2021-03-31](https://www.ruby-lang.org/en/downloads/branches/) this means we only support Ruby version 2.6 and up.
16
16
 
17
17
  ## Can you handle concurrent requests?
18
18
 
@@ -68,19 +68,19 @@ id = MessageBus.last_id("/channel")
68
68
  MessageBus.backlog "/channel", id
69
69
  ```
70
70
 
71
- ### Targetted messages
71
+ ### Targeted messages
72
72
 
73
- Messages can be targetted to particular clients by supplying the `client_ids` option when publishing a message.
73
+ Messages can be targeted to particular clients by supplying the `client_ids` option when publishing a message.
74
74
 
75
75
  ```ruby
76
76
  MessageBus.publish "/channel", "hello", client_ids: ["XXX", "YYY"] # (using MessageBus.clientId)
77
77
  ```
78
78
 
79
- By configuring the `user_id_lookup` and `group_ids_lookup` options with a Proc or Lambda which will be called with a [Rack specification environment](https://github.com/rack/rack/blob/master/SPEC.rdoc#the-environment-), messages can be targetted to particular clients users or groups by supplying either the `user_ids` or `group_ids` options when publishing a message.
79
+ By configuring the `user_id_lookup` and `group_ids_lookup` options with a Proc or Lambda which will be called with a [Rack specification environment](https://github.com/rack/rack/blob/master/SPEC.rdoc#the-environment-), messages can be targeted to particular clients users or groups by supplying either the `user_ids` or `group_ids` options when publishing a message.
80
80
 
81
81
  ```ruby
82
82
  MessageBus.configure(user_id_lookup: proc do |env|
83
- # this lookup occurs on JS-client poolings, so that server can retrieve backlog
83
+ # this lookup occurs on JS-client polling, so that server can retrieve backlog
84
84
  # for the client considering/matching/filtering user_ids set on published messages
85
85
  # if user_id is not set on publish time, any user_id returned here will receive the message
86
86
  # return the user id here
@@ -98,7 +98,7 @@ end)
98
98
  MessageBus.publish "/channel", "hello", group_ids: [1, 2, 3]
99
99
 
100
100
  # example of MessageBus to set user_ids from an initializer in Rails and Devise:
101
- # config/inializers/message_bus.rb
101
+ # config/initializers/message_bus.rb
102
102
  MessageBus.user_id_lookup do |env|
103
103
  req = Rack::Request.new(env)
104
104
 
@@ -109,13 +109,13 @@ MessageBus.user_id_lookup do |env|
109
109
  end
110
110
  ```
111
111
 
112
- If both `user_ids` and `group_ids` options are supplied when publishing a message, the message will be targetted at clients with lookup return values that matches on either the `user_ids` **or** the `group_ids` options.
112
+ If both `user_ids` and `group_ids` options are supplied when publishing a message, the message will be targeted at clients with lookup return values that matches on either the `user_ids` **or** the `group_ids` options.
113
113
 
114
114
  ```ruby
115
115
  MessageBus.publish "/channel", "hello", user_ids: [1, 2, 3], group_ids: [1, 2, 3]
116
116
  ```
117
117
 
118
- If the `client_ids` option is supplied with either the `user_ids` or `group_ids` options when publising a message, the `client_ids` option will be applied unconditionally and messages will be filtered further using `user_id` or `group_id` clauses.
118
+ If the `client_ids` option is supplied with either the `user_ids` or `group_ids` options when publishing a message, the `client_ids` option will be applied unconditionally and messages will be filtered further using `user_id` or `group_id` clauses.
119
119
 
120
120
  ```ruby
121
121
  MessageBus.publish "/channel", "hello", client_ids: ["XXX", "YYY"], user_ids: [1, 2, 3], group_ids: [1, 2, 3]
@@ -245,7 +245,7 @@ end)
245
245
  MessageBus.publish "/channel", "some message"
246
246
 
247
247
  # you can also choose to pass the `:site_id`.
248
- # This takes precendence over whatever `site_id_lookup`
248
+ # This takes precedence over whatever `site_id_lookup`
249
249
  # returns
250
250
  MessageBus.publish "/channel", "some message", site_id: "site-id"
251
251
 
@@ -454,7 +454,7 @@ using a packed string encoder.
454
454
 
455
455
  Keep in mind, much of MessageBus internals and supporting tools expect data to be converted to JSON and back, if you use a naive (and fast) `Marshal` based codec you may need to limit the features you use. Specifically the Postgresql backend expects the codec never to return a string with `\u0000`, additionally some classes like DistributedCache expect keys to be converted to Strings.
456
456
 
457
- Another example may be very large and complicated messages where Oj in compatability mode outperforms JSON. To opt for the Oj codec use:
457
+ Another example may be very large and complicated messages where Oj in compatibility mode outperforms JSON. To opt for the Oj codec use:
458
458
 
459
459
  ```
460
460
  MessageBus.configure(transport_codec: MessageBus::Codec::Oj.new)
data/Rakefile CHANGED
@@ -4,12 +4,8 @@ require 'rake/testtask'
4
4
  require 'bundler'
5
5
  require 'bundler/gem_tasks'
6
6
  require 'bundler/setup'
7
- require 'jasmine'
8
-
9
- ENV['JASMINE_CONFIG_PATH'] ||= File.join(Dir.pwd, 'spec', 'assets', 'support', 'jasmine.yml')
10
- load 'jasmine/tasks/jasmine.rake'
11
-
12
7
  require 'rubocop/rake_task'
8
+
13
9
  RuboCop::RakeTask.new
14
10
 
15
11
  require 'yard'
@@ -35,7 +31,14 @@ module Bundler
35
31
  end
36
32
  end
37
33
 
38
- task spec_client_js: 'jasmine:ci'
34
+ namespace :jasmine do
35
+ desc "Run Jasmine tests in headless mode"
36
+ task 'ci' do
37
+ if !system("npx jasmine-browser-runner runSpecs")
38
+ exit 1
39
+ end
40
+ end
41
+ end
39
42
 
40
43
  backends = Dir["lib/message_bus/backends/*.rb"].map { |file| file.match(%r{backends/(?<backend>.*).rb})[:backend] } - ["base"]
41
44
 
@@ -57,6 +60,8 @@ namespace :spec do
57
60
 
58
61
  desc "Run integration tests"
59
62
  task :integration do
63
+ require "socket"
64
+
60
65
  def port_available?(port)
61
66
  server = TCPServer.open("0.0.0.0", port)
62
67
  server.close
@@ -78,7 +83,7 @@ namespace :spec do
78
83
  end
79
84
 
80
85
  desc "Run tests on all backends, plus client JS tests"
81
- task spec: backends.map { |backend| "spec:#{backend}" } + [:spec_client_js, "spec:integration"]
86
+ task spec: backends.map { |backend| "spec:#{backend}" } + ["jasmine:ci", "spec:integration"]
82
87
 
83
88
  desc "Run performance benchmarks on all backends"
84
89
  task :performance do
@@ -2,7 +2,7 @@
2
2
  // as a fallback if jQuery is not present
3
3
  //
4
4
  // Only implements methods & options used by MessageBus
5
- (function(global, undefined) {
5
+ (function(global) {
6
6
  'use strict';
7
7
  if (!global.MessageBus){
8
8
  throw new Error("MessageBus must be loaded before the ajax adapter");
@@ -16,7 +16,7 @@
16
16
  for (var name in options.headers){
17
17
  xhr.setRequestHeader(name, options.headers[name]);
18
18
  }
19
- xhr.setRequestHeader('Content-Type', 'application/json');
19
+ xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
20
20
  if (options.messageBus.chunked){
21
21
  options.messageBus.onProgressListener(xhr);
22
22
  }
@@ -31,7 +31,7 @@
31
31
  options.complete();
32
32
  }
33
33
  }
34
- xhr.send(JSON.stringify(options.data));
34
+ xhr.send(new URLSearchParams(options.data).toString());
35
35
  return xhr;
36
36
  };
37
37
 
@@ -6,6 +6,6 @@ class MarshalCodec
6
6
  end
7
7
 
8
8
  def decode(payload)
9
- ::Marshal.load(payload)
9
+ ::Marshal.load(payload) # rubocop:disable Security/MarshalLoad
10
10
  end
11
11
  end
@@ -55,7 +55,7 @@ class PackedString
55
55
  end
56
56
 
57
57
  def decode(payload)
58
- result = Marshal.load(payload)
58
+ result = Marshal.load(payload) # rubocop:disable Security/MarshalLoad
59
59
  result["data"] = ::Oj.load(result["data"], @oj_options)
60
60
 
61
61
  if str = result["user_ids"]
@@ -1,9 +1,9 @@
1
1
  -- wrk returns lots of read errors, this is unavoidable cause
2
2
  --
3
- -- 1. There is no internal implmentation of chunked encoding in wrk (which would be ideal)
3
+ -- 1. There is no internal implementation of chunked encoding in wrk (which would be ideal)
4
4
  --
5
5
  -- 2. MessageBus gem does not provide http keepalive (by design), and can not provide content length
6
- -- if MessageBus provided keepalive it would have to be able to redispatch the reqs to rack, something
6
+ -- if MessageBus provided keepalive it would have to be able to re-dispatch requests to rack, something
7
7
  -- that is not supported by the underlying rack hijack protocol, once a req is hijacked it can not be
8
8
  -- returned
9
9
  --
@@ -62,7 +62,7 @@ module MessageBus
62
62
  attr_accessor :max_backlog_size
63
63
  # @return [Integer] the largest permitted size (number of messages) for the global backlog; beyond this capacity, old messages will be dropped.
64
64
  attr_accessor :max_global_backlog_size
65
- # @return [Integer] the longest amount of time a message may live in a backlog before beging removed, in seconds.
65
+ # @return [Integer] the longest amount of time a message may live in a backlog before being removed, in seconds.
66
66
  attr_accessor :max_backlog_age
67
67
  # Typically, backlogs are trimmed whenever we publish to them. This setting allows some tolerance in order to improve performance.
68
68
  # @return [Integer] the interval of publications between which the backlog will not be cleared.
@@ -74,7 +74,7 @@ module MessageBus
74
74
  # @param [Integer] max_backlog_size the largest permitted size (number of messages) for per-channel backlogs; beyond this capacity, old messages will be dropped.
75
75
  def initialize(config = {}, max_backlog_size = 1000); end
76
76
 
77
- # Performs routines specific to the backend that are necessary after a process fork, typically triggerd by a forking webserver. Typically this re-opens sockets to the backend.
77
+ # Performs routines specific to the backend that are necessary after a process fork, typically triggered by a forking webserver. Typically this re-opens sockets to the backend.
78
78
  def after_fork
79
79
  raise ConcreteClassMustImplementError
80
80
  end
@@ -96,7 +96,7 @@ module MessageBus
96
96
  # @param [JSON] data some data to publish to the channel. Must be an object that can be encoded as JSON
97
97
  # @param [Hash] opts
98
98
  # @option opts [Boolean] :queue_in_memory (true) whether or not to hold the message in an in-memory buffer if publication fails, to be re-tried later
99
- # @option opts [Integer] :max_backlog_age (`self.max_backlog_age`) the longest amount of time a message may live in a backlog before beging removed, in seconds
99
+ # @option opts [Integer] :max_backlog_age (`self.max_backlog_age`) the longest amount of time a message may live in a backlog before being removed, in seconds
100
100
  # @option opts [Integer] :max_backlog_size (`self.max_backlog_size`) the largest permitted size (number of messages) for the channel backlog; beyond this capacity, old messages will be dropped
101
101
  #
102
102
  # @return [Integer] the channel-specific ID the message was given
@@ -44,6 +44,7 @@ module MessageBus
44
44
  @listening_on = {}
45
45
  @available = []
46
46
  @allocated = {}
47
+ @subscribe_connection = nil
47
48
  @mutex = Mutex.new
48
49
  @pid = Process.pid
49
50
  end
@@ -131,7 +132,7 @@ module MessageBus
131
132
  listener = Listener.new
132
133
  yield listener
133
134
 
134
- conn = raw_pg_connection
135
+ conn = @subscribe_connection = raw_pg_connection
135
136
  conn.exec "LISTEN #{channel}"
136
137
  listener.do_sub.call
137
138
  while listening_on?(channel, obj)
@@ -145,6 +146,9 @@ module MessageBus
145
146
 
146
147
  conn.exec "UNLISTEN #{channel}"
147
148
  nil
149
+ ensure
150
+ @subscribe_connection&.close
151
+ @subscribe_connection = nil
148
152
  end
149
153
 
150
154
  def unsubscribe
@@ -251,7 +255,7 @@ module MessageBus
251
255
  @clear_every = config[:clear_every] || 1
252
256
  end
253
257
 
254
- # Reconnects to Postgres; used after a process fork, typically triggerd by a forking webserver
258
+ # Reconnects to Postgres; used after a process fork, typically triggered by a forking webserver
255
259
  # @see Base#after_fork
256
260
  def after_fork
257
261
  client.reconnect
@@ -277,7 +281,7 @@ module MessageBus
277
281
  msg = MessageBus::Message.new backlog_id, backlog_id, channel, data
278
282
  payload = msg.encode
279
283
  c.publish postgresql_channel_name, payload
280
- if backlog_id % clear_every == 0
284
+ if backlog_id && backlog_id % clear_every == 0
281
285
  max_backlog_size = (opts && opts[:max_backlog_size]) || self.max_backlog_size
282
286
  max_backlog_age = (opts && opts[:max_backlog_age]) || self.max_backlog_age
283
287
  c.clear_global_backlog(backlog_id, @max_global_backlog_size)
@@ -62,7 +62,7 @@ module MessageBus
62
62
  @max_backlog_age = 604800
63
63
  end
64
64
 
65
- # Reconnects to Redis; used after a process fork, typically triggerd by a forking webserver
65
+ # Reconnects to Redis; used after a process fork, typically triggered by a forking webserver
66
66
  # @see Base#after_fork
67
67
  def after_fork
68
68
  pub_redis.disconnect!
@@ -220,7 +220,7 @@ class MessageBus::Client
220
220
 
221
221
  private
222
222
 
223
- # heavily optimised to avoid all uneeded allocations
223
+ # heavily optimised to avoid all unneeded allocations
224
224
  NEWLINE = "\r\n".freeze
225
225
  COLON_SPACE = ": ".freeze
226
226
  HTTP_11 = "HTTP/1.1 200 OK\r\n".freeze
@@ -261,7 +261,7 @@ class MessageBus::Client
261
261
  @wrote_headers = true
262
262
  end
263
263
 
264
- # chunked encoding may be "re-chunked" by proxies, so add a seperator
264
+ # chunked encoding may be "re-chunked" by proxies, so add a separator
265
265
  postfix = NEWLINE + "|" + NEWLINE
266
266
  data = data.gsub(postfix, NEWLINE + "||" + NEWLINE)
267
267
  chunk_length = data.bytesize + postfix.bytesize
@@ -275,11 +275,7 @@ class MessageBus::Client
275
275
  @async_response << postfix
276
276
  @async_response << NEWLINE
277
277
  else
278
- @io.write(chunk_length.to_s(16))
279
- @io.write(NEWLINE)
280
- @io.write(data)
281
- @io.write(postfix)
282
- @io.write(NEWLINE)
278
+ @io.write(chunk_length.to_s(16) << NEWLINE << data << postfix << NEWLINE)
283
279
  end
284
280
  end
285
281
 
@@ -37,7 +37,7 @@ class MessageBus::ConnectionManager
37
37
  rescue
38
38
  # pipe may be broken, move on
39
39
  end
40
- # turns out you can delete from a set while itereating
40
+ # turns out you can delete from a set while iterating
41
41
  remove_client(client) if client.closed?
42
42
  end
43
43
  end
@@ -45,7 +45,8 @@ module MessageBus
45
45
  hash = current.hash(message.site_id || DEFAULT_SITE_ID)
46
46
 
47
47
  case payload["op"]
48
- when "set" then hash[payload["key"]] = payload["marshalled"] ? Marshal.load(Base64.decode64(payload["value"])) : payload["value"]
48
+ # TODO: consider custom marshal support with a restricted set
49
+ when "set" then hash[payload["key"]] = payload["marshalled"] ? Marshal.load(Base64.decode64(payload["value"])) : payload["value"] # rubocop:disable Security/MarshalLoad
49
50
  when "delete" then hash.delete(payload["key"])
50
51
  when "clear" then hash.clear
51
52
  end
@@ -146,8 +146,8 @@ module MessageBus
146
146
  #
147
147
  # A last_message_id may be provided.
148
148
  # * -1 will subscribe to all new messages
149
- # * -2 will recieve last message + all new messages
150
- # * -3 will recieve last 2 message + all new messages
149
+ # * -2 will receive last message + all new messages
150
+ # * -3 will receive last 2 message + all new messages
151
151
  #
152
152
  # @example Subscribing to a channel with `last_message_id`
153
153
  # client.subscribe("/test", last_message_id: -2) do |payload|
@@ -13,6 +13,15 @@ class MessageBus::Rack::Diagnostics
13
13
  @bus = config[:message_bus] || MessageBus
14
14
  end
15
15
 
16
+ JS_ASSETS = %w{
17
+ jquery-1.8.2.js
18
+ react.js
19
+ react-dom.js
20
+ babel.min.js
21
+ message-bus.js
22
+ application.jsx
23
+ }
24
+
16
25
  # Process an HTTP request from a subscriber client
17
26
  # @param [Rack::Request::Env] env the request environment
18
27
  def call(env)
@@ -39,9 +48,9 @@ class MessageBus::Rack::Diagnostics
39
48
  end
40
49
 
41
50
  asset = route.split('/assets/')[1]
42
- if asset && !asset !~ /\//
51
+
52
+ if asset && JS_ASSETS.include?(asset)
43
53
  content = asset_contents(asset)
44
- split = asset.split('.')
45
54
  return [200, { 'Content-Type' => 'application/javascript;charset=UTF-8' }, [content]]
46
55
  end
47
56
 
@@ -75,6 +84,23 @@ class MessageBus::Rack::Diagnostics
75
84
  File.expand_path("../../../../assets/#{asset}", __FILE__)
76
85
  end
77
86
 
87
+ def script_tags
88
+ tags = []
89
+
90
+ JS_ASSETS.each do |asset|
91
+ type =
92
+ if asset.end_with?('.js')
93
+ 'text/javascript'
94
+ elsif asset.end_with?('.jsx')
95
+ 'text/jsx'
96
+ end
97
+
98
+ tags << js_asset(asset, type)
99
+ end
100
+
101
+ tags.join("\n")
102
+ end
103
+
78
104
  def index
79
105
  html = <<~HTML
80
106
  <!DOCTYPE html>
@@ -83,12 +109,8 @@ class MessageBus::Rack::Diagnostics
83
109
  </head>
84
110
  <body>
85
111
  <div id="app"></div>
86
- #{js_asset "jquery-1.8.2.js"}
87
- #{js_asset "react.js"}
88
- #{js_asset "react-dom.js"}
89
- #{js_asset "babel.min.js"}
90
- #{js_asset "message-bus.js"}
91
- #{js_asset "application.jsx", "text/jsx"}
112
+
113
+ #{script_tags}
92
114
  </body>
93
115
  </html>
94
116
  HTML
@@ -66,6 +66,12 @@ class MessageBus::Rack::Middleware
66
66
  private
67
67
 
68
68
  def handle_request(env)
69
+ # Prevent simple polling from clobbering the session
70
+ # See: https://github.com/discourse/message_bus/issues/257
71
+ if (rack_session_options = env[Rack::RACK_SESSION_OPTIONS])
72
+ rack_session_options[:skip] = true
73
+ end
74
+
69
75
  # special debug/test route
70
76
  if @bus.allow_broadcast? && env['PATH_INFO'] == @broadcast_route
71
77
  parsed = Rack::Request.new(env)
@@ -38,7 +38,7 @@ module Thin
38
38
  end
39
39
  end
40
40
 
41
- # Response whos body is sent asynchronously.
41
+ # Response which body is sent asynchronously.
42
42
  class AsyncResponse
43
43
  include Rack::Response::Helpers
44
44