message_bus 0.0.2 → 0.9.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.

Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +18 -0
  3. data/.travis.yml +6 -0
  4. data/CHANGELOG +9 -0
  5. data/Gemfile +15 -0
  6. data/Guardfile +7 -0
  7. data/README.md +8 -0
  8. data/Rakefile +14 -0
  9. data/assets/application.handlebars +7 -0
  10. data/assets/application.js +79 -0
  11. data/assets/ember.js +26839 -0
  12. data/assets/handlebars.js +2201 -0
  13. data/assets/index.handlebars +25 -0
  14. data/assets/jquery-1.8.2.js +9440 -0
  15. data/assets/message-bus.js +247 -0
  16. data/examples/bench/ab.sample +1 -0
  17. data/examples/bench/config.ru +24 -0
  18. data/examples/bench/payload.post +1 -0
  19. data/examples/bench/unicorn.conf.rb +4 -0
  20. data/examples/chat/chat.rb +74 -0
  21. data/examples/chat/config.ru +2 -0
  22. data/lib/message_bus.rb +60 -5
  23. data/lib/message_bus/client.rb +45 -7
  24. data/lib/message_bus/connection_manager.rb +35 -7
  25. data/lib/message_bus/em_ext.rb +5 -0
  26. data/lib/message_bus/rack/middleware.rb +60 -89
  27. data/lib/message_bus/rack/thin_ext.rb +71 -0
  28. data/lib/message_bus/rails/railtie.rb +4 -1
  29. data/lib/message_bus/reliable_pub_sub.rb +22 -4
  30. data/lib/message_bus/version.rb +1 -1
  31. data/message_bus.gemspec +20 -0
  32. data/spec/lib/client_spec.rb +50 -0
  33. data/spec/lib/connection_manager_spec.rb +83 -0
  34. data/spec/lib/fake_async_middleware.rb +134 -0
  35. data/spec/lib/handlers/demo_message_handler.rb +5 -0
  36. data/spec/lib/message_bus_spec.rb +112 -0
  37. data/spec/lib/message_handler_spec.rb +39 -0
  38. data/spec/lib/middleware_spec.rb +306 -0
  39. data/spec/lib/multi_process_spec.rb +60 -0
  40. data/spec/lib/reliable_pub_sub_spec.rb +167 -0
  41. data/spec/spec_helper.rb +19 -0
  42. data/vendor/assets/javascripts/message-bus.js +247 -0
  43. metadata +55 -26
@@ -0,0 +1,19 @@
1
+ require 'thin'
2
+ require 'lib/fake_async_middleware'
3
+
4
+ RSpec.configure do |config|
5
+ config.color_enabled = true
6
+ end
7
+
8
+ def wait_for(timeout_milliseconds)
9
+ timeout = (timeout_milliseconds + 0.0) / 1000
10
+ finish = Time.now + timeout
11
+ t = Thread.new do
12
+ while Time.now < finish && !yield
13
+ sleep(0.001)
14
+ end
15
+ end
16
+ t.join
17
+ end
18
+
19
+
@@ -0,0 +1,247 @@
1
+ /*jshint bitwise: false*/
2
+
3
+ /**
4
+ Message Bus functionality.
5
+
6
+ @class MessageBus
7
+ @namespace Discourse
8
+ @module Discourse
9
+ **/
10
+ window.MessageBus = (function() {
11
+ // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
12
+ var callbacks, clientId, failCount, interval, shouldLongPoll, queue, responseCallbacks, uniqueId, baseUrl;
13
+ var me, started, stopped, longPoller, pollTimeout;
14
+
15
+ uniqueId = function() {
16
+ return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
17
+ var r, v;
18
+ r = Math.random() * 16 | 0;
19
+ v = c === 'x' ? r : (r & 0x3 | 0x8);
20
+ return v.toString(16);
21
+ });
22
+ };
23
+
24
+ clientId = uniqueId();
25
+ responseCallbacks = {};
26
+ callbacks = [];
27
+ queue = [];
28
+ interval = null;
29
+ failCount = 0;
30
+ baseUrl = "/";
31
+
32
+ /* TODO: The plan is to force a long poll as soon as page becomes visible
33
+ // MIT based off https://github.com/mathiasbynens/jquery-visibility/blob/master/jquery-visibility.js
34
+ initVisibilityTracking = function(window, document, $, undefined) {
35
+ var prefix;
36
+ var property;
37
+ // In Opera, `'onfocusin' in document == true`, hence the extra `hasFocus` check to detect IE-like behavior
38
+ var eventName = 'onfocusin' in document && 'hasFocus' in document ? 'focusin focusout' : 'focus blur';
39
+ var prefixes = ['webkit', 'o', 'ms', 'moz', ''];
40
+ var $event = $.event;
41
+
42
+ while ((prefix = prefixes.pop()) !== undefined) {
43
+ property = (prefix ? prefix + 'H': 'h') + 'idden';
44
+ var supportsVisibility = typeof document[property] === 'boolean';
45
+ if (supportsVisibility) {
46
+ eventName = prefix + 'visibilitychange';
47
+ break;
48
+ }
49
+ }
50
+
51
+ $(/blur$/.test(eventName) ? window : document).on(eventName, function(event) {
52
+ var type = event.type;
53
+ var originalEvent = event.originalEvent;
54
+
55
+ // Avoid errors from triggered native events for which `originalEvent` is
56
+ // not available.
57
+ if (!originalEvent) {
58
+ return;
59
+ }
60
+
61
+ var toElement = originalEvent.toElement;
62
+
63
+ // If it’s a `{focusin,focusout}` event (IE), `fromElement` and `toElement`
64
+ // should both be `null` or `undefined`; else, the page visibility hasn’t
65
+ // changed, but the user just clicked somewhere in the doc. In IE9, we need
66
+ // to check the `relatedTarget` property instead.
67
+ if (
68
+ !/^focus./.test(type) || (
69
+ toElement === undefined &&
70
+ originalEvent.fromElement === undefined &&
71
+ originalEvent.relatedTarget === undefined
72
+ )
73
+ ) {
74
+ visibilityChanged(property && document[property] || /^(?:blur|focusout)$/.test(type) ? 'hide' : 'show');
75
+ }
76
+ });
77
+
78
+ };
79
+ */
80
+
81
+ var hiddenProperty;
82
+
83
+ $.each(["","webkit","ms","moz","ms"], function(index, prefix){
84
+ var check = prefix + (prefix === "" ? "hidden" : "Hidden");
85
+ if(document[check] !== undefined ){
86
+ hiddenProperty = check;
87
+ }
88
+ });
89
+
90
+ var isHidden = function() {
91
+ if (hiddenProperty !== undefined){
92
+ return document[hiddenProperty];
93
+ } else {
94
+ return !document.hasFocus;
95
+ }
96
+ };
97
+
98
+ shouldLongPoll = function() {
99
+ return me.alwaysLongPoll || !isHidden();
100
+ };
101
+
102
+ longPoller = function(poll,data){
103
+ var gotData = false;
104
+ var lastAjax = new Date();
105
+
106
+ return $.ajax(baseUrl + "message-bus/" + clientId + "/poll?" + (!shouldLongPoll() || !me.enableLongPolling ? "dlp=t" : ""), {
107
+ data: data,
108
+ cache: false,
109
+ dataType: 'json',
110
+ type: 'POST',
111
+ headers: {
112
+ 'X-SILENCE-LOGGER': 'true'
113
+ },
114
+ success: function(messages) {
115
+ failCount = 0;
116
+ $.each(messages,function(_,message) {
117
+ gotData = true;
118
+ $.each(callbacks, function(_,callback) {
119
+ if (callback.channel === message.channel) {
120
+ callback.last_id = message.message_id;
121
+ callback.func(message.data);
122
+ }
123
+ if (message.channel === "/__status") {
124
+ if (message.data[callback.channel] !== undefined) {
125
+ callback.last_id = message.data[callback.channel];
126
+ }
127
+ }
128
+ });
129
+ });
130
+ },
131
+ error: failCount += 1,
132
+ complete: function() {
133
+ if (gotData) {
134
+ pollTimeout = setTimeout(poll, 100);
135
+ } else {
136
+ interval = me.callbackInterval;
137
+ if (failCount > 2) {
138
+ interval = interval * failCount;
139
+ } else if (!shouldLongPoll()) {
140
+ // slowning down stuff a lot when hidden
141
+ // we will need to add a lot of fine tuning here
142
+ interval = interval * 4;
143
+ }
144
+ if (interval > me.maxPollInterval) {
145
+ interval = me.maxPollInterval;
146
+ }
147
+
148
+ interval -= (new Date() - lastAjax);
149
+ if (interval < 100) {
150
+ interval = 100;
151
+ }
152
+
153
+ pollTimeout = setTimeout(poll, interval);
154
+ }
155
+ me.longPoll = null;
156
+ }
157
+ });
158
+ };
159
+
160
+ me = {
161
+ enableLongPolling: true,
162
+ callbackInterval: 15000,
163
+ maxPollInterval: 3 * 60 * 1000,
164
+ callbacks: callbacks,
165
+ clientId: clientId,
166
+ alwaysLongPoll: false,
167
+ baseUrl: baseUrl,
168
+
169
+ stop: function() {
170
+ stopped = true;
171
+ started = false;
172
+ },
173
+
174
+ // Start polling
175
+ start: function(opts) {
176
+ var poll;
177
+
178
+ if (started) return;
179
+ started = true;
180
+ stopped = false;
181
+
182
+ if (!opts) opts = {};
183
+
184
+ poll = function() {
185
+ var data;
186
+
187
+ if(stopped) {
188
+ return;
189
+ }
190
+
191
+ if (callbacks.length === 0) {
192
+ setTimeout(poll, 500);
193
+ return;
194
+ }
195
+
196
+ data = {};
197
+ $.each(callbacks, function(_,callback) {
198
+ data[callback.channel] = callback.last_id;
199
+ });
200
+ me.longPoll = longPoller(poll,data);
201
+ };
202
+ poll();
203
+ },
204
+
205
+ // Subscribe to a channel
206
+ subscribe: function(channel, func, lastId) {
207
+
208
+ if(!started && !stopped){
209
+ me.start();
210
+ }
211
+
212
+ if (typeof(lastId) !== "number" || lastId < -1){
213
+ lastId = -1;
214
+ }
215
+ callbacks.push({
216
+ channel: channel,
217
+ func: func,
218
+ last_id: lastId
219
+ });
220
+ if (me.longPoll) {
221
+ return me.longPoll.abort();
222
+ }
223
+ },
224
+
225
+ // Unsubscribe from a channel
226
+ unsubscribe: function(channel) {
227
+ // TODO proper globbing
228
+ var glob;
229
+ if (channel.indexOf("*", channel.length - 1) !== -1) {
230
+ channel = channel.substr(0, channel.length - 1);
231
+ glob = true;
232
+ }
233
+ callbacks = $.grep(callbacks,function(callback) {
234
+ if (glob) {
235
+ return callback.channel.substr(0, channel.length) !== channel;
236
+ } else {
237
+ return callback.channel !== channel;
238
+ }
239
+ });
240
+ if (me.longPoll) {
241
+ return me.longPoll.abort();
242
+ }
243
+ }
244
+ };
245
+
246
+ return me;
247
+ })();
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: 0.0.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-15 00:00:00.000000000 Z
11
+ date: 2013-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -24,20 +24,6 @@ dependencies:
24
24
  - - '>='
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.1.3
27
- - !ruby/object:Gem::Dependency
28
- name: thin
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '>='
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - '>='
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: eventmachine
43
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,26 +52,59 @@ dependencies:
66
52
  - - '>='
67
53
  - !ruby/object:Gem::Version
68
54
  version: '0'
69
- description: A message bus built on websockets
55
+ description: A message bus for rack
70
56
  email:
71
57
  - sam.saffron@gmail.com
72
58
  executables: []
73
59
  extensions: []
74
60
  extra_rdoc_files: []
75
61
  files:
76
- - README.md
62
+ - .gitignore
63
+ - .travis.yml
64
+ - CHANGELOG
65
+ - Gemfile
66
+ - Guardfile
77
67
  - LICENSE
68
+ - README.md
69
+ - Rakefile
70
+ - assets/application.handlebars
71
+ - assets/application.js
72
+ - assets/ember.js
73
+ - assets/handlebars.js
74
+ - assets/index.handlebars
75
+ - assets/jquery-1.8.2.js
76
+ - assets/message-bus.js
77
+ - examples/bench/ab.sample
78
+ - examples/bench/config.ru
79
+ - examples/bench/payload.post
80
+ - examples/bench/unicorn.conf.rb
81
+ - examples/chat/chat.rb
82
+ - examples/chat/config.ru
78
83
  - lib/message_bus.rb
79
- - lib/message_bus/rack/diagnostics.rb
80
- - lib/message_bus/rack/middleware.rb
81
- - lib/message_bus/message.rb
84
+ - lib/message_bus/client.rb
82
85
  - lib/message_bus/connection_manager.rb
86
+ - lib/message_bus/diagnostics.rb
87
+ - lib/message_bus/em_ext.rb
88
+ - lib/message_bus/message.rb
83
89
  - lib/message_bus/message_handler.rb
90
+ - lib/message_bus/rack/diagnostics.rb
91
+ - lib/message_bus/rack/middleware.rb
92
+ - lib/message_bus/rack/thin_ext.rb
84
93
  - lib/message_bus/rails/railtie.rb
85
- - lib/message_bus/version.rb
86
- - lib/message_bus/diagnostics.rb
87
- - lib/message_bus/client.rb
88
94
  - lib/message_bus/reliable_pub_sub.rb
95
+ - lib/message_bus/version.rb
96
+ - message_bus.gemspec
97
+ - spec/lib/client_spec.rb
98
+ - spec/lib/connection_manager_spec.rb
99
+ - spec/lib/fake_async_middleware.rb
100
+ - spec/lib/handlers/demo_message_handler.rb
101
+ - spec/lib/message_bus_spec.rb
102
+ - spec/lib/message_handler_spec.rb
103
+ - spec/lib/middleware_spec.rb
104
+ - spec/lib/multi_process_spec.rb
105
+ - spec/lib/reliable_pub_sub_spec.rb
106
+ - spec/spec_helper.rb
107
+ - vendor/assets/javascripts/message-bus.js
89
108
  homepage: ''
90
109
  licenses: []
91
110
  metadata: {}
@@ -105,8 +124,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
124
  version: '0'
106
125
  requirements: []
107
126
  rubyforge_project:
108
- rubygems_version: 2.0.2
127
+ rubygems_version: 2.0.3
109
128
  signing_key:
110
129
  specification_version: 4
111
130
  summary: ''
112
- test_files: []
131
+ test_files:
132
+ - spec/lib/client_spec.rb
133
+ - spec/lib/connection_manager_spec.rb
134
+ - spec/lib/fake_async_middleware.rb
135
+ - spec/lib/handlers/demo_message_handler.rb
136
+ - spec/lib/message_bus_spec.rb
137
+ - spec/lib/message_handler_spec.rb
138
+ - spec/lib/middleware_spec.rb
139
+ - spec/lib/multi_process_spec.rb
140
+ - spec/lib/reliable_pub_sub_spec.rb
141
+ - spec/spec_helper.rb