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.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -92
- data/.rubocop_todo.yml +659 -0
- data/.travis.yml +1 -1
- data/CHANGELOG +61 -0
- data/Dockerfile +18 -0
- data/Gemfile +3 -1
- data/Guardfile +0 -1
- data/README.md +188 -101
- data/Rakefile +12 -1
- data/assets/message-bus.js +1 -1
- data/docker-compose.yml +46 -0
- data/examples/bench/config.ru +8 -9
- data/examples/bench/unicorn.conf.rb +1 -1
- data/examples/chat/chat.rb +150 -153
- data/examples/minimal/config.ru +2 -3
- data/lib/message_bus.rb +224 -36
- data/lib/message_bus/backends.rb +7 -0
- data/lib/message_bus/backends/base.rb +184 -0
- data/lib/message_bus/backends/memory.rb +304 -226
- data/lib/message_bus/backends/postgres.rb +359 -318
- data/lib/message_bus/backends/redis.rb +380 -337
- data/lib/message_bus/client.rb +99 -41
- data/lib/message_bus/connection_manager.rb +29 -21
- data/lib/message_bus/diagnostics.rb +50 -41
- data/lib/message_bus/distributed_cache.rb +5 -7
- data/lib/message_bus/message.rb +2 -2
- data/lib/message_bus/rack/diagnostics.rb +65 -55
- data/lib/message_bus/rack/middleware.rb +64 -44
- data/lib/message_bus/rack/thin_ext.rb +13 -9
- data/lib/message_bus/rails/railtie.rb +2 -0
- data/lib/message_bus/timer_thread.rb +2 -2
- data/lib/message_bus/version.rb +2 -1
- data/message_bus.gemspec +3 -2
- data/spec/assets/support/jasmine_helper.rb +1 -1
- data/spec/lib/fake_async_middleware.rb +1 -6
- data/spec/lib/message_bus/assets/asset_encoding_spec.rb +3 -3
- data/spec/lib/message_bus/backend_spec.rb +409 -0
- data/spec/lib/message_bus/client_spec.rb +8 -11
- data/spec/lib/message_bus/connection_manager_spec.rb +8 -14
- data/spec/lib/message_bus/distributed_cache_spec.rb +0 -4
- data/spec/lib/message_bus/multi_process_spec.rb +6 -7
- data/spec/lib/message_bus/rack/middleware_spec.rb +47 -43
- data/spec/lib/message_bus/timer_thread_spec.rb +0 -2
- data/spec/lib/message_bus_spec.rb +59 -43
- data/spec/spec_helper.rb +16 -4
- metadata +12 -9
- data/spec/lib/message_bus/backends/postgres_spec.rb +0 -221
- 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, :
|
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
|
|
data/assets/message-bus.js
CHANGED
@@ -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
|
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
|
data/docker-compose.yml
ADDED
@@ -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
|
data/examples/bench/config.ru
CHANGED
@@ -4,17 +4,16 @@ require 'message_bus'
|
|
4
4
|
require 'stackprof'
|
5
5
|
|
6
6
|
if defined?(PhusionPassenger)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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 { |
|
32
|
+
run lambda { |_env| [200, { "Content-Type" => "text/html" }, ["Howdy"]] }
|
data/examples/chat/chat.rb
CHANGED
@@ -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
|
-
|
12
|
+
$online[user] = Time.now
|
14
13
|
end
|
15
14
|
if user = msg.data["leave"]
|
16
|
-
|
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",
|
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
|
-
|
36
|
-
|
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',
|
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',
|
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
|
-
|
82
|
-
|
83
|
-
<
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
182
|
+
var safe = function(html){
|
183
|
+
return String(html).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
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
|
-
|
186
|
-
|
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
|