@libp2p/webrtc 1.2.0 → 2.0.1
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 +19 -16
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -2
- package/dist/src/index.js.map +1 -1
- 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/pb/message.d.ts +20 -0
- package/dist/src/pb/message.d.ts.map +1 -0
- package/dist/src/pb/message.js +73 -0
- package/dist/src/pb/message.js.map +1 -0
- package/dist/src/{peer_transport → private-to-private}/handler.d.ts +10 -2
- package/dist/src/private-to-private/handler.d.ts.map +1 -0
- package/dist/src/{peer_transport → private-to-private}/handler.js +23 -11
- package/dist/src/private-to-private/handler.js.map +1 -0
- package/dist/src/{peer_transport → private-to-private}/listener.d.ts +6 -7
- package/dist/src/private-to-private/listener.d.ts.map +1 -0
- package/dist/src/private-to-private/listener.js +35 -0
- package/dist/src/private-to-private/listener.js.map +1 -0
- package/dist/src/{peer_transport/pb/index.d.ts → private-to-private/pb/message.d.ts} +2 -2
- package/dist/src/private-to-private/pb/message.d.ts.map +1 -0
- package/dist/src/{peer_transport/pb/index.js → private-to-private/pb/message.js} +1 -1
- package/dist/src/private-to-private/pb/message.js.map +1 -0
- package/dist/src/{peer_transport → private-to-private}/transport.d.ts +4 -6
- package/dist/src/private-to-private/transport.d.ts.map +1 -0
- package/dist/src/{peer_transport → private-to-private}/transport.js +21 -20
- package/dist/src/private-to-private/transport.js.map +1 -0
- package/dist/src/{peer_transport → private-to-private}/util.d.ts +3 -4
- package/dist/src/private-to-private/util.d.ts.map +1 -0
- package/dist/src/{peer_transport → private-to-private}/util.js +4 -6
- package/dist/src/private-to-private/util.js.map +1 -0
- package/dist/src/private-to-public/options.d.ts.map +1 -0
- package/dist/src/private-to-public/options.js.map +1 -0
- package/dist/src/private-to-public/sdp.d.ts.map +1 -0
- package/dist/src/{sdp.js → private-to-public/sdp.js} +1 -1
- package/dist/src/private-to-public/sdp.js.map +1 -0
- package/dist/src/private-to-public/transport.d.ts.map +1 -0
- package/dist/src/{transport.js → private-to-public/transport.js} +10 -12
- package/dist/src/private-to-public/transport.js.map +1 -0
- package/dist/src/private-to-public/util.d.ts +2 -0
- package/dist/src/private-to-public/util.d.ts.map +1 -0
- package/dist/src/private-to-public/util.js +3 -0
- package/dist/src/private-to-public/util.js.map +1 -0
- package/dist/src/stream.d.ts +2 -2
- package/dist/src/stream.d.ts.map +1 -1
- package/dist/src/stream.js +17 -17
- package/dist/src/stream.js.map +1 -1
- package/dist/src/util.d.ts +1 -1
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +3 -2
- package/dist/src/util.js.map +1 -1
- package/package.json +11 -16
- package/src/index.ts +3 -3
- package/src/maconn.ts +6 -0
- package/src/{message.proto → pb/message.proto} +2 -4
- package/src/pb/message.ts +92 -0
- package/src/{peer_transport → private-to-private}/handler.ts +32 -14
- package/src/private-to-private/listener.ts +55 -0
- package/src/{peer_transport/pb/index.ts → private-to-private/pb/message.ts} +1 -1
- package/src/{peer_transport → private-to-private}/transport.ts +29 -24
- package/src/{peer_transport → private-to-private}/util.ts +6 -9
- package/src/{sdp.ts → private-to-public/sdp.ts} +1 -1
- package/src/{transport.ts → private-to-public/transport.ts} +10 -12
- package/src/private-to-public/util.ts +3 -0
- package/src/stream.ts +19 -19
- package/src/util.ts +5 -3
- package/dist/proto_ts/message.d.ts +0 -56
- package/dist/proto_ts/message.d.ts.map +0 -1
- package/dist/proto_ts/message.js +0 -86
- package/dist/proto_ts/message.js.map +0 -1
- package/dist/src/options.d.ts.map +0 -1
- package/dist/src/options.js.map +0 -1
- package/dist/src/peer_transport/handler.d.ts.map +0 -1
- package/dist/src/peer_transport/handler.js.map +0 -1
- package/dist/src/peer_transport/listener.d.ts.map +0 -1
- package/dist/src/peer_transport/listener.js +0 -33
- package/dist/src/peer_transport/listener.js.map +0 -1
- package/dist/src/peer_transport/pb/index.d.ts.map +0 -1
- package/dist/src/peer_transport/pb/index.js.map +0 -1
- package/dist/src/peer_transport/transport.d.ts.map +0 -1
- package/dist/src/peer_transport/transport.js.map +0 -1
- package/dist/src/peer_transport/util.d.ts.map +0 -1
- package/dist/src/peer_transport/util.js.map +0 -1
- package/dist/src/sdp.d.ts.map +0 -1
- package/dist/src/sdp.js.map +0 -1
- package/dist/src/transport.d.ts.map +0 -1
- package/dist/src/transport.js.map +0 -1
- package/proto_ts/message.ts +0 -106
- package/src/peer_transport/listener.ts +0 -44
- /package/dist/src/{options.d.ts → private-to-public/options.d.ts} +0 -0
- /package/dist/src/{options.js → private-to-public/options.js} +0 -0
- /package/dist/src/{sdp.d.ts → private-to-public/sdp.d.ts} +0 -0
- /package/dist/src/{transport.d.ts → private-to-public/transport.d.ts} +0 -0
- /package/src/{peer_transport/pb/index.proto → private-to-private/pb/message.proto} +0 -0
- /package/src/{options.ts → private-to-public/options.ts} +0 -0
|
@@ -3,7 +3,7 @@ import { abortableDuplex } from 'abortable-iterator'
|
|
|
3
3
|
import { pbStream } from 'it-pb-stream'
|
|
4
4
|
import pDefer, { type DeferredPromise } from 'p-defer'
|
|
5
5
|
import { DataChannelMuxerFactory } from '../muxer.js'
|
|
6
|
-
import
|
|
6
|
+
import { Message } from './pb/message.js'
|
|
7
7
|
import { readCandidatesUntilConnected, resolveOnConnected } from './util.js'
|
|
8
8
|
import type { Stream } from '@libp2p/interface-connection'
|
|
9
9
|
import type { IncomingStreamData } from '@libp2p/interface-registrar'
|
|
@@ -15,9 +15,9 @@ 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
|
-
const stream = pbStream(abortableDuplex(rawStream, signal)).pb(
|
|
20
|
+
const stream = pbStream(abortableDuplex(rawStream, signal)).pb(Message)
|
|
21
21
|
const pc = new RTCPeerConnection(rtcConfiguration)
|
|
22
22
|
const muxerFactory = new DataChannelMuxerFactory(pc)
|
|
23
23
|
|
|
@@ -30,7 +30,7 @@ export async function handleIncomingStream ({ rtcConfiguration, stream: rawStrea
|
|
|
30
30
|
answerSentPromise.promise.then(
|
|
31
31
|
() => {
|
|
32
32
|
stream.write({
|
|
33
|
-
type:
|
|
33
|
+
type: Message.Type.ICE_CANDIDATE,
|
|
34
34
|
data: (candidate != null) ? JSON.stringify(candidate.toJSON()) : ''
|
|
35
35
|
})
|
|
36
36
|
},
|
|
@@ -44,7 +44,7 @@ export async function handleIncomingStream ({ rtcConfiguration, stream: rawStrea
|
|
|
44
44
|
|
|
45
45
|
// read an SDP offer
|
|
46
46
|
const pbOffer = await stream.read()
|
|
47
|
-
if (pbOffer.type !==
|
|
47
|
+
if (pbOffer.type !== Message.Type.SDP_OFFER) {
|
|
48
48
|
throw new Error(`expected message type SDP_OFFER, received: ${pbOffer.type ?? 'undefined'} `)
|
|
49
49
|
}
|
|
50
50
|
const offer = new RTCSessionDescription({
|
|
@@ -64,7 +64,7 @@ export async function handleIncomingStream ({ rtcConfiguration, stream: rawStrea
|
|
|
64
64
|
throw new Error('Failed to create answer')
|
|
65
65
|
})
|
|
66
66
|
// write the answer to the remote
|
|
67
|
-
stream.write({ type:
|
|
67
|
+
stream.write({ type: Message.Type.SDP_ANSWER, data: answer.sdp })
|
|
68
68
|
|
|
69
69
|
await pc.setLocalDescription(answer).catch(err => {
|
|
70
70
|
log.error('could not execute setLocalDescription', err)
|
|
@@ -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<
|
|
89
|
-
const stream = pbStream(abortableDuplex(rawStream, signal)).pb(
|
|
90
|
-
|
|
91
|
+
export async function initiateConnection ({ rtcConfiguration, signal, stream: rawStream }: ConnectOptions): Promise<{ pc: RTCPeerConnection, muxerFactory: StreamMuxerFactory, remoteAddress: string }> {
|
|
92
|
+
const stream = pbStream(abortableDuplex(rawStream, signal)).pb(Message)
|
|
91
93
|
// setup peer connection
|
|
92
94
|
const pc = new RTCPeerConnection(rtcConfiguration)
|
|
93
95
|
const muxerFactory = new DataChannelMuxerFactory(pc)
|
|
@@ -105,14 +107,14 @@ export async function initiateConnection ({ rtcConfiguration, signal, stream: ra
|
|
|
105
107
|
// peer
|
|
106
108
|
pc.onicecandidate = ({ candidate }) => {
|
|
107
109
|
stream.write({
|
|
108
|
-
type:
|
|
110
|
+
type: Message.Type.ICE_CANDIDATE,
|
|
109
111
|
data: (candidate != null) ? JSON.stringify(candidate.toJSON()) : ''
|
|
110
112
|
})
|
|
111
113
|
}
|
|
112
114
|
// create an offer
|
|
113
115
|
const offerSdp = await pc.createOffer()
|
|
114
116
|
// write the offer to the stream
|
|
115
|
-
stream.write({ type:
|
|
117
|
+
stream.write({ type: Message.Type.SDP_OFFER, data: offerSdp.sdp })
|
|
116
118
|
// set offer as local description
|
|
117
119
|
await pc.setLocalDescription(offerSdp).catch(err => {
|
|
118
120
|
log.error('could not execute setLocalDescription', err)
|
|
@@ -121,7 +123,7 @@ export async function initiateConnection ({ rtcConfiguration, signal, stream: ra
|
|
|
121
123
|
|
|
122
124
|
// read answer
|
|
123
125
|
const answerMessage = await stream.read()
|
|
124
|
-
if (answerMessage.type !==
|
|
126
|
+
if (answerMessage.type !== Message.Type.SDP_ANSWER) {
|
|
125
127
|
throw new Error('remote should send an SDP answer')
|
|
126
128
|
}
|
|
127
129
|
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { EventEmitter } from '@libp2p/interfaces/events'
|
|
2
|
+
import type { Libp2pEvents } from '@libp2p/interface-libp2p'
|
|
3
|
+
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
4
|
+
import type { ListenerEvents, Listener } from '@libp2p/interface-transport'
|
|
5
|
+
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
6
|
+
|
|
7
|
+
export interface ListenerOptions {
|
|
8
|
+
peerId: PeerId
|
|
9
|
+
events: EventEmitter<Libp2pEvents>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class WebRTCPeerListener extends EventEmitter<ListenerEvents> implements Listener {
|
|
13
|
+
private readonly peerId: PeerId
|
|
14
|
+
private listeners: Listener[] = []
|
|
15
|
+
|
|
16
|
+
constructor (opts: ListenerOptions) {
|
|
17
|
+
super()
|
|
18
|
+
|
|
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
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async listen (ma: Multiaddr): Promise<void> {
|
|
39
|
+
this.safeDispatchEvent('listening', {})
|
|
40
|
+
}
|
|
41
|
+
|
|
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
|
+
}
|
|
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,
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import { logger } from '@libp2p/logger'
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import { isFirefox } from '../util.js'
|
|
3
|
+
import { Message } from './pb/message.js'
|
|
4
4
|
import type { DeferredPromise } from 'p-defer'
|
|
5
5
|
|
|
6
|
-
const browser = detect()
|
|
7
|
-
export const isFirefox = ((browser != null) && browser.name === 'firefox')
|
|
8
|
-
|
|
9
6
|
interface MessageStream {
|
|
10
|
-
read: () => Promise<
|
|
11
|
-
write: (d:
|
|
7
|
+
read: () => Promise<Message>
|
|
8
|
+
write: (d: Message) => void | Promise<void>
|
|
12
9
|
}
|
|
13
10
|
|
|
14
11
|
const log = logger('libp2p:webrtc:peer:util')
|
|
@@ -19,7 +16,7 @@ export const readCandidatesUntilConnected = async (connectedPromise: DeferredPro
|
|
|
19
16
|
// check if readResult is a message
|
|
20
17
|
if (readResult instanceof Object) {
|
|
21
18
|
const message = readResult
|
|
22
|
-
if (message.type !==
|
|
19
|
+
if (message.type !== Message.Type.ICE_CANDIDATE) {
|
|
23
20
|
throw new Error('expected only ice candidates')
|
|
24
21
|
}
|
|
25
22
|
// end of candidates has been signalled
|
|
@@ -53,7 +50,7 @@ export function resolveOnConnected (pc: RTCPeerConnection, promise: DeferredProm
|
|
|
53
50
|
case 'failed':
|
|
54
51
|
case 'disconnected':
|
|
55
52
|
case 'closed':
|
|
56
|
-
promise.reject()
|
|
53
|
+
promise.reject(new Error('RTCPeerConnection was closed'))
|
|
57
54
|
break
|
|
58
55
|
default:
|
|
59
56
|
break
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { logger } from '@libp2p/logger'
|
|
2
2
|
import { bases } from 'multiformats/basics'
|
|
3
3
|
import * as multihashes from 'multihashes'
|
|
4
|
-
import { inappropriateMultiaddr, invalidArgument, invalidFingerprint, unsupportedHashAlgorithm } from '
|
|
4
|
+
import { inappropriateMultiaddr, invalidArgument, invalidFingerprint, unsupportedHashAlgorithm } from '../error.js'
|
|
5
5
|
import { CERTHASH_CODE } from './transport.js'
|
|
6
6
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
7
7
|
import type { HashCode, HashName } from 'multihashes'
|
|
@@ -6,12 +6,12 @@ import { protocols } from '@multiformats/multiaddr'
|
|
|
6
6
|
import * as multihashes from 'multihashes'
|
|
7
7
|
import { concat } from 'uint8arrays/concat'
|
|
8
8
|
import { fromString as uint8arrayFromString } from 'uint8arrays/from-string'
|
|
9
|
-
import { dataChannelError, inappropriateMultiaddr, unimplemented, invalidArgument } from '
|
|
10
|
-
import { WebRTCMultiaddrConnection } from '
|
|
11
|
-
import { DataChannelMuxerFactory } from '
|
|
12
|
-
import {
|
|
9
|
+
import { dataChannelError, inappropriateMultiaddr, unimplemented, invalidArgument } from '../error.js'
|
|
10
|
+
import { WebRTCMultiaddrConnection } from '../maconn.js'
|
|
11
|
+
import { DataChannelMuxerFactory } from '../muxer.js'
|
|
12
|
+
import { WebRTCStream } from '../stream.js'
|
|
13
|
+
import { isFirefox } from '../util.js'
|
|
13
14
|
import * as sdp from './sdp.js'
|
|
14
|
-
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'
|
|
@@ -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
|
package/src/stream.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { pipe } from 'it-pipe'
|
|
|
5
5
|
import { pushable } from 'it-pushable'
|
|
6
6
|
import defer, { type DeferredPromise } from 'p-defer'
|
|
7
7
|
import { Uint8ArrayList } from 'uint8arraylist'
|
|
8
|
-
import
|
|
8
|
+
import { Message } from './pb/message.js'
|
|
9
9
|
import type { Stream, StreamStat, Direction } from '@libp2p/interface-connection'
|
|
10
10
|
import type { Source } from 'it-stream-types'
|
|
11
11
|
|
|
@@ -66,7 +66,7 @@ interface StreamStateInput {
|
|
|
66
66
|
* 1 = STOP_SENDING
|
|
67
67
|
* 2 = RESET
|
|
68
68
|
*/
|
|
69
|
-
flag:
|
|
69
|
+
flag: Message.Flag
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
export enum StreamStates {
|
|
@@ -99,7 +99,7 @@ class StreamState {
|
|
|
99
99
|
|
|
100
100
|
if (direction === 'inbound') {
|
|
101
101
|
switch (flag) {
|
|
102
|
-
case
|
|
102
|
+
case Message.Flag.FIN:
|
|
103
103
|
if (this.state === StreamStates.OPEN) {
|
|
104
104
|
this.state = StreamStates.READ_CLOSED
|
|
105
105
|
} else if (this.state === StreamStates.WRITE_CLOSED) {
|
|
@@ -107,7 +107,7 @@ class StreamState {
|
|
|
107
107
|
}
|
|
108
108
|
break
|
|
109
109
|
|
|
110
|
-
case
|
|
110
|
+
case Message.Flag.STOP_SENDING:
|
|
111
111
|
if (this.state === StreamStates.OPEN) {
|
|
112
112
|
this.state = StreamStates.WRITE_CLOSED
|
|
113
113
|
} else if (this.state === StreamStates.READ_CLOSED) {
|
|
@@ -115,7 +115,7 @@ class StreamState {
|
|
|
115
115
|
}
|
|
116
116
|
break
|
|
117
117
|
|
|
118
|
-
case
|
|
118
|
+
case Message.Flag.RESET:
|
|
119
119
|
this.state = StreamStates.CLOSED
|
|
120
120
|
break
|
|
121
121
|
default:
|
|
@@ -123,7 +123,7 @@ class StreamState {
|
|
|
123
123
|
}
|
|
124
124
|
} else {
|
|
125
125
|
switch (flag) {
|
|
126
|
-
case
|
|
126
|
+
case Message.Flag.FIN:
|
|
127
127
|
if (this.state === StreamStates.OPEN) {
|
|
128
128
|
this.state = StreamStates.WRITE_CLOSED
|
|
129
129
|
} else if (this.state === StreamStates.READ_CLOSED) {
|
|
@@ -131,7 +131,7 @@ class StreamState {
|
|
|
131
131
|
}
|
|
132
132
|
break
|
|
133
133
|
|
|
134
|
-
case
|
|
134
|
+
case Message.Flag.STOP_SENDING:
|
|
135
135
|
if (this.state === StreamStates.OPEN) {
|
|
136
136
|
this.state = StreamStates.READ_CLOSED
|
|
137
137
|
} else if (this.state === StreamStates.WRITE_CLOSED) {
|
|
@@ -139,7 +139,7 @@ class StreamState {
|
|
|
139
139
|
}
|
|
140
140
|
break
|
|
141
141
|
|
|
142
|
-
case
|
|
142
|
+
case Message.Flag.RESET:
|
|
143
143
|
this.state = StreamStates.CLOSED
|
|
144
144
|
break
|
|
145
145
|
|
|
@@ -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())
|
|
@@ -313,7 +313,7 @@ export class WebRTCStream implements Stream {
|
|
|
313
313
|
if (this.streamState.isWriteClosed()) {
|
|
314
314
|
return
|
|
315
315
|
}
|
|
316
|
-
const msgbuf =
|
|
316
|
+
const msgbuf = Message.encode({ message: buf.subarray() })
|
|
317
317
|
const sendbuf = lengthPrefixed.encode.single(msgbuf)
|
|
318
318
|
|
|
319
319
|
this.channel.send(sendbuf.subarray())
|
|
@@ -324,7 +324,7 @@ export class WebRTCStream implements Stream {
|
|
|
324
324
|
* Handle incoming
|
|
325
325
|
*/
|
|
326
326
|
processIncomingProtobuf (buffer: Uint8Array): Uint8Array | undefined {
|
|
327
|
-
const message =
|
|
327
|
+
const message = Message.decode(buffer)
|
|
328
328
|
|
|
329
329
|
if (message.flag !== undefined) {
|
|
330
330
|
const [currentState, nextState] = this.streamState.transition({ direction: 'inbound', flag: message.flag })
|
|
@@ -371,14 +371,14 @@ export class WebRTCStream implements Stream {
|
|
|
371
371
|
* Close a stream for reading only
|
|
372
372
|
*/
|
|
373
373
|
closeRead (): void {
|
|
374
|
-
const [currentState, nextState] = this.streamState.transition({ direction: 'outbound', flag:
|
|
374
|
+
const [currentState, nextState] = this.streamState.transition({ direction: 'outbound', flag: Message.Flag.STOP_SENDING })
|
|
375
375
|
if (currentState === nextState) {
|
|
376
376
|
// No change, no op
|
|
377
377
|
return
|
|
378
378
|
}
|
|
379
379
|
|
|
380
380
|
if (currentState === StreamStates.OPEN || currentState === StreamStates.WRITE_CLOSED) {
|
|
381
|
-
this._sendFlag(
|
|
381
|
+
this._sendFlag(Message.Flag.STOP_SENDING)
|
|
382
382
|
this._innersrc.end()
|
|
383
383
|
}
|
|
384
384
|
|
|
@@ -391,14 +391,14 @@ export class WebRTCStream implements Stream {
|
|
|
391
391
|
* Close a stream for writing only
|
|
392
392
|
*/
|
|
393
393
|
closeWrite (): void {
|
|
394
|
-
const [currentState, nextState] = this.streamState.transition({ direction: 'outbound', flag:
|
|
394
|
+
const [currentState, nextState] = this.streamState.transition({ direction: 'outbound', flag: Message.Flag.FIN })
|
|
395
395
|
if (currentState === nextState) {
|
|
396
396
|
// No change, no op
|
|
397
397
|
return
|
|
398
398
|
}
|
|
399
399
|
|
|
400
400
|
if (currentState === StreamStates.OPEN || currentState === StreamStates.READ_CLOSED) {
|
|
401
|
-
this._sendFlag(
|
|
401
|
+
this._sendFlag(Message.Flag.FIN)
|
|
402
402
|
this.closeWritePromise.resolve()
|
|
403
403
|
}
|
|
404
404
|
|
|
@@ -421,20 +421,20 @@ export class WebRTCStream implements Stream {
|
|
|
421
421
|
* @see this.closeWrite
|
|
422
422
|
*/
|
|
423
423
|
reset (): void {
|
|
424
|
-
const [currentState, nextState] = this.streamState.transition({ direction: 'outbound', flag:
|
|
424
|
+
const [currentState, nextState] = this.streamState.transition({ direction: 'outbound', flag: Message.Flag.RESET })
|
|
425
425
|
if (currentState === nextState) {
|
|
426
426
|
// No change, no op
|
|
427
427
|
return
|
|
428
428
|
}
|
|
429
429
|
|
|
430
|
-
this._sendFlag(
|
|
430
|
+
this._sendFlag(Message.Flag.RESET)
|
|
431
431
|
this.close()
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
private _sendFlag (flag:
|
|
434
|
+
private _sendFlag (flag: Message.Flag): void {
|
|
435
435
|
try {
|
|
436
436
|
log.trace('Sending flag: %s', flag.toString())
|
|
437
|
-
const msgbuf =
|
|
437
|
+
const msgbuf = Message.encode({ flag })
|
|
438
438
|
this.channel.send(lengthPrefixed.encode.single(msgbuf).subarray())
|
|
439
439
|
} catch (err) {
|
|
440
440
|
if (err instanceof Error) {
|
package/src/util.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { detect } from 'detect-browser'
|
|
2
|
+
|
|
3
|
+
const browser = detect()
|
|
4
|
+
export const isFirefox = ((browser != null) && browser.name === 'firefox')
|
|
5
|
+
|
|
1
6
|
export const nopSource = async function * nop (): AsyncGenerator<Uint8Array, any, unknown> {}
|
|
2
7
|
|
|
3
8
|
export const nopSink = async (_: any): Promise<void> => {}
|
|
4
|
-
|
|
5
|
-
const charset = Array.from('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/')
|
|
6
|
-
export const genUfrag = (len: number): string => [...Array(len)].map(() => charset.at(Math.floor(Math.random() * charset.length))).join('')
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import type { BinaryWriteOptions } from "@protobuf-ts/runtime";
|
|
2
|
-
import type { IBinaryWriter } from "@protobuf-ts/runtime";
|
|
3
|
-
import type { BinaryReadOptions } from "@protobuf-ts/runtime";
|
|
4
|
-
import type { IBinaryReader } from "@protobuf-ts/runtime";
|
|
5
|
-
import type { PartialMessage } from "@protobuf-ts/runtime";
|
|
6
|
-
import { MessageType } from "@protobuf-ts/runtime";
|
|
7
|
-
/**
|
|
8
|
-
* @generated from protobuf message webrtc.pb.Message
|
|
9
|
-
*/
|
|
10
|
-
export interface Message {
|
|
11
|
-
/**
|
|
12
|
-
* @generated from protobuf field: optional webrtc.pb.Message.Flag flag = 1;
|
|
13
|
-
*/
|
|
14
|
-
flag?: Message_Flag;
|
|
15
|
-
/**
|
|
16
|
-
* @generated from protobuf field: optional bytes message = 2;
|
|
17
|
-
*/
|
|
18
|
-
message?: Uint8Array;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* @generated from protobuf enum webrtc.pb.Message.Flag
|
|
22
|
-
*/
|
|
23
|
-
export declare enum Message_Flag {
|
|
24
|
-
/**
|
|
25
|
-
* The sender will no longer send messages on the stream.
|
|
26
|
-
*
|
|
27
|
-
* @generated from protobuf enum value: FIN = 0;
|
|
28
|
-
*/
|
|
29
|
-
FIN = 0,
|
|
30
|
-
/**
|
|
31
|
-
* The sender will no longer read messages on the stream. Incoming data is
|
|
32
|
-
* being discarded on receipt.
|
|
33
|
-
*
|
|
34
|
-
* @generated from protobuf enum value: STOP_SENDING = 1;
|
|
35
|
-
*/
|
|
36
|
-
STOP_SENDING = 1,
|
|
37
|
-
/**
|
|
38
|
-
* The sender abruptly terminates the sending part of the stream. The
|
|
39
|
-
* receiver can discard any data that it already received on that stream.
|
|
40
|
-
*
|
|
41
|
-
* @generated from protobuf enum value: RESET = 2;
|
|
42
|
-
*/
|
|
43
|
-
RESET = 2
|
|
44
|
-
}
|
|
45
|
-
declare class Message$Type extends MessageType<Message> {
|
|
46
|
-
constructor();
|
|
47
|
-
create(value?: PartialMessage<Message>): Message;
|
|
48
|
-
internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Message): Message;
|
|
49
|
-
internalBinaryWrite(message: Message, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* @generated MessageType for protobuf message webrtc.pb.Message
|
|
53
|
-
*/
|
|
54
|
-
export declare const Message: Message$Type;
|
|
55
|
-
export {};
|
|
56
|
-
//# sourceMappingURL=message.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../proto_ts/message.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD;;GAEG;AACH,MAAM,WAAW,OAAO;IACpB;;OAEG;IACH,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,CAAC;CACxB;AACD;;GAEG;AACH,oBAAY,YAAY;IACpB;;;;OAIG;IACH,GAAG,IAAI;IACP;;;;;OAKG;IACH,YAAY,IAAI;IAChB;;;;;OAKG;IACH,KAAK,IAAI;CACZ;AAED,cAAM,YAAa,SAAQ,WAAW,CAAC,OAAO,CAAC;;IAO3C,MAAM,CAAC,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,GAAG,OAAO;IAOhD,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO;IAsBhH,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,GAAG,aAAa;CAY3G;AACD;;GAEG;AACH,eAAO,MAAM,OAAO,cAAqB,CAAC"}
|