message_bus 2.2.1 → 2.2.2
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 +4 -4
- data/CHANGELOG +8 -0
- data/assets/message-bus.js +140 -88
- data/lib/message_bus/backends/redis.rb +3 -2
- data/lib/message_bus/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79e90ec066435ef35d00e9184481acdb2a03dbecb41b629dd18584c8a824ae4b
|
4
|
+
data.tar.gz: 8d571923665a26165255e06a4a217ad660b39caad101ae3d3755473d740fd3c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ad3699e51995f038ba76197eed72f9d494f29a3b5ab09be389277cc0b62fe2848eb1d96f090563f75393480768490798c012a16f279f19bbded8b7ea78667d7
|
7
|
+
data.tar.gz: 2e8772dc961eefaa746d3569ff57ceecea034c406a4749177c9ba1139ac6575891d8448c00cd7c4f314acd72794cf886ecd5066beb5925a5f7a3b0520270979c
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
Unreleased
|
2
|
+
|
3
|
+
- Version 2.2.1
|
4
|
+
|
5
|
+
- FEATURE: Support rate limiting by server, 429 status codes are respected and we hold off as needed
|
6
|
+
|
7
|
+
- FIX: In the redis backend make the `is_readonly?` method compatible with the redis gem both pre and post v4.0 when the `client` attribute was removed
|
8
|
+
|
1
9
|
30-04-2019
|
2
10
|
|
3
11
|
- Version 2.2.1
|
data/assets/message-bus.js
CHANGED
@@ -1,20 +1,36 @@
|
|
1
1
|
/*jshint bitwise: false*/
|
2
2
|
(function(global, document, undefined) {
|
3
|
-
|
3
|
+
"use strict";
|
4
4
|
var previousMessageBus = global.MessageBus;
|
5
5
|
|
6
6
|
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
7
|
-
var callbacks,
|
8
|
-
|
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;
|
9
25
|
var delayPollTimeout;
|
10
26
|
|
11
27
|
var ajaxInProgress = false;
|
12
28
|
|
13
29
|
uniqueId = function() {
|
14
|
-
return
|
30
|
+
return "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
15
31
|
var r, v;
|
16
|
-
r = Math.random() * 16 | 0;
|
17
|
-
v = c ===
|
32
|
+
r = (Math.random() * 16) | 0;
|
33
|
+
v = c === "x" ? r : (r & 0x3) | 0x8;
|
18
34
|
return v.toString(16);
|
19
35
|
});
|
20
36
|
};
|
@@ -32,19 +48,19 @@
|
|
32
48
|
jQuery = global.jQuery;
|
33
49
|
var hiddenProperty;
|
34
50
|
|
35
|
-
(function(){
|
36
|
-
var prefixes = ["","webkit","ms","moz"];
|
37
|
-
for(var i=0; i<prefixes.length; i++) {
|
51
|
+
(function() {
|
52
|
+
var prefixes = ["", "webkit", "ms", "moz"];
|
53
|
+
for (var i = 0; i < prefixes.length; i++) {
|
38
54
|
var prefix = prefixes[i];
|
39
55
|
var check = prefix + (prefix === "" ? "hidden" : "Hidden");
|
40
|
-
if(document[check] !== undefined
|
56
|
+
if (document[check] !== undefined) {
|
41
57
|
hiddenProperty = check;
|
42
58
|
}
|
43
59
|
}
|
44
60
|
})();
|
45
61
|
|
46
62
|
var isHidden = function() {
|
47
|
-
if (hiddenProperty !== undefined){
|
63
|
+
if (hiddenProperty !== undefined) {
|
48
64
|
return document[hiddenProperty];
|
49
65
|
} else {
|
50
66
|
return !document.hasFocus;
|
@@ -56,7 +72,7 @@
|
|
56
72
|
localStorage.setItem("mbTestLocalStorage", Date.now());
|
57
73
|
localStorage.removeItem("mbTestLocalStorage");
|
58
74
|
return true;
|
59
|
-
} catch(e) {
|
75
|
+
} catch (e) {
|
60
76
|
return false;
|
61
77
|
}
|
62
78
|
})();
|
@@ -65,7 +81,7 @@
|
|
65
81
|
if (hasLocalStorage) {
|
66
82
|
localStorage.setItem("__mbLastAjax", Date.now());
|
67
83
|
}
|
68
|
-
}
|
84
|
+
};
|
69
85
|
|
70
86
|
var hiddenTabShouldWait = function() {
|
71
87
|
if (hasLocalStorage && isHidden()) {
|
@@ -75,10 +91,10 @@
|
|
75
91
|
return deltaAjax >= 0 && deltaAjax < me.minHiddenPollInterval;
|
76
92
|
}
|
77
93
|
return false;
|
78
|
-
}
|
94
|
+
};
|
79
95
|
|
80
|
-
var hasonprogress =
|
81
|
-
var allowChunked = function(){
|
96
|
+
var hasonprogress = new XMLHttpRequest().onprogress === null;
|
97
|
+
var allowChunked = function() {
|
82
98
|
return me.enableChunkedEncoding && hasonprogress;
|
83
99
|
};
|
84
100
|
|
@@ -94,19 +110,23 @@
|
|
94
110
|
var gotData = false;
|
95
111
|
if (!messages) return false; // server unexpectedly closed connection
|
96
112
|
|
97
|
-
for (var i=0; i<messages.length; i++) {
|
113
|
+
for (var i = 0; i < messages.length; i++) {
|
98
114
|
var message = messages[i];
|
99
115
|
gotData = true;
|
100
|
-
for (var j=0; j<callbacks.length; j++) {
|
116
|
+
for (var j = 0; j < callbacks.length; j++) {
|
101
117
|
var callback = callbacks[j];
|
102
118
|
if (callback.channel === message.channel) {
|
103
119
|
callback.last_id = message.message_id;
|
104
120
|
try {
|
105
121
|
callback.func(message.data, message.global_id, message.message_id);
|
106
|
-
}
|
107
|
-
|
108
|
-
|
109
|
-
|
122
|
+
} catch (e) {
|
123
|
+
if (console.log) {
|
124
|
+
console.log(
|
125
|
+
"MESSAGE BUS FAIL: callback " +
|
126
|
+
callback.channel +
|
127
|
+
" caused exception " +
|
128
|
+
e.stack
|
129
|
+
);
|
110
130
|
}
|
111
131
|
}
|
112
132
|
}
|
@@ -125,7 +145,7 @@
|
|
125
145
|
failCount = 0;
|
126
146
|
if (paused) {
|
127
147
|
if (messages) {
|
128
|
-
for (var i=0; i<messages.length; i++) {
|
148
|
+
for (var i = 0; i < messages.length; i++) {
|
129
149
|
later.push(messages[i]);
|
130
150
|
}
|
131
151
|
}
|
@@ -136,7 +156,6 @@
|
|
136
156
|
};
|
137
157
|
|
138
158
|
longPoller = function(poll, data) {
|
139
|
-
|
140
159
|
if (ajaxInProgress) {
|
141
160
|
// never allow concurrent ajax reqs
|
142
161
|
return;
|
@@ -144,6 +163,9 @@
|
|
144
163
|
|
145
164
|
var gotData = false;
|
146
165
|
var aborted = false;
|
166
|
+
var rateLimited = false;
|
167
|
+
var rateLimitedSeconds;
|
168
|
+
|
147
169
|
lastAjax = new Date();
|
148
170
|
totalAjaxCalls += 1;
|
149
171
|
data.__seq = totalAjaxCalls;
|
@@ -156,20 +178,19 @@
|
|
156
178
|
}
|
157
179
|
|
158
180
|
var headers = {
|
159
|
-
|
181
|
+
"X-SILENCE-LOGGER": "true"
|
160
182
|
};
|
161
|
-
for (var name in me.headers){
|
183
|
+
for (var name in me.headers) {
|
162
184
|
headers[name] = me.headers[name];
|
163
185
|
}
|
164
186
|
|
165
|
-
if (!chunked){
|
166
|
-
headers["Dont-Chunk"] =
|
187
|
+
if (!chunked) {
|
188
|
+
headers["Dont-Chunk"] = "true";
|
167
189
|
}
|
168
190
|
|
169
191
|
var dataType = chunked ? "text" : "json";
|
170
192
|
|
171
193
|
var handle_progress = function(payload, position) {
|
172
|
-
|
173
194
|
var separator = "\r\n|\r\n";
|
174
195
|
var endChunk = payload.indexOf(separator, position);
|
175
196
|
|
@@ -182,7 +203,7 @@
|
|
182
203
|
|
183
204
|
try {
|
184
205
|
reqSuccess(JSON.parse(chunk));
|
185
|
-
} catch(e) {
|
206
|
+
} catch (e) {
|
186
207
|
if (console.log) {
|
187
208
|
console.log("FAILED TO PARSE CHUNKED REPLY");
|
188
209
|
console.log(data);
|
@@ -190,9 +211,9 @@
|
|
190
211
|
}
|
191
212
|
|
192
213
|
return handle_progress(payload, endChunk + separator.length);
|
193
|
-
}
|
214
|
+
};
|
194
215
|
|
195
|
-
var disableChunked = function(){
|
216
|
+
var disableChunked = function() {
|
196
217
|
if (me.longPoll) {
|
197
218
|
me.longPoll.abort();
|
198
219
|
chunkedBackoff = 30;
|
@@ -203,18 +224,21 @@
|
|
203
224
|
var position = 0;
|
204
225
|
// if it takes longer than 3000 ms to get first chunk, we have some proxy
|
205
226
|
// this is messing with us, so just backoff from using chunked for now
|
206
|
-
var chunkedTimeout = setTimeout(disableChunked,3000);
|
207
|
-
xhr.onprogress = function
|
227
|
+
var chunkedTimeout = setTimeout(disableChunked, 3000);
|
228
|
+
xhr.onprogress = function() {
|
208
229
|
clearTimeout(chunkedTimeout);
|
209
|
-
if(
|
230
|
+
if (
|
231
|
+
xhr.getResponseHeader("Content-Type") ===
|
232
|
+
"application/json; charset=utf-8"
|
233
|
+
) {
|
210
234
|
// not chunked we are sending json back
|
211
235
|
chunked = false;
|
212
236
|
return;
|
213
237
|
}
|
214
238
|
position = handle_progress(xhr.responseText, position);
|
215
|
-
}
|
239
|
+
};
|
216
240
|
};
|
217
|
-
if (!me.ajax){
|
241
|
+
if (!me.ajax) {
|
218
242
|
throw new Error("Either jQuery or the ajax adapter must be loaded");
|
219
243
|
}
|
220
244
|
|
@@ -222,12 +246,17 @@
|
|
222
246
|
|
223
247
|
ajaxInProgress = true;
|
224
248
|
var req = me.ajax({
|
225
|
-
url:
|
249
|
+
url:
|
250
|
+
me.baseUrl +
|
251
|
+
"message-bus/" +
|
252
|
+
me.clientId +
|
253
|
+
"/poll" +
|
254
|
+
(!longPoll ? "?dlp=t" : ""),
|
226
255
|
data: data,
|
227
256
|
cache: false,
|
228
257
|
async: true,
|
229
258
|
dataType: dataType,
|
230
|
-
type:
|
259
|
+
type: "POST",
|
231
260
|
headers: headers,
|
232
261
|
messageBus: {
|
233
262
|
chunked: chunked,
|
@@ -235,15 +264,18 @@
|
|
235
264
|
var position = 0;
|
236
265
|
// if it takes longer than 3000 ms to get first chunk, we have some proxy
|
237
266
|
// this is messing with us, so just backoff from using chunked for now
|
238
|
-
var chunkedTimeout = setTimeout(disableChunked,3000);
|
239
|
-
return xhr.onprogress = function
|
267
|
+
var chunkedTimeout = setTimeout(disableChunked, 3000);
|
268
|
+
return (xhr.onprogress = function() {
|
240
269
|
clearTimeout(chunkedTimeout);
|
241
|
-
if(
|
270
|
+
if (
|
271
|
+
xhr.getResponseHeader("Content-Type") ===
|
272
|
+
"application/json; charset=utf-8"
|
273
|
+
) {
|
242
274
|
chunked = false; // not chunked, we are sending json back
|
243
275
|
} else {
|
244
276
|
position = handle_progress(xhr.responseText, position);
|
245
277
|
}
|
246
|
-
}
|
278
|
+
});
|
247
279
|
}
|
248
280
|
},
|
249
281
|
xhr: function() {
|
@@ -255,16 +287,27 @@
|
|
255
287
|
return xhr;
|
256
288
|
},
|
257
289
|
success: function(messages) {
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
290
|
+
if (!chunked) {
|
291
|
+
// we may have requested text so jQuery will not parse
|
292
|
+
if (typeof messages === "string") {
|
293
|
+
messages = JSON.parse(messages);
|
294
|
+
}
|
295
|
+
gotData = reqSuccess(messages);
|
296
|
+
}
|
297
|
+
},
|
266
298
|
error: function(xhr, textStatus, err) {
|
267
|
-
if(
|
299
|
+
if (xhr.status === 429) {
|
300
|
+
var tryAfter =
|
301
|
+
parseInt(
|
302
|
+
xhr.getResponseHeader && xhr.getResponseHeader("Retry-After")
|
303
|
+
) || 0;
|
304
|
+
tryAfter = tryAfter || 0;
|
305
|
+
if (tryAfter < 15) {
|
306
|
+
tryAfter = 15;
|
307
|
+
}
|
308
|
+
rateLimitedSeconds = tryAfter;
|
309
|
+
rateLimited = true;
|
310
|
+
} else if (textStatus === "abort") {
|
268
311
|
aborted = true;
|
269
312
|
} else {
|
270
313
|
failCount += 1;
|
@@ -272,12 +315,13 @@
|
|
272
315
|
}
|
273
316
|
},
|
274
317
|
complete: function() {
|
275
|
-
|
276
318
|
ajaxInProgress = false;
|
277
319
|
|
278
320
|
var interval;
|
279
321
|
try {
|
280
|
-
if (
|
322
|
+
if (rateLimited) {
|
323
|
+
interval = Math.max(me.minPollInterval, rateLimitedSeconds * 1000);
|
324
|
+
} else if (gotData || aborted) {
|
281
325
|
interval = me.minPollInterval;
|
282
326
|
} else {
|
283
327
|
interval = me.callbackInterval;
|
@@ -290,14 +334,14 @@
|
|
290
334
|
interval = me.maxPollInterval;
|
291
335
|
}
|
292
336
|
|
293
|
-
interval -=
|
337
|
+
interval -= new Date() - lastAjax;
|
294
338
|
|
295
339
|
if (interval < 100) {
|
296
340
|
interval = 100;
|
297
341
|
}
|
298
342
|
}
|
299
|
-
} catch(e) {
|
300
|
-
if(console.log && e.message) {
|
343
|
+
} catch (e) {
|
344
|
+
if (console.log && e.message) {
|
301
345
|
console.log("MESSAGE BUS FAIL: " + e.message);
|
302
346
|
}
|
303
347
|
}
|
@@ -308,7 +352,7 @@
|
|
308
352
|
}
|
309
353
|
|
310
354
|
if (started) {
|
311
|
-
pollTimeout = setTimeout(function(){
|
355
|
+
pollTimeout = setTimeout(function() {
|
312
356
|
pollTimeout = null;
|
313
357
|
poll();
|
314
358
|
}, interval);
|
@@ -335,17 +379,26 @@
|
|
335
379
|
alwaysLongPoll: false,
|
336
380
|
baseUrl: baseUrl,
|
337
381
|
headers: {},
|
338
|
-
ajax:
|
339
|
-
noConflict: function(){
|
382
|
+
ajax: jQuery && jQuery.ajax,
|
383
|
+
noConflict: function() {
|
340
384
|
global.MessageBus = global.MessageBus.previousMessageBus;
|
341
385
|
return this;
|
342
386
|
},
|
343
|
-
diagnostics: function(){
|
387
|
+
diagnostics: function() {
|
344
388
|
console.log("Stopped: " + stopped + " Started: " + started);
|
345
389
|
console.log("Current callbacks");
|
346
390
|
console.log(callbacks);
|
347
|
-
console.log(
|
348
|
-
|
391
|
+
console.log(
|
392
|
+
"Total ajax calls: " +
|
393
|
+
totalAjaxCalls +
|
394
|
+
" Recent failure count: " +
|
395
|
+
failCount +
|
396
|
+
" Total failures: " +
|
397
|
+
totalAjaxFailures
|
398
|
+
);
|
399
|
+
console.log(
|
400
|
+
"Last ajax call: " + (new Date() - lastAjax) / 1000 + " seconds ago"
|
401
|
+
);
|
349
402
|
},
|
350
403
|
|
351
404
|
pause: function() {
|
@@ -381,12 +434,12 @@
|
|
381
434
|
poll = function() {
|
382
435
|
var data;
|
383
436
|
|
384
|
-
if(stopped) {
|
437
|
+
if (stopped) {
|
385
438
|
return;
|
386
439
|
}
|
387
440
|
|
388
441
|
if (callbacks.length === 0 || hiddenTabShouldWait()) {
|
389
|
-
if(!delayPollTimeout) {
|
442
|
+
if (!delayPollTimeout) {
|
390
443
|
delayPollTimeout = setTimeout(function() {
|
391
444
|
delayPollTimeout = null;
|
392
445
|
poll();
|
@@ -396,7 +449,7 @@
|
|
396
449
|
}
|
397
450
|
|
398
451
|
data = {};
|
399
|
-
for (var i=0;i<callbacks.length;i++) {
|
452
|
+
for (var i = 0; i < callbacks.length; i++) {
|
400
453
|
data[callbacks[i].channel] = callbacks[i].last_id;
|
401
454
|
}
|
402
455
|
|
@@ -407,30 +460,31 @@
|
|
407
460
|
}
|
408
461
|
};
|
409
462
|
|
410
|
-
|
411
463
|
// monitor visibility, issue a new long poll when the page shows
|
412
|
-
if(document.addEventListener &&
|
413
|
-
me.visibilityEvent = global.document.addEventListener(
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
464
|
+
if (document.addEventListener && "hidden" in document) {
|
465
|
+
me.visibilityEvent = global.document.addEventListener(
|
466
|
+
"visibilitychange",
|
467
|
+
function() {
|
468
|
+
if (!document.hidden && !me.longPoll && pollTimeout) {
|
469
|
+
clearTimeout(pollTimeout);
|
470
|
+
clearTimeout(delayPollTimeout);
|
418
471
|
|
419
|
-
|
420
|
-
|
421
|
-
|
472
|
+
delayPollTimeout = null;
|
473
|
+
pollTimeout = null;
|
474
|
+
poll();
|
475
|
+
}
|
422
476
|
}
|
423
|
-
|
477
|
+
);
|
424
478
|
}
|
425
479
|
|
426
480
|
poll();
|
427
481
|
},
|
428
482
|
|
429
|
-
|
483
|
+
status: function() {
|
430
484
|
if (paused) {
|
431
|
-
|
485
|
+
return "paused";
|
432
486
|
} else if (started) {
|
433
|
-
|
487
|
+
return "started";
|
434
488
|
} else if (stopped) {
|
435
489
|
return "stopped";
|
436
490
|
} else {
|
@@ -445,16 +499,15 @@
|
|
445
499
|
// -2 will recieve last message + all new messages
|
446
500
|
// -3 will recieve last 2 messages + all new messages
|
447
501
|
subscribe: function(channel, func, lastId) {
|
448
|
-
|
449
|
-
if(!started && !stopped){
|
502
|
+
if (!started && !stopped) {
|
450
503
|
me.start();
|
451
504
|
}
|
452
505
|
|
453
|
-
if (typeof
|
506
|
+
if (typeof lastId !== "number") {
|
454
507
|
lastId = -1;
|
455
508
|
}
|
456
509
|
|
457
|
-
if (typeof
|
510
|
+
if (typeof channel !== "string") {
|
458
511
|
throw "Channel name must be a string!";
|
459
512
|
}
|
460
513
|
|
@@ -483,8 +536,7 @@
|
|
483
536
|
|
484
537
|
var removed = false;
|
485
538
|
|
486
|
-
for (var i=callbacks.length-1; i>=0; i--) {
|
487
|
-
|
539
|
+
for (var i = callbacks.length - 1; i >= 0; i--) {
|
488
540
|
var callback = callbacks[i];
|
489
541
|
var keep;
|
490
542
|
|
@@ -494,12 +546,12 @@
|
|
494
546
|
keep = callback.channel !== channel;
|
495
547
|
}
|
496
548
|
|
497
|
-
if(!keep && func && callback.func !== func){
|
549
|
+
if (!keep && func && callback.func !== func) {
|
498
550
|
keep = true;
|
499
551
|
}
|
500
552
|
|
501
553
|
if (!keep) {
|
502
|
-
callbacks.splice(i,1);
|
554
|
+
callbacks.splice(i, 1);
|
503
555
|
removed = true;
|
504
556
|
}
|
505
557
|
}
|
@@ -433,10 +433,11 @@ LUA
|
|
433
433
|
key = "__mb_is_readonly"
|
434
434
|
|
435
435
|
begin
|
436
|
+
# disconnect to force a reconnect when attempting to set the key
|
436
437
|
# in case we are not connected to the correct server
|
437
438
|
# which can happen when sharing ips
|
438
|
-
pub_redis.
|
439
|
-
pub_redis.
|
439
|
+
pub_redis.disconnect!
|
440
|
+
pub_redis.set(key, '1')
|
440
441
|
false
|
441
442
|
rescue ::Redis::CommandError => e
|
442
443
|
return true if e.message =~ /^READONLY/
|
data/lib/message_bus/version.rb
CHANGED
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: 2.2.
|
4
|
+
version: 2.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Saffron
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|