@libp2p/mplex 1.0.0 → 1.0.3
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/src/index.d.ts +7 -62
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -213
- package/dist/src/index.js.map +1 -1
- package/dist/src/mplex.d.ts +63 -0
- package/dist/src/mplex.d.ts.map +1 -0
- package/dist/src/mplex.js +195 -0
- package/dist/src/mplex.js.map +1 -0
- package/dist/src/stream.d.ts +1 -1
- package/dist/src/stream.js +7 -7
- package/dist/src/stream.js.map +1 -1
- package/package.json +19 -19
- package/src/index.ts +8 -274
- package/src/mplex.ts +256 -0
- package/src/stream.ts +8 -8
package/dist/src/stream.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,OAAO,MAAM,UAAU,CAAA;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAA;AAChF,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAMvC,MAAM,GAAG,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAA;AAEzC,MAAM,sBAAsB,GAAG,wBAAwB,CAAA;AACvD,MAAM,sBAAsB,GAAG,wBAAwB,CAAA;AAWvD,MAAM,UAAU,YAAY,CAAE,OAAgB;IAC5C,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,WAAW,EAAE,UAAU,GAAG,YAAY,EAAE,GAAG,OAAO,CAAA;IAExF,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;IAC7C,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAA;IAC7C,MAAM,KAAK,GAAG,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,oBAAoB,CAAA;IACjF,MAAM,UAAU,GAAG,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAA;IAC/D,MAAM,UAAU,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAEhD,IAAI,WAAW,GAAG,KAAK,CAAA;IACvB,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,IAAI,MAAyB,CAAA;IAE7B,MAAM,QAAQ,GAAa;QACzB,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE;KACjB,CAAA;IAED,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,EAAE;QAClC,IAAI,WAAW,EAAE;YACf,OAAM;SACP;QAED,WAAW,GAAG,IAAI,CAAA;QAClB,GAAG,CAAC,yBAAyB,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,CAAA;
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/stream.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@libp2p/mplex",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.3",
|
4
4
|
"description": "JavaScript implementation of https://github.com/libp2p/mplex",
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
6
6
|
"homepage": "https://github.com/libp2p/js-libp2p-mplex#readme",
|
@@ -126,38 +126,38 @@
|
|
126
126
|
]
|
127
127
|
},
|
128
128
|
"scripts": {
|
129
|
+
"clean": "aegir clean",
|
129
130
|
"lint": "aegir lint",
|
130
131
|
"dep-check": "aegir dep-check",
|
131
|
-
"build": "
|
132
|
-
"
|
133
|
-
"test": "aegir test -
|
134
|
-
"test:chrome": "
|
135
|
-
"test:
|
136
|
-
"test:firefox": "
|
137
|
-
"test:
|
138
|
-
"test:
|
139
|
-
"
|
140
|
-
"release": "semantic-release"
|
132
|
+
"build": "aegir build",
|
133
|
+
"test": "aegir test",
|
134
|
+
"test:chrome": "aegir test -t browser --cov",
|
135
|
+
"test:chrome-webworker": "aegir test -t webworker",
|
136
|
+
"test:firefox": "aegir test -t browser -- --browser firefox",
|
137
|
+
"test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
|
138
|
+
"test:node": "aegir test -t node --cov",
|
139
|
+
"test:electron-main": "aegir test -t electron-main",
|
140
|
+
"release": "aegir release"
|
141
141
|
},
|
142
142
|
"dependencies": {
|
143
|
-
"@libp2p/logger": "^1.
|
144
|
-
"@libp2p/tracked-map": "^1.0.
|
143
|
+
"@libp2p/logger": "^1.1.3",
|
144
|
+
"@libp2p/tracked-map": "^1.0.5",
|
145
145
|
"abortable-iterator": "^4.0.2",
|
146
146
|
"any-signal": "^3.0.0",
|
147
147
|
"err-code": "^3.0.1",
|
148
148
|
"it-pipe": "^2.0.3",
|
149
149
|
"it-pushable": "^2.0.1",
|
150
150
|
"it-stream-types": "^1.0.4",
|
151
|
-
"uint8arraylist": "^1.
|
151
|
+
"uint8arraylist": "^1.4.0",
|
152
152
|
"varint": "^6.0.0"
|
153
153
|
},
|
154
154
|
"devDependencies": {
|
155
|
-
"@libp2p/interface-compliance-tests": "^1.
|
156
|
-
"@libp2p/interfaces": "^1.
|
155
|
+
"@libp2p/interface-compliance-tests": "^1.1.21",
|
156
|
+
"@libp2p/interfaces": "^1.3.20",
|
157
157
|
"@types/varint": "^6.0.0",
|
158
|
-
"aegir": "^
|
159
|
-
"cborg": "^1.
|
160
|
-
"iso-random-stream": "^2.0.
|
158
|
+
"aegir": "^37.0.10",
|
159
|
+
"cborg": "^1.8.1",
|
160
|
+
"iso-random-stream": "^2.0.2",
|
161
161
|
"it-all": "^1.0.6",
|
162
162
|
"it-drain": "^1.0.5",
|
163
163
|
"it-foreach": "^0.1.1",
|
package/src/index.ts
CHANGED
@@ -1,281 +1,15 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import {
|
4
|
-
import { encode } from './encode.js'
|
5
|
-
import { decode } from './decode.js'
|
6
|
-
import { restrictSize } from './restrict-size.js'
|
7
|
-
import { MessageTypes, MessageTypeNames, Message } from './message-types.js'
|
8
|
-
import { createStream } from './stream.js'
|
9
|
-
import { toString as uint8ArrayToString } from 'uint8arrays'
|
10
|
-
import { trackedMap } from '@libp2p/tracked-map'
|
11
|
-
import { logger } from '@libp2p/logger'
|
12
|
-
import type { AbortOptions } from '@libp2p/interfaces'
|
13
|
-
import type { Sink } from 'it-stream-types'
|
14
|
-
import type { Muxer } from '@libp2p/interfaces/stream-muxer'
|
15
|
-
import type { Stream } from '@libp2p/interfaces/connection'
|
16
|
-
import type { ComponentMetricsTracker } from '@libp2p/interfaces/metrics'
|
17
|
-
import each from 'it-foreach'
|
1
|
+
import type { Components } from '@libp2p/interfaces/components'
|
2
|
+
import type { StreamMuxerFactory, StreamMuxerInit } from '@libp2p/interfaces/stream-muxer'
|
3
|
+
import { MplexStreamMuxer } from './mplex.js'
|
18
4
|
|
19
|
-
|
20
|
-
|
21
|
-
function printMessage (msg: Message) {
|
22
|
-
const output: any = {
|
23
|
-
...msg,
|
24
|
-
type: `${MessageTypeNames[msg.type]} (${msg.type})`
|
25
|
-
}
|
26
|
-
|
27
|
-
if (msg.type === MessageTypes.NEW_STREAM) {
|
28
|
-
output.data = uint8ArrayToString(msg.data instanceof Uint8Array ? msg.data : msg.data.slice())
|
29
|
-
}
|
30
|
-
|
31
|
-
if (msg.type === MessageTypes.MESSAGE_INITIATOR || msg.type === MessageTypes.MESSAGE_RECEIVER) {
|
32
|
-
output.data = uint8ArrayToString(msg.data instanceof Uint8Array ? msg.data : msg.data.slice(), 'base16')
|
33
|
-
}
|
34
|
-
|
35
|
-
return output
|
36
|
-
}
|
37
|
-
|
38
|
-
export interface MplexStream extends Stream {
|
39
|
-
source: Pushable<Uint8Array>
|
40
|
-
}
|
41
|
-
|
42
|
-
export interface MplexOptions extends AbortOptions {
|
43
|
-
onStream?: (...args: any[]) => void
|
44
|
-
onStreamEnd?: (...args: any[]) => void
|
5
|
+
export interface MplexInit extends StreamMuxerInit {
|
45
6
|
maxMsgSize?: number
|
46
|
-
metrics?: ComponentMetricsTracker
|
47
7
|
}
|
48
8
|
|
49
|
-
export class Mplex implements
|
50
|
-
|
51
|
-
|
52
|
-
public sink: Sink<Uint8Array>
|
53
|
-
public source: AsyncIterable<Uint8Array>
|
54
|
-
|
55
|
-
private _streamId: number
|
56
|
-
private readonly _streams: { initiators: Map<number, MplexStream>, receivers: Map<number, MplexStream> }
|
57
|
-
private readonly _options: MplexOptions
|
58
|
-
private readonly _source: { push: (val: Message) => void, end: (err?: Error) => void }
|
59
|
-
|
60
|
-
constructor (options?: MplexOptions) {
|
61
|
-
options = options ?? {}
|
62
|
-
|
63
|
-
this._streamId = 0
|
64
|
-
this._streams = {
|
65
|
-
/**
|
66
|
-
* Stream to ids map
|
67
|
-
*/
|
68
|
-
initiators: trackedMap<number, MplexStream>({ metrics: options.metrics, component: 'mplex', metric: 'initiatorStreams' }),
|
69
|
-
/**
|
70
|
-
* Stream to ids map
|
71
|
-
*/
|
72
|
-
receivers: trackedMap<number, MplexStream>({ metrics: options.metrics, component: 'mplex', metric: 'receiverStreams' })
|
73
|
-
}
|
74
|
-
this._options = options
|
75
|
-
|
76
|
-
/**
|
77
|
-
* An iterable sink
|
78
|
-
*/
|
79
|
-
this.sink = this._createSink()
|
80
|
-
|
81
|
-
/**
|
82
|
-
* An iterable source
|
83
|
-
*/
|
84
|
-
const source = this._createSource()
|
85
|
-
this._source = source
|
86
|
-
this.source = source
|
87
|
-
}
|
88
|
-
|
89
|
-
/**
|
90
|
-
* Returns a Map of streams and their ids
|
91
|
-
*/
|
92
|
-
get streams () {
|
93
|
-
// Inbound and Outbound streams may have the same ids, so we need to make those unique
|
94
|
-
const streams: Stream[] = []
|
95
|
-
this._streams.initiators.forEach(stream => {
|
96
|
-
streams.push(stream)
|
97
|
-
})
|
98
|
-
this._streams.receivers.forEach(stream => {
|
99
|
-
streams.push(stream)
|
100
|
-
})
|
101
|
-
return streams
|
102
|
-
}
|
103
|
-
|
104
|
-
/**
|
105
|
-
* Initiate a new stream with the given name. If no name is
|
106
|
-
* provided, the id of the stream will be used.
|
107
|
-
*/
|
108
|
-
newStream (name?: string): Stream {
|
109
|
-
const id = this._streamId++
|
110
|
-
name = name == null ? id.toString() : name.toString()
|
111
|
-
const registry = this._streams.initiators
|
112
|
-
return this._newStream({ id, name, type: 'initiator', registry })
|
113
|
-
}
|
114
|
-
|
115
|
-
/**
|
116
|
-
* Called whenever an inbound stream is created
|
117
|
-
*/
|
118
|
-
_newReceiverStream (options: { id: number, name: string }) {
|
119
|
-
const { id, name } = options
|
120
|
-
const registry = this._streams.receivers
|
121
|
-
return this._newStream({ id, name, type: 'receiver', registry })
|
122
|
-
}
|
123
|
-
|
124
|
-
_newStream (options: { id: number, name: string, type: 'initiator' | 'receiver', registry: Map<number, MplexStream> }) {
|
125
|
-
const { id, name, type, registry } = options
|
126
|
-
|
127
|
-
log('new %s stream %s %s', type, id, name)
|
128
|
-
|
129
|
-
if (registry.has(id)) {
|
130
|
-
throw new Error(`${type} stream ${id} already exists!`)
|
131
|
-
}
|
132
|
-
|
133
|
-
const send = (msg: Message) => {
|
134
|
-
if (log.enabled) {
|
135
|
-
log('%s stream %s send', type, id, printMessage(msg))
|
136
|
-
}
|
137
|
-
|
138
|
-
if (msg.type === MessageTypes.NEW_STREAM || msg.type === MessageTypes.MESSAGE_INITIATOR || msg.type === MessageTypes.MESSAGE_RECEIVER) {
|
139
|
-
msg.data = msg.data instanceof Uint8Array ? msg.data : msg.data.slice()
|
140
|
-
}
|
141
|
-
|
142
|
-
this._source.push(msg)
|
143
|
-
}
|
144
|
-
|
145
|
-
const onEnd = () => {
|
146
|
-
log('%s stream %s %s ended', type, id, name)
|
147
|
-
registry.delete(id)
|
148
|
-
|
149
|
-
if (this._options.onStreamEnd != null) {
|
150
|
-
this._options.onStreamEnd(stream)
|
151
|
-
}
|
152
|
-
}
|
153
|
-
|
154
|
-
const stream = createStream({ id, name, send, type, onEnd, maxMsgSize: this._options.maxMsgSize })
|
155
|
-
registry.set(id, stream)
|
156
|
-
return stream
|
157
|
-
}
|
158
|
-
|
159
|
-
/**
|
160
|
-
* Creates a sink with an abortable source. Incoming messages will
|
161
|
-
* also have their size restricted. All messages will be varint decoded.
|
162
|
-
*/
|
163
|
-
_createSink () {
|
164
|
-
const sink: Sink<Uint8Array> = async source => {
|
165
|
-
if (this._options.signal != null) {
|
166
|
-
source = abortableSource(source, this._options.signal)
|
167
|
-
}
|
168
|
-
|
169
|
-
try {
|
170
|
-
await pipe(
|
171
|
-
source,
|
172
|
-
source => each(source, (buf) => {
|
173
|
-
// console.info('incoming', uint8ArrayToString(buf, 'base64'))
|
174
|
-
}),
|
175
|
-
decode,
|
176
|
-
restrictSize(this._options.maxMsgSize),
|
177
|
-
async source => {
|
178
|
-
for await (const msg of source) {
|
179
|
-
this._handleIncoming(msg)
|
180
|
-
}
|
181
|
-
}
|
182
|
-
)
|
183
|
-
|
184
|
-
this._source.end()
|
185
|
-
} catch (err: any) {
|
186
|
-
log('error in sink', err)
|
187
|
-
this._source.end(err) // End the source with an error
|
188
|
-
}
|
189
|
-
}
|
190
|
-
|
191
|
-
return sink
|
192
|
-
}
|
193
|
-
|
194
|
-
/**
|
195
|
-
* Creates a source that restricts outgoing message sizes
|
196
|
-
* and varint encodes them
|
197
|
-
*/
|
198
|
-
_createSource () {
|
199
|
-
const onEnd = (err?: Error) => {
|
200
|
-
const { initiators, receivers } = this._streams
|
201
|
-
// Abort all the things!
|
202
|
-
for (const s of initiators.values()) {
|
203
|
-
s.abort(err)
|
204
|
-
}
|
205
|
-
for (const s of receivers.values()) {
|
206
|
-
s.abort(err)
|
207
|
-
}
|
208
|
-
}
|
209
|
-
const source = pushableV<Message>({ onEnd })
|
210
|
-
/*
|
211
|
-
const p = pipe(
|
212
|
-
source,
|
213
|
-
source => each(source, (msgs) => {
|
214
|
-
if (log.enabled) {
|
215
|
-
msgs.forEach(msg => {
|
216
|
-
log('outgoing message', printMessage(msg))
|
217
|
-
})
|
218
|
-
}
|
219
|
-
}),
|
220
|
-
source => encode(source),
|
221
|
-
source => each(source, (buf) => {
|
222
|
-
console.info('outgoing', uint8ArrayToString(buf, 'base64'))
|
223
|
-
})
|
224
|
-
)
|
225
|
-
|
226
|
-
return Object.assign(p, {
|
227
|
-
push: source.push,
|
228
|
-
end: source.end,
|
229
|
-
return: source.return
|
230
|
-
})
|
231
|
-
*/
|
232
|
-
return Object.assign(encode(source), {
|
233
|
-
push: source.push,
|
234
|
-
end: source.end,
|
235
|
-
return: source.return
|
236
|
-
})
|
237
|
-
}
|
238
|
-
|
239
|
-
_handleIncoming (message: Message) {
|
240
|
-
const { id, type } = message
|
241
|
-
|
242
|
-
if (log.enabled) {
|
243
|
-
log('incoming message', printMessage(message))
|
244
|
-
}
|
245
|
-
|
246
|
-
// Create a new stream?
|
247
|
-
if (message.type === MessageTypes.NEW_STREAM) {
|
248
|
-
const stream = this._newReceiverStream({ id, name: uint8ArrayToString(message.data instanceof Uint8Array ? message.data : message.data.slice()) })
|
249
|
-
|
250
|
-
if (this._options.onStream != null) {
|
251
|
-
this._options.onStream(stream)
|
252
|
-
}
|
253
|
-
|
254
|
-
return
|
255
|
-
}
|
256
|
-
|
257
|
-
const list = (type & 1) === 1 ? this._streams.initiators : this._streams.receivers
|
258
|
-
const stream = list.get(id)
|
259
|
-
|
260
|
-
if (stream == null) {
|
261
|
-
return log('missing stream %s', id)
|
262
|
-
}
|
9
|
+
export class Mplex implements StreamMuxerFactory {
|
10
|
+
public protocol = '/mplex/6.7.0'
|
263
11
|
|
264
|
-
|
265
|
-
|
266
|
-
case MessageTypes.MESSAGE_RECEIVER:
|
267
|
-
stream.source.push(message.data.slice())
|
268
|
-
break
|
269
|
-
case MessageTypes.CLOSE_INITIATOR:
|
270
|
-
case MessageTypes.CLOSE_RECEIVER:
|
271
|
-
stream.close()
|
272
|
-
break
|
273
|
-
case MessageTypes.RESET_INITIATOR:
|
274
|
-
case MessageTypes.RESET_RECEIVER:
|
275
|
-
stream.reset()
|
276
|
-
break
|
277
|
-
default:
|
278
|
-
log('unknown message type %s', type)
|
279
|
-
}
|
12
|
+
createStreamMuxer (components: Components, init?: MplexInit) {
|
13
|
+
return new MplexStreamMuxer(components, init)
|
280
14
|
}
|
281
15
|
}
|
package/src/mplex.ts
ADDED
@@ -0,0 +1,256 @@
|
|
1
|
+
import { pipe } from 'it-pipe'
|
2
|
+
import { Pushable, pushableV } from 'it-pushable'
|
3
|
+
import { abortableSource } from 'abortable-iterator'
|
4
|
+
import { encode } from './encode.js'
|
5
|
+
import { decode } from './decode.js'
|
6
|
+
import { restrictSize } from './restrict-size.js'
|
7
|
+
import { MessageTypes, MessageTypeNames, Message } from './message-types.js'
|
8
|
+
import { createStream } from './stream.js'
|
9
|
+
import { toString as uint8ArrayToString } from 'uint8arrays'
|
10
|
+
import { trackedMap } from '@libp2p/tracked-map'
|
11
|
+
import { logger } from '@libp2p/logger'
|
12
|
+
import type { Components } from '@libp2p/interfaces/components'
|
13
|
+
import type { Sink } from 'it-stream-types'
|
14
|
+
import type { StreamMuxer, StreamMuxerInit } from '@libp2p/interfaces/stream-muxer'
|
15
|
+
import type { Stream } from '@libp2p/interfaces/connection'
|
16
|
+
|
17
|
+
const log = logger('libp2p:mplex')
|
18
|
+
|
19
|
+
function printMessage (msg: Message) {
|
20
|
+
const output: any = {
|
21
|
+
...msg,
|
22
|
+
type: `${MessageTypeNames[msg.type]} (${msg.type})`
|
23
|
+
}
|
24
|
+
|
25
|
+
if (msg.type === MessageTypes.NEW_STREAM) {
|
26
|
+
output.data = uint8ArrayToString(msg.data instanceof Uint8Array ? msg.data : msg.data.slice())
|
27
|
+
}
|
28
|
+
|
29
|
+
if (msg.type === MessageTypes.MESSAGE_INITIATOR || msg.type === MessageTypes.MESSAGE_RECEIVER) {
|
30
|
+
output.data = uint8ArrayToString(msg.data instanceof Uint8Array ? msg.data : msg.data.slice(), 'base16')
|
31
|
+
}
|
32
|
+
|
33
|
+
return output
|
34
|
+
}
|
35
|
+
|
36
|
+
export interface MplexStream extends Stream {
|
37
|
+
source: Pushable<Uint8Array>
|
38
|
+
}
|
39
|
+
|
40
|
+
export interface MplexInit extends StreamMuxerInit {
|
41
|
+
maxMsgSize?: number
|
42
|
+
}
|
43
|
+
|
44
|
+
export class MplexStreamMuxer implements StreamMuxer {
|
45
|
+
public protocol = '/mplex/6.7.0'
|
46
|
+
|
47
|
+
public sink: Sink<Uint8Array>
|
48
|
+
public source: AsyncIterable<Uint8Array>
|
49
|
+
|
50
|
+
private _streamId: number
|
51
|
+
private readonly _streams: { initiators: Map<number, MplexStream>, receivers: Map<number, MplexStream> }
|
52
|
+
private readonly _init: MplexInit
|
53
|
+
private readonly _source: { push: (val: Message) => void, end: (err?: Error) => void }
|
54
|
+
|
55
|
+
constructor (components: Components, init?: MplexInit) {
|
56
|
+
init = init ?? {}
|
57
|
+
|
58
|
+
this._streamId = 0
|
59
|
+
this._streams = {
|
60
|
+
/**
|
61
|
+
* Stream to ids map
|
62
|
+
*/
|
63
|
+
initiators: trackedMap<number, MplexStream>({ metrics: components.getMetrics(), component: 'mplex', metric: 'initiatorStreams' }),
|
64
|
+
/**
|
65
|
+
* Stream to ids map
|
66
|
+
*/
|
67
|
+
receivers: trackedMap<number, MplexStream>({ metrics: components.getMetrics(), component: 'mplex', metric: 'receiverStreams' })
|
68
|
+
}
|
69
|
+
this._init = init
|
70
|
+
|
71
|
+
/**
|
72
|
+
* An iterable sink
|
73
|
+
*/
|
74
|
+
this.sink = this._createSink()
|
75
|
+
|
76
|
+
/**
|
77
|
+
* An iterable source
|
78
|
+
*/
|
79
|
+
const source = this._createSource()
|
80
|
+
this._source = source
|
81
|
+
this.source = source
|
82
|
+
}
|
83
|
+
|
84
|
+
init (components: Components) {
|
85
|
+
|
86
|
+
}
|
87
|
+
|
88
|
+
/**
|
89
|
+
* Returns a Map of streams and their ids
|
90
|
+
*/
|
91
|
+
get streams () {
|
92
|
+
// Inbound and Outbound streams may have the same ids, so we need to make those unique
|
93
|
+
const streams: Stream[] = []
|
94
|
+
this._streams.initiators.forEach(stream => {
|
95
|
+
streams.push(stream)
|
96
|
+
})
|
97
|
+
this._streams.receivers.forEach(stream => {
|
98
|
+
streams.push(stream)
|
99
|
+
})
|
100
|
+
return streams
|
101
|
+
}
|
102
|
+
|
103
|
+
/**
|
104
|
+
* Initiate a new stream with the given name. If no name is
|
105
|
+
* provided, the id of the stream will be used.
|
106
|
+
*/
|
107
|
+
newStream (name?: string): Stream {
|
108
|
+
const id = this._streamId++
|
109
|
+
name = name == null ? id.toString() : name.toString()
|
110
|
+
const registry = this._streams.initiators
|
111
|
+
return this._newStream({ id, name, type: 'initiator', registry })
|
112
|
+
}
|
113
|
+
|
114
|
+
/**
|
115
|
+
* Called whenever an inbound stream is created
|
116
|
+
*/
|
117
|
+
_newReceiverStream (options: { id: number, name: string }) {
|
118
|
+
const { id, name } = options
|
119
|
+
const registry = this._streams.receivers
|
120
|
+
return this._newStream({ id, name, type: 'receiver', registry })
|
121
|
+
}
|
122
|
+
|
123
|
+
_newStream (options: { id: number, name: string, type: 'initiator' | 'receiver', registry: Map<number, MplexStream> }) {
|
124
|
+
const { id, name, type, registry } = options
|
125
|
+
|
126
|
+
log('new %s stream %s %s', type, id, name)
|
127
|
+
|
128
|
+
if (registry.has(id)) {
|
129
|
+
throw new Error(`${type} stream ${id} already exists!`)
|
130
|
+
}
|
131
|
+
|
132
|
+
const send = (msg: Message) => {
|
133
|
+
if (log.enabled) {
|
134
|
+
log.trace('%s stream %s send', type, id, printMessage(msg))
|
135
|
+
}
|
136
|
+
|
137
|
+
if (msg.type === MessageTypes.NEW_STREAM || msg.type === MessageTypes.MESSAGE_INITIATOR || msg.type === MessageTypes.MESSAGE_RECEIVER) {
|
138
|
+
msg.data = msg.data instanceof Uint8Array ? msg.data : msg.data.slice()
|
139
|
+
}
|
140
|
+
|
141
|
+
this._source.push(msg)
|
142
|
+
}
|
143
|
+
|
144
|
+
const onEnd = () => {
|
145
|
+
log('%s stream %s %s ended', type, id, name)
|
146
|
+
registry.delete(id)
|
147
|
+
|
148
|
+
if (this._init.onStreamEnd != null) {
|
149
|
+
this._init.onStreamEnd(stream)
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
const stream = createStream({ id, name, send, type, onEnd, maxMsgSize: this._init.maxMsgSize })
|
154
|
+
registry.set(id, stream)
|
155
|
+
return stream
|
156
|
+
}
|
157
|
+
|
158
|
+
/**
|
159
|
+
* Creates a sink with an abortable source. Incoming messages will
|
160
|
+
* also have their size restricted. All messages will be varint decoded.
|
161
|
+
*/
|
162
|
+
_createSink () {
|
163
|
+
const sink: Sink<Uint8Array> = async source => {
|
164
|
+
if (this._init.signal != null) {
|
165
|
+
source = abortableSource(source, this._init.signal)
|
166
|
+
}
|
167
|
+
|
168
|
+
try {
|
169
|
+
await pipe(
|
170
|
+
source,
|
171
|
+
decode,
|
172
|
+
restrictSize(this._init.maxMsgSize),
|
173
|
+
async source => {
|
174
|
+
for await (const msg of source) {
|
175
|
+
this._handleIncoming(msg)
|
176
|
+
}
|
177
|
+
}
|
178
|
+
)
|
179
|
+
|
180
|
+
this._source.end()
|
181
|
+
} catch (err: any) {
|
182
|
+
log('error in sink', err)
|
183
|
+
this._source.end(err) // End the source with an error
|
184
|
+
}
|
185
|
+
}
|
186
|
+
|
187
|
+
return sink
|
188
|
+
}
|
189
|
+
|
190
|
+
/**
|
191
|
+
* Creates a source that restricts outgoing message sizes
|
192
|
+
* and varint encodes them
|
193
|
+
*/
|
194
|
+
_createSource () {
|
195
|
+
const onEnd = (err?: Error) => {
|
196
|
+
const { initiators, receivers } = this._streams
|
197
|
+
// Abort all the things!
|
198
|
+
for (const s of initiators.values()) {
|
199
|
+
s.abort(err)
|
200
|
+
}
|
201
|
+
for (const s of receivers.values()) {
|
202
|
+
s.abort(err)
|
203
|
+
}
|
204
|
+
}
|
205
|
+
const source = pushableV<Message>({ onEnd })
|
206
|
+
|
207
|
+
return Object.assign(encode(source), {
|
208
|
+
push: source.push,
|
209
|
+
end: source.end,
|
210
|
+
return: source.return
|
211
|
+
})
|
212
|
+
}
|
213
|
+
|
214
|
+
_handleIncoming (message: Message) {
|
215
|
+
const { id, type } = message
|
216
|
+
|
217
|
+
if (log.enabled) {
|
218
|
+
log.trace('incoming message', printMessage(message))
|
219
|
+
}
|
220
|
+
|
221
|
+
// Create a new stream?
|
222
|
+
if (message.type === MessageTypes.NEW_STREAM) {
|
223
|
+
const stream = this._newReceiverStream({ id, name: uint8ArrayToString(message.data instanceof Uint8Array ? message.data : message.data.slice()) })
|
224
|
+
|
225
|
+
if (this._init.onIncomingStream != null) {
|
226
|
+
this._init.onIncomingStream(stream)
|
227
|
+
}
|
228
|
+
|
229
|
+
return
|
230
|
+
}
|
231
|
+
|
232
|
+
const list = (type & 1) === 1 ? this._streams.initiators : this._streams.receivers
|
233
|
+
const stream = list.get(id)
|
234
|
+
|
235
|
+
if (stream == null) {
|
236
|
+
return log('missing stream %s', id)
|
237
|
+
}
|
238
|
+
|
239
|
+
switch (type) {
|
240
|
+
case MessageTypes.MESSAGE_INITIATOR:
|
241
|
+
case MessageTypes.MESSAGE_RECEIVER:
|
242
|
+
stream.source.push(message.data.slice())
|
243
|
+
break
|
244
|
+
case MessageTypes.CLOSE_INITIATOR:
|
245
|
+
case MessageTypes.CLOSE_RECEIVER:
|
246
|
+
stream.close()
|
247
|
+
break
|
248
|
+
case MessageTypes.RESET_INITIATOR:
|
249
|
+
case MessageTypes.RESET_RECEIVER:
|
250
|
+
stream.reset()
|
251
|
+
break
|
252
|
+
default:
|
253
|
+
log('unknown message type %s', type)
|
254
|
+
}
|
255
|
+
}
|
256
|
+
}
|
package/src/stream.ts
CHANGED
@@ -10,7 +10,7 @@ import { logger } from '@libp2p/logger'
|
|
10
10
|
import type { Message } from './message-types.js'
|
11
11
|
import type { Timeline } from '@libp2p/interfaces/connection'
|
12
12
|
import type { Source } from 'it-stream-types'
|
13
|
-
import type { MplexStream } from './
|
13
|
+
import type { MplexStream } from './mplex.js'
|
14
14
|
|
15
15
|
const log = logger('libp2p:mplex:stream')
|
16
16
|
|
@@ -49,7 +49,7 @@ export function createStream (options: Options): MplexStream {
|
|
49
49
|
}
|
50
50
|
|
51
51
|
sourceEnded = true
|
52
|
-
log('%s stream %s source end', type, streamName, err)
|
52
|
+
log.trace('%s stream %s source end', type, streamName, err)
|
53
53
|
|
54
54
|
if (err != null && endErr == null) {
|
55
55
|
endErr = err
|
@@ -70,7 +70,7 @@ export function createStream (options: Options): MplexStream {
|
|
70
70
|
}
|
71
71
|
|
72
72
|
sinkEnded = true
|
73
|
-
log('%s stream %s sink end - err: %o', type, streamName, err)
|
73
|
+
log.trace('%s stream %s sink end - err: %o', type, streamName, err)
|
74
74
|
|
75
75
|
if (err != null && endErr == null) {
|
76
76
|
endErr = err
|
@@ -92,7 +92,7 @@ export function createStream (options: Options): MplexStream {
|
|
92
92
|
},
|
93
93
|
// Close for reading and writing (local error)
|
94
94
|
abort: (err?: Error) => {
|
95
|
-
log('%s stream %s abort', type, streamName, err)
|
95
|
+
log.trace('%s stream %s abort', type, streamName, err)
|
96
96
|
// End the source with the passed error
|
97
97
|
stream.source.end(err)
|
98
98
|
abortController.abort()
|
@@ -148,13 +148,13 @@ export function createStream (options: Options): MplexStream {
|
|
148
148
|
|
149
149
|
// Send no more data if this stream was remotely reset
|
150
150
|
if (err.code === ERR_MPLEX_STREAM_RESET) {
|
151
|
-
log('%s stream %s reset', type, name)
|
151
|
+
log.trace('%s stream %s reset', type, name)
|
152
152
|
} else {
|
153
|
-
log('%s stream %s error', type, name, err)
|
153
|
+
log.trace('%s stream %s error', type, name, err)
|
154
154
|
try {
|
155
155
|
send({ id, type: Types.RESET })
|
156
156
|
} catch (err) {
|
157
|
-
log('%s stream %s error sending reset', type, name, err)
|
157
|
+
log.trace('%s stream %s error sending reset', type, name, err)
|
158
158
|
}
|
159
159
|
}
|
160
160
|
|
@@ -166,7 +166,7 @@ export function createStream (options: Options): MplexStream {
|
|
166
166
|
try {
|
167
167
|
send({ id, type: Types.CLOSE })
|
168
168
|
} catch (err) {
|
169
|
-
log('%s stream %s error sending close', type, name, err)
|
169
|
+
log.trace('%s stream %s error sending close', type, name, err)
|
170
170
|
}
|
171
171
|
|
172
172
|
onSinkEnd()
|