@libp2p/webrtc 5.2.24-a02cb0461 → 5.2.24-f5932c294
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 +20 -10
- package/dist/index.min.js +14 -14
- package/dist/index.min.js.map +4 -4
- package/dist/src/constants.d.ts +15 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +15 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +22 -12
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +22 -12
- package/dist/src/index.js.map +1 -1
- package/dist/src/maconn.d.ts +58 -0
- package/dist/src/maconn.d.ts.map +1 -0
- package/dist/src/maconn.js +56 -0
- package/dist/src/maconn.js.map +1 -0
- package/dist/src/muxer.d.ts +46 -14
- package/dist/src/muxer.d.ts.map +1 -1
- package/dist/src/muxer.js +135 -32
- package/dist/src/muxer.js.map +1 -1
- package/dist/src/private-to-private/initiate-connection.d.ts +4 -3
- package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
- package/dist/src/private-to-private/initiate-connection.js +5 -23
- package/dist/src/private-to-private/initiate-connection.js.map +1 -1
- package/dist/src/private-to-private/signaling-stream-handler.d.ts +4 -4
- package/dist/src/private-to-private/signaling-stream-handler.d.ts.map +1 -1
- package/dist/src/private-to-private/signaling-stream-handler.js +6 -10
- package/dist/src/private-to-private/signaling-stream-handler.js.map +1 -1
- package/dist/src/private-to-private/transport.d.ts +2 -2
- package/dist/src/private-to-private/transport.d.ts.map +1 -1
- package/dist/src/private-to-private/transport.js +15 -30
- package/dist/src/private-to-private/transport.js.map +1 -1
- package/dist/src/private-to-private/util.d.ts +1 -3
- package/dist/src/private-to-private/util.d.ts.map +1 -1
- package/dist/src/private-to-private/util.js +3 -15
- package/dist/src/private-to-private/util.js.map +1 -1
- package/dist/src/private-to-public/listener.js +2 -2
- package/dist/src/private-to-public/listener.js.map +1 -1
- package/dist/src/private-to-public/transport.js +1 -1
- package/dist/src/private-to-public/transport.js.map +1 -1
- package/dist/src/private-to-public/utils/connect.d.ts +1 -1
- package/dist/src/private-to-public/utils/connect.d.ts.map +1 -1
- package/dist/src/private-to-public/utils/connect.js +14 -17
- package/dist/src/private-to-public/utils/connect.js.map +1 -1
- package/dist/src/private-to-public/utils/get-rtcpeerconnection.d.ts +4 -4
- package/dist/src/private-to-public/utils/get-rtcpeerconnection.d.ts.map +1 -1
- package/dist/src/private-to-public/utils/get-rtcpeerconnection.js +2 -13
- package/dist/src/private-to-public/utils/get-rtcpeerconnection.js.map +1 -1
- package/dist/src/private-to-public/utils/sdp.d.ts.map +1 -1
- package/dist/src/private-to-public/utils/sdp.js +3 -8
- package/dist/src/private-to-public/utils/sdp.js.map +1 -1
- package/dist/src/private-to-public/utils/stun-listener.js +1 -1
- package/dist/src/private-to-public/utils/stun-listener.js.map +1 -1
- package/dist/src/stream.d.ts +26 -13
- package/dist/src/stream.d.ts.map +1 -1
- package/dist/src/stream.js +166 -64
- package/dist/src/stream.js.map +1 -1
- package/dist/src/util.d.ts +1 -3
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +0 -19
- package/dist/src/util.js.map +1 -1
- package/dist/src/webrtc/index.d.ts +1 -1
- package/dist/src/webrtc/index.d.ts.map +1 -1
- package/dist/src/webrtc/index.js +1 -1
- package/dist/src/webrtc/index.js.map +1 -1
- package/package.json +29 -26
- package/src/constants.ts +18 -0
- package/src/index.ts +22 -12
- package/src/maconn.ts +101 -0
- package/src/muxer.ts +166 -43
- package/src/private-to-private/initiate-connection.ts +9 -31
- package/src/private-to-private/signaling-stream-handler.ts +9 -12
- package/src/private-to-private/transport.ts +17 -33
- package/src/private-to-private/util.ts +4 -21
- package/src/private-to-public/listener.ts +2 -2
- package/src/private-to-public/transport.ts +1 -1
- package/src/private-to-public/utils/connect.ts +15 -18
- package/src/private-to-public/utils/get-rtcpeerconnection.ts +4 -16
- package/src/private-to-public/utils/sdp.ts +3 -8
- package/src/private-to-public/utils/stun-listener.ts +1 -1
- package/src/stream.ts +194 -74
- package/src/util.ts +1 -22
- package/src/webrtc/index.ts +1 -1
- package/dist/src/rtcpeerconnection-to-conn.d.ts +0 -12
- package/dist/src/rtcpeerconnection-to-conn.d.ts.map +0 -1
- package/dist/src/rtcpeerconnection-to-conn.js +0 -43
- package/dist/src/rtcpeerconnection-to-conn.js.map +0 -1
- package/src/rtcpeerconnection-to-conn.ts +0 -62
package/src/stream.ts
CHANGED
@@ -1,15 +1,20 @@
|
|
1
|
-
import { StreamStateError } from '@libp2p/interface'
|
2
|
-
import { AbstractStream } from '@libp2p/utils'
|
1
|
+
import { StreamStateError, TimeoutError } from '@libp2p/interface'
|
2
|
+
import { AbstractStream } from '@libp2p/utils/abstract-stream'
|
3
|
+
import { anySignal } from 'any-signal'
|
3
4
|
import * as lengthPrefixed from 'it-length-prefixed'
|
4
5
|
import { pushable } from 'it-pushable'
|
6
|
+
import pDefer from 'p-defer'
|
7
|
+
import pTimeout from 'p-timeout'
|
8
|
+
import { raceEvent } from 'race-event'
|
5
9
|
import { raceSignal } from 'race-signal'
|
6
10
|
import { Uint8ArrayList } from 'uint8arraylist'
|
7
|
-
import { MAX_BUFFERED_AMOUNT, MAX_MESSAGE_SIZE, PROTOBUF_OVERHEAD } from './constants.js'
|
11
|
+
import { BUFFERED_AMOUNT_LOW_TIMEOUT, FIN_ACK_TIMEOUT, MAX_BUFFERED_AMOUNT, MAX_MESSAGE_SIZE, OPEN_TIMEOUT, PROTOBUF_OVERHEAD } from './constants.js'
|
8
12
|
import { Message } from './private-to-public/pb/message.js'
|
9
13
|
import type { DataChannelOptions } from './index.js'
|
10
|
-
import type { AbortOptions,
|
11
|
-
import type { AbstractStreamInit
|
14
|
+
import type { AbortOptions, Direction, Logger } from '@libp2p/interface'
|
15
|
+
import type { AbstractStreamInit } from '@libp2p/utils/abstract-stream'
|
12
16
|
import type { Pushable } from 'it-pushable'
|
17
|
+
import type { DeferredPromise } from 'p-defer'
|
13
18
|
|
14
19
|
export interface WebRTCStreamInit extends AbstractStreamInit, DataChannelOptions {
|
15
20
|
/**
|
@@ -34,24 +39,76 @@ export class WebRTCStream extends AbstractStream {
|
|
34
39
|
* and then the protobuf decoder.
|
35
40
|
*/
|
36
41
|
private readonly incomingData: Pushable<Uint8Array>
|
42
|
+
|
37
43
|
private readonly maxBufferedAmount: number
|
38
|
-
|
44
|
+
|
45
|
+
private readonly bufferedAmountLowEventTimeout: number
|
46
|
+
|
47
|
+
/**
|
48
|
+
* The maximum size of a message in bytes
|
49
|
+
*/
|
50
|
+
private readonly maxMessageSize: number
|
51
|
+
|
52
|
+
/**
|
53
|
+
* When this promise is resolved, the remote has sent us a FIN flag
|
54
|
+
*/
|
55
|
+
private readonly receiveFinAck: DeferredPromise<void>
|
56
|
+
private readonly finAckTimeout: number
|
57
|
+
private readonly openTimeout: number
|
58
|
+
private readonly closeController: AbortController
|
39
59
|
|
40
60
|
constructor (init: WebRTCStreamInit) {
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
61
|
+
// override onEnd to send/receive FIN_ACK before closing the stream
|
62
|
+
const originalOnEnd = init.onEnd
|
63
|
+
init.onEnd = (err?: Error): void => {
|
64
|
+
this.log.trace('readable and writeable ends closed with status "%s"', this.status)
|
65
|
+
|
66
|
+
void Promise.resolve(async () => {
|
67
|
+
if (this.timeline.abort != null || this.timeline.reset !== null) {
|
68
|
+
return
|
69
|
+
}
|
70
|
+
|
71
|
+
// wait for FIN_ACK if we haven't received it already
|
72
|
+
try {
|
73
|
+
await pTimeout(this.receiveFinAck.promise, {
|
74
|
+
milliseconds: this.finAckTimeout
|
75
|
+
})
|
76
|
+
} catch (err) {
|
77
|
+
this.log.error('error receiving FIN_ACK', err)
|
78
|
+
}
|
79
|
+
})
|
80
|
+
.then(() => {
|
81
|
+
// stop processing incoming messages
|
82
|
+
this.incomingData.end()
|
83
|
+
|
84
|
+
// final cleanup
|
85
|
+
originalOnEnd?.(err)
|
86
|
+
})
|
87
|
+
.catch(err => {
|
88
|
+
this.log.error('error ending stream', err)
|
89
|
+
})
|
90
|
+
.finally(() => {
|
91
|
+
this.channel.close()
|
92
|
+
})
|
93
|
+
}
|
94
|
+
|
95
|
+
super(init)
|
45
96
|
|
46
97
|
this.channel = init.channel
|
47
98
|
this.channel.binaryType = 'arraybuffer'
|
48
99
|
this.incomingData = pushable<Uint8Array>()
|
100
|
+
this.bufferedAmountLowEventTimeout = init.bufferedAmountLowEventTimeout ?? BUFFERED_AMOUNT_LOW_TIMEOUT
|
49
101
|
this.maxBufferedAmount = init.maxBufferedAmount ?? MAX_BUFFERED_AMOUNT
|
50
|
-
this.
|
102
|
+
this.maxMessageSize = (init.maxMessageSize ?? MAX_MESSAGE_SIZE) - PROTOBUF_OVERHEAD
|
103
|
+
this.receiveFinAck = pDefer()
|
104
|
+
this.finAckTimeout = init.closeTimeout ?? FIN_ACK_TIMEOUT
|
105
|
+
this.openTimeout = init.openTimeout ?? OPEN_TIMEOUT
|
106
|
+
this.closeController = new AbortController()
|
51
107
|
|
52
108
|
// set up initial state
|
53
109
|
switch (this.channel.readyState) {
|
54
110
|
case 'open':
|
111
|
+
this.timeline.open = new Date().getTime()
|
55
112
|
break
|
56
113
|
|
57
114
|
case 'closed':
|
@@ -70,16 +127,31 @@ export class WebRTCStream extends AbstractStream {
|
|
70
127
|
}
|
71
128
|
|
72
129
|
// handle RTCDataChannel events
|
130
|
+
this.channel.onopen = (_evt) => {
|
131
|
+
this.timeline.open = new Date().getTime()
|
132
|
+
}
|
133
|
+
|
73
134
|
this.channel.onclose = (_evt) => {
|
74
135
|
this.log.trace('received onclose event')
|
75
136
|
|
76
|
-
|
77
|
-
this.
|
137
|
+
// stop any in-progress writes
|
138
|
+
this.closeController.abort()
|
139
|
+
|
140
|
+
// if the channel has closed we'll never receive a FIN_ACK so resolve the
|
141
|
+
// promise so we don't try to wait later
|
142
|
+
this.receiveFinAck.resolve()
|
143
|
+
|
144
|
+
void this.close().catch(err => {
|
145
|
+
this.log.error('error closing stream after channel closed', err)
|
146
|
+
})
|
78
147
|
}
|
79
148
|
|
80
149
|
this.channel.onerror = (evt) => {
|
81
150
|
this.log.trace('received onerror event')
|
82
151
|
|
152
|
+
// stop any in-progress writes
|
153
|
+
this.closeController.abort()
|
154
|
+
|
83
155
|
const err = (evt as RTCErrorEvent).error
|
84
156
|
this.abort(err)
|
85
157
|
}
|
@@ -94,12 +166,6 @@ export class WebRTCStream extends AbstractStream {
|
|
94
166
|
this.incomingData.push(new Uint8Array(data, 0, data.byteLength))
|
95
167
|
}
|
96
168
|
|
97
|
-
// dispatch drain event when the buffered amount drops to zero
|
98
|
-
this.channel.bufferedAmountLowThreshold = 0
|
99
|
-
this.channel.onbufferedamountlow = () => {
|
100
|
-
this.safeDispatchEvent('drain')
|
101
|
-
}
|
102
|
-
|
103
169
|
const self = this
|
104
170
|
|
105
171
|
// pipe framed protobuf messages through a length prefixed decoder, and
|
@@ -109,59 +175,94 @@ export class WebRTCStream extends AbstractStream {
|
|
109
175
|
const message = self.processIncomingProtobuf(buf)
|
110
176
|
|
111
177
|
if (message != null) {
|
112
|
-
self.
|
178
|
+
self.sourcePush(new Uint8ArrayList(message))
|
113
179
|
}
|
114
180
|
}
|
115
181
|
})
|
116
182
|
.catch(err => {
|
117
183
|
this.log.error('error processing incoming data channel messages', err)
|
118
184
|
})
|
119
|
-
|
120
|
-
// clean up the datachannel when both ends have sent a FIN
|
121
|
-
const webRTCStreamOnClose = (): void => {
|
122
|
-
this.channel.close()
|
123
|
-
}
|
124
|
-
this.addEventListener('close', webRTCStreamOnClose)
|
125
185
|
}
|
126
186
|
|
127
187
|
sendNewStream (): void {
|
128
188
|
// opening new streams is handled by WebRTC so this is a noop
|
129
189
|
}
|
130
190
|
|
131
|
-
_sendMessage (data: Uint8ArrayList): void {
|
191
|
+
async _sendMessage (data: Uint8ArrayList, checkBuffer: boolean = true): Promise<void> {
|
132
192
|
if (this.channel.readyState === 'closed' || this.channel.readyState === 'closing') {
|
133
193
|
throw new StreamStateError(`Invalid datachannel state - ${this.channel.readyState}`)
|
134
194
|
}
|
135
195
|
|
196
|
+
if (this.channel.readyState !== 'open') {
|
197
|
+
const timeout = AbortSignal.timeout(this.openTimeout)
|
198
|
+
const signal = anySignal([
|
199
|
+
this.closeController.signal,
|
200
|
+
timeout
|
201
|
+
])
|
202
|
+
|
203
|
+
try {
|
204
|
+
this.log('channel state is "%s" and not "open", waiting for "open" event before sending data', this.channel.readyState)
|
205
|
+
await raceEvent(this.channel, 'open', signal)
|
206
|
+
} finally {
|
207
|
+
signal.clear()
|
208
|
+
}
|
209
|
+
|
210
|
+
this.log('channel state is now "%s", sending data', this.channel.readyState)
|
211
|
+
}
|
212
|
+
|
213
|
+
if (checkBuffer && this.channel.bufferedAmount > this.maxBufferedAmount) {
|
214
|
+
const timeout = AbortSignal.timeout(this.bufferedAmountLowEventTimeout)
|
215
|
+
const signal = anySignal([
|
216
|
+
this.closeController.signal,
|
217
|
+
timeout
|
218
|
+
])
|
219
|
+
|
220
|
+
try {
|
221
|
+
this.log('channel buffer is %d, wait for "bufferedamountlow" event', this.channel.bufferedAmount)
|
222
|
+
await raceEvent(this.channel, 'bufferedamountlow', signal)
|
223
|
+
} catch (err: any) {
|
224
|
+
if (timeout.aborted) {
|
225
|
+
throw new TimeoutError(`Timed out waiting for DataChannel buffer to clear after ${this.bufferedAmountLowEventTimeout}ms`)
|
226
|
+
}
|
227
|
+
|
228
|
+
throw err
|
229
|
+
} finally {
|
230
|
+
signal.clear()
|
231
|
+
}
|
232
|
+
}
|
233
|
+
|
136
234
|
try {
|
137
235
|
this.log.trace('sending message, channel state "%s"', this.channel.readyState)
|
138
236
|
// send message without copying data
|
139
|
-
|
140
|
-
this.channel.send(buf)
|
141
|
-
}
|
237
|
+
this.channel.send(data.subarray())
|
142
238
|
} catch (err: any) {
|
143
239
|
this.log.error('error while sending message', err)
|
144
240
|
}
|
145
241
|
}
|
146
242
|
|
147
|
-
sendData (data: Uint8ArrayList):
|
148
|
-
const
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
243
|
+
async sendData (data: Uint8ArrayList): Promise<void> {
|
244
|
+
const bytesTotal = data.byteLength
|
245
|
+
// sending messages is an async operation so use a copy of the list as it
|
246
|
+
// may be changed beneath us
|
247
|
+
data = data.sublist()
|
248
|
+
|
249
|
+
while (data.byteLength > 0) {
|
250
|
+
const toSend = Math.min(data.byteLength, this.maxMessageSize)
|
251
|
+
const buf = data.subarray(0, toSend)
|
252
|
+
const messageBuf = Message.encode({ message: buf })
|
253
|
+
const sendBuf = lengthPrefixed.encode.single(messageBuf)
|
254
|
+
this.log.trace('sending %d/%d bytes on channel', buf.byteLength, bytesTotal)
|
255
|
+
await this._sendMessage(sendBuf)
|
256
|
+
|
257
|
+
data.consume(toSend)
|
157
258
|
}
|
158
|
-
}
|
159
259
|
|
160
|
-
|
161
|
-
|
260
|
+
this.log.trace('finished sending data, channel state "%s"', this.channel.readyState)
|
261
|
+
}
|
162
262
|
|
263
|
+
async sendReset (): Promise<void> {
|
163
264
|
try {
|
164
|
-
this._sendFlag(Message.Flag.RESET)
|
265
|
+
await this._sendFlag(Message.Flag.RESET)
|
165
266
|
} catch (err) {
|
166
267
|
this.log.error('failed to send reset - %e', err)
|
167
268
|
} finally {
|
@@ -169,20 +270,38 @@ export class WebRTCStream extends AbstractStream {
|
|
169
270
|
}
|
170
271
|
}
|
171
272
|
|
172
|
-
async sendCloseWrite (options
|
173
|
-
if (this.channel.readyState
|
174
|
-
this.
|
273
|
+
async sendCloseWrite (options: AbortOptions): Promise<void> {
|
274
|
+
if (this.channel.readyState !== 'open') {
|
275
|
+
this.receiveFinAck.resolve()
|
276
|
+
return
|
277
|
+
}
|
278
|
+
|
279
|
+
const sent = await this._sendFlag(Message.Flag.FIN)
|
280
|
+
|
281
|
+
if (sent) {
|
282
|
+
this.log.trace('awaiting FIN_ACK')
|
283
|
+
try {
|
284
|
+
await raceSignal(this.receiveFinAck.promise, options?.signal, {
|
285
|
+
errorMessage: 'sending close-write was aborted before FIN_ACK was received',
|
286
|
+
errorName: 'FinAckNotReceivedError'
|
287
|
+
})
|
288
|
+
} catch (err) {
|
289
|
+
this.log.error('failed to await FIN_ACK', err)
|
290
|
+
}
|
291
|
+
} else {
|
292
|
+
this.log.trace('sending FIN failed, not awaiting FIN_ACK')
|
175
293
|
}
|
176
294
|
|
177
|
-
|
295
|
+
// if we've attempted to receive a FIN_ACK, do not try again
|
296
|
+
this.receiveFinAck.resolve()
|
178
297
|
}
|
179
298
|
|
180
|
-
async sendCloseRead (
|
181
|
-
if (this.channel.readyState
|
182
|
-
|
299
|
+
async sendCloseRead (): Promise<void> {
|
300
|
+
if (this.channel.readyState !== 'open') {
|
301
|
+
return
|
183
302
|
}
|
184
303
|
|
185
|
-
|
304
|
+
await this._sendFlag(Message.Flag.STOP_SENDING)
|
186
305
|
}
|
187
306
|
|
188
307
|
/**
|
@@ -196,33 +315,38 @@ export class WebRTCStream extends AbstractStream {
|
|
196
315
|
|
197
316
|
if (message.flag === Message.Flag.FIN) {
|
198
317
|
// We should expect no more data from the remote, stop reading
|
199
|
-
this.
|
200
|
-
|
318
|
+
this.remoteCloseWrite()
|
319
|
+
|
320
|
+
this.log.trace('sending FIN_ACK')
|
321
|
+
void this._sendFlag(Message.Flag.FIN_ACK)
|
322
|
+
.catch(err => {
|
323
|
+
this.log.error('error sending FIN_ACK immediately', err)
|
324
|
+
})
|
201
325
|
}
|
202
326
|
|
203
327
|
if (message.flag === Message.Flag.RESET) {
|
204
|
-
this.receivedFinAck.resolve()
|
205
328
|
// Stop reading and writing to the stream immediately
|
206
|
-
this.
|
329
|
+
this.reset()
|
207
330
|
}
|
208
331
|
|
209
332
|
if (message.flag === Message.Flag.STOP_SENDING) {
|
210
333
|
// The remote has stopped reading
|
211
|
-
this.
|
334
|
+
this.remoteCloseRead()
|
212
335
|
}
|
213
336
|
|
214
337
|
if (message.flag === Message.Flag.FIN_ACK) {
|
215
|
-
this.
|
338
|
+
this.log.trace('received FIN_ACK')
|
339
|
+
this.receiveFinAck.resolve()
|
216
340
|
}
|
217
341
|
}
|
218
342
|
|
219
343
|
// ignore data messages if we've closed the readable end already
|
220
|
-
if (this.readStatus === '
|
344
|
+
if (this.readStatus === 'ready') {
|
221
345
|
return message.message
|
222
346
|
}
|
223
347
|
}
|
224
348
|
|
225
|
-
private _sendFlag (flag: Message.Flag): boolean {
|
349
|
+
private async _sendFlag (flag: Message.Flag): Promise<boolean> {
|
226
350
|
if (this.channel.readyState !== 'open') {
|
227
351
|
// flags can be sent while we or the remote are closing the datachannel so
|
228
352
|
// if the channel isn't open, don't try to send it but return false to let
|
@@ -236,7 +360,7 @@ export class WebRTCStream extends AbstractStream {
|
|
236
360
|
const prefixedBuf = lengthPrefixed.encode.single(messageBuf)
|
237
361
|
|
238
362
|
try {
|
239
|
-
this._sendMessage(prefixedBuf)
|
363
|
+
await this._sendMessage(prefixedBuf, false)
|
240
364
|
|
241
365
|
return true
|
242
366
|
} catch (err: any) {
|
@@ -245,14 +369,6 @@ export class WebRTCStream extends AbstractStream {
|
|
245
369
|
|
246
370
|
return false
|
247
371
|
}
|
248
|
-
|
249
|
-
sendPause (): void {
|
250
|
-
// TODO: read backpressure?
|
251
|
-
}
|
252
|
-
|
253
|
-
sendResume (): void {
|
254
|
-
// TODO: read backpressure?
|
255
|
-
}
|
256
372
|
}
|
257
373
|
|
258
374
|
export interface WebRTCStreamOptions extends DataChannelOptions {
|
@@ -267,7 +383,12 @@ export interface WebRTCStreamOptions extends DataChannelOptions {
|
|
267
383
|
/**
|
268
384
|
* The stream direction
|
269
385
|
*/
|
270
|
-
direction:
|
386
|
+
direction: Direction
|
387
|
+
|
388
|
+
/**
|
389
|
+
* A callback invoked when the channel ends
|
390
|
+
*/
|
391
|
+
onEnd?(err?: Error | undefined): void
|
271
392
|
|
272
393
|
/**
|
273
394
|
* The logger to create a scope from
|
@@ -278,16 +399,15 @@ export interface WebRTCStreamOptions extends DataChannelOptions {
|
|
278
399
|
* If true the underlying datachannel is being used to perform the noise
|
279
400
|
* handshake during connection establishment
|
280
401
|
*/
|
281
|
-
|
402
|
+
handshake?: boolean
|
282
403
|
}
|
283
404
|
|
284
405
|
export function createStream (options: WebRTCStreamOptions): WebRTCStream {
|
285
|
-
const { channel, direction,
|
406
|
+
const { channel, direction, handshake } = options
|
286
407
|
|
287
408
|
return new WebRTCStream({
|
288
409
|
...options,
|
289
410
|
id: `${channel.id}`,
|
290
|
-
log: options.log.newScope(`${
|
291
|
-
protocol: ''
|
411
|
+
log: options.log.newScope(`${handshake === true ? 'handshake' : direction}:${channel.id}`)
|
292
412
|
})
|
293
413
|
}
|
package/src/util.ts
CHANGED
@@ -2,9 +2,8 @@ import { detect } from 'detect-browser'
|
|
2
2
|
import pDefer from 'p-defer'
|
3
3
|
import pTimeout from 'p-timeout'
|
4
4
|
import { DATA_CHANNEL_DRAIN_TIMEOUT, DEFAULT_ICE_SERVERS, UFRAG_ALPHABET, UFRAG_PREFIX } from './constants.js'
|
5
|
+
import type { PeerConnection } from '@ipshipyard/node-datachannel'
|
5
6
|
import type { LoggerOptions } from '@libp2p/interface'
|
6
|
-
import type { Duplex, Source } from 'it-stream-types'
|
7
|
-
import type { PeerConnection } from 'node-datachannel'
|
8
7
|
|
9
8
|
const browser = detect()
|
10
9
|
export const isFirefox = ((browser != null) && browser.name === 'firefox')
|
@@ -13,26 +12,6 @@ export const nopSource = async function * nop (): AsyncGenerator<Uint8Array, any
|
|
13
12
|
|
14
13
|
export const nopSink = async (_: any): Promise<void> => {}
|
15
14
|
|
16
|
-
// Duplex that does nothing. Needed to fulfill the interface
|
17
|
-
export function inertDuplex (): Duplex<any, any, any> {
|
18
|
-
return {
|
19
|
-
source: {
|
20
|
-
[Symbol.asyncIterator] () {
|
21
|
-
return {
|
22
|
-
async next () {
|
23
|
-
// This will never resolve
|
24
|
-
return new Promise(() => { })
|
25
|
-
}
|
26
|
-
}
|
27
|
-
}
|
28
|
-
},
|
29
|
-
sink: async (source: Source<any>) => {
|
30
|
-
// This will never resolve
|
31
|
-
return new Promise(() => { })
|
32
|
-
}
|
33
|
-
}
|
34
|
-
}
|
35
|
-
|
36
15
|
export function drainAndClose (channel: RTCDataChannel, direction: string, drainTimeout: number = DATA_CHANNEL_DRAIN_TIMEOUT, options: LoggerOptions): void {
|
37
16
|
if (channel.readyState !== 'open') {
|
38
17
|
return
|
package/src/webrtc/index.ts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
export { RTCSessionDescription, RTCIceCandidate, RTCPeerConnection } from 'node-datachannel/polyfill'
|
1
|
+
export { RTCSessionDescription, RTCIceCandidate, RTCPeerConnection } from '@ipshipyard/node-datachannel/polyfill'
|
@@ -1,12 +0,0 @@
|
|
1
|
-
import type { RTCPeerConnection } from './webrtc/index.js';
|
2
|
-
import type { MultiaddrConnection } from '@libp2p/interface';
|
3
|
-
import type { AbstractMultiaddrConnectionInit } from '@libp2p/utils';
|
4
|
-
export interface RTCPeerConnectionMultiaddrConnectionInit extends Omit<AbstractMultiaddrConnectionInit, 'stream'> {
|
5
|
-
peerConnection: RTCPeerConnection;
|
6
|
-
}
|
7
|
-
/**
|
8
|
-
* Convert a RTCPeerConnection into a MultiaddrConnection
|
9
|
-
* https://github.com/libp2p/interface-transport#multiaddrconnection
|
10
|
-
*/
|
11
|
-
export declare const toMultiaddrConnection: (init: RTCPeerConnectionMultiaddrConnectionInit) => MultiaddrConnection;
|
12
|
-
//# sourceMappingURL=rtcpeerconnection-to-conn.d.ts.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"rtcpeerconnection-to-conn.d.ts","sourceRoot":"","sources":["../../src/rtcpeerconnection-to-conn.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,KAAK,EAAgB,mBAAmB,EAAE,MAAM,mBAAmB,CAAA;AAC1E,OAAO,KAAK,EAAE,+BAA+B,EAAc,MAAM,eAAe,CAAA;AAGhF,MAAM,WAAW,wCAAyC,SAAQ,IAAI,CAAC,+BAA+B,EAAE,QAAQ,CAAC;IAC/G,cAAc,EAAE,iBAAiB,CAAA;CAClC;AA+CD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,MAAM,wCAAwC,KAAG,mBAEtF,CAAA"}
|
@@ -1,43 +0,0 @@
|
|
1
|
-
import { AbstractMultiaddrConnection } from '@libp2p/utils';
|
2
|
-
class RTCPeerConnectionMultiaddrConnection extends AbstractMultiaddrConnection {
|
3
|
-
peerConnection;
|
4
|
-
constructor(init) {
|
5
|
-
super(init);
|
6
|
-
this.peerConnection = init.peerConnection;
|
7
|
-
const initialState = init.peerConnection.connectionState;
|
8
|
-
this.peerConnection.onconnectionstatechange = () => {
|
9
|
-
this.log.trace('peer connection state change %s initial state %s', this.peerConnection.connectionState, initialState);
|
10
|
-
if (this.peerConnection.connectionState === 'disconnected' || this.peerConnection.connectionState === 'failed' || this.peerConnection.connectionState === 'closed') {
|
11
|
-
// nothing else to do but close the connection
|
12
|
-
this.onTransportClosed();
|
13
|
-
}
|
14
|
-
};
|
15
|
-
}
|
16
|
-
sendData(data) {
|
17
|
-
return {
|
18
|
-
sentBytes: data.byteLength,
|
19
|
-
canSendMore: true
|
20
|
-
};
|
21
|
-
}
|
22
|
-
async sendClose(options) {
|
23
|
-
this.peerConnection.close();
|
24
|
-
options?.signal?.throwIfAborted();
|
25
|
-
}
|
26
|
-
sendReset() {
|
27
|
-
this.peerConnection.close();
|
28
|
-
}
|
29
|
-
sendPause() {
|
30
|
-
// TODO: readable backpressure?
|
31
|
-
}
|
32
|
-
sendResume() {
|
33
|
-
// TODO: readable backpressure?
|
34
|
-
}
|
35
|
-
}
|
36
|
-
/**
|
37
|
-
* Convert a RTCPeerConnection into a MultiaddrConnection
|
38
|
-
* https://github.com/libp2p/interface-transport#multiaddrconnection
|
39
|
-
*/
|
40
|
-
export const toMultiaddrConnection = (init) => {
|
41
|
-
return new RTCPeerConnectionMultiaddrConnection(init);
|
42
|
-
};
|
43
|
-
//# sourceMappingURL=rtcpeerconnection-to-conn.js.map
|
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"rtcpeerconnection-to-conn.js","sourceRoot":"","sources":["../../src/rtcpeerconnection-to-conn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAA;AAU3D,MAAM,oCAAqC,SAAQ,2BAA2B;IACpE,cAAc,CAAmB;IAEzC,YAAa,IAA8C;QACzD,KAAK,CAAC,IAAI,CAAC,CAAA;QAEX,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAA;QAEzC,MAAM,YAAY,GAAG,IAAI,CAAC,cAAc,CAAC,eAAe,CAAA;QAExD,IAAI,CAAC,cAAc,CAAC,uBAAuB,GAAG,GAAG,EAAE;YACjD,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,kDAAkD,EAAE,IAAI,CAAC,cAAc,CAAC,eAAe,EAAE,YAAY,CAAC,CAAA;YAErH,IAAI,IAAI,CAAC,cAAc,CAAC,eAAe,KAAK,cAAc,IAAI,IAAI,CAAC,cAAc,CAAC,eAAe,KAAK,QAAQ,IAAI,IAAI,CAAC,cAAc,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;gBACnK,8CAA8C;gBAC9C,IAAI,CAAC,iBAAiB,EAAE,CAAA;YAC1B,CAAC;QACH,CAAC,CAAA;IACH,CAAC;IAED,QAAQ,CAAE,IAAoB;QAC5B,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,UAAU;YAC1B,WAAW,EAAE,IAAI;SAClB,CAAA;IACH,CAAC;IAED,KAAK,CAAC,SAAS,CAAE,OAAsB;QACrC,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;QAC3B,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,CAAA;IACnC,CAAC;IAED,SAAS;QACP,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAA;IAC7B,CAAC;IAED,SAAS;QACP,+BAA+B;IACjC,CAAC;IAED,UAAU;QACR,+BAA+B;IACjC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,IAA8C,EAAuB,EAAE;IAC3G,OAAO,IAAI,oCAAoC,CAAC,IAAI,CAAC,CAAA;AACvD,CAAC,CAAA"}
|
@@ -1,62 +0,0 @@
|
|
1
|
-
import { AbstractMultiaddrConnection } from '@libp2p/utils'
|
2
|
-
import type { RTCPeerConnection } from './webrtc/index.js'
|
3
|
-
import type { AbortOptions, MultiaddrConnection } from '@libp2p/interface'
|
4
|
-
import type { AbstractMultiaddrConnectionInit, SendResult } from '@libp2p/utils'
|
5
|
-
import type { Uint8ArrayList } from 'uint8arraylist'
|
6
|
-
|
7
|
-
export interface RTCPeerConnectionMultiaddrConnectionInit extends Omit<AbstractMultiaddrConnectionInit, 'stream'> {
|
8
|
-
peerConnection: RTCPeerConnection
|
9
|
-
}
|
10
|
-
|
11
|
-
class RTCPeerConnectionMultiaddrConnection extends AbstractMultiaddrConnection {
|
12
|
-
private peerConnection: RTCPeerConnection
|
13
|
-
|
14
|
-
constructor (init: RTCPeerConnectionMultiaddrConnectionInit) {
|
15
|
-
super(init)
|
16
|
-
|
17
|
-
this.peerConnection = init.peerConnection
|
18
|
-
|
19
|
-
const initialState = init.peerConnection.connectionState
|
20
|
-
|
21
|
-
this.peerConnection.onconnectionstatechange = () => {
|
22
|
-
this.log.trace('peer connection state change %s initial state %s', this.peerConnection.connectionState, initialState)
|
23
|
-
|
24
|
-
if (this.peerConnection.connectionState === 'disconnected' || this.peerConnection.connectionState === 'failed' || this.peerConnection.connectionState === 'closed') {
|
25
|
-
// nothing else to do but close the connection
|
26
|
-
this.onTransportClosed()
|
27
|
-
}
|
28
|
-
}
|
29
|
-
}
|
30
|
-
|
31
|
-
sendData (data: Uint8ArrayList): SendResult {
|
32
|
-
return {
|
33
|
-
sentBytes: data.byteLength,
|
34
|
-
canSendMore: true
|
35
|
-
}
|
36
|
-
}
|
37
|
-
|
38
|
-
async sendClose (options?: AbortOptions): Promise<void> {
|
39
|
-
this.peerConnection.close()
|
40
|
-
options?.signal?.throwIfAborted()
|
41
|
-
}
|
42
|
-
|
43
|
-
sendReset (): void {
|
44
|
-
this.peerConnection.close()
|
45
|
-
}
|
46
|
-
|
47
|
-
sendPause (): void {
|
48
|
-
// TODO: readable backpressure?
|
49
|
-
}
|
50
|
-
|
51
|
-
sendResume (): void {
|
52
|
-
// TODO: readable backpressure?
|
53
|
-
}
|
54
|
-
}
|
55
|
-
|
56
|
-
/**
|
57
|
-
* Convert a RTCPeerConnection into a MultiaddrConnection
|
58
|
-
* https://github.com/libp2p/interface-transport#multiaddrconnection
|
59
|
-
*/
|
60
|
-
export const toMultiaddrConnection = (init: RTCPeerConnectionMultiaddrConnectionInit): MultiaddrConnection => {
|
61
|
-
return new RTCPeerConnectionMultiaddrConnection(init)
|
62
|
-
}
|