message_bus 4.3.1 → 4.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG +13 -2
- data/README.md +3 -8
- data/assets/message-bus.js +8 -4
- data/lib/message_bus/client.rb +1 -1
- data/lib/message_bus/rack/middleware.rb +4 -4
- data/lib/message_bus/version.rb +1 -1
- data/package-lock.json +573 -847
- data/spec/assets/SpecHelper.js +23 -5
- data/spec/assets/message-bus.spec.js +59 -0
- data/spec/lib/message_bus/client_spec.rb +6 -0
- data/vendor/assets/javascripts/message-bus.js +8 -4
- metadata +2 -2
data/spec/assets/SpecHelper.js
CHANGED
@@ -34,8 +34,23 @@ beforeEach(function () {
|
|
34
34
|
this.readyState = 4
|
35
35
|
this.responseText = encodeChunks(this, spec.responseChunks);
|
36
36
|
this.status = spec.responseStatus;
|
37
|
-
|
38
|
-
|
37
|
+
|
38
|
+
spec.requestStarted?.();
|
39
|
+
|
40
|
+
const complete = () => {
|
41
|
+
if(this.statusText === "abort"){
|
42
|
+
return;
|
43
|
+
}
|
44
|
+
this.onprogress?.();
|
45
|
+
this.onreadystatechange();
|
46
|
+
}
|
47
|
+
|
48
|
+
if(spec.delayResponsePromise){
|
49
|
+
spec.delayResponsePromise.then(() => complete())
|
50
|
+
spec.delayResponsePromise = null;
|
51
|
+
}else{
|
52
|
+
complete();
|
53
|
+
}
|
39
54
|
}
|
40
55
|
|
41
56
|
MockedXMLHttpRequest.prototype.open = function(){ }
|
@@ -43,8 +58,8 @@ beforeEach(function () {
|
|
43
58
|
MockedXMLHttpRequest.prototype.abort = function(){
|
44
59
|
this.readyState = 4
|
45
60
|
this.responseText = '';
|
46
|
-
this.statusText = '';
|
47
|
-
this.status =
|
61
|
+
this.statusText = 'abort';
|
62
|
+
this.status = 0;
|
48
63
|
this.onreadystatechange()
|
49
64
|
}
|
50
65
|
|
@@ -68,6 +83,10 @@ beforeEach(function () {
|
|
68
83
|
"Content-Type": 'text/plain; charset=utf-8',
|
69
84
|
};
|
70
85
|
|
86
|
+
MessageBus.enableChunkedEncoding = true;
|
87
|
+
MessageBus.firstChunkTimeout = 3000;
|
88
|
+
MessageBus.retryChunkedAfterRequests = 1;
|
89
|
+
|
71
90
|
MessageBus.start();
|
72
91
|
});
|
73
92
|
|
@@ -75,7 +94,6 @@ afterEach(function(){
|
|
75
94
|
MessageBus.stop()
|
76
95
|
MessageBus.callbacks.splice(0, MessageBus.callbacks.length)
|
77
96
|
MessageBus.shouldLongPollCallback = null;
|
78
|
-
MessageBus.enableChunkedEncoding = true;
|
79
97
|
});
|
80
98
|
|
81
99
|
window.testMB = function(description, testFn, path, data){
|
@@ -166,4 +166,63 @@ describe("Messagebus", function () {
|
|
166
166
|
const nextPollScheduledIn = window.setTimeout.calls.mostRecent().args[1];
|
167
167
|
expect(nextPollScheduledIn).toEqual(MessageBus.minPollInterval);
|
168
168
|
});
|
169
|
+
|
170
|
+
it("enters don't-chunk-mode if first chunk times out", async function () {
|
171
|
+
spyOn(this.MockedXMLHttpRequest.prototype, "send").and.callThrough();
|
172
|
+
spyOn(
|
173
|
+
this.MockedXMLHttpRequest.prototype,
|
174
|
+
"setRequestHeader"
|
175
|
+
).and.callThrough();
|
176
|
+
|
177
|
+
let resolveFirstResponse;
|
178
|
+
this.delayResponsePromise = new Promise(
|
179
|
+
(resolve) => (resolveFirstResponse = resolve)
|
180
|
+
);
|
181
|
+
MessageBus.firstChunkTimeout = 50;
|
182
|
+
|
183
|
+
await new Promise((resolve) => MessageBus.subscribe("/test", resolve));
|
184
|
+
resolveFirstResponse();
|
185
|
+
|
186
|
+
const calls =
|
187
|
+
this.MockedXMLHttpRequest.prototype.setRequestHeader.calls.all();
|
188
|
+
|
189
|
+
const dontChunkCalls = calls.filter((c) => c.args[0] === "Dont-Chunk");
|
190
|
+
expect(dontChunkCalls.length).toEqual(1);
|
191
|
+
});
|
192
|
+
|
193
|
+
it("doesn't enter don't-chunk-mode if aborted before first chunk", async function () {
|
194
|
+
spyOn(
|
195
|
+
this.MockedXMLHttpRequest.prototype,
|
196
|
+
"setRequestHeader"
|
197
|
+
).and.callThrough();
|
198
|
+
|
199
|
+
this.delayResponsePromise = new Promise(() => {});
|
200
|
+
MessageBus.firstChunkTimeout = 300;
|
201
|
+
|
202
|
+
const requestWasStarted = new Promise(
|
203
|
+
(resolve) => (this.requestStarted = resolve)
|
204
|
+
);
|
205
|
+
|
206
|
+
// Trigger request
|
207
|
+
const subscribedPromise = new Promise((resolve) =>
|
208
|
+
MessageBus.subscribe("/test", resolve)
|
209
|
+
);
|
210
|
+
|
211
|
+
await requestWasStarted;
|
212
|
+
|
213
|
+
// Change subscription (triggers an abort and re-poll)
|
214
|
+
MessageBus.subscribe("/test2", () => {});
|
215
|
+
|
216
|
+
// Wait for stuff to settle
|
217
|
+
await subscribedPromise;
|
218
|
+
|
219
|
+
// Wait 300ms to ensure dontChunk timeout has passed
|
220
|
+
await new Promise((resolve) => setTimeout(resolve, 300));
|
221
|
+
|
222
|
+
const calls =
|
223
|
+
this.MockedXMLHttpRequest.prototype.setRequestHeader.calls.all();
|
224
|
+
|
225
|
+
const dontChunkCalls = calls.filter((c) => c.args[0] === "Dont-Chunk");
|
226
|
+
expect(dontChunkCalls.length).toEqual(0);
|
227
|
+
});
|
169
228
|
});
|
@@ -99,6 +99,12 @@ describe MessageBus::Client do
|
|
99
99
|
chunk2.length.must_equal 0
|
100
100
|
end
|
101
101
|
|
102
|
+
it "does not raise an error when trying to write a message to a closed client using chunked encoding" do
|
103
|
+
@client.use_chunked = true
|
104
|
+
assert(@client.closed?)
|
105
|
+
@client << MessageBus::Message.new(1, 1, "/test", "test")
|
106
|
+
end
|
107
|
+
|
102
108
|
it "does not bleed data across sites" do
|
103
109
|
@client.site_id = "test"
|
104
110
|
|
@@ -205,10 +205,11 @@
|
|
205
205
|
return handle_progress(payload, endChunk + separator.length);
|
206
206
|
};
|
207
207
|
|
208
|
+
var chunkedTimeout;
|
208
209
|
var disableChunked = function () {
|
209
210
|
if (me.longPoll) {
|
210
211
|
me.longPoll.abort();
|
211
|
-
chunkedBackoff =
|
212
|
+
chunkedBackoff = me.retryChunkedAfterRequests;
|
212
213
|
}
|
213
214
|
};
|
214
215
|
|
@@ -235,9 +236,9 @@
|
|
235
236
|
chunked: chunked,
|
236
237
|
onProgressListener: function (xhr) {
|
237
238
|
var position = 0;
|
238
|
-
// if it takes longer than
|
239
|
-
//
|
240
|
-
|
239
|
+
// if it takes longer than firstChunkTimeout to get first chunk, there may be a proxy
|
240
|
+
// buffering the response. Switch to non-chunked long-polling mode.
|
241
|
+
chunkedTimeout = setTimeout(disableChunked, me.firstChunkTimeout);
|
241
242
|
return (xhr.onprogress = function () {
|
242
243
|
clearTimeout(chunkedTimeout);
|
243
244
|
if (
|
@@ -269,6 +270,7 @@
|
|
269
270
|
}
|
270
271
|
},
|
271
272
|
error: function (xhr, textStatus) {
|
273
|
+
clearTimeout(chunkedTimeout);
|
272
274
|
if (xhr.status === 429) {
|
273
275
|
var tryAfter =
|
274
276
|
parseInt(
|
@@ -364,6 +366,8 @@
|
|
364
366
|
clientId: clientId,
|
365
367
|
alwaysLongPoll: false,
|
366
368
|
shouldLongPollCallback: undefined,
|
369
|
+
firstChunkTimeout: 3000,
|
370
|
+
retryChunkedAfterRequests: 30,
|
367
371
|
baseUrl: baseUrl,
|
368
372
|
headers: {},
|
369
373
|
ajax: typeof jQuery !== "undefined" && jQuery.ajax,
|
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: 4.3.
|
4
|
+
version: 4.3.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: 2023-
|
11
|
+
date: 2023-06-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|