@libp2p/webrtc 5.2.24 → 6.0.0-049bfa0fa

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 (91) hide show
  1. package/README.md +10 -20
  2. package/dist/index.min.js +17 -17
  3. package/dist/index.min.js.map +4 -4
  4. package/dist/src/constants.d.ts +4 -23
  5. package/dist/src/constants.d.ts.map +1 -1
  6. package/dist/src/constants.js +4 -23
  7. package/dist/src/constants.js.map +1 -1
  8. package/dist/src/index.d.ts +20 -22
  9. package/dist/src/index.d.ts.map +1 -1
  10. package/dist/src/index.js +12 -22
  11. package/dist/src/index.js.map +1 -1
  12. package/dist/src/muxer.d.ts +14 -46
  13. package/dist/src/muxer.d.ts.map +1 -1
  14. package/dist/src/muxer.js +30 -138
  15. package/dist/src/muxer.js.map +1 -1
  16. package/dist/src/private-to-private/initiate-connection.d.ts +2 -3
  17. package/dist/src/private-to-private/initiate-connection.d.ts.map +1 -1
  18. package/dist/src/private-to-private/initiate-connection.js +37 -5
  19. package/dist/src/private-to-private/initiate-connection.js.map +1 -1
  20. package/dist/src/private-to-private/signaling-stream-handler.d.ts +4 -4
  21. package/dist/src/private-to-private/signaling-stream-handler.d.ts.map +1 -1
  22. package/dist/src/private-to-private/signaling-stream-handler.js +19 -7
  23. package/dist/src/private-to-private/signaling-stream-handler.js.map +1 -1
  24. package/dist/src/private-to-private/transport.d.ts +2 -9
  25. package/dist/src/private-to-private/transport.d.ts.map +1 -1
  26. package/dist/src/private-to-private/transport.js +30 -15
  27. package/dist/src/private-to-private/transport.js.map +1 -1
  28. package/dist/src/private-to-private/util.d.ts +3 -2
  29. package/dist/src/private-to-private/util.d.ts.map +1 -1
  30. package/dist/src/private-to-private/util.js +26 -14
  31. package/dist/src/private-to-private/util.js.map +1 -1
  32. package/dist/src/private-to-public/listener.d.ts.map +1 -1
  33. package/dist/src/private-to-public/listener.js +21 -15
  34. package/dist/src/private-to-public/listener.js.map +1 -1
  35. package/dist/src/private-to-public/transport.d.ts +0 -8
  36. package/dist/src/private-to-public/transport.d.ts.map +1 -1
  37. package/dist/src/private-to-public/transport.js +3 -2
  38. package/dist/src/private-to-public/transport.js.map +1 -1
  39. package/dist/src/private-to-public/utils/connect.d.ts +1 -1
  40. package/dist/src/private-to-public/utils/connect.d.ts.map +1 -1
  41. package/dist/src/private-to-public/utils/connect.js +17 -14
  42. package/dist/src/private-to-public/utils/connect.js.map +1 -1
  43. package/dist/src/private-to-public/utils/get-rtcpeerconnection.d.ts +4 -4
  44. package/dist/src/private-to-public/utils/get-rtcpeerconnection.d.ts.map +1 -1
  45. package/dist/src/private-to-public/utils/get-rtcpeerconnection.js +13 -2
  46. package/dist/src/private-to-public/utils/get-rtcpeerconnection.js.map +1 -1
  47. package/dist/src/private-to-public/utils/sdp.d.ts.map +1 -1
  48. package/dist/src/private-to-public/utils/sdp.js +25 -13
  49. package/dist/src/private-to-public/utils/sdp.js.map +1 -1
  50. package/dist/src/private-to-public/utils/stun-listener.js +1 -1
  51. package/dist/src/private-to-public/utils/stun-listener.js.map +1 -1
  52. package/dist/src/rtcpeerconnection-to-conn.d.ts +12 -0
  53. package/dist/src/rtcpeerconnection-to-conn.d.ts.map +1 -0
  54. package/dist/src/rtcpeerconnection-to-conn.js +46 -0
  55. package/dist/src/rtcpeerconnection-to-conn.js.map +1 -0
  56. package/dist/src/stream.d.ts +14 -26
  57. package/dist/src/stream.d.ts.map +1 -1
  58. package/dist/src/stream.js +134 -204
  59. package/dist/src/stream.js.map +1 -1
  60. package/dist/src/util.d.ts +3 -1
  61. package/dist/src/util.d.ts.map +1 -1
  62. package/dist/src/util.js +19 -0
  63. package/dist/src/util.js.map +1 -1
  64. package/dist/src/webrtc/index.d.ts +1 -1
  65. package/dist/src/webrtc/index.d.ts.map +1 -1
  66. package/dist/src/webrtc/index.js +1 -1
  67. package/dist/src/webrtc/index.js.map +1 -1
  68. package/package.json +26 -29
  69. package/src/constants.ts +5 -28
  70. package/src/index.ts +21 -22
  71. package/src/muxer.ts +39 -169
  72. package/src/private-to-private/initiate-connection.ts +46 -8
  73. package/src/private-to-private/signaling-stream-handler.ts +23 -10
  74. package/src/private-to-private/transport.ts +33 -25
  75. package/src/private-to-private/util.ts +33 -16
  76. package/src/private-to-public/listener.ts +22 -15
  77. package/src/private-to-public/transport.ts +3 -12
  78. package/src/private-to-public/utils/connect.ts +18 -15
  79. package/src/private-to-public/utils/get-rtcpeerconnection.ts +16 -4
  80. package/src/private-to-public/utils/sdp.ts +29 -13
  81. package/src/private-to-public/utils/stun-listener.ts +1 -1
  82. package/src/rtcpeerconnection-to-conn.ts +66 -0
  83. package/src/stream.ts +153 -237
  84. package/src/util.ts +22 -1
  85. package/src/webrtc/index.ts +1 -1
  86. package/dist/src/maconn.d.ts +0 -58
  87. package/dist/src/maconn.d.ts.map +0 -1
  88. package/dist/src/maconn.js +0 -56
  89. package/dist/src/maconn.js.map +0 -1
  90. package/dist/typedoc-urls.json +0 -14
  91. package/src/maconn.ts +0 -101
package/src/stream.ts CHANGED
@@ -1,20 +1,17 @@
1
- import { StreamStateError, TimeoutError } from '@libp2p/interface'
2
- import { AbstractStream } from '@libp2p/utils/abstract-stream'
3
- import { anySignal } from 'any-signal'
1
+ import { StreamResetError, StreamStateError } from '@libp2p/interface'
2
+ import { AbstractStream } from '@libp2p/utils'
4
3
  import * as lengthPrefixed from 'it-length-prefixed'
5
4
  import { pushable } from 'it-pushable'
6
- import pDefer from 'p-defer'
7
- import pTimeout from 'p-timeout'
8
- import { raceEvent } from 'race-event'
5
+ import { pEvent } from 'p-event'
9
6
  import { raceSignal } from 'race-signal'
10
7
  import { Uint8ArrayList } from 'uint8arraylist'
11
- import { BUFFERED_AMOUNT_LOW_TIMEOUT, FIN_ACK_TIMEOUT, MAX_BUFFERED_AMOUNT, MAX_MESSAGE_SIZE, OPEN_TIMEOUT, PROTOBUF_OVERHEAD } from './constants.js'
8
+ import { DEFAULT_FIN_ACK_TIMEOUT, MAX_BUFFERED_AMOUNT, MAX_MESSAGE_SIZE, PROTOBUF_OVERHEAD } from './constants.js'
12
9
  import { Message } from './private-to-public/pb/message.js'
10
+ import { isFirefox } from './util.js'
13
11
  import type { DataChannelOptions } from './index.js'
14
- import type { AbortOptions, Direction, Logger } from '@libp2p/interface'
15
- import type { AbstractStreamInit } from '@libp2p/utils/abstract-stream'
12
+ import type { AbortOptions, MessageStreamDirection, Logger } from '@libp2p/interface'
13
+ import type { AbstractStreamInit, SendResult } from '@libp2p/utils'
16
14
  import type { Pushable } from 'it-pushable'
17
- import type { DeferredPromise } from 'p-defer'
18
15
 
19
16
  export interface WebRTCStreamInit extends AbstractStreamInit, DataChannelOptions {
20
17
  /**
@@ -39,124 +36,40 @@ export class WebRTCStream extends AbstractStream {
39
36
  * and then the protobuf decoder.
40
37
  */
41
38
  private readonly incomingData: Pushable<Uint8Array>
42
-
43
39
  private readonly maxBufferedAmount: number
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
40
+ private receivedFinAck?: PromiseWithResolvers<void>
41
+ private finAckTimeout: number
59
42
 
60
43
  constructor (init: WebRTCStreamInit) {
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)
44
+ super({
45
+ ...init,
46
+ maxMessageSize: (init.maxMessageSize ?? MAX_MESSAGE_SIZE) - PROTOBUF_OVERHEAD
47
+ })
96
48
 
97
49
  this.channel = init.channel
98
50
  this.channel.binaryType = 'arraybuffer'
99
51
  this.incomingData = pushable<Uint8Array>()
100
- this.bufferedAmountLowEventTimeout = init.bufferedAmountLowEventTimeout ?? BUFFERED_AMOUNT_LOW_TIMEOUT
101
52
  this.maxBufferedAmount = init.maxBufferedAmount ?? MAX_BUFFERED_AMOUNT
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()
107
-
108
- // set up initial state
109
- switch (this.channel.readyState) {
110
- case 'open':
111
- this.timeline.open = new Date().getTime()
112
- break
113
-
114
- case 'closed':
115
- case 'closing':
116
- if (this.timeline.close === undefined || this.timeline.close === 0) {
117
- this.timeline.close = Date.now()
118
- }
119
- break
120
- case 'connecting':
121
- // noop
122
- break
123
-
124
- default:
125
- this.log.error('unknown datachannel state %s', this.channel.readyState)
126
- throw new StreamStateError('Unknown datachannel state')
127
- }
53
+ this.finAckTimeout = init.finAckTimeout ?? DEFAULT_FIN_ACK_TIMEOUT
128
54
 
129
55
  // handle RTCDataChannel events
130
- this.channel.onopen = (_evt) => {
131
- this.timeline.open = new Date().getTime()
132
- }
133
-
134
- this.channel.onclose = (_evt) => {
135
- this.log.trace('received onclose event')
56
+ this.channel.onclose = () => {
57
+ this.log.trace('received datachannel close event')
136
58
 
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
- })
59
+ this.onRemoteCloseWrite()
60
+ this.onTransportClosed()
147
61
  }
148
62
 
149
63
  this.channel.onerror = (evt) => {
150
- this.log.trace('received onerror event')
64
+ const err = (evt as RTCErrorEvent).error
151
65
 
152
- // stop any in-progress writes
153
- this.closeController.abort()
66
+ this.log.trace('received datachannel error event - %e', err)
154
67
 
155
- const err = (evt as RTCErrorEvent).error
156
68
  this.abort(err)
157
69
  }
158
70
 
159
71
  this.channel.onmessage = async (event: MessageEvent<ArrayBuffer>) => {
72
+ this.log('incoming message %d bytes', event.data.byteLength)
160
73
  const { data } = event
161
74
 
162
75
  if (data === null || data.byteLength === 0) {
@@ -166,187 +79,186 @@ export class WebRTCStream extends AbstractStream {
166
79
  this.incomingData.push(new Uint8Array(data, 0, data.byteLength))
167
80
  }
168
81
 
169
- const self = this
82
+ // dispatch drain event when the buffered amount drops to zero
83
+ this.channel.bufferedAmountLowThreshold = 0
84
+
85
+ this.channel.onbufferedamountlow = () => {
86
+ if (this.writableNeedsDrain) {
87
+ this.safeDispatchEvent('drain')
88
+ }
89
+ }
90
+
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
+ }
170
107
 
171
108
  // pipe framed protobuf messages through a length prefixed decoder, and
172
109
  // surface data from the `Message.message` field through a source.
173
110
  Promise.resolve().then(async () => {
174
111
  for await (const buf of lengthPrefixed.decode(this.incomingData)) {
175
- const message = self.processIncomingProtobuf(buf)
176
-
177
- if (message != null) {
178
- self.sourcePush(new Uint8ArrayList(message))
179
- }
112
+ this.processIncomingProtobuf(buf)
180
113
  }
181
114
  })
182
115
  .catch(err => {
183
116
  this.log.error('error processing incoming data channel messages', err)
184
117
  })
118
+
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
+ }
125
+ }
126
+ this.addEventListener('close', cleanUpDatachannelOnClose)
185
127
  }
186
128
 
187
129
  sendNewStream (): void {
188
130
  // opening new streams is handled by WebRTC so this is a noop
189
131
  }
190
132
 
191
- async _sendMessage (data: Uint8ArrayList, checkBuffer: boolean = true): Promise<void> {
192
- if (this.channel.readyState === 'closed' || this.channel.readyState === 'closing') {
133
+ _sendMessage (data: Uint8ArrayList): void {
134
+ if (this.channel.readyState !== 'open') {
193
135
  throw new StreamStateError(`Invalid datachannel state - ${this.channel.readyState}`)
194
136
  }
195
137
 
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
- }
138
+ this.log.trace('sending message, channel state "%s"', this.channel.readyState)
209
139
 
210
- this.log('channel state is now "%s", sending data', this.channel.readyState)
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
211
146
  }
212
147
 
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
- }
148
+ // send message without copying data
149
+ for (const buf of data) {
150
+ this.channel.send(buf)
232
151
  }
152
+ }
233
153
 
234
- try {
235
- this.log.trace('sending message, channel state "%s"', this.channel.readyState)
236
- // send message without copying data
237
- this.channel.send(data.subarray())
238
- } catch (err: any) {
239
- this.log.error('error while sending message', err)
154
+ sendData (data: Uint8ArrayList): SendResult {
155
+ if (this.channel.readyState !== 'open') {
156
+ return {
157
+ sentBytes: 0,
158
+ canSendMore: false
159
+ }
240
160
  }
241
- }
242
161
 
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)
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
+ }
258
183
  }
184
+ */
259
185
 
260
- this.log.trace('finished sending data, channel state "%s"', this.channel.readyState)
186
+ return {
187
+ sentBytes: data.byteLength,
188
+ canSendMore: this.channel.bufferedAmount < this.maxBufferedAmount
189
+ }
261
190
  }
262
191
 
263
- async sendReset (): Promise<void> {
192
+ sendReset (err: Error): void {
264
193
  try {
265
- await this._sendFlag(Message.Flag.RESET)
194
+ this.log.error('sending reset - %e', err)
195
+ this._sendFlag(Message.Flag.RESET)
196
+ this.receivedFinAck?.reject(err)
266
197
  } catch (err) {
267
198
  this.log.error('failed to send reset - %e', err)
268
- } finally {
269
- this.channel.close()
270
199
  }
271
200
  }
272
201
 
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')
293
- }
294
-
295
- // if we've attempted to receive a FIN_ACK, do not try again
296
- this.receiveFinAck.resolve()
202
+ 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
+ ])
297
216
  }
298
217
 
299
- async sendCloseRead (): Promise<void> {
300
- if (this.channel.readyState !== 'open') {
301
- return
302
- }
303
-
304
- await this._sendFlag(Message.Flag.STOP_SENDING)
218
+ async sendCloseRead (options?: AbortOptions): Promise<void> {
219
+ this._sendFlag(Message.Flag.STOP_SENDING)
220
+ options?.signal?.throwIfAborted()
305
221
  }
306
222
 
307
223
  /**
308
224
  * Handle incoming
309
225
  */
310
- private processIncomingProtobuf (buffer: Uint8ArrayList): Uint8Array | undefined {
226
+ private processIncomingProtobuf (buffer: Uint8ArrayList): void {
311
227
  const message = Message.decode(buffer)
312
228
 
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
+
313
234
  if (message.flag !== undefined) {
314
235
  this.log.trace('incoming flag %s, write status "%s", read status "%s"', message.flag, this.writeStatus, this.readStatus)
315
236
 
316
237
  if (message.flag === Message.Flag.FIN) {
317
- // We should expect no more data from the remote, stop reading
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
- })
238
+ // we should expect no more data from the remote, stop reading
239
+ this._sendFlag(Message.Flag.FIN_ACK)
240
+ this.onRemoteCloseWrite()
325
241
  }
326
242
 
327
243
  if (message.flag === Message.Flag.RESET) {
328
- // Stop reading and writing to the stream immediately
329
- this.reset()
244
+ // stop reading and writing to the stream immediately
245
+ this.receivedFinAck?.reject(new StreamResetError('The stream was reset'))
246
+ this.onRemoteReset()
330
247
  }
331
248
 
332
249
  if (message.flag === Message.Flag.STOP_SENDING) {
333
- // The remote has stopped reading
334
- this.remoteCloseRead()
250
+ // the remote has stopped reading
251
+ this.onRemoteCloseRead()
335
252
  }
336
253
 
337
254
  if (message.flag === Message.Flag.FIN_ACK) {
338
- this.log.trace('received FIN_ACK')
339
- this.receiveFinAck.resolve()
255
+ // remote received our FIN
256
+ this.receivedFinAck?.resolve()
340
257
  }
341
258
  }
342
-
343
- // ignore data messages if we've closed the readable end already
344
- if (this.readStatus === 'ready') {
345
- return message.message
346
- }
347
259
  }
348
260
 
349
- private async _sendFlag (flag: Message.Flag): Promise<boolean> {
261
+ private _sendFlag (flag: Message.Flag): boolean {
350
262
  if (this.channel.readyState !== 'open') {
351
263
  // flags can be sent while we or the remote are closing the datachannel so
352
264
  // if the channel isn't open, don't try to send it but return false to let
@@ -360,7 +272,7 @@ export class WebRTCStream extends AbstractStream {
360
272
  const prefixedBuf = lengthPrefixed.encode.single(messageBuf)
361
273
 
362
274
  try {
363
- await this._sendMessage(prefixedBuf, false)
275
+ this._sendMessage(prefixedBuf)
364
276
 
365
277
  return true
366
278
  } catch (err: any) {
@@ -369,6 +281,14 @@ export class WebRTCStream extends AbstractStream {
369
281
 
370
282
  return false
371
283
  }
284
+
285
+ sendPause (): void {
286
+ // TODO: read backpressure?
287
+ }
288
+
289
+ sendResume (): void {
290
+ // TODO: read backpressure?
291
+ }
372
292
  }
373
293
 
374
294
  export interface WebRTCStreamOptions extends DataChannelOptions {
@@ -383,12 +303,7 @@ export interface WebRTCStreamOptions extends DataChannelOptions {
383
303
  /**
384
304
  * The stream direction
385
305
  */
386
- direction: Direction
387
-
388
- /**
389
- * A callback invoked when the channel ends
390
- */
391
- onEnd?(err?: Error | undefined): void
306
+ direction: MessageStreamDirection
392
307
 
393
308
  /**
394
309
  * The logger to create a scope from
@@ -399,15 +314,16 @@ export interface WebRTCStreamOptions extends DataChannelOptions {
399
314
  * If true the underlying datachannel is being used to perform the noise
400
315
  * handshake during connection establishment
401
316
  */
402
- handshake?: boolean
317
+ isHandshake?: boolean
403
318
  }
404
319
 
405
320
  export function createStream (options: WebRTCStreamOptions): WebRTCStream {
406
- const { channel, direction, handshake } = options
321
+ const { channel, direction, isHandshake } = options
407
322
 
408
323
  return new WebRTCStream({
409
324
  ...options,
410
325
  id: `${channel.id}`,
411
- log: options.log.newScope(`${handshake === true ? 'handshake' : direction}:${channel.id}`)
326
+ log: options.log.newScope(`${isHandshake === true ? 'handshake' : direction}:${channel.id}`),
327
+ protocol: ''
412
328
  })
413
329
  }
package/src/util.ts CHANGED
@@ -2,8 +2,9 @@ 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'
6
5
  import type { LoggerOptions } from '@libp2p/interface'
6
+ import type { Duplex, Source } from 'it-stream-types'
7
+ import type { PeerConnection } from 'node-datachannel'
7
8
 
8
9
  const browser = detect()
9
10
  export const isFirefox = ((browser != null) && browser.name === 'firefox')
@@ -12,6 +13,26 @@ export const nopSource = async function * nop (): AsyncGenerator<Uint8Array, any
12
13
 
13
14
  export const nopSink = async (_: any): Promise<void> => {}
14
15
 
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
+
15
36
  export function drainAndClose (channel: RTCDataChannel, direction: string, drainTimeout: number = DATA_CHANNEL_DRAIN_TIMEOUT, options: LoggerOptions): void {
16
37
  if (channel.readyState !== 'open') {
17
38
  return
@@ -1 +1 @@
1
- export { RTCSessionDescription, RTCIceCandidate, RTCPeerConnection } from '@ipshipyard/node-datachannel/polyfill'
1
+ export { RTCSessionDescription, RTCIceCandidate, RTCPeerConnection } from 'node-datachannel/polyfill'
@@ -1,58 +0,0 @@
1
- import type { RTCPeerConnection } from './webrtc/index.js';
2
- import type { ComponentLogger, Logger, MultiaddrConnection, MultiaddrConnectionTimeline, CounterGroup } from '@libp2p/interface';
3
- import type { AbortOptions, Multiaddr } from '@multiformats/multiaddr';
4
- import type { Source, Sink } from 'it-stream-types';
5
- import type { Uint8ArrayList } from 'uint8arraylist';
6
- interface WebRTCMultiaddrConnectionInit {
7
- /**
8
- * WebRTC Peer Connection
9
- */
10
- peerConnection: RTCPeerConnection;
11
- /**
12
- * The multiaddr address used to communicate with the remote peer
13
- */
14
- remoteAddr: Multiaddr;
15
- /**
16
- * Holds the relevant events timestamps of the connection
17
- */
18
- timeline: MultiaddrConnectionTimeline;
19
- /**
20
- * Optional metrics counter group for this connection
21
- */
22
- metrics?: CounterGroup;
23
- }
24
- export interface WebRTCMultiaddrConnectionComponents {
25
- logger: ComponentLogger;
26
- }
27
- export declare class WebRTCMultiaddrConnection implements MultiaddrConnection {
28
- readonly log: Logger;
29
- /**
30
- * WebRTC Peer Connection
31
- */
32
- readonly peerConnection: RTCPeerConnection;
33
- /**
34
- * The multiaddr address used to communicate with the remote peer
35
- */
36
- remoteAddr: Multiaddr;
37
- /**
38
- * Holds the life cycle times of the connection
39
- */
40
- timeline: MultiaddrConnectionTimeline;
41
- /**
42
- * Optional metrics counter group for this connection
43
- */
44
- metrics?: CounterGroup;
45
- /**
46
- * The stream source, a no-op as the transport natively supports multiplexing
47
- */
48
- source: AsyncGenerator<Uint8Array, any, unknown>;
49
- /**
50
- * The stream destination, a no-op as the transport natively supports multiplexing
51
- */
52
- sink: Sink<Source<Uint8Array | Uint8ArrayList>, Promise<void>>;
53
- constructor(components: WebRTCMultiaddrConnectionComponents, init: WebRTCMultiaddrConnectionInit);
54
- close(options?: AbortOptions): Promise<void>;
55
- abort(err: Error): void;
56
- }
57
- export {};
58
- //# sourceMappingURL=maconn.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"maconn.d.ts","sourceRoot":"","sources":["../../src/maconn.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AAC1D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChI,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACtE,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,UAAU,6BAA6B;IACrC;;OAEG;IACH,cAAc,EAAE,iBAAiB,CAAA;IAEjC;;OAEG;IACH,UAAU,EAAE,SAAS,CAAA;IAErB;;OAEG;IACH,QAAQ,EAAE,2BAA2B,CAAA;IAErC;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB;AAED,MAAM,WAAW,mCAAmC;IAClD,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,qBAAa,yBAA0B,YAAW,mBAAmB;IACnE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IAEpB;;OAEG;IACH,QAAQ,CAAC,cAAc,EAAE,iBAAiB,CAAA;IAE1C;;OAEG;IACH,UAAU,EAAE,SAAS,CAAA;IAErB;;OAEG;IACH,QAAQ,EAAE,2BAA2B,CAAA;IAErC;;OAEG;IACH,OAAO,CAAC,EAAE,YAAY,CAAA;IAEtB;;OAEG;IACH,MAAM,EAAE,cAAc,CAAC,UAAU,EAAE,GAAG,EAAE,OAAO,CAAC,CAAc;IAE9D;;OAEG;IACH,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,cAAc,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAU;gBAE3D,UAAU,EAAE,mCAAmC,EAAE,IAAI,EAAE,6BAA6B;IAmB3F,KAAK,CAAE,OAAO,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAQnD,KAAK,CAAE,GAAG,EAAE,KAAK,GAAG,IAAI;CAOzB"}