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.
@@ -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
- if (this.onprogress){ this.onprogress(); }
38
- this.onreadystatechange()
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 = 400;
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 = 30;
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 3000 ms to get first chunk, we have some proxy
239
- // this is messing with us, so just backoff from using chunked for now
240
- var chunkedTimeout = setTimeout(disableChunked, 3000);
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.1
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-01-06 00:00:00.000000000 Z
11
+ date: 2023-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack