message_bus 3.3.5 → 3.3.6

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: 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
+ });