@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.
- package/README.md +1 -1
- package/dist/index.min.js +21 -21
- package/dist/src/error.d.ts +2 -2
- package/dist/src/error.d.ts.map +1 -1
- package/dist/src/error.js +1 -1
- package/dist/src/error.js.map +1 -1
- package/dist/src/index.d.ts +6 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/maconn.d.ts +8 -4
- package/dist/src/maconn.d.ts.map +1 -1
- package/dist/src/maconn.js +6 -6
- package/dist/src/maconn.js.map +1 -1
- package/dist/src/muxer.d.ts +13 -5
- package/dist/src/muxer.d.ts.map +1 -1
- package/dist/src/muxer.js +36 -7
- package/dist/src/muxer.js.map +1 -1
- package/dist/src/pb/message.js.map +1 -1
- package/dist/src/private-to-private/initiate-connection.d.ts +4 -5
- package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
- package/dist/src/private-to-private/initiate-connection.js +4 -5
- package/dist/src/private-to-private/initiate-connection.js.map +1 -1
- package/dist/src/private-to-private/listener.d.ts +3 -4
- package/dist/src/private-to-private/listener.d.ts.map +1 -1
- package/dist/src/private-to-private/listener.js +1 -1
- package/dist/src/private-to-private/listener.js.map +1 -1
- package/dist/src/private-to-private/pb/message.js.map +1 -1
- package/dist/src/private-to-private/signaling-stream-handler.d.ts +4 -2
- package/dist/src/private-to-private/signaling-stream-handler.d.ts.map +1 -1
- package/dist/src/private-to-private/signaling-stream-handler.js +4 -5
- package/dist/src/private-to-private/signaling-stream-handler.js.map +1 -1
- package/dist/src/private-to-private/transport.d.ts +5 -9
- package/dist/src/private-to-private/transport.d.ts.map +1 -1
- package/dist/src/private-to-private/transport.js +16 -14
- package/dist/src/private-to-private/transport.js.map +1 -1
- package/dist/src/private-to-private/util.d.ts +2 -2
- package/dist/src/private-to-private/util.d.ts.map +1 -1
- package/dist/src/private-to-private/util.js +26 -41
- package/dist/src/private-to-private/util.js.map +1 -1
- package/dist/src/private-to-public/options.d.ts +1 -1
- package/dist/src/private-to-public/options.d.ts.map +1 -1
- package/dist/src/private-to-public/sdp.d.ts +2 -1
- package/dist/src/private-to-public/sdp.d.ts.map +1 -1
- package/dist/src/private-to-public/sdp.js +3 -6
- package/dist/src/private-to-public/sdp.js.map +1 -1
- package/dist/src/private-to-public/transport.d.ts +4 -5
- package/dist/src/private-to-public/transport.d.ts.map +1 -1
- package/dist/src/private-to-public/transport.js +26 -15
- package/dist/src/private-to-public/transport.js.map +1 -1
- package/dist/src/stream.d.ts +10 -4
- package/dist/src/stream.d.ts.map +1 -1
- package/dist/src/stream.js +19 -33
- package/dist/src/stream.js.map +1 -1
- package/dist/src/util.d.ts +2 -1
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +4 -6
- package/dist/src/util.js.map +1 -1
- package/dist/src/webrtc/rtc-data-channel.js.map +1 -1
- package/dist/src/webrtc/rtc-ice-candidate.js.map +1 -1
- package/dist/src/webrtc/rtc-peer-connection.js.map +1 -1
- package/package.json +27 -22
- package/src/error.ts +2 -2
- package/src/index.ts +7 -1
- package/src/maconn.ts +14 -10
- package/src/muxer.ts +57 -11
- package/src/private-to-private/initiate-connection.ts +7 -11
- package/src/private-to-private/listener.ts +3 -4
- package/src/private-to-private/signaling-stream-handler.ts +7 -7
- package/src/private-to-private/transport.ts +18 -22
- package/src/private-to-private/util.ts +30 -46
- package/src/private-to-public/options.ts +1 -1
- package/src/private-to-public/sdp.ts +4 -8
- package/src/private-to-public/transport.ts +27 -19
- package/src/stream.ts +27 -39
- package/src/util.ts +5 -7
- package/dist/typedoc-urls.json +0 -8
package/src/muxer.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import { logger } from '@libp2p/logger'
|
|
2
1
|
import { createStream } from './stream.js'
|
|
3
2
|
import { drainAndClose, nopSink, nopSource } from './util.js'
|
|
4
3
|
import type { DataChannelOptions } from './index.js'
|
|
5
|
-
import type { Stream } from '@libp2p/interface
|
|
6
|
-
import type { CounterGroup } from '@libp2p/interface/metrics'
|
|
7
|
-
import type { StreamMuxer, StreamMuxerFactory, StreamMuxerInit } from '@libp2p/interface/stream-muxer'
|
|
4
|
+
import type { ComponentLogger, Logger, Stream, CounterGroup, StreamMuxer, StreamMuxerFactory, StreamMuxerInit } from '@libp2p/interface'
|
|
8
5
|
import type { AbortOptions } from '@multiformats/multiaddr'
|
|
9
6
|
import type { Source, Sink } from 'it-stream-types'
|
|
10
7
|
import type { Uint8ArrayList } from 'uint8arraylist'
|
|
11
8
|
|
|
12
|
-
const log = logger('libp2p:webrtc:muxer')
|
|
13
|
-
|
|
14
9
|
const PROTOCOL = '/webrtc'
|
|
15
10
|
|
|
16
11
|
export interface DataChannelMuxerFactoryInit {
|
|
@@ -32,6 +27,10 @@ export interface DataChannelMuxerFactoryInit {
|
|
|
32
27
|
dataChannelOptions?: DataChannelOptions
|
|
33
28
|
}
|
|
34
29
|
|
|
30
|
+
export interface DataChannelMuxerFactoryComponents {
|
|
31
|
+
logger: ComponentLogger
|
|
32
|
+
}
|
|
33
|
+
|
|
35
34
|
interface BufferedStream {
|
|
36
35
|
stream: Stream
|
|
37
36
|
channel: RTCDataChannel
|
|
@@ -48,15 +47,29 @@ export class DataChannelMuxerFactory implements StreamMuxerFactory {
|
|
|
48
47
|
private bufferedStreams: BufferedStream[] = []
|
|
49
48
|
private readonly metrics?: CounterGroup
|
|
50
49
|
private readonly dataChannelOptions?: DataChannelOptions
|
|
50
|
+
private readonly components: DataChannelMuxerFactoryComponents
|
|
51
|
+
private readonly log: Logger
|
|
51
52
|
|
|
52
|
-
constructor (init: DataChannelMuxerFactoryInit) {
|
|
53
|
+
constructor (components: DataChannelMuxerFactoryComponents, init: DataChannelMuxerFactoryInit) {
|
|
54
|
+
this.components = components
|
|
53
55
|
this.peerConnection = init.peerConnection
|
|
54
56
|
this.metrics = init.metrics
|
|
55
57
|
this.protocol = init.protocol ?? PROTOCOL
|
|
56
58
|
this.dataChannelOptions = init.dataChannelOptions ?? {}
|
|
59
|
+
this.log = components.logger.forComponent('libp2p:webrtc:datachannelmuxerfactory')
|
|
57
60
|
|
|
58
61
|
// store any datachannels opened before upgrade has been completed
|
|
59
62
|
this.peerConnection.ondatachannel = ({ channel }) => {
|
|
63
|
+
this.log.trace('incoming early datachannel with channel id %d and label "%s"', channel.id)
|
|
64
|
+
|
|
65
|
+
// 'init' channel is only used during connection establishment
|
|
66
|
+
if (channel.label === 'init') {
|
|
67
|
+
this.log.trace('closing early init channel')
|
|
68
|
+
channel.close()
|
|
69
|
+
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
|
|
60
73
|
// @ts-expect-error fields are set below
|
|
61
74
|
const bufferedStream: BufferedStream = {}
|
|
62
75
|
|
|
@@ -66,6 +79,7 @@ export class DataChannelMuxerFactory implements StreamMuxerFactory {
|
|
|
66
79
|
onEnd: (err) => {
|
|
67
80
|
bufferedStream.onEnd(err)
|
|
68
81
|
},
|
|
82
|
+
logger: components.logger,
|
|
69
83
|
...this.dataChannelOptions
|
|
70
84
|
})
|
|
71
85
|
|
|
@@ -80,7 +94,7 @@ export class DataChannelMuxerFactory implements StreamMuxerFactory {
|
|
|
80
94
|
}
|
|
81
95
|
|
|
82
96
|
createStreamMuxer (init?: StreamMuxerInit): StreamMuxer {
|
|
83
|
-
return new DataChannelMuxer({
|
|
97
|
+
return new DataChannelMuxer(this.components, {
|
|
84
98
|
...init,
|
|
85
99
|
peerConnection: this.peerConnection,
|
|
86
100
|
dataChannelOptions: this.dataChannelOptions,
|
|
@@ -95,6 +109,10 @@ export interface DataChannelMuxerInit extends DataChannelMuxerFactoryInit, Strea
|
|
|
95
109
|
streams: BufferedStream[]
|
|
96
110
|
}
|
|
97
111
|
|
|
112
|
+
export interface DataChannelMuxerComponents {
|
|
113
|
+
logger: ComponentLogger
|
|
114
|
+
}
|
|
115
|
+
|
|
98
116
|
/**
|
|
99
117
|
* A libp2p data channel stream muxer
|
|
100
118
|
*/
|
|
@@ -105,11 +123,15 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
|
105
123
|
public streams: Stream[]
|
|
106
124
|
public protocol: string
|
|
107
125
|
|
|
126
|
+
private readonly log: Logger
|
|
108
127
|
private readonly peerConnection: RTCPeerConnection
|
|
109
128
|
private readonly dataChannelOptions: DataChannelOptions
|
|
110
129
|
private readonly metrics?: CounterGroup
|
|
130
|
+
private readonly logger: ComponentLogger
|
|
111
131
|
|
|
112
|
-
constructor (readonly init: DataChannelMuxerInit) {
|
|
132
|
+
constructor (components: DataChannelMuxerComponents, readonly init: DataChannelMuxerInit) {
|
|
133
|
+
this.log = components.logger.forComponent('libp2p:webrtc:muxer')
|
|
134
|
+
this.logger = components.logger
|
|
113
135
|
this.streams = init.streams.map(s => s.stream)
|
|
114
136
|
this.peerConnection = init.peerConnection
|
|
115
137
|
this.protocol = init.protocol ?? PROTOCOL
|
|
@@ -123,12 +145,24 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
|
123
145
|
* {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event}
|
|
124
146
|
*/
|
|
125
147
|
this.peerConnection.ondatachannel = ({ channel }) => {
|
|
148
|
+
this.log.trace('incoming datachannel with channel id %d', channel.id)
|
|
149
|
+
|
|
150
|
+
// 'init' channel is only used during connection establishment
|
|
151
|
+
if (channel.label === 'init') {
|
|
152
|
+
this.log.trace('closing init channel')
|
|
153
|
+
channel.close()
|
|
154
|
+
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
126
158
|
const stream = createStream({
|
|
127
159
|
channel,
|
|
128
160
|
direction: 'inbound',
|
|
129
161
|
onEnd: () => {
|
|
162
|
+
this.log('incoming channel %s ended with state %s', channel.id, channel.readyState)
|
|
130
163
|
this.#onStreamEnd(stream, channel)
|
|
131
164
|
},
|
|
165
|
+
logger: this.logger,
|
|
132
166
|
...this.dataChannelOptions
|
|
133
167
|
})
|
|
134
168
|
|
|
@@ -147,6 +181,7 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
|
147
181
|
queueMicrotask(() => {
|
|
148
182
|
this.init.streams.forEach(bufferedStream => {
|
|
149
183
|
bufferedStream.onEnd = () => {
|
|
184
|
+
this.log('incoming early channel %s ended with state %s', bufferedStream.channel.id, bufferedStream.channel.readyState)
|
|
150
185
|
this.#onStreamEnd(bufferedStream.stream, bufferedStream.channel)
|
|
151
186
|
}
|
|
152
187
|
|
|
@@ -158,8 +193,14 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
|
158
193
|
}
|
|
159
194
|
|
|
160
195
|
#onStreamEnd (stream: Stream, channel: RTCDataChannel): void {
|
|
161
|
-
log.trace('stream %s %s %s onEnd', stream.direction, stream.id, stream.protocol)
|
|
162
|
-
drainAndClose(
|
|
196
|
+
this.log.trace('stream %s %s %s onEnd', stream.direction, stream.id, stream.protocol)
|
|
197
|
+
drainAndClose(
|
|
198
|
+
channel,
|
|
199
|
+
`${stream.direction} ${stream.id} ${stream.protocol}`,
|
|
200
|
+
this.dataChannelOptions.drainTimeout, {
|
|
201
|
+
log: this.log
|
|
202
|
+
}
|
|
203
|
+
)
|
|
163
204
|
this.streams = this.streams.filter(s => s.id !== stream.id)
|
|
164
205
|
this.metrics?.increment({ stream_end: true })
|
|
165
206
|
this.init?.onStreamEnd?.(stream)
|
|
@@ -200,12 +241,17 @@ export class DataChannelMuxer implements StreamMuxer {
|
|
|
200
241
|
newStream (): Stream {
|
|
201
242
|
// The spec says the label SHOULD be an empty string: https://github.com/libp2p/specs/blob/master/webrtc/README.md#rtcdatachannel-label
|
|
202
243
|
const channel = this.peerConnection.createDataChannel('')
|
|
244
|
+
|
|
245
|
+
this.log.trace('opened outgoing datachannel with channel id %s', channel.id)
|
|
246
|
+
|
|
203
247
|
const stream = createStream({
|
|
204
248
|
channel,
|
|
205
249
|
direction: 'outbound',
|
|
206
250
|
onEnd: () => {
|
|
251
|
+
this.log('outgoing channel %s ended with state %s', channel.id, channel.readyState)
|
|
207
252
|
this.#onStreamEnd(stream, channel)
|
|
208
253
|
},
|
|
254
|
+
logger: this.logger,
|
|
209
255
|
...this.dataChannelOptions
|
|
210
256
|
})
|
|
211
257
|
this.streams.push(stream)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { CodeError } from '@libp2p/interface
|
|
2
|
-
import { logger } from '@libp2p/logger'
|
|
1
|
+
import { CodeError } from '@libp2p/interface'
|
|
3
2
|
import { peerIdFromString } from '@libp2p/peer-id'
|
|
4
3
|
import { pbStream } from 'it-protobuf-stream'
|
|
5
4
|
import pDefer, { type DeferredPromise } from 'p-defer'
|
|
@@ -8,21 +7,17 @@ import { Message } from './pb/message.js'
|
|
|
8
7
|
import { SIGNALING_PROTO_ID, splitAddr, type WebRTCTransportMetrics } from './transport.js'
|
|
9
8
|
import { readCandidatesUntilConnected, resolveOnConnected } from './util.js'
|
|
10
9
|
import type { DataChannelOptions } from '../index.js'
|
|
11
|
-
import type { Connection } from '@libp2p/interface
|
|
12
|
-
import type { ConnectionManager } from '@libp2p/interface-internal
|
|
13
|
-
import type { IncomingStreamData } from '@libp2p/interface-internal/registrar'
|
|
14
|
-
import type { TransportManager } from '@libp2p/interface-internal/transport-manager'
|
|
10
|
+
import type { LoggerOptions, Connection } from '@libp2p/interface'
|
|
11
|
+
import type { ConnectionManager, IncomingStreamData, TransportManager } from '@libp2p/interface-internal'
|
|
15
12
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
16
13
|
|
|
17
|
-
const log = logger('libp2p:webrtc:initiate-connection')
|
|
18
|
-
|
|
19
14
|
export interface IncomingStreamOpts extends IncomingStreamData {
|
|
20
15
|
rtcConfiguration?: RTCConfiguration
|
|
21
16
|
dataChannelOptions?: Partial<DataChannelOptions>
|
|
22
17
|
signal: AbortSignal
|
|
23
18
|
}
|
|
24
19
|
|
|
25
|
-
export interface ConnectOptions {
|
|
20
|
+
export interface ConnectOptions extends LoggerOptions {
|
|
26
21
|
peerConnection: RTCPeerConnection
|
|
27
22
|
multiaddr: Multiaddr
|
|
28
23
|
connectionManager: ConnectionManager
|
|
@@ -32,7 +27,7 @@ export interface ConnectOptions {
|
|
|
32
27
|
metrics?: WebRTCTransportMetrics
|
|
33
28
|
}
|
|
34
29
|
|
|
35
|
-
export async function initiateConnection ({ peerConnection, signal, metrics, multiaddr: ma, connectionManager, transportManager }: ConnectOptions): Promise<{ remoteAddress: Multiaddr }> {
|
|
30
|
+
export async function initiateConnection ({ peerConnection, signal, metrics, multiaddr: ma, connectionManager, transportManager, log }: ConnectOptions): Promise<{ remoteAddress: Multiaddr }> {
|
|
36
31
|
const { baseAddr } = splitAddr(ma)
|
|
37
32
|
|
|
38
33
|
metrics?.dialerEvents.increment({ open: true })
|
|
@@ -147,7 +142,8 @@ export async function initiateConnection ({ peerConnection, signal, metrics, mul
|
|
|
147
142
|
|
|
148
143
|
await readCandidatesUntilConnected(connectedPromise, peerConnection, messageStream, {
|
|
149
144
|
direction: 'initiator',
|
|
150
|
-
signal
|
|
145
|
+
signal,
|
|
146
|
+
log
|
|
151
147
|
})
|
|
152
148
|
|
|
153
149
|
log.trace('initiator connected, closing init channel')
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { TypedEventEmitter } from '@libp2p/interface
|
|
1
|
+
import { TypedEventEmitter } from '@libp2p/interface'
|
|
2
2
|
import { Circuit } from '@multiformats/mafmt'
|
|
3
|
-
import type { PeerId } from '@libp2p/interface
|
|
4
|
-
import type {
|
|
5
|
-
import type { TransportManager } from '@libp2p/interface-internal/transport-manager'
|
|
3
|
+
import type { PeerId, ListenerEvents, Listener } from '@libp2p/interface'
|
|
4
|
+
import type { TransportManager } from '@libp2p/interface-internal'
|
|
6
5
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
7
6
|
|
|
8
7
|
export interface WebRTCPeerListenerComponents {
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import { CodeError } from '@libp2p/interface
|
|
2
|
-
import { logger } from '@libp2p/logger'
|
|
1
|
+
import { CodeError } from '@libp2p/interface'
|
|
3
2
|
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
7
|
import { readCandidatesUntilConnected, resolveOnConnected } from './util.js'
|
|
9
|
-
import type {
|
|
10
|
-
|
|
11
|
-
const log = logger('libp2p:webrtc:signaling-stream-handler')
|
|
8
|
+
import type { Logger } from '@libp2p/interface'
|
|
9
|
+
import type { IncomingStreamData } from '@libp2p/interface-internal'
|
|
12
10
|
|
|
13
11
|
export interface IncomingStreamOpts extends IncomingStreamData {
|
|
14
12
|
peerConnection: RTCPeerConnection
|
|
15
13
|
signal: AbortSignal
|
|
14
|
+
log: Logger
|
|
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, log }: IncomingStreamOpts): Promise<{ remoteAddress: Multiaddr }> {
|
|
19
18
|
log.trace('new inbound signaling stream')
|
|
20
19
|
|
|
21
20
|
const messageStream = pbStream(stream).pb(Message)
|
|
@@ -104,7 +103,8 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co
|
|
|
104
103
|
// wait until candidates are connected
|
|
105
104
|
await readCandidatesUntilConnected(connectedPromise, peerConnection, messageStream, {
|
|
106
105
|
direction: 'recipient',
|
|
107
|
-
signal
|
|
106
|
+
signal,
|
|
107
|
+
log
|
|
108
108
|
})
|
|
109
109
|
|
|
110
110
|
log.trace('recipient connected, closing signaling stream')
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { CodeError } from '@libp2p/interface
|
|
2
|
-
import { type CreateListenerOptions, type DialOptions,
|
|
3
|
-
import { logger } from '@libp2p/logger'
|
|
1
|
+
import { CodeError } from '@libp2p/interface'
|
|
2
|
+
import { type CreateListenerOptions, type DialOptions, transportSymbol, type Transport, type Listener, type Upgrader, type ComponentLogger, type Logger, type Connection, type PeerId, type CounterGroup, type Metrics, type Startable } from '@libp2p/interface'
|
|
4
3
|
import { peerIdFromString } from '@libp2p/peer-id'
|
|
5
4
|
import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'
|
|
6
5
|
import { WebRTC } from '@multiformats/multiaddr-matcher'
|
|
@@ -12,15 +11,7 @@ import { initiateConnection } from './initiate-connection.js'
|
|
|
12
11
|
import { WebRTCPeerListener } from './listener.js'
|
|
13
12
|
import { handleIncomingStream } from './signaling-stream-handler.js'
|
|
14
13
|
import type { DataChannelOptions } from '../index.js'
|
|
15
|
-
import type {
|
|
16
|
-
import type { PeerId } from '@libp2p/interface/peer-id'
|
|
17
|
-
import type { CounterGroup, Metrics } from '@libp2p/interface/src/metrics/index.js'
|
|
18
|
-
import type { Startable } from '@libp2p/interface/startable'
|
|
19
|
-
import type { IncomingStreamData, Registrar } from '@libp2p/interface-internal/registrar'
|
|
20
|
-
import type { ConnectionManager } from '@libp2p/interface-internal/src/connection-manager/index.js'
|
|
21
|
-
import type { TransportManager } from '@libp2p/interface-internal/transport-manager'
|
|
22
|
-
|
|
23
|
-
const log = logger('libp2p:webrtc:peer')
|
|
14
|
+
import type { IncomingStreamData, Registrar, ConnectionManager, TransportManager } from '@libp2p/interface-internal'
|
|
24
15
|
|
|
25
16
|
const WEBRTC_TRANSPORT = '/webrtc'
|
|
26
17
|
const CIRCUIT_RELAY_TRANSPORT = '/p2p-circuit'
|
|
@@ -45,6 +36,7 @@ export interface WebRTCTransportComponents {
|
|
|
45
36
|
transportManager: TransportManager
|
|
46
37
|
connectionManager: ConnectionManager
|
|
47
38
|
metrics?: Metrics
|
|
39
|
+
logger: ComponentLogger
|
|
48
40
|
}
|
|
49
41
|
|
|
50
42
|
export interface WebRTCTransportMetrics {
|
|
@@ -53,6 +45,7 @@ export interface WebRTCTransportMetrics {
|
|
|
53
45
|
}
|
|
54
46
|
|
|
55
47
|
export class WebRTCTransport implements Transport, Startable {
|
|
48
|
+
private readonly log: Logger
|
|
56
49
|
private _started = false
|
|
57
50
|
private readonly metrics?: WebRTCTransportMetrics
|
|
58
51
|
private readonly shutdownController: AbortController
|
|
@@ -61,6 +54,7 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
61
54
|
private readonly components: WebRTCTransportComponents,
|
|
62
55
|
private readonly init: WebRTCTransportInit = {}
|
|
63
56
|
) {
|
|
57
|
+
this.log = components.logger.forComponent('libp2p:webrtc')
|
|
64
58
|
this.shutdownController = new AbortController()
|
|
65
59
|
|
|
66
60
|
if (components.metrics != null) {
|
|
@@ -83,7 +77,7 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
83
77
|
|
|
84
78
|
async start (): Promise<void> {
|
|
85
79
|
await this.components.registrar.handle(SIGNALING_PROTO_ID, (data: IncomingStreamData) => {
|
|
86
|
-
this._onProtocol(data).catch(err => { log.error('failed to handle incoming connect from %p', data.connection.remotePeer, err) })
|
|
80
|
+
this._onProtocol(data).catch(err => { this.log.error('failed to handle incoming connect from %p', data.connection.remotePeer, err) })
|
|
87
81
|
}, {
|
|
88
82
|
runOnTransientConnection: true
|
|
89
83
|
})
|
|
@@ -104,7 +98,7 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
104
98
|
|
|
105
99
|
readonly [Symbol.toStringTag] = '@libp2p/webrtc'
|
|
106
100
|
|
|
107
|
-
readonly [
|
|
101
|
+
readonly [transportSymbol] = true
|
|
108
102
|
|
|
109
103
|
filter (multiaddrs: Multiaddr[]): Multiaddr[] {
|
|
110
104
|
return multiaddrs.filter(WebRTC.exactMatch)
|
|
@@ -118,10 +112,10 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
118
112
|
* <relay address>/p2p/<relay-peer>/p2p-circuit/webrtc/p2p/<destination-peer>
|
|
119
113
|
*/
|
|
120
114
|
async dial (ma: Multiaddr, options: DialOptions): Promise<Connection> {
|
|
121
|
-
log.trace('dialing address: %a', ma)
|
|
115
|
+
this.log.trace('dialing address: %a', ma)
|
|
122
116
|
|
|
123
117
|
const peerConnection = new RTCPeerConnection(this.init.rtcConfiguration)
|
|
124
|
-
const muxerFactory = new DataChannelMuxerFactory({
|
|
118
|
+
const muxerFactory = new DataChannelMuxerFactory(this.components, {
|
|
125
119
|
peerConnection,
|
|
126
120
|
dataChannelOptions: this.init.dataChannel
|
|
127
121
|
})
|
|
@@ -132,10 +126,11 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
132
126
|
dataChannelOptions: this.init.dataChannel,
|
|
133
127
|
signal: options.signal,
|
|
134
128
|
connectionManager: this.components.connectionManager,
|
|
135
|
-
transportManager: this.components.transportManager
|
|
129
|
+
transportManager: this.components.transportManager,
|
|
130
|
+
log: this.log
|
|
136
131
|
})
|
|
137
132
|
|
|
138
|
-
const webRTCConn = new WebRTCMultiaddrConnection({
|
|
133
|
+
const webRTCConn = new WebRTCMultiaddrConnection(this.components, {
|
|
139
134
|
peerConnection,
|
|
140
135
|
timeline: { open: Date.now() },
|
|
141
136
|
remoteAddr: remoteAddress,
|
|
@@ -157,7 +152,7 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
157
152
|
async _onProtocol ({ connection, stream }: IncomingStreamData): Promise<void> {
|
|
158
153
|
const signal = AbortSignal.timeout(this.init.inboundConnectionTimeout ?? INBOUND_CONNECTION_TIMEOUT)
|
|
159
154
|
const peerConnection = new RTCPeerConnection(this.init.rtcConfiguration)
|
|
160
|
-
const muxerFactory = new DataChannelMuxerFactory({
|
|
155
|
+
const muxerFactory = new DataChannelMuxerFactory(this.components, {
|
|
161
156
|
peerConnection,
|
|
162
157
|
dataChannelOptions: this.init.dataChannel
|
|
163
158
|
})
|
|
@@ -167,10 +162,11 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
167
162
|
peerConnection,
|
|
168
163
|
connection,
|
|
169
164
|
stream,
|
|
170
|
-
signal
|
|
165
|
+
signal,
|
|
166
|
+
log: this.log
|
|
171
167
|
})
|
|
172
168
|
|
|
173
|
-
const webRTCConn = new WebRTCMultiaddrConnection({
|
|
169
|
+
const webRTCConn = new WebRTCMultiaddrConnection(this.components, {
|
|
174
170
|
peerConnection,
|
|
175
171
|
timeline: { open: (new Date()).getTime() },
|
|
176
172
|
remoteAddr: remoteAddress,
|
|
@@ -201,7 +197,7 @@ export class WebRTCTransport implements Transport, Startable {
|
|
|
201
197
|
const shutDownListener = (): void => {
|
|
202
198
|
webRTCConn.close()
|
|
203
199
|
.catch(err => {
|
|
204
|
-
log.error('could not close WebRTCMultiaddrConnection', err)
|
|
200
|
+
this.log.error('could not close WebRTCMultiaddrConnection', err)
|
|
205
201
|
})
|
|
206
202
|
}
|
|
207
203
|
|
|
@@ -1,19 +1,14 @@
|
|
|
1
|
-
import { CodeError } from '@libp2p/interface
|
|
2
|
-
import {
|
|
3
|
-
import { abortableSource } from 'abortable-iterator'
|
|
1
|
+
import { CodeError } from '@libp2p/interface'
|
|
2
|
+
import { closeSource } from '@libp2p/utils/close-source'
|
|
4
3
|
import { anySignal } from 'any-signal'
|
|
5
|
-
import * as lp from 'it-length-prefixed'
|
|
6
|
-
import { AbortError, raceSignal } from 'race-signal'
|
|
7
4
|
import { isFirefox } from '../util.js'
|
|
8
5
|
import { RTCIceCandidate } from '../webrtc/index.js'
|
|
9
6
|
import { Message } from './pb/message.js'
|
|
10
|
-
import type { Stream } from '@libp2p/interface
|
|
7
|
+
import type { LoggerOptions, Stream } from '@libp2p/interface'
|
|
11
8
|
import type { AbortOptions, MessageStream } from 'it-protobuf-stream'
|
|
12
9
|
import type { DeferredPromise } from 'p-defer'
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export interface ReadCandidatesOptions extends AbortOptions {
|
|
11
|
+
export interface ReadCandidatesOptions extends AbortOptions, LoggerOptions {
|
|
17
12
|
direction: string
|
|
18
13
|
}
|
|
19
14
|
|
|
@@ -31,71 +26,60 @@ export const readCandidatesUntilConnected = async (connectedPromise: DeferredPro
|
|
|
31
26
|
options.signal
|
|
32
27
|
])
|
|
33
28
|
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
}
|
|
29
|
+
const abortListener = (): void => {
|
|
30
|
+
closeSource(stream.unwrap().unwrap().source, options.log)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
signal.addEventListener('abort', abortListener)
|
|
37
34
|
|
|
38
35
|
try {
|
|
39
36
|
// read candidates until we are connected or we reach the end of the stream
|
|
40
|
-
|
|
41
|
-
const message =
|
|
37
|
+
while (true) {
|
|
38
|
+
const message = await Promise.race([
|
|
39
|
+
connectedPromise.promise,
|
|
40
|
+
stream.read()
|
|
41
|
+
])
|
|
42
|
+
|
|
43
|
+
// stream ended or we became connected
|
|
44
|
+
if (message == null) {
|
|
45
|
+
break
|
|
46
|
+
}
|
|
42
47
|
|
|
43
48
|
if (message.type !== Message.Type.ICE_CANDIDATE) {
|
|
44
49
|
throw new CodeError('ICE candidate message expected', 'ERR_NOT_ICE_CANDIDATE')
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
|
|
52
|
+
const candidateInit = JSON.parse(message.data ?? 'null')
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
sdpMLineIndex: 0
|
|
55
|
-
}
|
|
56
|
-
}
|
|
54
|
+
// an empty string means this generation of candidates is complete, a null
|
|
55
|
+
// candidate means candidate gathering has finished
|
|
56
|
+
// see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent
|
|
57
|
+
if (candidateInit === '' || candidateInit === null) {
|
|
58
|
+
options.log.trace('end-of-candidates received')
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
log.trace('end-of-candidates received')
|
|
60
|
-
candidateInit = {
|
|
61
|
-
candidate: null,
|
|
62
|
-
sdpMid: '0',
|
|
63
|
-
sdpMLineIndex: 0
|
|
64
|
-
}
|
|
60
|
+
continue
|
|
65
61
|
}
|
|
66
62
|
|
|
67
|
-
// a null candidate means end-of-candidates
|
|
68
|
-
// see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent
|
|
69
63
|
const candidate = new RTCIceCandidate(candidateInit)
|
|
70
64
|
|
|
71
|
-
log.trace('%s received new ICE candidate', options.direction, candidate)
|
|
65
|
+
options.log.trace('%s received new ICE candidate', options.direction, candidate)
|
|
72
66
|
|
|
73
67
|
try {
|
|
74
68
|
await pc.addIceCandidate(candidate)
|
|
75
69
|
} catch (err) {
|
|
76
|
-
log.error('%s bad candidate received', options.direction, err)
|
|
70
|
+
options.log.error('%s bad candidate received', options.direction, candidateInit, err)
|
|
77
71
|
}
|
|
78
72
|
}
|
|
79
73
|
} catch (err) {
|
|
80
|
-
log.error('%s error parsing ICE candidate', options.direction, err)
|
|
74
|
+
options.log.error('%s error parsing ICE candidate', options.direction, err)
|
|
81
75
|
} finally {
|
|
76
|
+
signal.removeEventListener('abort', abortListener)
|
|
82
77
|
signal.clear()
|
|
83
78
|
}
|
|
84
|
-
|
|
85
|
-
if (options.signal?.aborted === true) {
|
|
86
|
-
throw new AbortError('Aborted while reading ICE candidates', 'ERR_ICE_CANDIDATES_READ_ABORTED')
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// read all available ICE candidates, wait for connection state change
|
|
90
|
-
await raceSignal(connectedPromise.promise, options.signal, {
|
|
91
|
-
errorMessage: 'Aborted before connected',
|
|
92
|
-
errorCode: 'ERR_ABORTED_BEFORE_CONNECTED'
|
|
93
|
-
})
|
|
94
79
|
}
|
|
95
80
|
|
|
96
81
|
export function resolveOnConnected (pc: RTCPeerConnection, promise: DeferredPromise<void>): void {
|
|
97
82
|
pc[isFirefox ? 'oniceconnectionstatechange' : 'onconnectionstatechange'] = (_) => {
|
|
98
|
-
log.trace('receiver peerConnectionState state change: %s', pc.connectionState)
|
|
99
83
|
switch (isFirefox ? pc.iceConnectionState : pc.connectionState) {
|
|
100
84
|
case 'connected':
|
|
101
85
|
promise.resolve()
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CreateListenerOptions, DialOptions } from '@libp2p/interface
|
|
1
|
+
import type { CreateListenerOptions, DialOptions } from '@libp2p/interface'
|
|
2
2
|
|
|
3
3
|
export interface WebRTCListenerOptions extends CreateListenerOptions {}
|
|
4
4
|
export interface WebRTCDialOptions extends DialOptions {}
|
|
@@ -1,24 +1,22 @@
|
|
|
1
|
-
import { logger } from '@libp2p/logger'
|
|
2
1
|
import { bases } from 'multiformats/basics'
|
|
3
2
|
import * as multihashes from 'multihashes'
|
|
4
3
|
import { inappropriateMultiaddr, invalidArgument, invalidFingerprint, unsupportedHashAlgorithm } from '../error.js'
|
|
5
4
|
import { CERTHASH_CODE } from './transport.js'
|
|
5
|
+
import type { LoggerOptions } from '@libp2p/interface'
|
|
6
6
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
7
7
|
import type { HashCode, HashName } from 'multihashes'
|
|
8
8
|
|
|
9
|
-
const log = logger('libp2p:webrtc:sdp')
|
|
10
|
-
|
|
11
9
|
/**
|
|
12
10
|
* Get base2 | identity decoders
|
|
13
11
|
*/
|
|
14
12
|
// @ts-expect-error - Not easy to combine these types.
|
|
15
13
|
export const mbdecoder: any = Object.values(bases).map(b => b.decoder).reduce((d, b) => d.or(b))
|
|
16
14
|
|
|
17
|
-
export function getLocalFingerprint (pc: RTCPeerConnection): string | undefined {
|
|
15
|
+
export function getLocalFingerprint (pc: RTCPeerConnection, options: LoggerOptions): string | undefined {
|
|
18
16
|
// try to fetch fingerprint from local certificate
|
|
19
17
|
const localCert = pc.getConfiguration().certificates?.at(0)
|
|
20
18
|
if (localCert == null || localCert.getFingerprints == null) {
|
|
21
|
-
log.trace('fetching fingerprint from local SDP')
|
|
19
|
+
options.log.trace('fetching fingerprint from local SDP')
|
|
22
20
|
const localDescription = pc.localDescription
|
|
23
21
|
if (localDescription == null) {
|
|
24
22
|
return undefined
|
|
@@ -26,7 +24,7 @@ export function getLocalFingerprint (pc: RTCPeerConnection): string | undefined
|
|
|
26
24
|
return getFingerprintFromSdp(localDescription.sdp)
|
|
27
25
|
}
|
|
28
26
|
|
|
29
|
-
log.trace('fetching fingerprint from local certificate')
|
|
27
|
+
options.log.trace('fetching fingerprint from local certificate')
|
|
30
28
|
|
|
31
29
|
if (localCert.getFingerprints().length === 0) {
|
|
32
30
|
return undefined
|
|
@@ -55,8 +53,6 @@ function ipv (ma: Multiaddr): string {
|
|
|
55
53
|
}
|
|
56
54
|
}
|
|
57
55
|
|
|
58
|
-
log('Warning: multiaddr does not appear to contain IP4 or IP6, defaulting to IP6', ma)
|
|
59
|
-
|
|
60
56
|
return 'IP6'
|
|
61
57
|
}
|
|
62
58
|
|