@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.
- 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 +26 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +37 -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 +75 -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 +240 -0
- package/dist/src/stream.js.map +1 -0
- package/package.json +188 -0
- package/src/config.ts +66 -0
- package/src/constants.ts +25 -0
- package/src/decode.ts +104 -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 +506 -0
- package/src/stream.ts +293 -0
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
|
+
}
|
package/src/frame.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export enum FrameType {
|
|
2
|
+
/** Used to transmit data. May transmit zero length payloads depending on the flags. */
|
|
3
|
+
Data = 0x0,
|
|
4
|
+
/** Used to updated the senders receive window size. This is used to implement per-session flow control. */
|
|
5
|
+
WindowUpdate = 0x1,
|
|
6
|
+
/** Used to measure RTT. It can also be used to heart-beat and do keep-alive over TCP. */
|
|
7
|
+
Ping = 0x2,
|
|
8
|
+
/** Used to close a session. */
|
|
9
|
+
GoAway = 0x3
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export enum Flag {
|
|
13
|
+
/** Signals the start of a new stream. May be sent with a data or window update message. Also sent with a ping to indicate outbound. */
|
|
14
|
+
SYN = 0x1,
|
|
15
|
+
/** Acknowledges the start of a new stream. May be sent with a data or window update message. Also sent with a ping to indicate response. */
|
|
16
|
+
ACK = 0x2,
|
|
17
|
+
/** Performs a half-close of a stream. May be sent with a data message or window update. */
|
|
18
|
+
FIN = 0x4,
|
|
19
|
+
/** Reset a stream immediately. May be sent with a data or window update message. */
|
|
20
|
+
RST = 0x8
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const flagCodes = Object.values(Flag).filter((x) => typeof x !== 'string') as Flag[]
|
|
24
|
+
|
|
25
|
+
export const YAMUX_VERSION = 0
|
|
26
|
+
|
|
27
|
+
export enum GoAwayCode {
|
|
28
|
+
NormalTermination = 0x0,
|
|
29
|
+
ProtocolError = 0x1,
|
|
30
|
+
InternalError = 0x2
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const HEADER_LENGTH = 12
|
|
34
|
+
|
|
35
|
+
export interface FrameHeader {
|
|
36
|
+
/**
|
|
37
|
+
* The version field is used for future backward compatibility.
|
|
38
|
+
* At the current time, the field is always set to 0, to indicate the initial version.
|
|
39
|
+
*/
|
|
40
|
+
version?: number
|
|
41
|
+
/** The type field is used to switch the frame message type. */
|
|
42
|
+
type: FrameType
|
|
43
|
+
/** The flags field is used to provide additional information related to the message type. */
|
|
44
|
+
flag: number
|
|
45
|
+
/**
|
|
46
|
+
* The StreamID field is used to identify the logical stream the frame is addressing.
|
|
47
|
+
* The client side should use odd ID's, and the server even.
|
|
48
|
+
* This prevents any collisions. Additionally, the 0 ID is reserved to represent the session.
|
|
49
|
+
*/
|
|
50
|
+
streamID: number
|
|
51
|
+
/**
|
|
52
|
+
* The meaning of the length field depends on the message type:
|
|
53
|
+
* Data - provides the length of bytes following the header
|
|
54
|
+
* Window update - provides a delta update to the window size
|
|
55
|
+
* Ping - Contains an opaque value, echoed back
|
|
56
|
+
* Go Away - Contains an error code
|
|
57
|
+
*/
|
|
58
|
+
length: number
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function stringifyHeader (header: FrameHeader): string {
|
|
62
|
+
const flags = flagCodes.filter(f => (header.flag & f) === f).map(f => Flag[f]).join('|')
|
|
63
|
+
return `streamID=${header.streamID} type=${FrameType[header.type]} flag=${flags} length=${header.length}`
|
|
64
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
*
|
|
4
|
+
* This module is a JavaScript implementation of [Yamux from Hashicorp](https://github.com/hashicorp/yamux/blob/master/spec.md) designed to be used with [js-libp2p](https://github.com/libp2p/js-libp2p).
|
|
5
|
+
*
|
|
6
|
+
* @example Configure libp2p with Yamux
|
|
7
|
+
*
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { createLibp2p } from 'libp2p'
|
|
10
|
+
* import { yamux } from '@libp2p/yamux'
|
|
11
|
+
*
|
|
12
|
+
* const node = await createLibp2p({
|
|
13
|
+
* // ... other options
|
|
14
|
+
* streamMuxers: [
|
|
15
|
+
* yamux()
|
|
16
|
+
* ]
|
|
17
|
+
* })
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @example Using the low-level API
|
|
21
|
+
*
|
|
22
|
+
* ```js
|
|
23
|
+
* import { yamux } from '@libp2p/yamux'
|
|
24
|
+
* import { pipe } from 'it-pipe'
|
|
25
|
+
* import { duplexPair } from 'it-pair/duplex'
|
|
26
|
+
* import all from 'it-all'
|
|
27
|
+
*
|
|
28
|
+
* // Connect two yamux muxers to demo basic stream multiplexing functionality
|
|
29
|
+
*
|
|
30
|
+
* const clientMuxer = yamux({
|
|
31
|
+
* client: true,
|
|
32
|
+
* onIncomingStream: stream => {
|
|
33
|
+
* // echo data on incoming streams
|
|
34
|
+
* pipe(stream, stream)
|
|
35
|
+
* },
|
|
36
|
+
* onStreamEnd: stream => {
|
|
37
|
+
* // do nothing
|
|
38
|
+
* }
|
|
39
|
+
* })()
|
|
40
|
+
*
|
|
41
|
+
* const serverMuxer = yamux({
|
|
42
|
+
* client: false,
|
|
43
|
+
* onIncomingStream: stream => {
|
|
44
|
+
* // echo data on incoming streams
|
|
45
|
+
* pipe(stream, stream)
|
|
46
|
+
* },
|
|
47
|
+
* onStreamEnd: stream => {
|
|
48
|
+
* // do nothing
|
|
49
|
+
* }
|
|
50
|
+
* })()
|
|
51
|
+
*
|
|
52
|
+
* // `p` is our "connections", what we use to connect the two sides
|
|
53
|
+
* // In a real application, a connection is usually to a remote computer
|
|
54
|
+
* const p = duplexPair()
|
|
55
|
+
*
|
|
56
|
+
* // connect the muxers together
|
|
57
|
+
* pipe(p[0], clientMuxer, p[0])
|
|
58
|
+
* pipe(p[1], serverMuxer, p[1])
|
|
59
|
+
*
|
|
60
|
+
* // now either side can open streams
|
|
61
|
+
* const stream0 = clientMuxer.newStream()
|
|
62
|
+
* const stream1 = serverMuxer.newStream()
|
|
63
|
+
*
|
|
64
|
+
* // Send some data to the other side
|
|
65
|
+
* const encoder = new TextEncoder()
|
|
66
|
+
* const data = [encoder.encode('hello'), encoder.encode('world')]
|
|
67
|
+
* pipe(data, stream0)
|
|
68
|
+
*
|
|
69
|
+
* // Receive data back
|
|
70
|
+
* const result = await pipe(stream0, all)
|
|
71
|
+
*
|
|
72
|
+
* // close a stream
|
|
73
|
+
* stream1.close()
|
|
74
|
+
*
|
|
75
|
+
* // close the muxer
|
|
76
|
+
* clientMuxer.close()
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
import { Yamux } from './muxer.js'
|
|
81
|
+
import type { YamuxMuxer, YamuxMuxerInit } from './muxer.js'
|
|
82
|
+
import type { StreamMuxerFactory } from '@libp2p/interface'
|
|
83
|
+
|
|
84
|
+
export { GoAwayCode } from './frame.js'
|
|
85
|
+
export type { FrameHeader, FrameType } from './frame.js'
|
|
86
|
+
export type { YamuxMuxerInit }
|
|
87
|
+
|
|
88
|
+
export function yamux (init: YamuxMuxerInit = {}): () => StreamMuxerFactory<YamuxMuxer> {
|
|
89
|
+
return () => new Yamux(init)
|
|
90
|
+
}
|