@libp2p/webrtc 1.2.0 → 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.
- package/README.md +3 -3
- package/dist/index.min.js +21 -17
- package/dist/src/maconn.d.ts.map +1 -1
- package/dist/src/maconn.js +5 -0
- package/dist/src/maconn.js.map +1 -1
- package/dist/src/peer_transport/handler.d.ts +10 -2
- package/dist/src/peer_transport/handler.d.ts.map +1 -1
- package/dist/src/peer_transport/handler.js +14 -2
- package/dist/src/peer_transport/handler.js.map +1 -1
- package/dist/src/peer_transport/listener.d.ts +6 -7
- package/dist/src/peer_transport/listener.d.ts.map +1 -1
- package/dist/src/peer_transport/listener.js +26 -24
- package/dist/src/peer_transport/listener.js.map +1 -1
- package/dist/src/peer_transport/transport.d.ts +4 -6
- package/dist/src/peer_transport/transport.d.ts.map +1 -1
- package/dist/src/peer_transport/transport.js +21 -20
- package/dist/src/peer_transport/transport.js.map +1 -1
- package/dist/src/peer_transport/util.js +1 -1
- package/dist/src/peer_transport/util.js.map +1 -1
- package/dist/src/stream.js +1 -1
- package/dist/src/stream.js.map +1 -1
- package/dist/src/transport.d.ts.map +1 -1
- package/dist/src/transport.js +5 -7
- package/dist/src/transport.js.map +1 -1
- package/package.json +10 -12
- package/src/maconn.ts +6 -0
- package/src/peer_transport/handler.ts +23 -5
- package/src/peer_transport/listener.ts +39 -28
- package/src/peer_transport/transport.ts +29 -24
- package/src/peer_transport/util.ts +1 -1
- package/src/stream.ts +1 -1
- package/src/transport.ts +5 -7
package/src/maconn.ts
CHANGED
|
@@ -64,6 +64,12 @@ export class WebRTCMultiaddrConnection implements MultiaddrConnection {
|
|
|
64
64
|
this.remoteAddr = init.remoteAddr
|
|
65
65
|
this.timeline = init.timeline
|
|
66
66
|
this.peerConnection = init.peerConnection
|
|
67
|
+
|
|
68
|
+
this.peerConnection.onconnectionstatechange = () => {
|
|
69
|
+
if (this.peerConnection.connectionState === 'closed' || this.peerConnection.connectionState === 'disconnected' || this.peerConnection.connectionState === 'failed') {
|
|
70
|
+
this.timeline.close = Date.now()
|
|
71
|
+
}
|
|
72
|
+
}
|
|
67
73
|
}
|
|
68
74
|
|
|
69
75
|
async close (err?: Error | undefined): Promise<void> {
|
|
@@ -15,7 +15,7 @@ const log = logger('libp2p:webrtc:peer')
|
|
|
15
15
|
|
|
16
16
|
export type IncomingStreamOpts = { rtcConfiguration?: RTCConfiguration } & IncomingStreamData
|
|
17
17
|
|
|
18
|
-
export async function handleIncomingStream ({ rtcConfiguration, stream: rawStream }: IncomingStreamOpts): Promise<
|
|
18
|
+
export async function handleIncomingStream ({ rtcConfiguration, stream: rawStream }: IncomingStreamOpts): Promise<{ pc: RTCPeerConnection, muxerFactory: StreamMuxerFactory, remoteAddress: string }> {
|
|
19
19
|
const signal = AbortSignal.timeout(DEFAULT_TIMEOUT)
|
|
20
20
|
const stream = pbStream(abortableDuplex(rawStream, signal)).pb(pb.Message)
|
|
21
21
|
const pc = new RTCPeerConnection(rtcConfiguration)
|
|
@@ -76,7 +76,10 @@ export async function handleIncomingStream ({ rtcConfiguration, stream: rawStrea
|
|
|
76
76
|
|
|
77
77
|
// wait until candidates are connected
|
|
78
78
|
await readCandidatesUntilConnected(connectedPromise, pc, stream)
|
|
79
|
-
|
|
79
|
+
|
|
80
|
+
const remoteAddress = parseRemoteAddress(pc.currentRemoteDescription?.sdp ?? '')
|
|
81
|
+
|
|
82
|
+
return { pc, muxerFactory, remoteAddress }
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
export interface ConnectOptions {
|
|
@@ -85,9 +88,8 @@ export interface ConnectOptions {
|
|
|
85
88
|
rtcConfiguration?: RTCConfiguration
|
|
86
89
|
}
|
|
87
90
|
|
|
88
|
-
export async function initiateConnection ({ rtcConfiguration, signal, stream: rawStream }: ConnectOptions): Promise<
|
|
91
|
+
export async function initiateConnection ({ rtcConfiguration, signal, stream: rawStream }: ConnectOptions): Promise<{ pc: RTCPeerConnection, muxerFactory: StreamMuxerFactory, remoteAddress: string }> {
|
|
89
92
|
const stream = pbStream(abortableDuplex(rawStream, signal)).pb(pb.Message)
|
|
90
|
-
|
|
91
93
|
// setup peer connection
|
|
92
94
|
const pc = new RTCPeerConnection(rtcConfiguration)
|
|
93
95
|
const muxerFactory = new DataChannelMuxerFactory(pc)
|
|
@@ -133,5 +135,21 @@ export async function initiateConnection ({ rtcConfiguration, signal, stream: ra
|
|
|
133
135
|
|
|
134
136
|
await readCandidatesUntilConnected(connectedPromise, pc, stream)
|
|
135
137
|
channel.close()
|
|
136
|
-
|
|
138
|
+
|
|
139
|
+
const remoteAddress = parseRemoteAddress(pc.currentRemoteDescription?.sdp ?? '')
|
|
140
|
+
|
|
141
|
+
return { pc, muxerFactory, remoteAddress }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function parseRemoteAddress (sdp: string): string {
|
|
145
|
+
// 'a=candidate:1746876089 1 udp 2113937151 0614fbad-b...ocal 54882 typ host generation 0 network-cost 999'
|
|
146
|
+
const candidateLine = sdp.split('\r\n').filter(line => line.startsWith('a=candidate')).pop()
|
|
147
|
+
const candidateParts = candidateLine?.split(' ')
|
|
148
|
+
|
|
149
|
+
if (candidateLine == null || candidateParts == null || candidateParts.length < 5) {
|
|
150
|
+
log('could not parse remote address from', candidateLine)
|
|
151
|
+
return '/webrtc'
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return `/dnsaddr/${candidateParts[4]}/${candidateParts[2]}/${candidateParts[3]}/webrtc`
|
|
137
155
|
}
|
|
@@ -1,44 +1,55 @@
|
|
|
1
1
|
import { EventEmitter } from '@libp2p/interfaces/events'
|
|
2
|
-
import {
|
|
3
|
-
import { inappropriateMultiaddr } from '../error.js'
|
|
4
|
-
import { TRANSPORT } from './transport.js'
|
|
2
|
+
import type { Libp2pEvents } from '@libp2p/interface-libp2p'
|
|
5
3
|
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
6
|
-
import type { ListenerEvents,
|
|
4
|
+
import type { ListenerEvents, Listener } from '@libp2p/interface-transport'
|
|
5
|
+
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
7
6
|
|
|
8
7
|
export interface ListenerOptions {
|
|
9
8
|
peerId: PeerId
|
|
10
|
-
|
|
11
|
-
transportManager: TransportManager
|
|
9
|
+
events: EventEmitter<Libp2pEvents>
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
export class WebRTCPeerListener extends EventEmitter<ListenerEvents> implements Listener {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
private readonly peerId: PeerId
|
|
14
|
+
private listeners: Listener[] = []
|
|
15
|
+
|
|
16
|
+
constructor (opts: ListenerOptions) {
|
|
18
17
|
super()
|
|
19
|
-
}
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
this.peerId = opts.peerId
|
|
20
|
+
|
|
21
|
+
opts.events.addEventListener('transport:listening', (event) => {
|
|
22
|
+
const listener = event.detail
|
|
23
|
+
|
|
24
|
+
if (listener === this || this.listeners.includes(listener)) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.listeners.push(listener)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
opts.events.addEventListener('transport:close', (event) => {
|
|
32
|
+
const listener = event.detail
|
|
33
|
+
|
|
34
|
+
this.listeners = this.listeners.filter(l => l !== listener)
|
|
35
|
+
})
|
|
27
36
|
}
|
|
28
37
|
|
|
29
|
-
private listeningAddrs: Multiaddr[] = []
|
|
30
38
|
async listen (ma: Multiaddr): Promise<void> {
|
|
31
|
-
|
|
32
|
-
const tpt = this.opts.transportManager.transportForMultiaddr(baseAddr)
|
|
33
|
-
const listener = tpt?.createListener({ ...this.opts })
|
|
34
|
-
await listener?.listen(baseAddr)
|
|
35
|
-
const listeningAddr = ma.encapsulate(`/p2p/${this.opts.peerId.toString()}`)
|
|
36
|
-
this.listeningAddrs.push(listeningAddr)
|
|
37
|
-
listener?.addEventListener('close', () => {
|
|
38
|
-
this.listeningAddrs = this.listeningAddrs.filter(a => a !== listeningAddr)
|
|
39
|
-
})
|
|
39
|
+
this.safeDispatchEvent('listening', {})
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
getAddrs (): Multiaddr[] {
|
|
43
|
-
|
|
42
|
+
getAddrs (): Multiaddr[] {
|
|
43
|
+
return this.listeners
|
|
44
|
+
.map(l => l.getAddrs()
|
|
45
|
+
.map(ma => {
|
|
46
|
+
return ma.encapsulate(`/webrtc/p2p/${this.peerId}`)
|
|
47
|
+
})
|
|
48
|
+
)
|
|
49
|
+
.flat()
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async close (): Promise<void> {
|
|
53
|
+
this.safeDispatchEvent('close', {})
|
|
54
|
+
}
|
|
44
55
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CreateListenerOptions, type DialOptions, type Listener, symbol, type Transport, type
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
77
|
+
const addrs = ma.toString().split(WEBRTC_TRANSPORT)
|
|
76
78
|
if (addrs.length !== 2) {
|
|
77
|
-
throw new CodeError('
|
|
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(
|
|
88
|
+
const destination = multiaddr(addrs[1])
|
|
82
89
|
|
|
83
90
|
const destinationIdString = destination.getPeerId()
|
|
84
91
|
if (destinationIdString == null) {
|
|
85
|
-
throw new CodeError('
|
|
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
|
|
121
|
-
stream:
|
|
126
|
+
const { pc, muxerFactory, remoteAddress } = await initiateConnection({
|
|
127
|
+
stream: signalingStream,
|
|
122
128
|
rtcConfiguration: this.init.rtcConfiguration,
|
|
123
129
|
signal: options.signal
|
|
124
130
|
})
|
|
125
|
-
|
|
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:
|
|
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
|
-
|
|
146
|
+
signalingStream.close()
|
|
141
147
|
return result
|
|
142
148
|
} catch (err) {
|
|
143
149
|
// reset the stream in case of any error
|
|
144
|
-
|
|
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
|
|
157
|
+
const { pc, muxerFactory, remoteAddress } = await handleIncomingStream({
|
|
152
158
|
rtcConfiguration: this.init.rtcConfiguration,
|
|
153
159
|
connection,
|
|
154
160
|
stream
|
|
155
161
|
})
|
|
156
|
-
|
|
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:
|
|
166
|
+
remoteAddr: multiaddr(remoteAddress).encapsulate(`/p2p/${connection.remotePeer.toString()}`)
|
|
162
167
|
}), {
|
|
163
168
|
skipEncryption: true,
|
|
164
169
|
skipProtection: true,
|
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
|
@@ -189,15 +189,13 @@ export class WebRTCDirectTransport implements Transport {
|
|
|
189
189
|
const wrappedDuplex = {
|
|
190
190
|
...wrappedChannel,
|
|
191
191
|
sink: wrappedChannel.sink.bind(wrappedChannel),
|
|
192
|
-
source: {
|
|
193
|
-
|
|
194
|
-
for
|
|
195
|
-
|
|
196
|
-
yield buf
|
|
197
|
-
}
|
|
192
|
+
source: (async function * () {
|
|
193
|
+
for await (const list of wrappedChannel.source) {
|
|
194
|
+
for (const buf of list) {
|
|
195
|
+
yield buf
|
|
198
196
|
}
|
|
199
197
|
}
|
|
200
|
-
}
|
|
198
|
+
}())
|
|
201
199
|
}
|
|
202
200
|
|
|
203
201
|
// Creating the connection before completion of the noise
|