message_bus 3.3.5 → 3.3.6

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f34126c192c671b895e7cf912a04ffcb5d05a5a5447786c3f5e3db3595c79004
4
- data.tar.gz: 5a638bf3eb07680d17d93b762bc41d92d8b4c4412d9f3fae3e7410ec2ae67488
3
+ metadata.gz: 52ac95c63b3775df984e4900aff333c2ea9f9bab7e79d16b85909048247fb709
4
+ data.tar.gz: 879fd243f8947150fe8a31307d023b6ca719192568e0def45255dfdddaf1e34f
5
5
  SHA512:
6
- metadata.gz: f7102c7e62cc9854237fab235e2020f318bbdc956ba64f6d0c77c515430df1169bb06e01a9125f71631546daa3dfa1179c971ca207f32a9cda96880b0d9be6c6
7
- data.tar.gz: 91b8e655e1dc27b4f386477d38dea8ef4f44daa658793a2205392135cb2f846a80ac0aca52fc04c9a471990b64cb18c6ea9dbd36818690c28cac0c80f922d8be
6
+ metadata.gz: fe7252d6965628dd75027af80f775126394e6b3a81be01fd03f538f17fe5e7874e997cea552ee2e92d91b7ee47d17059755e7df995c5b8bab24049ce2746e0a8
7
+ data.tar.gz: 2c4ef234bab5ee1701b5bb2d7362929128855dda113a2531dd35f025b9d2be11a2c18a287aa25731e73a9e8f82af898e2f7725a7c9ea4200a390eaff633b4098
data/.eslintrc.js ADDED
@@ -0,0 +1,13 @@
1
+ /*global module*/
2
+ module.exports = {
3
+ env: {
4
+ browser: true,
5
+ es2021: false,
6
+ },
7
+ extends: "eslint:recommended",
8
+ parserOptions: {
9
+ ecmaVersion: 2015,
10
+ sourceType: "module",
11
+ },
12
+ rules: {},
13
+ };
data/.gitignore CHANGED
@@ -18,3 +18,5 @@ tmp
18
18
  *.swp
19
19
  .rubocop-https---raw-githubusercontent-com-discourse-discourse-master--rubocop-yml
20
20
  .byebug_history
21
+ node_modules/
22
+ yarn.lock
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ 31-05-2021
2
+
3
+ - Version 3.3.6
4
+
5
+ - FEATURE: Introduce support for transport codecs
6
+ - 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
8
+
1
9
  28-04-2021
2
10
 
3
11
  - Version 3.3.5
data/Gemfile CHANGED
@@ -14,10 +14,12 @@ group :test do
14
14
  gem 'rack-test', require: 'rack/test'
15
15
  gem 'jasmine'
16
16
  gem 'puma'
17
+ gem 'm'
17
18
  end
18
19
 
19
20
  group :test, :development do
20
21
  gem 'byebug'
22
+ gem 'oj'
21
23
  end
22
24
 
23
25
  group :development do
data/README.md CHANGED
@@ -435,6 +435,31 @@ MessageBus.configure(backend: :memory)
435
435
 
436
436
  The `:clear_every` option supported by the PostgreSQL backend is also supported by the in-memory backend.
437
437
 
438
+
439
+ ### Transport codecs
440
+
441
+ By default MessageBus serializes messages to the backend using JSON. Under most situation this performs extremely well.
442
+
443
+ In some exceptional cases you may consider a different transport codec. To configure a custom codec use:
444
+
445
+ ```ruby
446
+ MessageBus.configure(transport_codec: codec)
447
+ ```
448
+
449
+ A codec class must implement MessageBus::Codec::Base. Specifically an `encode` and `decode` method.
450
+
451
+ See the `bench` directory for examples where the default JSON codec can perform poorly. A specific examples may be
452
+ attempting to distribute a message to a restricted list of thousands of users. In cases like this you may consider
453
+ using a packed string encoder.
454
+
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
+
457
+ Another example may be very large and complicated messages where Oj in compatability mode outperforms JSON. To opt for the Oj codec use:
458
+
459
+ ```
460
+ MessageBus.configure(transport_codec: MessageBus::Codec::Oj.new)
461
+ ```
462
+
438
463
  ### Forking/threading app servers
439
464
 
440
465
  If you're using a forking or threading app server and you're not getting immediate delivery of published messages, you might need to configure your web server to re-connect to the message_bus backend
data/Rakefile CHANGED
@@ -94,5 +94,5 @@ desc "Run all tests, link checks and confirms documentation compiles without err
94
94
  task default: [:spec, :rubocop, :test_doc]
95
95
 
96
96
  Rake::Task['release'].enhance do
97
- sh "npm publish"
97
+ sh "yarn publish"
98
98
  end
@@ -1,9 +1,9 @@
1
- /*jshint bitwise: false*/
1
+ /*global define, jQuery*/
2
2
 
3
3
  (function (root, factory) {
4
- if (typeof define === 'function' && define.amd) {
4
+ if (typeof define === "function" && define.amd) {
5
5
  // AMD. Register as an anonymous module.
6
- define([], function (b) {
6
+ define([], function () {
7
7
  // Also create a global in case some scripts
8
8
  // that are loaded still are looking for
9
9
  // a global even when an AMD loader is in use.
@@ -13,12 +13,12 @@
13
13
  // Browser globals
14
14
  root.MessageBus = factory();
15
15
  }
16
- }(typeof self !== 'undefined' ? self : this, function () {
16
+ })(typeof self !== "undefined" ? self : this, function () {
17
17
  "use strict";
18
18
 
19
19
  // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
20
- var uniqueId = function() {
21
- return "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, function(c) {
20
+ var uniqueId = function () {
21
+ return "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, function (c) {
22
22
  var r = (Math.random() * 16) | 0;
23
23
  var v = c === "x" ? r : (r & 0x3) | 0x8;
24
24
  return v.toString(16);
@@ -42,7 +42,7 @@
42
42
  var totalAjaxCalls = 0;
43
43
  var lastAjax;
44
44
 
45
- var isHidden = (function() {
45
+ var isHidden = (function () {
46
46
  var prefixes = ["", "webkit", "ms", "moz"];
47
47
  var hiddenProperty;
48
48
  for (var i = 0; i < prefixes.length; i++) {
@@ -53,7 +53,7 @@
53
53
  }
54
54
  }
55
55
 
56
- return function() {
56
+ return function () {
57
57
  if (hiddenProperty !== undefined) {
58
58
  return document[hiddenProperty];
59
59
  } else {
@@ -62,7 +62,7 @@
62
62
  };
63
63
  })();
64
64
 
65
- var hasLocalStorage = (function() {
65
+ var hasLocalStorage = (function () {
66
66
  try {
67
67
  localStorage.setItem("mbTestLocalStorage", Date.now());
68
68
  localStorage.removeItem("mbTestLocalStorage");
@@ -72,13 +72,13 @@
72
72
  }
73
73
  })();
74
74
 
75
- var updateLastAjax = function() {
75
+ var updateLastAjax = function () {
76
76
  if (hasLocalStorage) {
77
77
  localStorage.setItem("__mbLastAjax", Date.now());
78
78
  }
79
79
  };
80
80
 
81
- var hiddenTabShouldWait = function() {
81
+ var hiddenTabShouldWait = function () {
82
82
  if (hasLocalStorage && isHidden()) {
83
83
  var lastAjaxCall = parseInt(localStorage.getItem("__mbLastAjax"), 10);
84
84
  var deltaAjax = Date.now() - lastAjaxCall;
@@ -89,19 +89,21 @@
89
89
  };
90
90
 
91
91
  var hasonprogress = new XMLHttpRequest().onprogress === null;
92
- var allowChunked = function() {
92
+ var allowChunked = function () {
93
93
  return me.enableChunkedEncoding && hasonprogress;
94
94
  };
95
95
 
96
- var shouldLongPoll = function() {
96
+ var shouldLongPoll = function () {
97
97
  return (
98
98
  me.alwaysLongPoll ||
99
99
  (me.shouldLongPollCallback ? me.shouldLongPollCallback() : !isHidden())
100
100
  );
101
101
  };
102
102
 
103
- var processMessages = function(messages) {
104
- if ((!messages) || (messages.length === 0)) { return false; }
103
+ var processMessages = function (messages) {
104
+ if (!messages || messages.length === 0) {
105
+ return false;
106
+ }
105
107
 
106
108
  for (var i = 0; i < messages.length; i++) {
107
109
  var message = messages[i];
@@ -133,7 +135,7 @@
133
135
  return true;
134
136
  };
135
137
 
136
- var reqSuccess = function(messages) {
138
+ var reqSuccess = function (messages) {
137
139
  failCount = 0;
138
140
  if (paused) {
139
141
  if (messages) {
@@ -147,7 +149,7 @@
147
149
  return false;
148
150
  };
149
151
 
150
- var longPoller = function(poll, data) {
152
+ var longPoller = function (poll, data) {
151
153
  if (ajaxInProgress) {
152
154
  // never allow concurrent ajax reqs
153
155
  return;
@@ -180,7 +182,7 @@
180
182
 
181
183
  var dataType = chunked ? "text" : "json";
182
184
 
183
- var handle_progress = function(payload, position) {
185
+ var handle_progress = function (payload, position) {
184
186
  var separator = "\r\n|\r\n";
185
187
  var endChunk = payload.indexOf(separator, position);
186
188
 
@@ -203,7 +205,7 @@
203
205
  return handle_progress(payload, endChunk + separator.length);
204
206
  };
205
207
 
206
- var disableChunked = function() {
208
+ var disableChunked = function () {
207
209
  if (me.longPoll) {
208
210
  me.longPoll.abort();
209
211
  chunkedBackoff = 30;
@@ -231,12 +233,12 @@
231
233
  headers: headers,
232
234
  messageBus: {
233
235
  chunked: chunked,
234
- onProgressListener: function(xhr) {
236
+ onProgressListener: function (xhr) {
235
237
  var position = 0;
236
238
  // if it takes longer than 3000 ms to get first chunk, we have some proxy
237
239
  // this is messing with us, so just backoff from using chunked for now
238
240
  var chunkedTimeout = setTimeout(disableChunked, 3000);
239
- return (xhr.onprogress = function() {
241
+ return (xhr.onprogress = function () {
240
242
  clearTimeout(chunkedTimeout);
241
243
  if (
242
244
  xhr.getResponseHeader("Content-Type") ===
@@ -247,9 +249,9 @@
247
249
  position = handle_progress(xhr.responseText, position);
248
250
  }
249
251
  });
250
- }
252
+ },
251
253
  },
252
- xhr: function() {
254
+ xhr: function () {
253
255
  var xhr = jQuery.ajaxSettings.xhr();
254
256
  if (!chunked) {
255
257
  return xhr;
@@ -257,7 +259,7 @@
257
259
  this.messageBus.onProgressListener(xhr);
258
260
  return xhr;
259
261
  },
260
- success: function(messages) {
262
+ success: function (messages) {
261
263
  if (!chunked) {
262
264
  // we may have requested text so jQuery will not parse
263
265
  if (typeof messages === "string") {
@@ -266,7 +268,7 @@
266
268
  gotData = reqSuccess(messages);
267
269
  }
268
270
  },
269
- error: function(xhr, textStatus, err) {
271
+ error: function (xhr, textStatus) {
270
272
  if (xhr.status === 429) {
271
273
  var tryAfter =
272
274
  parseInt(
@@ -285,7 +287,7 @@
285
287
  totalAjaxFailures += 1;
286
288
  }
287
289
  },
288
- complete: function() {
290
+ complete: function () {
289
291
  ajaxInProgress = false;
290
292
 
291
293
  var interval;
@@ -323,14 +325,14 @@
323
325
  }
324
326
 
325
327
  if (started) {
326
- pollTimeout = setTimeout(function() {
328
+ pollTimeout = setTimeout(function () {
327
329
  pollTimeout = null;
328
330
  poll();
329
331
  }, interval);
330
332
  }
331
333
 
332
334
  me.longPoll = null;
333
- }
335
+ },
334
336
  });
335
337
 
336
338
  return req;
@@ -352,7 +354,7 @@
352
354
  baseUrl: baseUrl,
353
355
  headers: {},
354
356
  ajax: typeof jQuery !== "undefined" && jQuery.ajax,
355
- diagnostics: function() {
357
+ diagnostics: function () {
356
358
  console.log("Stopped: " + stopped + " Started: " + started);
357
359
  console.log("Current callbacks");
358
360
  console.log(callbacks);
@@ -369,42 +371,50 @@
369
371
  );
370
372
  },
371
373
 
372
- pause: function() {
374
+ pause: function () {
373
375
  paused = true;
374
376
  },
375
377
 
376
- resume: function() {
378
+ resume: function () {
377
379
  paused = false;
378
380
  processMessages(later);
379
381
  later = [];
380
382
  },
381
383
 
382
- stop: function() {
384
+ stop: function () {
383
385
  stopped = true;
384
386
  started = false;
385
387
  if (delayPollTimeout) {
386
388
  clearTimeout(delayPollTimeout);
387
389
  delayPollTimeout = null;
388
390
  }
391
+ if (pollTimeout) {
392
+ clearTimeout(pollTimeout);
393
+ pollTimeout = null;
394
+ }
389
395
  if (me.longPoll) {
390
396
  me.longPoll.abort();
391
397
  }
398
+ if (me.onVisibilityChange) {
399
+ document.removeEventListener("visibilitychange", me.onVisibilityChange);
400
+ me.onVisibilityChange = null;
401
+ }
392
402
  },
393
403
 
394
404
  // Start polling
395
- start: function() {
405
+ start: function () {
396
406
  if (started) return;
397
407
  started = true;
398
408
  stopped = false;
399
409
 
400
- var poll = function() {
410
+ var poll = function () {
401
411
  if (stopped) {
402
412
  return;
403
413
  }
404
414
 
405
415
  if (callbacks.length === 0 || hiddenTabShouldWait()) {
406
416
  if (!delayPollTimeout) {
407
- delayPollTimeout = setTimeout(function() {
417
+ delayPollTimeout = setTimeout(function () {
408
418
  delayPollTimeout = null;
409
419
  poll();
410
420
  }, parseInt(500 + Math.random() * 500));
@@ -426,25 +436,28 @@
426
436
 
427
437
  // monitor visibility, issue a new long poll when the page shows
428
438
  if (document.addEventListener && "hidden" in document) {
429
- me.visibilityEvent = document.addEventListener(
430
- "visibilitychange",
431
- function() {
432
- if (!document.hidden && !me.longPoll && (pollTimeout || delayPollTimeout)) {
433
- clearTimeout(pollTimeout);
434
- clearTimeout(delayPollTimeout);
435
-
436
- delayPollTimeout = null;
437
- pollTimeout = null;
438
- poll();
439
- }
439
+ me.onVisibilityChange = function () {
440
+ if (
441
+ !document.hidden &&
442
+ !me.longPoll &&
443
+ (pollTimeout || delayPollTimeout)
444
+ ) {
445
+ clearTimeout(pollTimeout);
446
+ clearTimeout(delayPollTimeout);
447
+
448
+ delayPollTimeout = null;
449
+ pollTimeout = null;
450
+ poll();
440
451
  }
441
- );
452
+ };
453
+
454
+ document.addEventListener("visibilitychange", me.onVisibilityChange);
442
455
  }
443
456
 
444
457
  poll();
445
458
  },
446
459
 
447
- status: function() {
460
+ status: function () {
448
461
  if (paused) {
449
462
  return "paused";
450
463
  } else if (started) {
@@ -463,7 +476,7 @@
463
476
  // -2 will recieve last message + all new messages
464
477
  // -3 will recieve last 2 messages + all new messages
465
478
  // if undefined will default to -1
466
- subscribe: function(channel, func, lastId) {
479
+ subscribe: function (channel, func, lastId) {
467
480
  if (!started && !stopped) {
468
481
  me.start();
469
482
  }
@@ -471,7 +484,9 @@
471
484
  if (lastId === null || typeof lastId === "undefined") {
472
485
  lastId = -1;
473
486
  } else if (typeof lastId !== "number") {
474
- throw "lastId has type " + typeof lastId + " but a number was expected.";
487
+ throw (
488
+ "lastId has type " + typeof lastId + " but a number was expected."
489
+ );
475
490
  }
476
491
 
477
492
  if (typeof channel !== "string") {
@@ -481,7 +496,7 @@
481
496
  callbacks.push({
482
497
  channel: channel,
483
498
  func: func,
484
- last_id: lastId
499
+ last_id: lastId,
485
500
  });
486
501
  if (me.longPoll) {
487
502
  me.longPoll.abort();
@@ -491,7 +506,7 @@
491
506
  },
492
507
 
493
508
  // Unsubscribe from a channel
494
- unsubscribe: function(channel, func) {
509
+ unsubscribe: function (channel, func) {
495
510
  // TODO allow for globbing in the middle of a channel name
496
511
  // like /something/*/something
497
512
  // at the moment we only support globbing /something/*
@@ -528,7 +543,7 @@
528
543
  }
529
544
 
530
545
  return removed;
531
- }
546
+ },
532
547
  };
533
548
  return me;
534
- }));
549
+ });