message_bus 2.1.6 → 2.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.

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