@libp2p/webrtc 5.2.24-6059227cb → 5.2.24-87bc8d4fb
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 +18 -18
- package/dist/index.min.js.map +4 -4
- package/dist/src/constants.d.ts +23 -4
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +23 -4
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +22 -20
- 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 +138 -30
- package/dist/src/muxer.js.map +1 -1
- package/dist/src/private-to-private/initiate-connection.d.ts +3 -2
- package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
- package/dist/src/private-to-private/initiate-connection.js +5 -37
- 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 +7 -19
- package/dist/src/private-to-private/signaling-stream-handler.js.map +1 -1
- package/dist/src/private-to-private/transport.d.ts +9 -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 +2 -3
- package/dist/src/private-to-private/util.d.ts.map +1 -1
- package/dist/src/private-to-private/util.js +14 -26
- package/dist/src/private-to-private/util.js.map +1 -1
- package/dist/src/private-to-public/listener.d.ts.map +1 -1
- package/dist/src/private-to-public/listener.js +15 -21
- package/dist/src/private-to-public/listener.js.map +1 -1
- package/dist/src/private-to-public/transport.d.ts +8 -0
- package/dist/src/private-to-public/transport.d.ts.map +1 -1
- package/dist/src/private-to-public/transport.js +2 -3
- 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 +13 -25
- 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 -14
- package/dist/src/stream.d.ts.map +1 -1
- package/dist/src/stream.js +204 -134
- 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 +28 -5
- package/src/index.ts +22 -21
- package/src/maconn.ts +101 -0
- package/src/muxer.ts +169 -39
- package/src/private-to-private/initiate-connection.ts +8 -46
- package/src/private-to-private/signaling-stream-handler.ts +10 -23
- package/src/private-to-private/transport.ts +25 -33
- package/src/private-to-private/util.ts +16 -33
- package/src/private-to-public/listener.ts +15 -22
- package/src/private-to-public/transport.ts +12 -3
- 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 +13 -29
- package/src/private-to-public/utils/stun-listener.ts +1 -1
- package/src/stream.ts +237 -153
- 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 -46
- package/dist/src/rtcpeerconnection-to-conn.js.map +0 -1
- package/src/rtcpeerconnection-to-conn.ts +0 -66
@@ -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,
|
12
|
+
import type { LoggerOptions, Connection, ComponentLogger, IncomingStreamData } from '@libp2p/interface'
|
14
13
|
import type { ConnectionManager, TransportManager } from '@libp2p/interface-internal'
|
15
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
|
})
|
@@ -94,20 +82,10 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa
|
|
94
82
|
|
95
83
|
// setup callback to write ICE candidates to the remote peer
|
96
84
|
peerConnection.onicecandidate = ({ candidate }) => {
|
97
|
-
if (peerConnection.connectionState === 'connected') {
|
98
|
-
log.trace('ignore new ice candidate as peer connection is already connected')
|
99
|
-
return
|
100
|
-
}
|
101
|
-
|
102
85
|
// a null candidate means end-of-candidates, an empty string candidate
|
103
86
|
// means end-of-candidates for this generation, otherwise this should
|
104
87
|
// be a valid candidate object
|
105
88
|
// see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent
|
106
|
-
if (candidate == null || candidate?.candidate === '') {
|
107
|
-
log.trace('initiator detected end of ICE candidates')
|
108
|
-
return
|
109
|
-
}
|
110
|
-
|
111
89
|
const data = JSON.stringify(candidate?.toJSON() ?? null)
|
112
90
|
|
113
91
|
log.trace('initiator sending ICE candidate %o', candidate)
|
@@ -119,7 +97,7 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa
|
|
119
97
|
signal
|
120
98
|
})
|
121
99
|
.catch(err => {
|
122
|
-
log.error('error sending ICE candidate
|
100
|
+
log.error('error sending ICE candidate', err)
|
123
101
|
})
|
124
102
|
}
|
125
103
|
peerConnection.onicecandidateerror = (event) => {
|
@@ -179,25 +157,9 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa
|
|
179
157
|
onProgress
|
180
158
|
})
|
181
159
|
|
182
|
-
log.trace('initiator connected')
|
183
|
-
|
184
|
-
if (channel.readyState !== 'open') {
|
185
|
-
log.trace('wait for init channel to open')
|
186
|
-
await pEvent(channel, 'open', {
|
187
|
-
signal
|
188
|
-
})
|
189
|
-
}
|
190
|
-
|
191
|
-
log.trace('closing init channel')
|
160
|
+
log.trace('initiator connected, closing init channel')
|
192
161
|
channel.close()
|
193
162
|
|
194
|
-
// wait for init channel to close before proceeding, otherwise the channel
|
195
|
-
// id can be reused before both sides have seen the channel close
|
196
|
-
log.trace('waiting for init channel to close')
|
197
|
-
await pEvent(channel, 'close', {
|
198
|
-
signal
|
199
|
-
})
|
200
|
-
|
201
163
|
onProgress?.(new CustomProgressEvent('webrtc:close-signaling-stream'))
|
202
164
|
|
203
165
|
log.trace('closing signaling channel')
|
@@ -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 {
|
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)
|
@@ -21,20 +22,10 @@ export async function handleIncomingStream (stream: Stream, connection: Connecti
|
|
21
22
|
try {
|
22
23
|
// candidate callbacks
|
23
24
|
peerConnection.onicecandidate = ({ candidate }) => {
|
24
|
-
if (peerConnection.connectionState === 'connected') {
|
25
|
-
log.trace('ignore new ice candidate as peer connection is already connected')
|
26
|
-
return
|
27
|
-
}
|
28
|
-
|
29
25
|
// a null candidate means end-of-candidates, an empty string candidate
|
30
26
|
// means end-of-candidates for this generation, otherwise this should
|
31
27
|
// be a valid candidate object
|
32
28
|
// see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent
|
33
|
-
if (candidate == null || candidate?.candidate === '') {
|
34
|
-
log.trace('recipient detected end of ICE candidates')
|
35
|
-
return
|
36
|
-
}
|
37
|
-
|
38
29
|
const data = JSON.stringify(candidate?.toJSON() ?? null)
|
39
30
|
|
40
31
|
log.trace('recipient sending ICE candidate %s', data)
|
@@ -46,7 +37,7 @@ export async function handleIncomingStream (stream: Stream, connection: Connecti
|
|
46
37
|
signal
|
47
38
|
})
|
48
39
|
.catch(err => {
|
49
|
-
log.error('error sending ICE candidate
|
40
|
+
log.error('error sending ICE candidate', err)
|
50
41
|
})
|
51
42
|
}
|
52
43
|
|
@@ -100,7 +91,7 @@ export async function handleIncomingStream (stream: Stream, connection: Connecti
|
|
100
91
|
log
|
101
92
|
})
|
102
93
|
} catch (err: any) {
|
103
|
-
if (peerConnection
|
94
|
+
if (getConnectionState(peerConnection) !== 'connected') {
|
104
95
|
log.error('error while handling signaling stream from peer %a', connection.remoteAddr, err)
|
105
96
|
|
106
97
|
peerConnection.close()
|
@@ -110,13 +101,9 @@ export async function handleIncomingStream (stream: Stream, connection: Connecti
|
|
110
101
|
}
|
111
102
|
}
|
112
103
|
|
113
|
-
const
|
114
|
-
const remoteAddress = multiaddr(`/webrtc/p2p/${remotePeer}`)
|
104
|
+
const remoteAddress = multiaddr(`/webrtc/p2p/${connection.remoteAddr.getPeerId()}`)
|
115
105
|
|
116
106
|
log.trace('recipient connected to remote address %s', remoteAddress)
|
117
107
|
|
118
|
-
return {
|
119
|
-
remoteAddress,
|
120
|
-
remotePeer
|
121
|
-
}
|
108
|
+
return { remoteAddress }
|
122
109
|
}
|
@@ -4,16 +4,15 @@ 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'
|
7
8
|
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'
|
15
14
|
import type { DataChannelOptions } from '../index.js'
|
16
|
-
import type { OutboundConnectionUpgradeEvents, CreateListenerOptions, DialTransportOptions, Transport, Listener, Upgrader, ComponentLogger, Logger, Connection, PeerId, CounterGroup, Metrics, Startable, OpenConnectionProgressEvents,
|
15
|
+
import type { OutboundConnectionUpgradeEvents, CreateListenerOptions, DialTransportOptions, Transport, Listener, Upgrader, ComponentLogger, Logger, Connection, PeerId, CounterGroup, Metrics, Startable, OpenConnectionProgressEvents, IncomingStreamData, Libp2pEvents } from '@libp2p/interface'
|
17
16
|
import type { Registrar, ConnectionManager, TransportManager } from '@libp2p/interface-internal'
|
18
17
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
19
18
|
import type { TypedEventTarget } from 'main-event'
|
@@ -31,6 +30,14 @@ export interface WebRTCTransportInit {
|
|
31
30
|
* Any options here will be applied to any RTCDataChannels that are opened.
|
32
31
|
*/
|
33
32
|
dataChannel?: DataChannelOptions
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Inbound connections must complete the upgrade within this many ms
|
36
|
+
*
|
37
|
+
* @default 30_000
|
38
|
+
* @deprecated configure `connectionManager.inboundUpgradeTimeout` instead
|
39
|
+
*/
|
40
|
+
inboundConnectionTimeout?: number
|
34
41
|
}
|
35
42
|
|
36
43
|
export interface WebRTCTransportComponents {
|
@@ -108,13 +115,13 @@ export class WebRTCTransport implements Transport<WebRTCDialEvents>, Startable {
|
|
108
115
|
}
|
109
116
|
|
110
117
|
async start (): Promise<void> {
|
111
|
-
await this.components.registrar.handle(SIGNALING_PROTOCOL, (
|
118
|
+
await this.components.registrar.handle(SIGNALING_PROTOCOL, (data: IncomingStreamData) => {
|
112
119
|
// ensure we don't try to upgrade forever
|
113
120
|
const signal = this.components.upgrader.createInboundAbortSignal(this.shutdownController.signal)
|
114
121
|
|
115
|
-
this._onProtocol(
|
122
|
+
this._onProtocol(data, signal)
|
116
123
|
.catch(err => {
|
117
|
-
this.log.error('failed to handle incoming connect from %p', connection.remotePeer, err)
|
124
|
+
this.log.error('failed to handle incoming connect from %p', data.connection.remotePeer, err)
|
118
125
|
})
|
119
126
|
.finally(() => {
|
120
127
|
signal.clear()
|
@@ -173,18 +180,16 @@ export class WebRTCTransport implements Transport<WebRTCDialEvents>, Startable {
|
|
173
180
|
onProgress: options.onProgress
|
174
181
|
})
|
175
182
|
|
176
|
-
const webRTCConn =
|
183
|
+
const webRTCConn = new WebRTCMultiaddrConnection(this.components, {
|
177
184
|
peerConnection,
|
185
|
+
timeline: { open: Date.now() },
|
178
186
|
remoteAddr: remoteAddress,
|
179
|
-
metrics: this.metrics?.dialerEvents
|
180
|
-
direction: 'outbound',
|
181
|
-
log: this.components.logger.forComponent('libp2p:webrtc:connection')
|
187
|
+
metrics: this.metrics?.dialerEvents
|
182
188
|
})
|
183
189
|
|
184
190
|
const connection = await options.upgrader.upgradeOutbound(webRTCConn, {
|
185
191
|
skipProtection: true,
|
186
192
|
skipEncryption: true,
|
187
|
-
remotePeer: getRemotePeer(ma),
|
188
193
|
muxerFactory,
|
189
194
|
onProgress: options.onProgress,
|
190
195
|
signal: options.signal
|
@@ -196,29 +201,18 @@ export class WebRTCTransport implements Transport<WebRTCDialEvents>, Startable {
|
|
196
201
|
return connection
|
197
202
|
}
|
198
203
|
|
199
|
-
async _onProtocol (
|
204
|
+
async _onProtocol ({ connection, stream }: IncomingStreamData, signal: AbortSignal): Promise<void> {
|
200
205
|
const peerConnection = new RTCPeerConnection(await getRtcConfiguration(this.init.rtcConfiguration))
|
201
|
-
|
202
|
-
// make sure C++ peer connection is garbage collected
|
203
|
-
// https://github.com/murat-dogan/node-datachannel/issues/366#issuecomment-3228453155
|
204
|
-
peerConnection.addEventListener('connectionstatechange', () => {
|
205
|
-
switch (peerConnection.connectionState) {
|
206
|
-
case 'closed':
|
207
|
-
peerConnection.close()
|
208
|
-
break
|
209
|
-
default:
|
210
|
-
break
|
211
|
-
}
|
212
|
-
})
|
213
|
-
const muxerFactory = new DataChannelMuxerFactory({
|
214
|
-
// @ts-expect-error https://github.com/murat-dogan/node-datachannel/pull/370
|
206
|
+
const muxerFactory = new DataChannelMuxerFactory(this.components, {
|
215
207
|
peerConnection,
|
216
208
|
dataChannelOptions: this.init.dataChannel
|
217
209
|
})
|
218
210
|
|
219
211
|
try {
|
220
|
-
const { remoteAddress
|
212
|
+
const { remoteAddress } = await handleIncomingStream({
|
221
213
|
peerConnection,
|
214
|
+
connection,
|
215
|
+
stream,
|
222
216
|
signal,
|
223
217
|
log: this.log
|
224
218
|
})
|
@@ -228,18 +222,16 @@ export class WebRTCTransport implements Transport<WebRTCDialEvents>, Startable {
|
|
228
222
|
signal
|
229
223
|
})
|
230
224
|
|
231
|
-
const webRTCConn =
|
225
|
+
const webRTCConn = new WebRTCMultiaddrConnection(this.components, {
|
232
226
|
peerConnection,
|
227
|
+
timeline: { open: (new Date()).getTime() },
|
233
228
|
remoteAddr: remoteAddress,
|
234
|
-
metrics: this.metrics?.listenerEvents
|
235
|
-
direction: 'inbound',
|
236
|
-
log: this.components.logger.forComponent('libp2p:webrtc:connection')
|
229
|
+
metrics: this.metrics?.listenerEvents
|
237
230
|
})
|
238
231
|
|
239
232
|
await this.components.upgrader.upgradeInbound(webRTCConn, {
|
240
233
|
skipEncryption: true,
|
241
234
|
skipProtection: true,
|
242
|
-
remotePeer,
|
243
235
|
muxerFactory,
|
244
236
|
signal
|
245
237
|
})
|
@@ -255,7 +247,7 @@ export class WebRTCTransport implements Transport<WebRTCDialEvents>, Startable {
|
|
255
247
|
}
|
256
248
|
}
|
257
249
|
|
258
|
-
private _closeOnShutdown (pc: RTCPeerConnection, webRTCConn:
|
250
|
+
private _closeOnShutdown (pc: RTCPeerConnection, webRTCConn: WebRTCMultiaddrConnection): void {
|
259
251
|
// close the connection on shut down
|
260
252
|
const shutDownListener = (): void => {
|
261
253
|
webRTCConn.close()
|
@@ -1,12 +1,12 @@
|
|
1
|
-
import { ConnectionFailedError, InvalidMessageError
|
2
|
-
import
|
1
|
+
import { ConnectionFailedError, InvalidMessageError } from '@libp2p/interface'
|
2
|
+
import pDefer from 'p-defer'
|
3
3
|
import { CustomProgressEvent } from 'progress-events'
|
4
|
+
import { isFirefox } from '../util.js'
|
4
5
|
import { RTCIceCandidate } from '../webrtc/index.js'
|
5
6
|
import { Message } from './pb/message.js'
|
6
7
|
import type { WebRTCDialEvents } from './transport.js'
|
7
8
|
import type { RTCPeerConnection } from '../webrtc/index.js'
|
8
|
-
import type { AbortOptions, LoggerOptions,
|
9
|
-
import type { Multiaddr } from '@multiformats/multiaddr'
|
9
|
+
import type { AbortOptions, LoggerOptions, Stream } from '@libp2p/interface'
|
10
10
|
import type { MessageStream } from 'it-protobuf-stream'
|
11
11
|
import type { DeferredPromise } from 'p-defer'
|
12
12
|
import type { ProgressOptions } from 'progress-events'
|
@@ -17,7 +17,7 @@ export interface ReadCandidatesOptions extends AbortOptions, LoggerOptions, Prog
|
|
17
17
|
|
18
18
|
export const readCandidatesUntilConnected = async (pc: RTCPeerConnection, stream: MessageStream<Message, Stream>, options: ReadCandidatesOptions): Promise<void> => {
|
19
19
|
try {
|
20
|
-
const connectedPromise
|
20
|
+
const connectedPromise: DeferredPromise<void> = pDefer()
|
21
21
|
resolveOnConnected(pc, connectedPromise)
|
22
22
|
|
23
23
|
// read candidates until we are connected or we reach the end of the stream
|
@@ -27,7 +27,7 @@ export const readCandidatesUntilConnected = async (pc: RTCPeerConnection, stream
|
|
27
27
|
connectedPromise.promise,
|
28
28
|
stream.read({
|
29
29
|
signal: options.signal
|
30
|
-
})
|
30
|
+
}).catch(() => {})
|
31
31
|
])
|
32
32
|
|
33
33
|
// stream ended or we became connected
|
@@ -62,52 +62,35 @@ export const readCandidatesUntilConnected = async (pc: RTCPeerConnection, stream
|
|
62
62
|
options.onProgress?.(new CustomProgressEvent<string>('webrtc:add-ice-candidate', candidate.candidate))
|
63
63
|
await pc.addIceCandidate(candidate)
|
64
64
|
} catch (err) {
|
65
|
-
options.log.error('%s bad candidate received
|
65
|
+
options.log.error('%s bad candidate received', options.direction, candidateInit, err)
|
66
66
|
}
|
67
67
|
}
|
68
68
|
} catch (err) {
|
69
|
-
options.log.error('%s error parsing ICE candidate
|
69
|
+
options.log.error('%s error parsing ICE candidate', options.direction, err)
|
70
70
|
|
71
|
-
if (options.signal?.aborted === true && pc
|
71
|
+
if (options.signal?.aborted === true && getConnectionState(pc) !== 'connected') {
|
72
72
|
throw err
|
73
73
|
}
|
74
74
|
}
|
75
75
|
}
|
76
76
|
|
77
|
-
function
|
78
|
-
|
79
|
-
|
80
|
-
return
|
81
|
-
}
|
77
|
+
export function getConnectionState (pc: RTCPeerConnection): string {
|
78
|
+
return isFirefox ? pc.iceConnectionState : pc.connectionState
|
79
|
+
}
|
82
80
|
|
83
|
-
|
84
|
-
|
81
|
+
function resolveOnConnected (pc: RTCPeerConnection, promise: DeferredPromise<void>): void {
|
82
|
+
pc[isFirefox ? 'oniceconnectionstatechange' : 'onconnectionstatechange'] = (_) => {
|
83
|
+
switch (getConnectionState(pc)) {
|
85
84
|
case 'connected':
|
86
85
|
promise.resolve()
|
87
86
|
break
|
88
87
|
case 'failed':
|
89
88
|
case 'disconnected':
|
90
89
|
case 'closed':
|
91
|
-
promise.reject(new ConnectionFailedError(
|
90
|
+
promise.reject(new ConnectionFailedError('RTCPeerConnection was closed'))
|
92
91
|
break
|
93
92
|
default:
|
94
93
|
break
|
95
94
|
}
|
96
95
|
}
|
97
96
|
}
|
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,11 +1,12 @@
|
|
1
1
|
import { isIPv4 } from '@chainsafe/is-ip'
|
2
2
|
import { InvalidParametersError } from '@libp2p/interface'
|
3
|
-
import {
|
4
|
-
import {
|
3
|
+
import { getThinWaistAddresses } from '@libp2p/utils/get-thin-waist-addresses'
|
4
|
+
import { multiaddr, fromStringTuples } from '@multiformats/multiaddr'
|
5
5
|
import { WebRTCDirect } from '@multiformats/multiaddr-matcher'
|
6
6
|
import getPort from 'get-port'
|
7
7
|
import { TypedEventEmitter, setMaxListeners } from 'main-event'
|
8
8
|
import pWaitFor from 'p-wait-for'
|
9
|
+
import { CODEC_CERTHASH, CODEC_WEBRTC_DIRECT } from '../constants.js'
|
9
10
|
import { connect } from './utils/connect.js'
|
10
11
|
import { createDialerRTCPeerConnection } from './utils/get-rtcpeerconnection.js'
|
11
12
|
import { stunListener } from './utils/stun-listener.js'
|
@@ -93,11 +94,7 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
|
|
93
94
|
}
|
94
95
|
|
95
96
|
async listen (ma: Multiaddr): Promise<void> {
|
96
|
-
const { host, port,
|
97
|
-
|
98
|
-
if (port == null || protocol !== 'udp' || (type !== 'ip4' && type !== 'ip6')) {
|
99
|
-
throw new InvalidParametersError(`Multiaddr ${ma} was not an IPv4 or IPv6 address or was missing a UDP port`)
|
100
|
-
}
|
97
|
+
const { host, port, family } = ma.toOptions()
|
101
98
|
|
102
99
|
let udpMuxServer: UDPMuxServer | undefined
|
103
100
|
|
@@ -109,7 +106,7 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
|
|
109
106
|
udpMuxServer = UDP_MUX_LISTENERS.find(s => s.port === port)
|
110
107
|
|
111
108
|
// make sure the port is free for the given family
|
112
|
-
if (udpMuxServer != null && ((udpMuxServer.isIPv4 &&
|
109
|
+
if (udpMuxServer != null && ((udpMuxServer.isIPv4 && family === 4) || (udpMuxServer.isIPv6 && family === 6))) {
|
113
110
|
throw new InvalidParametersError(`There is already a listener for ${host}:${port}`)
|
114
111
|
}
|
115
112
|
|
@@ -122,13 +119,13 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
|
|
122
119
|
// start the mux server if we don't have one already
|
123
120
|
if (udpMuxServer == null) {
|
124
121
|
this.log('starting UDP mux server on %s:%p', host, port)
|
125
|
-
udpMuxServer = this.startUDPMuxServer(host, port,
|
122
|
+
udpMuxServer = this.startUDPMuxServer(host, port, family)
|
126
123
|
UDP_MUX_LISTENERS.push(udpMuxServer)
|
127
124
|
}
|
128
125
|
|
129
|
-
if (
|
126
|
+
if (family === 4) {
|
130
127
|
udpMuxServer.isIPv4 = true
|
131
|
-
} else if (
|
128
|
+
} else if (family === 6) {
|
132
129
|
udpMuxServer.isIPv6 = true
|
133
130
|
}
|
134
131
|
|
@@ -208,7 +205,7 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
|
|
208
205
|
metrics: this.components.metrics,
|
209
206
|
events: this.metrics?.listenerEvents,
|
210
207
|
signal,
|
211
|
-
remoteAddr: multiaddr(`/ip${isIPv4(remoteHost) ? 4 : 6}/${remoteHost}/udp/${remotePort}
|
208
|
+
remoteAddr: multiaddr(`/ip${isIPv4(remoteHost) ? 4 : 6}/${remoteHost}/udp/${remotePort}`),
|
212
209
|
dataChannel: this.init.dataChannel,
|
213
210
|
upgrader: this.init.upgrader,
|
214
211
|
peerId: this.components.peerId,
|
@@ -241,23 +238,19 @@ export class WebRTCDirectListener extends TypedEventEmitter<ListenerEvents> impl
|
|
241
238
|
}
|
242
239
|
|
243
240
|
// add the certhash if it is missing
|
244
|
-
const
|
241
|
+
const tuples = ma.stringTuples()
|
245
242
|
|
246
|
-
for (let j = 0; j <
|
247
|
-
if (
|
243
|
+
for (let j = 0; j < tuples.length; j++) {
|
244
|
+
if (tuples[j][0] !== CODEC_WEBRTC_DIRECT) {
|
248
245
|
continue
|
249
246
|
}
|
250
247
|
|
251
248
|
const certhashIndex = j + 1
|
252
249
|
|
253
|
-
if (
|
254
|
-
|
255
|
-
code: CODE_CERTHASH,
|
256
|
-
name: 'certhash',
|
257
|
-
value: this.certificate?.certhash
|
258
|
-
})
|
250
|
+
if (tuples[certhashIndex] == null || tuples[certhashIndex][0] !== CODEC_CERTHASH) {
|
251
|
+
tuples.splice(certhashIndex, 0, [CODEC_CERTHASH, this.certificate?.certhash])
|
259
252
|
|
260
|
-
ma =
|
253
|
+
ma = fromStringTuples(tuples)
|
261
254
|
multiaddrs[i] = ma
|
262
255
|
}
|
263
256
|
}
|
@@ -1,7 +1,6 @@
|
|
1
1
|
import { generateKeyPair, privateKeyToCryptoKeyPair } from '@libp2p/crypto/keys'
|
2
2
|
import { InvalidParametersError, NotFoundError, NotStartedError, serviceCapabilities, transportSymbol } from '@libp2p/interface'
|
3
3
|
import { peerIdFromString } from '@libp2p/peer-id'
|
4
|
-
import { CODE_P2P } from '@multiformats/multiaddr'
|
5
4
|
import { WebRTCDirect } from '@multiformats/multiaddr-matcher'
|
6
5
|
import { BasicConstraintsExtension, X509Certificate, X509CertificateGenerator } from '@peculiar/x509'
|
7
6
|
import { Key } from 'interface-datastore'
|
@@ -51,6 +50,11 @@ export interface WebRTCTransportDirectInit {
|
|
51
50
|
*/
|
52
51
|
dataChannel?: DataChannelOptions
|
53
52
|
|
53
|
+
/**
|
54
|
+
* @deprecated use `certificate` instead - this option will be removed in a future release
|
55
|
+
*/
|
56
|
+
certificates?: TransportCertificate[]
|
57
|
+
|
54
58
|
/**
|
55
59
|
* Use an existing TLS certificate to secure incoming connections or supply
|
56
60
|
* settings to generate one.
|
@@ -63,6 +67,11 @@ export interface WebRTCTransportDirectInit {
|
|
63
67
|
*/
|
64
68
|
certificate?: TransportCertificate
|
65
69
|
|
70
|
+
/**
|
71
|
+
* @deprecated this setting is ignored and will be removed in a future release
|
72
|
+
*/
|
73
|
+
useLibjuice?: boolean
|
74
|
+
|
66
75
|
/**
|
67
76
|
* The key the certificate is stored in the datastore under
|
68
77
|
*
|
@@ -155,7 +164,7 @@ export class WebRTCDirectTransport implements Transport, Startable {
|
|
155
164
|
options.signal.throwIfAborted()
|
156
165
|
|
157
166
|
let theirPeerId: PeerId | undefined
|
158
|
-
const remotePeerString = ma.
|
167
|
+
const remotePeerString = ma.getPeerId()
|
159
168
|
if (remotePeerString != null) {
|
160
169
|
theirPeerId = peerIdFromString(remotePeerString)
|
161
170
|
}
|
@@ -177,7 +186,7 @@ export class WebRTCDirectTransport implements Transport, Startable {
|
|
177
186
|
dataChannel: this.init.dataChannel,
|
178
187
|
upgrader: options.upgrader,
|
179
188
|
peerId: this.components.peerId,
|
180
|
-
|
189
|
+
remotePeerId: theirPeerId,
|
181
190
|
privateKey: this.components.privateKey
|
182
191
|
})
|
183
192
|
} catch (err) {
|
@@ -1,8 +1,8 @@
|
|
1
|
-
import { noise } from '@libp2p
|
2
|
-
import {
|
1
|
+
import { noise } from '@chainsafe/libp2p-noise'
|
2
|
+
import { raceEvent } from 'race-event'
|
3
3
|
import { WebRTCTransportError } from '../../error.js'
|
4
|
+
import { WebRTCMultiaddrConnection } from '../../maconn.js'
|
4
5
|
import { DataChannelMuxerFactory } from '../../muxer.js'
|
5
|
-
import { toMultiaddrConnection } from '../../rtcpeerconnection-to-conn.ts'
|
6
6
|
import { createStream } from '../../stream.js'
|
7
7
|
import { isFirefox } from '../../util.js'
|
8
8
|
import { generateNoisePrologue } from './generate-noise-prologue.js'
|
@@ -22,7 +22,7 @@ export interface ConnectOptions {
|
|
22
22
|
dataChannel?: DataChannelOptions
|
23
23
|
upgrader: Upgrader
|
24
24
|
peerId: PeerId
|
25
|
-
|
25
|
+
remotePeerId?: PeerId
|
26
26
|
signal: AbortSignal
|
27
27
|
privateKey: PrivateKey
|
28
28
|
}
|
@@ -83,7 +83,7 @@ export async function connect (peerConnection: DirectRTCPeerConnection, ufrag: s
|
|
83
83
|
|
84
84
|
if (handshakeDataChannel.readyState !== 'open') {
|
85
85
|
options.log.trace('%s wait for handshake channel to open, starting status %s', options.role, handshakeDataChannel.readyState)
|
86
|
-
await
|
86
|
+
await raceEvent(handshakeDataChannel, 'open', options.signal)
|
87
87
|
}
|
88
88
|
|
89
89
|
options.log.trace('%s handshake channel opened', options.role)
|
@@ -116,19 +116,20 @@ export async function connect (peerConnection: DirectRTCPeerConnection, ufrag: s
|
|
116
116
|
const handshakeStream = createStream({
|
117
117
|
channel: handshakeDataChannel,
|
118
118
|
direction: 'outbound',
|
119
|
-
|
119
|
+
handshake: true,
|
120
120
|
log: options.log,
|
121
121
|
...(options.dataChannel ?? {})
|
122
122
|
})
|
123
123
|
|
124
124
|
// Creating the connection before completion of the noise
|
125
125
|
// handshake ensures that the stream opening callback is set up
|
126
|
-
const maConn =
|
126
|
+
const maConn = new WebRTCMultiaddrConnection(options, {
|
127
127
|
peerConnection,
|
128
128
|
remoteAddr: options.remoteAddr,
|
129
|
-
|
130
|
-
|
131
|
-
|
129
|
+
timeline: {
|
130
|
+
open: Date.now()
|
131
|
+
},
|
132
|
+
metrics: options.events
|
132
133
|
})
|
133
134
|
|
134
135
|
peerConnection.addEventListener(CONNECTION_STATE_CHANGE_EVENT, () => {
|
@@ -149,8 +150,7 @@ export async function connect (peerConnection: DirectRTCPeerConnection, ufrag: s
|
|
149
150
|
// Track opened peer connection
|
150
151
|
options.events?.increment({ peer_connection: true })
|
151
152
|
|
152
|
-
const muxerFactory = new DataChannelMuxerFactory({
|
153
|
-
// @ts-expect-error https://github.com/murat-dogan/node-datachannel/pull/370
|
153
|
+
const muxerFactory = new DataChannelMuxerFactory(options, {
|
154
154
|
peerConnection,
|
155
155
|
metrics: options.events,
|
156
156
|
dataChannelOptions: options.dataChannel
|
@@ -161,8 +161,8 @@ export async function connect (peerConnection: DirectRTCPeerConnection, ufrag: s
|
|
161
161
|
// handshake. Therefore, we need to secure an inbound noise connection
|
162
162
|
// from the server.
|
163
163
|
options.log.trace('%s secure inbound', options.role)
|
164
|
-
|
165
|
-
remotePeer: options.
|
164
|
+
await connectionEncrypter.secureInbound(handshakeStream, {
|
165
|
+
remotePeer: options.remotePeerId,
|
166
166
|
signal: options.signal,
|
167
167
|
skipStreamMuxerNegotiation: true
|
168
168
|
})
|
@@ -171,7 +171,6 @@ export async function connect (peerConnection: DirectRTCPeerConnection, ufrag: s
|
|
171
171
|
return await options.upgrader.upgradeOutbound(maConn, {
|
172
172
|
skipProtection: true,
|
173
173
|
skipEncryption: true,
|
174
|
-
remotePeer: result.remotePeer,
|
175
174
|
muxerFactory,
|
176
175
|
signal: options.signal
|
177
176
|
})
|
@@ -182,7 +181,7 @@ export async function connect (peerConnection: DirectRTCPeerConnection, ufrag: s
|
|
182
181
|
// the client.
|
183
182
|
options.log.trace('%s secure outbound', options.role)
|
184
183
|
const result = await connectionEncrypter.secureOutbound(handshakeStream, {
|
185
|
-
remotePeer: options.
|
184
|
+
remotePeer: options.remotePeerId,
|
186
185
|
signal: options.signal,
|
187
186
|
skipStreamMuxerNegotiation: true
|
188
187
|
})
|
@@ -194,13 +193,11 @@ export async function connect (peerConnection: DirectRTCPeerConnection, ufrag: s
|
|
194
193
|
await options.upgrader.upgradeInbound(maConn, {
|
195
194
|
skipProtection: true,
|
196
195
|
skipEncryption: true,
|
197
|
-
remotePeer: result.remotePeer,
|
198
196
|
muxerFactory,
|
199
197
|
signal: options.signal
|
200
198
|
})
|
201
199
|
} catch (err) {
|
202
200
|
handshakeDataChannel.close()
|
203
|
-
peerConnection.close()
|
204
201
|
|
205
202
|
throw err
|
206
203
|
}
|