@libp2p/webrtc 3.2.11 → 4.0.0-06e6d235f

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 (76) hide show
  1. package/README.md +1 -1
  2. package/dist/index.min.js +21 -21
  3. package/dist/src/error.d.ts +2 -2
  4. package/dist/src/error.d.ts.map +1 -1
  5. package/dist/src/error.js +1 -1
  6. package/dist/src/error.js.map +1 -1
  7. package/dist/src/index.d.ts +6 -1
  8. package/dist/src/index.d.ts.map +1 -1
  9. package/dist/src/index.js.map +1 -1
  10. package/dist/src/maconn.d.ts +8 -4
  11. package/dist/src/maconn.d.ts.map +1 -1
  12. package/dist/src/maconn.js +6 -6
  13. package/dist/src/maconn.js.map +1 -1
  14. package/dist/src/muxer.d.ts +13 -5
  15. package/dist/src/muxer.d.ts.map +1 -1
  16. package/dist/src/muxer.js +36 -7
  17. package/dist/src/muxer.js.map +1 -1
  18. package/dist/src/pb/message.js.map +1 -1
  19. package/dist/src/private-to-private/initiate-connection.d.ts +4 -5
  20. package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
  21. package/dist/src/private-to-private/initiate-connection.js +4 -5
  22. package/dist/src/private-to-private/initiate-connection.js.map +1 -1
  23. package/dist/src/private-to-private/listener.d.ts +3 -4
  24. package/dist/src/private-to-private/listener.d.ts.map +1 -1
  25. package/dist/src/private-to-private/listener.js +1 -1
  26. package/dist/src/private-to-private/listener.js.map +1 -1
  27. package/dist/src/private-to-private/pb/message.js.map +1 -1
  28. package/dist/src/private-to-private/signaling-stream-handler.d.ts +4 -2
  29. package/dist/src/private-to-private/signaling-stream-handler.d.ts.map +1 -1
  30. package/dist/src/private-to-private/signaling-stream-handler.js +4 -5
  31. package/dist/src/private-to-private/signaling-stream-handler.js.map +1 -1
  32. package/dist/src/private-to-private/transport.d.ts +5 -9
  33. package/dist/src/private-to-private/transport.d.ts.map +1 -1
  34. package/dist/src/private-to-private/transport.js +16 -14
  35. package/dist/src/private-to-private/transport.js.map +1 -1
  36. package/dist/src/private-to-private/util.d.ts +2 -2
  37. package/dist/src/private-to-private/util.d.ts.map +1 -1
  38. package/dist/src/private-to-private/util.js +26 -41
  39. package/dist/src/private-to-private/util.js.map +1 -1
  40. package/dist/src/private-to-public/options.d.ts +1 -1
  41. package/dist/src/private-to-public/options.d.ts.map +1 -1
  42. package/dist/src/private-to-public/sdp.d.ts +2 -1
  43. package/dist/src/private-to-public/sdp.d.ts.map +1 -1
  44. package/dist/src/private-to-public/sdp.js +3 -6
  45. package/dist/src/private-to-public/sdp.js.map +1 -1
  46. package/dist/src/private-to-public/transport.d.ts +4 -5
  47. package/dist/src/private-to-public/transport.d.ts.map +1 -1
  48. package/dist/src/private-to-public/transport.js +26 -15
  49. package/dist/src/private-to-public/transport.js.map +1 -1
  50. package/dist/src/stream.d.ts +10 -4
  51. package/dist/src/stream.d.ts.map +1 -1
  52. package/dist/src/stream.js +19 -33
  53. package/dist/src/stream.js.map +1 -1
  54. package/dist/src/util.d.ts +2 -1
  55. package/dist/src/util.d.ts.map +1 -1
  56. package/dist/src/util.js +4 -6
  57. package/dist/src/util.js.map +1 -1
  58. package/dist/src/webrtc/rtc-data-channel.js.map +1 -1
  59. package/dist/src/webrtc/rtc-ice-candidate.js.map +1 -1
  60. package/dist/src/webrtc/rtc-peer-connection.js.map +1 -1
  61. package/package.json +27 -22
  62. package/src/error.ts +2 -2
  63. package/src/index.ts +7 -1
  64. package/src/maconn.ts +14 -10
  65. package/src/muxer.ts +57 -11
  66. package/src/private-to-private/initiate-connection.ts +7 -11
  67. package/src/private-to-private/listener.ts +3 -4
  68. package/src/private-to-private/signaling-stream-handler.ts +7 -7
  69. package/src/private-to-private/transport.ts +18 -22
  70. package/src/private-to-private/util.ts +30 -46
  71. package/src/private-to-public/options.ts +1 -1
  72. package/src/private-to-public/sdp.ts +4 -8
  73. package/src/private-to-public/transport.ts +27 -19
  74. package/src/stream.ts +27 -39
  75. package/src/util.ts +5 -7
  76. package/dist/typedoc-urls.json +0 -8
@@ -1,6 +1,5 @@
1
- import { noise as Noise } from '@chainsafe/libp2p-noise'
2
- import { type CreateListenerOptions, symbol, type Transport, type Listener } from '@libp2p/interface/transport'
3
- import { logger } from '@libp2p/logger'
1
+ import { noise } from '@chainsafe/libp2p-noise'
2
+ import { type CreateListenerOptions, transportSymbol, type Transport, type Listener, type ComponentLogger, type Logger, type Connection, type CounterGroup, type Metrics, type PeerId } from '@libp2p/interface'
4
3
  import * as p from '@libp2p/peer-id'
5
4
  import { protocols } from '@multiformats/multiaddr'
6
5
  import { WebRTCDirect } from '@multiformats/multiaddr-matcher'
@@ -17,13 +16,8 @@ import * as sdp from './sdp.js'
17
16
  import { genUfrag } from './util.js'
18
17
  import type { WebRTCDialOptions } from './options.js'
19
18
  import type { DataChannelOptions } from '../index.js'
20
- import type { Connection } from '@libp2p/interface/connection'
21
- import type { CounterGroup, Metrics } from '@libp2p/interface/metrics'
22
- import type { PeerId } from '@libp2p/interface/peer-id'
23
19
  import type { Multiaddr } from '@multiformats/multiaddr'
24
20
 
25
- const log = logger('libp2p:webrtc:transport')
26
-
27
21
  /**
28
22
  * The time to wait, in milliseconds, for the data channel handshake to complete
29
23
  */
@@ -49,6 +43,7 @@ export const CERTHASH_CODE: number = protocols('certhash').code
49
43
  export interface WebRTCDirectTransportComponents {
50
44
  peerId: PeerId
51
45
  metrics?: Metrics
46
+ logger: ComponentLogger
52
47
  }
53
48
 
54
49
  export interface WebRTCMetrics {
@@ -60,10 +55,12 @@ export interface WebRTCTransportDirectInit {
60
55
  }
61
56
 
62
57
  export class WebRTCDirectTransport implements Transport {
58
+ private readonly log: Logger
63
59
  private readonly metrics?: WebRTCMetrics
64
60
  private readonly components: WebRTCDirectTransportComponents
65
61
  private readonly init: WebRTCTransportDirectInit
66
62
  constructor (components: WebRTCDirectTransportComponents, init: WebRTCTransportDirectInit = {}) {
63
+ this.log = components.logger.forComponent('libp2p:webrtc-direct')
67
64
  this.components = components
68
65
  this.init = init
69
66
  if (components.metrics != null) {
@@ -81,7 +78,7 @@ export class WebRTCDirectTransport implements Transport {
81
78
  */
82
79
  async dial (ma: Multiaddr, options: WebRTCDialOptions): Promise<Connection> {
83
80
  const rawConn = await this._connect(ma, options)
84
- log('dialing address: %a', ma)
81
+ this.log('dialing address: %a', ma)
85
82
  return rawConn
86
83
  }
87
84
 
@@ -107,7 +104,7 @@ export class WebRTCDirectTransport implements Transport {
107
104
  /**
108
105
  * Symbol.for('@libp2p/transport')
109
106
  */
110
- readonly [symbol] = true
107
+ readonly [transportSymbol] = true
111
108
 
112
109
  /**
113
110
  * Connect to a peer using a multiaddr
@@ -144,7 +141,7 @@ export class WebRTCDirectTransport implements Transport {
144
141
  const handshakeDataChannel = peerConnection.createDataChannel('', { negotiated: true, id: 0 })
145
142
  const handshakeTimeout = setTimeout(() => {
146
143
  const error = `Data channel was never opened: state: ${handshakeDataChannel.readyState}`
147
- log.error(error)
144
+ this.log.error(error)
148
145
  this.metrics?.dialerEvents.increment({ open_error: true })
149
146
  reject(dataChannelError('data', error))
150
147
  }, HANDSHAKE_TIMEOUT_MS)
@@ -159,7 +156,7 @@ export class WebRTCDirectTransport implements Transport {
159
156
  clearTimeout(handshakeTimeout)
160
157
  const errorTarget = event.target?.toString() ?? 'not specified'
161
158
  const error = `Error opening a data channel for handshaking: ${errorTarget}`
162
- log.error(error)
159
+ this.log.error(error)
163
160
  // NOTE: We use unknown error here but this could potentially be considered a reset by some standards.
164
161
  this.metrics?.dialerEvents.increment({ unknown_error: true })
165
162
  reject(dataChannelError('data', error))
@@ -192,9 +189,14 @@ export class WebRTCDirectTransport implements Transport {
192
189
 
193
190
  // Since we use the default crypto interface and do not use a static key or early data,
194
191
  // we pass in undefined for these parameters.
195
- const noise = Noise({ prologueBytes: fingerprintsPrologue })()
192
+ const connectionEncrypter = noise({ prologueBytes: fingerprintsPrologue })(this.components)
196
193
 
197
- const wrappedChannel = createStream({ channel: handshakeDataChannel, direction: 'inbound', ...(this.init.dataChannel ?? {}) })
194
+ const wrappedChannel = createStream({
195
+ channel: handshakeDataChannel,
196
+ direction: 'inbound',
197
+ logger: this.components.logger,
198
+ ...(this.init.dataChannel ?? {})
199
+ })
198
200
  const wrappedDuplex = {
199
201
  ...wrappedChannel,
200
202
  sink: wrappedChannel.sink.bind(wrappedChannel),
@@ -209,7 +211,7 @@ export class WebRTCDirectTransport implements Transport {
209
211
 
210
212
  // Creating the connection before completion of the noise
211
213
  // handshake ensures that the stream opening callback is set up
212
- const maConn = new WebRTCMultiaddrConnection({
214
+ const maConn = new WebRTCMultiaddrConnection(this.components, {
213
215
  peerConnection,
214
216
  remoteAddr: ma,
215
217
  timeline: {
@@ -226,7 +228,7 @@ export class WebRTCDirectTransport implements Transport {
226
228
  case 'disconnected':
227
229
  case 'closed':
228
230
  maConn.close().catch((err) => {
229
- log.error('error closing connection', err)
231
+ this.log.error('error closing connection', err)
230
232
  }).finally(() => {
231
233
  // Remove the event listener once the connection is closed
232
234
  controller.abort()
@@ -240,11 +242,15 @@ export class WebRTCDirectTransport implements Transport {
240
242
  // Track opened peer connection
241
243
  this.metrics?.dialerEvents.increment({ peer_connection: true })
242
244
 
243
- const muxerFactory = new DataChannelMuxerFactory({ peerConnection, metrics: this.metrics?.dialerEvents, dataChannelOptions: this.init.dataChannel })
245
+ const muxerFactory = new DataChannelMuxerFactory(this.components, {
246
+ peerConnection,
247
+ metrics: this.metrics?.dialerEvents,
248
+ dataChannelOptions: this.init.dataChannel
249
+ })
244
250
 
245
251
  // For outbound connections, the remote is expected to start the noise handshake.
246
252
  // Therefore, we need to secure an inbound noise connection from the remote.
247
- await noise.secureInbound(myPeerId, wrappedDuplex, theirPeerId)
253
+ await connectionEncrypter.secureInbound(myPeerId, wrappedDuplex, theirPeerId)
248
254
 
249
255
  return await options.upgrader.upgradeOutbound(maConn, { skipProtection: true, skipEncryption: true, muxerFactory })
250
256
  } catch (err) {
@@ -262,7 +268,9 @@ export class WebRTCDirectTransport implements Transport {
262
268
  throw invalidArgument('no local certificate')
263
269
  }
264
270
 
265
- const localFingerprint = sdp.getLocalFingerprint(pc)
271
+ const localFingerprint = sdp.getLocalFingerprint(pc, {
272
+ log: this.log
273
+ })
266
274
  if (localFingerprint == null) {
267
275
  throw invalidArgument('no local fingerprint found')
268
276
  }
package/src/stream.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { CodeError } from '@libp2p/interface/errors'
2
- import { AbstractStream, type AbstractStreamInit } from '@libp2p/interface/stream-muxer/stream'
3
- import { logger } from '@libp2p/logger'
1
+ import { CodeError } from '@libp2p/interface'
2
+ import { AbstractStream, type AbstractStreamInit } from '@libp2p/utils/abstract-stream'
4
3
  import * as lengthPrefixed from 'it-length-prefixed'
5
4
  import { type Pushable, pushable } from 'it-pushable'
6
5
  import pDefer from 'p-defer'
@@ -10,8 +9,7 @@ import { raceSignal } from 'race-signal'
10
9
  import { Uint8ArrayList } from 'uint8arraylist'
11
10
  import { Message } from './pb/message.js'
12
11
  import type { DataChannelOptions } from './index.js'
13
- import type { AbortOptions } from '@libp2p/interface'
14
- import type { Direction } from '@libp2p/interface/connection'
12
+ import type { AbortOptions, ComponentLogger, Direction } from '@libp2p/interface'
15
13
  import type { DeferredPromise } from 'p-defer'
16
14
 
17
15
  export interface WebRTCStreamInit extends AbstractStreamInit, DataChannelOptions {
@@ -22,6 +20,8 @@ export interface WebRTCStreamInit extends AbstractStreamInit, DataChannelOptions
22
20
  * {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel}
23
21
  */
24
22
  channel: RTCDataChannel
23
+
24
+ logger: ComponentLogger
25
25
  }
26
26
 
27
27
  /**
@@ -56,6 +56,12 @@ export const MAX_MESSAGE_SIZE = 16 * 1024
56
56
  */
57
57
  export const FIN_ACK_TIMEOUT = 5000
58
58
 
59
+ /**
60
+ * When sending data messages, if the channel is not in the "open" state, wait
61
+ * this long for the "open" event to fire.
62
+ */
63
+ export const OPEN_TIMEOUT = 5000
64
+
59
65
  export class WebRTCStream extends AbstractStream {
60
66
  /**
61
67
  * The data channel used to send and receive data
@@ -68,8 +74,6 @@ export class WebRTCStream extends AbstractStream {
68
74
  */
69
75
  private readonly incomingData: Pushable<Uint8Array>
70
76
 
71
- private messageQueue?: Uint8ArrayList
72
-
73
77
  private readonly maxBufferedAmount: number
74
78
 
75
79
  private readonly bufferedAmountLowEventTimeout: number
@@ -84,6 +88,7 @@ export class WebRTCStream extends AbstractStream {
84
88
  */
85
89
  private readonly receiveFinAck: DeferredPromise<void>
86
90
  private readonly finAckTimeout: number
91
+ private readonly openTimeout: number
87
92
 
88
93
  constructor (init: WebRTCStreamInit) {
89
94
  // override onEnd to send/receive FIN_ACK before closing the stream
@@ -121,17 +126,18 @@ export class WebRTCStream extends AbstractStream {
121
126
 
122
127
  this.channel = init.channel
123
128
  this.channel.binaryType = 'arraybuffer'
124
- this.incomingData = pushable()
125
- this.messageQueue = new Uint8ArrayList()
129
+ this.incomingData = pushable<Uint8Array>()
126
130
  this.bufferedAmountLowEventTimeout = init.bufferedAmountLowEventTimeout ?? BUFFERED_AMOUNT_LOW_TIMEOUT
127
131
  this.maxBufferedAmount = init.maxBufferedAmount ?? MAX_BUFFERED_AMOUNT
128
132
  this.maxMessageSize = (init.maxMessageSize ?? MAX_MESSAGE_SIZE) - PROTOBUF_OVERHEAD - VARINT_LENGTH
129
133
  this.receiveFinAck = pDefer()
130
134
  this.finAckTimeout = init.closeTimeout ?? FIN_ACK_TIMEOUT
135
+ this.openTimeout = init.openTimeout ?? OPEN_TIMEOUT
131
136
 
132
137
  // set up initial state
133
138
  switch (this.channel.readyState) {
134
139
  case 'open':
140
+ this.timeline.open = new Date().getTime()
135
141
  break
136
142
 
137
143
  case 'closed':
@@ -152,19 +158,6 @@ export class WebRTCStream extends AbstractStream {
152
158
  // handle RTCDataChannel events
153
159
  this.channel.onopen = (_evt) => {
154
160
  this.timeline.open = new Date().getTime()
155
-
156
- if (this.messageQueue != null && this.messageQueue.byteLength > 0) {
157
- this.log.trace('dataChannel opened, sending queued messages', this.messageQueue.byteLength, this.channel.readyState)
158
-
159
- // send any queued messages
160
- this._sendMessage(this.messageQueue)
161
- .catch(err => {
162
- this.log.error('error sending queued messages', err)
163
- this.abort(err)
164
- })
165
- }
166
-
167
- this.messageQueue = undefined
168
161
  }
169
162
 
170
163
  this.channel.onclose = (_evt) => {
@@ -217,6 +210,7 @@ export class WebRTCStream extends AbstractStream {
217
210
  async _sendMessage (data: Uint8ArrayList, checkBuffer: boolean = true): Promise<void> {
218
211
  if (checkBuffer && this.channel.bufferedAmount > this.maxBufferedAmount) {
219
212
  try {
213
+ this.log('channel buffer is %d, wait for "bufferedamountlow" event', this.channel.bufferedAmount)
220
214
  await pEvent(this.channel, 'bufferedamountlow', { timeout: this.bufferedAmountLowEventTimeout })
221
215
  } catch (err: any) {
222
216
  if (err instanceof TimeoutError) {
@@ -231,22 +225,14 @@ export class WebRTCStream extends AbstractStream {
231
225
  throw new CodeError(`Invalid datachannel state - ${this.channel.readyState}`, 'ERR_INVALID_STATE')
232
226
  }
233
227
 
234
- if (this.channel.readyState === 'open') {
235
- // send message without copying data
236
- for (const buf of data) {
237
- this.channel.send(buf)
238
- }
239
- } else if (this.channel.readyState === 'connecting') {
240
- // queue message for when we are open
241
- if (this.messageQueue == null) {
242
- this.messageQueue = new Uint8ArrayList()
243
- }
244
-
245
- this.messageQueue.append(data)
246
- } else {
247
- this.log.error('unknown datachannel state %s', this.channel.readyState)
248
- throw new CodeError('Unknown datachannel state', 'ERR_INVALID_STATE')
228
+ if (this.channel.readyState !== 'open') {
229
+ this.log('channel state is "%s" and not "open", waiting for "open" event before sending data', this.channel.readyState)
230
+ await pEvent(this.channel, 'open', { timeout: this.openTimeout })
231
+ this.log('channel state is now "%s", sending data', this.channel.readyState)
249
232
  }
233
+
234
+ // send message without copying data
235
+ this.channel.send(data.subarray())
250
236
  }
251
237
 
252
238
  async sendData (data: Uint8ArrayList): Promise<void> {
@@ -341,7 +327,7 @@ export class WebRTCStream extends AbstractStream {
341
327
  // flags can be sent while we or the remote are closing the datachannel so
342
328
  // if the channel isn't open, don't try to send it but return false to let
343
329
  // the caller know and act if they need to
344
- this.log.trace('not sending flag %s because channel is not open', flag.toString())
330
+ this.log.trace('not sending flag %s because channel is "%s" and not "open"', this.channel.readyState, flag.toString())
345
331
  return false
346
332
  }
347
333
 
@@ -379,6 +365,8 @@ export interface WebRTCStreamOptions extends DataChannelOptions {
379
365
  * A callback invoked when the channel ends
380
366
  */
381
367
  onEnd?(err?: Error | undefined): void
368
+
369
+ logger: ComponentLogger
382
370
  }
383
371
 
384
372
  export function createStream (options: WebRTCStreamOptions): WebRTCStream {
@@ -386,7 +374,7 @@ export function createStream (options: WebRTCStreamOptions): WebRTCStream {
386
374
 
387
375
  return new WebRTCStream({
388
376
  id: direction === 'inbound' ? (`i${channel.id}`) : `r${channel.id}`,
389
- log: logger(`libp2p:webrtc:stream:${direction}:${channel.id}`),
377
+ log: options.logger.forComponent(`libp2p:webrtc:stream:${direction}:${channel.id}`),
390
378
  ...options
391
379
  })
392
380
  }
package/src/util.ts CHANGED
@@ -1,9 +1,7 @@
1
- import { logger } from '@libp2p/logger'
2
1
  import { detect } from 'detect-browser'
3
2
  import pDefer from 'p-defer'
4
3
  import pTimeout from 'p-timeout'
5
-
6
- const log = logger('libp2p:webrtc:utils')
4
+ import type { LoggerOptions } from '@libp2p/interface'
7
5
 
8
6
  const browser = detect()
9
7
  export const isFirefox = ((browser != null) && browser.name === 'firefox')
@@ -14,7 +12,7 @@ export const nopSink = async (_: any): Promise<void> => {}
14
12
 
15
13
  export const DATA_CHANNEL_DRAIN_TIMEOUT = 30 * 1000
16
14
 
17
- export function drainAndClose (channel: RTCDataChannel, direction: string, drainTimeout: number = DATA_CHANNEL_DRAIN_TIMEOUT): void {
15
+ export function drainAndClose (channel: RTCDataChannel, direction: string, drainTimeout: number = DATA_CHANNEL_DRAIN_TIMEOUT, options: LoggerOptions): void {
18
16
  if (channel.readyState !== 'open') {
19
17
  return
20
18
  }
@@ -23,7 +21,7 @@ export function drainAndClose (channel: RTCDataChannel, direction: string, drain
23
21
  .then(async () => {
24
22
  // wait for bufferedAmount to become zero
25
23
  if (channel.bufferedAmount > 0) {
26
- log('%s drain channel with %d buffered bytes', direction, channel.bufferedAmount)
24
+ options.log('%s drain channel with %d buffered bytes', direction, channel.bufferedAmount)
27
25
  const deferred = pDefer()
28
26
  let drained = false
29
27
 
@@ -31,7 +29,7 @@ export function drainAndClose (channel: RTCDataChannel, direction: string, drain
31
29
 
32
30
  const closeListener = (): void => {
33
31
  if (!drained) {
34
- log('%s drain channel closed before drain', direction)
32
+ options.log('%s drain channel closed before drain', direction)
35
33
  deferred.resolve()
36
34
  }
37
35
  }
@@ -58,7 +56,7 @@ export function drainAndClose (channel: RTCDataChannel, direction: string, drain
58
56
  }
59
57
  })
60
58
  .catch(err => {
61
- log.error('error closing outbound stream', err)
59
+ options.log.error('error closing outbound stream', err)
62
60
  })
63
61
  }
64
62
 
@@ -1,8 +0,0 @@
1
- {
2
- "DataChannelOptions": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webrtc.DataChannelOptions.html",
3
- ".:DataChannelOptions": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_webrtc.DataChannelOptions.html",
4
- "webRTC": "https://libp2p.github.io/js-libp2p/functions/_libp2p_webrtc.webRTC.html",
5
- ".:webRTC": "https://libp2p.github.io/js-libp2p/functions/_libp2p_webrtc.webRTC.html",
6
- "webRTCDirect": "https://libp2p.github.io/js-libp2p/functions/_libp2p_webrtc.webRTCDirect.html",
7
- ".:webRTCDirect": "https://libp2p.github.io/js-libp2p/functions/_libp2p_webrtc.webRTCDirect.html"
8
- }