@helia/ipns 9.1.9-eaeb734d → 9.2.0
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.
- package/dist/index.min.js +9 -9
- package/dist/index.min.js.map +4 -4
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.js +3 -3
- package/dist/src/ipns/publisher.d.ts +3 -3
- package/dist/src/ipns/republisher.d.ts +2 -2
- package/dist/src/ipns/republisher.js +1 -1
- package/dist/src/ipns/resolver.d.ts +3 -3
- package/dist/src/ipns/resolver.js +2 -2
- package/dist/src/ipns.d.ts +2 -2
- package/dist/src/ipns.js +2 -2
- package/dist/src/local-store.d.ts +2 -2
- package/dist/src/local-store.js +2 -2
- package/dist/src/pb/metadata.d.ts +11 -2
- package/dist/src/pb/metadata.d.ts.map +1 -1
- package/dist/src/pb/metadata.js +36 -5
- package/dist/src/pb/metadata.js.map +1 -1
- package/dist/src/routing/helia.d.ts +2 -2
- package/dist/src/routing/index.d.ts +6 -6
- package/dist/src/routing/index.js +2 -2
- package/dist/src/routing/pubsub.d.ts +74 -9
- package/dist/src/routing/pubsub.d.ts.map +1 -1
- package/dist/src/routing/pubsub.js +198 -39
- package/dist/src/routing/pubsub.js.map +1 -1
- package/dist/typedoc-urls.json +51 -0
- package/package.json +11 -6
- package/src/index.ts +6 -6
- package/src/ipns/publisher.ts +3 -3
- package/src/ipns/republisher.ts +3 -3
- package/src/ipns/resolver.ts +5 -5
- package/src/ipns.ts +5 -5
- package/src/local-store.ts +3 -3
- package/src/pb/metadata.ts +44 -3
- package/src/routing/helia.ts +2 -2
- package/src/routing/index.ts +6 -6
- package/src/routing/pubsub.ts +267 -53
package/src/routing/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { HeliaRoutingProgressEvents } from './helia.
|
|
2
|
-
import type { DatastoreProgressEvents } from '../index.
|
|
3
|
-
import type { PubSubProgressEvents } from './pubsub.
|
|
1
|
+
import type { HeliaRoutingProgressEvents } from './helia.ts'
|
|
2
|
+
import type { DatastoreProgressEvents } from '../index.ts'
|
|
3
|
+
import type { PubSubProgressEvents } from './pubsub.ts'
|
|
4
4
|
import type { IPNSPublishMetadata } from '../pb/metadata.ts'
|
|
5
5
|
import type { AbortOptions } from '@libp2p/interface'
|
|
6
6
|
import type { ProgressOptions } from 'progress-events'
|
|
@@ -32,6 +32,6 @@ export type IPNSRoutingProgressEvents =
|
|
|
32
32
|
HeliaRoutingProgressEvents |
|
|
33
33
|
PubSubProgressEvents
|
|
34
34
|
|
|
35
|
-
export { helia } from './helia.
|
|
36
|
-
export { pubsub } from './pubsub.
|
|
37
|
-
export type { PubsubRoutingComponents, PubSub, Message, PublishResult, PubSubEvents } from './pubsub.
|
|
35
|
+
export { helia } from './helia.ts'
|
|
36
|
+
export { pubsub } from './pubsub.ts'
|
|
37
|
+
export type { PubsubRoutingComponents, PubSub, Message, PublishResult, PubSubEvents } from './pubsub.ts'
|
package/src/routing/pubsub.ts
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
import { isPublicKey } from '@libp2p/interface'
|
|
1
|
+
import { isPublicKey, NotFoundError, setMaxListeners } from '@libp2p/interface'
|
|
2
2
|
import { logger } from '@libp2p/logger'
|
|
3
|
+
import { PeerSet } from '@libp2p/peer-collections'
|
|
4
|
+
import { Queue } from '@libp2p/utils'
|
|
5
|
+
import { anySignal } from 'any-signal'
|
|
6
|
+
import delay from 'delay'
|
|
3
7
|
import { multihashToIPNSRoutingKey } from 'ipns'
|
|
4
8
|
import { ipnsSelector } from 'ipns/selector'
|
|
5
9
|
import { ipnsValidator } from 'ipns/validator'
|
|
6
10
|
import { CustomProgressEvent } from 'progress-events'
|
|
11
|
+
import { raceSignal } from 'race-signal'
|
|
7
12
|
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
|
|
8
13
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
9
14
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
10
|
-
import { InvalidTopicError } from '../errors.
|
|
11
|
-
import { localStore } from '../local-store.
|
|
12
|
-
import
|
|
13
|
-
import type {
|
|
14
|
-
import type {
|
|
15
|
+
import { InvalidTopicError } from '../errors.ts'
|
|
16
|
+
import { localStore } from '../local-store.ts'
|
|
17
|
+
import { IPNS_STRING_PREFIX } from '../utils.ts'
|
|
18
|
+
import type { GetOptions, IPNSRouting, PutOptions } from './index.ts'
|
|
19
|
+
import type { LocalStore } from '../local-store.ts'
|
|
20
|
+
import type { Fetch } from '@libp2p/fetch'
|
|
21
|
+
import type { PeerId, PublicKey, TypedEventTarget, ComponentLogger, Startable, AbortOptions, Metrics, Libp2p } from '@libp2p/interface'
|
|
15
22
|
import type { Datastore } from 'interface-datastore'
|
|
16
23
|
import type { MultihashDigest } from 'multiformats/hashes/interface'
|
|
17
24
|
import type { ProgressEvent } from 'progress-events'
|
|
@@ -25,7 +32,18 @@ export interface Message {
|
|
|
25
32
|
data: Uint8Array
|
|
26
33
|
}
|
|
27
34
|
|
|
35
|
+
export interface Subscription {
|
|
36
|
+
topic: string
|
|
37
|
+
subscribe: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface SubscriptionChangeData {
|
|
41
|
+
peerId: PeerId
|
|
42
|
+
subscriptions: Subscription[]
|
|
43
|
+
}
|
|
44
|
+
|
|
28
45
|
export interface PubSubEvents {
|
|
46
|
+
'subscription-change': CustomEvent<SubscriptionChangeData>
|
|
29
47
|
message: CustomEvent<Message>
|
|
30
48
|
}
|
|
31
49
|
|
|
@@ -44,12 +62,31 @@ export interface PubSub extends TypedEventTarget<PubSubEvents> {
|
|
|
44
62
|
export interface PubsubRoutingComponents {
|
|
45
63
|
datastore: Datastore
|
|
46
64
|
logger: ComponentLogger
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
65
|
+
metrics?: Metrics
|
|
66
|
+
libp2p: Pick<Libp2p<{ pubsub: PubSub, fetch?: Fetch }>, 'peerId' | 'register' | 'unregister' | 'services'>
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface PubsubRoutingInit {
|
|
70
|
+
/**
|
|
71
|
+
* How many fetch requests to run concurrently
|
|
72
|
+
*
|
|
73
|
+
* @default 8
|
|
74
|
+
*/
|
|
75
|
+
fetchConcurrency?: number
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* How long to allow a fetch request to run for in ms
|
|
79
|
+
*
|
|
80
|
+
* @default 2_500
|
|
81
|
+
*/
|
|
82
|
+
fetchTimeout?: number
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* How many ms to wait before sending a fetch request to a topic peer
|
|
86
|
+
*
|
|
87
|
+
* @default 0
|
|
88
|
+
*/
|
|
89
|
+
fetchDelay?: number
|
|
53
90
|
}
|
|
54
91
|
|
|
55
92
|
export type PubSubProgressEvents =
|
|
@@ -57,32 +94,105 @@ export type PubSubProgressEvents =
|
|
|
57
94
|
ProgressEvent<'ipns:pubsub:subscribe', { topic: string }> |
|
|
58
95
|
ProgressEvent<'ipns:pubsub:error', Error>
|
|
59
96
|
|
|
60
|
-
class PubSubRouting implements IPNSRouting {
|
|
61
|
-
private subscriptions: string
|
|
97
|
+
export class PubSubRouting implements IPNSRouting, Startable {
|
|
98
|
+
private readonly subscriptions: Set<string>
|
|
62
99
|
private readonly localStore: LocalStore
|
|
63
|
-
private readonly
|
|
64
|
-
private readonly
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
100
|
+
private readonly libp2p: Pick<Libp2p<{ pubsub: PubSub, fetch?: Fetch }>, 'peerId' | 'register' | 'unregister' | 'services'>
|
|
101
|
+
private readonly fetchConcurrency: number
|
|
102
|
+
private readonly fetchTimeout: number
|
|
103
|
+
private readonly fetchDelay: number
|
|
104
|
+
private readonly fetchQueue: Queue<Uint8Array | undefined>
|
|
105
|
+
private readonly fetchPeers: PeerSet
|
|
106
|
+
private shutdownController: AbortController
|
|
107
|
+
private fetchTopologyId?: string
|
|
108
|
+
|
|
109
|
+
constructor (components: PubsubRoutingComponents, init: PubsubRoutingInit = {}) {
|
|
110
|
+
this.subscriptions = new Set()
|
|
111
|
+
this.shutdownController = new AbortController()
|
|
112
|
+
setMaxListeners(Infinity, this.shutdownController.signal)
|
|
113
|
+
this.fetchPeers = new PeerSet()
|
|
68
114
|
this.localStore = localStore(components.datastore, components.logger.forComponent('helia:ipns:local-store'))
|
|
69
|
-
this.
|
|
70
|
-
this.
|
|
115
|
+
this.libp2p = components.libp2p
|
|
116
|
+
this.fetchConcurrency = init.fetchConcurrency ?? 8
|
|
117
|
+
this.fetchDelay = init.fetchDelay ?? 0
|
|
118
|
+
|
|
119
|
+
// default libp2p-fetch timeout is 10 seconds - we should have an existing
|
|
120
|
+
// connection to the peer so this can be shortened
|
|
121
|
+
this.fetchTimeout = init.fetchTimeout ?? 2_500
|
|
122
|
+
this.fetchQueue = new Queue<Uint8Array | undefined>({
|
|
123
|
+
concurrency: this.fetchConcurrency,
|
|
124
|
+
metrics: components.metrics,
|
|
125
|
+
metricName: 'helia_ipns_pubsub_fetch_queue'
|
|
126
|
+
})
|
|
71
127
|
|
|
72
|
-
this.pubsub.addEventListener('message', (evt) => {
|
|
128
|
+
this.libp2p.services.pubsub.addEventListener('message', (evt) => {
|
|
73
129
|
const message = evt.detail
|
|
74
130
|
|
|
75
|
-
if (!this.subscriptions.
|
|
131
|
+
if (!this.subscriptions.has(message.topic)) {
|
|
76
132
|
return
|
|
77
133
|
}
|
|
78
134
|
|
|
79
|
-
this.#processPubSubMessage(message
|
|
135
|
+
this.#processPubSubMessage(message, {
|
|
136
|
+
signal: this.shutdownController.signal
|
|
137
|
+
}).catch(err => {
|
|
80
138
|
log.error('Error processing message - %e', err)
|
|
81
139
|
})
|
|
82
140
|
})
|
|
141
|
+
|
|
142
|
+
// ipns over libp2p-fetch feature
|
|
143
|
+
if (this.libp2p.services.fetch != null) {
|
|
144
|
+
try {
|
|
145
|
+
this.libp2p.services.pubsub.addEventListener('subscription-change', (evt) => {
|
|
146
|
+
const { peerId, subscriptions } = evt.detail
|
|
147
|
+
|
|
148
|
+
if (!this.fetchPeers.has(peerId)) {
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
for (const sub of subscriptions) {
|
|
153
|
+
if (!this.subscriptions.has(sub.topic)) {
|
|
154
|
+
continue
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (sub.subscribe === false) {
|
|
158
|
+
continue
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
log('peer %s joined topic %s', peerId, sub.topic)
|
|
162
|
+
|
|
163
|
+
const routingKey = topicToKey(sub.topic)
|
|
164
|
+
this.#fetchFromPeer(sub.topic, routingKey, peerId, {
|
|
165
|
+
signal: this.shutdownController.signal
|
|
166
|
+
})
|
|
167
|
+
.catch(err => {
|
|
168
|
+
log.error('failed to fetch IPNS record for %m from peer %s - %e', routingKey, peerId, err)
|
|
169
|
+
})
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
this.libp2p.services.fetch.registerLookupFunction(IPNS_STRING_PREFIX, async (key) => {
|
|
174
|
+
try {
|
|
175
|
+
const { record } = await this.localStore.get(key, {
|
|
176
|
+
signal: this.shutdownController.signal
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
return record
|
|
180
|
+
} catch (err: any) {
|
|
181
|
+
if (err.name !== 'NotFoundError') {
|
|
182
|
+
throw err
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
log('registered lookup function for IPNS with libp2p/fetch service')
|
|
187
|
+
} catch (e) {
|
|
188
|
+
log('unable to register lookup function for IPNS with libp2p/fetch service - %e', e)
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
log('no libp2p/fetch service found. Skipping registration of lookup function for IPNS.')
|
|
192
|
+
}
|
|
83
193
|
}
|
|
84
194
|
|
|
85
|
-
async #processPubSubMessage (message: Message): Promise<void> {
|
|
195
|
+
async #processPubSubMessage (message: Message, options?: AbortOptions): Promise<void> {
|
|
86
196
|
log('message received for topic', message.topic)
|
|
87
197
|
|
|
88
198
|
if (message.type !== 'signed') {
|
|
@@ -90,33 +200,77 @@ class PubSubRouting implements IPNSRouting {
|
|
|
90
200
|
return
|
|
91
201
|
}
|
|
92
202
|
|
|
93
|
-
if (message.from.equals(this.peerId)) {
|
|
203
|
+
if (message.from.equals(this.libp2p.peerId)) {
|
|
94
204
|
log('not storing record from self')
|
|
95
205
|
return
|
|
96
206
|
}
|
|
97
207
|
|
|
98
|
-
|
|
208
|
+
await this.#handleRecord(message.topic, topicToKey(message.topic), message.data, false, options)
|
|
209
|
+
}
|
|
99
210
|
|
|
100
|
-
|
|
211
|
+
async #fetchFromPeer (topic: string, routingKey: Uint8Array, peerId: PeerId, options?: AbortOptions): Promise<Uint8Array> {
|
|
212
|
+
const marshalledRecord = await this.fetchQueue.add(async ({ signal }) => {
|
|
213
|
+
log('fetching ipns record for %m from peer %s', routingKey, peerId)
|
|
214
|
+
|
|
215
|
+
const sig = anySignal([
|
|
216
|
+
signal,
|
|
217
|
+
AbortSignal.timeout(this.fetchTimeout)
|
|
218
|
+
])
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
return await this.libp2p.services.fetch?.fetch(peerId, routingKey, {
|
|
222
|
+
signal: sig
|
|
223
|
+
})
|
|
224
|
+
} finally {
|
|
225
|
+
sig.clear()
|
|
226
|
+
}
|
|
227
|
+
}, options)
|
|
228
|
+
|
|
229
|
+
if (marshalledRecord == null) {
|
|
230
|
+
throw new NotFoundError(`Peer ${peerId} did not have record for routing key ${uint8ArrayToString(routingKey, 'base64')}`)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
log('fetched ipns record for %m from peer %s', routingKey, peerId)
|
|
234
|
+
return this.#handleRecord(topic, routingKey, marshalledRecord, true, options)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async #handleRecord (topic: string, routingKey: Uint8Array, marshalledRecord: Uint8Array, publish: boolean, options?: AbortOptions): Promise<Uint8Array> {
|
|
238
|
+
await ipnsValidator(routingKey, marshalledRecord)
|
|
239
|
+
this.shutdownController.signal.throwIfAborted()
|
|
101
240
|
|
|
102
241
|
if (await this.localStore.has(routingKey)) {
|
|
103
|
-
const { record: currentRecord } = await this.localStore.get(routingKey)
|
|
242
|
+
const { record: currentRecord } = await this.localStore.get(routingKey, options)
|
|
104
243
|
|
|
105
|
-
if (uint8ArrayEquals(currentRecord,
|
|
106
|
-
log('
|
|
107
|
-
return
|
|
244
|
+
if (uint8ArrayEquals(currentRecord, marshalledRecord)) {
|
|
245
|
+
log.trace('found identical record for %m', routingKey)
|
|
246
|
+
return currentRecord
|
|
108
247
|
}
|
|
109
248
|
|
|
110
|
-
const records = [currentRecord,
|
|
249
|
+
const records = [currentRecord, marshalledRecord]
|
|
111
250
|
const index = ipnsSelector(routingKey, records)
|
|
112
251
|
|
|
113
252
|
if (index === 0) {
|
|
114
|
-
log('
|
|
115
|
-
return
|
|
253
|
+
log.trace('found old record for %m', routingKey)
|
|
254
|
+
return currentRecord
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
log('found new record for %m', routingKey)
|
|
259
|
+
await this.localStore.put(routingKey, marshalledRecord, options)
|
|
260
|
+
|
|
261
|
+
// if the record was received via fetch, republish it
|
|
262
|
+
if (publish) {
|
|
263
|
+
log('publish value for topic %s', topic)
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
const result = await this.libp2p.services.pubsub.publish(topic, marshalledRecord)
|
|
267
|
+
log('published record on topic %s to %d recipients', topic, result.recipients)
|
|
268
|
+
} catch (err) {
|
|
269
|
+
log.error('could not publish record on topic %s - %e', err)
|
|
116
270
|
}
|
|
117
271
|
}
|
|
118
272
|
|
|
119
|
-
|
|
273
|
+
return marshalledRecord
|
|
120
274
|
}
|
|
121
275
|
|
|
122
276
|
/**
|
|
@@ -127,7 +281,8 @@ class PubSubRouting implements IPNSRouting {
|
|
|
127
281
|
const topic = keyToTopic(routingKey)
|
|
128
282
|
|
|
129
283
|
log('publish value for topic %s', topic)
|
|
130
|
-
const result = await this.pubsub.publish(topic, marshaledRecord)
|
|
284
|
+
const result = await this.libp2p.services.pubsub.publish(topic, marshaledRecord)
|
|
285
|
+
options?.signal?.throwIfAborted()
|
|
131
286
|
|
|
132
287
|
log('published record on topic %s to %d recipients', topic, result.recipients)
|
|
133
288
|
options.onProgress?.(new CustomProgressEvent('ipns:pubsub:publish', { topic, result }))
|
|
@@ -143,33 +298,65 @@ class PubSubRouting implements IPNSRouting {
|
|
|
143
298
|
* updated once new publishes occur
|
|
144
299
|
*/
|
|
145
300
|
async get (routingKey: Uint8Array, options: GetOptions = {}): Promise<Uint8Array> {
|
|
146
|
-
|
|
147
|
-
const topic = keyToTopic(routingKey)
|
|
301
|
+
const topic = keyToTopic(routingKey)
|
|
148
302
|
|
|
303
|
+
try {
|
|
149
304
|
// ensure we are subscribed to topic
|
|
150
|
-
if (!this.pubsub.getTopics().includes(topic)) {
|
|
305
|
+
if (!this.libp2p.services.pubsub.getTopics().includes(topic)) {
|
|
151
306
|
log('add subscription for topic', topic)
|
|
152
|
-
this.pubsub.subscribe(topic)
|
|
153
|
-
this.subscriptions.
|
|
307
|
+
this.libp2p.services.pubsub.subscribe(topic)
|
|
308
|
+
this.subscriptions.add(topic)
|
|
154
309
|
|
|
155
310
|
options.onProgress?.(new CustomProgressEvent('ipns:pubsub:subscribe', { topic }))
|
|
156
311
|
}
|
|
157
|
-
|
|
158
|
-
// chain through to local store
|
|
159
|
-
const { record } = await this.localStore.get(routingKey, options)
|
|
160
|
-
|
|
161
|
-
return record
|
|
162
312
|
} catch (err: any) {
|
|
163
313
|
options.onProgress?.(new CustomProgressEvent<Error>('ipns:pubsub:error', err))
|
|
164
314
|
throw err
|
|
165
315
|
}
|
|
316
|
+
|
|
317
|
+
// delay before fetch to allow pubsub to resolve
|
|
318
|
+
await raceSignal(delay(this.fetchDelay), this.shutdownController.signal)
|
|
319
|
+
|
|
320
|
+
const fetchController = new AbortController()
|
|
321
|
+
const promises: Array<Promise<Uint8Array>> = []
|
|
322
|
+
|
|
323
|
+
for (const peerId of this.libp2p.services.pubsub.getSubscribers(topic)) {
|
|
324
|
+
const signal = anySignal([
|
|
325
|
+
options?.signal,
|
|
326
|
+
fetchController.signal
|
|
327
|
+
])
|
|
328
|
+
|
|
329
|
+
promises.push(
|
|
330
|
+
this.#fetchFromPeer(topic, routingKey, peerId, {
|
|
331
|
+
...options,
|
|
332
|
+
signal
|
|
333
|
+
})
|
|
334
|
+
.finally(() => {
|
|
335
|
+
signal.clear()
|
|
336
|
+
})
|
|
337
|
+
)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (promises.length > 0) {
|
|
341
|
+
// fetch record from topic peers
|
|
342
|
+
const record = await Promise.any(promises)
|
|
343
|
+
|
|
344
|
+
// cancel any in-flight requests
|
|
345
|
+
fetchController.abort()
|
|
346
|
+
|
|
347
|
+
if (record != null) {
|
|
348
|
+
return record
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
throw new NotFoundError('Pubsub routing does not actively query peers')
|
|
166
353
|
}
|
|
167
354
|
|
|
168
355
|
/**
|
|
169
356
|
* Get pubsub subscriptions related to ipns
|
|
170
357
|
*/
|
|
171
358
|
getSubscriptions (): string[] {
|
|
172
|
-
return this.subscriptions
|
|
359
|
+
return [...this.subscriptions]
|
|
173
360
|
}
|
|
174
361
|
|
|
175
362
|
/**
|
|
@@ -181,17 +368,44 @@ class PubSubRouting implements IPNSRouting {
|
|
|
181
368
|
const topic = keyToTopic(routingKey)
|
|
182
369
|
|
|
183
370
|
// Not found topic
|
|
184
|
-
if (!this.subscriptions.
|
|
371
|
+
if (!this.subscriptions.has(topic)) {
|
|
185
372
|
return
|
|
186
373
|
}
|
|
187
374
|
|
|
188
|
-
this.pubsub.unsubscribe(topic)
|
|
189
|
-
this.subscriptions
|
|
375
|
+
this.libp2p.services.pubsub.unsubscribe(topic)
|
|
376
|
+
this.subscriptions.delete(topic)
|
|
190
377
|
}
|
|
191
378
|
|
|
192
379
|
toString (): string {
|
|
193
380
|
return 'PubSubRouting()'
|
|
194
381
|
}
|
|
382
|
+
|
|
383
|
+
async start (): Promise<void> {
|
|
384
|
+
this.shutdownController = new AbortController()
|
|
385
|
+
setMaxListeners(Infinity, this.shutdownController.signal)
|
|
386
|
+
|
|
387
|
+
if (this.libp2p.services.fetch != null) {
|
|
388
|
+
this.fetchTopologyId = await this.libp2p.register(this.libp2p.services.fetch.protocol, {
|
|
389
|
+
onConnect: (peerId) => {
|
|
390
|
+
this.fetchPeers.add(peerId)
|
|
391
|
+
},
|
|
392
|
+
onDisconnect: (peerId) => {
|
|
393
|
+
this.fetchPeers.delete(peerId)
|
|
394
|
+
}
|
|
395
|
+
}, {
|
|
396
|
+
signal: this.shutdownController.signal
|
|
397
|
+
})
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
stop (): void {
|
|
402
|
+
this.fetchQueue.abort()
|
|
403
|
+
this.shutdownController.abort()
|
|
404
|
+
|
|
405
|
+
if (this.fetchTopologyId != null) {
|
|
406
|
+
this.libp2p.unregister(this.fetchTopologyId)
|
|
407
|
+
}
|
|
408
|
+
}
|
|
195
409
|
}
|
|
196
410
|
|
|
197
411
|
const PUBSUB_NAMESPACE = '/record/'
|
|
@@ -226,6 +440,6 @@ function topicToKey (topic: string): Uint8Array {
|
|
|
226
440
|
* updated records, so the first call to `.get` should be expected
|
|
227
441
|
* to fail!
|
|
228
442
|
*/
|
|
229
|
-
export function pubsub (components: PubsubRoutingComponents): IPNSRouting {
|
|
230
|
-
return new PubSubRouting(components)
|
|
443
|
+
export function pubsub (components: PubsubRoutingComponents, init: PubsubRoutingInit = {}): IPNSRouting {
|
|
444
|
+
return new PubSubRouting(components, init)
|
|
231
445
|
}
|