message_bus 2.0.3 → 2.0.5

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
  SHA1:
3
- metadata.gz: f3cdd346c2878cd29ee74ec652ad39b524322db2
4
- data.tar.gz: dcb547c36393e89b014e61eb37fa01757a813fac
3
+ metadata.gz: 6ab5f806affa121e66619143bef08f116e700722
4
+ data.tar.gz: 43e51a93bb2ac7fc232b89af04b08f25c526af0e
5
5
  SHA512:
6
- metadata.gz: ad0c582fa78e53d1d59d355ee595b05e3d74ffb68858a3617db6fcbab45005220566e2baf74b9ea57bb19b3f03ccdc222928cf3b4e91dfe8f6cf015059b0fe67
7
- data.tar.gz: faf5a01c159e6b016e7d99f418b195330ea3382390a306eef54be053b69d85b4bcf413ee4fa68d1dcf5f79a812822ac804ae38cc0d54bd0d1eb367c9182eb1bc
6
+ metadata.gz: 1ce530dbf86a71ae8d7f593446768d4090055cdcddc52335d2ba38482e959375c0165221cda880b1f5a5c2098e7fcdd5a4b28880e5b8161530fd99068da8ef35
7
+ data.tar.gz: 8b9b5cc7eff8bea4ae4d94d92fa09a24ff42eb348414d862415162103e97cb814f3e29306299ec9a9f4327f1b524373ef46da6d53c3d7db246a88ad67627341c
data/CHANGELOG CHANGED
@@ -1,5 +1,9 @@
1
1
  16-08-2017
2
2
 
3
+ - Version 2.0.4
4
+
5
+ - Quick fix, build on earlier version of Ruby cause https://github.com/rubygems/rubygems/issues/1448 is still open
6
+
3
7
  - Version 2.0.3
4
8
  - Fix: broken MessageBus.redis_config
5
9
  - Perf: publish status message for filtered messages
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module MessageBus
3
- VERSION = "2.0.3"
3
+ VERSION = "2.0.5"
4
4
  end
@@ -0,0 +1,44 @@
1
+ // A bare-bones implementation of $.ajax that MessageBus will use
2
+ // as a fallback if jQuery is not present
3
+ //
4
+ // Only implements methods & options used by MessageBus
5
+ (function(global, undefined) {
6
+ 'use strict';
7
+ if (!global.MessageBus){
8
+ throw new Error("MessageBus must be loaded before the ajax adapter");
9
+ }
10
+
11
+ var cacheBuster = Math.random() * 10000 | 0;
12
+
13
+ global.MessageBus.ajax = function(options){
14
+ var XHRImpl = (global.MessageBus && global.MessageBus.xhrImplementation) || global.XMLHttpRequest;
15
+ var xhr = new XHRImpl();
16
+ xhr.dataType = options.dataType;
17
+ var url = options.url;
18
+ if (!options.cache){
19
+ url += ((-1 == url.indexOf('?')) ? '?' : '&') + '_=' + (cacheBuster++)
20
+ }
21
+ xhr.open('POST', url);
22
+ for (var name in options.headers){
23
+ xhr.setRequestHeader(name, options.headers[name]);
24
+ }
25
+ xhr.setRequestHeader('Content-Type', 'application/json');
26
+ if (options.messageBus.chunked){
27
+ options.messageBus.onProgressListener(xhr);
28
+ }
29
+ xhr.onreadystatechange = function(){
30
+ if (xhr.readyState === 4){
31
+ var status = xhr.status;
32
+ if (status >= 200 && status < 300 || status === 304){
33
+ options.success(xhr.responseText);
34
+ } else {
35
+ options.error(xhr, xhr.statusText);
36
+ }
37
+ options.complete();
38
+ }
39
+ }
40
+ xhr.send(JSON.stringify(options.data));
41
+ return xhr;
42
+ };
43
+
44
+ })(window);
@@ -0,0 +1,431 @@
1
+ /*jshint bitwise: false*/
2
+ (function(global, document, undefined) {
3
+ 'use strict';
4
+ var previousMessageBus = global.MessageBus;
5
+
6
+ // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
7
+ var callbacks, clientId, failCount, shouldLongPoll, queue, responseCallbacks, uniqueId, baseUrl;
8
+ var me, started, stopped, longPoller, pollTimeout, paused, later, jQuery, interval, chunkedBackoff;
9
+
10
+ uniqueId = function() {
11
+ return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
12
+ var r, v;
13
+ r = Math.random() * 16 | 0;
14
+ v = c === 'x' ? r : (r & 0x3 | 0x8);
15
+ return v.toString(16);
16
+ });
17
+ };
18
+
19
+ clientId = uniqueId();
20
+ responseCallbacks = {};
21
+ callbacks = [];
22
+ queue = [];
23
+ interval = null;
24
+ failCount = 0;
25
+ baseUrl = "/";
26
+ paused = false;
27
+ later = [];
28
+ chunkedBackoff = 0;
29
+ jQuery = global.jQuery;
30
+ var hiddenProperty;
31
+
32
+ (function(){
33
+ var prefixes = ["","webkit","ms","moz"];
34
+ for(var i=0; i<prefixes.length; i++) {
35
+ var prefix = prefixes[i];
36
+ var check = prefix + (prefix === "" ? "hidden" : "Hidden");
37
+ if(document[check] !== undefined ){
38
+ hiddenProperty = check;
39
+ }
40
+ }
41
+ })();
42
+
43
+ var isHidden = function() {
44
+ if (hiddenProperty !== undefined){
45
+ return document[hiddenProperty];
46
+ } else {
47
+ return !document.hasFocus;
48
+ }
49
+ };
50
+
51
+ var hasonprogress = (new XMLHttpRequest()).onprogress === null;
52
+ var allowChunked = function(){
53
+ return me.enableChunkedEncoding && hasonprogress;
54
+ };
55
+
56
+ shouldLongPoll = function() {
57
+ return me.alwaysLongPoll || !isHidden();
58
+ };
59
+
60
+ var totalAjaxFailures = 0;
61
+ var totalAjaxCalls = 0;
62
+ var lastAjax;
63
+
64
+ var processMessages = function(messages) {
65
+ var gotData = false;
66
+ if (!messages) return false; // server unexpectedly closed connection
67
+
68
+ for (var i=0; i<messages.length; i++) {
69
+ var message = messages[i];
70
+ gotData = true;
71
+ for (var j=0; j<callbacks.length; j++) {
72
+ var callback = callbacks[j];
73
+ if (callback.channel === message.channel) {
74
+ callback.last_id = message.message_id;
75
+ try {
76
+ callback.func(message.data, message.global_id, message.message_id);
77
+ }
78
+ catch(e){
79
+ if(console.log) {
80
+ console.log("MESSAGE BUS FAIL: callback " + callback.channel + " caused exception " + e.message);
81
+ }
82
+ }
83
+ }
84
+ if (message.channel === "/__status") {
85
+ if (message.data[callback.channel] !== undefined) {
86
+ callback.last_id = message.data[callback.channel];
87
+ }
88
+ }
89
+ }
90
+ }
91
+
92
+ return gotData;
93
+ };
94
+
95
+ var reqSuccess = function(messages) {
96
+ failCount = 0;
97
+ if (paused) {
98
+ if (messages) {
99
+ for (var i=0; i<messages.length; i++) {
100
+ later.push(messages[i]);
101
+ }
102
+ }
103
+ } else {
104
+ return processMessages(messages);
105
+ }
106
+ return false;
107
+ };
108
+
109
+ longPoller = function(poll,data){
110
+ var gotData = false;
111
+ var aborted = false;
112
+ lastAjax = new Date();
113
+ totalAjaxCalls += 1;
114
+ data.__seq = totalAjaxCalls;
115
+
116
+ var longPoll = shouldLongPoll() && me.enableLongPolling;
117
+ var chunked = longPoll && allowChunked();
118
+ if (chunkedBackoff > 0) {
119
+ chunkedBackoff--;
120
+ chunked = false;
121
+ }
122
+
123
+ var headers = {
124
+ 'X-SILENCE-LOGGER': 'true'
125
+ };
126
+ for (var name in me.headers){
127
+ headers[name] = me.headers[name];
128
+ }
129
+
130
+ if (!chunked){
131
+ headers["Dont-Chunk"] = 'true';
132
+ }
133
+
134
+ var dataType = chunked ? "text" : "json";
135
+
136
+ var handle_progress = function(payload, position) {
137
+
138
+ var separator = "\r\n|\r\n";
139
+ var endChunk = payload.indexOf(separator, position);
140
+
141
+ if (endChunk === -1) {
142
+ return position;
143
+ }
144
+
145
+ var chunk = payload.substring(position, endChunk);
146
+ chunk = chunk.replace(/\r\n\|\|\r\n/g, separator);
147
+
148
+ try {
149
+ reqSuccess(JSON.parse(chunk));
150
+ } catch(e) {
151
+ if (console.log) {
152
+ console.log("FAILED TO PARSE CHUNKED REPLY");
153
+ console.log(data);
154
+ }
155
+ }
156
+
157
+ return handle_progress(payload, endChunk + separator.length);
158
+ }
159
+
160
+ var disableChunked = function(){
161
+ if (me.longPoll) {
162
+ me.longPoll.abort();
163
+ chunkedBackoff = 30;
164
+ }
165
+ };
166
+
167
+ var setOnProgressListener = function(xhr) {
168
+ var position = 0;
169
+ // if it takes longer than 3000 ms to get first chunk, we have some proxy
170
+ // this is messing with us, so just backoff from using chunked for now
171
+ var chunkedTimeout = setTimeout(disableChunked,3000);
172
+ xhr.onprogress = function () {
173
+ clearTimeout(chunkedTimeout);
174
+ if(xhr.getResponseHeader('Content-Type') === 'application/json; charset=utf-8') {
175
+ // not chunked we are sending json back
176
+ chunked = false;
177
+ return;
178
+ }
179
+ position = handle_progress(xhr.responseText, position);
180
+ }
181
+ };
182
+ if (!me.ajax){
183
+ throw new Error("Either jQuery or the ajax adapter must be loaded");
184
+ }
185
+ var req = me.ajax({
186
+ url: me.baseUrl + "message-bus/" + me.clientId + "/poll" + (!longPoll ? "?dlp=t" : ""),
187
+ data: data,
188
+ cache: false,
189
+ async: true,
190
+ dataType: dataType,
191
+ type: 'POST',
192
+ headers: headers,
193
+ messageBus: {
194
+ chunked: chunked,
195
+ onProgressListener: function(xhr) {
196
+ var position = 0;
197
+ // if it takes longer than 3000 ms to get first chunk, we have some proxy
198
+ // this is messing with us, so just backoff from using chunked for now
199
+ var chunkedTimeout = setTimeout(disableChunked,3000);
200
+ return xhr.onprogress = function () {
201
+ clearTimeout(chunkedTimeout);
202
+ if(xhr.getResponseHeader('Content-Type') === 'application/json; charset=utf-8') {
203
+ chunked = false; // not chunked, we are sending json back
204
+ } else {
205
+ position = handle_progress(xhr.responseText, position);
206
+ }
207
+ }
208
+ }
209
+ },
210
+ xhr: function() {
211
+ var xhr = jQuery.ajaxSettings.xhr();
212
+ if (!chunked) {
213
+ return xhr;
214
+ }
215
+ this.messageBus.onProgressListener(xhr);
216
+ return xhr;
217
+ },
218
+ success: function(messages) {
219
+ if (!chunked) {
220
+ // we may have requested text so jQuery will not parse
221
+ if (typeof(messages) === "string") {
222
+ messages = JSON.parse(messages);
223
+ }
224
+ gotData = reqSuccess(messages);
225
+ }
226
+ },
227
+ error: function(xhr, textStatus, err) {
228
+ if(textStatus === "abort") {
229
+ aborted = true;
230
+ } else {
231
+ failCount += 1;
232
+ totalAjaxFailures += 1;
233
+ }
234
+ },
235
+ complete: function() {
236
+ var interval;
237
+ try {
238
+ if (gotData || aborted) {
239
+ interval = 100;
240
+ } else {
241
+ interval = me.callbackInterval;
242
+ if (failCount > 2) {
243
+ interval = interval * failCount;
244
+ } else if (!shouldLongPoll()) {
245
+ interval = me.backgroundCallbackInterval;
246
+ }
247
+ if (interval > me.maxPollInterval) {
248
+ interval = me.maxPollInterval;
249
+ }
250
+
251
+ interval -= (new Date() - lastAjax);
252
+
253
+ if (interval < 100) {
254
+ interval = 100;
255
+ }
256
+ }
257
+ } catch(e) {
258
+ if(console.log && e.message) {
259
+ console.log("MESSAGE BUS FAIL: " + e.message);
260
+ }
261
+ }
262
+
263
+ pollTimeout = setTimeout(function(){pollTimeout=null; poll();}, interval);
264
+ me.longPoll = null;
265
+ }
266
+ });
267
+
268
+ return req;
269
+ };
270
+
271
+ me = {
272
+ enableChunkedEncoding: true,
273
+ enableLongPolling: true,
274
+ callbackInterval: 15000,
275
+ backgroundCallbackInterval: 60000,
276
+ maxPollInterval: 3 * 60 * 1000,
277
+ callbacks: callbacks,
278
+ clientId: clientId,
279
+ alwaysLongPoll: false,
280
+ baseUrl: baseUrl,
281
+ headers: {},
282
+ ajax: (jQuery && jQuery.ajax),
283
+ noConflict: function(){
284
+ global.MessageBus = global.MessageBus.previousMessageBus;
285
+ return this;
286
+ },
287
+ diagnostics: function(){
288
+ console.log("Stopped: " + stopped + " Started: " + started);
289
+ console.log("Current callbacks");
290
+ console.log(callbacks);
291
+ console.log("Total ajax calls: " + totalAjaxCalls + " Recent failure count: " + failCount + " Total failures: " + totalAjaxFailures);
292
+ console.log("Last ajax call: " + (new Date() - lastAjax) / 1000 + " seconds ago") ;
293
+ },
294
+
295
+ pause: function() {
296
+ paused = true;
297
+ },
298
+
299
+ resume: function() {
300
+ paused = false;
301
+ processMessages(later);
302
+ later = [];
303
+ },
304
+
305
+ stop: function() {
306
+ stopped = true;
307
+ started = false;
308
+ },
309
+
310
+ // Start polling
311
+ start: function() {
312
+ var poll, delayPollTimeout;
313
+
314
+ if (started) return;
315
+ started = true;
316
+ stopped = false;
317
+
318
+ poll = function() {
319
+ var data;
320
+
321
+ if(stopped) {
322
+ return;
323
+ }
324
+
325
+ if (callbacks.length === 0) {
326
+ if(!delayPollTimeout) {
327
+ delayPollTimeout = setTimeout(function(){ delayPollTimeout = null; poll();}, 500);
328
+ }
329
+ return;
330
+ }
331
+
332
+ data = {};
333
+ for (var i=0;i<callbacks.length;i++) {
334
+ data[callbacks[i].channel] = callbacks[i].last_id;
335
+ }
336
+
337
+ me.longPoll = longPoller(poll,data);
338
+ };
339
+
340
+
341
+ // monitor visibility, issue a new long poll when the page shows
342
+ if(document.addEventListener && 'hidden' in document){
343
+ me.visibilityEvent = global.document.addEventListener('visibilitychange', function(){
344
+ if(!document.hidden && !me.longPoll && pollTimeout){
345
+ clearTimeout(pollTimeout);
346
+ pollTimeout = null;
347
+ poll();
348
+ }
349
+ });
350
+ }
351
+
352
+ poll();
353
+ },
354
+
355
+ "status": function() {
356
+ if (paused) {
357
+ return "paused";
358
+ } else if (started) {
359
+ return "started";
360
+ } else if (stopped) {
361
+ return "stopped";
362
+ } else {
363
+ throw "Cannot determine current status";
364
+ }
365
+ },
366
+
367
+ // Subscribe to a channel
368
+ subscribe: function(channel, func, lastId) {
369
+
370
+ if(!started && !stopped){
371
+ me.start();
372
+ }
373
+
374
+ if (typeof(lastId) !== "number" || lastId < -1){
375
+ lastId = -1;
376
+ }
377
+ callbacks.push({
378
+ channel: channel,
379
+ func: func,
380
+ last_id: lastId
381
+ });
382
+ if (me.longPoll) {
383
+ me.longPoll.abort();
384
+ }
385
+
386
+ return func;
387
+ },
388
+
389
+ // Unsubscribe from a channel
390
+ unsubscribe: function(channel, func) {
391
+ // TODO allow for globbing in the middle of a channel name
392
+ // like /something/*/something
393
+ // at the moment we only support globbing /something/*
394
+ var glob;
395
+ if (channel.indexOf("*", channel.length - 1) !== -1) {
396
+ channel = channel.substr(0, channel.length - 1);
397
+ glob = true;
398
+ }
399
+
400
+ var removed = false;
401
+
402
+ for (var i=callbacks.length-1; i>=0; i--) {
403
+
404
+ var callback = callbacks[i];
405
+ var keep;
406
+
407
+ if (glob) {
408
+ keep = callback.channel.substr(0, channel.length) !== channel;
409
+ } else {
410
+ keep = callback.channel !== channel;
411
+ }
412
+
413
+ if(!keep && func && callback.func !== func){
414
+ keep = true;
415
+ }
416
+
417
+ if (!keep) {
418
+ callbacks.splice(i,1);
419
+ removed = true;
420
+ }
421
+ }
422
+
423
+ if (removed && me.longPoll) {
424
+ me.longPoll.abort();
425
+ }
426
+
427
+ return removed;
428
+ }
429
+ };
430
+ global.MessageBus = me;
431
+ })(window, document);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: message_bus
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
@@ -14,42 +14,42 @@ dependencies:
14
14
  name: rack
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
19
  version: 1.1.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.1.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: redis
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - '>='
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - '>='
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pg
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - '>='
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  description: A message bus for rack
@@ -59,9 +59,9 @@ executables: []
59
59
  extensions: []
60
60
  extra_rdoc_files: []
61
61
  files:
62
- - ".gitignore"
63
- - ".rubocop.yml"
64
- - ".travis.yml"
62
+ - .gitignore
63
+ - .rubocop.yml
64
+ - .travis.yml
65
65
  - CHANGELOG
66
66
  - Gemfile
67
67
  - Guardfile
@@ -131,17 +131,17 @@ require_paths:
131
131
  - lib
132
132
  required_ruby_version: !ruby/object:Gem::Requirement
133
133
  requirements:
134
- - - ">="
134
+ - - '>='
135
135
  - !ruby/object:Gem::Version
136
136
  version: 1.9.3
137
137
  required_rubygems_version: !ruby/object:Gem::Requirement
138
138
  requirements:
139
- - - ">="
139
+ - - '>='
140
140
  - !ruby/object:Gem::Version
141
141
  version: '0'
142
142
  requirements: []
143
143
  rubyforge_project:
144
- rubygems_version: 2.5.2
144
+ rubygems_version: 2.0.14
145
145
  signing_key:
146
146
  specification_version: 4
147
147
  summary: ''
@@ -1 +0,0 @@
1
- ../../../assets/message-bus-ajax.js
@@ -1 +0,0 @@
1
- ../../../assets/message-bus.js