message_bus 2.0.2 → 2.0.3

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.

@@ -1,44 +0,0 @@
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);
@@ -1,431 +0,0 @@
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);