@libp2p/webrtc 5.2.24-6059227cb → 5.2.24-8484de8a2
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/dist/index.min.js +13 -13
- package/dist/index.min.js.map +4 -4
- package/dist/src/constants.d.ts +0 -4
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +0 -4
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +0 -8
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/muxer.d.ts.map +1 -1
- package/dist/src/muxer.js +12 -7
- package/dist/src/muxer.js.map +1 -1
- package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
- package/dist/src/private-to-private/initiate-connection.js +1 -15
- package/dist/src/private-to-private/initiate-connection.js.map +1 -1
- package/dist/src/private-to-private/signaling-stream-handler.d.ts.map +1 -1
- package/dist/src/private-to-private/signaling-stream-handler.js +2 -10
- package/dist/src/private-to-private/signaling-stream-handler.js.map +1 -1
- package/dist/src/private-to-private/transport.d.ts +7 -0
- package/dist/src/private-to-private/transport.d.ts.map +1 -1
- package/dist/src/private-to-private/transport.js.map +1 -1
- package/dist/src/private-to-private/util.d.ts +1 -0
- package/dist/src/private-to-private/util.d.ts.map +1 -1
- package/dist/src/private-to-private/util.js +11 -11
- package/dist/src/private-to-private/util.js.map +1 -1
- package/dist/src/private-to-public/transport.d.ts +8 -0
- package/dist/src/private-to-public/transport.d.ts.map +1 -1
- package/dist/src/private-to-public/transport.js.map +1 -1
- package/dist/src/rtcpeerconnection-to-conn.d.ts.map +1 -1
- package/dist/src/rtcpeerconnection-to-conn.js +0 -3
- package/dist/src/rtcpeerconnection-to-conn.js.map +1 -1
- package/dist/src/stream.d.ts +2 -3
- package/dist/src/stream.d.ts.map +1 -1
- package/dist/src/stream.js +68 -100
- package/dist/src/stream.js.map +1 -1
- package/package.json +10 -10
- package/src/constants.ts +0 -5
- package/src/index.ts +0 -9
- package/src/muxer.ts +13 -6
- package/src/private-to-private/initiate-connection.ts +2 -18
- package/src/private-to-private/signaling-stream-handler.ts +2 -12
- package/src/private-to-private/transport.ts +8 -0
- package/src/private-to-private/util.ts +12 -12
- package/src/private-to-public/transport.ts +10 -0
- package/src/rtcpeerconnection-to-conn.ts +0 -4
- package/src/stream.ts +79 -115
package/dist/src/stream.js
CHANGED
@@ -1,13 +1,11 @@
|
|
1
|
-
import {
|
1
|
+
import { StreamStateError } from '@libp2p/interface';
|
2
2
|
import { AbstractStream } from '@libp2p/utils';
|
3
3
|
import * as lengthPrefixed from 'it-length-prefixed';
|
4
4
|
import { pushable } from 'it-pushable';
|
5
|
-
import { pEvent } from 'p-event';
|
6
5
|
import { raceSignal } from 'race-signal';
|
7
6
|
import { Uint8ArrayList } from 'uint8arraylist';
|
8
|
-
import {
|
7
|
+
import { MAX_BUFFERED_AMOUNT, MAX_MESSAGE_SIZE, PROTOBUF_OVERHEAD } from './constants.js';
|
9
8
|
import { Message } from './private-to-public/pb/message.js';
|
10
|
-
import { isFirefox } from './util.js';
|
11
9
|
export class WebRTCStream extends AbstractStream {
|
12
10
|
/**
|
13
11
|
* The data channel used to send and receive data
|
@@ -20,7 +18,6 @@ export class WebRTCStream extends AbstractStream {
|
|
20
18
|
incomingData;
|
21
19
|
maxBufferedAmount;
|
22
20
|
receivedFinAck;
|
23
|
-
finAckTimeout;
|
24
21
|
constructor(init) {
|
25
22
|
super({
|
26
23
|
...init,
|
@@ -30,20 +27,36 @@ export class WebRTCStream extends AbstractStream {
|
|
30
27
|
this.channel.binaryType = 'arraybuffer';
|
31
28
|
this.incomingData = pushable();
|
32
29
|
this.maxBufferedAmount = init.maxBufferedAmount ?? MAX_BUFFERED_AMOUNT;
|
33
|
-
this.
|
30
|
+
this.receivedFinAck = Promise.withResolvers();
|
31
|
+
// set up initial state
|
32
|
+
switch (this.channel.readyState) {
|
33
|
+
case 'open':
|
34
|
+
break;
|
35
|
+
case 'closed':
|
36
|
+
case 'closing':
|
37
|
+
if (this.timeline.close === undefined || this.timeline.close === 0) {
|
38
|
+
this.timeline.close = Date.now();
|
39
|
+
}
|
40
|
+
break;
|
41
|
+
case 'connecting':
|
42
|
+
// noop
|
43
|
+
break;
|
44
|
+
default:
|
45
|
+
this.log.error('unknown datachannel state %s', this.channel.readyState);
|
46
|
+
throw new StreamStateError('Unknown datachannel state');
|
47
|
+
}
|
34
48
|
// handle RTCDataChannel events
|
35
|
-
this.channel.onclose = () => {
|
36
|
-
this.log.trace('received
|
49
|
+
this.channel.onclose = (_evt) => {
|
50
|
+
this.log.trace('received onclose event');
|
37
51
|
this.onRemoteCloseWrite();
|
38
52
|
this.onTransportClosed();
|
39
53
|
};
|
40
54
|
this.channel.onerror = (evt) => {
|
55
|
+
this.log.trace('received onerror event');
|
41
56
|
const err = evt.error;
|
42
|
-
this.log.trace('received datachannel error event - %e', err);
|
43
57
|
this.abort(err);
|
44
58
|
};
|
45
59
|
this.channel.onmessage = async (event) => {
|
46
|
-
this.log('incoming message %d bytes', event.data.byteLength);
|
47
60
|
const { data } = event;
|
48
61
|
if (data === null || data.byteLength === 0) {
|
49
62
|
return;
|
@@ -53,123 +66,79 @@ export class WebRTCStream extends AbstractStream {
|
|
53
66
|
// dispatch drain event when the buffered amount drops to zero
|
54
67
|
this.channel.bufferedAmountLowThreshold = 0;
|
55
68
|
this.channel.onbufferedamountlow = () => {
|
56
|
-
|
57
|
-
this.safeDispatchEvent('drain');
|
58
|
-
}
|
69
|
+
this.safeDispatchEvent('drain');
|
59
70
|
};
|
60
|
-
|
61
|
-
this.log('channel ready state is "%s" and not "open", waiting for "open" event before sending data', this.channel.readyState);
|
62
|
-
pEvent(this.channel, 'open', {
|
63
|
-
rejectionEvents: [
|
64
|
-
'close',
|
65
|
-
'error'
|
66
|
-
]
|
67
|
-
})
|
68
|
-
.then(() => {
|
69
|
-
this.log('channel ready state is now "%s", dispatching drain', this.channel.readyState);
|
70
|
-
this.safeDispatchEvent('drain');
|
71
|
-
})
|
72
|
-
.catch(err => {
|
73
|
-
this.abort(err.error ?? err);
|
74
|
-
});
|
75
|
-
}
|
71
|
+
const self = this;
|
76
72
|
// pipe framed protobuf messages through a length prefixed decoder, and
|
77
73
|
// surface data from the `Message.message` field through a source.
|
78
74
|
Promise.resolve().then(async () => {
|
79
75
|
for await (const buf of lengthPrefixed.decode(this.incomingData)) {
|
80
|
-
|
76
|
+
const message = self.processIncomingProtobuf(buf);
|
77
|
+
if (message != null) {
|
78
|
+
self.onData(new Uint8ArrayList(message));
|
79
|
+
}
|
81
80
|
}
|
82
81
|
})
|
83
82
|
.catch(err => {
|
84
83
|
this.log.error('error processing incoming data channel messages', err);
|
85
84
|
});
|
86
|
-
//
|
87
|
-
const
|
88
|
-
|
89
|
-
this.log.trace('stream closed, closing underlying datachannel');
|
90
|
-
this.channel.close();
|
91
|
-
}
|
85
|
+
// clean up the datachannel when both ends have sent a FIN
|
86
|
+
const webRTCStreamOnClose = () => {
|
87
|
+
this.channel.close();
|
92
88
|
};
|
93
|
-
this.addEventListener('close',
|
89
|
+
this.addEventListener('close', webRTCStreamOnClose);
|
94
90
|
}
|
95
91
|
sendNewStream() {
|
96
92
|
// opening new streams is handled by WebRTC so this is a noop
|
97
93
|
}
|
98
94
|
_sendMessage(data) {
|
99
|
-
if (this.channel.readyState
|
95
|
+
if (this.channel.readyState === 'closed' || this.channel.readyState === 'closing') {
|
100
96
|
throw new StreamStateError(`Invalid datachannel state - ${this.channel.readyState}`);
|
101
97
|
}
|
102
|
-
|
103
|
-
|
104
|
-
//
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
return;
|
98
|
+
try {
|
99
|
+
this.log.trace('sending message, channel state "%s"', this.channel.readyState);
|
100
|
+
// send message without copying data
|
101
|
+
for (const buf of data) {
|
102
|
+
this.channel.send(buf);
|
103
|
+
}
|
109
104
|
}
|
110
|
-
|
111
|
-
|
112
|
-
this.channel.send(buf);
|
105
|
+
catch (err) {
|
106
|
+
this.log.error('error while sending message', err);
|
113
107
|
}
|
114
108
|
}
|
115
109
|
sendData(data) {
|
116
|
-
|
117
|
-
return {
|
118
|
-
sentBytes: 0,
|
119
|
-
canSendMore: false
|
120
|
-
};
|
121
|
-
}
|
122
|
-
// TODO: firefox can deliver small messages out of order - remove once a
|
123
|
-
// browser with https://bugzilla.mozilla.org/show_bug.cgi?id=1983831 is
|
124
|
-
// available in playwright-test
|
125
|
-
// ----
|
126
|
-
// this is also necessary to work with rust-libp2p 0.54 though 0.53 seems ok
|
127
|
-
this._sendMessage(lengthPrefixed.encode.single(Message.encode({
|
110
|
+
const messageBuf = Message.encode({
|
128
111
|
message: data.subarray()
|
129
|
-
})
|
130
|
-
|
131
|
-
|
132
|
-
// send message without copying data
|
133
|
-
for (const message of data) {
|
134
|
-
this._sendMessage(
|
135
|
-
lengthPrefixed.encode.single(Message.encode({
|
136
|
-
message
|
137
|
-
}))
|
138
|
-
)
|
139
|
-
}
|
140
|
-
}
|
141
|
-
*/
|
112
|
+
});
|
113
|
+
const prefixedBuf = lengthPrefixed.encode.single(messageBuf);
|
114
|
+
this._sendMessage(prefixedBuf);
|
142
115
|
return {
|
143
116
|
sentBytes: data.byteLength,
|
144
117
|
canSendMore: this.channel.bufferedAmount < this.maxBufferedAmount
|
145
118
|
};
|
146
119
|
}
|
147
|
-
sendReset(
|
120
|
+
sendReset() {
|
121
|
+
this.receivedFinAck.resolve();
|
148
122
|
try {
|
149
|
-
this.log.error('sending reset - %e', err);
|
150
123
|
this._sendFlag(Message.Flag.RESET);
|
151
|
-
this.receivedFinAck?.reject(err);
|
152
124
|
}
|
153
125
|
catch (err) {
|
154
126
|
this.log.error('failed to send reset - %e', err);
|
155
127
|
}
|
128
|
+
finally {
|
129
|
+
this.channel.close();
|
130
|
+
}
|
156
131
|
}
|
157
132
|
async sendCloseWrite(options) {
|
158
|
-
this.
|
159
|
-
|
160
|
-
|
161
|
-
await
|
162
|
-
raceSignal(this.receivedFinAck.promise, options?.signal),
|
163
|
-
new Promise(resolve => {
|
164
|
-
AbortSignal.timeout(this.finAckTimeout)
|
165
|
-
.addEventListener('abort', () => {
|
166
|
-
resolve();
|
167
|
-
});
|
168
|
-
})
|
169
|
-
]);
|
133
|
+
if (this.channel.readyState === 'open') {
|
134
|
+
this._sendFlag(Message.Flag.FIN);
|
135
|
+
}
|
136
|
+
await raceSignal(this.receivedFinAck.promise, options?.signal);
|
170
137
|
}
|
171
138
|
async sendCloseRead(options) {
|
172
|
-
this.
|
139
|
+
if (this.channel.readyState === 'open') {
|
140
|
+
this._sendFlag(Message.Flag.STOP_SENDING);
|
141
|
+
}
|
173
142
|
options?.signal?.throwIfAborted();
|
174
143
|
}
|
175
144
|
/**
|
@@ -177,31 +146,30 @@ export class WebRTCStream extends AbstractStream {
|
|
177
146
|
*/
|
178
147
|
processIncomingProtobuf(buffer) {
|
179
148
|
const message = Message.decode(buffer);
|
180
|
-
// ignore data messages if we've closed the readable end already
|
181
|
-
if (message.message != null && (this.readStatus === 'readable' || this.readStatus === 'paused')) {
|
182
|
-
this.onData(new Uint8ArrayList(message.message));
|
183
|
-
}
|
184
149
|
if (message.flag !== undefined) {
|
185
150
|
this.log.trace('incoming flag %s, write status "%s", read status "%s"', message.flag, this.writeStatus, this.readStatus);
|
186
151
|
if (message.flag === Message.Flag.FIN) {
|
187
|
-
//
|
188
|
-
this._sendFlag(Message.Flag.FIN_ACK);
|
152
|
+
// We should expect no more data from the remote, stop reading
|
189
153
|
this.onRemoteCloseWrite();
|
154
|
+
this._sendFlag(Message.Flag.FIN_ACK);
|
190
155
|
}
|
191
156
|
if (message.flag === Message.Flag.RESET) {
|
192
|
-
|
193
|
-
|
157
|
+
this.receivedFinAck.resolve();
|
158
|
+
// Stop reading and writing to the stream immediately
|
194
159
|
this.onRemoteReset();
|
195
160
|
}
|
196
161
|
if (message.flag === Message.Flag.STOP_SENDING) {
|
197
|
-
//
|
162
|
+
// The remote has stopped reading
|
198
163
|
this.onRemoteCloseRead();
|
199
164
|
}
|
200
165
|
if (message.flag === Message.Flag.FIN_ACK) {
|
201
|
-
|
202
|
-
this.receivedFinAck?.resolve();
|
166
|
+
this.receivedFinAck.resolve();
|
203
167
|
}
|
204
168
|
}
|
169
|
+
// ignore data messages if we've closed the readable end already
|
170
|
+
if (this.readStatus === 'readable' || this.readStatus === 'paused') {
|
171
|
+
return message.message;
|
172
|
+
}
|
205
173
|
}
|
206
174
|
_sendFlag(flag) {
|
207
175
|
if (this.channel.readyState !== 'open') {
|
package/dist/src/stream.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/stream.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@libp2p/webrtc",
|
3
|
-
"version": "5.2.24-
|
3
|
+
"version": "5.2.24-8484de8a2",
|
4
4
|
"description": "A libp2p transport using WebRTC connections",
|
5
5
|
"license": "Apache-2.0 OR MIT",
|
6
6
|
"homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/transport-webrtc#readme",
|
@@ -45,13 +45,13 @@
|
|
45
45
|
},
|
46
46
|
"dependencies": {
|
47
47
|
"@chainsafe/is-ip": "^2.1.0",
|
48
|
-
"@libp2p/crypto": "5.1.8-
|
49
|
-
"@libp2p/interface": "2.11.0-
|
50
|
-
"@libp2p/interface-internal": "2.3.19-
|
51
|
-
"@libp2p/keychain": "5.2.9-
|
52
|
-
"@libp2p/noise": "16.1.4-
|
53
|
-
"@libp2p/peer-id": "5.1.9-
|
54
|
-
"@libp2p/utils": "6.7.2-
|
48
|
+
"@libp2p/crypto": "5.1.8-8484de8a2",
|
49
|
+
"@libp2p/interface": "2.11.0-8484de8a2",
|
50
|
+
"@libp2p/interface-internal": "2.3.19-8484de8a2",
|
51
|
+
"@libp2p/keychain": "5.2.9-8484de8a2",
|
52
|
+
"@libp2p/noise": "16.1.4-8484de8a2",
|
53
|
+
"@libp2p/peer-id": "5.1.9-8484de8a2",
|
54
|
+
"@libp2p/utils": "6.7.2-8484de8a2",
|
55
55
|
"@multiformats/multiaddr": "^13.0.1",
|
56
56
|
"@multiformats/multiaddr-matcher": "^3.0.1",
|
57
57
|
"@peculiar/webcrypto": "^1.5.0",
|
@@ -79,9 +79,9 @@
|
|
79
79
|
"uint8arrays": "^5.1.0"
|
80
80
|
},
|
81
81
|
"devDependencies": {
|
82
|
-
"@libp2p/logger": "5.2.0-
|
82
|
+
"@libp2p/logger": "5.2.0-8484de8a2",
|
83
83
|
"@types/sinon": "^17.0.4",
|
84
|
-
"aegir": "^47.0.
|
84
|
+
"aegir": "^47.0.21",
|
85
85
|
"any-signal": "^4.1.1",
|
86
86
|
"datastore-core": "^10.0.4",
|
87
87
|
"delay": "^6.0.0",
|
package/src/constants.ts
CHANGED
@@ -73,11 +73,6 @@ export const PROTOBUF_OVERHEAD = calculateProtobufOverhead()
|
|
73
73
|
*/
|
74
74
|
export const DATA_CHANNEL_DRAIN_TIMEOUT = 30_000
|
75
75
|
|
76
|
-
/**
|
77
|
-
* Wait for the remote to acknowledge our FIN for this long
|
78
|
-
*/
|
79
|
-
export const DEFAULT_FIN_ACK_TIMEOUT = 10_000
|
80
|
-
|
81
76
|
/**
|
82
77
|
* Set as the 'negotiated' muxer protocol name
|
83
78
|
*/
|
package/src/index.ts
CHANGED
@@ -308,15 +308,6 @@ export interface DataChannelOptions {
|
|
308
308
|
* @default 5_000
|
309
309
|
*/
|
310
310
|
openTimeout?: number
|
311
|
-
|
312
|
-
/**
|
313
|
-
* Due to bugs in WebRTC implementations it's necessary for the remote end of
|
314
|
-
* the connection to acknowledge the FIN message we send during stream
|
315
|
-
* closing. A stream will wait for this many ms.
|
316
|
-
*
|
317
|
-
* @default 10_000
|
318
|
-
*/
|
319
|
-
finAckTimeout?: number
|
320
311
|
}
|
321
312
|
|
322
313
|
/**
|
package/src/muxer.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import { AbstractStreamMuxer } from '@libp2p/utils'
|
2
|
+
import { pEvent } from 'p-event'
|
2
3
|
import { MUXER_PROTOCOL } from './constants.js'
|
3
4
|
import { createStream, WebRTCStream } from './stream.js'
|
4
5
|
import type { DataChannelOptions } from './index.js'
|
@@ -89,12 +90,11 @@ export class DataChannelMuxer extends AbstractStreamMuxer<WebRTCStream> implemen
|
|
89
90
|
* {@link https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/datachannel_event}
|
90
91
|
*/
|
91
92
|
this.peerConnection.ondatachannel = ({ channel }) => {
|
92
|
-
this.log.trace('incoming %s datachannel with channel id %d
|
93
|
+
this.log.trace('incoming %s datachannel with channel id %d and status', channel.protocol, channel.id, channel.readyState)
|
93
94
|
|
94
|
-
// 'init' channel is only used during connection establishment
|
95
|
-
// closed by the initiator
|
95
|
+
// 'init' channel is only used during connection establishment
|
96
96
|
if (channel.label === 'init') {
|
97
|
-
this.log.trace('closing init channel
|
97
|
+
this.log.trace('closing init channel')
|
98
98
|
channel.close()
|
99
99
|
|
100
100
|
return
|
@@ -114,13 +114,20 @@ export class DataChannelMuxer extends AbstractStreamMuxer<WebRTCStream> implemen
|
|
114
114
|
|
115
115
|
async onCreateStream (options?: CreateStreamOptions): Promise<WebRTCStream> {
|
116
116
|
// The spec says the label MUST be an empty string: https://github.com/libp2p/specs/blob/master/webrtc/README.md#rtcdatachannel-label
|
117
|
-
const channel = this.peerConnection.createDataChannel('', {
|
117
|
+
const channel = this.peerConnection.createDataChannel('wtf', {
|
118
118
|
// TODO: pre-negotiate stream protocol
|
119
|
-
|
119
|
+
protocol: options?.protocol
|
120
120
|
})
|
121
121
|
|
122
122
|
this.log('open channel %d for protocol %s', channel.id, options?.protocol)
|
123
123
|
|
124
|
+
if (channel.readyState !== 'open') {
|
125
|
+
this.log('channel %d state is "%s" and not "open", waiting for "open" event before sending data', channel.id, channel.readyState)
|
126
|
+
await pEvent(channel, 'open', options)
|
127
|
+
|
128
|
+
this.log('channel %d state is now "%s", sending data', channel.id, channel.readyState)
|
129
|
+
}
|
130
|
+
|
124
131
|
const stream = createStream({
|
125
132
|
...options,
|
126
133
|
...this.dataChannelOptions,
|
@@ -94,20 +94,10 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa
|
|
94
94
|
|
95
95
|
// setup callback to write ICE candidates to the remote peer
|
96
96
|
peerConnection.onicecandidate = ({ candidate }) => {
|
97
|
-
if (peerConnection.connectionState === 'connected') {
|
98
|
-
log.trace('ignore new ice candidate as peer connection is already connected')
|
99
|
-
return
|
100
|
-
}
|
101
|
-
|
102
97
|
// a null candidate means end-of-candidates, an empty string candidate
|
103
98
|
// means end-of-candidates for this generation, otherwise this should
|
104
99
|
// be a valid candidate object
|
105
100
|
// see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent
|
106
|
-
if (candidate == null || candidate?.candidate === '') {
|
107
|
-
log.trace('initiator detected end of ICE candidates')
|
108
|
-
return
|
109
|
-
}
|
110
|
-
|
111
101
|
const data = JSON.stringify(candidate?.toJSON() ?? null)
|
112
102
|
|
113
103
|
log.trace('initiator sending ICE candidate %o', candidate)
|
@@ -188,15 +178,9 @@ export async function initiateConnection ({ rtcConfiguration, dataChannel, signa
|
|
188
178
|
})
|
189
179
|
}
|
190
180
|
|
191
|
-
log.trace('closing init channel')
|
192
|
-
channel.close()
|
181
|
+
log.trace('closing init channel, starting status')
|
193
182
|
|
194
|
-
|
195
|
-
// id can be reused before both sides have seen the channel close
|
196
|
-
log.trace('waiting for init channel to close')
|
197
|
-
await pEvent(channel, 'close', {
|
198
|
-
signal
|
199
|
-
})
|
183
|
+
channel.close()
|
200
184
|
|
201
185
|
onProgress?.(new CustomProgressEvent('webrtc:close-signaling-stream'))
|
202
186
|
|
@@ -3,7 +3,7 @@ import { multiaddr } from '@multiformats/multiaddr'
|
|
3
3
|
import { SDPHandshakeFailedError } from '../error.js'
|
4
4
|
import { RTCSessionDescription } from '../webrtc/index.js'
|
5
5
|
import { Message } from './pb/message.js'
|
6
|
-
import { getRemotePeer, readCandidatesUntilConnected } from './util.js'
|
6
|
+
import { getConnectionState, getRemotePeer, readCandidatesUntilConnected } from './util.js'
|
7
7
|
import type { RTCPeerConnection } from '../webrtc/index.js'
|
8
8
|
import type { AbortOptions, Connection, Logger, PeerId, Stream } from '@libp2p/interface'
|
9
9
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
@@ -21,20 +21,10 @@ export async function handleIncomingStream (stream: Stream, connection: Connecti
|
|
21
21
|
try {
|
22
22
|
// candidate callbacks
|
23
23
|
peerConnection.onicecandidate = ({ candidate }) => {
|
24
|
-
if (peerConnection.connectionState === 'connected') {
|
25
|
-
log.trace('ignore new ice candidate as peer connection is already connected')
|
26
|
-
return
|
27
|
-
}
|
28
|
-
|
29
24
|
// a null candidate means end-of-candidates, an empty string candidate
|
30
25
|
// means end-of-candidates for this generation, otherwise this should
|
31
26
|
// be a valid candidate object
|
32
27
|
// see - https://www.w3.org/TR/webrtc/#rtcpeerconnectioniceevent
|
33
|
-
if (candidate == null || candidate?.candidate === '') {
|
34
|
-
log.trace('recipient detected end of ICE candidates')
|
35
|
-
return
|
36
|
-
}
|
37
|
-
|
38
28
|
const data = JSON.stringify(candidate?.toJSON() ?? null)
|
39
29
|
|
40
30
|
log.trace('recipient sending ICE candidate %s', data)
|
@@ -100,7 +90,7 @@ export async function handleIncomingStream (stream: Stream, connection: Connecti
|
|
100
90
|
log
|
101
91
|
})
|
102
92
|
} catch (err: any) {
|
103
|
-
if (peerConnection
|
93
|
+
if (getConnectionState(peerConnection) !== 'connected') {
|
104
94
|
log.error('error while handling signaling stream from peer %a', connection.remoteAddr, err)
|
105
95
|
|
106
96
|
peerConnection.close()
|
@@ -31,6 +31,14 @@ export interface WebRTCTransportInit {
|
|
31
31
|
* Any options here will be applied to any RTCDataChannels that are opened.
|
32
32
|
*/
|
33
33
|
dataChannel?: DataChannelOptions
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Inbound connections must complete the upgrade within this many ms
|
37
|
+
*
|
38
|
+
* @default 30_000
|
39
|
+
* @deprecated configure `connectionManager.inboundUpgradeTimeout` instead
|
40
|
+
*/
|
41
|
+
inboundConnectionTimeout?: number
|
34
42
|
}
|
35
43
|
|
36
44
|
export interface WebRTCTransportComponents {
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { ConnectionFailedError, InvalidMessageError, InvalidMultiaddrError } from '@libp2p/interface'
|
2
2
|
import { peerIdFromString } from '@libp2p/peer-id'
|
3
3
|
import { CustomProgressEvent } from 'progress-events'
|
4
|
+
import { isFirefox } from '../util.js'
|
4
5
|
import { RTCIceCandidate } from '../webrtc/index.js'
|
5
6
|
import { Message } from './pb/message.js'
|
6
7
|
import type { WebRTCDialEvents } from './transport.js'
|
@@ -27,7 +28,7 @@ export const readCandidatesUntilConnected = async (pc: RTCPeerConnection, stream
|
|
27
28
|
connectedPromise.promise,
|
28
29
|
stream.read({
|
29
30
|
signal: options.signal
|
30
|
-
})
|
31
|
+
}).catch(() => {})
|
31
32
|
])
|
32
33
|
|
33
34
|
// stream ended or we became connected
|
@@ -62,33 +63,32 @@ export const readCandidatesUntilConnected = async (pc: RTCPeerConnection, stream
|
|
62
63
|
options.onProgress?.(new CustomProgressEvent<string>('webrtc:add-ice-candidate', candidate.candidate))
|
63
64
|
await pc.addIceCandidate(candidate)
|
64
65
|
} catch (err) {
|
65
|
-
options.log.error('%s bad candidate received
|
66
|
+
options.log.error('%s bad candidate received', options.direction, candidateInit, err)
|
66
67
|
}
|
67
68
|
}
|
68
69
|
} catch (err) {
|
69
|
-
options.log.error('%s error parsing ICE candidate
|
70
|
+
options.log.error('%s error parsing ICE candidate', options.direction, err)
|
70
71
|
|
71
|
-
if (options.signal?.aborted === true && pc
|
72
|
+
if (options.signal?.aborted === true && getConnectionState(pc) !== 'connected') {
|
72
73
|
throw err
|
73
74
|
}
|
74
75
|
}
|
75
76
|
}
|
76
77
|
|
77
|
-
function
|
78
|
-
|
79
|
-
|
80
|
-
return
|
81
|
-
}
|
78
|
+
export function getConnectionState (pc: RTCPeerConnection): string {
|
79
|
+
return isFirefox ? pc.iceConnectionState : pc.connectionState
|
80
|
+
}
|
82
81
|
|
83
|
-
|
84
|
-
|
82
|
+
function resolveOnConnected (pc: RTCPeerConnection, promise: DeferredPromise<void>): void {
|
83
|
+
pc[isFirefox ? 'oniceconnectionstatechange' : 'onconnectionstatechange'] = (_) => {
|
84
|
+
switch (getConnectionState(pc)) {
|
85
85
|
case 'connected':
|
86
86
|
promise.resolve()
|
87
87
|
break
|
88
88
|
case 'failed':
|
89
89
|
case 'disconnected':
|
90
90
|
case 'closed':
|
91
|
-
promise.reject(new ConnectionFailedError(
|
91
|
+
promise.reject(new ConnectionFailedError('RTCPeerConnection was closed'))
|
92
92
|
break
|
93
93
|
default:
|
94
94
|
break
|
@@ -51,6 +51,11 @@ export interface WebRTCTransportDirectInit {
|
|
51
51
|
*/
|
52
52
|
dataChannel?: DataChannelOptions
|
53
53
|
|
54
|
+
/**
|
55
|
+
* @deprecated use `certificate` instead - this option will be removed in a future release
|
56
|
+
*/
|
57
|
+
certificates?: TransportCertificate[]
|
58
|
+
|
54
59
|
/**
|
55
60
|
* Use an existing TLS certificate to secure incoming connections or supply
|
56
61
|
* settings to generate one.
|
@@ -63,6 +68,11 @@ export interface WebRTCTransportDirectInit {
|
|
63
68
|
*/
|
64
69
|
certificate?: TransportCertificate
|
65
70
|
|
71
|
+
/**
|
72
|
+
* @deprecated this setting is ignored and will be removed in a future release
|
73
|
+
*/
|
74
|
+
useLibjuice?: boolean
|
75
|
+
|
66
76
|
/**
|
67
77
|
* The key the certificate is stored in the datastore under
|
68
78
|
*
|
@@ -24,10 +24,6 @@ class RTCPeerConnectionMultiaddrConnection extends AbstractMultiaddrConnection {
|
|
24
24
|
if (this.peerConnection.connectionState === 'disconnected' || this.peerConnection.connectionState === 'failed' || this.peerConnection.connectionState === 'closed') {
|
25
25
|
// nothing else to do but close the connection
|
26
26
|
this.onTransportClosed()
|
27
|
-
|
28
|
-
// only necessary with node-datachannel
|
29
|
-
// https://github.com/murat-dogan/node-datachannel/issues/366#issuecomment-3228453155
|
30
|
-
this.peerConnection.close()
|
31
27
|
}
|
32
28
|
}
|
33
29
|
}
|