message_bus 2.1.6 → 2.2.0.pre

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +13 -92
  3. data/.rubocop_todo.yml +659 -0
  4. data/.travis.yml +1 -1
  5. data/CHANGELOG +61 -0
  6. data/Dockerfile +18 -0
  7. data/Gemfile +3 -1
  8. data/Guardfile +0 -1
  9. data/README.md +188 -101
  10. data/Rakefile +12 -1
  11. data/assets/message-bus.js +1 -1
  12. data/docker-compose.yml +46 -0
  13. data/examples/bench/config.ru +8 -9
  14. data/examples/bench/unicorn.conf.rb +1 -1
  15. data/examples/chat/chat.rb +150 -153
  16. data/examples/minimal/config.ru +2 -3
  17. data/lib/message_bus.rb +224 -36
  18. data/lib/message_bus/backends.rb +7 -0
  19. data/lib/message_bus/backends/base.rb +184 -0
  20. data/lib/message_bus/backends/memory.rb +304 -226
  21. data/lib/message_bus/backends/postgres.rb +359 -318
  22. data/lib/message_bus/backends/redis.rb +380 -337
  23. data/lib/message_bus/client.rb +99 -41
  24. data/lib/message_bus/connection_manager.rb +29 -21
  25. data/lib/message_bus/diagnostics.rb +50 -41
  26. data/lib/message_bus/distributed_cache.rb +5 -7
  27. data/lib/message_bus/message.rb +2 -2
  28. data/lib/message_bus/rack/diagnostics.rb +65 -55
  29. data/lib/message_bus/rack/middleware.rb +64 -44
  30. data/lib/message_bus/rack/thin_ext.rb +13 -9
  31. data/lib/message_bus/rails/railtie.rb +2 -0
  32. data/lib/message_bus/timer_thread.rb +2 -2
  33. data/lib/message_bus/version.rb +2 -1
  34. data/message_bus.gemspec +3 -2
  35. data/spec/assets/support/jasmine_helper.rb +1 -1
  36. data/spec/lib/fake_async_middleware.rb +1 -6
  37. data/spec/lib/message_bus/assets/asset_encoding_spec.rb +3 -3
  38. data/spec/lib/message_bus/backend_spec.rb +409 -0
  39. data/spec/lib/message_bus/client_spec.rb +8 -11
  40. data/spec/lib/message_bus/connection_manager_spec.rb +8 -14
  41. data/spec/lib/message_bus/distributed_cache_spec.rb +0 -4
  42. data/spec/lib/message_bus/multi_process_spec.rb +6 -7
  43. data/spec/lib/message_bus/rack/middleware_spec.rb +47 -43
  44. data/spec/lib/message_bus/timer_thread_spec.rb +0 -2
  45. data/spec/lib/message_bus_spec.rb +59 -43
  46. data/spec/spec_helper.rb +16 -4
  47. metadata +12 -9
  48. data/spec/lib/message_bus/backends/postgres_spec.rb +0 -221
  49. data/spec/lib/message_bus/backends/redis_spec.rb +0 -271
data/Rakefile CHANGED
@@ -8,6 +8,17 @@ require 'jasmine'
8
8
  ENV['JASMINE_CONFIG_PATH'] ||= File.join(Dir.pwd, 'spec', 'assets', 'support', 'jasmine.yml')
9
9
  load 'jasmine/tasks/jasmine.rake'
10
10
 
11
+ require 'rubocop/rake_task'
12
+ RuboCop::RakeTask.new
13
+
14
+ require 'yard'
15
+ YARD::Rake::YardocTask.new
16
+
17
+ desc "Generate documentation for Yard, and fail if there are any warnings"
18
+ task :test_doc do
19
+ sh "yard --fail-on-warning #{'--no-progress' if ENV['CI']}"
20
+ end
21
+
11
22
  Bundler.require(:default, :test)
12
23
 
13
24
  task default: :spec
@@ -34,7 +45,7 @@ run_spec = proc do |backend|
34
45
  end
35
46
  end
36
47
 
37
- task spec: [:spec_redis, :spec_postgres, :spec_memory, :spec_client_js]
48
+ task spec: [:spec_memory, :spec_redis, :spec_postgres, :spec_client_js, :rubocop, :test_doc]
38
49
 
39
50
  task spec_client_js: 'jasmine:ci'
40
51
 
@@ -440,7 +440,7 @@
440
440
 
441
441
  // Subscribe to a channel
442
442
  // if lastId is 0 or larger, it will recieve messages AFTER that id
443
- // if lastId is nagative it will perform lookbehind"
443
+ // if lastId is negative it will perform lookbehind
444
444
  // -1 will subscribe to all new messages
445
445
  // -2 will recieve last message + all new messages
446
446
  // -3 will recieve last 2 messages + all new messages
@@ -0,0 +1,46 @@
1
+ version: '3'
2
+ volumes:
3
+ bundle_config:
4
+ bundle:
5
+ redis_data:
6
+ postgres_data:
7
+ services:
8
+ tests:
9
+ build:
10
+ context: .
11
+ environment:
12
+ BUNDLE_TO: /usr/local/bundle
13
+ REDISURL: redis://redis:6379
14
+ PGHOST: postgres
15
+ PGUSER: postgres
16
+ PGPASSWORD: "1234"
17
+ volumes:
18
+ - .:/usr/src/app
19
+ - bundle_config:/home/src/app/.bundle
20
+ - bundle:/usr/local/bundle
21
+ depends_on:
22
+ - postgres
23
+ - redis
24
+ docs:
25
+ build:
26
+ context: .
27
+ command: yard server --bind 0.0.0.0 --reload
28
+ environment:
29
+ BUNDLE_TO: /usr/local/bundle
30
+ volumes:
31
+ - .:/usr/src/app
32
+ - bundle_config:/home/src/app/.bundle
33
+ - bundle:/usr/local/bundle
34
+ ports:
35
+ - 8808:8808
36
+ redis:
37
+ image: redis:5.0
38
+ volumes:
39
+ - redis_data:/data
40
+ postgres:
41
+ image: postgres:11.0
42
+ volumes:
43
+ - postgres_data:/var/lib/postgresql/data
44
+ environment:
45
+ - POSTGRES_PASSWORD=1234
46
+ - POSTGRES_DB=message_bus_test
@@ -4,17 +4,16 @@ require 'message_bus'
4
4
  require 'stackprof'
5
5
 
6
6
  if defined?(PhusionPassenger)
7
- PhusionPassenger.on_event(:starting_worker_process) do |forked|
8
- if forked
9
- # We're in smart spawning mode.
10
- MessageBus.after_fork
11
- else
12
- # We're in conservative spawning mode. We don't need to do anything.
13
- end
7
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
8
+ if forked
9
+ # We're in smart spawning mode.
10
+ MessageBus.after_fork
11
+ else
12
+ # We're in conservative spawning mode. We don't need to do anything.
14
13
  end
14
+ end
15
15
  end
16
16
 
17
-
18
17
  # require 'rack-mini-profiler'
19
18
 
20
19
  # Rack::MiniProfiler.config.storage = Rack::MiniProfiler::MemoryStore
@@ -30,4 +29,4 @@ end
30
29
  MessageBus.long_polling_interval = 1000 * 2
31
30
  MessageBus.max_active_clients = 10000
32
31
  use MessageBus::Rack::Middleware
33
- run lambda { |env| [200, {"Content-Type" => "text/html"}, ["Howdy"]] }
32
+ run lambda { |_env| [200, { "Content-Type" => "text/html" }, ["Howdy"]] }
@@ -1,4 +1,4 @@
1
1
  require 'message_bus'
2
- after_fork do |server, worker|
2
+ after_fork do |_server, _worker|
3
3
  MessageBus.after_fork
4
4
  end
@@ -7,13 +7,12 @@ require 'json'
7
7
 
8
8
  $online = Hash.new
9
9
 
10
-
11
10
  MessageBus.subscribe "/presence" do |msg|
12
11
  if user = msg.data["enter"]
13
- $online[user] = Time.now
12
+ $online[user] = Time.now
14
13
  end
15
14
  if user = msg.data["leave"]
16
- $online.delete user
15
+ $online.delete user
17
16
  end
18
17
  end
19
18
 
@@ -22,7 +21,7 @@ MessageBus.user_id_lookup do |env|
22
21
  name = env["HTTP_X_NAME"]
23
22
  if name
24
23
  unless $online[name]
25
- MessageBus.publish "/presence", {enter: name}
24
+ MessageBus.publish "/presence", enter: name
26
25
  end
27
26
  $online[name] = Time.now
28
27
  end
@@ -30,10 +29,10 @@ MessageBus.user_id_lookup do |env|
30
29
  end
31
30
 
32
31
  def expire_old_sessions
33
- $online.each do |name,time|
34
- if (Time.now - (5*60)) > time
35
- puts "forcing leave for #{name} session timed out"
36
- MessageBus.publish "/presence", {leave: name}
32
+ $online.each do |name, time|
33
+ if (Time.now - (5 * 60)) > time
34
+ puts "forcing leave for #{name} session timed out"
35
+ MessageBus.publish "/presence", leave: name
37
36
  end
38
37
  end
39
38
  rescue => e
@@ -48,8 +47,7 @@ Thread.new do
48
47
  end
49
48
 
50
49
  class Chat < Sinatra::Base
51
-
52
- set :public_folder, File.expand_path('../../../assets',__FILE__)
50
+ set :public_folder, File.expand_path('../../../assets', __FILE__)
53
51
 
54
52
  use MessageBus::Rack::Middleware
55
53
 
@@ -60,166 +58,165 @@ class Chat < Sinatra::Base
60
58
  name = "#{params["name"]}#{i}"
61
59
  i += 1
62
60
  end
63
- MessageBus.publish '/presence', {enter: name}
64
- {users: $online.keys, name: name}.to_json
61
+ MessageBus.publish '/presence', enter: name
62
+ { users: $online.keys, name: name }.to_json
65
63
  end
66
64
 
67
65
  post '/leave' do
68
- #puts "Got leave for #{params["name"]}"
69
- MessageBus.publish '/presence', {leave: params["name"]}
66
+ # puts "Got leave for #{params["name"]}"
67
+ MessageBus.publish '/presence', leave: params["name"]
70
68
  end
71
69
 
72
70
  post '/message' do
73
- msg = {data: params["data"][0..500], name: params["name"][0..100]}
71
+ msg = { data: params["data"][0..500], name: params["name"][0..100] }
74
72
  MessageBus.publish '/message', msg
75
73
 
76
74
  "OK"
77
75
  end
78
76
 
79
77
  get '/' do
80
-
81
- <<HTML
82
-
83
- <html>
84
- <head>
85
- <script src="/jquery-1.8.2.js"></script>
86
- <script src="/message-bus.js"></script>
87
- <style>
88
- #panel { position: fixed; bottom: 0; background-color: #FFFFFF; }
89
- #panel form { margin-bottom: 4px; }
90
- #panel button, #panel textarea { height: 40px }
91
- #panel button { width: 100px; vertical-align: top; }
92
- #messages { padding-bottom: 40px; }
93
- .hidden { display: none; }
94
- #users {
95
- position: fixed; top: 0; right: 0; width: 160px; background-color: #fafafa; height: 100%;
96
- border-left: 1px solid #dfdfdf;
97
- padding: 5px;
98
- }
99
- #users ul li { margin: 0; padding: 0; }
100
- #users ul li.me { font-weight: bold; }
101
- #users ul { list-style: none; margin 0; padding: 0; }
102
- body { padding-right: 160px; }
103
- </style>
104
- </head>
105
- <body>
106
- <p>This is a trivial chat demo... It is implemented as a <a href="https://github.com/SamSaffron/message_bus/blob/master/examples/chat/chat.rb">Sinatra app</a>. The <a href="https://github.com/SamSaffron/message_bus">message_bus</a> can easily be added to any Rails/Rack app. <small>This app can be deployed with <a href="https://github.com/discourse/discourse_docker">Discourse Docker</a> using <a href="https://github.com/SamSaffron/message_bus/blob/master/examples/chat/docker_container/chat.yml">this template</a>.</small></p>
107
- <div id='messages' class="hidden"></div>
108
- <div id='users' class="hidden">
109
- <h3>Online</h3>
110
- <ul></ul>
111
- </div>
112
- <div id='panel' class="hidden">
113
- <form>
114
- <textarea cols=80 rows=2></textarea>
115
- <button id="send">send</button>
116
- </form>
117
- </div>
118
- <div id='your-name'>Enter your name: <input type='text'/>
119
-
120
- <script>
121
- $(function() {
122
- var name;
123
-
124
- MessageBus.headers["X-NAME"] = name;
125
-
126
- var enter = function(name, opts) {
127
- if (opts && opts.check) {
128
- var found = false;
129
- $('#users ul li').each(function(){
130
- found = found || ($(this).text().trim() === name.trim());
131
- if (found && opts.me) {
132
- $(this).remove();
133
- found = false;
78
+ <<~HTML
79
+
80
+ <html>
81
+ <head>
82
+ <script src="/jquery-1.8.2.js"></script>
83
+ <script src="/message-bus.js"></script>
84
+ <style>
85
+ #panel { position: fixed; bottom: 0; background-color: #FFFFFF; }
86
+ #panel form { margin-bottom: 4px; }
87
+ #panel button, #panel textarea { height: 40px }
88
+ #panel button { width: 100px; vertical-align: top; }
89
+ #messages { padding-bottom: 40px; }
90
+ .hidden { display: none; }
91
+ #users {
92
+ position: fixed; top: 0; right: 0; width: 160px; background-color: #fafafa; height: 100%;
93
+ border-left: 1px solid #dfdfdf;
94
+ padding: 5px;
95
+ }
96
+ #users ul li { margin: 0; padding: 0; }
97
+ #users ul li.me { font-weight: bold; }
98
+ #users ul { list-style: none; margin 0; padding: 0; }
99
+ body { padding-right: 160px; }
100
+ </style>
101
+ </head>
102
+ <body>
103
+ <p>This is a trivial chat demo... It is implemented as a <a href="https://github.com/SamSaffron/message_bus/blob/master/examples/chat/chat.rb">Sinatra app</a>. The <a href="https://github.com/SamSaffron/message_bus">message_bus</a> can easily be added to any Rails/Rack app. <small>This app can be deployed with <a href="https://github.com/discourse/discourse_docker">Discourse Docker</a> using <a href="https://github.com/SamSaffron/message_bus/blob/master/examples/chat/docker_container/chat.yml">this template</a>.</small></p>
104
+ <div id='messages' class="hidden"></div>
105
+ <div id='users' class="hidden">
106
+ <h3>Online</h3>
107
+ <ul></ul>
108
+ </div>
109
+ <div id='panel' class="hidden">
110
+ <form>
111
+ <textarea cols=80 rows=2></textarea>
112
+ <button id="send">send</button>
113
+ </form>
114
+ </div>
115
+ <div id='your-name'>Enter your name: <input type='text'/>
116
+
117
+ <script>
118
+ $(function() {
119
+ var name;
120
+
121
+ MessageBus.headers["X-NAME"] = name;
122
+
123
+ var enter = function(name, opts) {
124
+ if (opts && opts.check) {
125
+ var found = false;
126
+ $('#users ul li').each(function(){
127
+ found = found || ($(this).text().trim() === name.trim());
128
+ if (found && opts.me) {
129
+ $(this).remove();
130
+ found = false;
131
+ }
132
+ return !found;
133
+ });
134
+ if (found) { return; }
135
+ }
136
+
137
+ var li = $('<li></li>');
138
+ li.text(name);
139
+ if (opts && opts.me) {
140
+ li.addClass("me");
141
+ $('#users ul').prepend(li);
142
+ } else {
143
+ $('#users ul').append(li);
144
+ }
145
+ };
146
+
147
+ $('#messages, #panel').addClass('hidden');
148
+
149
+ $('#your-name input').keyup(function(e){
150
+ if(e.keyCode == 13) {
151
+ name = $(this).val();
152
+ $.post("/enter", { name: name}, null, "json" ).success(function(data){
153
+ $.each(data.users,function(idx, name){
154
+ enter(name);
155
+ });
156
+ name = data.name;
157
+ enter(name, {check: true, me: true});
158
+ });
159
+ $('#your-name').addClass('hidden');
160
+ $('#messages, #panel, #users').removeClass('hidden');
161
+ $(document.body).scrollTop(document.body.scrollHeight);
162
+
163
+ window.onbeforeunload = function(){
164
+ $.post("/leave", { name: name });
165
+ };
166
+
167
+ MessageBus.subscribe("/presence", function(msg){
168
+ if (msg.enter) {
169
+ enter(msg.enter, {check: true});
170
+ }
171
+ if (msg.leave) {
172
+ $('#users ul li').each(function(){
173
+ if ($(this).text() === msg.leave) {
174
+ $(this).remove()
175
+ }
176
+ });
177
+ }
178
+ });
134
179
  }
135
- return !found;
136
- });
137
- if (found) { return; }
138
- }
139
-
140
- var li = $('<li></li>');
141
- li.text(name);
142
- if (opts && opts.me) {
143
- li.addClass("me");
144
- $('#users ul').prepend(li);
145
- } else {
146
- $('#users ul').append(li);
147
- }
148
- };
149
-
150
- $('#messages, #panel').addClass('hidden');
151
-
152
- $('#your-name input').keyup(function(e){
153
- if(e.keyCode == 13) {
154
- name = $(this).val();
155
- $.post("/enter", { name: name}, null, "json" ).success(function(data){
156
- $.each(data.users,function(idx, name){
157
- enter(name);
158
180
  });
159
- name = data.name;
160
- enter(name, {check: true, me: true});
161
- });
162
- $('#your-name').addClass('hidden');
163
- $('#messages, #panel, #users').removeClass('hidden');
164
- $(document.body).scrollTop(document.body.scrollHeight);
165
181
 
166
- window.onbeforeunload = function(){
167
- $.post("/leave", { name: name });
168
- };
182
+ var safe = function(html){
183
+ return String(html).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
184
+ };
185
+
186
+ MessageBus.subscribe("/message", function(msg){
187
+ $('#messages').append("<p>"+ safe(msg.name) + " said: " + safe(msg.data) + "</p>");
188
+ $(document.body).scrollTop(document.body.scrollHeight);
189
+ }, 0); // last id is zero, so getting backlog
190
+
191
+ var submit = function(){
192
+ var val = $('form textarea').val().trim();
193
+ if (val.length === 0) {
194
+ return;
195
+ }
196
+
197
+ if (val.length > 500) {
198
+ alert("message too long");
199
+ return false;
200
+ } else {
201
+ $.post("/message", { data: val, name: name} );
202
+ }
203
+ $('textarea').val("");
204
+ };
205
+
206
+ $('#send').click(function(){submit(); return false;});
207
+
208
+ $('textarea').keyup(function(e){
209
+ if(e.keyCode == 13) {
210
+ submit();
211
+ }
212
+ });
169
213
 
170
- MessageBus.subscribe("/presence", function(msg){
171
- if (msg.enter) {
172
- enter(msg.enter, {check: true});
173
- }
174
- if (msg.leave) {
175
- $('#users ul li').each(function(){
176
- if ($(this).text() === msg.leave) {
177
- $(this).remove()
178
- }
179
- });
180
- }
181
214
  });
182
- }
183
- });
184
-
185
- var safe = function(html){
186
- return String(html).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
187
- };
188
-
189
- MessageBus.subscribe("/message", function(msg){
190
- $('#messages').append("<p>"+ safe(msg.name) + " said: " + safe(msg.data) + "</p>");
191
- $(document.body).scrollTop(document.body.scrollHeight);
192
- }, 0); // last id is zero, so getting backlog
193
-
194
- var submit = function(){
195
- var val = $('form textarea').val().trim();
196
- if (val.length === 0) {
197
- return;
198
- }
199
-
200
- if (val.length > 500) {
201
- alert("message too long");
202
- return false;
203
- } else {
204
- $.post("/message", { data: val, name: name} );
205
- }
206
- $('textarea').val("");
207
- };
208
-
209
- $('#send').click(function(){submit(); return false;});
210
-
211
- $('textarea').keyup(function(e){
212
- if(e.keyCode == 13) {
213
- submit();
214
- }
215
- });
216
-
217
- });
218
- </script>
219
- </body>
220
- </html>
221
-
222
- HTML
215
+ </script>
216
+ </body>
217
+ </html>
218
+
219
+ HTML
223
220
  end
224
221
 
225
222
  run! if app_file == $0