@libp2p/yamux 7.0.4-a02cb0461
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 +127 -0
- package/dist/index.min.js +4 -0
- package/dist/index.min.js.map +7 -0
- package/dist/src/config.d.ts +30 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +41 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/constants.d.ts +12 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +22 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/decode.d.ts +34 -0
- package/dist/src/decode.d.ts.map +1 -0
- package/dist/src/decode.js +76 -0
- package/dist/src/decode.js.map +1 -0
- package/dist/src/encode.d.ts +3 -0
- package/dist/src/encode.d.ts.map +1 -0
- package/dist/src/encode.js +19 -0
- package/dist/src/encode.js.map +1 -0
- package/dist/src/errors.d.ts +40 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +70 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/frame.d.ts +54 -0
- package/dist/src/frame.d.ts.map +1 -0
- package/dist/src/frame.js +36 -0
- package/dist/src/frame.js.map +1 -0
- package/dist/src/index.d.ts +85 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +84 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/muxer.d.ts +91 -0
- package/dist/src/muxer.d.ts.map +1 -0
- package/dist/src/muxer.js +428 -0
- package/dist/src/muxer.js.map +1 -0
- package/dist/src/stream.d.ts +96 -0
- package/dist/src/stream.d.ts.map +1 -0
- package/dist/src/stream.js +253 -0
- package/dist/src/stream.js.map +1 -0
- package/package.json +95 -0
- package/src/config.ts +72 -0
- package/src/constants.ts +25 -0
- package/src/decode.ts +105 -0
- package/src/encode.ts +26 -0
- package/src/errors.ts +89 -0
- package/src/frame.ts +64 -0
- package/src/index.ts +90 -0
- package/src/muxer.ts +507 -0
- package/src/stream.ts +313 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { AbstractStream } from '@libp2p/utils';
|
|
2
|
+
import { Uint8ArrayList } from 'uint8arraylist';
|
|
3
|
+
import { INITIAL_STREAM_WINDOW, MAX_STREAM_WINDOW } from './constants.js';
|
|
4
|
+
import { isDataFrame } from "./decode.js";
|
|
5
|
+
import { InvalidFrameError, ReceiveWindowExceededError } from './errors.js';
|
|
6
|
+
import { Flag, FrameType, HEADER_LENGTH } from './frame.js';
|
|
7
|
+
export var StreamState;
|
|
8
|
+
(function (StreamState) {
|
|
9
|
+
StreamState[StreamState["Init"] = 0] = "Init";
|
|
10
|
+
StreamState[StreamState["SYNSent"] = 1] = "SYNSent";
|
|
11
|
+
StreamState[StreamState["SYNReceived"] = 2] = "SYNReceived";
|
|
12
|
+
StreamState[StreamState["Established"] = 3] = "Established";
|
|
13
|
+
StreamState[StreamState["Finished"] = 4] = "Finished";
|
|
14
|
+
StreamState[StreamState["Paused"] = 5] = "Paused";
|
|
15
|
+
})(StreamState || (StreamState = {}));
|
|
16
|
+
/** YamuxStream is used to represent a logical stream within a session */
|
|
17
|
+
export class YamuxStream extends AbstractStream {
|
|
18
|
+
streamId;
|
|
19
|
+
state;
|
|
20
|
+
/** The number of available bytes to send */
|
|
21
|
+
sendWindowCapacity;
|
|
22
|
+
/** The number of bytes available to receive in a full window */
|
|
23
|
+
recvWindow;
|
|
24
|
+
/** The number of available bytes to receive */
|
|
25
|
+
recvWindowCapacity;
|
|
26
|
+
maxStreamWindowSize;
|
|
27
|
+
/**
|
|
28
|
+
* An 'epoch' is the time it takes to process and read data
|
|
29
|
+
*
|
|
30
|
+
* Used in conjunction with RTT to determine whether to increase the recvWindow
|
|
31
|
+
*/
|
|
32
|
+
epochStart;
|
|
33
|
+
getRTT;
|
|
34
|
+
sendFrame;
|
|
35
|
+
constructor(init) {
|
|
36
|
+
const initialWindowSize = init.initialStreamWindowSize ?? INITIAL_STREAM_WINDOW;
|
|
37
|
+
super({
|
|
38
|
+
...init,
|
|
39
|
+
maxMessageSize: initialWindowSize - HEADER_LENGTH
|
|
40
|
+
});
|
|
41
|
+
this.streamId = init.streamId;
|
|
42
|
+
this.state = init.state;
|
|
43
|
+
this.sendWindowCapacity = initialWindowSize;
|
|
44
|
+
this.recvWindow = initialWindowSize;
|
|
45
|
+
this.recvWindowCapacity = this.recvWindow;
|
|
46
|
+
this.maxStreamWindowSize = init.maxStreamWindowSize ?? MAX_STREAM_WINDOW;
|
|
47
|
+
this.epochStart = Date.now();
|
|
48
|
+
this.getRTT = init.getRTT;
|
|
49
|
+
this.sendFrame = init.sendFrame;
|
|
50
|
+
const setStateToFinishedOnCloseListener = () => {
|
|
51
|
+
this.state = StreamState.Finished;
|
|
52
|
+
};
|
|
53
|
+
this.addEventListener('close', setStateToFinishedOnCloseListener);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Send a data message to the remote muxer
|
|
57
|
+
*/
|
|
58
|
+
sendData(buf) {
|
|
59
|
+
const totalBytes = buf.byteLength;
|
|
60
|
+
let sentBytes = 0;
|
|
61
|
+
let canSendMore = true;
|
|
62
|
+
this.log?.trace('send window capacity is %d bytes', this.sendWindowCapacity);
|
|
63
|
+
// send in chunks, waiting for window updates
|
|
64
|
+
while (buf.byteLength > 0) {
|
|
65
|
+
// we exhausted the send window, sending will resume later
|
|
66
|
+
if (this.sendWindowCapacity === 0) {
|
|
67
|
+
canSendMore = false;
|
|
68
|
+
this.log?.trace('sent %d/%d bytes, exhausted send window, waiting for window update', sentBytes, totalBytes);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
// send as much as we can
|
|
72
|
+
const toSend = Math.min(this.sendWindowCapacity, buf.byteLength);
|
|
73
|
+
const flags = this.getSendFlags();
|
|
74
|
+
const data = buf.sublist(0, toSend);
|
|
75
|
+
buf.consume(toSend);
|
|
76
|
+
const muxerSendMore = this.sendFrame({
|
|
77
|
+
type: FrameType.Data,
|
|
78
|
+
flag: flags,
|
|
79
|
+
streamID: this.streamId,
|
|
80
|
+
length: toSend
|
|
81
|
+
}, data);
|
|
82
|
+
this.sendWindowCapacity -= toSend;
|
|
83
|
+
sentBytes += toSend;
|
|
84
|
+
if (!muxerSendMore) {
|
|
85
|
+
canSendMore = muxerSendMore;
|
|
86
|
+
this.log.trace('sent %d/%d bytes, wait for muxer to have more send capacity', sentBytes, totalBytes);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
sentBytes,
|
|
92
|
+
canSendMore
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Send a reset message to the remote muxer
|
|
97
|
+
*/
|
|
98
|
+
async sendReset() {
|
|
99
|
+
this.sendFrame({
|
|
100
|
+
type: FrameType.WindowUpdate,
|
|
101
|
+
flag: Flag.RST,
|
|
102
|
+
streamID: this.streamId,
|
|
103
|
+
length: 0
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Send a message to the remote muxer, informing them no more data messages
|
|
108
|
+
* will be sent by this end of the stream
|
|
109
|
+
*/
|
|
110
|
+
async sendCloseWrite() {
|
|
111
|
+
const flags = this.getSendFlags() | Flag.FIN;
|
|
112
|
+
this.sendFrame({
|
|
113
|
+
type: FrameType.WindowUpdate,
|
|
114
|
+
flag: flags,
|
|
115
|
+
streamID: this.streamId,
|
|
116
|
+
length: 0
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Send a message to the remote muxer, informing them no more data messages
|
|
121
|
+
* will be read by this end of the stream - this is a no-op on Yamux streams
|
|
122
|
+
*/
|
|
123
|
+
async sendCloseRead(options) {
|
|
124
|
+
options?.signal?.throwIfAborted();
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Stop sending window updates temporarily - in the interim the the remote
|
|
128
|
+
* send window will exhaust and the remote will stop sending data
|
|
129
|
+
*/
|
|
130
|
+
sendPause() {
|
|
131
|
+
this.state = StreamState.Paused;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Start sending window updates as normal
|
|
135
|
+
*/
|
|
136
|
+
sendResume() {
|
|
137
|
+
this.state = StreamState.Established;
|
|
138
|
+
this.sendWindowUpdate();
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* handleWindowUpdate is called when the stream receives a window update frame
|
|
142
|
+
*/
|
|
143
|
+
handleWindowUpdate(frame) {
|
|
144
|
+
this.processFlags(frame.header.flag);
|
|
145
|
+
// increase send window
|
|
146
|
+
this.sendWindowCapacity += frame.header.length;
|
|
147
|
+
// change the chunk size the superclass uses
|
|
148
|
+
this.maxMessageSize = this.sendWindowCapacity - HEADER_LENGTH;
|
|
149
|
+
if (this.maxMessageSize < 0) {
|
|
150
|
+
this.maxMessageSize = 0;
|
|
151
|
+
}
|
|
152
|
+
if (this.maxMessageSize === 0) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
// if writing is paused and the update increases our send window, notify
|
|
156
|
+
// writers that writing can resume
|
|
157
|
+
if (this.writeBuffer.byteLength > 0) {
|
|
158
|
+
this.log?.trace('window update of %d bytes allows more data to be sent, have %d bytes queued, sending data %s', frame.header.length, this.writeBuffer.byteLength, this.sendingData);
|
|
159
|
+
this.safeDispatchEvent('drain');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* handleData is called when the stream receives a data frame
|
|
164
|
+
*/
|
|
165
|
+
handleData(frame) {
|
|
166
|
+
if (!isDataFrame(frame)) {
|
|
167
|
+
throw new InvalidFrameError('Frame was not data frame');
|
|
168
|
+
}
|
|
169
|
+
this.processFlags(frame.header.flag);
|
|
170
|
+
// check that our recv window is not exceeded
|
|
171
|
+
if (this.recvWindowCapacity < frame.header.length) {
|
|
172
|
+
throw new ReceiveWindowExceededError('Receive window exceeded');
|
|
173
|
+
}
|
|
174
|
+
this.recvWindowCapacity -= frame.header.length;
|
|
175
|
+
this.onData(frame.data);
|
|
176
|
+
this.sendWindowUpdate();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* processFlags is used to update the state of the stream based on set flags, if any.
|
|
180
|
+
*/
|
|
181
|
+
processFlags(flags) {
|
|
182
|
+
if ((flags & Flag.ACK) === Flag.ACK) {
|
|
183
|
+
if (this.state === StreamState.SYNSent) {
|
|
184
|
+
this.state = StreamState.Established;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if ((flags & Flag.FIN) === Flag.FIN) {
|
|
188
|
+
this.onRemoteCloseWrite();
|
|
189
|
+
}
|
|
190
|
+
if ((flags & Flag.RST) === Flag.RST) {
|
|
191
|
+
this.onRemoteReset();
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* getSendFlags determines any flags that are appropriate
|
|
196
|
+
* based on the current stream state.
|
|
197
|
+
*
|
|
198
|
+
* The state is updated as a side-effect.
|
|
199
|
+
*/
|
|
200
|
+
getSendFlags() {
|
|
201
|
+
switch (this.state) {
|
|
202
|
+
case StreamState.Init:
|
|
203
|
+
this.state = StreamState.SYNSent;
|
|
204
|
+
return Flag.SYN;
|
|
205
|
+
case StreamState.SYNReceived:
|
|
206
|
+
this.state = StreamState.Established;
|
|
207
|
+
return Flag.ACK;
|
|
208
|
+
default:
|
|
209
|
+
return 0;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Potentially sends a window update enabling further remote writes to take
|
|
214
|
+
* place.
|
|
215
|
+
*/
|
|
216
|
+
sendWindowUpdate() {
|
|
217
|
+
if (this.state === StreamState.Paused) {
|
|
218
|
+
// we don't want any more data from the remote right now - update the
|
|
219
|
+
// epoch start as otherwise when we unpause we'd be looking at the epoch
|
|
220
|
+
// start from before we were paused
|
|
221
|
+
this.epochStart = Date.now();
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
// determine the flags if any
|
|
225
|
+
const flags = this.getSendFlags();
|
|
226
|
+
// If the stream has already been established
|
|
227
|
+
// and we've processed data within the time it takes for 4 round trips
|
|
228
|
+
// then we (up to) double the recvWindow
|
|
229
|
+
const now = Date.now();
|
|
230
|
+
const rtt = this.getRTT();
|
|
231
|
+
if (flags === 0 && rtt > -1 && (now - this.epochStart) <= (rtt * 4)) {
|
|
232
|
+
// we've already validated that maxStreamWindowSize can't be more than MAX_UINT32
|
|
233
|
+
this.recvWindow = Math.min(this.recvWindow * 2, this.maxStreamWindowSize);
|
|
234
|
+
}
|
|
235
|
+
if (this.recvWindowCapacity >= this.recvWindow && flags === 0) {
|
|
236
|
+
// a window update isn't needed
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
// update the receive window
|
|
240
|
+
const delta = this.recvWindow - this.recvWindowCapacity;
|
|
241
|
+
this.recvWindowCapacity = this.recvWindow;
|
|
242
|
+
// update the epoch start
|
|
243
|
+
this.epochStart = now;
|
|
244
|
+
// send window update
|
|
245
|
+
this.sendFrame({
|
|
246
|
+
type: FrameType.WindowUpdate,
|
|
247
|
+
flag: flags,
|
|
248
|
+
streamID: this.streamId,
|
|
249
|
+
length: delta
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/stream.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@libp2p/yamux",
|
|
3
|
+
"version": "7.0.4-a02cb0461",
|
|
4
|
+
"description": "Yamux stream multiplexer for libp2p",
|
|
5
|
+
"license": "Apache-2.0 OR MIT",
|
|
6
|
+
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/stream-multiplexer-yamux#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/libp2p/js-libp2p.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/libp2p/js-libp2p/issues"
|
|
13
|
+
},
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public",
|
|
16
|
+
"provenance": true
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"IPFS",
|
|
20
|
+
"libp2p",
|
|
21
|
+
"multiplexer",
|
|
22
|
+
"muxer",
|
|
23
|
+
"stream"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"types": "./dist/src/index.d.ts",
|
|
27
|
+
"typesVersions": {
|
|
28
|
+
"*": {
|
|
29
|
+
"*": [
|
|
30
|
+
"*",
|
|
31
|
+
"dist/*",
|
|
32
|
+
"dist/src/*",
|
|
33
|
+
"dist/src/*/index"
|
|
34
|
+
],
|
|
35
|
+
"src/*": [
|
|
36
|
+
"*",
|
|
37
|
+
"dist/*",
|
|
38
|
+
"dist/src/*",
|
|
39
|
+
"dist/src/*/index"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"src",
|
|
45
|
+
"dist",
|
|
46
|
+
"!dist/test",
|
|
47
|
+
"!**/*.tsbuildinfo"
|
|
48
|
+
],
|
|
49
|
+
"exports": {
|
|
50
|
+
".": {
|
|
51
|
+
"types": "./dist/src/index.d.ts",
|
|
52
|
+
"import": "./dist/src/index.js"
|
|
53
|
+
},
|
|
54
|
+
"./config": {
|
|
55
|
+
"types": "./dist/src/config.d.ts",
|
|
56
|
+
"import": "./dist/src/config.js"
|
|
57
|
+
},
|
|
58
|
+
"./stream": {
|
|
59
|
+
"types": "./dist/src/stream.d.ts",
|
|
60
|
+
"import": "./dist/src/stream.js"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"clean": "aegir clean",
|
|
65
|
+
"lint": "aegir lint",
|
|
66
|
+
"dep-check": "aegir dep-check",
|
|
67
|
+
"doc-check": "aegir doc-check",
|
|
68
|
+
"benchmark": "benchmark dist/test/bench/*.bench.js --timeout 400000",
|
|
69
|
+
"build": "aegir build",
|
|
70
|
+
"test": "aegir test",
|
|
71
|
+
"test:chrome": "aegir test -t browser",
|
|
72
|
+
"test:chrome-webworker": "aegir test -t webworker",
|
|
73
|
+
"test:firefox": "aegir test -t browser -- --browser firefox",
|
|
74
|
+
"test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
|
|
75
|
+
"test:node": "aegir test -t node --cov",
|
|
76
|
+
"test:electron-main": "aegir test -t electron-main",
|
|
77
|
+
"docs": "aegir docs"
|
|
78
|
+
},
|
|
79
|
+
"dependencies": {
|
|
80
|
+
"@libp2p/interface": "2.11.0-a02cb0461",
|
|
81
|
+
"@libp2p/utils": "6.7.2-a02cb0461",
|
|
82
|
+
"race-signal": "^2.0.0",
|
|
83
|
+
"uint8arraylist": "^2.4.8"
|
|
84
|
+
},
|
|
85
|
+
"devDependencies": {
|
|
86
|
+
"@dapplion/benchmark": "^1.0.0",
|
|
87
|
+
"@libp2p/interface-compliance-tests": "6.5.0-a02cb0461",
|
|
88
|
+
"@libp2p/mplex": "11.0.47-a02cb0461",
|
|
89
|
+
"aegir": "^47.0.21",
|
|
90
|
+
"it-all": "^3.0.9",
|
|
91
|
+
"it-drain": "^3.0.10",
|
|
92
|
+
"it-pushable": "^3.2.3",
|
|
93
|
+
"p-event": "^6.0.1"
|
|
94
|
+
}
|
|
95
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { InvalidParametersError } from '@libp2p/interface'
|
|
2
|
+
import { INITIAL_STREAM_WINDOW, MAX_STREAM_WINDOW } from './constants.js'
|
|
3
|
+
import type { StreamMuxerOptions, StreamOptions } from '@libp2p/interface'
|
|
4
|
+
|
|
5
|
+
export interface YamuxStreamOptions extends StreamOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Used to control the initial window size that we allow for a stream.
|
|
8
|
+
*
|
|
9
|
+
* measured in bytes
|
|
10
|
+
*/
|
|
11
|
+
initialStreamWindowSize?: number
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Used to control the maximum window size that we allow for a stream.
|
|
15
|
+
*/
|
|
16
|
+
maxStreamWindowSize?: number
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// TODO use config items or delete them
|
|
20
|
+
export interface Config extends StreamMuxerOptions<YamuxStreamOptions> {
|
|
21
|
+
/**
|
|
22
|
+
* Used to do periodic keep alive messages using a ping
|
|
23
|
+
*/
|
|
24
|
+
enableKeepAlive?: boolean
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* How often to perform the keep alive
|
|
28
|
+
*
|
|
29
|
+
* measured in milliseconds
|
|
30
|
+
*/
|
|
31
|
+
keepAliveInterval?: number
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const defaultConfig: Required<Config> & { streamOptions: Required<YamuxStreamOptions> } = {
|
|
35
|
+
enableKeepAlive: true,
|
|
36
|
+
keepAliveInterval: 30_000,
|
|
37
|
+
maxInboundStreams: 1_000,
|
|
38
|
+
maxOutboundStreams: 1_000,
|
|
39
|
+
maxMessageSize: 64 * 1024,
|
|
40
|
+
maxEarlyStreams: 10,
|
|
41
|
+
streamOptions: {
|
|
42
|
+
initialStreamWindowSize: INITIAL_STREAM_WINDOW,
|
|
43
|
+
maxStreamWindowSize: MAX_STREAM_WINDOW,
|
|
44
|
+
inactivityTimeout: 120_000,
|
|
45
|
+
maxReadBufferLength: 4_194_304,
|
|
46
|
+
maxWriteBufferLength: Infinity
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function verifyConfig (config: Config): void {
|
|
51
|
+
if (config.keepAliveInterval != null && config.keepAliveInterval <= 0) {
|
|
52
|
+
throw new InvalidParametersError('keep-alive interval must be positive')
|
|
53
|
+
}
|
|
54
|
+
if (config.maxInboundStreams != null && config.maxInboundStreams < 0) {
|
|
55
|
+
throw new InvalidParametersError('max inbound streams must be larger or equal 0')
|
|
56
|
+
}
|
|
57
|
+
if (config.maxOutboundStreams != null && config.maxOutboundStreams < 0) {
|
|
58
|
+
throw new InvalidParametersError('max outbound streams must be larger or equal 0')
|
|
59
|
+
}
|
|
60
|
+
if (config.maxMessageSize != null && config.maxMessageSize < 1024) {
|
|
61
|
+
throw new InvalidParametersError('MaxMessageSize must be greater than a kilobyte')
|
|
62
|
+
}
|
|
63
|
+
if (config.streamOptions?.initialStreamWindowSize != null && config.streamOptions?.initialStreamWindowSize < INITIAL_STREAM_WINDOW) {
|
|
64
|
+
throw new InvalidParametersError('InitialStreamWindowSize must be larger or equal 256 kB')
|
|
65
|
+
}
|
|
66
|
+
if (config.streamOptions?.maxStreamWindowSize != null && config.streamOptions?.initialStreamWindowSize != null && config.streamOptions?.maxStreamWindowSize < config.streamOptions?.initialStreamWindowSize) {
|
|
67
|
+
throw new InvalidParametersError('MaxStreamWindowSize must be larger than the InitialStreamWindowSize')
|
|
68
|
+
}
|
|
69
|
+
if (config.streamOptions?.maxStreamWindowSize != null && config.streamOptions?.maxStreamWindowSize > 2 ** 32 - 1) {
|
|
70
|
+
throw new InvalidParametersError('MaxStreamWindowSize must be less than equal MAX_UINT32')
|
|
71
|
+
}
|
|
72
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Protocol violation errors
|
|
2
|
+
|
|
3
|
+
import { BothClientsError, DecodeInvalidVersionError, InvalidFrameError, NotMatchingPingError, ReceiveWindowExceededError, StreamAlreadyExistsError, UnRequestedPingError } from './errors.js'
|
|
4
|
+
|
|
5
|
+
export const PROTOCOL_ERRORS = new Set([
|
|
6
|
+
InvalidFrameError.name,
|
|
7
|
+
UnRequestedPingError.name,
|
|
8
|
+
NotMatchingPingError.name,
|
|
9
|
+
StreamAlreadyExistsError.name,
|
|
10
|
+
DecodeInvalidVersionError.name,
|
|
11
|
+
BothClientsError.name,
|
|
12
|
+
ReceiveWindowExceededError.name
|
|
13
|
+
])
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* INITIAL_STREAM_WINDOW is the initial stream window size.
|
|
17
|
+
*
|
|
18
|
+
* Not an implementation choice, this is defined in the specification
|
|
19
|
+
*/
|
|
20
|
+
export const INITIAL_STREAM_WINDOW = 256 * 1024
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Default max stream window
|
|
24
|
+
*/
|
|
25
|
+
export const MAX_STREAM_WINDOW = 16 * 1024 * 1024
|
package/src/decode.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Uint8ArrayList } from 'uint8arraylist'
|
|
2
|
+
import { InvalidFrameError } from './errors.js'
|
|
3
|
+
import { FrameType, HEADER_LENGTH, YAMUX_VERSION } from './frame.js'
|
|
4
|
+
import type { FrameHeader } from './frame.js'
|
|
5
|
+
|
|
6
|
+
export interface Frame {
|
|
7
|
+
header: FrameHeader
|
|
8
|
+
data?: Uint8ArrayList
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface DataFrame {
|
|
12
|
+
header: FrameHeader
|
|
13
|
+
data: Uint8ArrayList
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isDataFrame (frame: Frame): frame is DataFrame {
|
|
17
|
+
return frame.header.type === FrameType.Data && frame.data !== null
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// used to bit shift in decoding
|
|
21
|
+
// native bit shift can overflow into a negative number, so we bit shift by
|
|
22
|
+
// multiplying by a power of 2
|
|
23
|
+
const twoPow24 = 2 ** 24
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Decode a header from the front of a buffer
|
|
27
|
+
*
|
|
28
|
+
* @param data - Assumed to have enough bytes for a header
|
|
29
|
+
*/
|
|
30
|
+
export function decodeHeader (data: Uint8Array): FrameHeader {
|
|
31
|
+
if (data[0] !== YAMUX_VERSION) {
|
|
32
|
+
throw new InvalidFrameError('Invalid frame version')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
type: data[1],
|
|
37
|
+
flag: (data[2] << 8) + data[3],
|
|
38
|
+
streamID: (data[4] * twoPow24) + (data[5] << 16) + (data[6] << 8) + data[7],
|
|
39
|
+
length: (data[8] * twoPow24) + (data[9] << 16) + (data[10] << 8) + data[11]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Decodes yamux frames from a source
|
|
45
|
+
*/
|
|
46
|
+
export class Decoder {
|
|
47
|
+
/** Buffer for in-progress frames */
|
|
48
|
+
private readonly buffer: Uint8ArrayList
|
|
49
|
+
|
|
50
|
+
constructor () {
|
|
51
|
+
this.buffer = new Uint8ArrayList()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Emits frames from the decoder source.
|
|
56
|
+
*
|
|
57
|
+
* Note: If `readData` is emitted, it _must_ be called before the next iteration
|
|
58
|
+
* Otherwise an error is thrown
|
|
59
|
+
*/
|
|
60
|
+
* emitFrames (buf: Uint8Array | Uint8ArrayList): Generator<Frame> {
|
|
61
|
+
this.buffer.append(buf)
|
|
62
|
+
|
|
63
|
+
// Loop to consume as many bytes from the buffer as possible
|
|
64
|
+
// Eg: when a single chunk contains several frames
|
|
65
|
+
while (true) {
|
|
66
|
+
const frame = this.readFrame()
|
|
67
|
+
|
|
68
|
+
if (frame === undefined) {
|
|
69
|
+
break
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
yield frame
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private readFrame (): Frame | undefined {
|
|
77
|
+
let frameSize = HEADER_LENGTH
|
|
78
|
+
|
|
79
|
+
if (this.buffer.byteLength < HEADER_LENGTH) {
|
|
80
|
+
// not enough data yet
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// TODO: use sublist?
|
|
85
|
+
const header = decodeHeader(this.buffer.subarray(0, HEADER_LENGTH))
|
|
86
|
+
|
|
87
|
+
if (header.type === FrameType.Data) {
|
|
88
|
+
frameSize += header.length
|
|
89
|
+
|
|
90
|
+
if (this.buffer.byteLength < frameSize) {
|
|
91
|
+
// not enough data yet
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const data = this.buffer.sublist(HEADER_LENGTH, frameSize)
|
|
96
|
+
this.buffer.consume(frameSize)
|
|
97
|
+
|
|
98
|
+
return { header, data }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.buffer.consume(frameSize)
|
|
102
|
+
|
|
103
|
+
return { header }
|
|
104
|
+
}
|
|
105
|
+
}
|
package/src/encode.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { HEADER_LENGTH } from './frame.js'
|
|
2
|
+
import type { FrameHeader } from './frame.js'
|
|
3
|
+
|
|
4
|
+
export function encodeHeader (header: FrameHeader): Uint8Array {
|
|
5
|
+
const frame = new Uint8Array(HEADER_LENGTH)
|
|
6
|
+
|
|
7
|
+
// always assume version 0
|
|
8
|
+
// frameView.setUint8(0, header.version)
|
|
9
|
+
|
|
10
|
+
frame[1] = header.type
|
|
11
|
+
|
|
12
|
+
frame[2] = header.flag >>> 8
|
|
13
|
+
frame[3] = header.flag
|
|
14
|
+
|
|
15
|
+
frame[4] = header.streamID >>> 24
|
|
16
|
+
frame[5] = header.streamID >>> 16
|
|
17
|
+
frame[6] = header.streamID >>> 8
|
|
18
|
+
frame[7] = header.streamID
|
|
19
|
+
|
|
20
|
+
frame[8] = header.length >>> 24
|
|
21
|
+
frame[9] = header.length >>> 16
|
|
22
|
+
frame[10] = header.length >>> 8
|
|
23
|
+
frame[11] = header.length
|
|
24
|
+
|
|
25
|
+
return frame
|
|
26
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { GoAwayCode } from './frame.ts'
|
|
2
|
+
|
|
3
|
+
export class ProtocolError extends Error {
|
|
4
|
+
static name = 'ProtocolError'
|
|
5
|
+
|
|
6
|
+
public reason: GoAwayCode
|
|
7
|
+
|
|
8
|
+
constructor (message: string, reason: GoAwayCode) {
|
|
9
|
+
super(message)
|
|
10
|
+
this.name = 'ProtocolError'
|
|
11
|
+
this.reason = reason
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isProtocolError (err?: any): err is ProtocolError {
|
|
16
|
+
return err?.reason !== null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class InvalidFrameError extends ProtocolError {
|
|
20
|
+
static name = 'InvalidFrameError'
|
|
21
|
+
|
|
22
|
+
constructor (message = 'The frame was invalid') {
|
|
23
|
+
super(message, GoAwayCode.ProtocolError)
|
|
24
|
+
this.name = 'InvalidFrameError'
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export class UnRequestedPingError extends ProtocolError {
|
|
29
|
+
static name = 'UnRequestedPingError'
|
|
30
|
+
|
|
31
|
+
constructor (message = 'Un-requested ping error') {
|
|
32
|
+
super(message, GoAwayCode.ProtocolError)
|
|
33
|
+
this.name = 'UnRequestedPingError'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class NotMatchingPingError extends ProtocolError {
|
|
38
|
+
static name = 'NotMatchingPingError'
|
|
39
|
+
|
|
40
|
+
constructor (message = 'Not matching ping error') {
|
|
41
|
+
super(message, GoAwayCode.ProtocolError)
|
|
42
|
+
this.name = 'NotMatchingPingError'
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class InvalidStateError extends Error {
|
|
47
|
+
static name = 'InvalidStateError'
|
|
48
|
+
|
|
49
|
+
constructor (message = 'Invalid state') {
|
|
50
|
+
super(message)
|
|
51
|
+
this.name = 'InvalidStateError'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export class StreamAlreadyExistsError extends ProtocolError {
|
|
56
|
+
static name = 'StreamAlreadyExistsError'
|
|
57
|
+
|
|
58
|
+
constructor (message = 'Stream already exists') {
|
|
59
|
+
super(message, GoAwayCode.ProtocolError)
|
|
60
|
+
this.name = 'StreamAlreadyExistsError'
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class DecodeInvalidVersionError extends ProtocolError {
|
|
65
|
+
static name = 'DecodeInvalidVersionError'
|
|
66
|
+
|
|
67
|
+
constructor (message = 'Decode invalid version') {
|
|
68
|
+
super(message, GoAwayCode.ProtocolError)
|
|
69
|
+
this.name = 'DecodeInvalidVersionError'
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class BothClientsError extends ProtocolError {
|
|
74
|
+
static name = 'BothClientsError'
|
|
75
|
+
|
|
76
|
+
constructor (message = 'Both clients') {
|
|
77
|
+
super(message, GoAwayCode.ProtocolError)
|
|
78
|
+
this.name = 'BothClientsError'
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export class ReceiveWindowExceededError extends ProtocolError {
|
|
83
|
+
static name = 'ReceiveWindowExceededError'
|
|
84
|
+
|
|
85
|
+
constructor (message = 'Receive window exceeded') {
|
|
86
|
+
super(message, GoAwayCode.ProtocolError)
|
|
87
|
+
this.name = 'ReceiveWindowExceededError'
|
|
88
|
+
}
|
|
89
|
+
}
|