message_bus 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7ff8ef38b49e1ca6d2fa08b0f56a62929247d71256ea5e717c2952dde35b63bf
4
- data.tar.gz: 158ca236805f872f60737d3af030bb38319c0b7355499b9c9d26006cb001121f
3
+ metadata.gz: d4103e822baabb87e382a7c3c960605fa31d737fd89ed2b2f2036a9983fbf8fc
4
+ data.tar.gz: d3f83ce786dd1a06b495a3773041145bea990869462238d46e723c4f9e82a0e7
5
5
  SHA512:
6
- metadata.gz: b8b0a6c5079e5a1fd025dbaa8bde07140160fc9041ee7ac25defb32fb658c5817472efe1a98f25875e67e74ce81d1ff20ab32209f89af995ff87529bb5c8da92
7
- data.tar.gz: 40baa9cb6ca20f986591ee766f1c52fbc6a73595b5beca94f2d80be1211915668f5555fd4a1c9db80b9ddf191e3dd065d9d244c4356b8c47420aca62102cb375
6
+ metadata.gz: f2623043461d284141e727cd28c20750d544ac6edc047c2332f1f306bceb6afc79f154261d4f94085cc6f18396274c2d9ec8fc662cb6185c54e7220675f352c2
7
+ data.tar.gz: 12b3027295123f1c17468ef56920c19f57aeec82bc9ffb75bb0054fb8a426560c52f552b5150f02cab02ae3979a3161777bd2ae42d023aee53e1a2b37d41f772
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ - Unreleased
2
+
3
+ - FEATURE: `MessageBus.base_route=` to alter the route that message bus will listen on.
4
+
5
+ 07-05-2020
6
+
1
7
  - Version 3.2.0
2
8
 
3
9
  - FIX: compatability with Rails 6.0.3, note: apps without ActionDispatch::Flash may stop working after this upgrade
data/README.md CHANGED
@@ -319,7 +319,7 @@ minPollInterval|100|When polling requests succeed, this is the minimum amount of
319
319
  maxPollInterval|180000|If request to the server start failing, MessageBus will backoff, this is the upper limit of the backoff.
320
320
  alwaysLongPoll|false|For debugging you may want to disable the "is browser in background" check and always long-poll
321
321
  shouldLongPollCallback|undefined|A callback returning true or false that determines if we should long-poll or not, if unset ignore and simply depend on window visibility.
322
- baseUrl|/|If message bus is mounted at a sub-path or different domain, you may configure it to perform requests there
322
+ baseUrl|/|If message bus is mounted at a sub-path or different domain, you may configure it to perform requests there. See `MessageBus.base_route=` on how to configure the MessageBus server to listen on a sub-path.
323
323
  ajax|$.ajax falling back to XMLHttpRequest|MessageBus will first attempt to use jQuery and then fallback to a plain XMLHttpRequest version that's contained in the `message-bus-ajax.js` file. `message-bus-ajax.js` must be loaded after `message-bus.js` for it to be used. You may override this option with a function that implements an ajax request by some other means
324
324
  headers|{}|Extra headers to be include with requests. Properties and values of object must be valid values for HTTP Headers, i.e. no spaces or control characters.
325
325
  minHiddenPollInterval|1500|Time to wait between poll requests performed by background or hidden tabs and windows, shared state via localStorage
@@ -341,8 +341,6 @@ enableChunkedEncoding|true|Allows streaming of message bus data over the HTTP co
341
341
 
342
342
  `MessageBus.status()` : Returns status (started, paused, stopped)
343
343
 
344
- `MessageBus.noConflict()` : Removes MessageBus from the global namespace by replacing it with whatever was present before MessageBus was loaded. Returns a reference to the MessageBus object.
345
-
346
344
  `MessageBus.diagnostics()` : Returns a log that may be used for diagnostics on the status of message bus.
347
345
 
348
346
  #### Ruby
@@ -1,55 +1,52 @@
1
1
  /*jshint bitwise: false*/
2
- (function(global, document, undefined) {
2
+
3
+ (function (root, factory) {
4
+ if (typeof define === 'function' && define.amd) {
5
+ // AMD. Register as an anonymous module.
6
+ define([], function (b) {
7
+ // Also create a global in case some scripts
8
+ // that are loaded still are looking for
9
+ // a global even when an AMD loader is in use.
10
+ return (root.MessageBus = factory());
11
+ });
12
+ } else {
13
+ // Browser globals
14
+ root.MessageBus = factory();
15
+ }
16
+ }(typeof self !== 'undefined' ? self : this, function () {
3
17
  "use strict";
4
- var previousMessageBus = global.MessageBus;
5
18
 
6
19
  // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
7
- var callbacks,
8
- clientId,
9
- failCount,
10
- shouldLongPoll,
11
- queue,
12
- responseCallbacks,
13
- uniqueId,
14
- baseUrl;
15
- var me,
16
- started,
17
- stopped,
18
- longPoller,
19
- pollTimeout,
20
- paused,
21
- later,
22
- jQuery,
23
- interval,
24
- chunkedBackoff;
25
- var delayPollTimeout;
26
-
27
- var ajaxInProgress = false;
28
-
29
- uniqueId = function() {
20
+ var uniqueId = function() {
30
21
  return "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, function(c) {
31
- var r, v;
32
- r = (Math.random() * 16) | 0;
33
- v = c === "x" ? r : (r & 0x3) | 0x8;
22
+ var r = (Math.random() * 16) | 0;
23
+ var v = c === "x" ? r : (r & 0x3) | 0x8;
34
24
  return v.toString(16);
35
25
  });
36
26
  };
37
27
 
38
- clientId = uniqueId();
39
- responseCallbacks = {};
40
- callbacks = [];
41
- queue = [];
42
- interval = null;
43
- failCount = 0;
44
- baseUrl = "/";
45
- paused = false;
46
- later = [];
47
- chunkedBackoff = 0;
48
- jQuery = global.jQuery;
49
- var hiddenProperty;
50
-
51
- (function() {
28
+ var me;
29
+ var delayPollTimeout;
30
+ var ajaxInProgress = false;
31
+ var started = false;
32
+ var clientId = uniqueId();
33
+ var callbacks = [];
34
+ var queue = [];
35
+ var interval = null;
36
+ var failCount = 0;
37
+ var baseUrl = "/";
38
+ var paused = false;
39
+ var later = [];
40
+ var chunkedBackoff = 0;
41
+ var stopped;
42
+ var pollTimeout = null;
43
+ var totalAjaxFailures = 0;
44
+ var totalAjaxCalls = 0;
45
+ var lastAjax;
46
+
47
+ var isHidden = (function() {
52
48
  var prefixes = ["", "webkit", "ms", "moz"];
49
+ var hiddenProperty;
53
50
  for (var i = 0; i < prefixes.length; i++) {
54
51
  var prefix = prefixes[i];
55
52
  var check = prefix + (prefix === "" ? "hidden" : "Hidden");
@@ -57,15 +54,15 @@
57
54
  hiddenProperty = check;
58
55
  }
59
56
  }
60
- })();
61
57
 
62
- var isHidden = function() {
63
- if (hiddenProperty !== undefined) {
64
- return document[hiddenProperty];
65
- } else {
66
- return !document.hasFocus;
67
- }
68
- };
58
+ return function() {
59
+ if (hiddenProperty !== undefined) {
60
+ return document[hiddenProperty];
61
+ } else {
62
+ return !document.hasFocus;
63
+ }
64
+ };
65
+ })();
69
66
 
70
67
  var hasLocalStorage = (function() {
71
68
  try {
@@ -98,24 +95,19 @@
98
95
  return me.enableChunkedEncoding && hasonprogress;
99
96
  };
100
97
 
101
- shouldLongPoll = function() {
98
+ var shouldLongPoll = function() {
102
99
  return (
103
100
  me.alwaysLongPoll ||
104
101
  (me.shouldLongPollCallback ? me.shouldLongPollCallback() : !isHidden())
105
102
  );
106
103
  };
107
104
 
108
- var totalAjaxFailures = 0;
109
- var totalAjaxCalls = 0;
110
- var lastAjax;
111
-
112
105
  var processMessages = function(messages) {
113
106
  var gotData = false;
114
- if (!messages) return false; // server unexpectedly closed connection
107
+ if ((!messages) || (messages.length === 0)) { return false; }
115
108
 
116
109
  for (var i = 0; i < messages.length; i++) {
117
110
  var message = messages[i];
118
- gotData = true;
119
111
  for (var j = 0; j < callbacks.length; j++) {
120
112
  var callback = callbacks[j];
121
113
  if (callback.channel === message.channel) {
@@ -141,7 +133,7 @@
141
133
  }
142
134
  }
143
135
 
144
- return gotData;
136
+ return true;
145
137
  };
146
138
 
147
139
  var reqSuccess = function(messages) {
@@ -158,7 +150,7 @@
158
150
  return false;
159
151
  };
160
152
 
161
- longPoller = function(poll, data) {
153
+ var longPoller = function(poll, data) {
162
154
  if (ajaxInProgress) {
163
155
  // never allow concurrent ajax reqs
164
156
  return;
@@ -180,9 +172,7 @@
180
172
  chunked = false;
181
173
  }
182
174
 
183
- var headers = {
184
- "X-SILENCE-LOGGER": "true"
185
- };
175
+ var headers = { "X-SILENCE-LOGGER": "true" };
186
176
  for (var name in me.headers) {
187
177
  headers[name] = me.headers[name];
188
178
  }
@@ -383,11 +373,7 @@
383
373
  shouldLongPollCallback: undefined,
384
374
  baseUrl: baseUrl,
385
375
  headers: {},
386
- ajax: jQuery && jQuery.ajax,
387
- noConflict: function() {
388
- global.MessageBus = global.MessageBus.previousMessageBus;
389
- return this;
390
- },
376
+ ajax: typeof jQuery !== "undefined" && jQuery.ajax,
391
377
  diagnostics: function() {
392
378
  console.log("Stopped: " + stopped + " Started: " + started);
393
379
  console.log("Current callbacks");
@@ -429,15 +415,11 @@
429
415
 
430
416
  // Start polling
431
417
  start: function() {
432
- var poll;
433
-
434
418
  if (started) return;
435
419
  started = true;
436
420
  stopped = false;
437
421
 
438
- poll = function() {
439
- var data;
440
-
422
+ var poll = function() {
441
423
  if (stopped) {
442
424
  return;
443
425
  }
@@ -452,7 +434,7 @@
452
434
  return;
453
435
  }
454
436
 
455
- data = {};
437
+ var data = {};
456
438
  for (var i = 0; i < callbacks.length; i++) {
457
439
  data[callbacks[i].channel] = callbacks[i].last_id;
458
440
  }
@@ -466,7 +448,7 @@
466
448
 
467
449
  // monitor visibility, issue a new long poll when the page shows
468
450
  if (document.addEventListener && "hidden" in document) {
469
- me.visibilityEvent = global.document.addEventListener(
451
+ me.visibilityEvent = document.addEventListener(
470
452
  "visibilitychange",
471
453
  function() {
472
454
  if (!document.hidden && !me.longPoll && pollTimeout) {
@@ -532,7 +514,7 @@
532
514
  // TODO allow for globbing in the middle of a channel name
533
515
  // like /something/*/something
534
516
  // at the moment we only support globbing /something/*
535
- var glob;
517
+ var glob = false;
536
518
  if (channel.indexOf("*", channel.length - 1) !== -1) {
537
519
  channel = channel.substr(0, channel.length - 1);
538
520
  glob = true;
@@ -567,5 +549,5 @@
567
549
  return removed;
568
550
  }
569
551
  };
570
- global.MessageBus = me;
571
- })(window, document);
552
+ return me;
553
+ }));
@@ -149,6 +149,19 @@ module MessageBus::Implementation
149
149
  @config[:long_polling_interval] || 25 * 1000
150
150
  end
151
151
 
152
+ # @param [String] route Message bus will listen to requests on this route.
153
+ # @return [void]
154
+ def base_route=(route)
155
+ configure(base_route: route.gsub(Regexp.new('\A(?!/)|(?<!/)\Z|//+'), "/"))
156
+ end
157
+
158
+ # @return [String] the route that message bus will respond to. If not
159
+ # explicitly set, defaults to "/". Requests to "#{base_route}message-bus/*" will be handled
160
+ # by the message bus server.
161
+ def base_route
162
+ @config[:base_route] || "/"
163
+ end
164
+
152
165
  # @return [Boolean] whether the bus is disabled or not
153
166
  def off?
154
167
  @off
@@ -16,9 +16,9 @@ class MessageBus::Rack::Diagnostics
16
16
  # Process an HTTP request from a subscriber client
17
17
  # @param [Rack::Request::Env] env the request environment
18
18
  def call(env)
19
- return @app.call(env) unless env['PATH_INFO'].start_with? '/message-bus/_diagnostics'
19
+ return @app.call(env) unless env['PATH_INFO'].start_with? "#{@bus.base_route}message-bus/_diagnostics"
20
20
 
21
- route = env['PATH_INFO'].split('/message-bus/_diagnostics')[1]
21
+ route = env['PATH_INFO'].split("#{@bus.base_route}message-bus/_diagnostics")[1]
22
22
 
23
23
  if @bus.is_admin_lookup.nil? || !@bus.is_admin_lookup.call(env)
24
24
  return [403, {}, ['not allowed']]
@@ -39,6 +39,10 @@ class MessageBus::Rack::Middleware
39
39
  @bus = config[:message_bus] || MessageBus
40
40
  @connection_manager = MessageBus::ConnectionManager.new(@bus)
41
41
  @started_listener = false
42
+ @base_route = "#{@bus.base_route}message-bus/"
43
+ @base_route_length = @base_route.length
44
+ @diagnostics_route = "#{@base_route}_diagnostics"
45
+ @broadcast_route = "#{@base_route}broadcast"
42
46
  start_listener unless @bus.off?
43
47
  end
44
48
 
@@ -54,7 +58,7 @@ class MessageBus::Rack::Middleware
54
58
  # Process an HTTP request from a subscriber client
55
59
  # @param [Rack::Request::Env] env the request environment
56
60
  def call(env)
57
- return @app.call(env) unless env['PATH_INFO'] =~ /^\/message-bus\//
61
+ return @app.call(env) unless env['PATH_INFO'].start_with? @base_route
58
62
 
59
63
  handle_request(env)
60
64
  end
@@ -63,18 +67,18 @@ class MessageBus::Rack::Middleware
63
67
 
64
68
  def handle_request(env)
65
69
  # special debug/test route
66
- if @bus.allow_broadcast? && env['PATH_INFO'] == '/message-bus/broadcast'
70
+ if @bus.allow_broadcast? && env['PATH_INFO'] == @broadcast_route
67
71
  parsed = Rack::Request.new(env)
68
72
  @bus.publish parsed["channel"], parsed["data"]
69
73
  return [200, { "Content-Type" => "text/html" }, ["sent"]]
70
74
  end
71
75
 
72
- if env['PATH_INFO'].start_with? '/message-bus/_diagnostics'
76
+ if env['PATH_INFO'].start_with? @diagnostics_route
73
77
  diags = MessageBus::Rack::Diagnostics.new(@app, message_bus: @bus)
74
78
  return diags.call(env)
75
79
  end
76
80
 
77
- client_id = env['PATH_INFO'].split("/")[2]
81
+ client_id = env['PATH_INFO'][@base_route_length..-1].split("/")[0]
78
82
  return [404, {}, ["not found"]] unless client_id
79
83
 
80
84
  user_id = @bus.user_id_lookup.call(env) if @bus.user_id_lookup
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MessageBus
4
- VERSION = "3.2.0"
4
+ VERSION = "3.3.0"
5
5
  end
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "message-bus-client",
3
+ "version": "3.3.0",
4
+ "description": "A message bus client in Javascript",
5
+ "main": "assets/message-bus.js",
6
+ "keywords": "es6, modules",
7
+ "files": ["assets/message-bus.js"],
8
+ "jsnext:main": "assets/message-bus.js",
9
+ "module": "assets/message-bus.js",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/discourse/message_bus.git"
13
+ },
14
+ "author": "Sam Saffron, Robin Ward",
15
+ "license": "MIT",
16
+ "bugs": {
17
+ "url": "https://github.com/discourse/message_bus/issues"
18
+ },
19
+ "homepage": "https://github.com/discourse/message_bus#readme"
20
+ }
@@ -75,15 +75,6 @@ describe("Messagebus", function() {
75
75
  })
76
76
  });
77
77
 
78
- it('removes itself from root namespace when noConflict is called', function(){
79
- expect(window.MessageBus).not.toBeUndefined();
80
- var mb = window.MessageBus;
81
- expect(mb).toEqual(window.MessageBus.noConflict());
82
- expect(window.MessageBus).toBeUndefined();
83
- // reset it so afterEach has something to work on
84
- window.MessageBus = mb;
85
- });
86
-
87
78
  it('respects minPollInterval setting with defaults', function(){
88
79
  expect(MessageBus.minPollInterval).toEqual(100);
89
80
  MessageBus.minPollInterval = 1000;
@@ -8,11 +8,13 @@ require 'rack/test'
8
8
  describe MessageBus::Rack::Middleware do
9
9
  include Rack::Test::Methods
10
10
  let(:extra_middleware) { nil }
11
+ let(:base_route) { nil }
11
12
 
12
13
  before do
13
14
  bus = @bus = MessageBus::Instance.new
14
15
  @bus.configure(MESSAGE_BUS_CONFIG)
15
16
  @bus.long_polling_enabled = false
17
+ @bus.base_route = base_route if base_route
16
18
 
17
19
  e_m = extra_middleware
18
20
  builder = Rack::Builder.new {
@@ -44,12 +46,27 @@ describe MessageBus::Rack::Middleware do
44
46
  @bus.long_polling_enabled = true
45
47
  end
46
48
 
49
+ describe "with altered base_route" do
50
+ let(:base_route) { "/base/route/" }
51
+
52
+ it "should respond as normal" do
53
+ post "/base/route/message-bus/ABC?dlp=t", '/foo1' => 0
54
+ @async_middleware.in_async?.must_equal false
55
+ last_response.ok?.must_equal true
56
+ end
57
+ end
58
+
47
59
  it "should respond right away if dlp=t" do
48
60
  post "/message-bus/ABC?dlp=t", '/foo1' => 0
49
61
  @async_middleware.in_async?.must_equal false
50
62
  last_response.ok?.must_equal true
51
63
  end
52
64
 
65
+ it "should respond with a 404 if the client_id is missing" do
66
+ post "/message-bus/?dlp=t", '/foo1' => 0
67
+ last_response.not_found?.must_equal true
68
+ end
69
+
53
70
  it "should respond right away to long polls that are polling on -1 with the last_id" do
54
71
  post "/message-bus/ABC", '/foo' => -1
55
72
  last_response.ok?.must_equal true
@@ -141,6 +158,19 @@ describe MessageBus::Rack::Middleware do
141
158
  last_response.status.must_equal 200
142
159
  end
143
160
 
161
+ describe "with an altered base_route" do
162
+ let(:base_route) { "/base/route/" }
163
+
164
+ it "should get a 200 with html for an authorized user" do
165
+ def @bus.is_admin_lookup
166
+ proc { |_| true }
167
+ end
168
+
169
+ get "/base/route/message-bus/_diagnostics"
170
+ last_response.status.must_equal 200
171
+ end
172
+ end
173
+
144
174
  it "should get the script it asks for" do
145
175
 
146
176
  def @bus.is_admin_lookup
@@ -243,6 +273,38 @@ describe MessageBus::Rack::Middleware do
243
273
  parsed[1]["data"].must_equal "borbs"
244
274
  end
245
275
 
276
+ it "should use the correct client ID" do
277
+ id = @bus.last_id('/foo')
278
+
279
+ client_id = "aBc123"
280
+ @bus.publish("/foo", "msg1", client_ids: [client_id])
281
+ @bus.publish("/foo", "msg2", client_ids: ["not_me#{client_id}"])
282
+
283
+ post "/message-bus/#{client_id}",
284
+ '/foo' => id
285
+
286
+ parsed = JSON.parse(last_response.body)
287
+ parsed.length.must_equal 2
288
+ parsed[0]["data"].must_equal("msg1")
289
+ parsed[1]["data"].wont_equal("msg2")
290
+ end
291
+
292
+ it "should use the correct client ID with additional path" do
293
+ id = @bus.last_id('/foo')
294
+
295
+ client_id = "aBc123"
296
+ @bus.publish("/foo", "msg1", client_ids: [client_id])
297
+ @bus.publish("/foo", "msg2", client_ids: ["not_me#{client_id}"])
298
+
299
+ post "/message-bus/#{client_id}/path/not/needed",
300
+ '/foo' => id
301
+
302
+ parsed = JSON.parse(last_response.body)
303
+ parsed.length.must_equal 2
304
+ parsed[0]["data"].must_equal("msg1")
305
+ parsed[1]["data"].wont_equal("msg2")
306
+ end
307
+
246
308
  it "should have no cross talk" do
247
309
  seq = 0
248
310
  @bus.site_id_lookup do
@@ -37,6 +37,23 @@ describe MessageBus do
37
37
  @bus.after_fork
38
38
  end
39
39
 
40
+ describe "#base_route=" do
41
+ it "adds leading and trailing slashes" do
42
+ @bus.base_route = "my/base/route"
43
+ @bus.base_route.must_equal '/my/base/route/'
44
+ end
45
+
46
+ it "leaves existing leading and trailing slashes" do
47
+ @bus.base_route = "/my/base/route/"
48
+ @bus.base_route.must_equal '/my/base/route/'
49
+ end
50
+
51
+ it "removes duplicate slashes" do
52
+ @bus.base_route = "//my///base/route"
53
+ @bus.base_route.must_equal '/my/base/route/'
54
+ end
55
+ end
56
+
40
57
  it "can subscribe from a point in time" do
41
58
  @bus.publish("/minion", "banana")
42
59
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: message_bus
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-07 00:00:00.000000000 Z
11
+ date: 2020-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -113,6 +113,7 @@ files:
113
113
  - lib/message_bus/timer_thread.rb
114
114
  - lib/message_bus/version.rb
115
115
  - message_bus.gemspec
116
+ - package.json
116
117
  - spec/assets/SpecHelper.js
117
118
  - spec/assets/message-bus.spec.js
118
119
  - spec/assets/support/jasmine.yml