@libp2p/pubsub 0.0.0 → 0.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/LICENSE +4 -0
- package/README.md +35 -0
- package/dist/src/errors.d.ts +39 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +41 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/index.d.ts +180 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +467 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/message/rpc.d.ts +258 -0
- package/dist/src/message/rpc.js +699 -0
- package/dist/src/message/sign.d.ts +17 -0
- package/dist/src/message/sign.d.ts.map +1 -0
- package/dist/src/message/sign.js +84 -0
- package/dist/src/message/sign.js.map +1 -0
- package/dist/src/message/topic-descriptor.d.ts +254 -0
- package/dist/src/message/topic-descriptor.js +647 -0
- package/dist/src/peer-streams.d.ts +67 -0
- package/dist/src/peer-streams.d.ts.map +1 -0
- package/dist/src/peer-streams.js +112 -0
- package/dist/src/peer-streams.js.map +1 -0
- package/dist/src/utils.d.ts +29 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +80 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/test/emit-self.spec.d.ts +2 -0
- package/dist/test/emit-self.spec.d.ts.map +1 -0
- package/dist/test/emit-self.spec.js +63 -0
- package/dist/test/emit-self.spec.js.map +1 -0
- package/dist/test/instance.spec.d.ts +2 -0
- package/dist/test/instance.spec.d.ts.map +1 -0
- package/dist/test/instance.spec.js +50 -0
- package/dist/test/instance.spec.js.map +1 -0
- package/dist/test/lifesycle.spec.d.ts +2 -0
- package/dist/test/lifesycle.spec.d.ts.map +1 -0
- package/dist/test/lifesycle.spec.js +192 -0
- package/dist/test/lifesycle.spec.js.map +1 -0
- package/dist/test/message.spec.d.ts +2 -0
- package/dist/test/message.spec.d.ts.map +1 -0
- package/dist/test/message.spec.js +83 -0
- package/dist/test/message.spec.js.map +1 -0
- package/dist/test/pubsub.spec.d.ts +2 -0
- package/dist/test/pubsub.spec.d.ts.map +1 -0
- package/dist/test/pubsub.spec.js +310 -0
- package/dist/test/pubsub.spec.js.map +1 -0
- package/dist/test/sign.spec.d.ts +2 -0
- package/dist/test/sign.spec.d.ts.map +1 -0
- package/dist/test/sign.spec.js +93 -0
- package/dist/test/sign.spec.js.map +1 -0
- package/dist/test/topic-validators.spec.d.ts +2 -0
- package/dist/test/topic-validators.spec.d.ts.map +1 -0
- package/dist/test/topic-validators.spec.js +86 -0
- package/dist/test/topic-validators.spec.js.map +1 -0
- package/dist/test/utils/index.d.ts +22 -0
- package/dist/test/utils/index.d.ts.map +1 -0
- package/dist/test/utils/index.js +86 -0
- package/dist/test/utils/index.js.map +1 -0
- package/dist/test/utils.spec.d.ts +2 -0
- package/dist/test/utils.spec.d.ts.map +1 -0
- package/dist/test/utils.spec.js +53 -0
- package/dist/test/utils.spec.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +109 -4
- package/src/README.md +251 -0
- package/src/errors.ts +45 -0
- package/src/index.ts +610 -0
- package/src/message/rpc.d.ts +258 -0
- package/src/message/rpc.js +699 -0
- package/src/message/rpc.proto +20 -0
- package/src/message/sign.ts +101 -0
- package/src/message/topic-descriptor.d.ts +254 -0
- package/src/message/topic-descriptor.js +647 -0
- package/src/message/topic-descriptor.proto +30 -0
- package/src/peer-streams.ts +169 -0
- package/src/utils.ts +93 -0
@@ -0,0 +1,169 @@
|
|
1
|
+
import debug from 'debug'
|
2
|
+
import { EventEmitter } from 'events'
|
3
|
+
import lp from 'it-length-prefixed'
|
4
|
+
import pushable from 'it-pushable'
|
5
|
+
import { pipe } from 'it-pipe'
|
6
|
+
import { source as abortable } from 'abortable-iterator'
|
7
|
+
import AbortController from 'abort-controller'
|
8
|
+
import type { PeerId } from '@libp2p/interfaces/peer-id'
|
9
|
+
import type { MuxedStream } from '@libp2p/interfaces/stream-muxer'
|
10
|
+
|
11
|
+
const log = Object.assign(debug('libp2p-pubsub:peer-streams'), {
|
12
|
+
error: debug('libp2p-pubsub:peer-streams:err')
|
13
|
+
})
|
14
|
+
|
15
|
+
export interface Options {
|
16
|
+
id: PeerId
|
17
|
+
protocol: string
|
18
|
+
}
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Thin wrapper around a peer's inbound / outbound pubsub streams
|
22
|
+
*/
|
23
|
+
export class PeerStreams extends EventEmitter {
|
24
|
+
public readonly id: PeerId
|
25
|
+
public readonly protocol: string
|
26
|
+
/**
|
27
|
+
* Write stream - it's preferable to use the write method
|
28
|
+
*/
|
29
|
+
public outboundStream: pushable.Pushable<Uint8Array> | undefined
|
30
|
+
/**
|
31
|
+
* Read stream
|
32
|
+
*/
|
33
|
+
public inboundStream: AsyncIterable<Uint8Array> | undefined
|
34
|
+
/**
|
35
|
+
* The raw outbound stream, as retrieved from conn.newStream
|
36
|
+
*/
|
37
|
+
private _rawOutboundStream: MuxedStream | undefined
|
38
|
+
/**
|
39
|
+
* The raw inbound stream, as retrieved from the callback from libp2p.handle
|
40
|
+
*/
|
41
|
+
private _rawInboundStream: MuxedStream | undefined
|
42
|
+
/**
|
43
|
+
* An AbortController for controlled shutdown of the inbound stream
|
44
|
+
*/
|
45
|
+
private readonly _inboundAbortController: AbortController
|
46
|
+
|
47
|
+
constructor (opts: Options) {
|
48
|
+
super()
|
49
|
+
|
50
|
+
this.id = opts.id
|
51
|
+
this.protocol = opts.protocol
|
52
|
+
|
53
|
+
this._inboundAbortController = new AbortController()
|
54
|
+
}
|
55
|
+
|
56
|
+
/**
|
57
|
+
* Do we have a connection to read from?
|
58
|
+
*
|
59
|
+
* @type {boolean}
|
60
|
+
*/
|
61
|
+
get isReadable () {
|
62
|
+
return Boolean(this.inboundStream)
|
63
|
+
}
|
64
|
+
|
65
|
+
/**
|
66
|
+
* Do we have a connection to write on?
|
67
|
+
*
|
68
|
+
* @type {boolean}
|
69
|
+
*/
|
70
|
+
get isWritable () {
|
71
|
+
return Boolean(this.outboundStream)
|
72
|
+
}
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Send a message to this peer.
|
76
|
+
* Throws if there is no `stream` to write to available.
|
77
|
+
*/
|
78
|
+
write (data: Uint8Array) {
|
79
|
+
if (this.outboundStream == null) {
|
80
|
+
const id = this.id.toString()
|
81
|
+
throw new Error('No writable connection to ' + id)
|
82
|
+
}
|
83
|
+
|
84
|
+
this.outboundStream.push(data)
|
85
|
+
}
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Attach a raw inbound stream and setup a read stream
|
89
|
+
*/
|
90
|
+
attachInboundStream (stream: MuxedStream) {
|
91
|
+
// Create and attach a new inbound stream
|
92
|
+
// The inbound stream is:
|
93
|
+
// - abortable, set to only return on abort, rather than throw
|
94
|
+
// - transformed with length-prefix transform
|
95
|
+
this._rawInboundStream = stream
|
96
|
+
this.inboundStream = abortable(
|
97
|
+
pipe(
|
98
|
+
this._rawInboundStream,
|
99
|
+
lp.decode()
|
100
|
+
),
|
101
|
+
this._inboundAbortController.signal,
|
102
|
+
{ returnOnAbort: true }
|
103
|
+
)
|
104
|
+
|
105
|
+
this.emit('stream:inbound')
|
106
|
+
return this.inboundStream
|
107
|
+
}
|
108
|
+
|
109
|
+
/**
|
110
|
+
* Attach a raw outbound stream and setup a write stream
|
111
|
+
*/
|
112
|
+
async attachOutboundStream (stream: MuxedStream) {
|
113
|
+
// If an outbound stream already exists, gently close it
|
114
|
+
const _prevStream = this.outboundStream
|
115
|
+
if (this.outboundStream != null) {
|
116
|
+
// End the stream without emitting a close event
|
117
|
+
await this.outboundStream.end()
|
118
|
+
}
|
119
|
+
|
120
|
+
this._rawOutboundStream = stream
|
121
|
+
this.outboundStream = pushable({
|
122
|
+
onEnd: (shouldEmit) => {
|
123
|
+
// close writable side of the stream
|
124
|
+
if ((this._rawOutboundStream?.reset) != null) {
|
125
|
+
this._rawOutboundStream.reset()
|
126
|
+
}
|
127
|
+
|
128
|
+
this._rawOutboundStream = undefined
|
129
|
+
this.outboundStream = undefined
|
130
|
+
if (shouldEmit != null) {
|
131
|
+
this.emit('close')
|
132
|
+
}
|
133
|
+
}
|
134
|
+
})
|
135
|
+
|
136
|
+
pipe(
|
137
|
+
this.outboundStream,
|
138
|
+
lp.encode(),
|
139
|
+
this._rawOutboundStream
|
140
|
+
).catch((err: Error) => {
|
141
|
+
log.error(err)
|
142
|
+
})
|
143
|
+
|
144
|
+
// Only emit if the connection is new
|
145
|
+
if (_prevStream == null) {
|
146
|
+
this.emit('stream:outbound')
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
150
|
+
/**
|
151
|
+
* Closes the open connection to peer
|
152
|
+
*/
|
153
|
+
close () {
|
154
|
+
// End the outbound stream
|
155
|
+
if (this.outboundStream != null) {
|
156
|
+
this.outboundStream.end()
|
157
|
+
}
|
158
|
+
// End the inbound stream
|
159
|
+
if (this.inboundStream != null) {
|
160
|
+
this._inboundAbortController.abort()
|
161
|
+
}
|
162
|
+
|
163
|
+
this._rawOutboundStream = undefined
|
164
|
+
this.outboundStream = undefined
|
165
|
+
this._rawInboundStream = undefined
|
166
|
+
this.inboundStream = undefined
|
167
|
+
this.emit('close')
|
168
|
+
}
|
169
|
+
}
|
package/src/utils.ts
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
import { randomBytes } from 'iso-random-stream'
|
2
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
3
|
+
import { PeerId } from '@libp2p/peer-id'
|
4
|
+
import { sha256 } from 'multiformats/hashes/sha2'
|
5
|
+
import type * as RPC from './message/rpc.js'
|
6
|
+
import type { Message } from '@libp2p/interfaces/pubsub'
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Generate a random sequence number
|
10
|
+
*/
|
11
|
+
export const randomSeqno = () => {
|
12
|
+
return randomBytes(8)
|
13
|
+
}
|
14
|
+
|
15
|
+
/**
|
16
|
+
* Generate a message id, based on the `from` and `seqno`
|
17
|
+
*/
|
18
|
+
export const msgId = (from: Uint8Array | string, seqno: Uint8Array) => {
|
19
|
+
let fromBytes
|
20
|
+
|
21
|
+
if (from instanceof Uint8Array) {
|
22
|
+
fromBytes = PeerId.fromBytes(from).multihash.digest
|
23
|
+
} else {
|
24
|
+
fromBytes = PeerId.fromString(from).multihash.digest
|
25
|
+
}
|
26
|
+
|
27
|
+
const msgId = new Uint8Array(fromBytes.length + seqno.length)
|
28
|
+
msgId.set(fromBytes, 0)
|
29
|
+
msgId.set(seqno, fromBytes.length)
|
30
|
+
return msgId
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Generate a message id, based on message `data`
|
35
|
+
*/
|
36
|
+
export const noSignMsgId = (data: Uint8Array) => sha256.encode(data)
|
37
|
+
|
38
|
+
/**
|
39
|
+
* Check if any member of the first set is also a member
|
40
|
+
* of the second set
|
41
|
+
*/
|
42
|
+
export const anyMatch = (a: Set<number> | number[], b: Set<number> | number[]) => {
|
43
|
+
let bHas
|
44
|
+
if (Array.isArray(b)) {
|
45
|
+
bHas = (val: number) => b.includes(val)
|
46
|
+
} else {
|
47
|
+
bHas = (val: number) => b.has(val)
|
48
|
+
}
|
49
|
+
|
50
|
+
for (const val of a) {
|
51
|
+
if (bHas(val)) {
|
52
|
+
return true
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
return false
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Make everything an array
|
61
|
+
*/
|
62
|
+
export const ensureArray = function <T> (maybeArray: T | T[]) {
|
63
|
+
if (!Array.isArray(maybeArray)) {
|
64
|
+
return [maybeArray]
|
65
|
+
}
|
66
|
+
|
67
|
+
return maybeArray
|
68
|
+
}
|
69
|
+
|
70
|
+
/**
|
71
|
+
* Ensures `message.from` is base58 encoded
|
72
|
+
*/
|
73
|
+
export const normalizeInRpcMessage = (message: RPC.RPC.IMessage, peerId?: string) => {
|
74
|
+
// @ts-expect-error receivedFrom not yet defined
|
75
|
+
const m: NormalizedIMessage = Object.assign({}, message)
|
76
|
+
|
77
|
+
if (peerId != null) {
|
78
|
+
m.receivedFrom = peerId
|
79
|
+
}
|
80
|
+
|
81
|
+
return m
|
82
|
+
}
|
83
|
+
|
84
|
+
export const normalizeOutRpcMessage = (message: Message) => {
|
85
|
+
const m: Message = Object.assign({}, message)
|
86
|
+
if (typeof message.from === 'string') {
|
87
|
+
m.from = uint8ArrayFromString(message.from, 'base58btc')
|
88
|
+
}
|
89
|
+
if (typeof message.data === 'string') {
|
90
|
+
m.data = uint8ArrayFromString(message.data)
|
91
|
+
}
|
92
|
+
return m
|
93
|
+
}
|