@libp2p/multistream-select 4.0.6-c960eb659 → 4.0.6-d729d66a5
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 +1 -1
- package/dist/index.min.js +14 -2
- package/dist/src/handle.d.ts +3 -5
- package/dist/src/handle.d.ts.map +1 -1
- package/dist/src/handle.js +72 -18
- package/dist/src/handle.js.map +1 -1
- package/dist/src/index.d.ts +5 -12
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/multistream.d.ts +14 -9
- package/dist/src/multistream.d.ts.map +1 -1
- package/dist/src/multistream.js +14 -52
- package/dist/src/multistream.js.map +1 -1
- package/dist/src/select.d.ts +4 -7
- package/dist/src/select.d.ts.map +1 -1
- package/dist/src/select.js +131 -67
- package/dist/src/select.js.map +1 -1
- package/package.json +9 -14
- package/src/handle.ts +35 -24
- package/src/index.ts +5 -13
- package/src/multistream.ts +19 -71
- package/src/select.ts +100 -73
package/dist/src/select.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/select.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/select.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AACvE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAsB,MAAM,CAAE,MAAM,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAG,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CA+ClL;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAE,MAAM,SAAS,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAG,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,qBAAqB,GAAG,cAAc,CAAC,MAAM,CAAC,CA4E3J"}
|
package/dist/src/select.js
CHANGED
|
@@ -1,95 +1,159 @@
|
|
|
1
1
|
import { CodeError } from '@libp2p/interface/errors';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import merge from 'it-merge';
|
|
5
|
-
import { pushable } from 'it-pushable';
|
|
6
|
-
import { reader } from 'it-reader';
|
|
2
|
+
import { lpStream } from 'it-length-prefixed-stream';
|
|
3
|
+
import * as varint from 'uint8-varint';
|
|
7
4
|
import { Uint8ArrayList } from 'uint8arraylist';
|
|
8
5
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
|
|
6
|
+
import { MAX_PROTOCOL_LENGTH } from './constants.js';
|
|
9
7
|
import * as multistream from './multistream.js';
|
|
10
8
|
import { PROTOCOL_ID } from './index.js';
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Negotiate a protocol to use from a list of protocols.
|
|
11
|
+
*
|
|
12
|
+
* @param stream - A duplex iterable stream to dial on
|
|
13
|
+
* @param protocols - A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made.
|
|
14
|
+
* @param options - An options object containing an AbortSignal and an optional boolean `writeBytes` - if this is true, `Uint8Array`s will be written into `duplex`, otherwise `Uint8ArrayList`s will
|
|
15
|
+
* @returns A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.
|
|
16
|
+
* @example
|
|
17
|
+
*
|
|
18
|
+
* ```js
|
|
19
|
+
* import { pipe } from 'it-pipe'
|
|
20
|
+
* import * as mss from '@libp2p/multistream-select'
|
|
21
|
+
* import { Mplex } from '@libp2p/mplex'
|
|
22
|
+
*
|
|
23
|
+
* const muxer = new Mplex()
|
|
24
|
+
* const muxedStream = muxer.newStream()
|
|
25
|
+
*
|
|
26
|
+
* // mss.select(protocol(s))
|
|
27
|
+
* // Select from one of the passed protocols (in priority order)
|
|
28
|
+
* // Returns selected stream and protocol
|
|
29
|
+
* const { stream: dhtStream, protocol } = await mss.select(muxedStream, [
|
|
30
|
+
* // This might just be different versions of DHT, but could be different impls
|
|
31
|
+
* '/ipfs-dht/2.0.0', // Most of the time this will probably just be one item.
|
|
32
|
+
* '/ipfs-dht/1.0.0'
|
|
33
|
+
* ])
|
|
34
|
+
*
|
|
35
|
+
* // Typically this stream will be passed back to the caller of libp2p.dialProtocol
|
|
36
|
+
* //
|
|
37
|
+
* // ...it might then do something like this:
|
|
38
|
+
* // try {
|
|
39
|
+
* // await pipe(
|
|
40
|
+
* // [uint8ArrayFromString('Some DHT data')]
|
|
41
|
+
* // dhtStream,
|
|
42
|
+
* // async source => {
|
|
43
|
+
* // for await (const chunk of source)
|
|
44
|
+
* // // DHT response data
|
|
45
|
+
* // }
|
|
46
|
+
* // )
|
|
47
|
+
* // } catch (err) {
|
|
48
|
+
* // // Error in stream
|
|
49
|
+
* // }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export async function select(stream, protocols, options) {
|
|
13
53
|
protocols = Array.isArray(protocols) ? [...protocols] : [protocols];
|
|
14
|
-
const
|
|
54
|
+
const lp = lpStream(stream, {
|
|
55
|
+
...options,
|
|
56
|
+
maxDataLength: MAX_PROTOCOL_LENGTH
|
|
57
|
+
});
|
|
15
58
|
const protocol = protocols.shift();
|
|
16
59
|
if (protocol == null) {
|
|
17
60
|
throw new Error('At least one protocol must be specified');
|
|
18
61
|
}
|
|
19
|
-
log.trace('select: write ["%s", "%s"]', PROTOCOL_ID, protocol);
|
|
20
|
-
const p1 = uint8ArrayFromString(PROTOCOL_ID);
|
|
21
|
-
const p2 = uint8ArrayFromString(protocol);
|
|
22
|
-
multistream.writeAll(
|
|
23
|
-
|
|
24
|
-
|
|
62
|
+
options?.log.trace('select: write ["%s", "%s"]', PROTOCOL_ID, protocol);
|
|
63
|
+
const p1 = uint8ArrayFromString(`${PROTOCOL_ID}\n`);
|
|
64
|
+
const p2 = uint8ArrayFromString(`${protocol}\n`);
|
|
65
|
+
await multistream.writeAll(lp, [p1, p2], options);
|
|
66
|
+
options?.log.trace('select: reading multistream-select header');
|
|
67
|
+
let response = await multistream.readString(lp, options);
|
|
68
|
+
options?.log.trace('select: read "%s"', response);
|
|
25
69
|
// Read the protocol response if we got the protocolId in return
|
|
26
70
|
if (response === PROTOCOL_ID) {
|
|
27
|
-
|
|
28
|
-
|
|
71
|
+
options?.log.trace('select: reading protocol response');
|
|
72
|
+
response = await multistream.readString(lp, options);
|
|
73
|
+
options?.log.trace('select: read "%s"', response);
|
|
29
74
|
}
|
|
30
75
|
// We're done
|
|
31
76
|
if (response === protocol) {
|
|
32
|
-
|
|
33
|
-
return { stream: shakeStream, protocol };
|
|
77
|
+
return { stream: lp.unwrap(), protocol };
|
|
34
78
|
}
|
|
35
79
|
// We haven't gotten a valid ack, try the other protocols
|
|
36
80
|
for (const protocol of protocols) {
|
|
37
|
-
log.trace('select: write "%s"', protocol);
|
|
38
|
-
multistream.write(
|
|
39
|
-
|
|
40
|
-
|
|
81
|
+
options?.log.trace('select: write "%s"', protocol);
|
|
82
|
+
await multistream.write(lp, uint8ArrayFromString(`${protocol}\n`), options);
|
|
83
|
+
options?.log.trace('select: reading protocol response');
|
|
84
|
+
const response = await multistream.readString(lp, options);
|
|
85
|
+
options?.log.trace('select: read "%s" for "%s"', response, protocol);
|
|
41
86
|
if (response === protocol) {
|
|
42
|
-
|
|
43
|
-
return { stream: shakeStream, protocol };
|
|
87
|
+
return { stream: lp.unwrap(), protocol };
|
|
44
88
|
}
|
|
45
89
|
}
|
|
46
|
-
rest();
|
|
47
90
|
throw new CodeError('protocol selection failed', 'ERR_UNSUPPORTED_PROTOCOL');
|
|
48
91
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
let response = await multistream.readString(byteReader);
|
|
82
|
-
if (response === PROTOCOL_ID) {
|
|
83
|
-
response = await multistream.readString(byteReader);
|
|
84
|
-
}
|
|
85
|
-
if (response !== protocol) {
|
|
86
|
-
throw new CodeError('protocol selection failed', 'ERR_UNSUPPORTED_PROTOCOL');
|
|
92
|
+
/**
|
|
93
|
+
* Lazily negotiates a protocol.
|
|
94
|
+
*
|
|
95
|
+
* It *does not* block writes waiting for the other end to respond. Instead, it
|
|
96
|
+
* simply assumes the negotiation went successfully and starts writing data.
|
|
97
|
+
*
|
|
98
|
+
* Use when it is known that the receiver supports the desired protocol.
|
|
99
|
+
*/
|
|
100
|
+
export function lazySelect(stream, protocol, options) {
|
|
101
|
+
const originalSink = stream.sink.bind(stream);
|
|
102
|
+
const originalSource = stream.source;
|
|
103
|
+
let selected = false;
|
|
104
|
+
const lp = lpStream({
|
|
105
|
+
sink: originalSink,
|
|
106
|
+
source: originalSource
|
|
107
|
+
}, {
|
|
108
|
+
...options,
|
|
109
|
+
maxDataLength: MAX_PROTOCOL_LENGTH
|
|
110
|
+
});
|
|
111
|
+
stream.sink = async (source) => {
|
|
112
|
+
const { sink } = lp.unwrap();
|
|
113
|
+
await sink(async function* () {
|
|
114
|
+
for await (const buf of source) {
|
|
115
|
+
// if writing before selecting, send selection with first data chunk
|
|
116
|
+
if (!selected) {
|
|
117
|
+
selected = true;
|
|
118
|
+
options?.log.trace('lazy: write ["%s", "%s", data] in sink', PROTOCOL_ID, protocol);
|
|
119
|
+
const protocolString = `${protocol}\n`;
|
|
120
|
+
// send protocols in first chunk of data written to transport
|
|
121
|
+
yield new Uint8ArrayList(Uint8Array.from([19]), // length of PROTOCOL_ID plus newline
|
|
122
|
+
uint8ArrayFromString(`${PROTOCOL_ID}\n`), varint.encode(protocolString.length), uint8ArrayFromString(protocolString), buf).subarray();
|
|
123
|
+
options?.log.trace('lazy: wrote ["%s", "%s", data] in sink', PROTOCOL_ID, protocol);
|
|
87
124
|
}
|
|
88
|
-
|
|
89
|
-
yield
|
|
125
|
+
else {
|
|
126
|
+
yield buf;
|
|
90
127
|
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
128
|
+
}
|
|
129
|
+
}());
|
|
130
|
+
};
|
|
131
|
+
stream.source = (async function* () {
|
|
132
|
+
// if reading before selecting, send selection before first data chunk
|
|
133
|
+
if (!selected) {
|
|
134
|
+
selected = true;
|
|
135
|
+
options?.log.trace('lazy: write ["%s", "%s", data] in source', PROTOCOL_ID, protocol);
|
|
136
|
+
await lp.writeV([
|
|
137
|
+
uint8ArrayFromString(`${PROTOCOL_ID}\n`),
|
|
138
|
+
uint8ArrayFromString(`${protocol}\n`)
|
|
139
|
+
]);
|
|
140
|
+
options?.log.trace('lazy: wrote ["%s", "%s", data] in source', PROTOCOL_ID, protocol);
|
|
141
|
+
}
|
|
142
|
+
options?.log.trace('lazy: reading multistream select header');
|
|
143
|
+
let response = await multistream.readString(lp, options);
|
|
144
|
+
options?.log.trace('lazy: read multistream select header "%s"', response);
|
|
145
|
+
if (response === PROTOCOL_ID) {
|
|
146
|
+
response = await multistream.readString(lp, options);
|
|
147
|
+
}
|
|
148
|
+
options?.log.trace('lazy: read protocol "%s", expecting "%s"', response, protocol);
|
|
149
|
+
if (response !== protocol) {
|
|
150
|
+
throw new CodeError('protocol selection failed', 'ERR_UNSUPPORTED_PROTOCOL');
|
|
151
|
+
}
|
|
152
|
+
options?.log.trace('lazy: reading rest of "%s" stream', protocol);
|
|
153
|
+
yield* lp.unwrap().source;
|
|
154
|
+
})();
|
|
155
|
+
return {
|
|
156
|
+
stream,
|
|
93
157
|
protocol
|
|
94
158
|
};
|
|
95
159
|
}
|
package/dist/src/select.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/select.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AACpD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/select.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libp2p/multistream-select",
|
|
3
|
-
"version": "4.0.6-
|
|
3
|
+
"version": "4.0.6-d729d66a5",
|
|
4
4
|
"description": "JavaScript implementation of multistream-select",
|
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
|
6
|
-
"homepage": "https://github.com/libp2p/js-libp2p/tree/
|
|
6
|
+
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/multistream-select#readme",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "git+https://github.com/libp2p/js-libp2p.git"
|
|
@@ -53,26 +53,21 @@
|
|
|
53
53
|
"test:electron-main": "aegir test -t electron-main"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@libp2p/interface": "0.1.6-
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"it-first": "^3.0.1",
|
|
60
|
-
"it-handshake": "^4.1.3",
|
|
61
|
-
"it-length-prefixed": "^9.0.1",
|
|
62
|
-
"it-merge": "^3.0.0",
|
|
56
|
+
"@libp2p/interface": "0.1.6-d729d66a5",
|
|
57
|
+
"it-length-prefixed": "^9.0.3",
|
|
58
|
+
"it-length-prefixed-stream": "^1.1.1",
|
|
63
59
|
"it-pipe": "^3.0.1",
|
|
64
|
-
"it-pushable": "^3.2.0",
|
|
65
|
-
"it-reader": "^6.0.1",
|
|
66
60
|
"it-stream-types": "^2.0.1",
|
|
67
|
-
"uint8-varint": "^2.0.
|
|
61
|
+
"uint8-varint": "^2.0.2",
|
|
68
62
|
"uint8arraylist": "^2.4.3",
|
|
69
63
|
"uint8arrays": "^4.0.6"
|
|
70
64
|
},
|
|
71
65
|
"devDependencies": {
|
|
66
|
+
"@libp2p/logger": "3.1.0-d729d66a5",
|
|
72
67
|
"aegir": "^41.0.2",
|
|
73
68
|
"iso-random-stream": "^2.0.2",
|
|
74
|
-
"it-all": "^3.0.
|
|
75
|
-
"it-
|
|
69
|
+
"it-all": "^3.0.3",
|
|
70
|
+
"it-drain": "^3.0.5",
|
|
76
71
|
"it-pair": "^2.0.6",
|
|
77
72
|
"p-timeout": "^6.0.0"
|
|
78
73
|
}
|
package/src/handle.ts
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { encode } from 'it-length-prefixed'
|
|
2
|
+
import { lpStream } from 'it-length-prefixed-stream'
|
|
3
3
|
import { Uint8ArrayList } from 'uint8arraylist'
|
|
4
4
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
5
|
-
import { PROTOCOL_ID } from './constants.js'
|
|
5
|
+
import { MAX_PROTOCOL_LENGTH, PROTOCOL_ID } from './constants.js'
|
|
6
6
|
import * as multistream from './multistream.js'
|
|
7
|
-
import type {
|
|
8
|
-
import type { Duplex
|
|
9
|
-
|
|
10
|
-
const log = logger('libp2p:mss:handle')
|
|
7
|
+
import type { MultistreamSelectInit, ProtocolStream } from './index.js'
|
|
8
|
+
import type { Duplex } from 'it-stream-types'
|
|
11
9
|
|
|
12
10
|
/**
|
|
13
11
|
* Handle multistream protocol selections for the given list of protocols.
|
|
@@ -55,38 +53,51 @@ const log = logger('libp2p:mss:handle')
|
|
|
55
53
|
* })
|
|
56
54
|
* ```
|
|
57
55
|
*/
|
|
58
|
-
export async function handle (stream:
|
|
59
|
-
export async function handle (stream: Duplex<Source<Uint8ArrayList | Uint8Array>, Source<Uint8ArrayList | Uint8Array>>, protocols: string | string[], options?: ByteListInit): Promise<ProtocolStream<Uint8ArrayList, Uint8ArrayList | Uint8Array>>
|
|
60
|
-
export async function handle (stream: any, protocols: string | string[], options?: MultistreamSelectInit): Promise<ProtocolStream<any>> {
|
|
56
|
+
export async function handle <Stream extends Duplex<any, any, any>> (stream: Stream, protocols: string | string[], options: MultistreamSelectInit): Promise<ProtocolStream<Stream>> {
|
|
61
57
|
protocols = Array.isArray(protocols) ? protocols : [protocols]
|
|
62
|
-
|
|
58
|
+
options.log.trace('handle: available protocols %s', protocols)
|
|
59
|
+
|
|
60
|
+
const lp = lpStream(stream, {
|
|
61
|
+
...options,
|
|
62
|
+
maxDataLength: MAX_PROTOCOL_LENGTH,
|
|
63
|
+
maxLengthLength: 2 // 2 bytes is enough to length-prefix MAX_PROTOCOL_LENGTH
|
|
64
|
+
})
|
|
63
65
|
|
|
64
66
|
while (true) {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
options?.log.trace('handle: reading incoming string')
|
|
68
|
+
const protocol = await multistream.readString(lp, options)
|
|
69
|
+
options.log.trace('handle: read "%s"', protocol)
|
|
67
70
|
|
|
68
71
|
if (protocol === PROTOCOL_ID) {
|
|
69
|
-
log.trace('respond with "%s" for "%s"', PROTOCOL_ID, protocol)
|
|
70
|
-
multistream.write(
|
|
72
|
+
options.log.trace('handle: respond with "%s" for "%s"', PROTOCOL_ID, protocol)
|
|
73
|
+
await multistream.write(lp, uint8ArrayFromString(`${PROTOCOL_ID}\n`), options)
|
|
74
|
+
options.log.trace('handle: responded with "%s" for "%s"', PROTOCOL_ID, protocol)
|
|
71
75
|
continue
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
if (protocols.includes(protocol)) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
options.log.trace('handle: respond with "%s" for "%s"', protocol, protocol)
|
|
80
|
+
await multistream.write(lp, uint8ArrayFromString(`${protocol}\n`), options)
|
|
81
|
+
options.log.trace('handle: responded with "%s" for "%s"', protocol, protocol)
|
|
82
|
+
|
|
83
|
+
return { stream: lp.unwrap(), protocol }
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
if (protocol === 'ls') {
|
|
82
87
|
// <varint-msg-len><varint-proto-name-len><proto-name>\n<varint-proto-name-len><proto-name>\n\n
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
const protos = new Uint8ArrayList(
|
|
89
|
+
...protocols.map(p => encode.single(uint8ArrayFromString(`${p}\n`))),
|
|
90
|
+
uint8ArrayFromString('\n')
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
options.log.trace('handle: respond with "%s" for %s', protocols, protocol)
|
|
94
|
+
await multistream.write(lp, protos, options)
|
|
95
|
+
options.log.trace('handle: responded with "%s" for %s', protocols, protocol)
|
|
86
96
|
continue
|
|
87
97
|
}
|
|
88
98
|
|
|
89
|
-
|
|
90
|
-
|
|
99
|
+
options.log('handle: respond with "na" for "%s"', protocol)
|
|
100
|
+
await multistream.write(lp, uint8ArrayFromString('na\n'), options)
|
|
101
|
+
options.log('handle: responded with "na" for "%s"', protocol)
|
|
91
102
|
}
|
|
92
103
|
}
|
package/src/index.ts
CHANGED
|
@@ -21,26 +21,18 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import { PROTOCOL_ID } from './constants.js'
|
|
24
|
-
import type { AbortOptions } from '@libp2p/interface'
|
|
25
|
-
import type {
|
|
24
|
+
import type { AbortOptions, LoggerOptions } from '@libp2p/interface'
|
|
25
|
+
import type { LengthPrefixedStreamOpts } from 'it-length-prefixed-stream'
|
|
26
26
|
|
|
27
27
|
export { PROTOCOL_ID }
|
|
28
28
|
|
|
29
|
-
export interface ProtocolStream<
|
|
30
|
-
stream:
|
|
29
|
+
export interface ProtocolStream<Stream> {
|
|
30
|
+
stream: Stream
|
|
31
31
|
protocol: string
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export interface
|
|
35
|
-
writeBytes: true
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface ByteListInit extends AbortOptions {
|
|
39
|
-
writeBytes?: false
|
|
40
|
-
}
|
|
34
|
+
export interface MultistreamSelectInit extends AbortOptions, LoggerOptions, Partial<LengthPrefixedStreamOpts> {
|
|
41
35
|
|
|
42
|
-
export interface MultistreamSelectInit extends AbortOptions {
|
|
43
|
-
writeBytes?: boolean
|
|
44
36
|
}
|
|
45
37
|
|
|
46
38
|
export { select, lazySelect } from './select.js'
|
package/src/multistream.ts
CHANGED
|
@@ -1,98 +1,46 @@
|
|
|
1
1
|
import { CodeError } from '@libp2p/interface/errors'
|
|
2
|
-
import {
|
|
3
|
-
import { abortableSource } from 'abortable-iterator'
|
|
4
|
-
import first from 'it-first'
|
|
5
|
-
import * as lp from 'it-length-prefixed'
|
|
6
|
-
import { pipe } from 'it-pipe'
|
|
7
|
-
import { Uint8ArrayList } from 'uint8arraylist'
|
|
2
|
+
import { type Uint8ArrayList } from 'uint8arraylist'
|
|
8
3
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
9
4
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
10
|
-
import { MAX_PROTOCOL_LENGTH } from './constants.js'
|
|
11
5
|
import type { MultistreamSelectInit } from '.'
|
|
12
|
-
import type { AbortOptions } from '@libp2p/interface'
|
|
13
|
-
import type {
|
|
14
|
-
import type {
|
|
15
|
-
import type { Source } from 'it-stream-types'
|
|
16
|
-
|
|
17
|
-
const log = logger('libp2p:mss')
|
|
6
|
+
import type { AbortOptions, LoggerOptions } from '@libp2p/interface'
|
|
7
|
+
import type { LengthPrefixedStream } from 'it-length-prefixed-stream'
|
|
8
|
+
import type { Duplex, Source } from 'it-stream-types'
|
|
18
9
|
|
|
19
10
|
const NewLine = uint8ArrayFromString('\n')
|
|
20
11
|
|
|
21
|
-
export function encode (buffer: Uint8Array | Uint8ArrayList): Uint8ArrayList {
|
|
22
|
-
const list = new Uint8ArrayList(buffer, NewLine)
|
|
23
|
-
|
|
24
|
-
return lp.encode.single(list)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
12
|
/**
|
|
28
13
|
* `write` encodes and writes a single buffer
|
|
29
14
|
*/
|
|
30
|
-
export function write (writer:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (options.writeBytes === true) {
|
|
34
|
-
writer.push(encoded.subarray())
|
|
35
|
-
} else {
|
|
36
|
-
writer.push(encoded)
|
|
37
|
-
}
|
|
15
|
+
export async function write (writer: LengthPrefixedStream<Duplex<AsyncGenerator<Uint8Array>, Source<Uint8Array>>>, buffer: Uint8Array | Uint8ArrayList, options?: MultistreamSelectInit): Promise<void> {
|
|
16
|
+
await writer.write(buffer, options)
|
|
38
17
|
}
|
|
39
18
|
|
|
40
19
|
/**
|
|
41
20
|
* `writeAll` behaves like `write`, except it encodes an array of items as a single write
|
|
42
21
|
*/
|
|
43
|
-
export function writeAll (writer:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
for (const buf of buffers) {
|
|
47
|
-
list.append(encode(buf))
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (options.writeBytes === true) {
|
|
51
|
-
writer.push(list.subarray())
|
|
52
|
-
} else {
|
|
53
|
-
writer.push(list)
|
|
54
|
-
}
|
|
22
|
+
export async function writeAll (writer: LengthPrefixedStream<Duplex<AsyncGenerator<Uint8Array>, Source<Uint8Array>>>, buffers: Uint8Array[], options?: MultistreamSelectInit): Promise<void> {
|
|
23
|
+
await writer.writeV(buffers, options)
|
|
55
24
|
}
|
|
56
25
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
let input: Source<Uint8ArrayList> = varByteSource
|
|
65
|
-
|
|
66
|
-
// If we have been passed an abort signal, wrap the input source in an abortable
|
|
67
|
-
// iterator that will throw if the operation is aborted
|
|
68
|
-
if (options?.signal != null) {
|
|
69
|
-
input = abortableSource(varByteSource, options.signal)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Once the length has been parsed, read chunk for that length
|
|
73
|
-
const onLength = (l: number): void => {
|
|
74
|
-
byteLength = l
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const buf = await pipe(
|
|
78
|
-
input,
|
|
79
|
-
(source) => lp.decode(source, { onLength, maxDataLength: MAX_PROTOCOL_LENGTH }),
|
|
80
|
-
async (source) => first(source)
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
if (buf == null || buf.length === 0) {
|
|
84
|
-
throw new CodeError('no buffer returned', 'ERR_INVALID_MULTISTREAM_SELECT_MESSAGE')
|
|
85
|
-
}
|
|
26
|
+
/**
|
|
27
|
+
* Read a length-prefixed buffer from the passed stream, stripping the final newline character
|
|
28
|
+
*/
|
|
29
|
+
export async function read (reader: LengthPrefixedStream<Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>, Source<Uint8Array>>>, options?: AbortOptions & LoggerOptions): Promise<Uint8ArrayList> {
|
|
30
|
+
const buf = await reader.read(options)
|
|
86
31
|
|
|
87
|
-
if (buf.get(buf.byteLength - 1) !== NewLine[0]) {
|
|
88
|
-
log.error('Invalid mss message - missing newline
|
|
32
|
+
if (buf.byteLength === 0 || buf.get(buf.byteLength - 1) !== NewLine[0]) {
|
|
33
|
+
options?.log.error('Invalid mss message - missing newline', buf)
|
|
89
34
|
throw new CodeError('missing newline', 'ERR_INVALID_MULTISTREAM_SELECT_MESSAGE')
|
|
90
35
|
}
|
|
91
36
|
|
|
92
37
|
return buf.sublist(0, -1) // Remove newline
|
|
93
38
|
}
|
|
94
39
|
|
|
95
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Read a length-prefixed string from the passed stream, stripping the final newline character
|
|
42
|
+
*/
|
|
43
|
+
export async function readString (reader: LengthPrefixedStream<Duplex<AsyncGenerator<Uint8Array | Uint8ArrayList>, Source<Uint8Array>>>, options?: AbortOptions & LoggerOptions): Promise<string> {
|
|
96
44
|
const buf = await read(reader, options)
|
|
97
45
|
|
|
98
46
|
return uint8ArrayToString(buf.subarray())
|