@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/src/stream.ts
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
|
import type { DataChannelOptions } from './index.js'
|
12
10
|
import type { AbortOptions, MessageStreamDirection, Logger } from '@libp2p/interface'
|
13
11
|
import type { AbstractStreamInit, SendResult } from '@libp2p/utils'
|
@@ -37,8 +35,7 @@ export class WebRTCStream extends AbstractStream {
|
|
37
35
|
*/
|
38
36
|
private readonly incomingData: Pushable<Uint8Array>
|
39
37
|
private readonly maxBufferedAmount: number
|
40
|
-
private receivedFinAck
|
41
|
-
private finAckTimeout: number
|
38
|
+
private readonly receivedFinAck: PromiseWithResolvers<void>
|
42
39
|
|
43
40
|
constructor (init: WebRTCStreamInit) {
|
44
41
|
super({
|
@@ -50,26 +47,44 @@ export class WebRTCStream extends AbstractStream {
|
|
50
47
|
this.channel.binaryType = 'arraybuffer'
|
51
48
|
this.incomingData = pushable<Uint8Array>()
|
52
49
|
this.maxBufferedAmount = init.maxBufferedAmount ?? MAX_BUFFERED_AMOUNT
|
53
|
-
this.
|
50
|
+
this.receivedFinAck = Promise.withResolvers()
|
51
|
+
|
52
|
+
// set up initial state
|
53
|
+
switch (this.channel.readyState) {
|
54
|
+
case 'open':
|
55
|
+
break
|
56
|
+
|
57
|
+
case 'closed':
|
58
|
+
case 'closing':
|
59
|
+
if (this.timeline.close === undefined || this.timeline.close === 0) {
|
60
|
+
this.timeline.close = Date.now()
|
61
|
+
}
|
62
|
+
break
|
63
|
+
case 'connecting':
|
64
|
+
// noop
|
65
|
+
break
|
66
|
+
|
67
|
+
default:
|
68
|
+
this.log.error('unknown datachannel state %s', this.channel.readyState)
|
69
|
+
throw new StreamStateError('Unknown datachannel state')
|
70
|
+
}
|
54
71
|
|
55
72
|
// handle RTCDataChannel events
|
56
|
-
this.channel.onclose = () => {
|
57
|
-
this.log.trace('received
|
73
|
+
this.channel.onclose = (_evt) => {
|
74
|
+
this.log.trace('received onclose event')
|
58
75
|
|
59
76
|
this.onRemoteCloseWrite()
|
60
77
|
this.onTransportClosed()
|
61
78
|
}
|
62
79
|
|
63
80
|
this.channel.onerror = (evt) => {
|
64
|
-
|
65
|
-
|
66
|
-
this.log.trace('received datachannel error event - %e', err)
|
81
|
+
this.log.trace('received onerror event')
|
67
82
|
|
83
|
+
const err = (evt as RTCErrorEvent).error
|
68
84
|
this.abort(err)
|
69
85
|
}
|
70
86
|
|
71
87
|
this.channel.onmessage = async (event: MessageEvent<ArrayBuffer>) => {
|
72
|
-
this.log('incoming message %d bytes', event.data.byteLength)
|
73
88
|
const { data } = event
|
74
89
|
|
75
90
|
if (data === null || data.byteLength === 0) {
|
@@ -81,49 +96,32 @@ export class WebRTCStream extends AbstractStream {
|
|
81
96
|
|
82
97
|
// dispatch drain event when the buffered amount drops to zero
|
83
98
|
this.channel.bufferedAmountLowThreshold = 0
|
84
|
-
|
85
99
|
this.channel.onbufferedamountlow = () => {
|
86
|
-
|
87
|
-
this.safeDispatchEvent('drain')
|
88
|
-
}
|
100
|
+
this.safeDispatchEvent('drain')
|
89
101
|
}
|
90
102
|
|
91
|
-
|
92
|
-
this.log('channel ready state is "%s" and not "open", waiting for "open" event before sending data', this.channel.readyState)
|
93
|
-
pEvent(this.channel, 'open', {
|
94
|
-
rejectionEvents: [
|
95
|
-
'close',
|
96
|
-
'error'
|
97
|
-
]
|
98
|
-
})
|
99
|
-
.then(() => {
|
100
|
-
this.log('channel ready state is now "%s", dispatching drain', this.channel.readyState)
|
101
|
-
this.safeDispatchEvent('drain')
|
102
|
-
})
|
103
|
-
.catch(err => {
|
104
|
-
this.abort(err.error ?? err)
|
105
|
-
})
|
106
|
-
}
|
103
|
+
const self = this
|
107
104
|
|
108
105
|
// pipe framed protobuf messages through a length prefixed decoder, and
|
109
106
|
// surface data from the `Message.message` field through a source.
|
110
107
|
Promise.resolve().then(async () => {
|
111
108
|
for await (const buf of lengthPrefixed.decode(this.incomingData)) {
|
112
|
-
|
109
|
+
const message = self.processIncomingProtobuf(buf)
|
110
|
+
|
111
|
+
if (message != null) {
|
112
|
+
self.onData(new Uint8ArrayList(message))
|
113
|
+
}
|
113
114
|
}
|
114
115
|
})
|
115
116
|
.catch(err => {
|
116
117
|
this.log.error('error processing incoming data channel messages', err)
|
117
118
|
})
|
118
119
|
|
119
|
-
//
|
120
|
-
const
|
121
|
-
|
122
|
-
this.log.trace('stream closed, closing underlying datachannel')
|
123
|
-
this.channel.close()
|
124
|
-
}
|
120
|
+
// clean up the datachannel when both ends have sent a FIN
|
121
|
+
const webRTCStreamOnClose = (): void => {
|
122
|
+
this.channel.close()
|
125
123
|
}
|
126
|
-
this.addEventListener('close',
|
124
|
+
this.addEventListener('close', webRTCStreamOnClose)
|
127
125
|
}
|
128
126
|
|
129
127
|
sendNewStream (): void {
|
@@ -131,57 +129,27 @@ export class WebRTCStream extends AbstractStream {
|
|
131
129
|
}
|
132
130
|
|
133
131
|
_sendMessage (data: Uint8ArrayList): void {
|
134
|
-
if (this.channel.readyState
|
132
|
+
if (this.channel.readyState === 'closed' || this.channel.readyState === 'closing') {
|
135
133
|
throw new StreamStateError(`Invalid datachannel state - ${this.channel.readyState}`)
|
136
134
|
}
|
137
135
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
}
|
147
|
-
|
148
|
-
// send message without copying data
|
149
|
-
for (const buf of data) {
|
150
|
-
this.channel.send(buf)
|
136
|
+
try {
|
137
|
+
this.log.trace('sending message, channel state "%s"', this.channel.readyState)
|
138
|
+
// send message without copying data
|
139
|
+
for (const buf of data) {
|
140
|
+
this.channel.send(buf)
|
141
|
+
}
|
142
|
+
} catch (err: any) {
|
143
|
+
this.log.error('error while sending message', err)
|
151
144
|
}
|
152
145
|
}
|
153
146
|
|
154
147
|
sendData (data: Uint8ArrayList): SendResult {
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
}
|
161
|
-
|
162
|
-
// TODO: firefox can deliver small messages out of order - remove once a
|
163
|
-
// browser with https://bugzilla.mozilla.org/show_bug.cgi?id=1983831 is
|
164
|
-
// available in playwright-test
|
165
|
-
// ----
|
166
|
-
// this is also necessary to work with rust-libp2p 0.54 though 0.53 seems ok
|
167
|
-
this._sendMessage(
|
168
|
-
lengthPrefixed.encode.single(Message.encode({
|
169
|
-
message: data.subarray()
|
170
|
-
}))
|
171
|
-
)
|
172
|
-
|
173
|
-
/*
|
174
|
-
// TODO: enable this when FF and rust-libp2p are not broken
|
175
|
-
// send message without copying data
|
176
|
-
for (const message of data) {
|
177
|
-
this._sendMessage(
|
178
|
-
lengthPrefixed.encode.single(Message.encode({
|
179
|
-
message
|
180
|
-
}))
|
181
|
-
)
|
182
|
-
}
|
183
|
-
}
|
184
|
-
*/
|
148
|
+
const messageBuf = Message.encode({
|
149
|
+
message: data.subarray()
|
150
|
+
})
|
151
|
+
const prefixedBuf = lengthPrefixed.encode.single(messageBuf)
|
152
|
+
this._sendMessage(prefixedBuf)
|
185
153
|
|
186
154
|
return {
|
187
155
|
sentBytes: data.byteLength,
|
@@ -189,73 +157,69 @@ export class WebRTCStream extends AbstractStream {
|
|
189
157
|
}
|
190
158
|
}
|
191
159
|
|
192
|
-
sendReset (
|
160
|
+
sendReset (): void {
|
161
|
+
this.receivedFinAck.resolve()
|
162
|
+
|
193
163
|
try {
|
194
|
-
this.log.error('sending reset - %e', err)
|
195
164
|
this._sendFlag(Message.Flag.RESET)
|
196
|
-
this.receivedFinAck?.reject(err)
|
197
165
|
} catch (err) {
|
198
166
|
this.log.error('failed to send reset - %e', err)
|
167
|
+
} finally {
|
168
|
+
this.channel.close()
|
199
169
|
}
|
200
170
|
}
|
201
171
|
|
202
172
|
async sendCloseWrite (options?: AbortOptions): Promise<void> {
|
203
|
-
this.
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
await
|
208
|
-
raceSignal(this.receivedFinAck.promise, options?.signal),
|
209
|
-
new Promise<void>(resolve => {
|
210
|
-
AbortSignal.timeout(this.finAckTimeout)
|
211
|
-
.addEventListener('abort', () => {
|
212
|
-
resolve()
|
213
|
-
})
|
214
|
-
})
|
215
|
-
])
|
173
|
+
if (this.channel.readyState === 'open') {
|
174
|
+
this._sendFlag(Message.Flag.FIN)
|
175
|
+
}
|
176
|
+
|
177
|
+
await raceSignal(this.receivedFinAck.promise, options?.signal)
|
216
178
|
}
|
217
179
|
|
218
180
|
async sendCloseRead (options?: AbortOptions): Promise<void> {
|
219
|
-
this.
|
181
|
+
if (this.channel.readyState === 'open') {
|
182
|
+
this._sendFlag(Message.Flag.STOP_SENDING)
|
183
|
+
}
|
184
|
+
|
220
185
|
options?.signal?.throwIfAborted()
|
221
186
|
}
|
222
187
|
|
223
188
|
/**
|
224
189
|
* Handle incoming
|
225
190
|
*/
|
226
|
-
private processIncomingProtobuf (buffer: Uint8ArrayList):
|
191
|
+
private processIncomingProtobuf (buffer: Uint8ArrayList): Uint8Array | undefined {
|
227
192
|
const message = Message.decode(buffer)
|
228
193
|
|
229
|
-
// ignore data messages if we've closed the readable end already
|
230
|
-
if (message.message != null && (this.readStatus === 'readable' || this.readStatus === 'paused')) {
|
231
|
-
this.onData(new Uint8ArrayList(message.message))
|
232
|
-
}
|
233
|
-
|
234
194
|
if (message.flag !== undefined) {
|
235
195
|
this.log.trace('incoming flag %s, write status "%s", read status "%s"', message.flag, this.writeStatus, this.readStatus)
|
236
196
|
|
237
197
|
if (message.flag === Message.Flag.FIN) {
|
238
|
-
//
|
239
|
-
this._sendFlag(Message.Flag.FIN_ACK)
|
198
|
+
// We should expect no more data from the remote, stop reading
|
240
199
|
this.onRemoteCloseWrite()
|
200
|
+
this._sendFlag(Message.Flag.FIN_ACK)
|
241
201
|
}
|
242
202
|
|
243
203
|
if (message.flag === Message.Flag.RESET) {
|
244
|
-
|
245
|
-
|
204
|
+
this.receivedFinAck.resolve()
|
205
|
+
// Stop reading and writing to the stream immediately
|
246
206
|
this.onRemoteReset()
|
247
207
|
}
|
248
208
|
|
249
209
|
if (message.flag === Message.Flag.STOP_SENDING) {
|
250
|
-
//
|
210
|
+
// The remote has stopped reading
|
251
211
|
this.onRemoteCloseRead()
|
252
212
|
}
|
253
213
|
|
254
214
|
if (message.flag === Message.Flag.FIN_ACK) {
|
255
|
-
|
256
|
-
this.receivedFinAck?.resolve()
|
215
|
+
this.receivedFinAck.resolve()
|
257
216
|
}
|
258
217
|
}
|
218
|
+
|
219
|
+
// ignore data messages if we've closed the readable end already
|
220
|
+
if (this.readStatus === 'readable' || this.readStatus === 'paused') {
|
221
|
+
return message.message
|
222
|
+
}
|
259
223
|
}
|
260
224
|
|
261
225
|
private _sendFlag (flag: Message.Flag): boolean {
|