@libp2p/webrtc 3.2.6-f4fac961 → 3.2.6-fdcb801e

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