message_bus 2.2.1 → 2.2.2
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 +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
|