@libp2p/webrtc 1.1.11 → 2.0.0

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 (39) hide show
  1. package/README.md +3 -3
  2. package/dist/index.min.js +21 -17
  3. package/dist/src/maconn.d.ts +9 -0
  4. package/dist/src/maconn.d.ts.map +1 -1
  5. package/dist/src/maconn.js +10 -0
  6. package/dist/src/maconn.js.map +1 -1
  7. package/dist/src/muxer.d.ts +12 -2
  8. package/dist/src/muxer.d.ts.map +1 -1
  9. package/dist/src/muxer.js +16 -4
  10. package/dist/src/muxer.js.map +1 -1
  11. package/dist/src/peer_transport/handler.d.ts +10 -2
  12. package/dist/src/peer_transport/handler.d.ts.map +1 -1
  13. package/dist/src/peer_transport/handler.js +14 -2
  14. package/dist/src/peer_transport/handler.js.map +1 -1
  15. package/dist/src/peer_transport/listener.d.ts +6 -7
  16. package/dist/src/peer_transport/listener.d.ts.map +1 -1
  17. package/dist/src/peer_transport/listener.js +26 -24
  18. package/dist/src/peer_transport/listener.js.map +1 -1
  19. package/dist/src/peer_transport/transport.d.ts +4 -6
  20. package/dist/src/peer_transport/transport.d.ts.map +1 -1
  21. package/dist/src/peer_transport/transport.js +21 -20
  22. package/dist/src/peer_transport/transport.js.map +1 -1
  23. package/dist/src/peer_transport/util.js +1 -1
  24. package/dist/src/peer_transport/util.js.map +1 -1
  25. package/dist/src/stream.js +1 -1
  26. package/dist/src/stream.js.map +1 -1
  27. package/dist/src/transport.d.ts +6 -3
  28. package/dist/src/transport.d.ts.map +1 -1
  29. package/dist/src/transport.js +22 -12
  30. package/dist/src/transport.js.map +1 -1
  31. package/package.json +15 -15
  32. package/src/maconn.ts +18 -1
  33. package/src/muxer.ts +23 -4
  34. package/src/peer_transport/handler.ts +23 -5
  35. package/src/peer_transport/listener.ts +39 -28
  36. package/src/peer_transport/transport.ts +29 -24
  37. package/src/peer_transport/util.ts +1 -1
  38. package/src/stream.ts +1 -1
  39. package/src/transport.ts +29 -13
@@ -1,4 +1,4 @@
1
- import { type CreateListenerOptions, type DialOptions, type Listener, symbol, type Transport, type TransportManager, type Upgrader } from '@libp2p/interface-transport'
1
+ import { type CreateListenerOptions, type DialOptions, type Listener, symbol, type Transport, type Upgrader, type TransportManager } from '@libp2p/interface-transport'
2
2
  import { CodeError } from '@libp2p/interfaces/errors'
3
3
  import { logger } from '@libp2p/logger'
4
4
  import { peerIdFromString } from '@libp2p/peer-id'
@@ -8,16 +8,18 @@ import { WebRTCMultiaddrConnection } from '../maconn.js'
8
8
  import { initiateConnection, handleIncomingStream } from './handler.js'
9
9
  import { WebRTCPeerListener } from './listener.js'
10
10
  import type { Connection } from '@libp2p/interface-connection'
11
+ import type { Libp2pEvents } from '@libp2p/interface-libp2p'
11
12
  import type { PeerId } from '@libp2p/interface-peer-id'
12
- import type { PeerStore } from '@libp2p/interface-peer-store'
13
13
  import type { IncomingStreamData, Registrar } from '@libp2p/interface-registrar'
14
+ import type { EventEmitter } from '@libp2p/interfaces/events'
14
15
  import type { Startable } from '@libp2p/interfaces/startable'
15
16
 
16
17
  const log = logger('libp2p:webrtc:peer')
17
18
 
18
- export const TRANSPORT = '/webrtc'
19
- export const SIGNALING_PROTO_ID = '/webrtc-signaling/0.0.1'
20
- export const CODE = protocols('webrtc').code
19
+ const WEBRTC_TRANSPORT = '/webrtc'
20
+ const CIRCUIT_RELAY_TRANSPORT = '/p2p-circuit'
21
+ const SIGNALING_PROTO_ID = '/webrtc-signaling/0.0.1'
22
+ const WEBRTC_CODE = protocols('webrtc').code
21
23
 
22
24
  export interface WebRTCTransportInit {
23
25
  rtcConfiguration?: RTCConfiguration
@@ -28,7 +30,7 @@ export interface WebRTCTransportComponents {
28
30
  registrar: Registrar
29
31
  upgrader: Upgrader
30
32
  transportManager: TransportManager
31
- peerStore: PeerStore
33
+ events: EventEmitter<Libp2pEvents>
32
34
  }
33
35
 
34
36
  export class WebRTCTransport implements Transport, Startable {
@@ -67,22 +69,27 @@ export class WebRTCTransport implements Transport, Startable {
67
69
  filter (multiaddrs: Multiaddr[]): Multiaddr[] {
68
70
  return multiaddrs.filter((ma) => {
69
71
  const codes = ma.protoCodes()
70
- return codes.includes(CODE)
72
+ return codes.includes(WEBRTC_CODE)
71
73
  })
72
74
  }
73
75
 
74
76
  private splitAddr (ma: Multiaddr): { baseAddr: Multiaddr, peerId: PeerId } {
75
- const addrs = ma.toString().split(`${TRANSPORT}/`)
77
+ const addrs = ma.toString().split(WEBRTC_TRANSPORT)
76
78
  if (addrs.length !== 2) {
77
- throw new CodeError('invalid multiaddr', codes.ERR_INVALID_MULTIADDR)
79
+ throw new CodeError('webrtc protocol was not present in multiaddr', codes.ERR_INVALID_MULTIADDR)
80
+ }
81
+
82
+ if (!addrs[0].includes(CIRCUIT_RELAY_TRANSPORT)) {
83
+ throw new CodeError('p2p-circuit protocol was not present in multiaddr', codes.ERR_INVALID_MULTIADDR)
78
84
  }
85
+
79
86
  // look for remote peerId
80
87
  let remoteAddr = multiaddr(addrs[0])
81
- const destination = multiaddr('/' + addrs[1])
88
+ const destination = multiaddr(addrs[1])
82
89
 
83
90
  const destinationIdString = destination.getPeerId()
84
91
  if (destinationIdString == null) {
85
- throw new CodeError('bad destination', codes.ERR_INVALID_MULTIADDR)
92
+ throw new CodeError('destination peer id was missing', codes.ERR_INVALID_MULTIADDR)
86
93
  }
87
94
 
88
95
  const lastProtoInRemote = remoteAddr.protos().pop()
@@ -112,22 +119,21 @@ export class WebRTCTransport implements Transport, Startable {
112
119
  options.signal = controller.signal
113
120
  }
114
121
 
115
- const connection = await this.components.transportManager.dial(baseAddr)
116
-
117
- const rawStream = await connection.newStream([SIGNALING_PROTO_ID], options)
122
+ const connection = await this.components.transportManager.dial(baseAddr, options)
123
+ const signalingStream = await connection.newStream([SIGNALING_PROTO_ID], options)
118
124
 
119
125
  try {
120
- const [pc, muxerFactory] = await initiateConnection({
121
- stream: rawStream,
126
+ const { pc, muxerFactory, remoteAddress } = await initiateConnection({
127
+ stream: signalingStream,
122
128
  rtcConfiguration: this.init.rtcConfiguration,
123
129
  signal: options.signal
124
130
  })
125
- const webrtcMultiaddr = baseAddr.encapsulate(`${TRANSPORT}/p2p/${peerId.toString()}`)
131
+
126
132
  const result = await options.upgrader.upgradeOutbound(
127
133
  new WebRTCMultiaddrConnection({
128
134
  peerConnection: pc,
129
135
  timeline: { open: Date.now() },
130
- remoteAddr: webrtcMultiaddr
136
+ remoteAddr: multiaddr(remoteAddress).encapsulate(`/p2p/${peerId.toString()}`)
131
137
  }),
132
138
  {
133
139
  skipProtection: true,
@@ -137,28 +143,27 @@ export class WebRTCTransport implements Transport, Startable {
137
143
  )
138
144
 
139
145
  // close the stream if SDP has been exchanged successfully
140
- rawStream.close()
146
+ signalingStream.close()
141
147
  return result
142
148
  } catch (err) {
143
149
  // reset the stream in case of any error
144
- rawStream.reset()
150
+ signalingStream.reset()
145
151
  throw err
146
152
  }
147
153
  }
148
154
 
149
155
  async _onProtocol ({ connection, stream }: IncomingStreamData): Promise<void> {
150
156
  try {
151
- const [pc, muxerFactory] = await handleIncomingStream({
157
+ const { pc, muxerFactory, remoteAddress } = await handleIncomingStream({
152
158
  rtcConfiguration: this.init.rtcConfiguration,
153
159
  connection,
154
160
  stream
155
161
  })
156
- const remotePeerId = connection.remoteAddr.getPeerId()
157
- const webrtcMultiaddr = connection.remoteAddr.encapsulate(`${TRANSPORT}/p2p/${remotePeerId}`)
162
+
158
163
  await this.components.upgrader.upgradeInbound(new WebRTCMultiaddrConnection({
159
164
  peerConnection: pc,
160
165
  timeline: { open: (new Date()).getTime() },
161
- remoteAddr: webrtcMultiaddr
166
+ remoteAddr: multiaddr(remoteAddress).encapsulate(`/p2p/${connection.remotePeer.toString()}`)
162
167
  }), {
163
168
  skipEncryption: true,
164
169
  skipProtection: true,
@@ -53,7 +53,7 @@ export function resolveOnConnected (pc: RTCPeerConnection, promise: DeferredProm
53
53
  case 'failed':
54
54
  case 'disconnected':
55
55
  case 'closed':
56
- promise.reject()
56
+ promise.reject(new Error('RTCPeerConnection was closed'))
57
57
  break
58
58
  default:
59
59
  break
package/src/stream.ts CHANGED
@@ -268,7 +268,7 @@ export class WebRTCStream implements Stream {
268
268
  // surface data from the `Message.message` field through a source.
269
269
  this._src = pipe(
270
270
  this._innersrc,
271
- lengthPrefixed.decode(),
271
+ (source) => lengthPrefixed.decode(source),
272
272
  (source) => (async function * () {
273
273
  for await (const buf of source) {
274
274
  const message = self.processIncomingProtobuf(buf.subarray())
package/src/transport.ts CHANGED
@@ -15,6 +15,7 @@ import { WebRTCStream } from './stream.js'
15
15
  import { genUfrag } from './util.js'
16
16
  import type { WebRTCDialOptions } from './options.js'
17
17
  import type { Connection } from '@libp2p/interface-connection'
18
+ import type { CounterGroup, Metrics } from '@libp2p/interface-metrics'
18
19
  import type { PeerId } from '@libp2p/interface-peer-id'
19
20
  import type { Multiaddr } from '@multiformats/multiaddr'
20
21
 
@@ -42,19 +43,29 @@ export const CERTHASH_CODE: number = protocols('certhash').code
42
43
  /**
43
44
  * The peer for this transport
44
45
  */
45
- // @TODO(ddimaria): seems like an unnessary abstraction, consider removing
46
46
  export interface WebRTCDirectTransportComponents {
47
47
  peerId: PeerId
48
+ metrics?: Metrics
49
+ }
50
+
51
+ export interface WebRTCMetrics {
52
+ dialerEvents: CounterGroup
48
53
  }
49
54
 
50
55
  export class WebRTCDirectTransport implements Transport {
51
- /**
52
- * The peer for this transport
53
- */
56
+ private readonly metrics?: WebRTCMetrics
54
57
  private readonly components: WebRTCDirectTransportComponents
55
58
 
56
59
  constructor (components: WebRTCDirectTransportComponents) {
57
60
  this.components = components
61
+ if (components.metrics != null) {
62
+ this.metrics = {
63
+ dialerEvents: components.metrics.registerCounterGroup('libp2p_webrtc_dialer_events_total', {
64
+ label: 'event',
65
+ help: 'Total count of WebRTC dial events by type'
66
+ })
67
+ }
68
+ }
58
69
  }
59
70
 
60
71
  /**
@@ -125,6 +136,7 @@ export class WebRTCDirectTransport implements Transport {
125
136
  const handshakeTimeout = setTimeout(() => {
126
137
  const error = `Data channel was never opened: state: ${handshakeDataChannel.readyState}`
127
138
  log.error(error)
139
+ this.metrics?.dialerEvents.increment({ open_error: true })
128
140
  reject(dataChannelError('data', error))
129
141
  }, HANDSHAKE_TIMEOUT_MS)
130
142
 
@@ -139,6 +151,8 @@ export class WebRTCDirectTransport implements Transport {
139
151
  const errorTarget = event.target?.toString() ?? 'not specified'
140
152
  const error = `Error opening a data channel for handshaking: ${errorTarget}`
141
153
  log.error(error)
154
+ // NOTE: We use unknown error here but this could potentially be considered a reset by some standards.
155
+ this.metrics?.dialerEvents.increment({ unknown_error: true })
142
156
  reject(dataChannelError('data', error))
143
157
  }
144
158
  })
@@ -175,15 +189,13 @@ export class WebRTCDirectTransport implements Transport {
175
189
  const wrappedDuplex = {
176
190
  ...wrappedChannel,
177
191
  sink: wrappedChannel.sink.bind(wrappedChannel),
178
- source: {
179
- [Symbol.asyncIterator]: async function * () {
180
- for await (const list of wrappedChannel.source) {
181
- for (const buf of list) {
182
- yield buf
183
- }
192
+ source: (async function * () {
193
+ for await (const list of wrappedChannel.source) {
194
+ for (const buf of list) {
195
+ yield buf
184
196
  }
185
197
  }
186
- }
198
+ }())
187
199
  }
188
200
 
189
201
  // Creating the connection before completion of the noise
@@ -193,7 +205,8 @@ export class WebRTCDirectTransport implements Transport {
193
205
  remoteAddr: ma,
194
206
  timeline: {
195
207
  open: Date.now()
196
- }
208
+ },
209
+ metrics: this.metrics?.dialerEvents
197
210
  })
198
211
 
199
212
  const eventListeningName = isFirefox ? 'iceconnectionstatechange' : 'connectionstatechange'
@@ -215,7 +228,10 @@ export class WebRTCDirectTransport implements Transport {
215
228
  }
216
229
  }, { signal })
217
230
 
218
- const muxerFactory = new DataChannelMuxerFactory(peerConnection)
231
+ // Track opened peer connection
232
+ this.metrics?.dialerEvents.increment({ peer_connection: true })
233
+
234
+ const muxerFactory = new DataChannelMuxerFactory(peerConnection, this.metrics?.dialerEvents)
219
235
 
220
236
  // For outbound connections, the remote is expected to start the noise handshake.
221
237
  // Therefore, we need to secure an inbound noise connection from the remote.