@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/src/select.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
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
|
-
import type {
|
|
12
|
-
import type { Duplex
|
|
13
|
-
|
|
14
|
-
const log = logger('libp2p:mss:select')
|
|
9
|
+
import type { MultistreamSelectInit, ProtocolStream } from './index.js'
|
|
10
|
+
import type { Duplex } from 'it-stream-types'
|
|
15
11
|
|
|
16
12
|
/**
|
|
17
13
|
* Negotiate a protocol to use from a list of protocols.
|
|
@@ -56,52 +52,52 @@ const log = logger('libp2p:mss:select')
|
|
|
56
52
|
* // }
|
|
57
53
|
* ```
|
|
58
54
|
*/
|
|
59
|
-
export async function select (stream:
|
|
60
|
-
export async function select (stream: Duplex<AsyncGenerator<Uint8ArrayList | Uint8Array>, Source<Uint8ArrayList | Uint8Array>>, protocols: string | string[], options?: ByteListInit): Promise<ProtocolStream<Uint8ArrayList, Uint8ArrayList | Uint8Array>>
|
|
61
|
-
export async function select (stream: any, protocols: string | string[], options: MultistreamSelectInit = {}): Promise<ProtocolStream<any>> {
|
|
55
|
+
export async function select <Stream extends Duplex<any, any, any>> (stream: Stream, protocols: string | string[], options: MultistreamSelectInit): Promise<ProtocolStream<Stream>> {
|
|
62
56
|
protocols = Array.isArray(protocols) ? [...protocols] : [protocols]
|
|
63
|
-
const
|
|
64
|
-
|
|
57
|
+
const lp = lpStream(stream, {
|
|
58
|
+
...options,
|
|
59
|
+
maxDataLength: MAX_PROTOCOL_LENGTH
|
|
60
|
+
})
|
|
65
61
|
const protocol = protocols.shift()
|
|
66
62
|
|
|
67
63
|
if (protocol == null) {
|
|
68
64
|
throw new Error('At least one protocol must be specified')
|
|
69
65
|
}
|
|
70
66
|
|
|
71
|
-
log.trace('select: write ["%s", "%s"]', PROTOCOL_ID, protocol)
|
|
72
|
-
const p1 = uint8ArrayFromString(PROTOCOL_ID)
|
|
73
|
-
const p2 = uint8ArrayFromString(protocol)
|
|
74
|
-
multistream.writeAll(
|
|
67
|
+
options?.log.trace('select: write ["%s", "%s"]', PROTOCOL_ID, protocol)
|
|
68
|
+
const p1 = uint8ArrayFromString(`${PROTOCOL_ID}\n`)
|
|
69
|
+
const p2 = uint8ArrayFromString(`${protocol}\n`)
|
|
70
|
+
await multistream.writeAll(lp, [p1, p2], options)
|
|
75
71
|
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
options?.log.trace('select: reading multistream-select header')
|
|
73
|
+
let response = await multistream.readString(lp, options)
|
|
74
|
+
options?.log.trace('select: read "%s"', response)
|
|
78
75
|
|
|
79
76
|
// Read the protocol response if we got the protocolId in return
|
|
80
77
|
if (response === PROTOCOL_ID) {
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
options?.log.trace('select: reading protocol response')
|
|
79
|
+
response = await multistream.readString(lp, options)
|
|
80
|
+
options?.log.trace('select: read "%s"', response)
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
// We're done
|
|
86
84
|
if (response === protocol) {
|
|
87
|
-
|
|
88
|
-
return { stream: shakeStream, protocol }
|
|
85
|
+
return { stream: lp.unwrap(), protocol }
|
|
89
86
|
}
|
|
90
87
|
|
|
91
88
|
// We haven't gotten a valid ack, try the other protocols
|
|
92
89
|
for (const protocol of protocols) {
|
|
93
|
-
log.trace('select: write "%s"', protocol)
|
|
94
|
-
multistream.write(
|
|
95
|
-
|
|
96
|
-
|
|
90
|
+
options?.log.trace('select: write "%s"', protocol)
|
|
91
|
+
await multistream.write(lp, uint8ArrayFromString(`${protocol}\n`), options)
|
|
92
|
+
options?.log.trace('select: reading protocol response')
|
|
93
|
+
const response = await multistream.readString(lp, options)
|
|
94
|
+
options?.log.trace('select: read "%s" for "%s"', response, protocol)
|
|
97
95
|
|
|
98
96
|
if (response === protocol) {
|
|
99
|
-
|
|
100
|
-
return { stream: shakeStream, protocol }
|
|
97
|
+
return { stream: lp.unwrap(), protocol }
|
|
101
98
|
}
|
|
102
99
|
}
|
|
103
100
|
|
|
104
|
-
rest()
|
|
105
101
|
throw new CodeError('protocol selection failed', 'ERR_UNSUPPORTED_PROTOCOL')
|
|
106
102
|
}
|
|
107
103
|
|
|
@@ -113,49 +109,80 @@ export async function select (stream: any, protocols: string | string[], options
|
|
|
113
109
|
*
|
|
114
110
|
* Use when it is known that the receiver supports the desired protocol.
|
|
115
111
|
*/
|
|
116
|
-
export function lazySelect (stream:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
for await (const chunk of byteReader) {
|
|
155
|
-
yield * chunk
|
|
112
|
+
export function lazySelect <Stream extends Duplex<any, any, any>> (stream: Stream, protocol: string, options: MultistreamSelectInit): ProtocolStream<Stream> {
|
|
113
|
+
const originalSink = stream.sink.bind(stream)
|
|
114
|
+
const originalSource = stream.source
|
|
115
|
+
let selected = false
|
|
116
|
+
|
|
117
|
+
const lp = lpStream({
|
|
118
|
+
sink: originalSink,
|
|
119
|
+
source: originalSource
|
|
120
|
+
}, {
|
|
121
|
+
...options,
|
|
122
|
+
maxDataLength: MAX_PROTOCOL_LENGTH
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
stream.sink = async source => {
|
|
126
|
+
const { sink } = lp.unwrap()
|
|
127
|
+
|
|
128
|
+
await sink(async function * () {
|
|
129
|
+
for await (const buf of source) {
|
|
130
|
+
// if writing before selecting, send selection with first data chunk
|
|
131
|
+
if (!selected) {
|
|
132
|
+
selected = true
|
|
133
|
+
options?.log.trace('lazy: write ["%s", "%s", data] in sink', PROTOCOL_ID, protocol)
|
|
134
|
+
|
|
135
|
+
const protocolString = `${protocol}\n`
|
|
136
|
+
|
|
137
|
+
// send protocols in first chunk of data written to transport
|
|
138
|
+
yield new Uint8ArrayList(
|
|
139
|
+
Uint8Array.from([19]), // length of PROTOCOL_ID plus newline
|
|
140
|
+
uint8ArrayFromString(`${PROTOCOL_ID}\n`),
|
|
141
|
+
varint.encode(protocolString.length),
|
|
142
|
+
uint8ArrayFromString(protocolString),
|
|
143
|
+
buf
|
|
144
|
+
).subarray()
|
|
145
|
+
|
|
146
|
+
options?.log.trace('lazy: wrote ["%s", "%s", data] in sink', PROTOCOL_ID, protocol)
|
|
147
|
+
} else {
|
|
148
|
+
yield buf
|
|
156
149
|
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
150
|
+
}
|
|
151
|
+
}())
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
stream.source = (async function * () {
|
|
155
|
+
// if reading before selecting, send selection before first data chunk
|
|
156
|
+
if (!selected) {
|
|
157
|
+
selected = true
|
|
158
|
+
options?.log.trace('lazy: write ["%s", "%s", data] in source', PROTOCOL_ID, protocol)
|
|
159
|
+
await lp.writeV([
|
|
160
|
+
uint8ArrayFromString(`${PROTOCOL_ID}\n`),
|
|
161
|
+
uint8ArrayFromString(`${protocol}\n`)
|
|
162
|
+
])
|
|
163
|
+
options?.log.trace('lazy: wrote ["%s", "%s", data] in source', PROTOCOL_ID, protocol)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
options?.log.trace('lazy: reading multistream select header')
|
|
167
|
+
let response = await multistream.readString(lp, options)
|
|
168
|
+
options?.log.trace('lazy: read multistream select header "%s"', response)
|
|
169
|
+
|
|
170
|
+
if (response === PROTOCOL_ID) {
|
|
171
|
+
response = await multistream.readString(lp, options)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
options?.log.trace('lazy: read protocol "%s", expecting "%s"', response, protocol)
|
|
175
|
+
|
|
176
|
+
if (response !== protocol) {
|
|
177
|
+
throw new CodeError('protocol selection failed', 'ERR_UNSUPPORTED_PROTOCOL')
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
options?.log.trace('lazy: reading rest of "%s" stream', protocol)
|
|
181
|
+
yield * lp.unwrap().source
|
|
182
|
+
})()
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
stream,
|
|
159
186
|
protocol
|
|
160
187
|
}
|
|
161
188
|
}
|