@libp2p/webrtc 5.2.23 → 5.2.24-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 +10 -20
- package/dist/index.min.js +14 -14
- package/dist/index.min.js.map +4 -4
- package/dist/src/constants.d.ts +0 -15
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +0 -15
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +12 -22
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +12 -22
- package/dist/src/index.js.map +1 -1
- package/dist/src/muxer.d.ts +14 -46
- package/dist/src/muxer.d.ts.map +1 -1
- package/dist/src/muxer.js +32 -135
- package/dist/src/muxer.js.map +1 -1
- package/dist/src/private-to-private/initiate-connection.d.ts +3 -4
- package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
- package/dist/src/private-to-private/initiate-connection.js +23 -5
- 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 +10 -6
- 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 +30 -15
- package/dist/src/private-to-private/transport.js.map +1 -1
- package/dist/src/private-to-private/util.d.ts +3 -1
- package/dist/src/private-to-private/util.d.ts.map +1 -1
- package/dist/src/private-to-private/util.js +15 -3
- 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 +18 -15
- 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 +13 -2
- 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 +8 -3
- 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/rtcpeerconnection-to-conn.d.ts +12 -0
- package/dist/src/rtcpeerconnection-to-conn.d.ts.map +1 -0
- package/dist/src/rtcpeerconnection-to-conn.js +43 -0
- package/dist/src/rtcpeerconnection-to-conn.js.map +1 -0
- package/dist/src/stream.d.ts +16 -26
- package/dist/src/stream.d.ts.map +1 -1
- package/dist/src/stream.js +65 -167
- package/dist/src/stream.js.map +1 -1
- package/dist/src/util.d.ts +3 -1
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +19 -0
- 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 +26 -29
- package/src/constants.ts +0 -18
- package/src/index.ts +12 -22
- package/src/muxer.ts +43 -166
- package/src/private-to-private/initiate-connection.ts +31 -9
- package/src/private-to-private/signaling-stream-handler.ts +12 -9
- package/src/private-to-private/transport.ts +33 -17
- package/src/private-to-private/util.ts +21 -4
- 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 +19 -16
- package/src/private-to-public/utils/get-rtcpeerconnection.ts +16 -4
- package/src/private-to-public/utils/sdp.ts +8 -3
- package/src/private-to-public/utils/stun-listener.ts +1 -1
- package/src/rtcpeerconnection-to-conn.ts +62 -0
- package/src/stream.ts +78 -195
- package/src/util.ts +22 -1
- package/src/webrtc/index.ts +1 -1
- package/dist/src/maconn.d.ts +0 -58
- package/dist/src/maconn.d.ts.map +0 -1
- package/dist/src/maconn.js +0 -56
- package/dist/src/maconn.js.map +0 -1
- package/dist/typedoc-urls.json +0 -14
- package/src/maconn.ts +0 -101
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 '@
|
30
|
-
* import { yamux } from '@
|
29
|
+
* import { noise } from '@libp2p/noise'
|
30
|
+
* import { yamux } from '@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,7 +35,6 @@
|
|
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'
|
39
38
|
* import { createLibp2p } from 'libp2p'
|
40
39
|
* import type { Multiaddr } from '@multiformats/multiaddr'
|
41
40
|
*
|
@@ -134,15 +133,11 @@
|
|
134
133
|
* await relay.stop()
|
135
134
|
*
|
136
135
|
* // send/receive some data from the remote peer via a direct connection
|
137
|
-
*
|
138
|
-
*
|
139
|
-
*
|
140
|
-
*
|
141
|
-
*
|
142
|
-
* console.info(new TextDecoder().decode(buf.subarray()))
|
143
|
-
* }
|
144
|
-
* }
|
145
|
-
* )
|
136
|
+
* stream.send(new TextEncoder().encode('hello world'))
|
137
|
+
*
|
138
|
+
* stream.addEventListener('message', (evt) => {
|
139
|
+
* console.info(new TextDecoder().decode(evt.data.subarray()))
|
140
|
+
* })
|
146
141
|
* ```
|
147
142
|
*
|
148
143
|
* @example WebRTC Direct
|
@@ -167,7 +162,6 @@
|
|
167
162
|
* ```TypeScript
|
168
163
|
* import { createLibp2p } from 'libp2p'
|
169
164
|
* import { multiaddr } from '@multiformats/multiaddr'
|
170
|
-
* import { pipe } from 'it-pipe'
|
171
165
|
* import { fromString, toString } from 'uint8arrays'
|
172
166
|
* import { webRTCDirect } from '@libp2p/webrtc'
|
173
167
|
*
|
@@ -196,15 +190,11 @@
|
|
196
190
|
* signal: AbortSignal.timeout(10_000)
|
197
191
|
* })
|
198
192
|
*
|
199
|
-
*
|
200
|
-
*
|
201
|
-
*
|
202
|
-
*
|
203
|
-
*
|
204
|
-
* console.info(toString(buf.subarray()))
|
205
|
-
* }
|
206
|
-
* }
|
207
|
-
* )
|
193
|
+
* stream.send(new TextEncoder().encode('hello world'))
|
194
|
+
*
|
195
|
+
* stream.addEventListener('message', (evt) => {
|
196
|
+
* console.info(new TextDecoder().decode(evt.data.subarray()))
|
197
|
+
* })
|
208
198
|
* ```
|
209
199
|
*
|
210
200
|
* ## WebRTC Direct certificate hashes
|
package/src/muxer.ts
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
+
import { AbstractStreamMuxer } from '@libp2p/utils'
|
2
|
+
import { pEvent } from 'p-event'
|
1
3
|
import { MUXER_PROTOCOL } from './constants.js'
|
2
|
-
import { createStream } from './stream.js'
|
3
|
-
import { drainAndClose, nopSink, nopSource } from './util.js'
|
4
|
+
import { createStream, WebRTCStream } from './stream.js'
|
4
5
|
import type { DataChannelOptions } from './index.js'
|
5
|
-
import type { ComponentLogger,
|
6
|
-
import type { AbortOptions } from '@multiformats/multiaddr'
|
7
|
-
import type { Source, Sink } from 'it-stream-types'
|
8
|
-
import type { Uint8ArrayList } from 'uint8arraylist'
|
6
|
+
import type { ComponentLogger, CounterGroup, StreamMuxer, StreamMuxerFactory, CreateStreamOptions, MultiaddrConnection } from '@libp2p/interface'
|
9
7
|
|
10
8
|
export interface DataChannelMuxerFactoryInit {
|
11
9
|
/**
|
@@ -23,6 +21,9 @@ export interface DataChannelMuxerFactoryInit {
|
|
23
21
|
*/
|
24
22
|
metrics?: CounterGroup
|
25
23
|
|
24
|
+
/**
|
25
|
+
* Options used to create data channels
|
26
|
+
*/
|
26
27
|
dataChannelOptions?: DataChannelOptions
|
27
28
|
}
|
28
29
|
|
@@ -30,12 +31,6 @@ export interface DataChannelMuxerFactoryComponents {
|
|
30
31
|
logger: ComponentLogger
|
31
32
|
}
|
32
33
|
|
33
|
-
interface BufferedStream {
|
34
|
-
stream: Stream
|
35
|
-
channel: RTCDataChannel
|
36
|
-
onEnd(err?: Error): void
|
37
|
-
}
|
38
|
-
|
39
34
|
export class DataChannelMuxerFactory implements StreamMuxerFactory {
|
40
35
|
public readonly protocol: string
|
41
36
|
|
@@ -43,69 +38,28 @@ export class DataChannelMuxerFactory implements StreamMuxerFactory {
|
|
43
38
|
* WebRTC Peer Connection
|
44
39
|
*/
|
45
40
|
private readonly peerConnection: RTCPeerConnection
|
46
|
-
private bufferedStreams: BufferedStream[] = []
|
47
41
|
private readonly metrics?: CounterGroup
|
48
42
|
private readonly dataChannelOptions?: DataChannelOptions
|
49
|
-
private readonly components: DataChannelMuxerFactoryComponents
|
50
|
-
private readonly log: Logger
|
51
43
|
|
52
|
-
constructor (
|
53
|
-
this.components = components
|
44
|
+
constructor (init: DataChannelMuxerFactoryInit) {
|
54
45
|
this.peerConnection = init.peerConnection
|
55
46
|
this.metrics = init.metrics
|
56
47
|
this.protocol = init.protocol ?? MUXER_PROTOCOL
|
57
48
|
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
|
-
logger: components.logger,
|
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
|
-
}
|
93
49
|
}
|
94
50
|
|
95
|
-
createStreamMuxer (
|
96
|
-
return new DataChannelMuxer(
|
97
|
-
...init,
|
51
|
+
createStreamMuxer (maConn: MultiaddrConnection): StreamMuxer {
|
52
|
+
return new DataChannelMuxer(maConn, {
|
98
53
|
peerConnection: this.peerConnection,
|
99
54
|
dataChannelOptions: this.dataChannelOptions,
|
100
55
|
metrics: this.metrics,
|
101
|
-
streams: this.bufferedStreams,
|
102
56
|
protocol: this.protocol
|
103
57
|
})
|
104
58
|
}
|
105
59
|
}
|
106
60
|
|
107
|
-
export interface DataChannelMuxerInit extends DataChannelMuxerFactoryInit
|
108
|
-
|
61
|
+
export interface DataChannelMuxerInit extends DataChannelMuxerFactoryInit {
|
62
|
+
protocol: string
|
109
63
|
}
|
110
64
|
|
111
65
|
export interface DataChannelMuxerComponents {
|
@@ -115,26 +69,18 @@ export interface DataChannelMuxerComponents {
|
|
115
69
|
/**
|
116
70
|
* A libp2p data channel stream muxer
|
117
71
|
*/
|
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
|
72
|
+
export class DataChannelMuxer extends AbstractStreamMuxer<WebRTCStream> implements StreamMuxer<WebRTCStream> {
|
126
73
|
private readonly peerConnection: RTCPeerConnection
|
127
74
|
private readonly dataChannelOptions: DataChannelOptions
|
128
|
-
private readonly metrics?: CounterGroup
|
129
|
-
private readonly logger: ComponentLogger
|
130
75
|
|
131
|
-
constructor (
|
132
|
-
|
133
|
-
|
134
|
-
|
76
|
+
constructor (maConn: MultiaddrConnection, init: DataChannelMuxerInit) {
|
77
|
+
super(maConn, {
|
78
|
+
...init,
|
79
|
+
name: 'muxer'
|
80
|
+
})
|
81
|
+
|
135
82
|
this.peerConnection = init.peerConnection
|
136
83
|
this.protocol = init.protocol ?? MUXER_PROTOCOL
|
137
|
-
this.metrics = init.metrics
|
138
84
|
this.dataChannelOptions = init.dataChannelOptions ?? {}
|
139
85
|
|
140
86
|
/**
|
@@ -144,7 +90,7 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
144
90
|
* {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event}
|
145
91
|
*/
|
146
92
|
this.peerConnection.ondatachannel = ({ channel }) => {
|
147
|
-
this.log.trace('incoming datachannel with channel id %d', channel.id)
|
93
|
+
this.log.trace('incoming %s datachannel with channel id %d and status', channel.protocol, channel.id, channel.readyState)
|
148
94
|
|
149
95
|
// 'init' channel is only used during connection establishment
|
150
96
|
if (channel.label === 'init') {
|
@@ -154,115 +100,46 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
154
100
|
return
|
155
101
|
}
|
156
102
|
|
157
|
-
// lib-datachannel throws if `.getId` is called on a closed channel so
|
158
|
-
// memoize it
|
159
|
-
const id = channel.id
|
160
|
-
|
161
103
|
const stream = createStream({
|
104
|
+
...this.streamOptions,
|
105
|
+
...this.dataChannelOptions,
|
162
106
|
channel,
|
163
107
|
direction: 'inbound',
|
164
|
-
onEnd: () => {
|
165
|
-
this.#onStreamEnd(stream, channel)
|
166
|
-
this.log('incoming channel %s ended', id)
|
167
|
-
},
|
168
|
-
logger: this.logger,
|
169
|
-
...this.dataChannelOptions
|
170
|
-
})
|
171
|
-
|
172
|
-
this.streams.push(stream)
|
173
|
-
this.metrics?.increment({ incoming_stream: true })
|
174
|
-
init?.onIncomingStream?.(stream)
|
175
|
-
}
|
176
|
-
|
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
|
-
}
|
197
|
-
|
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
108
|
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
|
-
}
|
211
|
-
|
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
|
-
}
|
109
|
+
})
|
224
110
|
|
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)
|
111
|
+
this.onRemoteStream(stream)
|
231
112
|
}
|
232
113
|
}
|
233
114
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
115
|
+
async onCreateStream (options?: CreateStreamOptions): Promise<WebRTCStream> {
|
116
|
+
// The spec says the label MUST be an empty string: https://github.com/libp2p/specs/blob/master/webrtc/README.md#rtcdatachannel-label
|
117
|
+
const channel = this.peerConnection.createDataChannel('wtf', {
|
118
|
+
// TODO: pre-negotiate stream protocol
|
119
|
+
protocol: options?.protocol
|
120
|
+
})
|
238
121
|
|
239
|
-
|
240
|
-
* The stream destination, a no-op as the transport natively supports multiplexing
|
241
|
-
*/
|
242
|
-
sink: Sink<Source<Uint8Array | Uint8ArrayList>, Promise<void>> = nopSink
|
122
|
+
this.log('open channel %d for protocol %s', channel.id, options?.protocol)
|
243
123
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
// lib-datachannel throws if `.getId` is called on a closed channel so
|
248
|
-
// memoize it
|
249
|
-
const id = channel.id
|
124
|
+
if (channel.readyState !== 'open') {
|
125
|
+
this.log('channel %d state is "%s" and not "open", waiting for "open" event before sending data', channel.id, channel.readyState)
|
126
|
+
await pEvent(channel, 'open', options)
|
250
127
|
|
251
|
-
|
128
|
+
this.log('channel %d state is now "%s", sending data', channel.id, channel.readyState)
|
129
|
+
}
|
252
130
|
|
253
131
|
const stream = createStream({
|
132
|
+
...options,
|
133
|
+
...this.dataChannelOptions,
|
254
134
|
channel,
|
255
135
|
direction: 'outbound',
|
256
|
-
|
257
|
-
this.#onStreamEnd(stream, channel)
|
258
|
-
this.log('outgoing channel %s ended', id)
|
259
|
-
},
|
260
|
-
logger: this.logger,
|
261
|
-
...this.dataChannelOptions
|
136
|
+
log: this.log
|
262
137
|
})
|
263
|
-
this.streams.push(stream)
|
264
|
-
this.metrics?.increment({ outgoing_stream: true })
|
265
138
|
|
266
139
|
return stream
|
267
140
|
}
|
141
|
+
|
142
|
+
onData (): void {
|
143
|
+
|
144
|
+
}
|
268
145
|
}
|
@@ -1,4 +1,5 @@
|
|
1
|
-
import { pbStream } from '
|
1
|
+
import { pbStream } from '@libp2p/utils'
|
2
|
+
import { pEvent } from 'p-event'
|
2
3
|
import { CustomProgressEvent } from 'progress-events'
|
3
4
|
import { SIGNALING_PROTOCOL } from '../constants.js'
|
4
5
|
import { SDPHandshakeFailedError } from '../error.js'
|
@@ -9,15 +10,14 @@ import { splitAddr } from './transport.js'
|
|
9
10
|
import { readCandidatesUntilConnected } from './util.js'
|
10
11
|
import type { WebRTCDialEvents, WebRTCTransportMetrics } from './transport.js'
|
11
12
|
import type { DataChannelOptions } from '../index.js'
|
12
|
-
import type { LoggerOptions, Connection, ComponentLogger
|
13
|
+
import type { LoggerOptions, Connection, ComponentLogger } from '@libp2p/interface'
|
13
14
|
import type { ConnectionManager, TransportManager } from '@libp2p/interface-internal'
|
14
|
-
import type { Multiaddr } from '@multiformats/multiaddr'
|
15
|
+
import type { AbortOptions, Multiaddr } from '@multiformats/multiaddr'
|
15
16
|
import type { ProgressOptions } from 'progress-events'
|
16
17
|
|
17
|
-
export interface
|
18
|
+
export interface IncomingStreamOptions extends AbortOptions {
|
18
19
|
rtcConfiguration?: RTCConfiguration
|
19
20
|
dataChannelOptions?: Partial<DataChannelOptions>
|
20
|
-
signal: AbortSignal
|
21
21
|
}
|
22
22
|
|
23
23
|
export interface ConnectOptions extends LoggerOptions, ProgressOptions<WebRTCDialEvents> {
|
@@ -67,9 +67,21 @@ 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
|
+
|
70
83
|
const muxerFactory = new DataChannelMuxerFactory({
|
71
|
-
|
72
|
-
}, {
|
84
|
+
// @ts-expect-error https://github.com/murat-dogan/node-datachannel/pull/370
|
73
85
|
peerConnection,
|
74
86
|
dataChannelOptions: dataChannel
|
75
87
|
})
|
@@ -97,7 +109,7 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa
|
|
97
109
|
signal
|
98
110
|
})
|
99
111
|
.catch(err => {
|
100
|
-
log.error('error sending ICE candidate', err)
|
112
|
+
log.error('error sending ICE candidate - %e', err)
|
101
113
|
})
|
102
114
|
}
|
103
115
|
peerConnection.onicecandidateerror = (event) => {
|
@@ -157,7 +169,17 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa
|
|
157
169
|
onProgress
|
158
170
|
})
|
159
171
|
|
160
|
-
log.trace('initiator connected
|
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
|
+
|
161
183
|
channel.close()
|
162
184
|
|
163
185
|
onProgress?.(new CustomProgressEvent('webrtc:close-signaling-stream'))
|
@@ -1,20 +1,19 @@
|
|
1
|
+
import { pbStream } from '@libp2p/utils'
|
1
2
|
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, readCandidatesUntilConnected } from './util.js'
|
6
|
+
import { getConnectionState, getRemotePeer, readCandidatesUntilConnected } from './util.js'
|
7
7
|
import type { RTCPeerConnection } from '../webrtc/index.js'
|
8
|
-
import type { Logger,
|
8
|
+
import type { AbortOptions, Connection, Logger, PeerId, Stream } from '@libp2p/interface'
|
9
9
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
10
10
|
|
11
|
-
export interface
|
11
|
+
export interface IncomingStreamOptions extends AbortOptions {
|
12
12
|
peerConnection: RTCPeerConnection
|
13
|
-
signal: AbortSignal
|
14
13
|
log: Logger
|
15
14
|
}
|
16
15
|
|
17
|
-
export async function handleIncomingStream (
|
16
|
+
export async function handleIncomingStream (stream: Stream, connection: Connection, { peerConnection, signal, log }: IncomingStreamOptions): Promise<{ remoteAddress: Multiaddr, remotePeer: PeerId }> {
|
18
17
|
log.trace('new inbound signaling stream')
|
19
18
|
|
20
19
|
const messageStream = pbStream(stream).pb(Message)
|
@@ -37,7 +36,7 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co
|
|
37
36
|
signal
|
38
37
|
})
|
39
38
|
.catch(err => {
|
40
|
-
log.error('error sending ICE candidate', err)
|
39
|
+
log.error('error sending ICE candidate - %e', err)
|
41
40
|
})
|
42
41
|
}
|
43
42
|
|
@@ -101,9 +100,13 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co
|
|
101
100
|
}
|
102
101
|
}
|
103
102
|
|
104
|
-
const
|
103
|
+
const remotePeer = getRemotePeer(connection.remoteAddr)
|
104
|
+
const remoteAddress = multiaddr(`/webrtc/p2p/${remotePeer}`)
|
105
105
|
|
106
106
|
log.trace('recipient connected to remote address %s', remoteAddress)
|
107
107
|
|
108
|
-
return {
|
108
|
+
return {
|
109
|
+
remoteAddress,
|
110
|
+
remotePeer
|
111
|
+
}
|
109
112
|
}
|
@@ -4,15 +4,16 @@ import { multiaddr } from '@multiformats/multiaddr'
|
|
4
4
|
import { WebRTC } from '@multiformats/multiaddr-matcher'
|
5
5
|
import { setMaxListeners } from 'main-event'
|
6
6
|
import { SIGNALING_PROTOCOL } from '../constants.js'
|
7
|
-
import { WebRTCMultiaddrConnection } from '../maconn.js'
|
8
7
|
import { DataChannelMuxerFactory } from '../muxer.js'
|
8
|
+
import { toMultiaddrConnection } from '../rtcpeerconnection-to-conn.ts'
|
9
9
|
import { getRtcConfiguration } from '../util.js'
|
10
10
|
import { RTCPeerConnection } from '../webrtc/index.js'
|
11
11
|
import { initiateConnection } from './initiate-connection.js'
|
12
12
|
import { WebRTCPeerListener } from './listener.js'
|
13
13
|
import { handleIncomingStream } from './signaling-stream-handler.js'
|
14
|
+
import { getRemotePeer } from './util.ts'
|
14
15
|
import type { DataChannelOptions } from '../index.js'
|
15
|
-
import type { OutboundConnectionUpgradeEvents, CreateListenerOptions, DialTransportOptions, Transport, Listener, Upgrader, ComponentLogger, Logger, Connection, PeerId, CounterGroup, Metrics, Startable, OpenConnectionProgressEvents,
|
16
|
+
import type { OutboundConnectionUpgradeEvents, CreateListenerOptions, DialTransportOptions, Transport, Listener, Upgrader, ComponentLogger, Logger, Connection, PeerId, CounterGroup, Metrics, Startable, OpenConnectionProgressEvents, Libp2pEvents, MultiaddrConnection, Stream } from '@libp2p/interface'
|
16
17
|
import type { Registrar, ConnectionManager, TransportManager } from '@libp2p/interface-internal'
|
17
18
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
18
19
|
import type { TypedEventTarget } from 'main-event'
|
@@ -115,13 +116,13 @@ export class WebRTCTransport implements Transport<WebRTCDialEvents>, Startable {
|
|
115
116
|
}
|
116
117
|
|
117
118
|
async start (): Promise<void> {
|
118
|
-
await this.components.registrar.handle(SIGNALING_PROTOCOL, (
|
119
|
+
await this.components.registrar.handle(SIGNALING_PROTOCOL, (stream: Stream, connection: Connection) => {
|
119
120
|
// ensure we don't try to upgrade forever
|
120
121
|
const signal = this.components.upgrader.createInboundAbortSignal(this.shutdownController.signal)
|
121
122
|
|
122
|
-
this._onProtocol(
|
123
|
+
this._onProtocol(stream, connection, signal)
|
123
124
|
.catch(err => {
|
124
|
-
this.log.error('failed to handle incoming connect from %p',
|
125
|
+
this.log.error('failed to handle incoming connect from %p', connection.remotePeer, err)
|
125
126
|
})
|
126
127
|
.finally(() => {
|
127
128
|
signal.clear()
|
@@ -180,16 +181,18 @@ export class WebRTCTransport implements Transport<WebRTCDialEvents>, Startable {
|
|
180
181
|
onProgress: options.onProgress
|
181
182
|
})
|
182
183
|
|
183
|
-
const webRTCConn =
|
184
|
+
const webRTCConn = toMultiaddrConnection({
|
184
185
|
peerConnection,
|
185
|
-
timeline: { open: Date.now() },
|
186
186
|
remoteAddr: remoteAddress,
|
187
|
-
metrics: this.metrics?.dialerEvents
|
187
|
+
metrics: this.metrics?.dialerEvents,
|
188
|
+
direction: 'outbound',
|
189
|
+
log: this.components.logger.forComponent('libp2p:webrtc:connection')
|
188
190
|
})
|
189
191
|
|
190
192
|
const connection = await options.upgrader.upgradeOutbound(webRTCConn, {
|
191
193
|
skipProtection: true,
|
192
194
|
skipEncryption: true,
|
195
|
+
remotePeer: getRemotePeer(ma),
|
193
196
|
muxerFactory,
|
194
197
|
onProgress: options.onProgress,
|
195
198
|
signal: options.signal
|
@@ -201,18 +204,29 @@ export class WebRTCTransport implements Transport<WebRTCDialEvents>, Startable {
|
|
201
204
|
return connection
|
202
205
|
}
|
203
206
|
|
204
|
-
async _onProtocol (
|
207
|
+
async _onProtocol (stream: Stream, connection: Connection, signal: AbortSignal): Promise<void> {
|
205
208
|
const peerConnection = new RTCPeerConnection(await getRtcConfiguration(this.init.rtcConfiguration))
|
206
|
-
|
209
|
+
|
210
|
+
// make sure C++ peer connection is garbage collected
|
211
|
+
// https://github.com/murat-dogan/node-datachannel/issues/366#issuecomment-3228453155
|
212
|
+
peerConnection.addEventListener('connectionstatechange', () => {
|
213
|
+
switch (peerConnection.connectionState) {
|
214
|
+
case 'closed':
|
215
|
+
peerConnection.close()
|
216
|
+
break
|
217
|
+
default:
|
218
|
+
break
|
219
|
+
}
|
220
|
+
})
|
221
|
+
const muxerFactory = new DataChannelMuxerFactory({
|
222
|
+
// @ts-expect-error https://github.com/murat-dogan/node-datachannel/pull/370
|
207
223
|
peerConnection,
|
208
224
|
dataChannelOptions: this.init.dataChannel
|
209
225
|
})
|
210
226
|
|
211
227
|
try {
|
212
|
-
const { remoteAddress } = await handleIncomingStream({
|
228
|
+
const { remoteAddress, remotePeer } = await handleIncomingStream(stream, connection, {
|
213
229
|
peerConnection,
|
214
|
-
connection,
|
215
|
-
stream,
|
216
230
|
signal,
|
217
231
|
log: this.log
|
218
232
|
})
|
@@ -222,16 +236,18 @@ export class WebRTCTransport implements Transport<WebRTCDialEvents>, Startable {
|
|
222
236
|
signal
|
223
237
|
})
|
224
238
|
|
225
|
-
const webRTCConn =
|
239
|
+
const webRTCConn = toMultiaddrConnection({
|
226
240
|
peerConnection,
|
227
|
-
timeline: { open: (new Date()).getTime() },
|
228
241
|
remoteAddr: remoteAddress,
|
229
|
-
metrics: this.metrics?.listenerEvents
|
242
|
+
metrics: this.metrics?.listenerEvents,
|
243
|
+
direction: 'inbound',
|
244
|
+
log: this.components.logger.forComponent('libp2p:webrtc:connection')
|
230
245
|
})
|
231
246
|
|
232
247
|
await this.components.upgrader.upgradeInbound(webRTCConn, {
|
233
248
|
skipEncryption: true,
|
234
249
|
skipProtection: true,
|
250
|
+
remotePeer,
|
235
251
|
muxerFactory,
|
236
252
|
signal
|
237
253
|
})
|
@@ -247,7 +263,7 @@ export class WebRTCTransport implements Transport<WebRTCDialEvents>, Startable {
|
|
247
263
|
}
|
248
264
|
}
|
249
265
|
|
250
|
-
private _closeOnShutdown (pc: RTCPeerConnection, webRTCConn:
|
266
|
+
private _closeOnShutdown (pc: RTCPeerConnection, webRTCConn: MultiaddrConnection): void {
|
251
267
|
// close the connection on shut down
|
252
268
|
const shutDownListener = (): void => {
|
253
269
|
webRTCConn.close()
|
@@ -1,12 +1,13 @@
|
|
1
|
-
import { ConnectionFailedError, InvalidMessageError } from '@libp2p/interface'
|
2
|
-
import
|
1
|
+
import { ConnectionFailedError, InvalidMessageError, InvalidMultiaddrError } from '@libp2p/interface'
|
2
|
+
import { peerIdFromString } from '@libp2p/peer-id'
|
3
3
|
import { CustomProgressEvent } from 'progress-events'
|
4
4
|
import { isFirefox } from '../util.js'
|
5
5
|
import { RTCIceCandidate } from '../webrtc/index.js'
|
6
6
|
import { Message } from './pb/message.js'
|
7
7
|
import type { WebRTCDialEvents } from './transport.js'
|
8
8
|
import type { RTCPeerConnection } from '../webrtc/index.js'
|
9
|
-
import type { AbortOptions, LoggerOptions, Stream } from '@libp2p/interface'
|
9
|
+
import type { AbortOptions, LoggerOptions, PeerId, Stream } from '@libp2p/interface'
|
10
|
+
import type { Multiaddr } from '@multiformats/multiaddr'
|
10
11
|
import type { MessageStream } from 'it-protobuf-stream'
|
11
12
|
import type { DeferredPromise } from 'p-defer'
|
12
13
|
import type { ProgressOptions } from 'progress-events'
|
@@ -17,7 +18,7 @@ export interface ReadCandidatesOptions extends AbortOptions, LoggerOptions, Prog
|
|
17
18
|
|
18
19
|
export const readCandidatesUntilConnected = async (pc: RTCPeerConnection, stream: MessageStream<Message, Stream>, options: ReadCandidatesOptions): Promise<void> => {
|
19
20
|
try {
|
20
|
-
const connectedPromise
|
21
|
+
const connectedPromise = Promise.withResolvers<void>()
|
21
22
|
resolveOnConnected(pc, connectedPromise)
|
22
23
|
|
23
24
|
// read candidates until we are connected or we reach the end of the stream
|
@@ -94,3 +95,19 @@ function resolveOnConnected (pc: RTCPeerConnection, promise: DeferredPromise<voi
|
|
94
95
|
}
|
95
96
|
}
|
96
97
|
}
|
98
|
+
|
99
|
+
export function getRemotePeer (ma: Multiaddr): PeerId {
|
100
|
+
let remotePeer: PeerId | undefined
|
101
|
+
|
102
|
+
for (const component of ma.getComponents()) {
|
103
|
+
if (component.name === 'p2p') {
|
104
|
+
remotePeer = peerIdFromString(component.value ?? '')
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
if (remotePeer == null) {
|
109
|
+
throw new InvalidMultiaddrError('Remote peerId must be present in multiaddr')
|
110
|
+
}
|
111
|
+
|
112
|
+
return remotePeer
|
113
|
+
}
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { isIPv4 } from '@chainsafe/is-ip'
|
2
2
|
import { InvalidParametersError } from '@libp2p/interface'
|
3
|
-
import { getThinWaistAddresses } from '@libp2p/utils
|
3
|
+
import { getThinWaistAddresses } from '@libp2p/utils'
|
4
4
|
import { multiaddr, fromStringTuples } from '@multiformats/multiaddr'
|
5
5
|
import { WebRTCDirect } from '@multiformats/multiaddr-matcher'
|
6
6
|
import getPort from 'get-port'
|
@@ -205,7 +205,7 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
|
|
205
205
|
metrics: this.components.metrics,
|
206
206
|
events: this.metrics?.listenerEvents,
|
207
207
|
signal,
|
208
|
-
remoteAddr: multiaddr(`/ip${isIPv4(remoteHost) ? 4 : 6}/${remoteHost}/udp/${remotePort}`),
|
208
|
+
remoteAddr: multiaddr(`/ip${isIPv4(remoteHost) ? 4 : 6}/${remoteHost}/udp/${remotePort}/webrtc-direct`),
|
209
209
|
dataChannel: this.init.dataChannel,
|
210
210
|
upgrader: this.init.upgrader,
|
211
211
|
peerId: this.components.peerId,
|