@libp2p/multistream-select 2.0.2 → 3.1.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 CHANGED
@@ -18,26 +18,14 @@
18
18
  - [Dialer](#dialer)
19
19
  - [Listener](#listener)
20
20
  - [API](#api)
21
- - [`new Dialer(duplex)`](#new-dialerduplex)
21
+ - [`mss.select(dulpex, protocols, [options])`](#mssselectdulpex-protocols-options)
22
22
  - [Parameters](#parameters)
23
23
  - [Returns](#returns)
24
24
  - [Examples](#examples)
25
- - [`dialer.select(protocols, [options])`](#dialerselectprotocols-options)
25
+ - [`mss.handle(duplex, protocols, [options])`](#msshandleduplex-protocols-options)
26
26
  - [Parameters](#parameters-1)
27
27
  - [Returns](#returns-1)
28
28
  - [Examples](#examples-1)
29
- - [`dialer.ls([options])`](#dialerlsoptions)
30
- - [Parameters](#parameters-2)
31
- - [Returns](#returns-2)
32
- - [Examples](#examples-2)
33
- - [`new Listener(duplex)`](#new-listenerduplex)
34
- - [Parameters](#parameters-3)
35
- - [Returns](#returns-3)
36
- - [Examples](#examples-3)
37
- - [`listener.handle(protocols, [options])`](#listenerhandleprotocols-options)
38
- - [Parameters](#parameters-4)
39
- - [Returns](#returns-4)
40
- - [Examples](#examples-4)
41
29
  - [License](#license)
42
30
  - [Contribution](#contribution)
43
31
 
@@ -69,33 +57,29 @@ The caller will send "interactive" messages, expecting for some acknowledgement
69
57
  > <dht-message>
70
58
  ```
71
59
 
72
- This mode also packs a `ls` option, so that the callee can list the protocols it currently supports
73
-
74
60
  ## Usage
75
61
 
76
62
  ```js
77
- import { Dialer, Listener } from '@libp2p/multistream-select'
63
+ import { select, handle } from '@libp2p/multistream-select'
78
64
  // You can now use
79
- // Dialer - actively select a protocol with a remote
80
- // Listener - handle a protocol with a remote
65
+ // select - actively select a protocol with a remote
66
+ // handle - handle a protocol with a remote
81
67
  ```
82
68
 
83
69
  ### Dialer
84
70
 
85
71
  ```js
86
72
  import { pipe } from 'it-pipe'
87
- import { Dialer } from '@libp2p/multistream-select'
73
+ import * as mss from '@libp2p/multistream-select'
88
74
  import { Mplex } from '@libp2p/mplex'
89
75
 
90
76
  const muxer = new Mplex()
91
77
  const muxedStream = muxer.newStream()
92
78
 
93
- const mss = new Dialer(muxedStream)
94
-
95
79
  // mss.select(protocol(s))
96
80
  // Select from one of the passed protocols (in priority order)
97
81
  // Returns selected stream and protocol
98
- const { stream: dhtStream, protocol } = await mss.select([
82
+ const { stream: dhtStream, protocol } = await mss.select(muxedStream, [
99
83
  // This might just be different versions of DHT, but could be different impls
100
84
  '/ipfs-dht/2.0.0', // Most of the time this will probably just be one item.
101
85
  '/ipfs-dht/1.0.0'
@@ -122,16 +106,14 @@ const { stream: dhtStream, protocol } = await mss.select([
122
106
 
123
107
  ```js
124
108
  import { pipe } from 'it-pipe'
125
- import { Listener } from '@libp2p/multistream-select'
109
+ import * as mss from '@libp2p/multistream-select'
126
110
  import { Mplex } from '@libp2p/mplex'
127
111
 
128
112
  const muxer = new Mplex({
129
113
  async onStream (muxedStream) {
130
- const mss = new Listener(muxedStream)
131
-
132
114
  // mss.handle(handledProtocols)
133
115
  // Returns selected stream and protocol
134
- const { stream, protocol } = await mss.handle([
116
+ const { stream, protocol } = await mss.handle(muxedStream, [
135
117
  '/ipfs-dht/1.0.0',
136
118
  '/ipfs-bitswap/1.0.0'
137
119
  ])
@@ -159,36 +141,19 @@ const muxer = new Mplex({
159
141
 
160
142
  ## API
161
143
 
162
- ### `new Dialer(duplex)`
163
-
164
- 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.
165
-
166
- #### Parameters
167
-
168
- - `duplex` (`Object`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to dial on.
169
-
170
- #### Returns
171
-
172
- A new multistream select dialer instance.
173
-
174
- #### Examples
175
-
176
- ```js
177
- const dialer = new MSS.Dialer(duplex)
178
- ```
179
-
180
- ### `dialer.select(protocols, [options])`
144
+ ### `mss.select(dulpex, protocols, [options])`
181
145
 
182
146
  Negotiate a protocol to use from a list of protocols.
183
147
 
184
148
  #### Parameters
185
149
 
186
- - `protocols` (`String[]`/`String`) - A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made.
187
- - `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal
150
+ - `duplex` (`Duplex`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to dial on.
151
+ - `protocols` (`string[]`/`string`) - A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made.
152
+ - `options` (`{ signal: AbortSignal, writeBytes?: boolean }`) - 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
188
153
 
189
154
  #### Returns
190
155
 
191
- `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`.
156
+ `Promise<{ stream<Duplex>, protocol<string> }>` - A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.
192
157
 
193
158
  Note that after a protocol is selected `dialer` can no longer be used.
194
159
 
@@ -203,68 +168,26 @@ const { stream, protocol } = await dialer.select([
203
168
  // Now talk `protocol` on `stream`
204
169
  ```
205
170
 
206
- ### `dialer.ls([options])`
207
-
208
- List protocols that the remote supports.
209
-
210
- #### Parameters
211
-
212
- - `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal
213
-
214
- #### Returns
215
-
216
- `String[]` - A list of all the protocols the remote supports.
217
-
218
- #### Examples
219
-
220
- ```js
221
- const protocols = await dialer.ls()
222
- const wantedProto = '/ipfs-dht/2.0.0'
223
-
224
- if (!protocols.includes(wantedProto)) {
225
- throw new Error('remote does not support ' + wantedProto)
226
- }
227
-
228
- // Now use dialer.select to use wantedProto, safe in the knowledge it is supported
229
- ```
230
-
231
- ### `new Listener(duplex)`
232
-
233
- Construct a new multistream select "listener" instance which can be used to handle multistream protocol selections for particular protocols.
234
-
235
- #### Parameters
236
-
237
- - `duplex` (`Object`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to listen on.
238
-
239
- #### Returns
240
-
241
- A new multistream select listener instance.
242
-
243
- #### Examples
244
-
245
- ```js
246
- const listener = new MSS.Listener(duplex)
247
- ```
248
-
249
- ### `listener.handle(protocols, [options])`
171
+ ### `mss.handle(duplex, protocols, [options])`
250
172
 
251
173
  Handle multistream protocol selections for the given list of protocols.
252
174
 
253
175
  #### Parameters
254
176
 
177
+ - `duplex` (`Duplex`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to listen on.
255
178
  - `protocols` (`String[]`/`String`) - A list of protocols (or single protocol) that this listener is able to speak.
256
- - `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal
179
+ - `options` (`{ signal: AbortSignal, writeBytes?: boolean }`) - 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
257
180
 
258
181
  #### Returns
259
182
 
260
- `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`.
183
+ `Promise<{ stream<Duplex>, protocol<string> }>` - A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.
261
184
 
262
185
  Note that after a protocol is handled `listener` can no longer be used.
263
186
 
264
187
  #### Examples
265
188
 
266
189
  ```js
267
- const { stream, protocol } = await listener.handle([
190
+ const { stream, protocol } = await mss.handle(duplex, [
268
191
  '/ipfs-dht/1.0.0',
269
192
  '/ipfs-bitswap/1.0.0'
270
193
  ])
@@ -1,7 +1,6 @@
1
- import type { AbortOptions } from '@libp2p/interfaces';
1
+ import { Uint8ArrayList } from 'uint8arraylist';
2
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
- }>;
3
+ import type { ByteArrayInit, ByteListInit, ProtocolStream } from './index.js';
4
+ export declare function handle(stream: Duplex<Uint8Array>, protocols: string | string[], options: ByteArrayInit): Promise<ProtocolStream<Uint8Array>>;
5
+ export declare function handle(stream: Duplex<Uint8ArrayList, Uint8ArrayList | Uint8Array>, protocols: string | string[], options?: ByteListInit): Promise<ProtocolStream<Uint8ArrayList, Uint8ArrayList | Uint8Array>>;
7
6
  //# sourceMappingURL=handle.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"handle.d.ts","sourceRoot":"","sources":["../../src/handle.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAyB,cAAc,EAAE,MAAM,YAAY,CAAA;AAIpG,wBAAsB,MAAM,CAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAA;AACpJ,wBAAsB,MAAM,CAAE,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,cAAc,GAAG,UAAU,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,cAAc,EAAE,cAAc,GAAG,UAAU,CAAC,CAAC,CAAA"}
@@ -13,22 +13,23 @@ export async function handle(stream, protocols, options) {
13
13
  log('read "%s"', protocol);
14
14
  if (protocol === PROTOCOL_ID) {
15
15
  log('respond with "%s" for "%s"', PROTOCOL_ID, protocol);
16
- multistream.write(writer, uint8ArrayFromString(PROTOCOL_ID));
16
+ multistream.write(writer, uint8ArrayFromString(PROTOCOL_ID), options);
17
17
  continue;
18
18
  }
19
19
  if (protocols.includes(protocol)) {
20
- multistream.write(writer, uint8ArrayFromString(protocol));
20
+ multistream.write(writer, uint8ArrayFromString(protocol), options);
21
21
  log('respond with "%s" for "%s"', protocol, protocol);
22
22
  rest();
23
23
  return { stream: shakeStream, protocol };
24
24
  }
25
25
  if (protocol === 'ls') {
26
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)))));
27
+ multistream.write(writer, new Uint8ArrayList(...protocols.map(p => multistream.encode(uint8ArrayFromString(p)))), options);
28
+ // multistream.writeAll(writer, protocols.map(p => uint8ArrayFromString(p)))
28
29
  log('respond with "%s" for %s', protocols, protocol);
29
30
  continue;
30
31
  }
31
- multistream.write(writer, uint8ArrayFromString('na'));
32
+ multistream.write(writer, uint8ArrayFromString('na'), options);
32
33
  log('respond with "na" for "%s"', protocol);
33
34
  }
34
35
  }
@@ -1 +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"}
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;AAIvC,MAAM,CAAC,KAAK,UAAU,MAAM,CAAE,MAAmB,EAAE,SAA4B,EAAE,OAA+B;IAC9G,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,EAAE,OAAO,CAAC,CAAA;YACrE,SAAQ;SACT;QAED,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;YAChC,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAA;YAClE,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,EAAE,OAAO,CAAC,CAAA;YAC1H,4EAA4E;YAC5E,GAAG,CAAC,0BAA0B,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAA;YACpD,SAAQ;SACT;QAED,WAAW,CAAC,KAAK,CAAC,MAAM,EAAE,oBAAoB,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;QAC9D,GAAG,CAAC,4BAA4B,EAAE,QAAQ,CAAC,CAAA;KAC5C;AACH,CAAC"}
@@ -2,25 +2,19 @@ import { PROTOCOL_ID } from './constants.js';
2
2
  import type { Duplex } from 'it-stream-types';
3
3
  import type { AbortOptions } from '@libp2p/interfaces';
4
4
  export { PROTOCOL_ID };
5
- export interface ProtocolStream {
6
- stream: Duplex<Uint8Array>;
5
+ export interface ProtocolStream<TSource, TSink = TSource> {
6
+ stream: Duplex<TSource, TSink>;
7
7
  protocol: string;
8
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>;
9
+ export interface ByteArrayInit extends AbortOptions {
10
+ writeBytes: true;
19
11
  }
20
- export declare class Dialer extends MultistreamSelect {
21
- select(protocols: string | string[], options?: AbortOptions): Promise<ProtocolStream>;
12
+ export interface ByteListInit extends AbortOptions {
13
+ writeBytes?: false;
22
14
  }
23
- export declare class Listener extends MultistreamSelect {
24
- handle(protocols: string | string[], options?: AbortOptions): Promise<ProtocolStream>;
15
+ export interface MultistreamSelectInit extends AbortOptions {
16
+ writeBytes?: boolean;
25
17
  }
18
+ export { select, lazySelect } from './select.js';
19
+ export { handle } from './handle.js';
26
20
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,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;CAG7F;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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,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,CAAC,OAAO,EAAE,KAAK,GAAG,OAAO;IACtD,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IAC9B,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,UAAU,EAAE,IAAI,CAAA;CACjB;AAED,MAAM,WAAW,YAAa,SAAQ,YAAY;IAChD,UAAU,CAAC,EAAE,KAAK,CAAA;CACnB;AAED,MAAM,WAAW,qBAAsB,SAAQ,YAAY;IACzD,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA"}
package/dist/src/index.js CHANGED
@@ -1,34 +1,5 @@
1
- import { select } from './select.js';
2
- import { handle } from './handle.js';
3
1
  import { PROTOCOL_ID } from './constants.js';
4
2
  export { PROTOCOL_ID };
5
- class MultistreamSelect {
6
- constructor(stream) {
7
- this.stream = stream;
8
- this.shaken = false;
9
- }
10
- /**
11
- * Perform the multistream-select handshake
12
- *
13
- * @param {AbortOptions} [options]
14
- */
15
- async _handshake(options) {
16
- if (this.shaken) {
17
- return;
18
- }
19
- const { stream } = await select(this.stream, PROTOCOL_ID, undefined, options);
20
- this.stream = stream;
21
- this.shaken = true;
22
- }
23
- }
24
- export class Dialer extends MultistreamSelect {
25
- async select(protocols, options) {
26
- return await select(this.stream, protocols, this.shaken ? undefined : PROTOCOL_ID, options);
27
- }
28
- }
29
- export class Listener extends MultistreamSelect {
30
- async handle(protocols, options) {
31
- return await handle(this.stream, protocols, options);
32
- }
33
- }
3
+ export { select, lazySelect } from './select.js';
4
+ export { handle } from './handle.js';
34
5
  //# sourceMappingURL=index.js.map
@@ -1 +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,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;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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAI5C,OAAO,EAAE,WAAW,EAAE,CAAA;AAmBtB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA"}
@@ -2,15 +2,16 @@ import { Uint8ArrayList } from 'uint8arraylist';
2
2
  import type { Pushable } from 'it-pushable';
3
3
  import type { AbortOptions } from '@libp2p/interfaces';
4
4
  import type { Reader } from 'it-reader';
5
- export declare function encode(buffer: Uint8Array | Uint8ArrayList): Uint8Array;
5
+ import type { MultistreamSelectInit } from '.';
6
+ export declare function encode(buffer: Uint8Array | Uint8ArrayList): Uint8ArrayList;
6
7
  /**
7
8
  * `write` encodes and writes a single buffer
8
9
  */
9
- export declare function write(writer: Pushable<Uint8Array>, buffer: Uint8Array | Uint8ArrayList): void;
10
+ export declare function write(writer: Pushable<any>, buffer: Uint8Array | Uint8ArrayList, options?: MultistreamSelectInit): void;
10
11
  /**
11
12
  * `writeAll` behaves like `write`, except it encodes an array of items as a single write
12
13
  */
13
- export declare function writeAll(writer: Pushable<Uint8Array>, buffers: Uint8Array[]): void;
14
- export declare function read(reader: Reader, options?: AbortOptions): Promise<Uint8Array>;
14
+ export declare function writeAll(writer: Pushable<any>, buffers: Uint8Array[], options?: MultistreamSelectInit): void;
15
+ export declare function read(reader: Reader, options?: AbortOptions): Promise<Uint8ArrayList>;
15
16
  export declare function readString(reader: Reader, options?: AbortOptions): Promise<string>;
16
17
  //# sourceMappingURL=multistream.d.ts.map
@@ -1 +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"}
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;AACvC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,GAAG,CAAA;AAI9C,wBAAgB,MAAM,CAAE,MAAM,EAAE,UAAU,GAAG,cAAc,GAAG,cAAc,CAI3E;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,UAAU,GAAG,cAAc,EAAE,OAAO,GAAE,qBAA0B,QAQrH;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAE,MAAM,EAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,OAAO,GAAE,qBAA0B,QAY1G;AAED,wBAAsB,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,CAmC3F;AAED,wBAAsB,UAAU,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,mBAIvE"}
@@ -9,23 +9,34 @@ import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
9
9
  const NewLine = uint8ArrayFromString('\n');
10
10
  export function encode(buffer) {
11
11
  const list = new Uint8ArrayList(buffer, NewLine);
12
- return lp.encode.single(list).subarray();
12
+ return lp.encode.single(list);
13
13
  }
14
14
  /**
15
15
  * `write` encodes and writes a single buffer
16
16
  */
17
- export function write(writer, buffer) {
18
- writer.push(encode(buffer).subarray());
17
+ export function write(writer, buffer, options = {}) {
18
+ const encoded = encode(buffer);
19
+ if (options.writeBytes === true) {
20
+ writer.push(encoded.subarray());
21
+ }
22
+ else {
23
+ writer.push(encoded);
24
+ }
19
25
  }
20
26
  /**
21
27
  * `writeAll` behaves like `write`, except it encodes an array of items as a single write
22
28
  */
23
- export function writeAll(writer, buffers) {
29
+ export function writeAll(writer, buffers, options = {}) {
24
30
  const list = new Uint8ArrayList();
25
31
  for (const buf of buffers) {
26
32
  list.append(encode(buf));
27
33
  }
28
- writer.push(list.slice());
34
+ if (options.writeBytes === true) {
35
+ writer.push(list.subarray());
36
+ }
37
+ else {
38
+ writer.push(list);
39
+ }
29
40
  }
30
41
  export async function read(reader, options) {
31
42
  let byteLength = 1; // Read single byte chunks until the length is known
@@ -40,7 +51,9 @@ export async function read(reader, options) {
40
51
  input = abortableSource(varByteSource, options.signal);
41
52
  }
42
53
  // Once the length has been parsed, read chunk for that length
43
- const onLength = (l) => { byteLength = l; };
54
+ const onLength = (l) => {
55
+ byteLength = l;
56
+ };
44
57
  const buf = await pipe(input, lp.decode({ onLength }), async (source) => await first(source));
45
58
  if (buf == null) {
46
59
  throw errCode(new Error('no buffer returned'), 'ERR_INVALID_MULTISTREAM_SELECT_MESSAGE');
@@ -48,10 +61,10 @@ export async function read(reader, options) {
48
61
  if (buf.get(buf.byteLength - 1) !== NewLine[0]) {
49
62
  throw errCode(new Error('missing newline'), 'ERR_INVALID_MULTISTREAM_SELECT_MESSAGE');
50
63
  }
51
- return buf.slice(0, -1); // Remove newline
64
+ return buf.sublist(0, -1); // Remove newline
52
65
  }
53
66
  export async function readString(reader, options) {
54
67
  const buf = await read(reader, options);
55
- return uint8ArrayToString(buf);
68
+ return uint8ArrayToString(buf.subarray());
56
69
  }
57
70
  //# sourceMappingURL=multistream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"multistream.js","sourceRoot":"","sources":["../../src/multistream.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"multistream.js","sourceRoot":"","sources":["../../src/multistream.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,16 @@
1
- import type { AbortOptions } from '@libp2p/interfaces';
2
1
  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
- }>;
2
+ import { Uint8ArrayList } from 'uint8arraylist';
3
+ import type { ByteArrayInit, ByteListInit, ProtocolStream } from './index.js';
4
+ export declare function select(stream: Duplex<Uint8Array>, protocols: string | string[], options: ByteArrayInit): Promise<ProtocolStream<Uint8Array>>;
5
+ export declare function select(stream: Duplex<Uint8ArrayList, Uint8ArrayList | Uint8Array>, protocols: string | string[], options?: ByteListInit): Promise<ProtocolStream<Uint8ArrayList, Uint8ArrayList | Uint8Array>>;
6
+ /**
7
+ * Lazily negotiates a protocol.
8
+ *
9
+ * It *does not* block writes waiting for the other end to respond. Instead, it
10
+ * simply assumes the negotiation went successfully and starts writing data.
11
+ *
12
+ * Use when it is known that the receiver supports the desired protocol.
13
+ */
14
+ export declare function lazySelect(stream: Duplex<Uint8Array>, protocol: string): ProtocolStream<Uint8Array>;
15
+ export declare function lazySelect(stream: Duplex<Uint8ArrayList, Uint8ArrayList | Uint8Array>, protocol: string): ProtocolStream<Uint8ArrayList, Uint8ArrayList | Uint8Array>;
7
16
  //# sourceMappingURL=select.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/select.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAI/C,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAyB,cAAc,EAAE,MAAM,YAAY,CAAA;AAIpG,wBAAsB,MAAM,CAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAAA;AACpJ,wBAAsB,MAAM,CAAE,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,cAAc,GAAG,UAAU,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,cAAc,CAAC,cAAc,EAAE,cAAc,GAAG,UAAU,CAAC,CAAC,CAAA;AAgDtN;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAE,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAA;AACrG,wBAAgB,UAAU,CAAE,MAAM,EAAE,MAAM,CAAC,cAAc,EAAE,cAAc,GAAG,UAAU,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAAC,cAAc,EAAE,cAAc,GAAG,UAAU,CAAC,CAAA"}
@@ -3,26 +3,27 @@ import errCode from 'err-code';
3
3
  import * as multistream from './multistream.js';
4
4
  import { handshake } from 'it-handshake';
5
5
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
6
+ import { PROTOCOL_ID } from './index.js';
7
+ import { Uint8ArrayList } from 'uint8arraylist';
8
+ import { pushable } from 'it-pushable';
9
+ import merge from 'it-merge';
10
+ import { reader } from 'it-reader';
6
11
  const log = logger('libp2p:mss:select');
7
- export async function select(stream, protocols, protocolId, options) {
12
+ export async function select(stream, protocols, options = {}) {
8
13
  protocols = Array.isArray(protocols) ? [...protocols] : [protocols];
9
14
  const { reader, writer, rest, stream: shakeStream } = handshake(stream);
10
15
  const protocol = protocols.shift();
11
16
  if (protocol == null) {
12
17
  throw new Error('At least one protocol must be specified');
13
18
  }
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
- }
19
+ log('select: write ["%s", "%s"]', PROTOCOL_ID, protocol);
20
+ const p1 = uint8ArrayFromString(PROTOCOL_ID);
21
+ const p2 = uint8ArrayFromString(protocol);
22
+ multistream.writeAll(writer, [p1, p2], options);
22
23
  let response = await multistream.readString(reader, options);
23
24
  log('select: read "%s"', response);
24
25
  // Read the protocol response if we got the protocolId in return
25
- if (response === protocolId) {
26
+ if (response === PROTOCOL_ID) {
26
27
  response = await multistream.readString(reader, options);
27
28
  log('select: read "%s"', response);
28
29
  }
@@ -34,7 +35,7 @@ export async function select(stream, protocols, protocolId, options) {
34
35
  // We haven't gotten a valid ack, try the other protocols
35
36
  for (const protocol of protocols) {
36
37
  log('select: write "%s"', protocol);
37
- multistream.write(writer, uint8ArrayFromString(protocol));
38
+ multistream.write(writer, uint8ArrayFromString(protocol), options);
38
39
  const response = await multistream.readString(reader, options);
39
40
  log('select: read "%s" for "%s"', response, protocol);
40
41
  if (response === protocol) {
@@ -45,4 +46,49 @@ export async function select(stream, protocols, protocolId, options) {
45
46
  rest();
46
47
  throw errCode(new Error('protocol selection failed'), 'ERR_UNSUPPORTED_PROTOCOL');
47
48
  }
49
+ export function lazySelect(stream, protocol) {
50
+ // This is a signal to write the multistream headers if the consumer tries to
51
+ // read from the source
52
+ const negotiateTrigger = pushable();
53
+ let negotiated = false;
54
+ return {
55
+ stream: {
56
+ sink: async (source) => await stream.sink((async function* () {
57
+ let first = true;
58
+ for await (const chunk of merge(source, negotiateTrigger)) {
59
+ if (first) {
60
+ first = false;
61
+ negotiated = true;
62
+ negotiateTrigger.end();
63
+ const p1 = uint8ArrayFromString(PROTOCOL_ID);
64
+ const p2 = uint8ArrayFromString(protocol);
65
+ const list = new Uint8ArrayList(multistream.encode(p1), multistream.encode(p2));
66
+ if (chunk.length > 0)
67
+ list.append(chunk);
68
+ yield* list;
69
+ }
70
+ else {
71
+ yield chunk;
72
+ }
73
+ }
74
+ })()),
75
+ source: (async function* () {
76
+ if (!negotiated)
77
+ negotiateTrigger.push(new Uint8Array());
78
+ const byteReader = reader(stream.source);
79
+ let response = await multistream.readString(byteReader);
80
+ if (response === PROTOCOL_ID) {
81
+ response = await multistream.readString(byteReader);
82
+ }
83
+ if (response !== protocol) {
84
+ throw errCode(new Error('protocol selection failed'), 'ERR_UNSUPPORTED_PROTOCOL');
85
+ }
86
+ for await (const chunk of byteReader) {
87
+ yield* chunk;
88
+ }
89
+ })()
90
+ },
91
+ protocol
92
+ };
93
+ }
48
94
  //# sourceMappingURL=select.js.map
@@ -1 +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"}
1
+ {"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/select.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@libp2p/multistream-select",
3
- "version": "2.0.2",
3
+ "version": "3.1.0",
4
4
  "description": "JavaScript implementation of multistream-select",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "homepage": "https://github.com/libp2p/js-libp2p-multistream-select#readme",
@@ -149,13 +149,14 @@
149
149
  "it-first": "^1.0.6",
150
150
  "it-handshake": "^4.0.1",
151
151
  "it-length-prefixed": "^8.0.2",
152
+ "it-merge": "^1.0.4",
152
153
  "it-pipe": "^2.0.3",
153
154
  "it-pushable": "^3.0.0",
154
155
  "it-reader": "^6.0.1",
155
156
  "it-stream-types": "^1.0.4",
156
157
  "p-defer": "^4.0.0",
157
- "uint8arraylist": "^2.0.0",
158
- "uint8arrays": "^3.0.0"
158
+ "uint8arraylist": "^2.3.1",
159
+ "uint8arrays": "^4.0.2"
159
160
  },
160
161
  "devDependencies": {
161
162
  "@types/varint": "^6.0.0",
package/src/handle.ts CHANGED
@@ -4,12 +4,14 @@ import { handshake } from 'it-handshake'
4
4
  import { PROTOCOL_ID } from './constants.js'
5
5
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
6
6
  import { Uint8ArrayList } from 'uint8arraylist'
7
- import type { AbortOptions } from '@libp2p/interfaces'
8
7
  import type { Duplex } from 'it-stream-types'
8
+ import type { ByteArrayInit, ByteListInit, MultistreamSelectInit, ProtocolStream } from './index.js'
9
9
 
10
10
  const log = logger('libp2p:mss:handle')
11
11
 
12
- export async function handle (stream: Duplex<Uint8Array>, protocols: string | string[], options?: AbortOptions) {
12
+ export async function handle (stream: Duplex<Uint8Array>, protocols: string | string[], options: ByteArrayInit): Promise<ProtocolStream<Uint8Array>>
13
+ export async function handle (stream: Duplex<Uint8ArrayList, Uint8ArrayList | Uint8Array>, protocols: string | string[], options?: ByteListInit): Promise<ProtocolStream<Uint8ArrayList, Uint8ArrayList | Uint8Array>>
14
+ export async function handle (stream: Duplex<any>, protocols: string | string[], options?: MultistreamSelectInit): Promise<ProtocolStream<any>> {
13
15
  protocols = Array.isArray(protocols) ? protocols : [protocols]
14
16
  const { writer, reader, rest, stream: shakeStream } = handshake(stream)
15
17
 
@@ -19,12 +21,12 @@ export async function handle (stream: Duplex<Uint8Array>, protocols: string | st
19
21
 
20
22
  if (protocol === PROTOCOL_ID) {
21
23
  log('respond with "%s" for "%s"', PROTOCOL_ID, protocol)
22
- multistream.write(writer, uint8ArrayFromString(PROTOCOL_ID))
24
+ multistream.write(writer, uint8ArrayFromString(PROTOCOL_ID), options)
23
25
  continue
24
26
  }
25
27
 
26
28
  if (protocols.includes(protocol)) {
27
- multistream.write(writer, uint8ArrayFromString(protocol))
29
+ multistream.write(writer, uint8ArrayFromString(protocol), options)
28
30
  log('respond with "%s" for "%s"', protocol, protocol)
29
31
  rest()
30
32
  return { stream: shakeStream, protocol }
@@ -32,12 +34,13 @@ export async function handle (stream: Duplex<Uint8Array>, protocols: string | st
32
34
 
33
35
  if (protocol === 'ls') {
34
36
  // <varint-msg-len><varint-proto-name-len><proto-name>\n<varint-proto-name-len><proto-name>\n\n
35
- multistream.write(writer, new Uint8ArrayList(...protocols.map(p => multistream.encode(uint8ArrayFromString(p)))))
37
+ multistream.write(writer, new Uint8ArrayList(...protocols.map(p => multistream.encode(uint8ArrayFromString(p)))), options)
38
+ // multistream.writeAll(writer, protocols.map(p => uint8ArrayFromString(p)))
36
39
  log('respond with "%s" for %s', protocols, protocol)
37
40
  continue
38
41
  }
39
42
 
40
- multistream.write(writer, uint8ArrayFromString('na'))
43
+ multistream.write(writer, uint8ArrayFromString('na'), options)
41
44
  log('respond with "na" for "%s"', protocol)
42
45
  }
43
46
  }
package/src/index.ts CHANGED
@@ -1,49 +1,25 @@
1
- import { select } from './select.js'
2
- import { handle } from './handle.js'
3
1
  import { PROTOCOL_ID } from './constants.js'
4
2
  import type { Duplex } from 'it-stream-types'
5
3
  import type { AbortOptions } from '@libp2p/interfaces'
6
4
 
7
5
  export { PROTOCOL_ID }
8
6
 
9
- export interface ProtocolStream {
10
- stream: Duplex<Uint8Array>
7
+ export interface ProtocolStream<TSource, TSink = TSource> {
8
+ stream: Duplex<TSource, TSink>
11
9
  protocol: string
12
10
  }
13
11
 
14
- class MultistreamSelect {
15
- protected stream: Duplex<Uint8Array>
16
- protected shaken: boolean
17
-
18
- constructor (stream: Duplex<Uint8Array>) {
19
- this.stream = stream
20
- this.shaken = false
21
- }
22
-
23
- /**
24
- * Perform the multistream-select handshake
25
- *
26
- * @param {AbortOptions} [options]
27
- */
28
- async _handshake (options?: AbortOptions): Promise<void> {
29
- if (this.shaken) {
30
- return
31
- }
32
-
33
- const { stream } = await select(this.stream, PROTOCOL_ID, undefined, options)
34
- this.stream = stream
35
- this.shaken = true
36
- }
12
+ export interface ByteArrayInit extends AbortOptions {
13
+ writeBytes: true
37
14
  }
38
15
 
39
- export class Dialer extends MultistreamSelect {
40
- async select (protocols: string | string[], options?: AbortOptions): Promise<ProtocolStream> {
41
- return await select(this.stream, protocols, this.shaken ? undefined : PROTOCOL_ID, options)
42
- }
16
+ export interface ByteListInit extends AbortOptions {
17
+ writeBytes?: false
43
18
  }
44
19
 
45
- export class Listener extends MultistreamSelect {
46
- async handle (protocols: string | string[], options?: AbortOptions): Promise<ProtocolStream> {
47
- return await handle(this.stream, protocols, options)
48
- }
20
+ export interface MultistreamSelectInit extends AbortOptions {
21
+ writeBytes?: boolean
49
22
  }
23
+
24
+ export { select, lazySelect } from './select.js'
25
+ export { handle } from './handle.js'
@@ -11,36 +11,47 @@ import type { Pushable } from 'it-pushable'
11
11
  import type { AbortOptions } from '@libp2p/interfaces'
12
12
  import type { Source } from 'it-stream-types'
13
13
  import type { Reader } from 'it-reader'
14
+ import type { MultistreamSelectInit } from '.'
14
15
 
15
16
  const NewLine = uint8ArrayFromString('\n')
16
17
 
17
- export function encode (buffer: Uint8Array | Uint8ArrayList): Uint8Array {
18
+ export function encode (buffer: Uint8Array | Uint8ArrayList): Uint8ArrayList {
18
19
  const list = new Uint8ArrayList(buffer, NewLine)
19
20
 
20
- return lp.encode.single(list).subarray()
21
+ return lp.encode.single(list)
21
22
  }
22
23
 
23
24
  /**
24
25
  * `write` encodes and writes a single buffer
25
26
  */
26
- export function write (writer: Pushable<Uint8Array>, buffer: Uint8Array | Uint8ArrayList) {
27
- writer.push(encode(buffer).subarray())
27
+ export function write (writer: Pushable<any>, buffer: Uint8Array | Uint8ArrayList, options: MultistreamSelectInit = {}) {
28
+ const encoded = encode(buffer)
29
+
30
+ if (options.writeBytes === true) {
31
+ writer.push(encoded.subarray())
32
+ } else {
33
+ writer.push(encoded)
34
+ }
28
35
  }
29
36
 
30
37
  /**
31
38
  * `writeAll` behaves like `write`, except it encodes an array of items as a single write
32
39
  */
33
- export function writeAll (writer: Pushable<Uint8Array>, buffers: Uint8Array[]) {
40
+ export function writeAll (writer: Pushable<any>, buffers: Uint8Array[], options: MultistreamSelectInit = {}) {
34
41
  const list = new Uint8ArrayList()
35
42
 
36
43
  for (const buf of buffers) {
37
44
  list.append(encode(buf))
38
45
  }
39
46
 
40
- writer.push(list.slice())
47
+ if (options.writeBytes === true) {
48
+ writer.push(list.subarray())
49
+ } else {
50
+ writer.push(list)
51
+ }
41
52
  }
42
53
 
43
- export async function read (reader: Reader, options?: AbortOptions) {
54
+ export async function read (reader: Reader, options?: AbortOptions): Promise<Uint8ArrayList> {
44
55
  let byteLength = 1 // Read single byte chunks until the length is known
45
56
  const varByteSource = { // No return impl - we want the reader to remain readable
46
57
  [Symbol.asyncIterator]: () => varByteSource,
@@ -56,7 +67,9 @@ export async function read (reader: Reader, options?: AbortOptions) {
56
67
  }
57
68
 
58
69
  // Once the length has been parsed, read chunk for that length
59
- const onLength = (l: number) => { byteLength = l }
70
+ const onLength = (l: number) => {
71
+ byteLength = l
72
+ }
60
73
 
61
74
  const buf = await pipe(
62
75
  input,
@@ -72,11 +85,11 @@ export async function read (reader: Reader, options?: AbortOptions) {
72
85
  throw errCode(new Error('missing newline'), 'ERR_INVALID_MULTISTREAM_SELECT_MESSAGE')
73
86
  }
74
87
 
75
- return buf.slice(0, -1) // Remove newline
88
+ return buf.sublist(0, -1) // Remove newline
76
89
  }
77
90
 
78
91
  export async function readString (reader: Reader, options?: AbortOptions) {
79
92
  const buf = await read(reader, options)
80
93
 
81
- return uint8ArrayToString(buf)
94
+ return uint8ArrayToString(buf.subarray())
82
95
  }
package/src/select.ts CHANGED
@@ -3,12 +3,19 @@ import errCode from 'err-code'
3
3
  import * as multistream from './multistream.js'
4
4
  import { handshake } from 'it-handshake'
5
5
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
6
- import type { AbortOptions } from '@libp2p/interfaces'
6
+ import { PROTOCOL_ID } from './index.js'
7
7
  import type { Duplex } from 'it-stream-types'
8
+ import { Uint8ArrayList } from 'uint8arraylist'
9
+ import { pushable } from 'it-pushable'
10
+ import merge from 'it-merge'
11
+ import { reader } from 'it-reader'
12
+ import type { ByteArrayInit, ByteListInit, MultistreamSelectInit, ProtocolStream } from './index.js'
8
13
 
9
14
  const log = logger('libp2p:mss:select')
10
15
 
11
- export async function select (stream: Duplex<Uint8Array>, protocols: string | string[], protocolId?: string, options?: AbortOptions) {
16
+ export async function select (stream: Duplex<Uint8Array>, protocols: string | string[], options: ByteArrayInit): Promise<ProtocolStream<Uint8Array>>
17
+ export async function select (stream: Duplex<Uint8ArrayList, Uint8ArrayList | Uint8Array>, protocols: string | string[], options?: ByteListInit): Promise<ProtocolStream<Uint8ArrayList, Uint8ArrayList | Uint8Array>>
18
+ export async function select (stream: Duplex<any>, protocols: string | string[], options: MultistreamSelectInit = {}): Promise<ProtocolStream<any>> {
12
19
  protocols = Array.isArray(protocols) ? [...protocols] : [protocols]
13
20
  const { reader, writer, rest, stream: shakeStream } = handshake(stream)
14
21
 
@@ -18,19 +25,16 @@ export async function select (stream: Duplex<Uint8Array>, protocols: string | st
18
25
  throw new Error('At least one protocol must be specified')
19
26
  }
20
27
 
21
- if (protocolId != null) {
22
- log('select: write ["%s", "%s"]', protocolId, protocol)
23
- multistream.writeAll(writer, [uint8ArrayFromString(protocolId), uint8ArrayFromString(protocol)])
24
- } else {
25
- log('select: write "%s"', protocol)
26
- multistream.write(writer, uint8ArrayFromString(protocol))
27
- }
28
+ log('select: write ["%s", "%s"]', PROTOCOL_ID, protocol)
29
+ const p1 = uint8ArrayFromString(PROTOCOL_ID)
30
+ const p2 = uint8ArrayFromString(protocol)
31
+ multistream.writeAll(writer, [p1, p2], options)
28
32
 
29
33
  let response = await multistream.readString(reader, options)
30
34
  log('select: read "%s"', response)
31
35
 
32
36
  // Read the protocol response if we got the protocolId in return
33
- if (response === protocolId) {
37
+ if (response === PROTOCOL_ID) {
34
38
  response = await multistream.readString(reader, options)
35
39
  log('select: read "%s"', response)
36
40
  }
@@ -44,7 +48,7 @@ export async function select (stream: Duplex<Uint8Array>, protocols: string | st
44
48
  // We haven't gotten a valid ack, try the other protocols
45
49
  for (const protocol of protocols) {
46
50
  log('select: write "%s"', protocol)
47
- multistream.write(writer, uint8ArrayFromString(protocol))
51
+ multistream.write(writer, uint8ArrayFromString(protocol), options)
48
52
  const response = await multistream.readString(reader, options)
49
53
  log('select: read "%s" for "%s"', response, protocol)
50
54
 
@@ -57,3 +61,56 @@ export async function select (stream: Duplex<Uint8Array>, protocols: string | st
57
61
  rest()
58
62
  throw errCode(new Error('protocol selection failed'), 'ERR_UNSUPPORTED_PROTOCOL')
59
63
  }
64
+
65
+ /**
66
+ * Lazily negotiates a protocol.
67
+ *
68
+ * It *does not* block writes waiting for the other end to respond. Instead, it
69
+ * simply assumes the negotiation went successfully and starts writing data.
70
+ *
71
+ * Use when it is known that the receiver supports the desired protocol.
72
+ */
73
+ export function lazySelect (stream: Duplex<Uint8Array>, protocol: string): ProtocolStream<Uint8Array>
74
+ export function lazySelect (stream: Duplex<Uint8ArrayList, Uint8ArrayList | Uint8Array>, protocol: string): ProtocolStream<Uint8ArrayList, Uint8ArrayList | Uint8Array>
75
+ export function lazySelect (stream: Duplex<any>, protocol: string): ProtocolStream<any> {
76
+ // This is a signal to write the multistream headers if the consumer tries to
77
+ // read from the source
78
+ const negotiateTrigger = pushable()
79
+ let negotiated = false
80
+ return {
81
+ stream: {
82
+ sink: async source => await stream.sink((async function * () {
83
+ let first = true
84
+ for await (const chunk of merge(source, negotiateTrigger)) {
85
+ if (first) {
86
+ first = false
87
+ negotiated = true
88
+ negotiateTrigger.end()
89
+ const p1 = uint8ArrayFromString(PROTOCOL_ID)
90
+ const p2 = uint8ArrayFromString(protocol)
91
+ const list = new Uint8ArrayList(multistream.encode(p1), multistream.encode(p2))
92
+ if (chunk.length > 0) list.append(chunk)
93
+ yield * list
94
+ } else {
95
+ yield chunk
96
+ }
97
+ }
98
+ })()),
99
+ source: (async function * () {
100
+ if (!negotiated) negotiateTrigger.push(new Uint8Array())
101
+ const byteReader = reader(stream.source)
102
+ let response = await multistream.readString(byteReader)
103
+ if (response === PROTOCOL_ID) {
104
+ response = await multistream.readString(byteReader)
105
+ }
106
+ if (response !== protocol) {
107
+ throw errCode(new Error('protocol selection failed'), 'ERR_UNSUPPORTED_PROTOCOL')
108
+ }
109
+ for await (const chunk of byteReader) {
110
+ yield * chunk
111
+ }
112
+ })()
113
+ },
114
+ protocol
115
+ }
116
+ }