@libp2p/mplex 11.0.47-6059227cb → 11.0.47-87bc8d4fb
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 +1 -1
- package/dist/index.min.js.map +4 -4
- package/dist/src/encode.d.ts +2 -1
- package/dist/src/encode.d.ts.map +1 -1
- package/dist/src/encode.js +6 -4
- package/dist/src/encode.js.map +1 -1
- package/dist/src/index.d.ts +31 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/mplex.d.ts +53 -11
- package/dist/src/mplex.d.ts.map +1 -1
- package/dist/src/mplex.js +222 -56
- package/dist/src/mplex.js.map +1 -1
- package/dist/src/stream.d.ts +23 -17
- package/dist/src/stream.d.ts.map +1 -1
- package/dist/src/stream.js +28 -56
- package/dist/src/stream.js.map +1 -1
- package/package.json +15 -12
- package/src/encode.ts +7 -5
- package/src/index.ts +43 -10
- package/src/mplex.ts +273 -58
- package/src/stream.ts +46 -78
package/dist/src/encode.d.ts
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
import { Uint8ArrayList } from 'uint8arraylist';
|
2
2
|
import type { Message } from './message-types.js';
|
3
|
+
import type { Source } from 'it-stream-types';
|
3
4
|
/**
|
4
5
|
* Encode and yield one or more messages
|
5
6
|
*/
|
6
|
-
export declare function encode(
|
7
|
+
export declare function encode(source: Source<Message>): AsyncGenerator<Uint8Array | Uint8ArrayList, void, undefined>;
|
7
8
|
//# sourceMappingURL=encode.d.ts.map
|
package/dist/src/encode.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../../src/encode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAG/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;
|
1
|
+
{"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../../src/encode.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAG/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAkD7C;;GAEG;AACH,wBAAwB,MAAM,CAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,UAAU,GAAG,cAAc,EAAE,IAAI,EAAE,SAAS,CAAC,CAMrH"}
|
package/dist/src/encode.js
CHANGED
@@ -44,9 +44,11 @@ const encoder = new Encoder();
|
|
44
44
|
/**
|
45
45
|
* Encode and yield one or more messages
|
46
46
|
*/
|
47
|
-
export function encode(
|
48
|
-
const
|
49
|
-
|
50
|
-
|
47
|
+
export async function* encode(source) {
|
48
|
+
for await (const message of source) {
|
49
|
+
const list = new Uint8ArrayList();
|
50
|
+
encoder.write(message, list);
|
51
|
+
yield list;
|
52
|
+
}
|
51
53
|
}
|
52
54
|
//# sourceMappingURL=encode.js.map
|
package/dist/src/encode.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"encode.js","sourceRoot":"","sources":["../../src/encode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,cAAc,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;
|
1
|
+
{"version":3,"file":"encode.js","sourceRoot":"","sources":["../../src/encode.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* This is a [simple stream multiplexer(https://docs.libp2p.io/concepts/multiplex/mplex/) that has been deprecated.
|
5
5
|
*
|
6
|
-
* Please use [@libp2p
|
6
|
+
* Please use [@chainsafe/libp2p-yamux](https://www.npmjs.com/package/@chainsafe/libp2p-yamux) instead.
|
7
7
|
*
|
8
8
|
* @example
|
9
9
|
*
|
@@ -30,7 +30,9 @@
|
|
30
30
|
* pipe([1, 2, 3], stream)
|
31
31
|
* ```
|
32
32
|
*/
|
33
|
+
import type { MplexComponents } from './mplex.js';
|
33
34
|
import type { StreamMuxerFactory } from '@libp2p/interface';
|
35
|
+
export type { MplexComponents };
|
34
36
|
export interface MplexInit {
|
35
37
|
/**
|
36
38
|
* The maximum size of message that can be sent in one go in bytes.
|
@@ -38,18 +40,42 @@ export interface MplexInit {
|
|
38
40
|
* messages. If we receive a message larger than this an error will
|
39
41
|
* be thrown and the connection closed.
|
40
42
|
*
|
41
|
-
* @default
|
43
|
+
* @default 1048576
|
42
44
|
*/
|
43
|
-
|
45
|
+
maxMsgSize?: number;
|
44
46
|
/**
|
45
47
|
* Constrains the size of the unprocessed message queue buffer.
|
46
48
|
* Before messages are deserialized, the raw bytes are buffered to ensure
|
47
49
|
* we have the complete message to deserialized. If the queue gets longer
|
48
50
|
* than this value an error will be thrown and the connection closed.
|
49
51
|
*
|
50
|
-
* @default
|
52
|
+
* @default 4194304
|
51
53
|
*/
|
52
54
|
maxUnprocessedMessageQueueSize?: number;
|
55
|
+
/**
|
56
|
+
* The maximum number of multiplexed streams that can be open at any
|
57
|
+
* one time. A request to open more than this will have a stream
|
58
|
+
* reset message sent immediately as a response for the newly opened
|
59
|
+
* stream id
|
60
|
+
*
|
61
|
+
* @default 1024
|
62
|
+
*/
|
63
|
+
maxInboundStreams?: number;
|
64
|
+
/**
|
65
|
+
* The maximum number of multiplexed streams that can be open at any
|
66
|
+
* one time. An attempt to open more than this will throw
|
67
|
+
*
|
68
|
+
* @default 1024
|
69
|
+
*/
|
70
|
+
maxOutboundStreams?: number;
|
71
|
+
/**
|
72
|
+
* Incoming stream messages are buffered until processed by the stream
|
73
|
+
* handler. If the buffer reaches this size in bytes the stream will
|
74
|
+
* be reset
|
75
|
+
*
|
76
|
+
* @default 4194304
|
77
|
+
*/
|
78
|
+
maxStreamBufferSize?: number;
|
53
79
|
/**
|
54
80
|
* When `maxInboundStreams` is hit, if the remote continues try to open
|
55
81
|
* more than this many new multiplexed streams per second the connection
|
@@ -62,5 +88,5 @@ export interface MplexInit {
|
|
62
88
|
/**
|
63
89
|
* @deprecated mplex is deprecated as it has no flow control. Please use yamux instead.
|
64
90
|
*/
|
65
|
-
export declare function mplex(init?: MplexInit): () => StreamMuxerFactory;
|
91
|
+
export declare function mplex(init?: MplexInit): (components: MplexComponents) => StreamMuxerFactory;
|
66
92
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/src/index.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAIH,OAAO,KAAK,
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AACjD,OAAO,KAAK,EAAe,kBAAkB,EAAmB,MAAM,mBAAmB,CAAA;AAEzF,YAAY,EAAE,eAAe,EAAE,CAAA;AAE/B,MAAM,WAAW,SAAS;IACxB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;;;;;OAOG;IACH,8BAA8B,CAAC,EAAE,MAAM,CAAA;IAEvC;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAE1B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAE3B;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAE5B;;;;;;OAMG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAC7B;AA0BD;;GAEG;AACH,wBAAgB,KAAK,CAAE,IAAI,GAAE,SAAc,GAAG,CAAC,UAAU,EAAE,eAAe,KAAK,kBAAkB,CAEhG"}
|
package/dist/src/index.js
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
*
|
4
4
|
* This is a [simple stream multiplexer(https://docs.libp2p.io/concepts/multiplex/mplex/) that has been deprecated.
|
5
5
|
*
|
6
|
-
* Please use [@libp2p
|
6
|
+
* Please use [@chainsafe/libp2p-yamux](https://www.npmjs.com/package/@chainsafe/libp2p-yamux) instead.
|
7
7
|
*
|
8
8
|
* @example
|
9
9
|
*
|
@@ -35,15 +35,18 @@ import { MplexStreamMuxer } from './mplex.js';
|
|
35
35
|
class Mplex {
|
36
36
|
protocol = '/mplex/6.7.0';
|
37
37
|
_init;
|
38
|
-
|
38
|
+
components;
|
39
|
+
constructor(components, init = {}) {
|
40
|
+
this.components = components;
|
39
41
|
this._init = init;
|
40
42
|
}
|
41
43
|
[Symbol.toStringTag] = '@libp2p/mplex';
|
42
44
|
[serviceCapabilities] = [
|
43
45
|
'@libp2p/stream-multiplexing'
|
44
46
|
];
|
45
|
-
createStreamMuxer(
|
46
|
-
return new MplexStreamMuxer(
|
47
|
+
createStreamMuxer(init) {
|
48
|
+
return new MplexStreamMuxer(this.components, {
|
49
|
+
...init,
|
47
50
|
...this._init
|
48
51
|
});
|
49
52
|
}
|
@@ -52,6 +55,6 @@ class Mplex {
|
|
52
55
|
* @deprecated mplex is deprecated as it has no flow control. Please use yamux instead.
|
53
56
|
*/
|
54
57
|
export function mplex(init = {}) {
|
55
|
-
return () => new Mplex(init);
|
58
|
+
return (components) => new Mplex(components, init);
|
56
59
|
}
|
57
60
|
//# sourceMappingURL=index.js.map
|
package/dist/src/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAgE7C,MAAM,KAAK;IACF,QAAQ,GAAG,cAAc,CAAA;IACf,KAAK,CAAW;IAChB,UAAU,CAAiB;IAE5C,YAAa,UAA2B,EAAE,OAAkB,EAAE;QAC5D,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;QAC5B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;IACnB,CAAC;IAEQ,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,eAAe,CAAA;IAEtC,CAAC,mBAAmB,CAAC,GAAa;QACzC,6BAA6B;KAC9B,CAAA;IAED,iBAAiB,CAAE,IAAqB;QACtC,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,UAAU,EAAE;YAC3C,GAAG,IAAI;YACP,GAAG,IAAI,CAAC,KAAK;SACd,CAAC,CAAA;IACJ,CAAC;CACF;AAED;;GAEG;AACH,MAAM,UAAU,KAAK,CAAE,OAAkB,EAAE;IACzC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;AACpD,CAAC"}
|
package/dist/src/mplex.d.ts
CHANGED
@@ -1,23 +1,65 @@
|
|
1
|
-
import { AbstractStreamMuxer } from '@libp2p/utils';
|
2
1
|
import type { MplexInit } from './index.js';
|
3
2
|
import type { Message } from './message-types.js';
|
4
3
|
import type { MplexStream } from './stream.js';
|
5
|
-
import type {
|
4
|
+
import type { AbortOptions, ComponentLogger, Stream, StreamMuxer, StreamMuxerInit } from '@libp2p/interface';
|
5
|
+
import type { Sink, Source } from 'it-stream-types';
|
6
6
|
import type { Uint8ArrayList } from 'uint8arraylist';
|
7
|
-
export
|
7
|
+
export interface MplexComponents {
|
8
|
+
logger: ComponentLogger;
|
9
|
+
}
|
10
|
+
interface MplexStreamMuxerInit extends MplexInit, StreamMuxerInit {
|
11
|
+
/**
|
12
|
+
* The default timeout to use in ms when shutting down the muxer.
|
13
|
+
*/
|
14
|
+
closeTimeout?: number;
|
15
|
+
}
|
16
|
+
export declare class MplexStreamMuxer implements StreamMuxer {
|
17
|
+
protocol: string;
|
18
|
+
sink: Sink<Source<Uint8ArrayList | Uint8Array>, Promise<void>>;
|
19
|
+
source: AsyncGenerator<Uint8ArrayList | Uint8Array>;
|
20
|
+
private readonly log;
|
8
21
|
private _streamId;
|
22
|
+
private readonly _streams;
|
23
|
+
private readonly _init;
|
24
|
+
private readonly _source;
|
25
|
+
private readonly closeController;
|
9
26
|
private readonly rateLimiter;
|
10
|
-
private readonly
|
11
|
-
private readonly
|
12
|
-
|
13
|
-
|
14
|
-
|
27
|
+
private readonly closeTimeout;
|
28
|
+
private readonly logger;
|
29
|
+
constructor(components: MplexComponents, init?: MplexStreamMuxerInit);
|
30
|
+
/**
|
31
|
+
* Returns a Map of streams and their ids
|
32
|
+
*/
|
33
|
+
get streams(): Stream[];
|
15
34
|
/**
|
16
35
|
* Initiate a new stream with the given name. If no name is
|
17
36
|
* provided, the id of the stream will be used.
|
18
37
|
*/
|
19
|
-
|
20
|
-
|
21
|
-
|
38
|
+
newStream(name?: string): Stream;
|
39
|
+
/**
|
40
|
+
* Close or abort all tracked streams and stop the muxer
|
41
|
+
*/
|
42
|
+
close(options?: AbortOptions): Promise<void>;
|
43
|
+
abort(err: Error): void;
|
44
|
+
/**
|
45
|
+
* Called whenever an inbound stream is created
|
46
|
+
*/
|
47
|
+
_newReceiverStream(options: {
|
48
|
+
id: number;
|
49
|
+
name: string;
|
50
|
+
}): MplexStream;
|
51
|
+
_newStream(options: {
|
52
|
+
id: number;
|
53
|
+
name: string;
|
54
|
+
type: 'initiator' | 'receiver';
|
55
|
+
registry: Map<number, MplexStream>;
|
56
|
+
}): MplexStream;
|
57
|
+
/**
|
58
|
+
* Creates a sink with an abortable source. Incoming messages will
|
59
|
+
* also have their size restricted. All messages will be varint decoded.
|
60
|
+
*/
|
61
|
+
_createSink(): Sink<Source<Uint8ArrayList | Uint8Array>, Promise<void>>;
|
62
|
+
_handleIncoming(message: Message): Promise<void>;
|
22
63
|
}
|
64
|
+
export {};
|
23
65
|
//# sourceMappingURL=mplex.d.ts.map
|
package/dist/src/mplex.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"mplex.d.ts","sourceRoot":"","sources":["../../src/mplex.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"mplex.d.ts","sourceRoot":"","sources":["../../src/mplex.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAC3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAU,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAEpH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAyBpD,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,UAAU,oBAAqB,SAAQ,SAAS,EAAE,eAAe;IAC/D;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,qBAAa,gBAAiB,YAAW,WAAW;IAC3C,QAAQ,SAAiB;IAEzB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,GAAG,UAAU,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAC9D,MAAM,EAAE,cAAc,CAAC,cAAc,GAAG,UAAU,CAAC,CAAA;IAE1D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+E;IACxG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmB;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiB;IACjD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAa;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;gBAE3B,UAAU,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,oBAAoB;IAyDrE;;OAEG;IACH,IAAI,OAAO,IAAK,MAAM,EAAE,CAWvB;IAED;;;OAGG;IACH,SAAS,CAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAUjC;;OAEG;IACG,KAAK,CAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BnD,KAAK,CAAE,GAAG,EAAE,KAAK,GAAG,IAAI;IASxB;;OAEG;IACH,kBAAkB,CAAE,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,WAAW;IAMvE,UAAU,CAAE,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC;QAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAA;KAAE,GAAG,WAAW;IAmCnI;;;OAGG;IACH,WAAW,IAAK,IAAI,CAAC,MAAM,CAAC,cAAc,GAAG,UAAU,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IA6BlE,eAAe,CAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAsGxD"}
|
package/dist/src/mplex.js
CHANGED
@@ -1,101 +1,257 @@
|
|
1
|
-
import { MuxerClosedError } from '@libp2p/interface';
|
2
|
-
import {
|
1
|
+
import { TooManyOutboundProtocolStreamsError, MuxerClosedError } from '@libp2p/interface';
|
2
|
+
import { closeSource } from '@libp2p/utils/close-source';
|
3
|
+
import { RateLimiter } from '@libp2p/utils/rate-limiter';
|
4
|
+
import { pipe } from 'it-pipe';
|
5
|
+
import { pushable } from 'it-pushable';
|
3
6
|
import { toString as uint8ArrayToString } from 'uint8arrays';
|
4
|
-
import { Decoder
|
7
|
+
import { Decoder } from './decode.js';
|
8
|
+
import { encode } from './encode.js';
|
9
|
+
import { StreamInputBufferError } from './errors.js';
|
5
10
|
import { MessageTypes, MessageTypeNames } from './message-types.js';
|
6
11
|
import { createStream } from './stream.js';
|
12
|
+
const MAX_STREAMS_INBOUND_STREAMS_PER_CONNECTION = 1024;
|
13
|
+
const MAX_STREAMS_OUTBOUND_STREAMS_PER_CONNECTION = 1024;
|
14
|
+
const MAX_STREAM_BUFFER_SIZE = 1024 * 1024 * 4; // 4MB
|
7
15
|
const DISCONNECT_THRESHOLD = 5;
|
16
|
+
const CLOSE_TIMEOUT = 500;
|
8
17
|
function printMessage(msg) {
|
9
18
|
const output = {
|
10
19
|
...msg,
|
11
20
|
type: `${MessageTypeNames[msg.type]} (${msg.type})`
|
12
21
|
};
|
13
22
|
if (msg.type === MessageTypes.NEW_STREAM) {
|
14
|
-
output.data = uint8ArrayToString(msg.data.subarray());
|
23
|
+
output.data = uint8ArrayToString(msg.data instanceof Uint8Array ? msg.data : msg.data.subarray());
|
15
24
|
}
|
16
25
|
if (msg.type === MessageTypes.MESSAGE_INITIATOR || msg.type === MessageTypes.MESSAGE_RECEIVER) {
|
17
|
-
output.data = uint8ArrayToString(msg.data.subarray(), 'base16');
|
26
|
+
output.data = uint8ArrayToString(msg.data instanceof Uint8Array ? msg.data : msg.data.subarray(), 'base16');
|
18
27
|
}
|
19
28
|
return output;
|
20
29
|
}
|
21
|
-
export class MplexStreamMuxer
|
30
|
+
export class MplexStreamMuxer {
|
31
|
+
protocol = '/mplex/6.7.0';
|
32
|
+
sink;
|
33
|
+
source;
|
34
|
+
log;
|
22
35
|
_streamId;
|
36
|
+
_streams;
|
37
|
+
_init;
|
38
|
+
_source;
|
39
|
+
closeController;
|
23
40
|
rateLimiter;
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
protocol: '/mplex/6.7.0',
|
31
|
-
name: 'mplex'
|
32
|
-
});
|
41
|
+
closeTimeout;
|
42
|
+
logger;
|
43
|
+
constructor(components, init) {
|
44
|
+
init = init ?? {};
|
45
|
+
this.log = init.log?.newScope('mplex') ?? components.logger.forComponent('libp2p:mplex');
|
46
|
+
this.logger = components.logger;
|
33
47
|
this._streamId = 0;
|
34
|
-
this.
|
35
|
-
|
36
|
-
|
48
|
+
this._streams = {
|
49
|
+
/**
|
50
|
+
* Stream to ids map
|
51
|
+
*/
|
52
|
+
initiators: new Map(),
|
53
|
+
/**
|
54
|
+
* Stream to ids map
|
55
|
+
*/
|
56
|
+
receivers: new Map()
|
57
|
+
};
|
58
|
+
this._init = init;
|
59
|
+
this.closeTimeout = init.closeTimeout ?? CLOSE_TIMEOUT;
|
60
|
+
/**
|
61
|
+
* An iterable sink
|
62
|
+
*/
|
63
|
+
this.sink = this._createSink();
|
64
|
+
/**
|
65
|
+
* An iterable source
|
66
|
+
*/
|
67
|
+
this._source = pushable({
|
68
|
+
objectMode: true,
|
69
|
+
onEnd: () => {
|
70
|
+
// the source has ended, we can't write any more messages to gracefully
|
71
|
+
// close streams so all we can do is destroy them
|
72
|
+
for (const stream of this._streams.initiators.values()) {
|
73
|
+
stream.destroy();
|
74
|
+
}
|
75
|
+
for (const stream of this._streams.receivers.values()) {
|
76
|
+
stream.destroy();
|
77
|
+
}
|
78
|
+
}
|
79
|
+
});
|
80
|
+
this.source = pipe(this._source, source => encode(source));
|
81
|
+
/**
|
82
|
+
* Close controller
|
83
|
+
*/
|
84
|
+
this.closeController = new AbortController();
|
37
85
|
this.rateLimiter = new RateLimiter({
|
38
86
|
points: init.disconnectThreshold ?? DISCONNECT_THRESHOLD,
|
39
87
|
duration: 1
|
40
88
|
});
|
41
89
|
}
|
42
|
-
|
43
|
-
|
44
|
-
|
90
|
+
/**
|
91
|
+
* Returns a Map of streams and their ids
|
92
|
+
*/
|
93
|
+
get streams() {
|
94
|
+
// Inbound and Outbound streams may have the same ids, so we need to make those unique
|
95
|
+
const streams = [];
|
96
|
+
for (const stream of this._streams.initiators.values()) {
|
97
|
+
streams.push(stream);
|
45
98
|
}
|
99
|
+
for (const stream of this._streams.receivers.values()) {
|
100
|
+
streams.push(stream);
|
101
|
+
}
|
102
|
+
return streams;
|
46
103
|
}
|
47
104
|
/**
|
48
105
|
* Initiate a new stream with the given name. If no name is
|
49
106
|
* provided, the id of the stream will be used.
|
50
107
|
*/
|
51
|
-
|
52
|
-
if (this.
|
108
|
+
newStream(name) {
|
109
|
+
if (this.closeController.signal.aborted) {
|
53
110
|
throw new MuxerClosedError('Muxer already closed');
|
54
111
|
}
|
55
112
|
const id = this._streamId++;
|
56
|
-
|
113
|
+
name = name == null ? id.toString() : name.toString();
|
114
|
+
const registry = this._streams.initiators;
|
115
|
+
return this._newStream({ id, name, type: 'initiator', registry });
|
57
116
|
}
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
117
|
+
/**
|
118
|
+
* Close or abort all tracked streams and stop the muxer
|
119
|
+
*/
|
120
|
+
async close(options) {
|
121
|
+
if (this.closeController.signal.aborted) {
|
122
|
+
return;
|
123
|
+
}
|
124
|
+
const signal = options?.signal ?? AbortSignal.timeout(this.closeTimeout);
|
125
|
+
try {
|
126
|
+
// try to gracefully close all streams
|
127
|
+
await Promise.all(this.streams.map(async (s) => s.close({
|
128
|
+
signal
|
129
|
+
})));
|
130
|
+
this._source.end();
|
131
|
+
// try to gracefully close the muxer
|
132
|
+
await this._source.onEmpty({
|
133
|
+
signal
|
134
|
+
});
|
135
|
+
this.closeController.abort();
|
136
|
+
}
|
137
|
+
catch (err) {
|
138
|
+
this.abort(err);
|
139
|
+
}
|
140
|
+
}
|
141
|
+
abort(err) {
|
142
|
+
if (this.closeController.signal.aborted) {
|
143
|
+
return;
|
144
|
+
}
|
145
|
+
this.streams.forEach(s => { s.abort(err); });
|
146
|
+
this.closeController.abort(err);
|
147
|
+
}
|
148
|
+
/**
|
149
|
+
* Called whenever an inbound stream is created
|
150
|
+
*/
|
151
|
+
_newReceiverStream(options) {
|
152
|
+
const { id, name } = options;
|
153
|
+
const registry = this._streams.receivers;
|
154
|
+
return this._newStream({ id, name, type: 'receiver', registry });
|
155
|
+
}
|
156
|
+
_newStream(options) {
|
157
|
+
const { id, name, type, registry } = options;
|
158
|
+
this.log('new %s stream %s', type, id);
|
159
|
+
if (type === 'initiator' && this._streams.initiators.size === (this._init.maxOutboundStreams ?? MAX_STREAMS_OUTBOUND_STREAMS_PER_CONNECTION)) {
|
160
|
+
throw new TooManyOutboundProtocolStreamsError('Too many outbound streams open');
|
161
|
+
}
|
162
|
+
if (registry.has(id)) {
|
163
|
+
throw new Error(`${type} stream ${id} already exists!`);
|
164
|
+
}
|
165
|
+
const send = async (msg) => {
|
166
|
+
if (this.log.enabled) {
|
167
|
+
this.log.trace('%s stream %s send', type, id, printMessage(msg));
|
168
|
+
}
|
169
|
+
this._source.push(msg);
|
170
|
+
};
|
171
|
+
const onEnd = () => {
|
172
|
+
this.log('%s stream with id %s and protocol %s ended', type, id, stream.protocol);
|
173
|
+
registry.delete(id);
|
174
|
+
if (this._init.onStreamEnd != null) {
|
175
|
+
this._init.onStreamEnd(stream);
|
176
|
+
}
|
177
|
+
};
|
178
|
+
const stream = createStream({ id, name, send, type, onEnd, maxMsgSize: this._init.maxMsgSize, log: this.log });
|
179
|
+
registry.set(id, stream);
|
68
180
|
return stream;
|
69
181
|
}
|
70
|
-
|
182
|
+
/**
|
183
|
+
* Creates a sink with an abortable source. Incoming messages will
|
184
|
+
* also have their size restricted. All messages will be varint decoded.
|
185
|
+
*/
|
186
|
+
_createSink() {
|
187
|
+
const sink = async (source) => {
|
188
|
+
const abortListener = () => {
|
189
|
+
closeSource(source, this.log);
|
190
|
+
};
|
191
|
+
this.closeController.signal.addEventListener('abort', abortListener);
|
192
|
+
try {
|
193
|
+
const decoder = new Decoder(this._init.maxMsgSize, this._init.maxUnprocessedMessageQueueSize);
|
194
|
+
for await (const chunk of source) {
|
195
|
+
for (const msg of decoder.write(chunk)) {
|
196
|
+
await this._handleIncoming(msg);
|
197
|
+
}
|
198
|
+
}
|
199
|
+
this._source.end();
|
200
|
+
}
|
201
|
+
catch (err) {
|
202
|
+
this.log('error in sink', err);
|
203
|
+
this._source.end(err); // End the source with an error
|
204
|
+
}
|
205
|
+
finally {
|
206
|
+
this.closeController.signal.removeEventListener('abort', abortListener);
|
207
|
+
}
|
208
|
+
};
|
209
|
+
return sink;
|
210
|
+
}
|
211
|
+
async _handleIncoming(message) {
|
212
|
+
const { id, type } = message;
|
71
213
|
if (this.log.enabled) {
|
72
214
|
this.log.trace('incoming message', printMessage(message));
|
73
215
|
}
|
74
216
|
// Create a new stream?
|
75
217
|
if (message.type === MessageTypes.NEW_STREAM) {
|
76
|
-
|
77
|
-
|
78
|
-
this
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
218
|
+
if (this._streams.receivers.size === (this._init.maxInboundStreams ?? MAX_STREAMS_INBOUND_STREAMS_PER_CONNECTION)) {
|
219
|
+
this.log('too many inbound streams open');
|
220
|
+
// not going to allow this stream, send the reset message manually
|
221
|
+
// instead of setting it up just to tear it down
|
222
|
+
this._source.push({
|
223
|
+
id,
|
224
|
+
type: MessageTypes.RESET_RECEIVER
|
225
|
+
});
|
226
|
+
// if we've hit our stream limit, and the remote keeps trying to open
|
227
|
+
// more new streams, if they are doing this very quickly maybe they
|
228
|
+
// are attacking us and we should close the connection
|
229
|
+
try {
|
230
|
+
await this.rateLimiter.consume('new-stream', 1);
|
231
|
+
}
|
232
|
+
catch {
|
233
|
+
this.log('rate limit hit when opening too many new streams over the inbound stream limit - closing remote connection');
|
234
|
+
// since there's no backpressure in mplex, the only thing we can really do to protect ourselves is close the connection
|
235
|
+
this.abort(new Error('Too many open streams'));
|
236
|
+
return;
|
237
|
+
}
|
84
238
|
return;
|
85
239
|
}
|
86
|
-
const stream = this.
|
87
|
-
this.
|
240
|
+
const stream = this._newReceiverStream({ id, name: uint8ArrayToString(message.data instanceof Uint8Array ? message.data : message.data.subarray()) });
|
241
|
+
if (this._init.onIncomingStream != null) {
|
242
|
+
this._init.onIncomingStream(stream);
|
243
|
+
}
|
88
244
|
return;
|
89
245
|
}
|
90
|
-
const
|
91
|
-
const stream =
|
246
|
+
const list = (type & 1) === 1 ? this._streams.initiators : this._streams.receivers;
|
247
|
+
const stream = list.get(id);
|
92
248
|
if (stream == null) {
|
93
|
-
this.log('missing stream %s for message type %s', id, MessageTypeNames[
|
249
|
+
this.log('missing stream %s for message type %s', id, MessageTypeNames[type]);
|
94
250
|
// if the remote keeps sending us messages for streams that have been
|
95
251
|
// closed or were never opened they may be attacking us so if they do
|
96
252
|
// this very quickly all we can do is close the connection
|
97
253
|
try {
|
98
|
-
this.rateLimiter.consume('missing-stream', 1);
|
254
|
+
await this.rateLimiter.consume('missing-stream', 1);
|
99
255
|
}
|
100
256
|
catch {
|
101
257
|
this.log('rate limit hit when receiving messages for streams that do not exist - closing remote connection');
|
@@ -105,29 +261,39 @@ export class MplexStreamMuxer extends AbstractStreamMuxer {
|
|
105
261
|
}
|
106
262
|
return;
|
107
263
|
}
|
264
|
+
const maxBufferSize = this._init.maxStreamBufferSize ?? MAX_STREAM_BUFFER_SIZE;
|
108
265
|
try {
|
109
|
-
switch (
|
266
|
+
switch (type) {
|
110
267
|
case MessageTypes.MESSAGE_INITIATOR:
|
111
268
|
case MessageTypes.MESSAGE_RECEIVER:
|
269
|
+
if (stream.sourceReadableLength() > maxBufferSize) {
|
270
|
+
// Stream buffer has got too large, reset the stream
|
271
|
+
this._source.push({
|
272
|
+
id: message.id,
|
273
|
+
type: type === MessageTypes.MESSAGE_INITIATOR ? MessageTypes.RESET_RECEIVER : MessageTypes.RESET_INITIATOR
|
274
|
+
});
|
275
|
+
// Inform the stream consumer they are not fast enough
|
276
|
+
throw new StreamInputBufferError('Input buffer full - increase Mplex maxBufferSize to accommodate slow consumers');
|
277
|
+
}
|
112
278
|
// We got data from the remote, push it into our local stream
|
113
|
-
stream.
|
279
|
+
stream.sourcePush(message.data);
|
114
280
|
break;
|
115
281
|
case MessageTypes.CLOSE_INITIATOR:
|
116
282
|
case MessageTypes.CLOSE_RECEIVER:
|
117
|
-
// The remote has stopped writing
|
118
|
-
stream.
|
283
|
+
// The remote has stopped writing, so we can stop reading
|
284
|
+
stream.remoteCloseWrite();
|
119
285
|
break;
|
120
286
|
case MessageTypes.RESET_INITIATOR:
|
121
287
|
case MessageTypes.RESET_RECEIVER:
|
122
288
|
// The remote has errored, stop reading and writing to the stream immediately
|
123
|
-
stream.
|
289
|
+
stream.reset();
|
124
290
|
break;
|
125
291
|
default:
|
126
|
-
this.log('unknown message type');
|
292
|
+
this.log('unknown message type %s', type);
|
127
293
|
}
|
128
294
|
}
|
129
295
|
catch (err) {
|
130
|
-
this.log.error('error while processing message
|
296
|
+
this.log.error('error while processing message', err);
|
131
297
|
stream.abort(err);
|
132
298
|
}
|
133
299
|
}
|