@libp2p/webrtc 3.2.6 → 3.2.7

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 (30) hide show
  1. package/dist/index.min.js +10 -11
  2. package/dist/src/muxer.d.ts +9 -2
  3. package/dist/src/muxer.d.ts.map +1 -1
  4. package/dist/src/muxer.js +32 -21
  5. package/dist/src/muxer.js.map +1 -1
  6. package/dist/src/private-to-private/initiate-connection.d.ts +1 -1
  7. package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
  8. package/dist/src/private-to-private/initiate-connection.js +4 -6
  9. package/dist/src/private-to-private/initiate-connection.js.map +1 -1
  10. package/dist/src/private-to-private/signaling-stream-handler.d.ts +2 -1
  11. package/dist/src/private-to-private/signaling-stream-handler.d.ts.map +1 -1
  12. package/dist/src/private-to-private/signaling-stream-handler.js +3 -2
  13. package/dist/src/private-to-private/signaling-stream-handler.js.map +1 -1
  14. package/dist/src/private-to-private/transport.d.ts.map +1 -1
  15. package/dist/src/private-to-private/transport.js +6 -8
  16. package/dist/src/private-to-private/transport.js.map +1 -1
  17. package/dist/src/private-to-private/util.d.ts +0 -1
  18. package/dist/src/private-to-private/util.d.ts.map +1 -1
  19. package/dist/src/private-to-private/util.js +0 -10
  20. package/dist/src/private-to-private/util.js.map +1 -1
  21. package/dist/src/stream.d.ts.map +1 -1
  22. package/dist/src/stream.js +0 -1
  23. package/dist/src/stream.js.map +1 -1
  24. package/package.json +2 -2
  25. package/src/muxer.ts +46 -22
  26. package/src/private-to-private/initiate-connection.ts +5 -7
  27. package/src/private-to-private/signaling-stream-handler.ts +4 -3
  28. package/src/private-to-private/transport.ts +6 -8
  29. package/src/private-to-private/util.ts +0 -13
  30. package/src/stream.ts +0 -1
package/src/muxer.ts CHANGED
@@ -32,6 +32,14 @@ export interface DataChannelMuxerFactoryInit {
32
32
  dataChannelOptions?: DataChannelOptions
33
33
  }
34
34
 
35
+ interface BufferedStream {
36
+ stream: Stream
37
+ channel: RTCDataChannel
38
+ onEnd(err?: Error): void
39
+ }
40
+
41
+ let streamIndex = 0
42
+
35
43
  export class DataChannelMuxerFactory implements StreamMuxerFactory {
36
44
  public readonly protocol: string
37
45
 
@@ -39,7 +47,7 @@ export class DataChannelMuxerFactory implements StreamMuxerFactory {
39
47
  * WebRTC Peer Connection
40
48
  */
41
49
  private readonly peerConnection: RTCPeerConnection
42
- private streamBuffer: Stream[] = []
50
+ private bufferedStreams: BufferedStream[] = []
43
51
  private readonly metrics?: CounterGroup
44
52
  private readonly dataChannelOptions?: DataChannelOptions
45
53
 
@@ -51,15 +59,25 @@ export class DataChannelMuxerFactory implements StreamMuxerFactory {
51
59
 
52
60
  // store any datachannels opened before upgrade has been completed
53
61
  this.peerConnection.ondatachannel = ({ channel }) => {
62
+ // @ts-expect-error fields are set below
63
+ const bufferedStream: BufferedStream = {}
64
+
54
65
  const stream = createStream({
55
66
  channel,
56
67
  direction: 'inbound',
57
- onEnd: () => {
58
- this.streamBuffer = this.streamBuffer.filter(s => s.id !== stream.id)
68
+ onEnd: (err) => {
69
+ bufferedStream.onEnd(err)
59
70
  },
60
71
  ...this.dataChannelOptions
61
72
  })
62
- this.streamBuffer.push(stream)
73
+
74
+ bufferedStream.stream = stream
75
+ bufferedStream.channel = channel
76
+ bufferedStream.onEnd = () => {
77
+ this.bufferedStreams = this.bufferedStreams.filter(s => s.stream.id !== stream.id)
78
+ }
79
+
80
+ this.bufferedStreams.push(bufferedStream)
63
81
  }
64
82
  }
65
83
 
@@ -69,14 +87,14 @@ export class DataChannelMuxerFactory implements StreamMuxerFactory {
69
87
  peerConnection: this.peerConnection,
70
88
  dataChannelOptions: this.dataChannelOptions,
71
89
  metrics: this.metrics,
72
- streams: this.streamBuffer,
90
+ streams: this.bufferedStreams,
73
91
  protocol: this.protocol
74
92
  })
75
93
  }
76
94
  }
77
95
 
78
96
  export interface DataChannelMuxerInit extends DataChannelMuxerFactoryInit, StreamMuxerInit {
79
- streams: Stream[]
97
+ streams: BufferedStream[]
80
98
  }
81
99
 
82
100
  /**
@@ -94,7 +112,7 @@ export class DataChannelMuxer implements StreamMuxer {
94
112
  private readonly metrics?: CounterGroup
95
113
 
96
114
  constructor (readonly init: DataChannelMuxerInit) {
97
- this.streams = init.streams
115
+ this.streams = init.streams.map(s => s.stream)
98
116
  this.peerConnection = init.peerConnection
99
117
  this.protocol = init.protocol ?? PROTOCOL
100
118
  this.metrics = init.metrics
@@ -111,11 +129,7 @@ export class DataChannelMuxer implements StreamMuxer {
111
129
  channel,
112
130
  direction: 'inbound',
113
131
  onEnd: () => {
114
- log.trace('stream %s %s %s onEnd', stream.direction, stream.id, stream.protocol)
115
- drainAndClose(channel, `inbound ${stream.id} ${stream.protocol}`, this.dataChannelOptions.drainTimeout)
116
- this.streams = this.streams.filter(s => s.id !== stream.id)
117
- this.metrics?.increment({ stream_end: true })
118
- init?.onStreamEnd?.(stream)
132
+ this.#onStreamEnd(stream, channel)
119
133
  },
120
134
  ...this.dataChannelOptions
121
135
  })
@@ -125,10 +139,22 @@ export class DataChannelMuxer implements StreamMuxer {
125
139
  init?.onIncomingStream?.(stream)
126
140
  }
127
141
 
128
- const onIncomingStream = init?.onIncomingStream
129
- if (onIncomingStream != null) {
130
- this.streams.forEach(s => { onIncomingStream(s) })
131
- }
142
+ this.init.streams.forEach(bufferedStream => {
143
+ bufferedStream.onEnd = () => {
144
+ this.#onStreamEnd(bufferedStream.stream, bufferedStream.channel)
145
+ }
146
+
147
+ this.metrics?.increment({ incoming_stream: true })
148
+ this.init?.onIncomingStream?.(bufferedStream.stream)
149
+ })
150
+ }
151
+
152
+ #onStreamEnd (stream: Stream, channel: RTCDataChannel): void {
153
+ log.trace('stream %s %s %s onEnd', stream.direction, stream.id, stream.protocol)
154
+ drainAndClose(channel, `${stream.direction} ${stream.id} ${stream.protocol}`, this.dataChannelOptions.drainTimeout)
155
+ this.streams = this.streams.filter(s => s.id !== stream.id)
156
+ this.metrics?.increment({ stream_end: true })
157
+ this.init?.onStreamEnd?.(stream)
132
158
  }
133
159
 
134
160
  /**
@@ -164,17 +190,15 @@ export class DataChannelMuxer implements StreamMuxer {
164
190
  sink: Sink<Source<Uint8Array | Uint8ArrayList>, Promise<void>> = nopSink
165
191
 
166
192
  newStream (): Stream {
193
+ streamIndex++
194
+
167
195
  // The spec says the label SHOULD be an empty string: https://github.com/libp2p/specs/blob/master/webrtc/README.md#rtcdatachannel-label
168
- const channel = this.peerConnection.createDataChannel('')
196
+ const channel = this.peerConnection.createDataChannel(`stream-${streamIndex}`)
169
197
  const stream = createStream({
170
198
  channel,
171
199
  direction: 'outbound',
172
200
  onEnd: () => {
173
- log.trace('stream %s %s %s onEnd', stream.direction, stream.id, stream.protocol)
174
- drainAndClose(channel, `outbound ${stream.id} ${stream.protocol}`, this.dataChannelOptions.drainTimeout)
175
- this.streams = this.streams.filter(s => s.id !== stream.id)
176
- this.metrics?.increment({ stream_end: true })
177
- this.init?.onStreamEnd?.(stream)
201
+ this.#onStreamEnd(stream, channel)
178
202
  },
179
203
  ...this.dataChannelOptions
180
204
  })
@@ -1,18 +1,18 @@
1
1
  import { CodeError } from '@libp2p/interface/errors'
2
2
  import { logger } from '@libp2p/logger'
3
3
  import { peerIdFromString } from '@libp2p/peer-id'
4
- import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'
5
4
  import { pbStream } from 'it-protobuf-stream'
6
5
  import pDefer, { type DeferredPromise } from 'p-defer'
7
6
  import { type RTCPeerConnection, RTCSessionDescription } from '../webrtc/index.js'
8
7
  import { Message } from './pb/message.js'
9
8
  import { SIGNALING_PROTO_ID, splitAddr, type WebRTCTransportMetrics } from './transport.js'
10
- import { parseRemoteAddress, readCandidatesUntilConnected, resolveOnConnected } from './util.js'
9
+ import { readCandidatesUntilConnected, resolveOnConnected } from './util.js'
11
10
  import type { DataChannelOptions } from '../index.js'
12
11
  import type { Connection } from '@libp2p/interface/connection'
13
12
  import type { ConnectionManager } from '@libp2p/interface-internal/connection-manager'
14
13
  import type { IncomingStreamData } from '@libp2p/interface-internal/registrar'
15
14
  import type { TransportManager } from '@libp2p/interface-internal/transport-manager'
15
+ import type { Multiaddr } from '@multiformats/multiaddr'
16
16
 
17
17
  const log = logger('libp2p:webrtc:initiate-connection')
18
18
 
@@ -33,7 +33,7 @@ export interface ConnectOptions {
33
33
  }
34
34
 
35
35
  export async function initiateConnection ({ peerConnection, signal, metrics, multiaddr: ma, connectionManager, transportManager }: ConnectOptions): Promise<{ remoteAddress: Multiaddr }> {
36
- const { baseAddr, peerId } = splitAddr(ma)
36
+ const { baseAddr } = splitAddr(ma)
37
37
 
38
38
  metrics?.dialerEvents.increment({ open: true })
39
39
 
@@ -158,12 +158,10 @@ export async function initiateConnection ({ peerConnection, signal, metrics, mul
158
158
  signal
159
159
  })
160
160
 
161
- const remoteAddress = parseRemoteAddress(peerConnection.currentRemoteDescription?.sdp ?? '')
162
-
163
- log.trace('initiator connected to remote address %s', remoteAddress)
161
+ log.trace('initiator connected to remote address %s', ma)
164
162
 
165
163
  return {
166
- remoteAddress: multiaddr(remoteAddress).encapsulate(`/p2p/${peerId.toString()}`)
164
+ remoteAddress: ma
167
165
  }
168
166
  } catch (err: any) {
169
167
  peerConnection.close()
@@ -1,10 +1,11 @@
1
1
  import { CodeError } from '@libp2p/interface/errors'
2
2
  import { logger } from '@libp2p/logger'
3
+ import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'
3
4
  import { pbStream } from 'it-protobuf-stream'
4
5
  import pDefer, { type DeferredPromise } from 'p-defer'
5
6
  import { type RTCPeerConnection, RTCSessionDescription } from '../webrtc/index.js'
6
7
  import { Message } from './pb/message.js'
7
- import { parseRemoteAddress, readCandidatesUntilConnected, resolveOnConnected } from './util.js'
8
+ import { readCandidatesUntilConnected, resolveOnConnected } from './util.js'
8
9
  import type { IncomingStreamData } from '@libp2p/interface-internal/registrar'
9
10
 
10
11
  const log = logger('libp2p:webrtc:signaling-stream-handler')
@@ -14,7 +15,7 @@ export interface IncomingStreamOpts extends IncomingStreamData {
14
15
  signal: AbortSignal
15
16
  }
16
17
 
17
- export async function handleIncomingStream ({ peerConnection, stream, signal, connection }: IncomingStreamOpts): Promise<{ remoteAddress: string }> {
18
+ export async function handleIncomingStream ({ peerConnection, stream, signal, connection }: IncomingStreamOpts): Promise<{ remoteAddress: Multiaddr }> {
18
19
  log.trace('new inbound signaling stream')
19
20
 
20
21
  const messageStream = pbStream(stream).pb(Message)
@@ -121,7 +122,7 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co
121
122
  }
122
123
  }
123
124
 
124
- const remoteAddress = parseRemoteAddress(peerConnection.currentRemoteDescription?.sdp ?? '')
125
+ const remoteAddress = multiaddr(`/webrtc/p2p/${connection.remoteAddr.getPeerId()}`)
125
126
 
126
127
  log.trace('recipient connected to remote address %s', remoteAddress)
127
128
 
@@ -121,10 +121,6 @@ export class WebRTCTransport implements Transport, Startable {
121
121
  log.trace('dialing address: %a', ma)
122
122
 
123
123
  const peerConnection = new RTCPeerConnection(this.init.rtcConfiguration)
124
- const muxerFactory = new DataChannelMuxerFactory({
125
- peerConnection,
126
- dataChannelOptions: this.init.dataChannel
127
- })
128
124
 
129
125
  const { remoteAddress } = await initiateConnection({
130
126
  peerConnection,
@@ -145,7 +141,10 @@ export class WebRTCTransport implements Transport, Startable {
145
141
  const connection = await options.upgrader.upgradeOutbound(webRTCConn, {
146
142
  skipProtection: true,
147
143
  skipEncryption: true,
148
- muxerFactory
144
+ muxerFactory: new DataChannelMuxerFactory({
145
+ peerConnection,
146
+ dataChannelOptions: this.init.dataChannel
147
+ })
149
148
  })
150
149
 
151
150
  // close the connection on shut down
@@ -157,7 +156,6 @@ export class WebRTCTransport implements Transport, Startable {
157
156
  async _onProtocol ({ connection, stream }: IncomingStreamData): Promise<void> {
158
157
  const signal = AbortSignal.timeout(this.init.inboundConnectionTimeout ?? INBOUND_CONNECTION_TIMEOUT)
159
158
  const peerConnection = new RTCPeerConnection(this.init.rtcConfiguration)
160
- const muxerFactory = new DataChannelMuxerFactory({ peerConnection, dataChannelOptions: this.init.dataChannel })
161
159
 
162
160
  try {
163
161
  const { remoteAddress } = await handleIncomingStream({
@@ -170,7 +168,7 @@ export class WebRTCTransport implements Transport, Startable {
170
168
  const webRTCConn = new WebRTCMultiaddrConnection({
171
169
  peerConnection,
172
170
  timeline: { open: (new Date()).getTime() },
173
- remoteAddr: multiaddr(remoteAddress).encapsulate(`/p2p/${connection.remotePeer.toString()}`),
171
+ remoteAddr: remoteAddress,
174
172
  metrics: this.metrics?.listenerEvents
175
173
  })
176
174
 
@@ -180,7 +178,7 @@ export class WebRTCTransport implements Transport, Startable {
180
178
  await this.components.upgrader.upgradeInbound(webRTCConn, {
181
179
  skipEncryption: true,
182
180
  skipProtection: true,
183
- muxerFactory
181
+ muxerFactory: new DataChannelMuxerFactory({ peerConnection, dataChannelOptions: this.init.dataChannel })
184
182
  })
185
183
 
186
184
  // close the stream if SDP messages have been exchanged successfully
@@ -110,16 +110,3 @@ export function resolveOnConnected (pc: RTCPeerConnection, promise: DeferredProm
110
110
  }
111
111
  }
112
112
  }
113
-
114
- export function parseRemoteAddress (sdp: string): string {
115
- // 'a=candidate:1746876089 1 udp 2113937151 0614fbad-b...ocal 54882 typ host generation 0 network-cost 999'
116
- const candidateLine = sdp.split('\r\n').filter(line => line.startsWith('a=candidate')).pop()
117
- const candidateParts = candidateLine?.split(' ')
118
-
119
- if (candidateLine == null || candidateParts == null || candidateParts.length < 5) {
120
- log('could not parse remote address from', candidateLine)
121
- return '/webrtc'
122
- }
123
-
124
- return `/dnsaddr/${candidateParts[4]}/${candidateParts[2].toLowerCase()}/${candidateParts[5]}/webrtc`
125
- }
package/src/stream.ts CHANGED
@@ -84,7 +84,6 @@ export class WebRTCStream extends AbstractStream {
84
84
  */
85
85
  private readonly receiveFinAck: DeferredPromise<void>
86
86
  private readonly finAckTimeout: number
87
- // private sentFinAck: boolean
88
87
 
89
88
  constructor (init: WebRTCStreamInit) {
90
89
  // override onEnd to send/receive FIN_ACK before closing the stream