@libp2p/multistream-select 0.0.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/README.md +290 -0
- package/dist/src/constants.d.ts +2 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +2 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/handle.d.ts +7 -0
- package/dist/src/handle.d.ts.map +1 -0
- package/dist/src/handle.js +35 -0
- package/dist/src/handle.js.map +1 -0
- package/dist/src/index.d.ts +27 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +42 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/ls.d.ts +7 -0
- package/dist/src/ls.d.ts.map +1 -0
- package/dist/src/ls.js +32 -0
- package/dist/src/ls.js.map +1 -0
- package/dist/src/multistream.d.ts +16 -0
- package/dist/src/multistream.d.ts.map +1 -0
- package/dist/src/multistream.js +57 -0
- package/dist/src/multistream.js.map +1 -0
- package/dist/src/select.d.ts +7 -0
- package/dist/src/select.d.ts.map +1 -0
- package/dist/src/select.js +48 -0
- package/dist/src/select.js.map +1 -0
- package/dist/test/dialer.spec.d.ts +2 -0
- package/dist/test/dialer.spec.d.ts.map +1 -0
- package/dist/test/dialer.spec.js +144 -0
- package/dist/test/dialer.spec.js.map +1 -0
- package/dist/test/integration.spec.d.ts +2 -0
- package/dist/test/integration.spec.d.ts.map +1 -0
- package/dist/test/integration.spec.js +55 -0
- package/dist/test/integration.spec.js.map +1 -0
- package/dist/test/listener.spec.d.ts +2 -0
- package/dist/test/listener.spec.d.ts.map +1 -0
- package/dist/test/listener.spec.js +123 -0
- package/dist/test/listener.spec.js.map +1 -0
- package/dist/test/multistream.spec.d.ts +2 -0
- package/dist/test/multistream.spec.d.ts.map +1 -0
- package/dist/test/multistream.spec.js +86 -0
- package/dist/test/multistream.spec.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +80 -0
- package/src/constants.ts +2 -0
- package/src/handle.ts +43 -0
- package/src/index.ts +58 -0
- package/src/ls.ts +45 -0
- package/src/multistream.ts +82 -0
- package/src/select.ts +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# js-multistream-select <!-- omit in toc -->
|
|
2
|
+
|
|
3
|
+
[](https://protocol.ai)
|
|
4
|
+
[](https://github.com/multiformats/multiformats)
|
|
5
|
+
[](https://webchat.freenode.net/?channels=%23ipfs)
|
|
6
|
+
[](https://codecov.io/gh/multiformats/js-multistream-select)
|
|
7
|
+
[](https://travis-ci.com/multiformats/js-multistream-select)
|
|
8
|
+
[](https://david-dm.org/multiformats/js-multistream-select)
|
|
9
|
+
[](https://github.com/feross/standard)
|
|
10
|
+
|
|
11
|
+
> JavaScript implementation of [multistream-select](https://github.com/multiformats/multistream-select)
|
|
12
|
+
|
|
13
|
+
## Lead Maintainer <!-- omit in toc -->
|
|
14
|
+
|
|
15
|
+
[Jacob Heun](https://github.com/jacobheun)
|
|
16
|
+
|
|
17
|
+
## Table of Contents <!-- omit in toc -->
|
|
18
|
+
|
|
19
|
+
- [Background](#background)
|
|
20
|
+
- [What is `multistream-select`?](#what-is-multistream-select)
|
|
21
|
+
- [Select a protocol flow](#select-a-protocol-flow)
|
|
22
|
+
- [Install](#install)
|
|
23
|
+
- [Usage](#usage)
|
|
24
|
+
- [Dialer](#dialer)
|
|
25
|
+
- [Listener](#listener)
|
|
26
|
+
- [API](#api)
|
|
27
|
+
- [`new MSS.Dialer(duplex)`](#new-mssdialerduplex)
|
|
28
|
+
- [Parameters](#parameters)
|
|
29
|
+
- [Returns](#returns)
|
|
30
|
+
- [Examples](#examples)
|
|
31
|
+
- [`dialer.select(protocols, [options])`](#dialerselectprotocols-options)
|
|
32
|
+
- [Parameters](#parameters-1)
|
|
33
|
+
- [Returns](#returns-1)
|
|
34
|
+
- [Examples](#examples-1)
|
|
35
|
+
- [`dialer.ls([options])`](#dialerlsoptions)
|
|
36
|
+
- [Parameters](#parameters-2)
|
|
37
|
+
- [Returns](#returns-2)
|
|
38
|
+
- [Examples](#examples-2)
|
|
39
|
+
- [`new MSS.Listener(duplex)`](#new-msslistenerduplex)
|
|
40
|
+
- [Parameters](#parameters-3)
|
|
41
|
+
- [Returns](#returns-3)
|
|
42
|
+
- [Examples](#examples-3)
|
|
43
|
+
- [`listener.handle(protocols, [options])`](#listenerhandleprotocols-options)
|
|
44
|
+
- [Parameters](#parameters-4)
|
|
45
|
+
- [Returns](#returns-4)
|
|
46
|
+
- [Examples](#examples-4)
|
|
47
|
+
- [Contribute](#contribute)
|
|
48
|
+
- [License](#license)
|
|
49
|
+
|
|
50
|
+
## Background
|
|
51
|
+
|
|
52
|
+
### What is `multistream-select`?
|
|
53
|
+
|
|
54
|
+
TLDR; multistream-select is protocol multiplexing per connection/stream. [Full spec here](https://github.com/multiformats/multistream-select)
|
|
55
|
+
|
|
56
|
+
#### Select a protocol flow
|
|
57
|
+
|
|
58
|
+
The caller will send "interactive" messages, expecting for some acknowledgement from the callee, which will "select" the handler for the desired and supported protocol:
|
|
59
|
+
|
|
60
|
+
```console
|
|
61
|
+
< /multistream-select/0.3.0 # i speak multistream-select/0.3.0
|
|
62
|
+
> /multistream-select/0.3.0 # ok, let's speak multistream-select/0.3.0
|
|
63
|
+
> /ipfs-dht/0.2.3 # i want to speak ipfs-dht/0.2.3
|
|
64
|
+
< na # ipfs-dht/0.2.3 is not available
|
|
65
|
+
> /ipfs-dht/0.1.9 # What about ipfs-dht/0.1.9 ?
|
|
66
|
+
< /ipfs-dht/0.1.9 # ok let's speak ipfs-dht/0.1.9 -- in a sense acts as an ACK
|
|
67
|
+
> <dht-message>
|
|
68
|
+
> <dht-message>
|
|
69
|
+
> <dht-message>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This mode also packs a `ls` option, so that the callee can list the protocols it currently supports
|
|
73
|
+
|
|
74
|
+
## Install
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
npm i multistream-select
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Usage
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
const MSS = require('multistream-select')
|
|
84
|
+
// You can now use
|
|
85
|
+
// MSS.Dialer - actively select a protocol with a remote
|
|
86
|
+
// MSS.Listener - handle a protocol with a remote
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Dialer
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
import { pipe } from 'it-pipe'
|
|
93
|
+
const MSS = require('multistream-select')
|
|
94
|
+
const Mplex = require('libp2p-mplex')
|
|
95
|
+
|
|
96
|
+
const muxer = new Mplex()
|
|
97
|
+
const muxedStream = muxer.newStream()
|
|
98
|
+
|
|
99
|
+
const mss = new MSS.Dialer(muxedStream)
|
|
100
|
+
|
|
101
|
+
// mss.select(protocol(s))
|
|
102
|
+
// Select from one of the passed protocols (in priority order)
|
|
103
|
+
// Returns selected stream and protocol
|
|
104
|
+
const { stream: dhtStream, protocol } = await mss.select([
|
|
105
|
+
// This might just be different versions of DHT, but could be different impls
|
|
106
|
+
'/ipfs-dht/2.0.0', // Most of the time this will probably just be one item.
|
|
107
|
+
'/ipfs-dht/1.0.0'
|
|
108
|
+
])
|
|
109
|
+
|
|
110
|
+
// Typically this stream will be passed back to the caller of libp2p.dialProtocol
|
|
111
|
+
//
|
|
112
|
+
// ...it might then do something like this:
|
|
113
|
+
// try {
|
|
114
|
+
// await pipe(
|
|
115
|
+
// [uint8ArrayFromString('Some DHT data')]
|
|
116
|
+
// dhtStream,
|
|
117
|
+
// async source => {
|
|
118
|
+
// for await (const chunk of source)
|
|
119
|
+
// // DHT response data
|
|
120
|
+
// }
|
|
121
|
+
// )
|
|
122
|
+
// } catch (err) {
|
|
123
|
+
// // Error in stream
|
|
124
|
+
// }
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Listener
|
|
128
|
+
|
|
129
|
+
```js
|
|
130
|
+
import { pipe } from 'it-pipe'
|
|
131
|
+
const MSS = require('multistream-select')
|
|
132
|
+
const Mplex = require('libp2p-mplex')
|
|
133
|
+
|
|
134
|
+
const muxer = new Mplex({
|
|
135
|
+
async onStream (muxedStream) {
|
|
136
|
+
const mss = new MSS.Listener(muxedStream)
|
|
137
|
+
|
|
138
|
+
// mss.handle(handledProtocols)
|
|
139
|
+
// Returns selected stream and protocol
|
|
140
|
+
const { stream, protocol } = await mss.handle([
|
|
141
|
+
'/ipfs-dht/1.0.0',
|
|
142
|
+
'/ipfs-bitswap/1.0.0'
|
|
143
|
+
])
|
|
144
|
+
|
|
145
|
+
// Typically here we'd call the handler function that was registered in
|
|
146
|
+
// libp2p for the given protocol:
|
|
147
|
+
// e.g. handlers[protocol].handler(stream)
|
|
148
|
+
//
|
|
149
|
+
// If protocol was /ipfs-dht/1.0.0 it might do something like this:
|
|
150
|
+
// try {
|
|
151
|
+
// await pipe(
|
|
152
|
+
// dhtStream,
|
|
153
|
+
// source => (async function * () {
|
|
154
|
+
// for await (const chunk of source)
|
|
155
|
+
// // Incoming DHT data -> process and yield to respond
|
|
156
|
+
// })(),
|
|
157
|
+
// dhtStream
|
|
158
|
+
// )
|
|
159
|
+
// } catch (err) {
|
|
160
|
+
// // Error in stream
|
|
161
|
+
// }
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## API
|
|
167
|
+
|
|
168
|
+
### `new MSS.Dialer(duplex)`
|
|
169
|
+
|
|
170
|
+
Create a new multistream select "dialer" instance which can be used to negotiate a protocol to use, list all available protocols the remote supports, or do both.
|
|
171
|
+
|
|
172
|
+
#### Parameters
|
|
173
|
+
|
|
174
|
+
* `duplex` (`Object`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to dial on.
|
|
175
|
+
|
|
176
|
+
#### Returns
|
|
177
|
+
|
|
178
|
+
A new multistream select dialer instance.
|
|
179
|
+
|
|
180
|
+
#### Examples
|
|
181
|
+
|
|
182
|
+
```js
|
|
183
|
+
const dialer = new MSS.Dialer(duplex)
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### `dialer.select(protocols, [options])`
|
|
187
|
+
|
|
188
|
+
Negotiate a protocol to use from a list of protocols.
|
|
189
|
+
|
|
190
|
+
#### Parameters
|
|
191
|
+
|
|
192
|
+
* `protocols` (`String[]`/`String`) - A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made.
|
|
193
|
+
* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal
|
|
194
|
+
|
|
195
|
+
#### Returns
|
|
196
|
+
|
|
197
|
+
`Promise<{ stream<Object>, protocol<String> }>` - A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.
|
|
198
|
+
|
|
199
|
+
Note that after a protocol is selected `dialer` can no longer be used.
|
|
200
|
+
|
|
201
|
+
#### Examples
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
const { stream, protocol } = await dialer.select([
|
|
205
|
+
// This might just be different versions of DHT, but could be different impls
|
|
206
|
+
'/ipfs-dht/2.0.0', // Most of the time this will probably just be one item.
|
|
207
|
+
'/ipfs-dht/1.0.0'
|
|
208
|
+
])
|
|
209
|
+
// Now talk `protocol` on `stream`
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### `dialer.ls([options])`
|
|
213
|
+
|
|
214
|
+
List protocols that the remote supports.
|
|
215
|
+
|
|
216
|
+
#### Parameters
|
|
217
|
+
|
|
218
|
+
* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal
|
|
219
|
+
|
|
220
|
+
#### Returns
|
|
221
|
+
|
|
222
|
+
`String[]` - A list of all the protocols the remote supports.
|
|
223
|
+
|
|
224
|
+
#### Examples
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
const protocols = await dialer.ls()
|
|
228
|
+
const wantedProto = '/ipfs-dht/2.0.0'
|
|
229
|
+
|
|
230
|
+
if (!protocols.includes(wantedProto)) {
|
|
231
|
+
throw new Error('remote does not support ' + wantedProto)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Now use dialer.select to use wantedProto, safe in the knowledge it is supported
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### `new MSS.Listener(duplex)`
|
|
238
|
+
|
|
239
|
+
Construct a new multistream select "listener" instance which can be used to handle multistream protocol selections for particular protocols.
|
|
240
|
+
|
|
241
|
+
#### Parameters
|
|
242
|
+
|
|
243
|
+
* `duplex` (`Object`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to listen on.
|
|
244
|
+
|
|
245
|
+
#### Returns
|
|
246
|
+
|
|
247
|
+
A new multistream select listener instance.
|
|
248
|
+
|
|
249
|
+
#### Examples
|
|
250
|
+
|
|
251
|
+
```js
|
|
252
|
+
const listener = new MSS.Listener(duplex)
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### `listener.handle(protocols, [options])`
|
|
256
|
+
|
|
257
|
+
Handle multistream protocol selections for the given list of protocols.
|
|
258
|
+
|
|
259
|
+
#### Parameters
|
|
260
|
+
|
|
261
|
+
* `protocols` (`String[]`/`String`) - A list of protocols (or single protocol) that this listener is able to speak.
|
|
262
|
+
* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal
|
|
263
|
+
|
|
264
|
+
#### Returns
|
|
265
|
+
|
|
266
|
+
`Promise<{ stream<Object>, protocol<String> }>` - A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.
|
|
267
|
+
|
|
268
|
+
Note that after a protocol is handled `listener` can no longer be used.
|
|
269
|
+
|
|
270
|
+
#### Examples
|
|
271
|
+
|
|
272
|
+
```js
|
|
273
|
+
const { stream, protocol } = await listener.handle([
|
|
274
|
+
'/ipfs-dht/1.0.0',
|
|
275
|
+
'/ipfs-bitswap/1.0.0'
|
|
276
|
+
])
|
|
277
|
+
// Remote wants to speak `protocol`
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
## Contribute
|
|
281
|
+
|
|
282
|
+
Contributions welcome. Please check out [the issues](https://github.com/multiformats/js-multistream-select/issues).
|
|
283
|
+
|
|
284
|
+
Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
|
|
285
|
+
|
|
286
|
+
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
|
|
287
|
+
|
|
288
|
+
## License
|
|
289
|
+
|
|
290
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,WAAW,uBAAuB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,WAAW,GAAG,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AbortOptions } from '@libp2p/interfaces';
|
|
2
|
+
import type { Duplex } from 'it-stream-types';
|
|
3
|
+
export declare function handle(stream: Duplex<Uint8Array>, protocols: string | string[], options?: AbortOptions): Promise<{
|
|
4
|
+
stream: Duplex<Uint8Array, Uint8Array, Promise<void>>;
|
|
5
|
+
protocol: string;
|
|
6
|
+
}>;
|
|
7
|
+
//# sourceMappingURL=handle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle.d.ts","sourceRoot":"","sources":["../../src/handle.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAI7C,wBAAsB,MAAM,CAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,YAAY;;;GA+B7G"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { logger } from '@libp2p/logger';
|
|
2
|
+
import * as multistream from './multistream.js';
|
|
3
|
+
import { handshake } from 'it-handshake';
|
|
4
|
+
import { PROTOCOL_ID } from './constants.js';
|
|
5
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
|
|
6
|
+
import { Uint8ArrayList } from 'uint8arraylist';
|
|
7
|
+
const log = logger('libp2p:mss:handle');
|
|
8
|
+
export async function handle(stream, protocols, options) {
|
|
9
|
+
protocols = Array.isArray(protocols) ? protocols : [protocols];
|
|
10
|
+
const { writer, reader, rest, stream: shakeStream } = handshake(stream);
|
|
11
|
+
while (true) {
|
|
12
|
+
const protocol = await multistream.readString(reader, options);
|
|
13
|
+
log('read "%s"', protocol);
|
|
14
|
+
if (protocol === PROTOCOL_ID) {
|
|
15
|
+
log('respond with "%s" for "%s"', PROTOCOL_ID, protocol);
|
|
16
|
+
multistream.write(writer, uint8ArrayFromString(PROTOCOL_ID));
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (protocols.includes(protocol)) {
|
|
20
|
+
multistream.write(writer, uint8ArrayFromString(protocol));
|
|
21
|
+
log('respond with "%s" for "%s"', protocol, protocol);
|
|
22
|
+
rest();
|
|
23
|
+
return { stream: shakeStream, protocol };
|
|
24
|
+
}
|
|
25
|
+
if (protocol === 'ls') {
|
|
26
|
+
// <varint-msg-len><varint-proto-name-len><proto-name>\n<varint-proto-name-len><proto-name>\n\n
|
|
27
|
+
multistream.write(writer, new Uint8ArrayList(...protocols.map(p => multistream.encode(uint8ArrayFromString(p)))));
|
|
28
|
+
log('respond with "%s" for %s', protocols, protocol);
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
multistream.write(writer, uint8ArrayFromString('na'));
|
|
32
|
+
log('respond with "na" for "%s"', protocol);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=handle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle.js","sourceRoot":"","sources":["../../src/handle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACvC,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAI/C,MAAM,GAAG,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAA;AAEvC,MAAM,CAAC,KAAK,UAAU,MAAM,CAAE,MAA0B,EAAE,SAA4B,EAAE,OAAsB;IAC5G,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IAC9D,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;IAEvE,OAAO,IAAI,EAAE;QACX,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC9D,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;QAE1B,IAAI,QAAQ,KAAK,WAAW,EAAE;YAC5B,GAAG,CAAC,4BAA4B,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAA;YACxD,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC,CAAA;YAC5D,SAAQ;SACT;QAED,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;YAChC,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAA;YACzD,GAAG,CAAC,4BAA4B,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;YACrD,IAAI,EAAE,CAAA;YACN,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAA;SACzC;QAED,IAAI,QAAQ,KAAK,IAAI,EAAE;YACrB,+FAA+F;YAC/F,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,cAAc,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACjH,GAAG,CAAC,0BAA0B,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;YACpD,SAAQ;SACT;QAED,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAA;QACrD,GAAG,CAAC,4BAA4B,EAAE,QAAQ,CAAC,CAAA;KAC5C;AACH,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { PROTOCOL_ID } from './constants.js';
|
|
2
|
+
import type { Duplex } from 'it-stream-types';
|
|
3
|
+
import type { AbortOptions } from '@libp2p/interfaces';
|
|
4
|
+
export { PROTOCOL_ID };
|
|
5
|
+
export interface ProtocolStream {
|
|
6
|
+
stream: Duplex<Uint8Array>;
|
|
7
|
+
protocol: string;
|
|
8
|
+
}
|
|
9
|
+
declare class MultistreamSelect {
|
|
10
|
+
protected stream: Duplex<Uint8Array>;
|
|
11
|
+
protected shaken: boolean;
|
|
12
|
+
constructor(stream: Duplex<Uint8Array>);
|
|
13
|
+
/**
|
|
14
|
+
* Perform the multistream-select handshake
|
|
15
|
+
*
|
|
16
|
+
* @param {AbortOptions} [options]
|
|
17
|
+
*/
|
|
18
|
+
_handshake(options?: AbortOptions): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
export declare class Dialer extends MultistreamSelect {
|
|
21
|
+
select(protocols: string | string[], options?: AbortOptions): Promise<ProtocolStream>;
|
|
22
|
+
ls(options?: AbortOptions): Promise<string[]>;
|
|
23
|
+
}
|
|
24
|
+
export declare class Listener extends MultistreamSelect {
|
|
25
|
+
handle(protocols: string | string[], options?: AbortOptions): Promise<ProtocolStream>;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,EAAE,WAAW,EAAE,CAAA;AAEtB,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;IAC1B,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,cAAM,iBAAiB;IACrB,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;IACpC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAA;gBAEZ,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC;IAKvC;;;;OAIG;IACG,UAAU,CAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CASzD;AAED,qBAAa,MAAO,SAAQ,iBAAiB;IACrC,MAAM,CAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC;IAItF,EAAE,CAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAOrD;AAED,qBAAa,QAAS,SAAQ,iBAAiB;IACvC,MAAM,CAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC;CAG7F"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { select } from './select.js';
|
|
2
|
+
import { handle } from './handle.js';
|
|
3
|
+
import { ls } from './ls.js';
|
|
4
|
+
import { PROTOCOL_ID } from './constants.js';
|
|
5
|
+
export { PROTOCOL_ID };
|
|
6
|
+
class MultistreamSelect {
|
|
7
|
+
constructor(stream) {
|
|
8
|
+
this.stream = stream;
|
|
9
|
+
this.shaken = false;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Perform the multistream-select handshake
|
|
13
|
+
*
|
|
14
|
+
* @param {AbortOptions} [options]
|
|
15
|
+
*/
|
|
16
|
+
async _handshake(options) {
|
|
17
|
+
if (this.shaken) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const { stream } = await select(this.stream, PROTOCOL_ID, undefined, options);
|
|
21
|
+
this.stream = stream;
|
|
22
|
+
this.shaken = true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export class Dialer extends MultistreamSelect {
|
|
26
|
+
async select(protocols, options) {
|
|
27
|
+
return await select(this.stream, protocols, this.shaken ? undefined : PROTOCOL_ID, options);
|
|
28
|
+
}
|
|
29
|
+
async ls(options) {
|
|
30
|
+
await this._handshake(options);
|
|
31
|
+
const res = await ls(this.stream, options);
|
|
32
|
+
const { stream, protocols } = res;
|
|
33
|
+
this.stream = stream;
|
|
34
|
+
return protocols;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export class Listener extends MultistreamSelect {
|
|
38
|
+
async handle(protocols, options) {
|
|
39
|
+
return await handle(this.stream, protocols, options);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACpC,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAA;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAI5C,OAAO,EAAE,WAAW,EAAE,CAAA;AAOtB,MAAM,iBAAiB;IAIrB,YAAa,MAA0B;QACrC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAA;IACrB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAU,CAAE,OAAsB;QACtC,IAAI,IAAI,CAAC,MAAM,EAAE;YACf,OAAM;SACP;QAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,CAAC,CAAA;QAC7E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;IACpB,CAAC;CACF;AAED,MAAM,OAAO,MAAO,SAAQ,iBAAiB;IAC3C,KAAK,CAAC,MAAM,CAAE,SAA4B,EAAE,OAAsB;QAChE,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IAC7F,CAAC;IAED,KAAK,CAAC,EAAE,CAAE,OAAsB;QAC9B,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA;QAC9B,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC1C,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,CAAA;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,OAAO,SAAS,CAAA;IAClB,CAAC;CACF;AAED,MAAM,OAAO,QAAS,SAAQ,iBAAiB;IAC7C,KAAK,CAAC,MAAM,CAAE,SAA4B,EAAE,OAAsB;QAChE,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAA;IACtD,CAAC;CACF"}
|
package/dist/src/ls.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Duplex } from 'it-stream-types';
|
|
2
|
+
import type { AbortOptions } from '@libp2p/interfaces';
|
|
3
|
+
export declare function ls(stream: Duplex<Uint8Array>, options?: AbortOptions): Promise<{
|
|
4
|
+
stream: Duplex<Uint8Array>;
|
|
5
|
+
protocols: string[];
|
|
6
|
+
}>;
|
|
7
|
+
//# sourceMappingURL=ls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../src/ls.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAItD,wBAAsB,EAAE,CAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA+B1I"}
|
package/dist/src/ls.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { reader as createReader } from 'it-reader';
|
|
2
|
+
import { logger } from '@libp2p/logger';
|
|
3
|
+
import * as multistream from './multistream.js';
|
|
4
|
+
import { handshake } from 'it-handshake';
|
|
5
|
+
import * as lp from 'it-length-prefixed';
|
|
6
|
+
import { pipe } from 'it-pipe';
|
|
7
|
+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
|
|
8
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
|
|
9
|
+
const log = logger('libp2p:mss:ls');
|
|
10
|
+
export async function ls(stream, options) {
|
|
11
|
+
const { reader, writer, rest, stream: shakeStream } = handshake(stream);
|
|
12
|
+
log('write "ls"');
|
|
13
|
+
multistream.write(writer, uint8ArrayFromString('ls'));
|
|
14
|
+
rest();
|
|
15
|
+
// Next message from remote will be (e.g. for 2 protocols):
|
|
16
|
+
// <varint-msg-len><varint-proto-name-len><proto-name>\n<varint-proto-name-len><proto-name>\n
|
|
17
|
+
const res = await multistream.read(reader, options);
|
|
18
|
+
// After reading response we have:
|
|
19
|
+
// <varint-proto-name-len><proto-name>\n<varint-proto-name-len><proto-name>\n
|
|
20
|
+
const protocolsReader = createReader([res]);
|
|
21
|
+
const protocols = [];
|
|
22
|
+
// Decode each of the protocols from the reader
|
|
23
|
+
await pipe(protocolsReader, lp.decode(), async (source) => {
|
|
24
|
+
for await (const protocol of source) {
|
|
25
|
+
// Remove the newline
|
|
26
|
+
protocols.push(uint8ArrayToString(protocol.slice(0, -1)));
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
const output = { stream: shakeStream, protocols };
|
|
30
|
+
return output;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=ls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ls.js","sourceRoot":"","sources":["../../src/ls.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACvC,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,KAAK,EAAE,MAAM,oBAAoB,CAAA;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAC9B,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AACtE,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAI5E,MAAM,GAAG,GAAG,MAAM,CAAC,eAAe,CAAC,CAAA;AAEnC,MAAM,CAAC,KAAK,UAAU,EAAE,CAAE,MAA0B,EAAE,OAAsB;IAC1E,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;IAEvE,GAAG,CAAC,YAAY,CAAC,CAAA;IACjB,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAA;IACrD,IAAI,EAAE,CAAA;IAEN,2DAA2D;IAC3D,6FAA6F;IAC7F,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAEnD,kCAAkC;IAClC,6EAA6E;IAC7E,MAAM,eAAe,GAAG,YAAY,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAC3C,MAAM,SAAS,GAAa,EAAE,CAAA;IAE9B,+CAA+C;IAC/C,MAAM,IAAI,CACR,eAAe,EACf,EAAE,CAAC,MAAM,EAAE,EACX,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,KAAK,EAAE,MAAM,QAAQ,IAAI,MAAM,EAAE;YACnC,qBAAqB;YACrB,SAAS,CAAC,IAAI,CAAC,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;SAC1D;IACH,CAAC,CACF,CAAA;IAED,MAAM,MAAM,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,CAAA;IAEjD,OAAO,MAAM,CAAA;AACf,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Uint8ArrayList } from 'uint8arraylist';
|
|
2
|
+
import type { Pushable } from 'it-pushable';
|
|
3
|
+
import type { AbortOptions } from '@libp2p/interfaces';
|
|
4
|
+
import type { Reader } from 'it-reader';
|
|
5
|
+
export declare function encode(buffer: Uint8Array | Uint8ArrayList): Uint8Array;
|
|
6
|
+
/**
|
|
7
|
+
* `write` encodes and writes a single buffer
|
|
8
|
+
*/
|
|
9
|
+
export declare function write(writer: Pushable<Uint8Array>, buffer: Uint8Array | Uint8ArrayList): void;
|
|
10
|
+
/**
|
|
11
|
+
* `writeAll` behaves like `write`, except it encodes an array of items as a single write
|
|
12
|
+
*/
|
|
13
|
+
export declare function writeAll(writer: Pushable<Uint8Array>, buffers: Uint8Array[]): void;
|
|
14
|
+
export declare function read(reader: Reader, options?: AbortOptions): Promise<Uint8Array>;
|
|
15
|
+
export declare function readString(reader: Reader, options?: AbortOptions): Promise<string>;
|
|
16
|
+
//# sourceMappingURL=multistream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multistream.d.ts","sourceRoot":"","sources":["../../src/multistream.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAQ/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AAIvC,wBAAgB,MAAM,CAAE,MAAM,EAAE,UAAU,GAAG,cAAc,GAAG,UAAU,CAIvE;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAE,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,GAAG,cAAc,QAEvF;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAE,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAQ5E;AAED,wBAAsB,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,uBAiCjE;AAED,wBAAsB,UAAU,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,mBAIvE"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Uint8ArrayList } from 'uint8arraylist';
|
|
2
|
+
import * as lp from 'it-length-prefixed';
|
|
3
|
+
import { pipe } from 'it-pipe';
|
|
4
|
+
import errCode from 'err-code';
|
|
5
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
|
|
6
|
+
import first from 'it-first';
|
|
7
|
+
import { abortableSource } from 'abortable-iterator';
|
|
8
|
+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
|
|
9
|
+
const NewLine = uint8ArrayFromString('\n');
|
|
10
|
+
export function encode(buffer) {
|
|
11
|
+
const list = new Uint8ArrayList(buffer, NewLine);
|
|
12
|
+
return lp.encode.single(list).slice();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* `write` encodes and writes a single buffer
|
|
16
|
+
*/
|
|
17
|
+
export function write(writer, buffer) {
|
|
18
|
+
writer.push(encode(buffer).slice());
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* `writeAll` behaves like `write`, except it encodes an array of items as a single write
|
|
22
|
+
*/
|
|
23
|
+
export function writeAll(writer, buffers) {
|
|
24
|
+
const list = new Uint8ArrayList();
|
|
25
|
+
for (const buf of buffers) {
|
|
26
|
+
list.append(encode(buf));
|
|
27
|
+
}
|
|
28
|
+
writer.push(list.slice());
|
|
29
|
+
}
|
|
30
|
+
export async function read(reader, options) {
|
|
31
|
+
let byteLength = 1; // Read single byte chunks until the length is known
|
|
32
|
+
const varByteSource = {
|
|
33
|
+
[Symbol.asyncIterator]: () => varByteSource,
|
|
34
|
+
next: async () => await reader.next(byteLength)
|
|
35
|
+
};
|
|
36
|
+
let input = varByteSource;
|
|
37
|
+
// If we have been passed an abort signal, wrap the input source in an abortable
|
|
38
|
+
// iterator that will throw if the operation is aborted
|
|
39
|
+
if (options?.signal != null) {
|
|
40
|
+
input = abortableSource(varByteSource, options.signal);
|
|
41
|
+
}
|
|
42
|
+
// Once the length has been parsed, read chunk for that length
|
|
43
|
+
const onLength = (l) => { byteLength = l; };
|
|
44
|
+
const buf = await pipe(input, lp.decode({ onLength }), async (source) => await first(source));
|
|
45
|
+
if (buf == null) {
|
|
46
|
+
throw errCode(new Error('no buffer returned'), 'ERR_INVALID_MULTISTREAM_SELECT_MESSAGE');
|
|
47
|
+
}
|
|
48
|
+
if (buf[buf.length - 1] !== NewLine[0]) {
|
|
49
|
+
throw errCode(new Error('missing newline'), 'ERR_INVALID_MULTISTREAM_SELECT_MESSAGE');
|
|
50
|
+
}
|
|
51
|
+
return buf.slice(0, -1); // Remove newline
|
|
52
|
+
}
|
|
53
|
+
export async function readString(reader, options) {
|
|
54
|
+
const buf = await read(reader, options);
|
|
55
|
+
return uint8ArrayToString(buf);
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=multistream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multistream.js","sourceRoot":"","sources":["../../src/multistream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AbortOptions } from '@libp2p/interfaces';
|
|
2
|
+
import type { Duplex } from 'it-stream-types';
|
|
3
|
+
export declare function select(stream: Duplex<Uint8Array>, protocols: string | string[], protocolId?: string, options?: AbortOptions): Promise<{
|
|
4
|
+
stream: Duplex<Uint8Array, Uint8Array, Promise<void>>;
|
|
5
|
+
protocol: string;
|
|
6
|
+
}>;
|
|
7
|
+
//# sourceMappingURL=select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/select.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAI7C,wBAAsB,MAAM,CAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY;;;GAgDlI"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { logger } from '@libp2p/logger';
|
|
2
|
+
import errCode from 'err-code';
|
|
3
|
+
import * as multistream from './multistream.js';
|
|
4
|
+
import { handshake } from 'it-handshake';
|
|
5
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
|
|
6
|
+
const log = logger('libp2p:mss:select');
|
|
7
|
+
export async function select(stream, protocols, protocolId, options) {
|
|
8
|
+
protocols = Array.isArray(protocols) ? [...protocols] : [protocols];
|
|
9
|
+
const { reader, writer, rest, stream: shakeStream } = handshake(stream);
|
|
10
|
+
const protocol = protocols.shift();
|
|
11
|
+
if (protocol == null) {
|
|
12
|
+
throw new Error('At least one protocol must be specified');
|
|
13
|
+
}
|
|
14
|
+
if (protocolId != null) {
|
|
15
|
+
log('select: write ["%s", "%s"]', protocolId, protocol);
|
|
16
|
+
multistream.writeAll(writer, [uint8ArrayFromString(protocolId), uint8ArrayFromString(protocol)]);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
log('select: write "%s"', protocol);
|
|
20
|
+
multistream.write(writer, uint8ArrayFromString(protocol));
|
|
21
|
+
}
|
|
22
|
+
let response = await multistream.readString(reader, options);
|
|
23
|
+
log('select: read "%s"', response);
|
|
24
|
+
// Read the protocol response if we got the protocolId in return
|
|
25
|
+
if (response === protocolId) {
|
|
26
|
+
response = await multistream.readString(reader, options);
|
|
27
|
+
log('select: read "%s"', response);
|
|
28
|
+
}
|
|
29
|
+
// We're done
|
|
30
|
+
if (response === protocol) {
|
|
31
|
+
rest();
|
|
32
|
+
return { stream: shakeStream, protocol };
|
|
33
|
+
}
|
|
34
|
+
// We haven't gotten a valid ack, try the other protocols
|
|
35
|
+
for (const protocol of protocols) {
|
|
36
|
+
log('select: write "%s"', protocol);
|
|
37
|
+
multistream.write(writer, uint8ArrayFromString(protocol));
|
|
38
|
+
const response = await multistream.readString(reader, options);
|
|
39
|
+
log('select: read "%s" for "%s"', response, protocol);
|
|
40
|
+
if (response === protocol) {
|
|
41
|
+
rest(); // End our writer so others can start writing to stream
|
|
42
|
+
return { stream: shakeStream, protocol };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
rest();
|
|
46
|
+
throw errCode(new Error('protocol selection failed'), 'ERR_UNSUPPORTED_PROTOCOL');
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/select.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AACvC,OAAO,OAAO,MAAM,UAAU,CAAA;AAC9B,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AACxC,OAAO,EAAE,UAAU,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAA;AAI5E,MAAM,GAAG,GAAG,MAAM,CAAC,mBAAmB,CAAC,CAAA;AAEvC,MAAM,CAAC,KAAK,UAAU,MAAM,CAAE,MAA0B,EAAE,SAA4B,EAAE,UAAmB,EAAE,OAAsB;IACjI,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;IACnE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAA;IAEvE,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,CAAA;IAElC,IAAI,QAAQ,IAAI,IAAI,EAAE;QACpB,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAA;KAC3D;IAED,IAAI,UAAU,IAAI,IAAI,EAAE;QACtB,GAAG,CAAC,4BAA4B,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAA;QACvD,WAAW,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,oBAAoB,CAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAA;KACjG;SAAM;QACL,GAAG,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAA;QACnC,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAA;KAC1D;IAED,IAAI,QAAQ,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC5D,GAAG,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAA;IAElC,gEAAgE;IAChE,IAAI,QAAQ,KAAK,UAAU,EAAE;QAC3B,QAAQ,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QACxD,GAAG,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAA;KACnC;IAED,aAAa;IACb,IAAI,QAAQ,KAAK,QAAQ,EAAE;QACzB,IAAI,EAAE,CAAA;QACN,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAA;KACzC;IAED,yDAAyD;IACzD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE;QAChC,GAAG,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAA;QACnC,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAA;QACzD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC9D,GAAG,CAAC,4BAA4B,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAErD,IAAI,QAAQ,KAAK,QAAQ,EAAE;YACzB,IAAI,EAAE,CAAA,CAAC,uDAAuD;YAC9D,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAA;SACzC;KACF;IAED,IAAI,EAAE,CAAA;IACN,MAAM,OAAO,CAAC,IAAI,KAAK,CAAC,2BAA2B,CAAC,EAAE,0BAA0B,CAAC,CAAA;AACnF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialer.spec.d.ts","sourceRoot":"","sources":["../../test/dialer.spec.ts"],"names":[],"mappings":""}
|