@libp2p/pubsub 1.2.9 → 1.2.12
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/README.md +2 -2
- package/dist/src/index.d.ts +36 -27
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +93 -91
- package/dist/src/index.js.map +1 -1
- package/dist/src/{message/sign.d.ts → sign.d.ts} +3 -3
- package/dist/src/sign.d.ts.map +1 -0
- package/dist/src/{message/sign.js → sign.js} +6 -7
- package/dist/src/sign.js.map +1 -0
- package/dist/src/utils.d.ts +3 -4
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +2 -2
- package/dist/src/utils.js.map +1 -1
- package/package.json +18 -25
- package/src/index.ts +128 -109
- package/src/{message/sign.ts → sign.ts} +7 -8
- package/src/utils.ts +5 -6
- package/dist/src/message/rpc.d.ts +0 -669
- package/dist/src/message/rpc.js +0 -1870
- package/dist/src/message/sign.d.ts.map +0 -1
- package/dist/src/message/sign.js.map +0 -1
- package/dist/src/message/topic-descriptor.d.ts +0 -254
- package/dist/src/message/topic-descriptor.js +0 -647
- package/src/message/rpc.d.ts +0 -669
- package/src/message/rpc.js +0 -1870
- package/src/message/rpc.proto +0 -54
- package/src/message/topic-descriptor.d.ts +0 -254
- package/src/message/topic-descriptor.js +0 -647
- package/src/message/topic-descriptor.proto +0 -30
package/src/index.ts
CHANGED
@@ -10,32 +10,28 @@ import { toMessage, ensureArray, randomSeqno, noSignMsgId, msgId, toRpcMessage }
|
|
10
10
|
import {
|
11
11
|
signMessage,
|
12
12
|
verifySignature
|
13
|
-
} from './
|
13
|
+
} from './sign.js'
|
14
14
|
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
15
|
-
import type {
|
15
|
+
import type { IncomingStreamData } from '@libp2p/interfaces/registrar'
|
16
16
|
import type { Connection } from '@libp2p/interfaces/connection'
|
17
|
-
import type { PubSub, Message, StrictNoSign, StrictSign,
|
18
|
-
import
|
19
|
-
import {
|
20
|
-
|
21
|
-
|
22
|
-
import { peerIdFromString } from '@libp2p/peer-id'
|
23
|
-
import type { IRPC } from './message/rpc.js'
|
24
|
-
import { RPC as RPCProto } from './message/rpc.js'
|
17
|
+
import type { PubSub, Message, StrictNoSign, StrictSign, PubSubInit, PubSubEvents, PeerStreams, PubSubRPCMessage, PubSubRPC, PubSubRPCSubscription, SubscriptionChangeData } from '@libp2p/interfaces/pubsub'
|
18
|
+
import { PeerMap, PeerSet } from '@libp2p/peer-collections'
|
19
|
+
import { Components, Initializable } from '@libp2p/interfaces/components'
|
20
|
+
|
21
|
+
const log = logger('libp2p:pubsub')
|
25
22
|
|
26
23
|
export interface TopicValidator { (topic: string, message: Message): Promise<void> }
|
27
24
|
|
28
25
|
/**
|
29
|
-
*
|
26
|
+
* PubSubBaseProtocol handles the peers and connections logic for pubsub routers
|
30
27
|
* and specifies the API that pubsub routers should have.
|
31
28
|
*/
|
32
|
-
export abstract class
|
33
|
-
public peerId: PeerId
|
29
|
+
export abstract class PubSubBaseProtocol extends EventEmitter<PubSubEvents> implements PubSub, Initializable {
|
34
30
|
public started: boolean
|
35
31
|
/**
|
36
32
|
* Map of topics to which peers are subscribed to
|
37
33
|
*/
|
38
|
-
public topics: Map<string,
|
34
|
+
public topics: Map<string, PeerSet>
|
39
35
|
/**
|
40
36
|
* List of our subscriptions
|
41
37
|
*/
|
@@ -64,36 +60,29 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
64
60
|
*/
|
65
61
|
public topicValidators: Map<string, TopicValidator>
|
66
62
|
public queue: Queue
|
67
|
-
public registrar: Registrar
|
68
63
|
public multicodecs: string[]
|
64
|
+
public components: Components = new Components()
|
69
65
|
|
70
|
-
protected log: Logger
|
71
|
-
protected _libp2p: any
|
72
|
-
private _registrarHandlerId: string | undefined
|
73
66
|
private _registrarTopologyId: string | undefined
|
67
|
+
protected enabled: boolean
|
74
68
|
|
75
|
-
constructor (props:
|
69
|
+
constructor (props: PubSubInit) {
|
76
70
|
super()
|
77
71
|
|
78
72
|
const {
|
79
|
-
debugName = 'libp2p:pubsub',
|
80
73
|
multicodecs = [],
|
81
|
-
peerId,
|
82
|
-
registrar,
|
83
74
|
globalSignaturePolicy = 'StrictSign',
|
84
75
|
canRelayMessage = false,
|
85
76
|
emitSelf = false,
|
86
77
|
messageProcessingConcurrency = 10
|
87
78
|
} = props
|
88
79
|
|
89
|
-
this.log = logger(debugName)
|
90
80
|
this.multicodecs = ensureArray(multicodecs)
|
91
|
-
this.
|
92
|
-
this.peerId = peerId
|
81
|
+
this.enabled = props.enabled !== false
|
93
82
|
this.started = false
|
94
83
|
this.topics = new Map()
|
95
84
|
this.subscriptions = new Set()
|
96
|
-
this.peers =
|
85
|
+
this.peers = new PeerMap<PeerStreams>()
|
97
86
|
this.globalSignaturePolicy = globalSignaturePolicy === 'StrictNoSign' ? 'StrictNoSign' : 'StrictSign'
|
98
87
|
this.canRelayMessage = canRelayMessage
|
99
88
|
this.emitSelf = emitSelf
|
@@ -105,6 +94,10 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
105
94
|
this._onPeerDisconnected = this._onPeerDisconnected.bind(this)
|
106
95
|
}
|
107
96
|
|
97
|
+
init (components: Components) {
|
98
|
+
this.components = components
|
99
|
+
}
|
100
|
+
|
108
101
|
// LIFECYCLE METHODS
|
109
102
|
|
110
103
|
/**
|
@@ -113,15 +106,15 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
113
106
|
* @returns {void}
|
114
107
|
*/
|
115
108
|
async start () {
|
116
|
-
if (this.started) {
|
109
|
+
if (this.started || !this.enabled) {
|
117
110
|
return
|
118
111
|
}
|
119
112
|
|
120
|
-
|
113
|
+
log('starting')
|
121
114
|
|
122
115
|
// Incoming streams
|
123
116
|
// Called after a peer dials us
|
124
|
-
|
117
|
+
await this.components.getRegistrar().handle(this.multicodecs, this._onIncomingStream)
|
125
118
|
|
126
119
|
// register protocol with topology
|
127
120
|
// Topology callbacks called on connection manager changes
|
@@ -129,9 +122,9 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
129
122
|
onConnect: this._onPeerConnected,
|
130
123
|
onDisconnect: this._onPeerDisconnected
|
131
124
|
})
|
132
|
-
this._registrarTopologyId = this.
|
125
|
+
this._registrarTopologyId = await this.components.getRegistrar().register(this.multicodecs, topology)
|
133
126
|
|
134
|
-
|
127
|
+
log('started')
|
135
128
|
this.started = true
|
136
129
|
}
|
137
130
|
|
@@ -139,19 +132,18 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
139
132
|
* Unregister the pubsub protocol and the streams with other peers will be closed.
|
140
133
|
*/
|
141
134
|
async stop () {
|
142
|
-
if (!this.started) {
|
135
|
+
if (!this.started || !this.enabled) {
|
143
136
|
return
|
144
137
|
}
|
145
138
|
|
146
139
|
// unregister protocol and handlers
|
147
140
|
if (this._registrarTopologyId != null) {
|
148
|
-
this.
|
149
|
-
}
|
150
|
-
if (this._registrarHandlerId != null) {
|
151
|
-
await this.registrar.unhandle(this._registrarHandlerId)
|
141
|
+
this.components.getRegistrar().unregister(this._registrarTopologyId)
|
152
142
|
}
|
153
143
|
|
154
|
-
this.
|
144
|
+
await this.components.getRegistrar().unhandle(this.multicodecs)
|
145
|
+
|
146
|
+
log('stopping')
|
155
147
|
for (const peerStreams of this.peers.values()) {
|
156
148
|
peerStreams.close()
|
157
149
|
}
|
@@ -159,7 +151,7 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
159
151
|
this.peers.clear()
|
160
152
|
this.subscriptions = new Set()
|
161
153
|
this.started = false
|
162
|
-
|
154
|
+
log('stopped')
|
163
155
|
}
|
164
156
|
|
165
157
|
isStarted () {
|
@@ -169,28 +161,28 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
169
161
|
/**
|
170
162
|
* On an inbound stream opened
|
171
163
|
*/
|
172
|
-
protected _onIncomingStream (
|
173
|
-
const { protocol, stream, connection } =
|
164
|
+
protected _onIncomingStream (data: IncomingStreamData) {
|
165
|
+
const { protocol, stream, connection } = data
|
174
166
|
const peerId = connection.remotePeer
|
175
167
|
const peer = this.addPeer(peerId, protocol)
|
176
168
|
const inboundStream = peer.attachInboundStream(stream)
|
177
169
|
|
178
170
|
this.processMessages(peerId, inboundStream, peer)
|
179
|
-
.catch(err =>
|
171
|
+
.catch(err => log(err))
|
180
172
|
}
|
181
173
|
|
182
174
|
/**
|
183
175
|
* Registrar notifies an established connection with pubsub protocol
|
184
176
|
*/
|
185
177
|
protected async _onPeerConnected (peerId: PeerId, conn: Connection) {
|
186
|
-
|
178
|
+
log('connected %p', peerId)
|
187
179
|
|
188
180
|
try {
|
189
181
|
const { stream, protocol } = await conn.newStream(this.multicodecs)
|
190
182
|
const peer = this.addPeer(peerId, protocol)
|
191
183
|
await peer.attachOutboundStream(stream)
|
192
184
|
} catch (err: any) {
|
193
|
-
|
185
|
+
log.error(err)
|
194
186
|
}
|
195
187
|
|
196
188
|
// Immediately send my own subscriptions to the newly established conn
|
@@ -203,7 +195,7 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
203
195
|
protected _onPeerDisconnected (peerId: PeerId, conn?: Connection) {
|
204
196
|
const idB58Str = peerId.toString()
|
205
197
|
|
206
|
-
|
198
|
+
log('connection ended', idB58Str)
|
207
199
|
this._removePeer(peerId)
|
208
200
|
}
|
209
201
|
|
@@ -219,7 +211,7 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
219
211
|
}
|
220
212
|
|
221
213
|
// else create a new peer streams
|
222
|
-
|
214
|
+
log('new peer %p', peerId)
|
223
215
|
|
224
216
|
const peerStreams: PeerStreams = new PeerStreamsImpl({
|
225
217
|
id: peerId,
|
@@ -238,7 +230,6 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
238
230
|
* Notifies the router that a peer has been disconnected
|
239
231
|
*/
|
240
232
|
protected _removePeer (peerId: PeerId) {
|
241
|
-
const id = peerId.toString()
|
242
233
|
const peerStreams = this.peers.get(peerId)
|
243
234
|
if (peerStreams == null) {
|
244
235
|
return
|
@@ -248,12 +239,12 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
248
239
|
peerStreams.close()
|
249
240
|
|
250
241
|
// delete peer streams
|
251
|
-
|
242
|
+
log('delete peer %p', peerId)
|
252
243
|
this.peers.delete(peerId)
|
253
244
|
|
254
245
|
// remove peer from topics map
|
255
246
|
for (const peers of this.topics.values()) {
|
256
|
-
peers.delete(
|
247
|
+
peers.delete(peerId)
|
257
248
|
}
|
258
249
|
|
259
250
|
return peerStreams
|
@@ -271,11 +262,11 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
271
262
|
async (source) => {
|
272
263
|
for await (const data of source) {
|
273
264
|
const rpcMsg = this.decodeRpc(data)
|
274
|
-
const messages:
|
265
|
+
const messages: PubSubRPCMessage[] = []
|
275
266
|
|
276
267
|
for (const msg of (rpcMsg.messages ?? [])) {
|
277
268
|
if (msg.from == null || msg.data == null || msg.topic == null) {
|
278
|
-
|
269
|
+
log('message from %p was missing from, data or topic fields, dropping', peerId)
|
279
270
|
continue
|
280
271
|
}
|
281
272
|
|
@@ -283,7 +274,7 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
283
274
|
from: msg.from,
|
284
275
|
data: msg.data,
|
285
276
|
topic: msg.topic,
|
286
|
-
|
277
|
+
sequenceNumber: msg.sequenceNumber ?? undefined,
|
287
278
|
signature: msg.signature ?? undefined,
|
288
279
|
key: msg.key ?? undefined
|
289
280
|
})
|
@@ -294,13 +285,13 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
294
285
|
// to prevent a top-level unhandled exception
|
295
286
|
// This processing of rpc messages should happen without awaiting full validation/execution of prior messages
|
296
287
|
this.processRpc(peerId, peerStreams, {
|
297
|
-
subscriptions: (rpcMsg.subscriptions).map(sub => ({
|
288
|
+
subscriptions: (rpcMsg.subscriptions ?? []).map(sub => ({
|
298
289
|
subscribe: Boolean(sub.subscribe),
|
299
290
|
topic: sub.topic ?? ''
|
300
291
|
})),
|
301
292
|
messages
|
302
293
|
})
|
303
|
-
.catch(err =>
|
294
|
+
.catch(err => log(err))
|
304
295
|
}
|
305
296
|
}
|
306
297
|
)
|
@@ -312,36 +303,42 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
312
303
|
/**
|
313
304
|
* Handles an rpc request from a peer
|
314
305
|
*/
|
315
|
-
async processRpc (from: PeerId, peerStreams: PeerStreams, rpc:
|
306
|
+
async processRpc (from: PeerId, peerStreams: PeerStreams, rpc: PubSubRPC): Promise<boolean> {
|
316
307
|
if (!this.acceptFrom(from)) {
|
317
|
-
|
318
|
-
return
|
308
|
+
log('received message from unacceptable peer %p', from)
|
309
|
+
return false
|
319
310
|
}
|
320
311
|
|
321
|
-
|
312
|
+
log('rpc from %p', from)
|
322
313
|
|
323
314
|
const { subscriptions, messages } = rpc
|
324
315
|
|
325
|
-
if (subscriptions.length > 0) {
|
326
|
-
|
316
|
+
if (subscriptions != null && subscriptions.length > 0) {
|
317
|
+
log('subscription update from %p', from)
|
327
318
|
|
328
319
|
// update peer subscriptions
|
329
320
|
subscriptions.forEach((subOpt) => {
|
330
321
|
this.processRpcSubOpt(from, subOpt)
|
331
322
|
})
|
332
323
|
|
333
|
-
super.dispatchEvent(new CustomEvent('pubsub:subscription-change', {
|
334
|
-
detail: {
|
324
|
+
super.dispatchEvent(new CustomEvent<SubscriptionChangeData>('pubsub:subscription-change', {
|
325
|
+
detail: {
|
326
|
+
peerId: peerStreams.id,
|
327
|
+
subscriptions: subscriptions.map(({ topic, subscribe }) => ({
|
328
|
+
topic: `${topic ?? ''}`,
|
329
|
+
subscribe: Boolean(subscribe)
|
330
|
+
}))
|
331
|
+
}
|
335
332
|
}))
|
336
333
|
}
|
337
334
|
|
338
|
-
if (messages.length > 0) {
|
339
|
-
|
335
|
+
if (messages != null && messages.length > 0) {
|
336
|
+
log('messages from %p', from)
|
340
337
|
|
341
338
|
this.queue.addAll(messages.map(message => async () => {
|
342
|
-
if (!this.subscriptions.has(message.topic) && !this.canRelayMessage) {
|
343
|
-
|
344
|
-
return
|
339
|
+
if (message.topic == null || (!this.subscriptions.has(message.topic) && !this.canRelayMessage)) {
|
340
|
+
log('received message we didn\'t subscribe to. Dropping.')
|
341
|
+
return false
|
345
342
|
}
|
346
343
|
|
347
344
|
try {
|
@@ -349,17 +346,19 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
349
346
|
|
350
347
|
await this.processMessage(from, msg)
|
351
348
|
} catch (err: any) {
|
352
|
-
|
349
|
+
log.error(err)
|
353
350
|
}
|
354
351
|
}))
|
355
|
-
.catch(err =>
|
352
|
+
.catch(err => log(err))
|
356
353
|
}
|
354
|
+
|
355
|
+
return true
|
357
356
|
}
|
358
357
|
|
359
358
|
/**
|
360
359
|
* Handles a subscription change from a peer
|
361
360
|
*/
|
362
|
-
processRpcSubOpt (id: PeerId, subOpt:
|
361
|
+
processRpcSubOpt (id: PeerId, subOpt: PubSubRPCSubscription) {
|
363
362
|
const t = subOpt.topic
|
364
363
|
|
365
364
|
if (t == null) {
|
@@ -368,24 +367,24 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
368
367
|
|
369
368
|
let topicSet = this.topics.get(t)
|
370
369
|
if (topicSet == null) {
|
371
|
-
topicSet = new
|
370
|
+
topicSet = new PeerSet()
|
372
371
|
this.topics.set(t, topicSet)
|
373
372
|
}
|
374
373
|
|
375
|
-
if (subOpt.subscribe) {
|
374
|
+
if (subOpt.subscribe === true) {
|
376
375
|
// subscribe peer to new topic
|
377
|
-
topicSet.add(id
|
376
|
+
topicSet.add(id)
|
378
377
|
} else {
|
379
378
|
// unsubscribe from existing topic
|
380
|
-
topicSet.delete(id
|
379
|
+
topicSet.delete(id)
|
381
380
|
}
|
382
381
|
}
|
383
382
|
|
384
383
|
/**
|
385
|
-
* Handles
|
384
|
+
* Handles a message from a peer
|
386
385
|
*/
|
387
386
|
async processMessage (from: PeerId, msg: Message) {
|
388
|
-
if (this.
|
387
|
+
if (this.components.getPeerId().equals(from) && !this.emitSelf) {
|
389
388
|
return
|
390
389
|
}
|
391
390
|
|
@@ -393,15 +392,15 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
393
392
|
try {
|
394
393
|
await this.validate(msg)
|
395
394
|
} catch (err: any) {
|
396
|
-
|
395
|
+
log('Message is invalid, dropping it. %O', err)
|
397
396
|
return
|
398
397
|
}
|
399
398
|
|
400
399
|
if (this.subscriptions.has(msg.topic)) {
|
401
|
-
const isFromSelf = this.
|
400
|
+
const isFromSelf = this.components.getPeerId().equals(from)
|
402
401
|
|
403
402
|
if (!isFromSelf || this.emitSelf) {
|
404
|
-
super.dispatchEvent(new CustomEvent(msg.topic, {
|
403
|
+
super.dispatchEvent(new CustomEvent<Message>(msg.topic, {
|
405
404
|
detail: msg
|
406
405
|
}))
|
407
406
|
}
|
@@ -418,7 +417,7 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
418
417
|
const signaturePolicy = this.globalSignaturePolicy
|
419
418
|
switch (signaturePolicy) {
|
420
419
|
case 'StrictSign':
|
421
|
-
if (msg.
|
420
|
+
if (msg.sequenceNumber == null) {
|
422
421
|
throw errcode(new Error('Need seqno when signature policy is StrictSign but it was missing'), codes.ERR_MISSING_SEQNO)
|
423
422
|
}
|
424
423
|
|
@@ -426,7 +425,7 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
426
425
|
throw errcode(new Error('Need key when signature policy is StrictSign but it was missing'), codes.ERR_MISSING_KEY)
|
427
426
|
}
|
428
427
|
|
429
|
-
return msgId(msg.key, msg.
|
428
|
+
return msgId(msg.key, msg.sequenceNumber)
|
430
429
|
case 'StrictNoSign':
|
431
430
|
return noSignMsgId(msg.data)
|
432
431
|
default:
|
@@ -446,17 +445,25 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
446
445
|
* Decode Uint8Array into an RPC object.
|
447
446
|
* This can be override to use a custom router protobuf.
|
448
447
|
*/
|
449
|
-
decodeRpc (bytes: Uint8Array)
|
450
|
-
return RPCProto.decode(bytes)
|
451
|
-
}
|
448
|
+
abstract decodeRpc (bytes: Uint8Array): PubSubRPC
|
452
449
|
|
453
450
|
/**
|
454
451
|
* Encode RPC object into a Uint8Array.
|
455
452
|
* This can be override to use a custom router protobuf.
|
456
453
|
*/
|
457
|
-
encodeRpc (rpc:
|
458
|
-
|
459
|
-
|
454
|
+
abstract encodeRpc (rpc: PubSubRPC): Uint8Array
|
455
|
+
|
456
|
+
/**
|
457
|
+
* Decode Uint8Array into an RPC object.
|
458
|
+
* This can be override to use a custom router protobuf.
|
459
|
+
*/
|
460
|
+
abstract decodeMessage (bytes: Uint8Array): PubSubRPCMessage
|
461
|
+
|
462
|
+
/**
|
463
|
+
* Encode RPC object into a Uint8Array.
|
464
|
+
* This can be override to use a custom router protobuf.
|
465
|
+
*/
|
466
|
+
abstract encodeMessage (rpc: PubSubRPCMessage): Uint8Array
|
460
467
|
|
461
468
|
/**
|
462
469
|
* Send an rpc object to a peer
|
@@ -473,13 +480,12 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
473
480
|
/**
|
474
481
|
* Send an rpc object to a peer
|
475
482
|
*/
|
476
|
-
sendRpc (peer: PeerId, rpc:
|
483
|
+
sendRpc (peer: PeerId, rpc: PubSubRPC) {
|
477
484
|
const peerStreams = this.peers.get(peer)
|
478
485
|
|
479
486
|
if (peerStreams == null || !peerStreams.isWritable) {
|
480
|
-
|
487
|
+
log.error('Cannot send RPC to %p as there is no open stream to it available', peer)
|
481
488
|
|
482
|
-
this.log.error(msg)
|
483
489
|
return
|
484
490
|
}
|
485
491
|
|
@@ -500,7 +506,7 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
500
506
|
if (message.key != null) {
|
501
507
|
throw errcode(new Error('StrictNoSigning: key should not be present'), codes.ERR_UNEXPECTED_KEY)
|
502
508
|
}
|
503
|
-
if (message.
|
509
|
+
if (message.sequenceNumber != null) {
|
504
510
|
throw errcode(new Error('StrictNoSigning: seqno should not be present'), codes.ERR_UNEXPECTED_SEQNO)
|
505
511
|
}
|
506
512
|
break
|
@@ -508,10 +514,10 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
508
514
|
if (message.signature == null) {
|
509
515
|
throw errcode(new Error('StrictSigning: Signing required and no signature was present'), codes.ERR_MISSING_SIGNATURE)
|
510
516
|
}
|
511
|
-
if (message.
|
517
|
+
if (message.sequenceNumber == null) {
|
512
518
|
throw errcode(new Error('StrictSigning: Signing required and no seqno was present'), codes.ERR_MISSING_SEQNO)
|
513
519
|
}
|
514
|
-
if (!(await verifySignature(message))) {
|
520
|
+
if (!(await verifySignature(message, this.encodeMessage.bind(this)))) {
|
515
521
|
throw errcode(new Error('StrictSigning: Invalid message signature'), codes.ERR_INVALID_SIGNATURE)
|
516
522
|
}
|
517
523
|
break
|
@@ -534,8 +540,8 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
534
540
|
const signaturePolicy = this.globalSignaturePolicy
|
535
541
|
switch (signaturePolicy) {
|
536
542
|
case 'StrictSign':
|
537
|
-
message.
|
538
|
-
return await signMessage(this.
|
543
|
+
message.sequenceNumber = randomSeqno()
|
544
|
+
return await signMessage(this.components.getPeerId(), message, this.encodeMessage.bind(this))
|
539
545
|
case 'StrictNoSign':
|
540
546
|
return await Promise.resolve(message)
|
541
547
|
default:
|
@@ -563,29 +569,37 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
563
569
|
return []
|
564
570
|
}
|
565
571
|
|
566
|
-
return Array.from(peersInTopic
|
572
|
+
return Array.from(peersInTopic.values())
|
567
573
|
}
|
568
574
|
|
569
575
|
/**
|
570
576
|
* Publishes messages to all subscribed peers
|
571
577
|
*/
|
572
|
-
dispatchEvent (event: CustomEvent): boolean {
|
578
|
+
dispatchEvent (event: CustomEvent<Uint8Array | Message>): boolean {
|
573
579
|
if (!this.started) {
|
574
580
|
throw new Error('Pubsub has not started')
|
575
581
|
}
|
576
582
|
|
577
583
|
const topic = event.type
|
578
|
-
let message: Message
|
584
|
+
let message: Message
|
579
585
|
|
580
|
-
if (
|
586
|
+
if (event.detail instanceof Uint8Array) {
|
581
587
|
message = {
|
582
|
-
from: this.
|
588
|
+
from: this.components.getPeerId(),
|
583
589
|
topic,
|
584
|
-
data:
|
590
|
+
data: event.detail
|
591
|
+
}
|
592
|
+
} else if (event.detail != null) {
|
593
|
+
message = event.detail
|
594
|
+
} else {
|
595
|
+
message = {
|
596
|
+
from: this.components.getPeerId(),
|
597
|
+
topic,
|
598
|
+
data: new Uint8Array(0)
|
585
599
|
}
|
586
600
|
}
|
587
601
|
|
588
|
-
|
602
|
+
log('publish topic: %s from: %p data: %m', topic, message.from, message.data)
|
589
603
|
|
590
604
|
Promise.resolve().then(async () => {
|
591
605
|
message = await this.buildMessage(message)
|
@@ -593,7 +607,7 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
593
607
|
// dispatch the event if we are interested
|
594
608
|
if (this.emitSelf) {
|
595
609
|
if (this.subscriptions.has(topic)) {
|
596
|
-
super.dispatchEvent(new CustomEvent(topic, {
|
610
|
+
super.dispatchEvent(new CustomEvent<Message>(topic, {
|
597
611
|
detail: message
|
598
612
|
}))
|
599
613
|
|
@@ -604,10 +618,10 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
604
618
|
}
|
605
619
|
|
606
620
|
// send to all the other peers
|
607
|
-
await this.publishMessage(this.
|
621
|
+
await this.publishMessage(this.components.getPeerId(), message)
|
608
622
|
})
|
609
623
|
.catch(err => {
|
610
|
-
|
624
|
+
log.error(err)
|
611
625
|
})
|
612
626
|
|
613
627
|
return true
|
@@ -615,9 +629,12 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
615
629
|
|
616
630
|
/**
|
617
631
|
* Overriding the implementation of publish should handle the appropriate algorithms for the publish/subscriber implementation.
|
618
|
-
* For example, a Floodsub implementation might simply publish each message to each topic for every peer
|
632
|
+
* For example, a Floodsub implementation might simply publish each message to each topic for every peer.
|
633
|
+
*
|
634
|
+
* `sender` might be this peer, or we might be forwarding a message on behalf of another peer, in which case sender
|
635
|
+
* is the peer we received the message from, which may not be the peer the message was created by.
|
619
636
|
*/
|
620
|
-
abstract publishMessage (
|
637
|
+
abstract publishMessage (sender: PeerId, message: Message): Promise<void>
|
621
638
|
|
622
639
|
/**
|
623
640
|
* Subscribes to a given topic.
|
@@ -662,7 +679,7 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
662
679
|
const wasSubscribed = this.subscriptions.has(topicStr)
|
663
680
|
const listeners = this.listenerCount(topicStr)
|
664
681
|
|
665
|
-
|
682
|
+
log('unsubscribe from %s - am subscribed %s, listeners %d', topic, wasSubscribed, listeners)
|
666
683
|
|
667
684
|
if (wasSubscribed && listeners === 0) {
|
668
685
|
this.subscriptions.delete(topicStr)
|
@@ -692,13 +709,15 @@ export abstract class PubsubBaseProtocol<EventMap extends PubSubEvents = PubSubE
|
|
692
709
|
return Array.from(this.peers.keys())
|
693
710
|
}
|
694
711
|
|
695
|
-
addEventListener
|
712
|
+
addEventListener (type: string, callback: EventHandler<any>, options?: AddEventListenerOptions | boolean) {
|
696
713
|
this.subscribe(type.toString())
|
697
714
|
|
715
|
+
// @ts-expect-error have to ignore types to accommodate custom string event names
|
698
716
|
super.addEventListener(type, callback, options)
|
699
717
|
}
|
700
718
|
|
701
|
-
removeEventListener
|
719
|
+
removeEventListener (type: string, callback: EventHandler<any> | undefined, options?: EventListenerOptions | boolean) {
|
720
|
+
// @ts-expect-error have to ignore types to accommodate custom string event names
|
702
721
|
super.removeEventListener(type, callback, options)
|
703
722
|
|
704
723
|
const topicStr = type.toString()
|
@@ -1,10 +1,9 @@
|
|
1
|
-
import { RPC } from './rpc.js'
|
2
1
|
import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
|
3
2
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
4
|
-
import { toRpcMessage } from '
|
3
|
+
import { toRpcMessage } from './utils.js'
|
5
4
|
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
6
5
|
import { keys } from '@libp2p/crypto'
|
7
|
-
import type { Message } from '@libp2p/interfaces/pubsub'
|
6
|
+
import type { Message, PubSubRPCMessage } from '@libp2p/interfaces/pubsub'
|
8
7
|
import { peerIdFromKeys } from '@libp2p/peer-id'
|
9
8
|
|
10
9
|
export const SignPrefix = uint8ArrayFromString('libp2p-pubsub:')
|
@@ -12,11 +11,11 @@ export const SignPrefix = uint8ArrayFromString('libp2p-pubsub:')
|
|
12
11
|
/**
|
13
12
|
* Signs the provided message with the given `peerId`
|
14
13
|
*/
|
15
|
-
export async function signMessage (peerId: PeerId, message: Message) {
|
14
|
+
export async function signMessage (peerId: PeerId, message: Message, encode: (rpc: PubSubRPCMessage) => Uint8Array) {
|
16
15
|
// Get the message in bytes, and prepend with the pubsub prefix
|
17
16
|
const bytes = uint8ArrayConcat([
|
18
17
|
SignPrefix,
|
19
|
-
|
18
|
+
encode(toRpcMessage(message))
|
20
19
|
])
|
21
20
|
|
22
21
|
if (peerId.privateKey == null) {
|
@@ -42,7 +41,7 @@ export async function signMessage (peerId: PeerId, message: Message) {
|
|
42
41
|
/**
|
43
42
|
* Verifies the signature of the given message
|
44
43
|
*/
|
45
|
-
export async function verifySignature (message: Message) {
|
44
|
+
export async function verifySignature (message: Message, encode: (rpc: PubSubRPCMessage) => Uint8Array) {
|
46
45
|
if (message.signature == null) {
|
47
46
|
throw new Error('Message must contain a signature to be verified')
|
48
47
|
}
|
@@ -54,11 +53,11 @@ export async function verifySignature (message: Message) {
|
|
54
53
|
// Get message sans the signature
|
55
54
|
const bytes = uint8ArrayConcat([
|
56
55
|
SignPrefix,
|
57
|
-
|
56
|
+
encode({
|
58
57
|
...toRpcMessage(message),
|
59
58
|
signature: undefined,
|
60
59
|
key: undefined
|
61
|
-
})
|
60
|
+
})
|
62
61
|
])
|
63
62
|
|
64
63
|
// Get the public key
|