@libp2p/webrtc 2.0.2 → 2.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/dist/index.min.js +17 -17
- package/dist/src/index.d.ts +19 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +20 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/muxer.d.ts +27 -17
- package/dist/src/muxer.d.ts.map +1 -1
- package/dist/src/muxer.js +47 -71
- package/dist/src/muxer.js.map +1 -1
- package/dist/src/private-to-private/handler.d.ts +5 -2
- package/dist/src/private-to-private/handler.d.ts.map +1 -1
- package/dist/src/private-to-private/handler.js +4 -4
- package/dist/src/private-to-private/handler.js.map +1 -1
- package/dist/src/private-to-private/transport.d.ts +3 -1
- package/dist/src/private-to-private/transport.d.ts.map +1 -1
- package/dist/src/private-to-private/transport.js +4 -2
- package/dist/src/private-to-private/transport.js.map +1 -1
- package/dist/src/private-to-public/transport.d.ts +6 -1
- package/dist/src/private-to-public/transport.d.ts.map +1 -1
- package/dist/src/private-to-public/transport.js +6 -4
- package/dist/src/private-to-public/transport.js.map +1 -1
- package/dist/src/stream.d.ts +20 -133
- package/dist/src/stream.d.ts.map +1 -1
- package/dist/src/stream.js +121 -289
- package/dist/src/stream.js.map +1 -1
- package/package.json +12 -4
- package/src/index.ts +21 -4
- package/src/muxer.ts +75 -76
- package/src/private-to-private/handler.ts +7 -6
- package/src/private-to-private/transport.ts +6 -2
- package/src/private-to-public/transport.ts +11 -5
- package/src/stream.ts +156 -345
package/src/muxer.ts
CHANGED
|
@@ -1,71 +1,96 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createStream } from './stream.js'
|
|
2
2
|
import { nopSink, nopSource } from './util.js'
|
|
3
|
+
import type { DataChannelOpts } from './stream.js'
|
|
3
4
|
import type { Stream } from '@libp2p/interface-connection'
|
|
4
5
|
import type { CounterGroup } from '@libp2p/interface-metrics'
|
|
5
6
|
import type { StreamMuxer, StreamMuxerFactory, StreamMuxerInit } from '@libp2p/interface-stream-muxer'
|
|
6
7
|
import type { Source, Sink } from 'it-stream-types'
|
|
7
8
|
import type { Uint8ArrayList } from 'uint8arraylist'
|
|
8
9
|
|
|
10
|
+
const PROTOCOL = '/webrtc'
|
|
11
|
+
|
|
9
12
|
export interface DataChannelMuxerFactoryInit {
|
|
13
|
+
/**
|
|
14
|
+
* WebRTC Peer Connection
|
|
15
|
+
*/
|
|
10
16
|
peerConnection: RTCPeerConnection
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Optional metrics for this data channel muxer
|
|
20
|
+
*/
|
|
11
21
|
metrics?: CounterGroup
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Data channel options
|
|
25
|
+
*/
|
|
26
|
+
dataChannelOptions?: Partial<DataChannelOpts>
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The protocol to use
|
|
30
|
+
*/
|
|
31
|
+
protocol?: string
|
|
12
32
|
}
|
|
13
33
|
|
|
14
34
|
export class DataChannelMuxerFactory implements StreamMuxerFactory {
|
|
35
|
+
public readonly protocol: string
|
|
36
|
+
|
|
15
37
|
/**
|
|
16
38
|
* WebRTC Peer Connection
|
|
17
39
|
*/
|
|
18
40
|
private readonly peerConnection: RTCPeerConnection
|
|
19
|
-
private streamBuffer:
|
|
41
|
+
private streamBuffer: Stream[] = []
|
|
20
42
|
private readonly metrics?: CounterGroup
|
|
43
|
+
private readonly dataChannelOptions?: Partial<DataChannelOpts>
|
|
44
|
+
|
|
45
|
+
constructor (init: DataChannelMuxerFactoryInit) {
|
|
46
|
+
this.peerConnection = init.peerConnection
|
|
47
|
+
this.metrics = init.metrics
|
|
48
|
+
this.protocol = init.protocol ?? PROTOCOL
|
|
49
|
+
this.dataChannelOptions = init.dataChannelOptions
|
|
21
50
|
|
|
22
|
-
constructor (peerConnection: RTCPeerConnection, metrics?: CounterGroup, readonly protocol = '/webrtc') {
|
|
23
|
-
this.peerConnection = peerConnection
|
|
24
51
|
// store any datachannels opened before upgrade has been completed
|
|
25
52
|
this.peerConnection.ondatachannel = ({ channel }) => {
|
|
26
|
-
const stream =
|
|
53
|
+
const stream = createStream({
|
|
27
54
|
channel,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
closeCb: (_stream) => {
|
|
33
|
-
this.streamBuffer = this.streamBuffer.filter(s => !_stream.eq(s))
|
|
55
|
+
direction: 'inbound',
|
|
56
|
+
dataChannelOptions: init.dataChannelOptions,
|
|
57
|
+
onEnd: () => {
|
|
58
|
+
this.streamBuffer = this.streamBuffer.filter(s => s.id !== stream.id)
|
|
34
59
|
}
|
|
35
60
|
})
|
|
36
61
|
this.streamBuffer.push(stream)
|
|
37
62
|
}
|
|
38
|
-
this.metrics = metrics
|
|
39
63
|
}
|
|
40
64
|
|
|
41
|
-
createStreamMuxer (init?: StreamMuxerInit
|
|
42
|
-
return new DataChannelMuxer(
|
|
65
|
+
createStreamMuxer (init?: StreamMuxerInit): StreamMuxer {
|
|
66
|
+
return new DataChannelMuxer({
|
|
67
|
+
...init,
|
|
68
|
+
peerConnection: this.peerConnection,
|
|
69
|
+
dataChannelOptions: this.dataChannelOptions,
|
|
70
|
+
metrics: this.metrics,
|
|
71
|
+
streams: this.streamBuffer,
|
|
72
|
+
protocol: this.protocol
|
|
73
|
+
})
|
|
43
74
|
}
|
|
44
75
|
}
|
|
45
76
|
|
|
77
|
+
export interface DataChannelMuxerInit extends DataChannelMuxerFactoryInit, StreamMuxerInit {
|
|
78
|
+
streams: Stream[]
|
|
79
|
+
}
|
|
80
|
+
|
|
46
81
|
/**
|
|
47
82
|
* A libp2p data channel stream muxer
|
|
48
83
|
*/
|
|
49
84
|
export class DataChannelMuxer implements StreamMuxer {
|
|
50
|
-
/**
|
|
51
|
-
* WebRTC Peer Connection
|
|
52
|
-
*/
|
|
53
|
-
private readonly peerConnection: RTCPeerConnection
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Optional metrics for this data channel muxer
|
|
57
|
-
*/
|
|
58
|
-
private readonly metrics?: CounterGroup
|
|
59
|
-
|
|
60
85
|
/**
|
|
61
86
|
* Array of streams in the data channel
|
|
62
87
|
*/
|
|
63
|
-
streams: Stream[]
|
|
88
|
+
public streams: Stream[]
|
|
89
|
+
public protocol: string
|
|
64
90
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
init?: StreamMuxerInit
|
|
91
|
+
private readonly peerConnection: RTCPeerConnection
|
|
92
|
+
private readonly dataChannelOptions?: DataChannelOpts
|
|
93
|
+
private readonly metrics?: CounterGroup
|
|
69
94
|
|
|
70
95
|
/**
|
|
71
96
|
* Close or abort all tracked streams and stop the muxer
|
|
@@ -82,16 +107,11 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
|
82
107
|
*/
|
|
83
108
|
sink: Sink<Source<Uint8Array | Uint8ArrayList>, Promise<void>> = nopSink
|
|
84
109
|
|
|
85
|
-
constructor (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
this.
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* WebRTC Peer Connection
|
|
93
|
-
*/
|
|
94
|
-
this.peerConnection = peerConnection
|
|
110
|
+
constructor (readonly init: DataChannelMuxerInit) {
|
|
111
|
+
this.streams = init.streams
|
|
112
|
+
this.peerConnection = init.peerConnection
|
|
113
|
+
this.protocol = init.protocol ?? PROTOCOL
|
|
114
|
+
this.metrics = init.metrics
|
|
95
115
|
|
|
96
116
|
/**
|
|
97
117
|
* Fired when a data channel has been added to the connection has been
|
|
@@ -100,15 +120,15 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
|
100
120
|
* {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event}
|
|
101
121
|
*/
|
|
102
122
|
this.peerConnection.ondatachannel = ({ channel }) => {
|
|
103
|
-
const stream =
|
|
123
|
+
const stream = createStream({
|
|
104
124
|
channel,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
125
|
+
direction: 'inbound',
|
|
126
|
+
dataChannelOptions: this.dataChannelOptions,
|
|
127
|
+
onEnd: () => {
|
|
128
|
+
this.streams = this.streams.filter(s => s.id !== stream.id)
|
|
129
|
+
this.metrics?.increment({ stream_end: true })
|
|
130
|
+
init?.onStreamEnd?.(stream)
|
|
131
|
+
}
|
|
112
132
|
})
|
|
113
133
|
|
|
114
134
|
this.streams.push(stream)
|
|
@@ -118,13 +138,6 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
|
118
138
|
}
|
|
119
139
|
}
|
|
120
140
|
|
|
121
|
-
// wrap open streams with the onStreamEnd callback
|
|
122
|
-
this.streams = streams
|
|
123
|
-
.filter(stream => stream.stat.timeline.close == null)
|
|
124
|
-
.map(stream => {
|
|
125
|
-
(stream as WebRTCStream).closeCb = this.wrapStreamEnd(init?.onStreamEnd)
|
|
126
|
-
return stream
|
|
127
|
-
})
|
|
128
141
|
const onIncomingStream = init?.onIncomingStream
|
|
129
142
|
if (onIncomingStream != null) {
|
|
130
143
|
this.streams.forEach(s => { onIncomingStream(s) })
|
|
@@ -134,33 +147,19 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
|
134
147
|
newStream (): Stream {
|
|
135
148
|
// The spec says the label SHOULD be an empty string: https://github.com/libp2p/specs/blob/master/webrtc/README.md#rtcdatachannel-label
|
|
136
149
|
const channel = this.peerConnection.createDataChannel('')
|
|
137
|
-
const
|
|
138
|
-
this.metrics?.increment({ stream_end: true })
|
|
139
|
-
this.init?.onStreamEnd?.(stream)
|
|
140
|
-
}
|
|
141
|
-
const stream = new WebRTCStream({
|
|
150
|
+
const stream = createStream({
|
|
142
151
|
channel,
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
152
|
+
direction: 'outbound',
|
|
153
|
+
dataChannelOptions: this.dataChannelOptions,
|
|
154
|
+
onEnd: () => {
|
|
155
|
+
this.streams = this.streams.filter(s => s.id !== stream.id)
|
|
156
|
+
this.metrics?.increment({ stream_end: true })
|
|
157
|
+
this.init?.onStreamEnd?.(stream)
|
|
158
|
+
}
|
|
150
159
|
})
|
|
151
160
|
this.streams.push(stream)
|
|
152
161
|
this.metrics?.increment({ outgoing_stream: true })
|
|
153
162
|
|
|
154
163
|
return stream
|
|
155
164
|
}
|
|
156
|
-
|
|
157
|
-
private wrapStreamEnd (onStreamEnd?: (s: Stream) => void): (stream: Stream) => void {
|
|
158
|
-
const self = this
|
|
159
|
-
return (_stream) => {
|
|
160
|
-
self.streams = self.streams.filter(s => !(_stream instanceof WebRTCStream && (_stream).eq(s)))
|
|
161
|
-
if (onStreamEnd != null) {
|
|
162
|
-
onStreamEnd(_stream)
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
165
|
}
|
|
@@ -5,6 +5,7 @@ import pDefer, { type DeferredPromise } from 'p-defer'
|
|
|
5
5
|
import { DataChannelMuxerFactory } from '../muxer.js'
|
|
6
6
|
import { Message } from './pb/message.js'
|
|
7
7
|
import { readCandidatesUntilConnected, resolveOnConnected } from './util.js'
|
|
8
|
+
import type { DataChannelOpts } from '../stream.js'
|
|
8
9
|
import type { Stream } from '@libp2p/interface-connection'
|
|
9
10
|
import type { IncomingStreamData } from '@libp2p/interface-registrar'
|
|
10
11
|
import type { StreamMuxerFactory } from '@libp2p/interface-stream-muxer'
|
|
@@ -13,14 +14,13 @@ const DEFAULT_TIMEOUT = 30 * 1000
|
|
|
13
14
|
|
|
14
15
|
const log = logger('libp2p:webrtc:peer')
|
|
15
16
|
|
|
16
|
-
export type IncomingStreamOpts = { rtcConfiguration?: RTCConfiguration } & IncomingStreamData
|
|
17
|
+
export type IncomingStreamOpts = { rtcConfiguration?: RTCConfiguration, dataChannelOptions?: Partial<DataChannelOpts> } & IncomingStreamData
|
|
17
18
|
|
|
18
|
-
export async function handleIncomingStream ({ rtcConfiguration, stream: rawStream }: IncomingStreamOpts): Promise<{ pc: RTCPeerConnection, muxerFactory: StreamMuxerFactory, remoteAddress: string }> {
|
|
19
|
+
export async function handleIncomingStream ({ rtcConfiguration, dataChannelOptions, stream: rawStream }: IncomingStreamOpts): Promise<{ pc: RTCPeerConnection, muxerFactory: StreamMuxerFactory, remoteAddress: string }> {
|
|
19
20
|
const signal = AbortSignal.timeout(DEFAULT_TIMEOUT)
|
|
20
21
|
const stream = pbStream(abortableDuplex(rawStream, signal)).pb(Message)
|
|
21
22
|
const pc = new RTCPeerConnection(rtcConfiguration)
|
|
22
|
-
const muxerFactory = new DataChannelMuxerFactory(pc)
|
|
23
|
-
|
|
23
|
+
const muxerFactory = new DataChannelMuxerFactory({ peerConnection: pc, dataChannelOptions })
|
|
24
24
|
const connectedPromise: DeferredPromise<void> = pDefer()
|
|
25
25
|
const answerSentPromise: DeferredPromise<void> = pDefer()
|
|
26
26
|
|
|
@@ -86,13 +86,14 @@ export interface ConnectOptions {
|
|
|
86
86
|
stream: Stream
|
|
87
87
|
signal: AbortSignal
|
|
88
88
|
rtcConfiguration?: RTCConfiguration
|
|
89
|
+
dataChannelOptions?: Partial<DataChannelOpts>
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
export async function initiateConnection ({ rtcConfiguration, signal, stream: rawStream }: ConnectOptions): Promise<{ pc: RTCPeerConnection, muxerFactory: StreamMuxerFactory, remoteAddress: string }> {
|
|
92
|
+
export async function initiateConnection ({ rtcConfiguration, dataChannelOptions, signal, stream: rawStream }: ConnectOptions): Promise<{ pc: RTCPeerConnection, muxerFactory: StreamMuxerFactory, remoteAddress: string }> {
|
|
92
93
|
const stream = pbStream(abortableDuplex(rawStream, signal)).pb(Message)
|
|
93
94
|
// setup peer connection
|
|
94
95
|
const pc = new RTCPeerConnection(rtcConfiguration)
|
|
95
|
-
const muxerFactory = new DataChannelMuxerFactory(pc)
|
|
96
|
+
const muxerFactory = new DataChannelMuxerFactory({ peerConnection: pc, dataChannelOptions })
|
|
96
97
|
|
|
97
98
|
const connectedPromise: DeferredPromise<void> = pDefer()
|
|
98
99
|
resolveOnConnected(pc, connectedPromise)
|
|
@@ -7,6 +7,7 @@ import { codes } from '../error.js'
|
|
|
7
7
|
import { WebRTCMultiaddrConnection } from '../maconn.js'
|
|
8
8
|
import { initiateConnection, handleIncomingStream } from './handler.js'
|
|
9
9
|
import { WebRTCPeerListener } from './listener.js'
|
|
10
|
+
import type { DataChannelOpts } from '../stream.js'
|
|
10
11
|
import type { Connection } from '@libp2p/interface-connection'
|
|
11
12
|
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
12
13
|
import type { IncomingStreamData, Registrar } from '@libp2p/interface-registrar'
|
|
@@ -21,6 +22,7 @@ const WEBRTC_CODE = protocols('webrtc').code
|
|
|
21
22
|
|
|
22
23
|
export interface WebRTCTransportInit {
|
|
23
24
|
rtcConfiguration?: RTCConfiguration
|
|
25
|
+
dataChannel?: Partial<DataChannelOpts>
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export interface WebRTCTransportComponents {
|
|
@@ -35,7 +37,7 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
35
37
|
|
|
36
38
|
constructor (
|
|
37
39
|
private readonly components: WebRTCTransportComponents,
|
|
38
|
-
private readonly init: WebRTCTransportInit
|
|
40
|
+
private readonly init: WebRTCTransportInit = {}
|
|
39
41
|
) {
|
|
40
42
|
}
|
|
41
43
|
|
|
@@ -123,6 +125,7 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
123
125
|
const { pc, muxerFactory, remoteAddress } = await initiateConnection({
|
|
124
126
|
stream: signalingStream,
|
|
125
127
|
rtcConfiguration: this.init.rtcConfiguration,
|
|
128
|
+
dataChannelOptions: this.init.dataChannel,
|
|
126
129
|
signal: options.signal
|
|
127
130
|
})
|
|
128
131
|
|
|
@@ -154,7 +157,8 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
154
157
|
const { pc, muxerFactory, remoteAddress } = await handleIncomingStream({
|
|
155
158
|
rtcConfiguration: this.init.rtcConfiguration,
|
|
156
159
|
connection,
|
|
157
|
-
stream
|
|
160
|
+
stream,
|
|
161
|
+
dataChannelOptions: this.init.dataChannel
|
|
158
162
|
})
|
|
159
163
|
|
|
160
164
|
await this.components.upgrader.upgradeInbound(new WebRTCMultiaddrConnection({
|
|
@@ -9,11 +9,12 @@ import { fromString as uint8arrayFromString } from 'uint8arrays/from-string'
|
|
|
9
9
|
import { dataChannelError, inappropriateMultiaddr, unimplemented, invalidArgument } from '../error.js'
|
|
10
10
|
import { WebRTCMultiaddrConnection } from '../maconn.js'
|
|
11
11
|
import { DataChannelMuxerFactory } from '../muxer.js'
|
|
12
|
-
import {
|
|
12
|
+
import { createStream } from '../stream.js'
|
|
13
13
|
import { isFirefox } from '../util.js'
|
|
14
14
|
import * as sdp from './sdp.js'
|
|
15
15
|
import { genUfrag } from './util.js'
|
|
16
16
|
import type { WebRTCDialOptions } from './options.js'
|
|
17
|
+
import type { DataChannelOpts } from '../stream.js'
|
|
17
18
|
import type { Connection } from '@libp2p/interface-connection'
|
|
18
19
|
import type { CounterGroup, Metrics } from '@libp2p/interface-metrics'
|
|
19
20
|
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
@@ -52,12 +53,17 @@ export interface WebRTCMetrics {
|
|
|
52
53
|
dialerEvents: CounterGroup
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
export interface WebRTCTransportDirectInit {
|
|
57
|
+
dataChannel?: Partial<DataChannelOpts>
|
|
58
|
+
}
|
|
59
|
+
|
|
55
60
|
export class WebRTCDirectTransport implements Transport {
|
|
56
61
|
private readonly metrics?: WebRTCMetrics
|
|
57
62
|
private readonly components: WebRTCDirectTransportComponents
|
|
58
|
-
|
|
59
|
-
constructor (components: WebRTCDirectTransportComponents) {
|
|
63
|
+
private readonly init: WebRTCTransportDirectInit
|
|
64
|
+
constructor (components: WebRTCDirectTransportComponents, init: WebRTCTransportDirectInit = {}) {
|
|
60
65
|
this.components = components
|
|
66
|
+
this.init = init
|
|
61
67
|
if (components.metrics != null) {
|
|
62
68
|
this.metrics = {
|
|
63
69
|
dialerEvents: components.metrics.registerCounterGroup('libp2p_webrtc_dialer_events_total', {
|
|
@@ -185,7 +191,7 @@ export class WebRTCDirectTransport implements Transport {
|
|
|
185
191
|
// we pass in undefined for these parameters.
|
|
186
192
|
const noise = Noise({ prologueBytes: fingerprintsPrologue })()
|
|
187
193
|
|
|
188
|
-
const wrappedChannel =
|
|
194
|
+
const wrappedChannel = createStream({ channel: handshakeDataChannel, direction: 'inbound', dataChannelOptions: this.init.dataChannel })
|
|
189
195
|
const wrappedDuplex = {
|
|
190
196
|
...wrappedChannel,
|
|
191
197
|
sink: wrappedChannel.sink.bind(wrappedChannel),
|
|
@@ -231,7 +237,7 @@ export class WebRTCDirectTransport implements Transport {
|
|
|
231
237
|
// Track opened peer connection
|
|
232
238
|
this.metrics?.dialerEvents.increment({ peer_connection: true })
|
|
233
239
|
|
|
234
|
-
const muxerFactory = new DataChannelMuxerFactory(peerConnection, this.metrics?.dialerEvents)
|
|
240
|
+
const muxerFactory = new DataChannelMuxerFactory({ peerConnection, metrics: this.metrics?.dialerEvents, dataChannelOptions: this.init.dataChannel })
|
|
235
241
|
|
|
236
242
|
// For outbound connections, the remote is expected to start the noise handshake.
|
|
237
243
|
// Therefore, we need to secure an inbound noise connection from the remote.
|