message_bus 2.0.0.beta.8 → 2.0.0.beta.9

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: 36e783040a809c36cf22fa4240a6c563c0b77445
4
- data.tar.gz: 4c1912ddfd8af23adcab074d340094e32721528d
3
+ metadata.gz: 0974fc7ea256d61e7ecd1b72b3f01413e1fc23b5
4
+ data.tar.gz: e2c501cfdefd50eebdf55e2ac2b2c097e235cbb0
5
5
  SHA512:
6
- metadata.gz: 7e4343488e590e4eb1270e2ba8c22b02d2e9b282be80fe79d606a8dce375ff90317abaccea16cf6f90350569a5be1e0daa1b9345f21253d522d42660091ff95c
7
- data.tar.gz: 821d8f2fe45aef0dd014cc0315761e4b9bbc4eb47a0f8d67f5e323c8ebf302d7b8fc996bb01ad443f6f16ba1c1d5b421c92216eca85e31e8755618b645b889ce
6
+ metadata.gz: abd739f0d8bb295cc06c953f90bf8e3b0f12e5f493830c2cd1cebbce3e448deff78f65e06bec78b294740703772f81a772196e6f92bcf2b5fd2911b8fb0e358e
7
+ data.tar.gz: 48eb3572114789e6d8665d8c09987501f593fccbc03cfbd708349b300428aee081ae0effee0d865ec3415f381d15d92808295a6a2ec0e461bdabec48feaa7c2d
data/CHANGELOG CHANGED
@@ -1,3 +1,8 @@
1
+ 11-05-2016
2
+
3
+ - Version 2.0.0.beta.8
4
+ - Fix: requests without content type were erroring out, breaks CORS
5
+
1
6
  27-04-2016
2
7
 
3
8
  - Version 2.0.0.beta.7
data/README.md CHANGED
@@ -71,6 +71,10 @@ MessageBus.publish "/channel", "hello", client_ids: ["XXX","YYY"]
71
71
  # message bus determines the user ids and groups based on env
72
72
 
73
73
  MessageBus.configure(user_id_lookup: proc do |env|
74
+ # this lookup occurs on JS-client poolings, so that server can retrieve backlog
75
+ # for the client considering/matching/filtering user_ids set on published messages
76
+ # if user_id is not set on publish time, any user_id returned here will receive the message
77
+
74
78
  # return the user id here
75
79
  end)
76
80
 
@@ -184,7 +184,7 @@ class MessageBus::Postgres::Client
184
184
 
185
185
  conn.exec 'PREPARE insert_message AS INSERT INTO message_bus (channel, value) VALUES ($1, $2) RETURNING id'
186
186
  conn.exec 'PREPARE clear_global_backlog AS DELETE FROM message_bus WHERE (id <= $1)'
187
- conn.exec 'PREPARE clear_channel_backlog AS DELETE FROM message_bus WHERE ((channel = $1) AND (id <= (SELECT id FROM message_bus WHERE ((channel = $1) AND (id <= $2)) ORDER BY id DESC OFFSET $3)))'
187
+ conn.exec 'PREPARE clear_channel_backlog AS DELETE FROM message_bus WHERE ((channel = $1) AND (id <= (SELECT id FROM message_bus WHERE ((channel = $1) AND (id <= $2)) ORDER BY id DESC LIMIT 1 OFFSET $3)))'
188
188
  conn.exec 'PREPARE channel_backlog AS SELECT id, value FROM message_bus WHERE ((channel = $1) AND (id > $2)) ORDER BY id'
189
189
  conn.exec 'PREPARE global_backlog AS SELECT id, channel, value FROM message_bus WHERE (id > $1) ORDER BY id'
190
190
  conn.exec "PREPARE expire AS DELETE FROM message_bus WHERE added_at < CURRENT_TIMESTAMP - ($1::text || ' seconds')::interval"
@@ -95,7 +95,8 @@ class MessageBus::Rack::Middleware
95
95
  end
96
96
  else
97
97
  request = Rack::Request.new(env)
98
- data = request.content_type.include?('application/json') ? JSON.parse(request.body.read) : request.POST
98
+ is_json = request.content_type && request.content_type.include?('application/json')
99
+ data = is_json ? JSON.parse(request.body.read) : request.POST
99
100
  data.each do |k,v|
100
101
  if k == "__seq".freeze
101
102
  client.seq = v.to_i
@@ -1,3 +1,3 @@
1
1
  module MessageBus
2
- VERSION = "2.0.0.beta.8"
2
+ VERSION = "2.0.0.beta.9"
3
3
  end
@@ -0,0 +1 @@
1
+ ../../../assets/message-bus-ajax.js
@@ -0,0 +1 @@
1
+ ../../../assets/message-bus.js
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.0.0.beta.8
4
+ version: 2.0.0.beta.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-27 00:00:00.000000000 Z
11
+ date: 2016-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -140,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
140
  version: 1.3.1
141
141
  requirements: []
142
142
  rubyforge_project:
143
- rubygems_version: 2.4.5.1
143
+ rubygems_version: 2.5.1
144
144
  signing_key:
145
145
  specification_version: 4
146
146
  summary: ''
@@ -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,418 +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);
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
- dataType: dataType,
190
- type: 'POST',
191
- headers: headers,
192
- messageBus: {
193
- chunked: chunked,
194
- onProgressListener: function(xhr) {
195
- var position = 0;
196
- // if it takes longer than 3000 ms to get first chunk, we have some proxy
197
- // this is messing with us, so just backoff from using chunked for now
198
- var chunkedTimeout = setTimeout(disableChunked,3000);
199
- return xhr.onprogress = function () {
200
- clearTimeout(chunkedTimeout);
201
- if(xhr.getResponseHeader('Content-Type') === 'application/json; charset=utf-8') {
202
- chunked = false; // not chunked, we are sending json back
203
- } else {
204
- position = handle_progress(xhr.responseText, position);
205
- }
206
- }
207
- }
208
- },
209
- xhr: function() {
210
- var xhr = jQuery.ajaxSettings.xhr();
211
- if (!chunked) {
212
- return xhr;
213
- }
214
- this.messageBus.onProgressListener(xhr);
215
- return xhr;
216
- },
217
- success: function(messages) {
218
- if (!chunked) {
219
- // we may have requested text so jQuery will not parse
220
- if (typeof(messages) === "string") {
221
- messages = JSON.parse(messages);
222
- }
223
- gotData = reqSuccess(messages);
224
- }
225
- },
226
- error: function(xhr, textStatus, err) {
227
- if(textStatus === "abort") {
228
- aborted = true;
229
- } else {
230
- failCount += 1;
231
- totalAjaxFailures += 1;
232
- }
233
- },
234
- complete: function() {
235
- var interval;
236
- try {
237
- if (gotData || aborted) {
238
- interval = 100;
239
- } else {
240
- interval = me.callbackInterval;
241
- if (failCount > 2) {
242
- interval = interval * failCount;
243
- } else if (!shouldLongPoll()) {
244
- interval = me.backgroundCallbackInterval;
245
- }
246
- if (interval > me.maxPollInterval) {
247
- interval = me.maxPollInterval;
248
- }
249
-
250
- interval -= (new Date() - lastAjax);
251
-
252
- if (interval < 100) {
253
- interval = 100;
254
- }
255
- }
256
- } catch(e) {
257
- if(console.log && e.message) {
258
- console.log("MESSAGE BUS FAIL: " + e.message);
259
- }
260
- }
261
-
262
- pollTimeout = setTimeout(function(){pollTimeout=null; poll();}, interval);
263
- me.longPoll = null;
264
- }
265
- });
266
-
267
- return req;
268
- };
269
-
270
- me = {
271
- enableChunkedEncoding: true,
272
- enableLongPolling: true,
273
- callbackInterval: 15000,
274
- backgroundCallbackInterval: 60000,
275
- maxPollInterval: 3 * 60 * 1000,
276
- callbacks: callbacks,
277
- clientId: clientId,
278
- alwaysLongPoll: false,
279
- baseUrl: baseUrl,
280
- headers: {},
281
- ajax: (jQuery && jQuery.ajax),
282
- noConflict: function(){
283
- global.MessageBus = global.MessageBus.previousMessageBus;
284
- return this;
285
- },
286
- diagnostics: function(){
287
- console.log("Stopped: " + stopped + " Started: " + started);
288
- console.log("Current callbacks");
289
- console.log(callbacks);
290
- console.log("Total ajax calls: " + totalAjaxCalls + " Recent failure count: " + failCount + " Total failures: " + totalAjaxFailures);
291
- console.log("Last ajax call: " + (new Date() - lastAjax) / 1000 + " seconds ago") ;
292
- },
293
-
294
- pause: function() {
295
- paused = true;
296
- },
297
-
298
- resume: function() {
299
- paused = false;
300
- processMessages(later);
301
- later = [];
302
- },
303
-
304
- stop: function() {
305
- stopped = true;
306
- started = false;
307
- },
308
-
309
- // Start polling
310
- start: function() {
311
- var poll, delayPollTimeout;
312
-
313
- if (started) return;
314
- started = true;
315
- stopped = false;
316
-
317
- poll = function() {
318
- var data;
319
-
320
- if(stopped) {
321
- return;
322
- }
323
-
324
- if (callbacks.length === 0) {
325
- if(!delayPollTimeout) {
326
- delayPollTimeout = setTimeout(function(){ delayPollTimeout = null; poll();}, 500);
327
- }
328
- return;
329
- }
330
-
331
- data = {};
332
- for (var i=0;i<callbacks.length;i++) {
333
- data[callbacks[i].channel] = callbacks[i].last_id;
334
- }
335
-
336
- me.longPoll = longPoller(poll,data);
337
- };
338
-
339
-
340
- // monitor visibility, issue a new long poll when the page shows
341
- if(document.addEventListener && 'hidden' in document){
342
- me.visibilityEvent = global.document.addEventListener('visibilitychange', function(){
343
- if(!document.hidden && !me.longPoll && pollTimeout){
344
- clearTimeout(pollTimeout);
345
- pollTimeout = null;
346
- poll();
347
- }
348
- });
349
- }
350
-
351
- poll();
352
- },
353
-
354
- // Subscribe to a channel
355
- subscribe: function(channel, func, lastId) {
356
-
357
- if(!started && !stopped){
358
- me.start();
359
- }
360
-
361
- if (typeof(lastId) !== "number" || lastId < -1){
362
- lastId = -1;
363
- }
364
- callbacks.push({
365
- channel: channel,
366
- func: func,
367
- last_id: lastId
368
- });
369
- if (me.longPoll) {
370
- me.longPoll.abort();
371
- }
372
-
373
- return func;
374
- },
375
-
376
- // Unsubscribe from a channel
377
- unsubscribe: function(channel, func) {
378
- // TODO allow for globbing in the middle of a channel name
379
- // like /something/*/something
380
- // at the moment we only support globbing /something/*
381
- var glob;
382
- if (channel.indexOf("*", channel.length - 1) !== -1) {
383
- channel = channel.substr(0, channel.length - 1);
384
- glob = true;
385
- }
386
-
387
- var removed = false;
388
-
389
- for (var i=callbacks.length-1; i>=0; i--) {
390
-
391
- var callback = callbacks[i];
392
- var keep;
393
-
394
- if (glob) {
395
- keep = callback.channel.substr(0, channel.length) !== channel;
396
- } else {
397
- keep = callback.channel !== channel;
398
- }
399
-
400
- if(!keep && func && callback.func !== func){
401
- keep = true;
402
- }
403
-
404
- if (!keep) {
405
- callbacks.splice(i,1);
406
- removed = true;
407
- }
408
- }
409
-
410
- if (removed && me.longPoll) {
411
- me.longPoll.abort();
412
- }
413
-
414
- return removed;
415
- }
416
- };
417
- global.MessageBus = me;
418
- })(window, document);