Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit 9e48da3

Browse files
authored
chore: simplify streaming http response code and use instances of pubsub tracker instead of a singleton (#3719)
Simplifies deps, pass peer id as string instead of cid.
1 parent b5470d4 commit 9e48da3

File tree

21 files changed

+295
-341
lines changed

21 files changed

+295
-341
lines changed

packages/interface-ipfs-core/src/pubsub/unsubscribe.js

+2-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
const { isBrowser, isWebWorker, isElectronRenderer } = require('ipfs-utils/src/env')
55
const { getTopic } = require('./utils')
66
const { getDescribe, getIt, expect } = require('../utils/mocha')
7-
const delay = require('delay')
87

98
/** @typedef { import("ipfsd-ctl/src/factory") } Factory */
109
/**
@@ -41,9 +40,7 @@ module.exports = (common, options) => {
4140
await ipfs.pubsub.unsubscribe(someTopic, handlers[i])
4241
}
4342

44-
await delay(100)
45-
const topics = await ipfs.pubsub.ls()
46-
expect(topics).to.eql([])
43+
return expect(ipfs.pubsub.ls()).to.eventually.eql([])
4744
})
4845

4946
it(`should subscribe ${count} handlers and unsubscribe once with no reference to the handlers`, async () => {
@@ -53,9 +50,7 @@ module.exports = (common, options) => {
5350
}
5451
await ipfs.pubsub.unsubscribe(someTopic)
5552

56-
await delay(100)
57-
const topics = await ipfs.pubsub.ls()
58-
expect(topics).to.eql([])
53+
return expect(ipfs.pubsub.ls()).to.eventually.eql([])
5954
})
6055
})
6156
}

packages/ipfs-core-types/src/repo/index.d.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,16 @@ export interface GCOptions extends AbortOptions {
2626
}
2727

2828
export interface GCError {
29-
err: Error
29+
err: Error,
30+
cid?: never
3031
}
3132

3233
export interface GCSuccess {
34+
err?: never,
3335
cid: CID
3436
}
3537

36-
export type GCResult = GCSuccess | GCError
38+
export type GCResult = GCSuccess | GCError
3739

3840
export interface StatResult {
3941
numObjects: BigInt
+13-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
'use strict'
22

3+
const SubscriptionTracker = require('./subscription-tracker')
4+
35
/**
46
* @param {import('../types').Options} config
57
*/
6-
module.exports = config => ({
7-
ls: require('./ls')(config),
8-
peers: require('./peers')(config),
9-
publish: require('./publish')(config),
10-
subscribe: require('./subscribe')(config),
11-
unsubscribe: require('./unsubscribe')(config)
12-
})
8+
module.exports = config => {
9+
const subscriptionTracker = new SubscriptionTracker()
10+
11+
return {
12+
ls: require('./ls')(config),
13+
peers: require('./peers')(config),
14+
publish: require('./publish')(config),
15+
subscribe: require('./subscribe')(config, subscriptionTracker),
16+
unsubscribe: require('./unsubscribe')(config, subscriptionTracker)
17+
}
18+
}

packages/ipfs-http-client/src/pubsub/subscribe.js

+61-57
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
const uint8ArrayFromString = require('uint8arrays/from-string')
44
const uint8ArrayToString = require('uint8arrays/to-string')
55
const log = require('debug')('ipfs-http-client:pubsub:subscribe')
6-
const SubscriptionTracker = require('./subscription-tracker')
76
const configure = require('../lib/configure')
87
const toUrlSearchParams = require('../lib/to-url-search-params')
98

@@ -12,70 +11,75 @@ const toUrlSearchParams = require('../lib/to-url-search-params')
1211
* @typedef {import('ipfs-core-types/src/pubsub').Message} Message
1312
* @typedef {(err: Error, fatal: boolean, msg?: Message) => void} ErrorHandlerFn
1413
* @typedef {import('ipfs-core-types/src/pubsub').API<HTTPClientExtraOptions & { onError?: ErrorHandlerFn }>} PubsubAPI
14+
* @typedef {import('../types').Options} Options
1515
*/
1616

17-
module.exports = configure((api, options) => {
18-
const subsTracker = SubscriptionTracker.singleton()
19-
20-
/**
21-
* @type {PubsubAPI["subscribe"]}
22-
*/
23-
async function subscribe (topic, handler, options = {}) { // eslint-disable-line require-await
24-
options.signal = subsTracker.subscribe(topic, handler, options.signal)
25-
26-
/** @type {(value?: any) => void} */
27-
let done
28-
/** @type {(error: Error) => void} */
29-
let fail
30-
31-
const result = new Promise((resolve, reject) => {
32-
done = resolve
33-
fail = reject
34-
})
35-
36-
// In Firefox, the initial call to fetch does not resolve until some data
37-
// is received. If this doesn't happen within 1 second assume success
38-
const ffWorkaround = setTimeout(() => done(), 1000)
39-
40-
// Do this async to not block Firefox
41-
setTimeout(() => {
42-
api.post('pubsub/sub', {
43-
timeout: options.timeout,
44-
signal: options.signal,
45-
searchParams: toUrlSearchParams({
46-
arg: topic,
47-
...options
48-
}),
49-
headers: options.headers
17+
/**
18+
* @param {Options} options
19+
* @param {import('./subscription-tracker')} subsTracker
20+
*/
21+
module.exports = (options, subsTracker) => {
22+
return configure((api) => {
23+
/**
24+
* @type {PubsubAPI["subscribe"]}
25+
*/
26+
async function subscribe (topic, handler, options = {}) { // eslint-disable-line require-await
27+
options.signal = subsTracker.subscribe(topic, handler, options.signal)
28+
29+
/** @type {(value?: any) => void} */
30+
let done
31+
/** @type {(error: Error) => void} */
32+
let fail
33+
34+
const result = new Promise((resolve, reject) => {
35+
done = resolve
36+
fail = reject
5037
})
51-
.catch((err) => {
52-
// Initial subscribe fail, ensure we clean up
53-
subsTracker.unsubscribe(topic, handler)
5438

55-
fail(err)
39+
// In Firefox, the initial call to fetch does not resolve until some data
40+
// is received. If this doesn't happen within 1 second assume success
41+
const ffWorkaround = setTimeout(() => done(), 1000)
42+
43+
// Do this async to not block Firefox
44+
setTimeout(() => {
45+
api.post('pubsub/sub', {
46+
timeout: options.timeout,
47+
signal: options.signal,
48+
searchParams: toUrlSearchParams({
49+
arg: topic,
50+
...options
51+
}),
52+
headers: options.headers
5653
})
57-
.then((response) => {
58-
clearTimeout(ffWorkaround)
59-
60-
if (!response) {
61-
// if there was no response, the subscribe failed
62-
return
63-
}
64-
65-
readMessages(response, {
66-
onMessage: handler,
67-
onEnd: () => subsTracker.unsubscribe(topic, handler),
68-
onError: options.onError
54+
.catch((err) => {
55+
// Initial subscribe fail, ensure we clean up
56+
subsTracker.unsubscribe(topic, handler)
57+
58+
fail(err)
6959
})
60+
.then((response) => {
61+
clearTimeout(ffWorkaround)
7062

71-
done()
72-
})
73-
}, 0)
63+
if (!response) {
64+
// if there was no response, the subscribe failed
65+
return
66+
}
7467

75-
return result
76-
}
77-
return subscribe
78-
})
68+
readMessages(response, {
69+
onMessage: handler,
70+
onEnd: () => subsTracker.unsubscribe(topic, handler),
71+
onError: options.onError
72+
})
73+
74+
done()
75+
})
76+
}, 0)
77+
78+
return result
79+
}
80+
return subscribe
81+
})(options)
82+
}
7983

8084
/**
8185
* @param {import('ipfs-utils/src/types').ExtendedResponse} response

packages/ipfs-http-client/src/pubsub/subscription-tracker.js

+4-11
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,6 @@ class SubscriptionTracker {
1616
this._subs = new Map()
1717
}
1818

19-
static singleton () {
20-
if (SubscriptionTracker.instance) return SubscriptionTracker.instance
21-
SubscriptionTracker.instance = new SubscriptionTracker()
22-
return SubscriptionTracker.instance
23-
}
24-
2519
/**
2620
* @param {string} topic
2721
* @param {MessageHandlerFn} handler
@@ -63,13 +57,12 @@ class SubscriptionTracker {
6357
unsubs = subs
6458
}
6559

60+
if (!(this._subs.get(topic) || []).length) {
61+
this._subs.delete(topic)
62+
}
63+
6664
unsubs.forEach(s => s.controller.abort())
6765
}
6866
}
6967

70-
/**
71-
* @type {SubscriptionTracker | null}
72-
*/
73-
SubscriptionTracker.instance = null
74-
7568
module.exports = SubscriptionTracker

packages/ipfs-http-client/src/pubsub/unsubscribe.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
'use strict'
22

3-
const SubscriptionTracker = require('./subscription-tracker')
4-
53
/**
64
* @typedef {import('../types').HTTPClientExtraOptions} HTTPClientExtraOptions
75
* @typedef {import('ipfs-core-types/src/pubsub').API<HTTPClientExtraOptions>} PubsubAPI
6+
* @typedef {import('../types').Options} Options
87
*/
98

109
/**
11-
* @param {import('../types').Options} config
10+
* @param {Options} options
11+
* @param {import('./subscription-tracker')} subsTracker
1212
*/
13-
module.exports = config => {
14-
const subsTracker = SubscriptionTracker.singleton()
15-
13+
module.exports = (options, subsTracker) => {
1614
/**
1715
* @type {PubsubAPI["unsubscribe"]}
1816
*/

packages/ipfs-http-client/src/refs/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const toUrlSearchParams = require('../lib/to-url-search-params')
1010
* @typedef {import('ipfs-core-types/src/refs').API<HTTPClientExtraOptions>} RefsAPI
1111
*/
1212

13-
module.exports = configure((api, options) => {
13+
module.exports = configure((api, opts) => {
1414
/**
1515
* @type {RefsAPI["refs"]}
1616
*/
@@ -34,6 +34,6 @@ module.exports = configure((api, options) => {
3434
}
3535

3636
return Object.assign(refs, {
37-
local: require('./local')(options)
37+
local: require('./local')(opts)
3838
})
3939
})

packages/ipfs-http-server/package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,16 @@
4747
"ipld-dag-pb": "^0.22.1",
4848
"it-all": "^1.0.4",
4949
"it-drain": "^1.0.3",
50+
"it-filter": "^1.0.2",
5051
"it-first": "^1.0.4",
5152
"it-last": "^1.0.4",
5253
"it-map": "^1.0.4",
54+
"it-merge": "^1.0.1",
5355
"it-multipart": "^2.0.0",
5456
"it-pipe": "^1.1.0",
57+
"it-pushable": "^1.4.0",
58+
"it-reduce": "^1.0.5",
5559
"it-tar": "^3.0.0",
56-
"it-to-stream": "^1.0.0",
57-
"iterable-ndjson": "^1.1.0",
5860
"joi": "^17.2.1",
5961
"just-safe-set": "^2.2.1",
6062
"multiaddr": "^9.0.1",
@@ -64,7 +66,6 @@
6466
"native-abort-controller": "^1.0.3",
6567
"parse-duration": "^1.0.0",
6668
"stream-to-it": "^0.2.2",
67-
"streaming-iterables": "^5.0.2",
6869
"uint8arrays": "^2.1.3",
6970
"uri-to-multiaddr": "^5.0.0"
7071
},

packages/ipfs-http-server/src/api/resources/block.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ const Boom = require('@hapi/boom')
88
const { cidToString } = require('ipfs-core-utils/src/cid')
99
const all = require('it-all')
1010
const { pipe } = require('it-pipe')
11-
const { map } = require('streaming-iterables')
12-
// @ts-ignore no types
13-
const ndjson = require('iterable-ndjson')
11+
const map = require('it-map')
1412
const streamResponse = require('../../utils/stream-response')
1513

1614
exports.get = {
@@ -234,8 +232,9 @@ exports.rm = {
234232
timeout,
235233
signal
236234
}),
237-
map(({ cid, error }) => ({ Hash: cidToString(cid, { base: cidBase }), Error: error ? error.message : undefined })),
238-
ndjson.stringify
235+
async function * (source) {
236+
yield * map(source, ({ cid, error }) => ({ Hash: cidToString(cid, { base: cidBase }), Error: error ? error.message : undefined }))
237+
}
239238
))
240239
}
241240
}

0 commit comments

Comments
 (0)