@libp2p/yamux 7.0.4

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.
Files changed (49) hide show
  1. package/README.md +127 -0
  2. package/dist/index.min.js +4 -0
  3. package/dist/index.min.js.map +7 -0
  4. package/dist/src/config.d.ts +26 -0
  5. package/dist/src/config.d.ts.map +1 -0
  6. package/dist/src/config.js +37 -0
  7. package/dist/src/config.js.map +1 -0
  8. package/dist/src/constants.d.ts +12 -0
  9. package/dist/src/constants.d.ts.map +1 -0
  10. package/dist/src/constants.js +22 -0
  11. package/dist/src/constants.js.map +1 -0
  12. package/dist/src/decode.d.ts +34 -0
  13. package/dist/src/decode.d.ts.map +1 -0
  14. package/dist/src/decode.js +75 -0
  15. package/dist/src/decode.js.map +1 -0
  16. package/dist/src/encode.d.ts +3 -0
  17. package/dist/src/encode.d.ts.map +1 -0
  18. package/dist/src/encode.js +19 -0
  19. package/dist/src/encode.js.map +1 -0
  20. package/dist/src/errors.d.ts +40 -0
  21. package/dist/src/errors.d.ts.map +1 -0
  22. package/dist/src/errors.js +70 -0
  23. package/dist/src/errors.js.map +1 -0
  24. package/dist/src/frame.d.ts +54 -0
  25. package/dist/src/frame.d.ts.map +1 -0
  26. package/dist/src/frame.js +36 -0
  27. package/dist/src/frame.js.map +1 -0
  28. package/dist/src/index.d.ts +85 -0
  29. package/dist/src/index.d.ts.map +1 -0
  30. package/dist/src/index.js +84 -0
  31. package/dist/src/index.js.map +1 -0
  32. package/dist/src/muxer.d.ts +91 -0
  33. package/dist/src/muxer.d.ts.map +1 -0
  34. package/dist/src/muxer.js +428 -0
  35. package/dist/src/muxer.js.map +1 -0
  36. package/dist/src/stream.d.ts +96 -0
  37. package/dist/src/stream.d.ts.map +1 -0
  38. package/dist/src/stream.js +240 -0
  39. package/dist/src/stream.js.map +1 -0
  40. package/package.json +188 -0
  41. package/src/config.ts +66 -0
  42. package/src/constants.ts +25 -0
  43. package/src/decode.ts +104 -0
  44. package/src/encode.ts +26 -0
  45. package/src/errors.ts +89 -0
  46. package/src/frame.ts +64 -0
  47. package/src/index.ts +90 -0
  48. package/src/muxer.ts +506 -0
  49. package/src/stream.ts +293 -0
@@ -0,0 +1,240 @@
1
+ import { AbstractStream } from '@libp2p/utils';
2
+ import { Uint8ArrayList } from 'uint8arraylist';
3
+ import { defaultConfig } from './config.js';
4
+ import { INITIAL_STREAM_WINDOW } from './constants.js';
5
+ import { isDataFrame } from "./decode.js";
6
+ import { InvalidFrameError, ReceiveWindowExceededError } from './errors.js';
7
+ import { Flag, FrameType, HEADER_LENGTH } from './frame.js';
8
+ export var StreamState;
9
+ (function (StreamState) {
10
+ StreamState[StreamState["Init"] = 0] = "Init";
11
+ StreamState[StreamState["SYNSent"] = 1] = "SYNSent";
12
+ StreamState[StreamState["SYNReceived"] = 2] = "SYNReceived";
13
+ StreamState[StreamState["Established"] = 3] = "Established";
14
+ StreamState[StreamState["Finished"] = 4] = "Finished";
15
+ StreamState[StreamState["Paused"] = 5] = "Paused";
16
+ })(StreamState || (StreamState = {}));
17
+ /** YamuxStream is used to represent a logical stream within a session */
18
+ export class YamuxStream extends AbstractStream {
19
+ streamId;
20
+ state;
21
+ /** The number of available bytes to send */
22
+ sendWindowCapacity;
23
+ /** The number of bytes available to receive in a full window */
24
+ recvWindow;
25
+ /** The number of available bytes to receive */
26
+ recvWindowCapacity;
27
+ maxStreamWindowSize;
28
+ /**
29
+ * An 'epoch' is the time it takes to process and read data
30
+ *
31
+ * Used in conjunction with RTT to determine whether to increase the recvWindow
32
+ */
33
+ epochStart;
34
+ getRTT;
35
+ sendFrame;
36
+ constructor(init) {
37
+ super({
38
+ ...init,
39
+ maxMessageSize: (init.maxMessageSize ?? defaultConfig.maxMessageSize) - HEADER_LENGTH
40
+ });
41
+ this.streamId = init.streamId;
42
+ this.state = init.state;
43
+ this.sendWindowCapacity = INITIAL_STREAM_WINDOW;
44
+ this.recvWindow = init.initialStreamWindowSize ?? defaultConfig.initialStreamWindowSize;
45
+ this.recvWindowCapacity = this.recvWindow;
46
+ this.maxStreamWindowSize = init.maxStreamWindowSize ?? defaultConfig.maxStreamWindowSize;
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
+ // send in chunks, waiting for window updates
63
+ while (buf.byteLength !== 0) {
64
+ // we exhausted the send window, sending will resume later
65
+ if (this.sendWindowCapacity === 0) {
66
+ canSendMore = false;
67
+ this.log?.trace('sent %d/%d bytes, wait for send window update, status %s', sentBytes, totalBytes, this.status);
68
+ break;
69
+ }
70
+ // send as much as we can
71
+ const toSend = Math.min(this.sendWindowCapacity, buf.length);
72
+ const flags = this.getSendFlags();
73
+ const muxerSendMore = this.sendFrame({
74
+ type: FrameType.Data,
75
+ flag: flags,
76
+ streamID: this.streamId,
77
+ length: toSend
78
+ }, buf.sublist(0, toSend));
79
+ this.sendWindowCapacity -= toSend;
80
+ sentBytes += toSend;
81
+ buf.consume(toSend);
82
+ if (!muxerSendMore) {
83
+ canSendMore = muxerSendMore;
84
+ this.log('sent %d/%d bytes, wait for muxer to have more send capacity', sentBytes, totalBytes);
85
+ break;
86
+ }
87
+ }
88
+ return {
89
+ sentBytes,
90
+ canSendMore
91
+ };
92
+ }
93
+ /**
94
+ * Send a reset message to the remote muxer
95
+ */
96
+ async sendReset() {
97
+ this.sendFrame({
98
+ type: FrameType.WindowUpdate,
99
+ flag: Flag.RST,
100
+ streamID: this.streamId,
101
+ length: 0
102
+ });
103
+ }
104
+ /**
105
+ * Send a message to the remote muxer, informing them no more data messages
106
+ * will be sent by this end of the stream
107
+ */
108
+ async sendCloseWrite() {
109
+ const flags = this.getSendFlags() | Flag.FIN;
110
+ this.sendFrame({
111
+ type: FrameType.WindowUpdate,
112
+ flag: flags,
113
+ streamID: this.streamId,
114
+ length: 0
115
+ });
116
+ }
117
+ /**
118
+ * Send a message to the remote muxer, informing them no more data messages
119
+ * will be read by this end of the stream - this is a no-op on Yamux streams
120
+ */
121
+ async sendCloseRead(options) {
122
+ options?.signal?.throwIfAborted();
123
+ }
124
+ /**
125
+ * Stop sending window updates temporarily - in the interim the the remote
126
+ * send window will exhaust and the remote will stop sending data
127
+ */
128
+ sendPause() {
129
+ this.state = StreamState.Paused;
130
+ }
131
+ /**
132
+ * Start sending window updates as normal
133
+ */
134
+ sendResume() {
135
+ this.state = StreamState.Established;
136
+ this.sendWindowUpdate();
137
+ }
138
+ /**
139
+ * handleWindowUpdate is called when the stream receives a window update frame
140
+ */
141
+ handleWindowUpdate(frame) {
142
+ this.processFlags(frame.header.flag);
143
+ // increase send window
144
+ const available = this.sendWindowCapacity;
145
+ this.sendWindowCapacity += frame.header.length;
146
+ // if the update increments a 0 availability, notify the stream that sending can resume
147
+ if (available === 0 && frame.header.length > 0) {
148
+ this.log?.trace('window update of %d bytes allows more data to be sent', frame.header.length);
149
+ this.safeDispatchEvent('drain');
150
+ }
151
+ }
152
+ /**
153
+ * handleData is called when the stream receives a data frame
154
+ */
155
+ handleData(frame) {
156
+ if (!isDataFrame(frame)) {
157
+ throw new InvalidFrameError('Frame was not data frame');
158
+ }
159
+ this.processFlags(frame.header.flag);
160
+ // check that our recv window is not exceeded
161
+ if (this.recvWindowCapacity < frame.header.length) {
162
+ throw new ReceiveWindowExceededError('Receive window exceeded');
163
+ }
164
+ this.recvWindowCapacity -= frame.header.length;
165
+ this.onData(frame.data);
166
+ this.sendWindowUpdate();
167
+ }
168
+ /**
169
+ * processFlags is used to update the state of the stream based on set flags, if any.
170
+ */
171
+ processFlags(flags) {
172
+ if ((flags & Flag.ACK) === Flag.ACK) {
173
+ if (this.state === StreamState.SYNSent) {
174
+ this.state = StreamState.Established;
175
+ }
176
+ }
177
+ if ((flags & Flag.FIN) === Flag.FIN) {
178
+ this.onRemoteCloseWrite();
179
+ }
180
+ if ((flags & Flag.RST) === Flag.RST) {
181
+ this.onRemoteReset();
182
+ }
183
+ }
184
+ /**
185
+ * getSendFlags determines any flags that are appropriate
186
+ * based on the current stream state.
187
+ *
188
+ * The state is updated as a side-effect.
189
+ */
190
+ getSendFlags() {
191
+ switch (this.state) {
192
+ case StreamState.Init:
193
+ this.state = StreamState.SYNSent;
194
+ return Flag.SYN;
195
+ case StreamState.SYNReceived:
196
+ this.state = StreamState.Established;
197
+ return Flag.ACK;
198
+ default:
199
+ return 0;
200
+ }
201
+ }
202
+ /**
203
+ * Potentially sends a window update enabling further remote writes to take
204
+ * place.
205
+ */
206
+ sendWindowUpdate() {
207
+ // determine the flags if any
208
+ const flags = this.getSendFlags();
209
+ // If the stream has already been established
210
+ // and we've processed data within the time it takes for 4 round trips
211
+ // then we (up to) double the recvWindow
212
+ const now = Date.now();
213
+ const rtt = this.getRTT();
214
+ if (flags === 0 && rtt > -1 && now - this.epochStart < rtt * 4) {
215
+ // we've already validated that maxStreamWindowSize can't be more than MAX_UINT32
216
+ this.recvWindow = Math.min(this.recvWindow * 2, this.maxStreamWindowSize);
217
+ }
218
+ if (this.recvWindowCapacity >= this.recvWindow && flags === 0) {
219
+ // a window update isn't needed
220
+ return;
221
+ }
222
+ if (this.state === StreamState.Paused) {
223
+ // we don't want any more data from the remote right now
224
+ return;
225
+ }
226
+ // update the receive window
227
+ const delta = this.recvWindow - this.recvWindowCapacity;
228
+ this.recvWindowCapacity = this.recvWindow;
229
+ // update the epoch start
230
+ this.epochStart = now;
231
+ // send window update
232
+ this.sendFrame({
233
+ type: FrameType.WindowUpdate,
234
+ flag: flags,
235
+ streamID: this.streamId,
236
+ length: delta
237
+ });
238
+ }
239
+ }
240
+ //# 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,188 @@
1
+ {
2
+ "name": "@libp2p/yamux",
3
+ "version": "7.0.4",
4
+ "description": "Yamux stream multiplexer for libp2p",
5
+ "license": "Apache-2.0 OR MIT",
6
+ "homepage": "https://github.com/ChainSafe/js-libp2p-yamux#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ChainSafe/js-libp2p-yamux.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/ChainSafe/js-libp2p-yamux/issues"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "keywords": [
18
+ "IPFS",
19
+ "libp2p",
20
+ "multiplexer",
21
+ "muxer",
22
+ "stream"
23
+ ],
24
+ "type": "module",
25
+ "types": "./dist/src/index.d.ts",
26
+ "typesVersions": {
27
+ "*": {
28
+ "*": [
29
+ "*",
30
+ "dist/*",
31
+ "dist/src/*",
32
+ "dist/src/*/index"
33
+ ],
34
+ "src/*": [
35
+ "*",
36
+ "dist/*",
37
+ "dist/src/*",
38
+ "dist/src/*/index"
39
+ ]
40
+ }
41
+ },
42
+ "files": [
43
+ "src",
44
+ "dist",
45
+ "!dist/test",
46
+ "!**/*.tsbuildinfo"
47
+ ],
48
+ "exports": {
49
+ ".": {
50
+ "types": "./dist/src/index.d.ts",
51
+ "import": "./dist/src/index.js"
52
+ },
53
+ "./config": {
54
+ "types": "./dist/src/config.d.ts",
55
+ "import": "./dist/src/config.js"
56
+ },
57
+ "./stream": {
58
+ "types": "./dist/src/stream.d.ts",
59
+ "import": "./dist/src/stream.js"
60
+ }
61
+ },
62
+ "release": {
63
+ "branches": [
64
+ "master"
65
+ ],
66
+ "plugins": [
67
+ [
68
+ "@semantic-release/commit-analyzer",
69
+ {
70
+ "preset": "conventionalcommits",
71
+ "releaseRules": [
72
+ {
73
+ "breaking": true,
74
+ "release": "major"
75
+ },
76
+ {
77
+ "revert": true,
78
+ "release": "patch"
79
+ },
80
+ {
81
+ "type": "feat",
82
+ "release": "minor"
83
+ },
84
+ {
85
+ "type": "fix",
86
+ "release": "patch"
87
+ },
88
+ {
89
+ "type": "docs",
90
+ "release": "patch"
91
+ },
92
+ {
93
+ "type": "test",
94
+ "release": "patch"
95
+ },
96
+ {
97
+ "type": "deps",
98
+ "release": "patch"
99
+ },
100
+ {
101
+ "scope": "no-release",
102
+ "release": false
103
+ }
104
+ ]
105
+ }
106
+ ],
107
+ [
108
+ "@semantic-release/release-notes-generator",
109
+ {
110
+ "preset": "conventionalcommits",
111
+ "presetConfig": {
112
+ "types": [
113
+ {
114
+ "type": "feat",
115
+ "section": "Features"
116
+ },
117
+ {
118
+ "type": "fix",
119
+ "section": "Bug Fixes"
120
+ },
121
+ {
122
+ "type": "chore",
123
+ "section": "Trivial Changes"
124
+ },
125
+ {
126
+ "type": "docs",
127
+ "section": "Documentation"
128
+ },
129
+ {
130
+ "type": "deps",
131
+ "section": "Dependencies"
132
+ },
133
+ {
134
+ "type": "test",
135
+ "section": "Tests"
136
+ }
137
+ ]
138
+ }
139
+ }
140
+ ],
141
+ "@semantic-release/changelog",
142
+ "@semantic-release/npm",
143
+ "@semantic-release/github",
144
+ [
145
+ "@semantic-release/git",
146
+ {
147
+ "assets": [
148
+ "CHANGELOG.md",
149
+ "package.json"
150
+ ]
151
+ }
152
+ ]
153
+ ]
154
+ },
155
+ "scripts": {
156
+ "clean": "aegir clean",
157
+ "lint": "aegir lint",
158
+ "dep-check": "aegir dep-check",
159
+ "doc-check": "aegir doc-check",
160
+ "benchmark": "benchmark dist/test/bench/*.bench.js --timeout 400000",
161
+ "build": "aegir build",
162
+ "test": "aegir test",
163
+ "test:chrome": "aegir test -t browser",
164
+ "test:chrome-webworker": "aegir test -t webworker",
165
+ "test:firefox": "aegir test -t browser -- --browser firefox",
166
+ "test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
167
+ "test:node": "aegir test -t node --cov",
168
+ "test:electron-main": "aegir test -t electron-main",
169
+ "release": "aegir release",
170
+ "docs": "aegir docs"
171
+ },
172
+ "dependencies": {
173
+ "@libp2p/interface": "^2.0.0",
174
+ "@libp2p/utils": "^6.0.0",
175
+ "race-signal": "^2.0.0",
176
+ "uint8arraylist": "^2.4.8"
177
+ },
178
+ "devDependencies": {
179
+ "@dapplion/benchmark": "^1.0.0",
180
+ "@libp2p/interface-compliance-tests": "^6.4.12",
181
+ "@libp2p/mplex": "^11.0.0",
182
+ "aegir": "^47.0.17",
183
+ "it-all": "^3.0.9",
184
+ "it-drain": "^3.0.5",
185
+ "it-pushable": "^3.2.3",
186
+ "p-event": "^6.0.1"
187
+ }
188
+ }
package/src/config.ts ADDED
@@ -0,0 +1,66 @@
1
+ import { InvalidParametersError } from '@libp2p/interface'
2
+ import { INITIAL_STREAM_WINDOW, MAX_STREAM_WINDOW } from './constants.js'
3
+ import type { StreamMuxerOptions } from '@libp2p/interface'
4
+
5
+ // TODO use config items or delete them
6
+ export interface Config extends StreamMuxerOptions {
7
+ /**
8
+ * Used to do periodic keep alive messages using a ping.
9
+ */
10
+ enableKeepAlive?: boolean
11
+
12
+ /**
13
+ * How often to perform the keep alive
14
+ *
15
+ * measured in milliseconds
16
+ */
17
+ keepAliveInterval?: number
18
+
19
+ /**
20
+ * Used to control the initial window size that we allow for a stream.
21
+ *
22
+ * measured in bytes
23
+ */
24
+ initialStreamWindowSize?: number
25
+
26
+ /**
27
+ * Used to control the maximum window size that we allow for a stream.
28
+ */
29
+ maxStreamWindowSize?: number
30
+ }
31
+
32
+ export const defaultConfig: Required<Config> = {
33
+ enableKeepAlive: true,
34
+ keepAliveInterval: 30_000,
35
+ maxInboundStreams: 1_000,
36
+ maxOutboundStreams: 1_000,
37
+ initialStreamWindowSize: INITIAL_STREAM_WINDOW,
38
+ maxStreamWindowSize: MAX_STREAM_WINDOW,
39
+ maxMessageSize: 64 * 1024,
40
+ maxEarlyStreams: 10,
41
+ streamOptions: {}
42
+ }
43
+
44
+ export function verifyConfig (config: Config): void {
45
+ if (config.keepAliveInterval != null && config.keepAliveInterval <= 0) {
46
+ throw new InvalidParametersError('keep-alive interval must be positive')
47
+ }
48
+ if (config.maxInboundStreams != null && config.maxInboundStreams < 0) {
49
+ throw new InvalidParametersError('max inbound streams must be larger or equal 0')
50
+ }
51
+ if (config.maxOutboundStreams != null && config.maxOutboundStreams < 0) {
52
+ throw new InvalidParametersError('max outbound streams must be larger or equal 0')
53
+ }
54
+ if (config.initialStreamWindowSize != null && config.initialStreamWindowSize < INITIAL_STREAM_WINDOW) {
55
+ throw new InvalidParametersError('InitialStreamWindowSize must be larger or equal 256 kB')
56
+ }
57
+ if (config.maxStreamWindowSize != null && config.initialStreamWindowSize != null && config.maxStreamWindowSize < config.initialStreamWindowSize) {
58
+ throw new InvalidParametersError('MaxStreamWindowSize must be larger than the InitialStreamWindowSize')
59
+ }
60
+ if (config.maxStreamWindowSize != null && config.maxStreamWindowSize > 2 ** 32 - 1) {
61
+ throw new InvalidParametersError('MaxStreamWindowSize must be less than equal MAX_UINT32')
62
+ }
63
+ if (config.maxMessageSize != null && config.maxMessageSize < 1024) {
64
+ throw new InvalidParametersError('MaxMessageSize must be greater than a kilobyte')
65
+ }
66
+ }
@@ -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,104 @@
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
+ const header = decodeHeader(this.buffer.subarray(0, HEADER_LENGTH))
85
+
86
+ if (header.type === FrameType.Data) {
87
+ frameSize += header.length
88
+
89
+ if (this.buffer.byteLength < frameSize) {
90
+ // not enough data yet
91
+ return
92
+ }
93
+
94
+ const data = this.buffer.sublist(HEADER_LENGTH, frameSize)
95
+ this.buffer.consume(frameSize)
96
+
97
+ return { header, data }
98
+ }
99
+
100
+ this.buffer.consume(frameSize)
101
+
102
+ return { header }
103
+ }
104
+ }
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
+ }