@libp2p/webrtc 5.2.24-a02cb0461 → 5.2.24-f5932c294
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 +20 -10
- package/dist/index.min.js +14 -14
- package/dist/index.min.js.map +4 -4
- package/dist/src/constants.d.ts +15 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +15 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +22 -12
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +22 -12
- package/dist/src/index.js.map +1 -1
- package/dist/src/maconn.d.ts +58 -0
- package/dist/src/maconn.d.ts.map +1 -0
- package/dist/src/maconn.js +56 -0
- package/dist/src/maconn.js.map +1 -0
- package/dist/src/muxer.d.ts +46 -14
- package/dist/src/muxer.d.ts.map +1 -1
- package/dist/src/muxer.js +135 -32
- package/dist/src/muxer.js.map +1 -1
- package/dist/src/private-to-private/initiate-connection.d.ts +4 -3
- package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
- package/dist/src/private-to-private/initiate-connection.js +5 -23
- package/dist/src/private-to-private/initiate-connection.js.map +1 -1
- package/dist/src/private-to-private/signaling-stream-handler.d.ts +4 -4
- package/dist/src/private-to-private/signaling-stream-handler.d.ts.map +1 -1
- package/dist/src/private-to-private/signaling-stream-handler.js +6 -10
- package/dist/src/private-to-private/signaling-stream-handler.js.map +1 -1
- package/dist/src/private-to-private/transport.d.ts +2 -2
- package/dist/src/private-to-private/transport.d.ts.map +1 -1
- package/dist/src/private-to-private/transport.js +15 -30
- package/dist/src/private-to-private/transport.js.map +1 -1
- package/dist/src/private-to-private/util.d.ts +1 -3
- package/dist/src/private-to-private/util.d.ts.map +1 -1
- package/dist/src/private-to-private/util.js +3 -15
- package/dist/src/private-to-private/util.js.map +1 -1
- package/dist/src/private-to-public/listener.js +2 -2
- package/dist/src/private-to-public/listener.js.map +1 -1
- package/dist/src/private-to-public/transport.js +1 -1
- package/dist/src/private-to-public/transport.js.map +1 -1
- package/dist/src/private-to-public/utils/connect.d.ts +1 -1
- package/dist/src/private-to-public/utils/connect.d.ts.map +1 -1
- package/dist/src/private-to-public/utils/connect.js +14 -17
- package/dist/src/private-to-public/utils/connect.js.map +1 -1
- package/dist/src/private-to-public/utils/get-rtcpeerconnection.d.ts +4 -4
- package/dist/src/private-to-public/utils/get-rtcpeerconnection.d.ts.map +1 -1
- package/dist/src/private-to-public/utils/get-rtcpeerconnection.js +2 -13
- package/dist/src/private-to-public/utils/get-rtcpeerconnection.js.map +1 -1
- package/dist/src/private-to-public/utils/sdp.d.ts.map +1 -1
- package/dist/src/private-to-public/utils/sdp.js +3 -8
- package/dist/src/private-to-public/utils/sdp.js.map +1 -1
- package/dist/src/private-to-public/utils/stun-listener.js +1 -1
- package/dist/src/private-to-public/utils/stun-listener.js.map +1 -1
- package/dist/src/stream.d.ts +26 -13
- package/dist/src/stream.d.ts.map +1 -1
- package/dist/src/stream.js +166 -64
- package/dist/src/stream.js.map +1 -1
- package/dist/src/util.d.ts +1 -3
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +0 -19
- package/dist/src/util.js.map +1 -1
- package/dist/src/webrtc/index.d.ts +1 -1
- package/dist/src/webrtc/index.d.ts.map +1 -1
- package/dist/src/webrtc/index.js +1 -1
- package/dist/src/webrtc/index.js.map +1 -1
- package/package.json +29 -26
- package/src/constants.ts +18 -0
- package/src/index.ts +22 -12
- package/src/maconn.ts +101 -0
- package/src/muxer.ts +166 -43
- package/src/private-to-private/initiate-connection.ts +9 -31
- package/src/private-to-private/signaling-stream-handler.ts +9 -12
- package/src/private-to-private/transport.ts +17 -33
- package/src/private-to-private/util.ts +4 -21
- package/src/private-to-public/listener.ts +2 -2
- package/src/private-to-public/transport.ts +1 -1
- package/src/private-to-public/utils/connect.ts +15 -18
- package/src/private-to-public/utils/get-rtcpeerconnection.ts +4 -16
- package/src/private-to-public/utils/sdp.ts +3 -8
- package/src/private-to-public/utils/stun-listener.ts +1 -1
- package/src/stream.ts +194 -74
- package/src/util.ts +1 -22
- package/src/webrtc/index.ts +1 -1
- package/dist/src/rtcpeerconnection-to-conn.d.ts +0 -12
- package/dist/src/rtcpeerconnection-to-conn.d.ts.map +0 -1
- package/dist/src/rtcpeerconnection-to-conn.js +0 -43
- package/dist/src/rtcpeerconnection-to-conn.js.map +0 -1
- package/src/rtcpeerconnection-to-conn.ts +0 -62
package/src/index.ts
CHANGED
@@ -26,8 +26,8 @@
|
|
26
26
|
* WebRTC requires use of a relay to connect two nodes. The listener first discovers a relay server and makes a reservation, then the dialer can connect via the relayed address.
|
27
27
|
*
|
28
28
|
* ```TypeScript
|
29
|
-
* import { noise } from '@libp2p
|
30
|
-
* import { yamux } from '@libp2p
|
29
|
+
* import { noise } from '@chainsafe/libp2p-noise'
|
30
|
+
* import { yamux } from '@chainsafe/libp2p-yamux'
|
31
31
|
* import { echo } from '@libp2p/echo'
|
32
32
|
* import { circuitRelayTransport, circuitRelayServer } from '@libp2p/circuit-relay-v2'
|
33
33
|
* import { identify } from '@libp2p/identify'
|
@@ -35,6 +35,7 @@
|
|
35
35
|
* import { webSockets } from '@libp2p/websockets'
|
36
36
|
* import { WebRTC } from '@multiformats/multiaddr-matcher'
|
37
37
|
* import delay from 'delay'
|
38
|
+
* import { pipe } from 'it-pipe'
|
38
39
|
* import { createLibp2p } from 'libp2p'
|
39
40
|
* import type { Multiaddr } from '@multiformats/multiaddr'
|
40
41
|
*
|
@@ -133,11 +134,15 @@
|
|
133
134
|
* await relay.stop()
|
134
135
|
*
|
135
136
|
* // send/receive some data from the remote peer via a direct connection
|
136
|
-
*
|
137
|
-
*
|
138
|
-
*
|
139
|
-
*
|
140
|
-
*
|
137
|
+
* await pipe(
|
138
|
+
* [new TextEncoder().encode('hello world')],
|
139
|
+
* stream,
|
140
|
+
* async source => {
|
141
|
+
* for await (const buf of source) {
|
142
|
+
* console.info(new TextDecoder().decode(buf.subarray()))
|
143
|
+
* }
|
144
|
+
* }
|
145
|
+
* )
|
141
146
|
* ```
|
142
147
|
*
|
143
148
|
* @example WebRTC Direct
|
@@ -162,6 +167,7 @@
|
|
162
167
|
* ```TypeScript
|
163
168
|
* import { createLibp2p } from 'libp2p'
|
164
169
|
* import { multiaddr } from '@multiformats/multiaddr'
|
170
|
+
* import { pipe } from 'it-pipe'
|
165
171
|
* import { fromString, toString } from 'uint8arrays'
|
166
172
|
* import { webRTCDirect } from '@libp2p/webrtc'
|
167
173
|
*
|
@@ -190,11 +196,15 @@
|
|
190
196
|
* signal: AbortSignal.timeout(10_000)
|
191
197
|
* })
|
192
198
|
*
|
193
|
-
*
|
194
|
-
*
|
195
|
-
*
|
196
|
-
*
|
197
|
-
*
|
199
|
+
* await pipe(
|
200
|
+
* [fromString(`Hello js-libp2p-webrtc\n`)],
|
201
|
+
* stream,
|
202
|
+
* async function (source) {
|
203
|
+
* for await (const buf of source) {
|
204
|
+
* console.info(toString(buf.subarray()))
|
205
|
+
* }
|
206
|
+
* }
|
207
|
+
* )
|
198
208
|
* ```
|
199
209
|
*
|
200
210
|
* ## WebRTC Direct certificate hashes
|
package/src/maconn.ts
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
import { nopSink, nopSource } from './util.js'
|
2
|
+
import type { RTCPeerConnection } from './webrtc/index.js'
|
3
|
+
import type { ComponentLogger, Logger, MultiaddrConnection, MultiaddrConnectionTimeline, CounterGroup } from '@libp2p/interface'
|
4
|
+
import type { AbortOptions, Multiaddr } from '@multiformats/multiaddr'
|
5
|
+
import type { Source, Sink } from 'it-stream-types'
|
6
|
+
import type { Uint8ArrayList } from 'uint8arraylist'
|
7
|
+
|
8
|
+
interface WebRTCMultiaddrConnectionInit {
|
9
|
+
/**
|
10
|
+
* WebRTC Peer Connection
|
11
|
+
*/
|
12
|
+
peerConnection: RTCPeerConnection
|
13
|
+
|
14
|
+
/**
|
15
|
+
* The multiaddr address used to communicate with the remote peer
|
16
|
+
*/
|
17
|
+
remoteAddr: Multiaddr
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Holds the relevant events timestamps of the connection
|
21
|
+
*/
|
22
|
+
timeline: MultiaddrConnectionTimeline
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Optional metrics counter group for this connection
|
26
|
+
*/
|
27
|
+
metrics?: CounterGroup
|
28
|
+
}
|
29
|
+
|
30
|
+
export interface WebRTCMultiaddrConnectionComponents {
|
31
|
+
logger: ComponentLogger
|
32
|
+
}
|
33
|
+
|
34
|
+
export class WebRTCMultiaddrConnection implements MultiaddrConnection {
|
35
|
+
readonly log: Logger
|
36
|
+
|
37
|
+
/**
|
38
|
+
* WebRTC Peer Connection
|
39
|
+
*/
|
40
|
+
readonly peerConnection: RTCPeerConnection
|
41
|
+
|
42
|
+
/**
|
43
|
+
* The multiaddr address used to communicate with the remote peer
|
44
|
+
*/
|
45
|
+
remoteAddr: Multiaddr
|
46
|
+
|
47
|
+
/**
|
48
|
+
* Holds the life cycle times of the connection
|
49
|
+
*/
|
50
|
+
timeline: MultiaddrConnectionTimeline
|
51
|
+
|
52
|
+
/**
|
53
|
+
* Optional metrics counter group for this connection
|
54
|
+
*/
|
55
|
+
metrics?: CounterGroup
|
56
|
+
|
57
|
+
/**
|
58
|
+
* The stream source, a no-op as the transport natively supports multiplexing
|
59
|
+
*/
|
60
|
+
source: AsyncGenerator<Uint8Array, any, unknown> = nopSource()
|
61
|
+
|
62
|
+
/**
|
63
|
+
* The stream destination, a no-op as the transport natively supports multiplexing
|
64
|
+
*/
|
65
|
+
sink: Sink<Source<Uint8Array | Uint8ArrayList>, Promise<void>> = nopSink
|
66
|
+
|
67
|
+
constructor (components: WebRTCMultiaddrConnectionComponents, init: WebRTCMultiaddrConnectionInit) {
|
68
|
+
this.log = components.logger.forComponent('libp2p:webrtc:maconn')
|
69
|
+
this.remoteAddr = init.remoteAddr
|
70
|
+
this.timeline = init.timeline
|
71
|
+
this.peerConnection = init.peerConnection
|
72
|
+
|
73
|
+
const peerConnection = this.peerConnection
|
74
|
+
const initialState = peerConnection.connectionState
|
75
|
+
|
76
|
+
this.peerConnection.onconnectionstatechange = () => {
|
77
|
+
this.log.trace('peer connection state change', peerConnection.connectionState, 'initial state', initialState)
|
78
|
+
|
79
|
+
if (peerConnection.connectionState === 'disconnected' || peerConnection.connectionState === 'failed' || peerConnection.connectionState === 'closed') {
|
80
|
+
// nothing else to do but close the connection
|
81
|
+
this.timeline.close = Date.now()
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
async close (options?: AbortOptions): Promise<void> {
|
87
|
+
this.log.trace('closing connection')
|
88
|
+
|
89
|
+
this.peerConnection.close()
|
90
|
+
this.timeline.close = Date.now()
|
91
|
+
this.metrics?.increment({ close: true })
|
92
|
+
}
|
93
|
+
|
94
|
+
abort (err: Error): void {
|
95
|
+
this.log.error('closing connection due to error', err)
|
96
|
+
|
97
|
+
this.peerConnection.close()
|
98
|
+
this.timeline.close = Date.now()
|
99
|
+
this.metrics?.increment({ abort: true })
|
100
|
+
}
|
101
|
+
}
|
package/src/muxer.ts
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
-
import { AbstractStreamMuxer } from '@libp2p/utils'
|
2
|
-
import { pEvent } from 'p-event'
|
3
1
|
import { MUXER_PROTOCOL } from './constants.js'
|
4
|
-
import { createStream
|
2
|
+
import { createStream } from './stream.js'
|
3
|
+
import { drainAndClose, nopSink, nopSource } from './util.js'
|
5
4
|
import type { DataChannelOptions } from './index.js'
|
6
|
-
import type { ComponentLogger, CounterGroup, StreamMuxer, StreamMuxerFactory,
|
5
|
+
import type { ComponentLogger, Logger, Stream, CounterGroup, StreamMuxer, StreamMuxerFactory, StreamMuxerInit } from '@libp2p/interface'
|
6
|
+
import type { AbortOptions } from '@multiformats/multiaddr'
|
7
|
+
import type { Source, Sink } from 'it-stream-types'
|
8
|
+
import type { Uint8ArrayList } from 'uint8arraylist'
|
7
9
|
|
8
10
|
export interface DataChannelMuxerFactoryInit {
|
9
11
|
/**
|
@@ -21,9 +23,6 @@ export interface DataChannelMuxerFactoryInit {
|
|
21
23
|
*/
|
22
24
|
metrics?: CounterGroup
|
23
25
|
|
24
|
-
/**
|
25
|
-
* Options used to create data channels
|
26
|
-
*/
|
27
26
|
dataChannelOptions?: DataChannelOptions
|
28
27
|
}
|
29
28
|
|
@@ -31,6 +30,12 @@ export interface DataChannelMuxerFactoryComponents {
|
|
31
30
|
logger: ComponentLogger
|
32
31
|
}
|
33
32
|
|
33
|
+
interface BufferedStream {
|
34
|
+
stream: Stream
|
35
|
+
channel: RTCDataChannel
|
36
|
+
onEnd(err?: Error): void
|
37
|
+
}
|
38
|
+
|
34
39
|
export class DataChannelMuxerFactory implements StreamMuxerFactory {
|
35
40
|
public readonly protocol: string
|
36
41
|
|
@@ -38,28 +43,69 @@ export class DataChannelMuxerFactory implements StreamMuxerFactory {
|
|
38
43
|
* WebRTC Peer Connection
|
39
44
|
*/
|
40
45
|
private readonly peerConnection: RTCPeerConnection
|
46
|
+
private bufferedStreams: BufferedStream[] = []
|
41
47
|
private readonly metrics?: CounterGroup
|
42
48
|
private readonly dataChannelOptions?: DataChannelOptions
|
49
|
+
private readonly components: DataChannelMuxerFactoryComponents
|
50
|
+
private readonly log: Logger
|
43
51
|
|
44
|
-
constructor (init: DataChannelMuxerFactoryInit) {
|
52
|
+
constructor (components: DataChannelMuxerFactoryComponents, init: DataChannelMuxerFactoryInit) {
|
53
|
+
this.components = components
|
45
54
|
this.peerConnection = init.peerConnection
|
46
55
|
this.metrics = init.metrics
|
47
56
|
this.protocol = init.protocol ?? MUXER_PROTOCOL
|
48
57
|
this.dataChannelOptions = init.dataChannelOptions ?? {}
|
58
|
+
this.log = components.logger.forComponent('libp2p:webrtc:muxerfactory')
|
59
|
+
|
60
|
+
// store any data channels opened before upgrade has been completed
|
61
|
+
this.peerConnection.ondatachannel = ({ channel }) => {
|
62
|
+
this.log.trace('incoming early datachannel with channel id %d and label "%s"', channel.id)
|
63
|
+
|
64
|
+
// 'init' channel is only used during connection establishment
|
65
|
+
if (channel.label === 'init') {
|
66
|
+
this.log.trace('closing early init channel')
|
67
|
+
channel.close()
|
68
|
+
|
69
|
+
return
|
70
|
+
}
|
71
|
+
|
72
|
+
// @ts-expect-error fields are set below
|
73
|
+
const bufferedStream: BufferedStream = {}
|
74
|
+
|
75
|
+
const stream = createStream({
|
76
|
+
channel,
|
77
|
+
direction: 'inbound',
|
78
|
+
onEnd: (err) => {
|
79
|
+
bufferedStream.onEnd(err)
|
80
|
+
},
|
81
|
+
log: this.log,
|
82
|
+
...this.dataChannelOptions
|
83
|
+
})
|
84
|
+
|
85
|
+
bufferedStream.stream = stream
|
86
|
+
bufferedStream.channel = channel
|
87
|
+
bufferedStream.onEnd = () => {
|
88
|
+
this.bufferedStreams = this.bufferedStreams.filter(s => s.stream.id !== stream.id)
|
89
|
+
}
|
90
|
+
|
91
|
+
this.bufferedStreams.push(bufferedStream)
|
92
|
+
}
|
49
93
|
}
|
50
94
|
|
51
|
-
createStreamMuxer (
|
52
|
-
return new DataChannelMuxer(
|
95
|
+
createStreamMuxer (init?: StreamMuxerInit): StreamMuxer {
|
96
|
+
return new DataChannelMuxer(this.components, {
|
97
|
+
...init,
|
53
98
|
peerConnection: this.peerConnection,
|
54
99
|
dataChannelOptions: this.dataChannelOptions,
|
55
100
|
metrics: this.metrics,
|
101
|
+
streams: this.bufferedStreams,
|
56
102
|
protocol: this.protocol
|
57
103
|
})
|
58
104
|
}
|
59
105
|
}
|
60
106
|
|
61
|
-
export interface DataChannelMuxerInit extends DataChannelMuxerFactoryInit {
|
62
|
-
|
107
|
+
export interface DataChannelMuxerInit extends DataChannelMuxerFactoryInit, StreamMuxerInit {
|
108
|
+
streams: BufferedStream[]
|
63
109
|
}
|
64
110
|
|
65
111
|
export interface DataChannelMuxerComponents {
|
@@ -69,18 +115,26 @@ export interface DataChannelMuxerComponents {
|
|
69
115
|
/**
|
70
116
|
* A libp2p data channel stream muxer
|
71
117
|
*/
|
72
|
-
export class DataChannelMuxer
|
118
|
+
export class DataChannelMuxer implements StreamMuxer {
|
119
|
+
/**
|
120
|
+
* Array of streams in the data channel
|
121
|
+
*/
|
122
|
+
public streams: Stream[]
|
123
|
+
public protocol: string
|
124
|
+
|
125
|
+
private readonly log: Logger
|
73
126
|
private readonly peerConnection: RTCPeerConnection
|
74
127
|
private readonly dataChannelOptions: DataChannelOptions
|
128
|
+
private readonly metrics?: CounterGroup
|
129
|
+
private readonly logger: ComponentLogger
|
75
130
|
|
76
|
-
constructor (
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
})
|
81
|
-
|
131
|
+
constructor (components: DataChannelMuxerComponents, readonly init: DataChannelMuxerInit) {
|
132
|
+
this.log = init.log?.newScope('muxer') ?? components.logger.forComponent('libp2p:webrtc:muxer')
|
133
|
+
this.logger = components.logger
|
134
|
+
this.streams = init.streams.map(s => s.stream)
|
82
135
|
this.peerConnection = init.peerConnection
|
83
136
|
this.protocol = init.protocol ?? MUXER_PROTOCOL
|
137
|
+
this.metrics = init.metrics
|
84
138
|
this.dataChannelOptions = init.dataChannelOptions ?? {}
|
85
139
|
|
86
140
|
/**
|
@@ -90,7 +144,7 @@ export class DataChannelMuxer extends AbstractStreamMuxer<WebRTCStream> implemen
|
|
90
144
|
* {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event}
|
91
145
|
*/
|
92
146
|
this.peerConnection.ondatachannel = ({ channel }) => {
|
93
|
-
this.log.trace('incoming
|
147
|
+
this.log.trace('incoming datachannel with channel id %d', channel.id)
|
94
148
|
|
95
149
|
// 'init' channel is only used during connection establishment
|
96
150
|
if (channel.label === 'init') {
|
@@ -100,46 +154,115 @@ export class DataChannelMuxer extends AbstractStreamMuxer<WebRTCStream> implemen
|
|
100
154
|
return
|
101
155
|
}
|
102
156
|
|
157
|
+
// lib-datachannel throws if `.getId` is called on a closed channel so
|
158
|
+
// memoize it
|
159
|
+
const id = channel.id
|
160
|
+
|
103
161
|
const stream = createStream({
|
104
|
-
...this.streamOptions,
|
105
|
-
...this.dataChannelOptions,
|
106
162
|
channel,
|
107
163
|
direction: 'inbound',
|
108
|
-
|
164
|
+
onEnd: () => {
|
165
|
+
this.#onStreamEnd(stream, channel)
|
166
|
+
this.log('incoming channel %s ended', id)
|
167
|
+
},
|
168
|
+
log: this.log,
|
169
|
+
...this.dataChannelOptions
|
109
170
|
})
|
110
171
|
|
111
|
-
this.
|
172
|
+
this.streams.push(stream)
|
173
|
+
this.metrics?.increment({ incoming_stream: true })
|
174
|
+
init?.onIncomingStream?.(stream)
|
112
175
|
}
|
113
|
-
}
|
114
176
|
|
115
|
-
|
116
|
-
//
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
177
|
+
// the DataChannelMuxer constructor is called during set up of the
|
178
|
+
// connection by the upgrader.
|
179
|
+
//
|
180
|
+
// If we invoke `init.onIncomingStream` immediately, the connection object
|
181
|
+
// will not be set up yet so add a tiny delay before letting the
|
182
|
+
// connection know about early streams
|
183
|
+
if (this.init.streams.length > 0) {
|
184
|
+
queueMicrotask(() => {
|
185
|
+
this.init.streams.forEach(bufferedStream => {
|
186
|
+
bufferedStream.onEnd = () => {
|
187
|
+
this.log('incoming early channel %s ended with state %s', bufferedStream.channel.id, bufferedStream.channel.readyState)
|
188
|
+
this.#onStreamEnd(bufferedStream.stream, bufferedStream.channel)
|
189
|
+
}
|
190
|
+
|
191
|
+
this.metrics?.increment({ incoming_stream: true })
|
192
|
+
this.init?.onIncomingStream?.(bufferedStream.stream)
|
193
|
+
})
|
194
|
+
})
|
195
|
+
}
|
196
|
+
}
|
121
197
|
|
122
|
-
|
198
|
+
#onStreamEnd (stream: Stream, channel: RTCDataChannel): void {
|
199
|
+
this.log.trace('stream %s %s %s onEnd', stream.direction, stream.id, stream.protocol)
|
200
|
+
drainAndClose(
|
201
|
+
channel,
|
202
|
+
`${stream.direction} ${stream.id} ${stream.protocol}`,
|
203
|
+
this.dataChannelOptions.drainTimeout, {
|
204
|
+
log: this.log
|
205
|
+
}
|
206
|
+
)
|
207
|
+
this.streams = this.streams.filter(s => s.id !== stream.id)
|
208
|
+
this.metrics?.increment({ stream_end: true })
|
209
|
+
this.init?.onStreamEnd?.(stream)
|
210
|
+
}
|
123
211
|
|
124
|
-
|
125
|
-
|
126
|
-
|
212
|
+
/**
|
213
|
+
* Gracefully close all tracked streams and stop the muxer
|
214
|
+
*/
|
215
|
+
async close (options?: AbortOptions): Promise<void> {
|
216
|
+
try {
|
217
|
+
await Promise.all(
|
218
|
+
this.streams.map(async stream => stream.close(options))
|
219
|
+
)
|
220
|
+
} catch (err: any) {
|
221
|
+
this.abort(err)
|
222
|
+
}
|
223
|
+
}
|
127
224
|
|
128
|
-
|
225
|
+
/**
|
226
|
+
* Abort all tracked streams and stop the muxer
|
227
|
+
*/
|
228
|
+
abort (err: Error): void {
|
229
|
+
for (const stream of this.streams) {
|
230
|
+
stream.abort(err)
|
129
231
|
}
|
232
|
+
}
|
233
|
+
|
234
|
+
/**
|
235
|
+
* The stream source, a no-op as the transport natively supports multiplexing
|
236
|
+
*/
|
237
|
+
source: AsyncGenerator<Uint8Array, any, unknown> = nopSource()
|
238
|
+
|
239
|
+
/**
|
240
|
+
* The stream destination, a no-op as the transport natively supports multiplexing
|
241
|
+
*/
|
242
|
+
sink: Sink<Source<Uint8Array | Uint8ArrayList>, Promise<void>> = nopSink
|
243
|
+
|
244
|
+
newStream (): Stream {
|
245
|
+
// The spec says the label MUST be an empty string: https://github.com/libp2p/specs/blob/master/webrtc/README.md#rtcdatachannel-label
|
246
|
+
const channel = this.peerConnection.createDataChannel('')
|
247
|
+
// lib-datachannel throws if `.getId` is called on a closed channel so
|
248
|
+
// memoize it
|
249
|
+
const id = channel.id
|
250
|
+
|
251
|
+
this.log.trace('opened outgoing datachannel with channel id %s', id)
|
130
252
|
|
131
253
|
const stream = createStream({
|
132
|
-
...options,
|
133
|
-
...this.dataChannelOptions,
|
134
254
|
channel,
|
135
255
|
direction: 'outbound',
|
136
|
-
|
256
|
+
onEnd: () => {
|
257
|
+
this.#onStreamEnd(stream, channel)
|
258
|
+
this.log('outgoing channel %s ended', id)
|
259
|
+
},
|
260
|
+
log: this.log,
|
261
|
+
...this.dataChannelOptions
|
137
262
|
})
|
263
|
+
this.streams.push(stream)
|
264
|
+
this.metrics?.increment({ outgoing_stream: true })
|
138
265
|
|
139
266
|
return stream
|
140
267
|
}
|
141
|
-
|
142
|
-
onData (): void {
|
143
|
-
|
144
|
-
}
|
145
268
|
}
|
@@ -1,5 +1,4 @@
|
|
1
|
-
import { pbStream } from '
|
2
|
-
import { pEvent } from 'p-event'
|
1
|
+
import { pbStream } from 'it-protobuf-stream'
|
3
2
|
import { CustomProgressEvent } from 'progress-events'
|
4
3
|
import { SIGNALING_PROTOCOL } from '../constants.js'
|
5
4
|
import { SDPHandshakeFailedError } from '../error.js'
|
@@ -10,14 +9,15 @@ import { splitAddr } from './transport.js'
|
|
10
9
|
import { readCandidatesUntilConnected } from './util.js'
|
11
10
|
import type { WebRTCDialEvents, WebRTCTransportMetrics } from './transport.js'
|
12
11
|
import type { DataChannelOptions } from '../index.js'
|
13
|
-
import type { LoggerOptions, Connection, ComponentLogger } from '@libp2p/interface'
|
12
|
+
import type { LoggerOptions, Connection, ComponentLogger, IncomingStreamData } from '@libp2p/interface'
|
14
13
|
import type { ConnectionManager, TransportManager } from '@libp2p/interface-internal'
|
15
|
-
import type {
|
14
|
+
import type { Multiaddr } from '@multiformats/multiaddr'
|
16
15
|
import type { ProgressOptions } from 'progress-events'
|
17
16
|
|
18
|
-
export interface
|
17
|
+
export interface IncomingStreamOpts extends IncomingStreamData {
|
19
18
|
rtcConfiguration?: RTCConfiguration
|
20
19
|
dataChannelOptions?: Partial<DataChannelOptions>
|
20
|
+
signal: AbortSignal
|
21
21
|
}
|
22
22
|
|
23
23
|
export interface ConnectOptions extends LoggerOptions, ProgressOptions<WebRTCDialEvents> {
|
@@ -67,21 +67,9 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa
|
|
67
67
|
|
68
68
|
const messageStream = pbStream(stream).pb(Message)
|
69
69
|
const peerConnection = new RTCPeerConnection(rtcConfiguration)
|
70
|
-
|
71
|
-
// make sure C++ peer connection is garbage collected
|
72
|
-
// https://github.com/murat-dogan/node-datachannel/issues/366#issuecomment-3228453155
|
73
|
-
peerConnection.addEventListener('connectionstatechange', () => {
|
74
|
-
switch (peerConnection.connectionState) {
|
75
|
-
case 'closed':
|
76
|
-
peerConnection.close()
|
77
|
-
break
|
78
|
-
default:
|
79
|
-
break
|
80
|
-
}
|
81
|
-
})
|
82
|
-
|
83
70
|
const muxerFactory = new DataChannelMuxerFactory({
|
84
|
-
|
71
|
+
logger
|
72
|
+
}, {
|
85
73
|
peerConnection,
|
86
74
|
dataChannelOptions: dataChannel
|
87
75
|
})
|
@@ -109,7 +97,7 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa
|
|
109
97
|
signal
|
110
98
|
})
|
111
99
|
.catch(err => {
|
112
|
-
log.error('error sending ICE candidate
|
100
|
+
log.error('error sending ICE candidate', err)
|
113
101
|
})
|
114
102
|
}
|
115
103
|
peerConnection.onicecandidateerror = (event) => {
|
@@ -169,17 +157,7 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa
|
|
169
157
|
onProgress
|
170
158
|
})
|
171
159
|
|
172
|
-
log.trace('initiator connected')
|
173
|
-
|
174
|
-
if (channel.readyState !== 'open') {
|
175
|
-
log.trace('wait for init channel to open')
|
176
|
-
await pEvent(channel, 'open', {
|
177
|
-
signal
|
178
|
-
})
|
179
|
-
}
|
180
|
-
|
181
|
-
log.trace('closing init channel, starting status')
|
182
|
-
|
160
|
+
log.trace('initiator connected, closing init channel')
|
183
161
|
channel.close()
|
184
162
|
|
185
163
|
onProgress?.(new CustomProgressEvent('webrtc:close-signaling-stream'))
|
@@ -1,19 +1,20 @@
|
|
1
|
-
import { pbStream } from '@libp2p/utils'
|
2
1
|
import { multiaddr } from '@multiformats/multiaddr'
|
2
|
+
import { pbStream } from 'it-protobuf-stream'
|
3
3
|
import { SDPHandshakeFailedError } from '../error.js'
|
4
4
|
import { RTCSessionDescription } from '../webrtc/index.js'
|
5
5
|
import { Message } from './pb/message.js'
|
6
|
-
import { getConnectionState,
|
6
|
+
import { getConnectionState, readCandidatesUntilConnected } from './util.js'
|
7
7
|
import type { RTCPeerConnection } from '../webrtc/index.js'
|
8
|
-
import type {
|
8
|
+
import type { Logger, IncomingStreamData } from '@libp2p/interface'
|
9
9
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
10
10
|
|
11
|
-
export interface
|
11
|
+
export interface IncomingStreamOpts extends IncomingStreamData {
|
12
12
|
peerConnection: RTCPeerConnection
|
13
|
+
signal: AbortSignal
|
13
14
|
log: Logger
|
14
15
|
}
|
15
16
|
|
16
|
-
export async function handleIncomingStream (
|
17
|
+
export async function handleIncomingStream ({ peerConnection, stream, signal, connection, log }: IncomingStreamOpts): Promise<{ remoteAddress: Multiaddr }> {
|
17
18
|
log.trace('new inbound signaling stream')
|
18
19
|
|
19
20
|
const messageStream = pbStream(stream).pb(Message)
|
@@ -36,7 +37,7 @@ export async function handleIncomingStream (stream: Stream, connection: Connecti
|
|
36
37
|
signal
|
37
38
|
})
|
38
39
|
.catch(err => {
|
39
|
-
log.error('error sending ICE candidate
|
40
|
+
log.error('error sending ICE candidate', err)
|
40
41
|
})
|
41
42
|
}
|
42
43
|
|
@@ -100,13 +101,9 @@ export async function handleIncomingStream (stream: Stream, connection: Connecti
|
|
100
101
|
}
|
101
102
|
}
|
102
103
|
|
103
|
-
const
|
104
|
-
const remoteAddress = multiaddr(`/webrtc/p2p/${remotePeer}`)
|
104
|
+
const remoteAddress = multiaddr(`/webrtc/p2p/${connection.remoteAddr.getPeerId()}`)
|
105
105
|
|
106
106
|
log.trace('recipient connected to remote address %s', remoteAddress)
|
107
107
|
|
108
|
-
return {
|
109
|
-
remoteAddress,
|
110
|
-
remotePeer
|
111
|
-
}
|
108
|
+
return { remoteAddress }
|
112
109
|
}
|