braid-http 1.0.5 → 1.0.7

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.
@@ -169,6 +169,9 @@ async function braid_fetch (url, params = {}) {
169
169
  params.headers.set('subscribe', 'true')
170
170
  if (params.peer)
171
171
  params.headers.set('peer', params.peer)
172
+
173
+ if (params.heartbeats)
174
+ params.headers.set('heartbeats', typeof params.heartbeats === 'number' ? `${params.heartbeats}s` : params.heartbeats)
172
175
 
173
176
  // Prevent browsers from going to disk cache
174
177
  params.cache = 'no-cache'
@@ -225,8 +228,23 @@ async function braid_fetch (url, params = {}) {
225
228
  return await new Promise((done, fail) => {
226
229
  connect()
227
230
  async function connect() {
231
+ let on_error = e => {
232
+ on_error = () => {}
233
+
234
+ if (!params.retry || (e.name === "AbortError")) {
235
+ subscription_error?.(e)
236
+ return fail(e)
237
+ }
238
+
239
+ underlying_aborter.abort()
240
+
241
+ console.log(`retrying in ${waitTime}ms: ${url} after error: ${e}`)
242
+ setTimeout(connect, waitTime)
243
+ waitTime = Math.min(waitTime * 2, 3000)
244
+ }
245
+
228
246
  try {
229
- if (original_signal?.aborted) return fail(new Error('abort'))
247
+ if (original_signal?.aborted) throw new DOMException('already aborted', 'AbortError')
230
248
 
231
249
  // We need a fresh underlying abort controller each time we connect
232
250
  underlying_aborter = new AbortController()
@@ -257,6 +275,23 @@ async function braid_fetch (url, params = {}) {
257
275
  subscription_cb = cb
258
276
  subscription_error = error
259
277
 
278
+ // heartbeat
279
+ let on_heartbeat = () => {}
280
+ if (res.headers.get('heartbeats')) {
281
+ let heartbeats = parseFloat(res.headers.get('heartbeats'))
282
+ if (isFinite(heartbeats)) {
283
+ let timeout = null
284
+ on_heartbeat = () => {
285
+ clearTimeout(timeout)
286
+ let wait_seconds = 1.2 * heartbeats + 3
287
+ timeout = setTimeout(() => {
288
+ on_error(new Error(`heartbeat not seen in ${wait_seconds.toFixed(2)}s`))
289
+ }, wait_seconds * 1000)
290
+ }
291
+ on_heartbeat()
292
+ }
293
+ }
294
+
260
295
  if (!res.ok)
261
296
  throw new Error('Request returned not ok status:', res.status)
262
297
 
@@ -274,20 +309,17 @@ async function braid_fetch (url, params = {}) {
274
309
  if (!err)
275
310
  // Yay! We got a new version! Tell the callback!
276
311
  cb(result)
277
- else {
312
+ else
278
313
  // This error handling code runs if the connection
279
314
  // closes, or if there is unparseable stuff in the
280
315
  // streamed response.
281
-
282
- // In any case, we want to be sure to abort the
283
- // underlying fetch.
284
- underlying_aborter.abort()
285
-
286
316
  on_error(err)
287
- }
288
317
  },
289
318
  !isTextContentType(res.headers.get('content-type')),
290
- params.onBytes
319
+ (...args) => {
320
+ on_heartbeat()
321
+ params.onBytes?.(...args)
322
+ }
291
323
  )
292
324
  }
293
325
 
@@ -366,16 +398,6 @@ async function braid_fetch (url, params = {}) {
366
398
  waitTime = 10
367
399
  } catch (e) { on_error(e) }
368
400
  }
369
- function on_error(e) {
370
- if (!params.retry || (e.name === "AbortError")) {
371
- subscription_error?.(e)
372
- return fail(e)
373
- }
374
-
375
- console.log(`retrying in ${waitTime}ms: ${url} after error: ${e}`)
376
- setTimeout(connect, waitTime)
377
- waitTime = Math.min(waitTime * 2, 3000)
378
- }
379
401
  })
380
402
  }
381
403
 
@@ -270,6 +270,22 @@ function braidify (req, res, next) {
270
270
  res.on('close', x => disconnected('close'))
271
271
  res.on('finish', x => disconnected('finish'))
272
272
  req.on('abort', x => disconnected('abort'))
273
+
274
+ // Heartbeats
275
+ if (req.headers['heartbeats']) {
276
+ let heartbeats = parseFloat(req.headers['heartbeats'])
277
+ if (isFinite(heartbeats)) {
278
+ res.setHeader('heartbeats', req.headers['heartbeats'])
279
+ let closed
280
+ res.on('close', () => closed = true)
281
+ loop()
282
+ function loop() {
283
+ if (res.writableEnded || closed) return
284
+ res.write("\r\n")
285
+ setTimeout(loop, 1000 * heartbeats)
286
+ }
287
+ }
288
+ }
273
289
  }
274
290
 
275
291
  // Check the Useragent to work around Firefox bugs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-http",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "An implementation of Braid-HTTP for Node.js and Browsers",
5
5
  "scripts": {
6
6
  "test": "node test/server.js"