@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.
Files changed (90) hide show
  1. package/README.md +20 -10
  2. package/dist/index.min.js +18 -18
  3. package/dist/index.min.js.map +4 -4
  4. package/dist/src/constants.d.ts +23 -4
  5. package/dist/src/constants.d.ts.map +1 -1
  6. package/dist/src/constants.js +23 -4
  7. package/dist/src/constants.js.map +1 -1
  8. package/dist/src/index.d.ts +22 -20
  9. package/dist/src/index.d.ts.map +1 -1
  10. package/dist/src/index.js +22 -12
  11. package/dist/src/index.js.map +1 -1
  12. package/dist/src/maconn.d.ts +58 -0
  13. package/dist/src/maconn.d.ts.map +1 -0
  14. package/dist/src/maconn.js +56 -0
  15. package/dist/src/maconn.js.map +1 -0
  16. package/dist/src/muxer.d.ts +46 -14
  17. package/dist/src/muxer.d.ts.map +1 -1
  18. package/dist/src/muxer.js +138 -30
  19. package/dist/src/muxer.js.map +1 -1
  20. package/dist/src/private-to-private/initiate-connection.d.ts +3 -2
  21. package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
  22. package/dist/src/private-to-private/initiate-connection.js +5 -37
  23. package/dist/src/private-to-private/initiate-connection.js.map +1 -1
  24. package/dist/src/private-to-private/signaling-stream-handler.d.ts +4 -4
  25. package/dist/src/private-to-private/signaling-stream-handler.d.ts.map +1 -1
  26. package/dist/src/private-to-private/signaling-stream-handler.js +7 -19
  27. package/dist/src/private-to-private/signaling-stream-handler.js.map +1 -1
  28. package/dist/src/private-to-private/transport.d.ts +9 -2
  29. package/dist/src/private-to-private/transport.d.ts.map +1 -1
  30. package/dist/src/private-to-private/transport.js +15 -30
  31. package/dist/src/private-to-private/transport.js.map +1 -1
  32. package/dist/src/private-to-private/util.d.ts +2 -3
  33. package/dist/src/private-to-private/util.d.ts.map +1 -1
  34. package/dist/src/private-to-private/util.js +14 -26
  35. package/dist/src/private-to-private/util.js.map +1 -1
  36. package/dist/src/private-to-public/listener.d.ts.map +1 -1
  37. package/dist/src/private-to-public/listener.js +15 -21
  38. package/dist/src/private-to-public/listener.js.map +1 -1
  39. package/dist/src/private-to-public/transport.d.ts +8 -0
  40. package/dist/src/private-to-public/transport.d.ts.map +1 -1
  41. package/dist/src/private-to-public/transport.js +2 -3
  42. package/dist/src/private-to-public/transport.js.map +1 -1
  43. package/dist/src/private-to-public/utils/connect.d.ts +1 -1
  44. package/dist/src/private-to-public/utils/connect.d.ts.map +1 -1
  45. package/dist/src/private-to-public/utils/connect.js +14 -17
  46. package/dist/src/private-to-public/utils/connect.js.map +1 -1
  47. package/dist/src/private-to-public/utils/get-rtcpeerconnection.d.ts +4 -4
  48. package/dist/src/private-to-public/utils/get-rtcpeerconnection.d.ts.map +1 -1
  49. package/dist/src/private-to-public/utils/get-rtcpeerconnection.js +2 -13
  50. package/dist/src/private-to-public/utils/get-rtcpeerconnection.js.map +1 -1
  51. package/dist/src/private-to-public/utils/sdp.d.ts.map +1 -1
  52. package/dist/src/private-to-public/utils/sdp.js +13 -25
  53. package/dist/src/private-to-public/utils/sdp.js.map +1 -1
  54. package/dist/src/private-to-public/utils/stun-listener.js +1 -1
  55. package/dist/src/private-to-public/utils/stun-listener.js.map +1 -1
  56. package/dist/src/stream.d.ts +26 -14
  57. package/dist/src/stream.d.ts.map +1 -1
  58. package/dist/src/stream.js +204 -134
  59. package/dist/src/stream.js.map +1 -1
  60. package/dist/src/util.d.ts +1 -3
  61. package/dist/src/util.d.ts.map +1 -1
  62. package/dist/src/util.js +0 -19
  63. package/dist/src/util.js.map +1 -1
  64. package/dist/src/webrtc/index.d.ts +1 -1
  65. package/dist/src/webrtc/index.d.ts.map +1 -1
  66. package/dist/src/webrtc/index.js +1 -1
  67. package/dist/src/webrtc/index.js.map +1 -1
  68. package/package.json +29 -26
  69. package/src/constants.ts +28 -5
  70. package/src/index.ts +22 -21
  71. package/src/maconn.ts +101 -0
  72. package/src/muxer.ts +169 -39
  73. package/src/private-to-private/initiate-connection.ts +8 -46
  74. package/src/private-to-private/signaling-stream-handler.ts +10 -23
  75. package/src/private-to-private/transport.ts +25 -33
  76. package/src/private-to-private/util.ts +16 -33
  77. package/src/private-to-public/listener.ts +15 -22
  78. package/src/private-to-public/transport.ts +12 -3
  79. package/src/private-to-public/utils/connect.ts +15 -18
  80. package/src/private-to-public/utils/get-rtcpeerconnection.ts +4 -16
  81. package/src/private-to-public/utils/sdp.ts +13 -29
  82. package/src/private-to-public/utils/stun-listener.ts +1 -1
  83. package/src/stream.ts +237 -153
  84. package/src/util.ts +1 -22
  85. package/src/webrtc/index.ts +1 -1
  86. package/dist/src/rtcpeerconnection-to-conn.d.ts +0 -12
  87. package/dist/src/rtcpeerconnection-to-conn.d.ts.map +0 -1
  88. package/dist/src/rtcpeerconnection-to-conn.js +0 -46
  89. package/dist/src/rtcpeerconnection-to-conn.js.map +0 -1
  90. package/src/rtcpeerconnection-to-conn.ts +0 -66
@@ -1,5 +1,4 @@
1
- import { pbStream } from '@libp2p/utils'
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, AbortOptions } from '@libp2p/interface'
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 IncomingStreamOptions extends AbortOptions {
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
- // @ts-expect-error https://github.com/murat-dogan/node-datachannel/pull/370
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 - %e', err)
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 { getRemotePeer, readCandidatesUntilConnected } from './util.js'
6
+ import { getConnectionState, readCandidatesUntilConnected } from './util.js'
7
7
  import type { RTCPeerConnection } from '../webrtc/index.js'
8
- import type { AbortOptions, Connection, Logger, PeerId, Stream } from '@libp2p/interface'
8
+ import type { Logger, IncomingStreamData } from '@libp2p/interface'
9
9
  import type { Multiaddr } from '@multiformats/multiaddr'
10
10
 
11
- export interface IncomingStreamOptions extends AbortOptions {
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 (stream: Stream, connection: Connection, { peerConnection, signal, log }: IncomingStreamOptions): Promise<{ remoteAddress: Multiaddr, remotePeer: PeerId }> {
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 - %e', err)
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.connectionState !== 'connected') {
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 remotePeer = getRemotePeer(connection.remoteAddr)
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, Libp2pEvents, MultiaddrConnection, Stream } from '@libp2p/interface'
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, (stream: Stream, connection: Connection) => {
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(stream, connection, signal)
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 = toMultiaddrConnection({
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 (stream: Stream, connection: Connection, signal: AbortSignal): Promise<void> {
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, remotePeer } = await handleIncomingStream(stream, connection, {
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 = toMultiaddrConnection({
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: MultiaddrConnection): void {
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, InvalidMultiaddrError } from '@libp2p/interface'
2
- import { peerIdFromString } from '@libp2p/peer-id'
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, PeerId, Stream } from '@libp2p/interface'
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 = Promise.withResolvers<void>()
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 %o - %e', options.direction, candidateInit, err)
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 - %e', options.direction, err)
69
+ options.log.error('%s error parsing ICE candidate', options.direction, err)
70
70
 
71
- if (options.signal?.aborted === true && pc.connectionState !== 'connected') {
71
+ if (options.signal?.aborted === true && getConnectionState(pc) !== 'connected') {
72
72
  throw err
73
73
  }
74
74
  }
75
75
  }
76
76
 
77
- function resolveOnConnected (pc: RTCPeerConnection, promise: DeferredPromise<void>): void {
78
- if (pc.connectionState === 'connected') {
79
- promise.resolve()
80
- return
81
- }
77
+ export function getConnectionState (pc: RTCPeerConnection): string {
78
+ return isFirefox ? pc.iceConnectionState : pc.connectionState
79
+ }
82
80
 
83
- pc.onconnectionstatechange = (_) => {
84
- switch (pc.connectionState) {
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(`RTCPeerConnection connection state became "${pc.connectionState}"`))
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 { getNetConfig, getThinWaistAddresses } from '@libp2p/utils'
4
- import { CODE_CERTHASH, CODE_WEBRTC_DIRECT, multiaddr } from '@multiformats/multiaddr'
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, type, protocol } = getNetConfig(ma)
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 && type === 'ip4') || (udpMuxServer.isIPv6 && type === 'ip6'))) {
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, type === 'ip4' ? 4 : 6)
122
+ udpMuxServer = this.startUDPMuxServer(host, port, family)
126
123
  UDP_MUX_LISTENERS.push(udpMuxServer)
127
124
  }
128
125
 
129
- if (type === 'ip4') {
126
+ if (family === 4) {
130
127
  udpMuxServer.isIPv4 = true
131
- } else if (type === 'ip6') {
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}/webrtc-direct`),
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 components = ma.getComponents()
241
+ const tuples = ma.stringTuples()
245
242
 
246
- for (let j = 0; j < components.length; j++) {
247
- if (components[j].code !== CODE_WEBRTC_DIRECT) {
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 (components[certhashIndex] == null || components[certhashIndex].code !== CODE_CERTHASH) {
254
- components.splice(certhashIndex, 0, {
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 = multiaddr(components)
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.getComponents().findLast(c => c.code === CODE_P2P)?.value
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
- remotePeer: theirPeerId,
189
+ remotePeerId: theirPeerId,
181
190
  privateKey: this.components.privateKey
182
191
  })
183
192
  } catch (err) {
@@ -1,8 +1,8 @@
1
- import { noise } from '@libp2p/noise'
2
- import { pEvent } from 'p-event'
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
- remotePeer?: PeerId
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 pEvent(handshakeDataChannel, 'open', options)
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
- isHandshake: true,
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 = toMultiaddrConnection({
126
+ const maConn = new WebRTCMultiaddrConnection(options, {
127
127
  peerConnection,
128
128
  remoteAddr: options.remoteAddr,
129
- metrics: options.events,
130
- direction: options.role === 'client' ? 'outbound' : 'inbound',
131
- log: options.logger.forComponent('libp2p:webrtc-direct:connection')
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
- const result = await connectionEncrypter.secureInbound(handshakeStream, {
165
- remotePeer: options.remotePeer,
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.remotePeer,
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
  }