@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.
Files changed (46) hide show
  1. package/dist/index.min.js +13 -13
  2. package/dist/index.min.js.map +4 -4
  3. package/dist/src/constants.d.ts +0 -4
  4. package/dist/src/constants.d.ts.map +1 -1
  5. package/dist/src/constants.js +0 -4
  6. package/dist/src/constants.js.map +1 -1
  7. package/dist/src/index.d.ts +0 -8
  8. package/dist/src/index.d.ts.map +1 -1
  9. package/dist/src/index.js.map +1 -1
  10. package/dist/src/muxer.d.ts.map +1 -1
  11. package/dist/src/muxer.js +12 -7
  12. package/dist/src/muxer.js.map +1 -1
  13. package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
  14. package/dist/src/private-to-private/initiate-connection.js +1 -15
  15. package/dist/src/private-to-private/initiate-connection.js.map +1 -1
  16. package/dist/src/private-to-private/signaling-stream-handler.d.ts.map +1 -1
  17. package/dist/src/private-to-private/signaling-stream-handler.js +2 -10
  18. package/dist/src/private-to-private/signaling-stream-handler.js.map +1 -1
  19. package/dist/src/private-to-private/transport.d.ts +7 -0
  20. package/dist/src/private-to-private/transport.d.ts.map +1 -1
  21. package/dist/src/private-to-private/transport.js.map +1 -1
  22. package/dist/src/private-to-private/util.d.ts +1 -0
  23. package/dist/src/private-to-private/util.d.ts.map +1 -1
  24. package/dist/src/private-to-private/util.js +11 -11
  25. package/dist/src/private-to-private/util.js.map +1 -1
  26. package/dist/src/private-to-public/transport.d.ts +8 -0
  27. package/dist/src/private-to-public/transport.d.ts.map +1 -1
  28. package/dist/src/private-to-public/transport.js.map +1 -1
  29. package/dist/src/rtcpeerconnection-to-conn.d.ts.map +1 -1
  30. package/dist/src/rtcpeerconnection-to-conn.js +0 -3
  31. package/dist/src/rtcpeerconnection-to-conn.js.map +1 -1
  32. package/dist/src/stream.d.ts +2 -3
  33. package/dist/src/stream.d.ts.map +1 -1
  34. package/dist/src/stream.js +68 -100
  35. package/dist/src/stream.js.map +1 -1
  36. package/package.json +10 -10
  37. package/src/constants.ts +0 -5
  38. package/src/index.ts +0 -9
  39. package/src/muxer.ts +13 -6
  40. package/src/private-to-private/initiate-connection.ts +2 -18
  41. package/src/private-to-private/signaling-stream-handler.ts +2 -12
  42. package/src/private-to-private/transport.ts +8 -0
  43. package/src/private-to-private/util.ts +12 -12
  44. package/src/private-to-public/transport.ts +10 -0
  45. package/src/rtcpeerconnection-to-conn.ts +0 -4
  46. package/src/stream.ts +79 -115
package/src/stream.ts CHANGED
@@ -1,13 +1,11 @@
1
- import { StreamResetError, StreamStateError } from '@libp2p/interface'
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 { DEFAULT_FIN_ACK_TIMEOUT, MAX_BUFFERED_AMOUNT, MAX_MESSAGE_SIZE, PROTOBUF_OVERHEAD } from './constants.js'
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?: PromiseWithResolvers<void>
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.finAckTimeout = init.finAckTimeout ?? DEFAULT_FIN_ACK_TIMEOUT
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 datachannel close event')
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
- const err = (evt as RTCErrorEvent).error
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
- if (this.writableNeedsDrain) {
87
- this.safeDispatchEvent('drain')
88
- }
100
+ this.safeDispatchEvent('drain')
89
101
  }
90
102
 
91
- if (this.channel.readyState !== 'open') {
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
- this.processIncomingProtobuf(buf)
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
- // close when both writable ends are closed or an error occurs
120
- const cleanUpDatachannelOnClose = (): void => {
121
- if (this.channel.readyState === 'open') {
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', cleanUpDatachannelOnClose)
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 !== 'open') {
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
- this.log.trace('sending message, channel state "%s"', this.channel.readyState)
139
-
140
- if (isFirefox) {
141
- // TODO: firefox can deliver small messages out of order - remove once a
142
- // browser with https://bugzilla.mozilla.org/show_bug.cgi?id=1983831 is
143
- // available in playwright-test
144
- this.channel.send(data.subarray())
145
- return
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
- if (this.channel.readyState !== 'open') {
156
- return {
157
- sentBytes: 0,
158
- canSendMore: false
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 (err: Error): void {
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._sendFlag(Message.Flag.FIN)
204
- options?.signal?.throwIfAborted()
205
- this.receivedFinAck = Promise.withResolvers<void>()
206
-
207
- await Promise.any([
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._sendFlag(Message.Flag.STOP_SENDING)
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): void {
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
- // we should expect no more data from the remote, stop reading
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
- // stop reading and writing to the stream immediately
245
- this.receivedFinAck?.reject(new StreamResetError('The stream was reset'))
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
- // the remote has stopped reading
210
+ // The remote has stopped reading
251
211
  this.onRemoteCloseRead()
252
212
  }
253
213
 
254
214
  if (message.flag === Message.Flag.FIN_ACK) {
255
- // remote received our FIN
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 {