@dxos/network-manager 0.6.13 → 0.6.14-main.69511f5

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 (161) hide show
  1. package/dist/lib/browser/{chunk-XYSYUN63.mjs → chunk-RUNQZNCV.mjs} +1247 -1066
  2. package/dist/lib/browser/chunk-RUNQZNCV.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +9 -19
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/browser/testing/index.mjs +20 -33
  6. package/dist/lib/browser/testing/index.mjs.map +3 -3
  7. package/dist/lib/browser/transport/tcp/index.mjs +38 -0
  8. package/dist/lib/browser/transport/tcp/index.mjs.map +7 -0
  9. package/dist/lib/node/{chunk-4YAYC7WN.cjs → chunk-D6P7ACEM.cjs} +1262 -1205
  10. package/dist/lib/node/chunk-D6P7ACEM.cjs.map +7 -0
  11. package/dist/lib/node/index.cjs +27 -37
  12. package/dist/lib/node/index.cjs.map +2 -2
  13. package/dist/lib/node/meta.json +1 -1
  14. package/dist/lib/node/testing/index.cjs +24 -34
  15. package/dist/lib/node/testing/index.cjs.map +3 -3
  16. package/dist/lib/node/transport/tcp/index.cjs +191 -0
  17. package/dist/lib/node/transport/tcp/index.cjs.map +7 -0
  18. package/dist/lib/node-esm/chunk-22DA2US6.mjs +4373 -0
  19. package/dist/lib/node-esm/chunk-22DA2US6.mjs.map +7 -0
  20. package/dist/lib/node-esm/index.mjs +50 -0
  21. package/dist/lib/node-esm/index.mjs.map +7 -0
  22. package/dist/lib/node-esm/meta.json +1 -0
  23. package/dist/lib/node-esm/testing/index.mjs +279 -0
  24. package/dist/lib/node-esm/testing/index.mjs.map +7 -0
  25. package/dist/lib/node-esm/transport/tcp/index.mjs +159 -0
  26. package/dist/lib/node-esm/transport/tcp/index.mjs.map +7 -0
  27. package/dist/types/src/network-manager.d.ts +2 -1
  28. package/dist/types/src/network-manager.d.ts.map +1 -1
  29. package/dist/types/src/signal/ice.d.ts.map +1 -1
  30. package/dist/types/src/signal/integration.node.test.d.ts +2 -0
  31. package/dist/types/src/signal/integration.node.test.d.ts.map +1 -0
  32. package/dist/types/src/signal/swarm-messenger.node.test.d.ts +2 -0
  33. package/dist/types/src/signal/swarm-messenger.node.test.d.ts.map +1 -0
  34. package/dist/types/src/swarm/connection.d.ts.map +1 -1
  35. package/dist/types/src/swarm/swarm.d.ts +1 -1
  36. package/dist/types/src/testing/test-builder.d.ts +2 -2
  37. package/dist/types/src/testing/test-builder.d.ts.map +1 -1
  38. package/dist/types/src/testing/test-wire-protocol.d.ts +1 -2
  39. package/dist/types/src/testing/test-wire-protocol.d.ts.map +1 -1
  40. package/dist/types/src/tests/basic-test-suite.d.ts.map +1 -1
  41. package/dist/types/src/tests/property-test-suite.d.ts.map +1 -1
  42. package/dist/types/src/tests/tcp-transport.node.test.d.ts +2 -0
  43. package/dist/types/src/tests/tcp-transport.node.test.d.ts.map +1 -0
  44. package/dist/types/src/tests/utils.d.ts.map +1 -1
  45. package/dist/types/src/transport/index.d.ts +1 -5
  46. package/dist/types/src/transport/index.d.ts.map +1 -1
  47. package/dist/types/src/transport/memory-transport.d.ts +2 -2
  48. package/dist/types/src/transport/memory-transport.d.ts.map +1 -1
  49. package/dist/types/src/transport/tcp/index.d.ts +2 -0
  50. package/dist/types/src/transport/tcp/index.d.ts.map +1 -0
  51. package/dist/types/src/transport/{tcp-transport.browser.d.ts → tcp/tcp-transport.browser.d.ts} +3 -3
  52. package/dist/types/src/transport/tcp/tcp-transport.browser.d.ts.map +1 -0
  53. package/dist/types/src/transport/{tcp-transport.d.ts → tcp/tcp-transport.d.ts} +3 -3
  54. package/dist/types/src/transport/tcp/tcp-transport.d.ts.map +1 -0
  55. package/dist/types/src/transport/transport.d.ts +7 -6
  56. package/dist/types/src/transport/transport.d.ts.map +1 -1
  57. package/dist/types/src/transport/webrtc/index.d.ts +4 -0
  58. package/dist/types/src/transport/webrtc/index.d.ts.map +1 -0
  59. package/dist/types/src/transport/webrtc/rtc-connection-factory.d.ts +14 -0
  60. package/dist/types/src/transport/webrtc/rtc-connection-factory.d.ts.map +1 -0
  61. package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts +68 -0
  62. package/dist/types/src/transport/webrtc/rtc-peer-connection.d.ts.map +1 -0
  63. package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts +33 -0
  64. package/dist/types/src/transport/webrtc/rtc-transport-channel.d.ts.map +1 -0
  65. package/dist/types/src/transport/webrtc/rtc-transport-channel.test.d.ts +2 -0
  66. package/dist/types/src/transport/webrtc/rtc-transport-channel.test.d.ts.map +1 -0
  67. package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts +4 -0
  68. package/dist/types/src/transport/webrtc/rtc-transport-factory.d.ts.map +1 -0
  69. package/dist/types/src/transport/{simplepeer-transport-proxy.d.ts → webrtc/rtc-transport-proxy.d.ts} +10 -12
  70. package/dist/types/src/transport/webrtc/rtc-transport-proxy.d.ts.map +1 -0
  71. package/dist/types/src/transport/webrtc/rtc-transport-proxy.test.d.ts +2 -0
  72. package/dist/types/src/transport/webrtc/rtc-transport-proxy.test.d.ts.map +1 -0
  73. package/dist/types/src/transport/{simplepeer-transport-service.d.ts → webrtc/rtc-transport-service.d.ts} +9 -7
  74. package/dist/types/src/transport/webrtc/rtc-transport-service.d.ts.map +1 -0
  75. package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts +4 -0
  76. package/dist/types/src/transport/webrtc/rtc-transport-stats.d.ts.map +1 -0
  77. package/dist/types/src/transport/webrtc/rtc-transport.test.d.ts +2 -0
  78. package/dist/types/src/transport/webrtc/rtc-transport.test.d.ts.map +1 -0
  79. package/dist/types/src/transport/webrtc/test-utils.d.ts +5 -0
  80. package/dist/types/src/transport/webrtc/test-utils.d.ts.map +1 -0
  81. package/dist/types/src/transport/webrtc/utils.d.ts +3 -0
  82. package/dist/types/src/transport/webrtc/utils.d.ts.map +1 -0
  83. package/package.json +53 -36
  84. package/src/network-manager.ts +5 -13
  85. package/src/signal/ice.test.ts +1 -3
  86. package/src/signal/ice.ts +6 -1
  87. package/src/signal/{integration.test.ts → integration.node.test.ts} +9 -15
  88. package/src/signal/{swarm-messenger.test.ts → swarm-messenger.node.test.ts} +13 -23
  89. package/src/swarm/connection-limiter.test.ts +3 -6
  90. package/src/swarm/connection.test.ts +63 -38
  91. package/src/swarm/connection.ts +5 -5
  92. package/src/swarm/swarm.test.ts +10 -12
  93. package/src/swarm/swarm.ts +1 -1
  94. package/src/testing/test-builder.ts +13 -29
  95. package/src/testing/test-wire-protocol.ts +1 -4
  96. package/src/tests/basic-test-suite.ts +34 -33
  97. package/src/tests/memory-transport.test.ts +40 -42
  98. package/src/tests/property-test-suite.ts +21 -22
  99. package/src/tests/tcp-transport.node.test.ts +65 -0
  100. package/src/tests/utils.ts +3 -2
  101. package/src/tests/webrtc-transport.test.ts +9 -9
  102. package/src/transport/index.ts +1 -5
  103. package/src/transport/memory-transport.ts +2 -0
  104. package/src/transport/tcp/index.ts +5 -0
  105. package/src/transport/{tcp-transport.browser.ts → tcp/tcp-transport.browser.ts} +7 -3
  106. package/src/transport/{tcp-transport.ts → tcp/tcp-transport.ts} +3 -1
  107. package/src/transport/transport.ts +8 -7
  108. package/src/transport/webrtc/index.ts +7 -0
  109. package/src/transport/webrtc/rtc-connection-factory.ts +82 -0
  110. package/src/transport/webrtc/rtc-peer-connection.ts +472 -0
  111. package/src/transport/webrtc/rtc-transport-channel.test.ts +176 -0
  112. package/src/transport/webrtc/rtc-transport-channel.ts +195 -0
  113. package/src/transport/webrtc/rtc-transport-factory.ts +28 -0
  114. package/src/transport/webrtc/rtc-transport-proxy.test.ts +413 -0
  115. package/src/transport/webrtc/rtc-transport-proxy.ts +264 -0
  116. package/src/transport/webrtc/rtc-transport-service.ts +192 -0
  117. package/src/transport/webrtc/rtc-transport-stats.ts +67 -0
  118. package/src/transport/webrtc/rtc-transport.test.ts +198 -0
  119. package/src/transport/webrtc/test-utils.ts +22 -0
  120. package/src/transport/webrtc/utils.ts +36 -0
  121. package/src/typings.d.ts +8 -2
  122. package/dist/lib/browser/chunk-XYSYUN63.mjs.map +0 -7
  123. package/dist/lib/node/chunk-4YAYC7WN.cjs.map +0 -7
  124. package/dist/types/src/signal/integration.test.d.ts +0 -2
  125. package/dist/types/src/signal/integration.test.d.ts.map +0 -1
  126. package/dist/types/src/signal/swarm-messenger.test.d.ts +0 -2
  127. package/dist/types/src/signal/swarm-messenger.test.d.ts.map +0 -1
  128. package/dist/types/src/tests/tcp-transport.test.d.ts +0 -2
  129. package/dist/types/src/tests/tcp-transport.test.d.ts.map +0 -1
  130. package/dist/types/src/transport/libdatachannel-transport.d.ts +0 -42
  131. package/dist/types/src/transport/libdatachannel-transport.d.ts.map +0 -1
  132. package/dist/types/src/transport/libdatachannel-transport.test.d.ts +0 -2
  133. package/dist/types/src/transport/libdatachannel-transport.test.d.ts.map +0 -1
  134. package/dist/types/src/transport/memory-transport.test.d.ts +0 -2
  135. package/dist/types/src/transport/memory-transport.test.d.ts.map +0 -1
  136. package/dist/types/src/transport/simplepeer-simple-peer.d.ts +0 -2
  137. package/dist/types/src/transport/simplepeer-simple-peer.d.ts.map +0 -1
  138. package/dist/types/src/transport/simplepeer-transport-proxy-test.d.ts +0 -2
  139. package/dist/types/src/transport/simplepeer-transport-proxy-test.d.ts.map +0 -1
  140. package/dist/types/src/transport/simplepeer-transport-proxy.d.ts.map +0 -1
  141. package/dist/types/src/transport/simplepeer-transport-service.d.ts.map +0 -1
  142. package/dist/types/src/transport/simplepeer-transport.d.ts +0 -36
  143. package/dist/types/src/transport/simplepeer-transport.d.ts.map +0 -1
  144. package/dist/types/src/transport/simplepeer-transport.test.d.ts +0 -2
  145. package/dist/types/src/transport/simplepeer-transport.test.d.ts.map +0 -1
  146. package/dist/types/src/transport/tcp-transport.browser.d.ts.map +0 -1
  147. package/dist/types/src/transport/tcp-transport.d.ts.map +0 -1
  148. package/dist/types/src/transport/webrtc.d.ts +0 -6
  149. package/dist/types/src/transport/webrtc.d.ts.map +0 -1
  150. package/src/globals.d.ts +0 -7
  151. package/src/tests/tcp-transport.test.ts +0 -67
  152. package/src/transport/libdatachannel-transport.test.ts +0 -100
  153. package/src/transport/libdatachannel-transport.ts +0 -376
  154. package/src/transport/memory-transport.test.ts +0 -74
  155. package/src/transport/simplepeer-simple-peer.ts +0 -26
  156. package/src/transport/simplepeer-transport-proxy-test.ts +0 -181
  157. package/src/transport/simplepeer-transport-proxy.ts +0 -246
  158. package/src/transport/simplepeer-transport-service.ts +0 -160
  159. package/src/transport/simplepeer-transport.test.ts +0 -61
  160. package/src/transport/simplepeer-transport.ts +0 -250
  161. package/src/transport/webrtc.ts +0 -15
@@ -0,0 +1,176 @@
1
+ //
2
+ // Copyright 2020 DXOS.org
3
+ //
4
+
5
+ import { Duplex } from 'node:stream';
6
+ import { describe, expect, test } from 'vitest';
7
+
8
+ import { sleep } from '@dxos/async';
9
+
10
+ import { type RtcPeerConnection } from './rtc-peer-connection';
11
+ import { RtcTransportChannel } from './rtc-transport-channel';
12
+ import { handleChannelErrors } from './test-utils';
13
+ import { type TransportOptions } from '../transport';
14
+
15
+ describe('RtcTransportChannel', () => {
16
+ test('transport error raised if channel creation fails', async () => {
17
+ const controller = createChannelController();
18
+ const { transport } = createTransport(controller.connection);
19
+ const transportErrors = handleChannelErrors(transport);
20
+ await transport.open();
21
+ controller.onChannelCreationFailed();
22
+ await transportErrors.expectErrorRaised();
23
+ });
24
+
25
+ test('channel closed if it was open after transport was closed', async () => {
26
+ const controller = createChannelController();
27
+ const { transport } = createTransport(controller.connection);
28
+ await transport.open();
29
+ await controller.onChannelCreated();
30
+ await transport.close();
31
+ controller.channel.onopen();
32
+ expect(controller.channel.wasClosed()).to.be.true;
33
+ });
34
+
35
+ test('channel open while transport is being closed', async () => {
36
+ for (const syncOpen of [false, true]) {
37
+ const controller = createChannelController();
38
+ const { transport } = createTransport(controller.connection);
39
+ await transport.open();
40
+ await controller.onChannelCreated();
41
+ void transport.close();
42
+ if (syncOpen) {
43
+ controller.channel.onopen();
44
+ } else {
45
+ setTimeout(() => controller.channel.onopen());
46
+ }
47
+ await sleep(10);
48
+ expect(controller.channel.wasClosed()).to.be.true;
49
+ }
50
+ });
51
+
52
+ test('channel close closes transport', async () => {
53
+ const controller = createChannelController();
54
+ const { transport } = createTransport(controller.connection);
55
+ const transportClosedEvent = handleClose(transport);
56
+ await transport.open();
57
+ await controller.onChannelCreated();
58
+ controller.channel.onopen();
59
+ await sleep(10);
60
+ await controller.channel.onclose();
61
+ expect(transport.isOpen).to.be.false;
62
+ await transportClosedEvent.expectWasEmitted();
63
+ });
64
+
65
+ test('channel closed if created after transport was closed', async () => {
66
+ const controller = createChannelController();
67
+ const { transport } = createTransport(controller.connection);
68
+ await transport.open();
69
+ await transport.close();
70
+ await controller.onChannelCreated();
71
+ controller.channel.onopen();
72
+ expect(controller.channel.wasClosed()).to.be.true;
73
+ });
74
+
75
+ test('message not delivered on a closed transport', async () => {
76
+ const controller = createChannelController();
77
+ const { deliveredMessages, transport } = createTransport(controller.connection);
78
+ await transport.open();
79
+ await controller.onChannelCreated();
80
+ controller.channel.onopen();
81
+ const message = 'hello';
82
+ await controller.channel.onMessage(message);
83
+ expect(deliveredMessages).toStrictEqual([message]);
84
+ await transport.close();
85
+ await controller.channel.onMessage(message + '1');
86
+ expect(deliveredMessages).toStrictEqual([message]);
87
+ });
88
+
89
+ test('message not sent on a closed transport', async () => {
90
+ const controller = createChannelController();
91
+ const { deliveredMessages, transport } = createTransport(controller.connection);
92
+ await transport.open();
93
+ await controller.onChannelCreated();
94
+ controller.channel.onopen();
95
+ const message = 'hello';
96
+ await controller.channel.onMessage(message);
97
+ expect(deliveredMessages).toStrictEqual([message]);
98
+ await transport.close();
99
+ await controller.channel.onMessage(message + '1');
100
+ expect(deliveredMessages).toStrictEqual([message]);
101
+ });
102
+
103
+ test('error raised if send fails', async () => {
104
+ const controller = createChannelController();
105
+ const { transport, stream } = createTransport(controller.connection);
106
+ await transport.open();
107
+ await controller.onChannelCreated();
108
+ const transportClosedEvent = handleChannelErrors(transport);
109
+ controller.channel.onopen();
110
+ controller.setFailSending(true);
111
+ stream.push('hello');
112
+ await transportClosedEvent.expectErrorRaised();
113
+ });
114
+
115
+ const createTransport = (connection: RtcPeerConnection) => {
116
+ const deliveredMessages: any[] = [];
117
+ const stream = new Duplex({
118
+ read: () => {},
119
+ write: (chunk: any, _: BufferEncoding, callback: (error?: Error | null) => void) => {
120
+ deliveredMessages.push(Buffer.from(chunk).toString());
121
+ callback();
122
+ },
123
+ });
124
+ const options = { topic: 'test', stream } as any as TransportOptions;
125
+ return { deliveredMessages, stream, transport: new RtcTransportChannel(connection, options) };
126
+ };
127
+
128
+ const handleClose = (channel: RtcTransportChannel) => {
129
+ let emitted = false;
130
+ channel.closed.on(() => (emitted = true));
131
+ return { expectWasEmitted: async () => expect(emitted).toBeTruthy() };
132
+ };
133
+
134
+ const createChannelController = () => {
135
+ // Lowercase methods will get overwritten internally.
136
+ let closed = false;
137
+ let failsSending = false;
138
+ const channel = {
139
+ onopen: () => {},
140
+ onclose: async () => {},
141
+ close: () => (closed = true),
142
+ send: () => {
143
+ if (failsSending) {
144
+ throw new Error('Expected');
145
+ }
146
+ },
147
+ wasClosed: () => closed,
148
+ onMessage: async (message: string) => {
149
+ (channel as any).onmessage({ data: message });
150
+ await sleep(5);
151
+ },
152
+ };
153
+ let onChannelCreated = async () => {};
154
+ let onChannelCreationFailed = () => {};
155
+ const createChannelPromise = new Promise((resolve, reject) => {
156
+ onChannelCreated = async () => {
157
+ resolve(channel);
158
+ await sleep(5);
159
+ };
160
+ onChannelCreationFailed = reject;
161
+ });
162
+ return {
163
+ onChannelCreated,
164
+ onChannelCreationFailed,
165
+ setFailSending: (fail: boolean) => {
166
+ failsSending = fail;
167
+ },
168
+ channel,
169
+ connection: {
170
+ createDataChannel: async (topic: string) => {
171
+ return createChannelPromise;
172
+ },
173
+ } as any as RtcPeerConnection,
174
+ };
175
+ };
176
+ });
@@ -0,0 +1,195 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { Duplex } from 'node:stream';
6
+
7
+ import { Event as AsyncEvent } from '@dxos/async';
8
+ import { Resource } from '@dxos/context';
9
+ import { ErrorStream } from '@dxos/debug';
10
+ import { invariant } from '@dxos/invariant';
11
+ import { log } from '@dxos/log';
12
+ import { ConnectivityError } from '@dxos/protocols';
13
+ import { type Signal } from '@dxos/protocols/proto/dxos/mesh/swarm';
14
+
15
+ import { type RtcPeerConnection } from './rtc-peer-connection';
16
+ import { createRtcTransportStats, describeSelectedRemoteCandidate } from './rtc-transport-stats';
17
+ import { type Transport, type TransportOptions, type TransportStats } from '../transport';
18
+
19
+ // https://viblast.com/blog/2015/2/5/webrtc-data-channel-message-size
20
+ const MAX_MESSAGE_SIZE = 64 * 1024;
21
+ // The default Readable stream buffer size: https://nodejs.org/api/stream.html#implementing-a-readable-stream
22
+ const MAX_BUFFERED_AMOUNT = 64 * 1024;
23
+
24
+ /**
25
+ * A WebRTC connection data channel.
26
+ * Manages a WebRTC connection to a remote peer using an abstract signalling mechanism.
27
+ */
28
+ export class RtcTransportChannel extends Resource implements Transport {
29
+ public readonly closed = new AsyncEvent();
30
+ public readonly connected = new AsyncEvent();
31
+ public readonly errors = new ErrorStream();
32
+
33
+ private _channel: RTCDataChannel | undefined;
34
+ private _stream: Duplex | undefined;
35
+ private _streamDataFlushedCallback: PendingStreamFlushedCallback | null = null;
36
+ private _isChannelCreationInProgress = false;
37
+
38
+ constructor(
39
+ private readonly _connection: RtcPeerConnection,
40
+ private readonly _options: TransportOptions,
41
+ ) {
42
+ super();
43
+ }
44
+
45
+ public get isRtcChannelCreationInProgress() {
46
+ return this._isChannelCreationInProgress;
47
+ }
48
+
49
+ public onConnectionError(error: Error) {
50
+ if (this.isOpen) {
51
+ this.errors.raise(error);
52
+ }
53
+ }
54
+
55
+ protected override async _open() {
56
+ invariant(!this._isChannelCreationInProgress);
57
+ this._isChannelCreationInProgress = true;
58
+ this._connection
59
+ .createDataChannel(this._options.topic)
60
+ .then((channel) => {
61
+ if (this.isOpen) {
62
+ this._channel = channel;
63
+ this._initChannel(this._channel);
64
+ } else {
65
+ this._safeCloseChannel(channel);
66
+ }
67
+ })
68
+ .catch((err) => {
69
+ if (this.isOpen) {
70
+ this.errors.raise(new ConnectivityError(`Failed to create a channel: ${err?.message ?? 'unknown reason.'}`));
71
+ }
72
+ })
73
+ .finally(() => {
74
+ this._isChannelCreationInProgress = false;
75
+ });
76
+ }
77
+
78
+ protected override async _close() {
79
+ if (this._channel) {
80
+ this._safeCloseChannel(this._channel);
81
+ this._channel = undefined;
82
+ this._stream = undefined;
83
+ }
84
+ this.closed.emit();
85
+
86
+ log('closed');
87
+ }
88
+
89
+ private _initChannel(channel: RTCDataChannel) {
90
+ Object.assign<RTCDataChannel, Partial<RTCDataChannel>>(channel, {
91
+ onopen: () => {
92
+ if (!this.isOpen) {
93
+ log.warn('channel opened in a closed transport', { topic: this._options.topic });
94
+ this._safeCloseChannel(channel);
95
+ return;
96
+ }
97
+
98
+ log('onopen');
99
+ const duplex = new Duplex({
100
+ read: () => {},
101
+ write: (chunk, encoding, callback) => {
102
+ return this._handleChannelWrite(chunk, callback);
103
+ },
104
+ });
105
+ duplex.pipe(this._options.stream).pipe(duplex);
106
+ this._stream = duplex;
107
+ this.connected.emit();
108
+ },
109
+
110
+ onclose: async () => {
111
+ log('onclose');
112
+ await this.close();
113
+ },
114
+
115
+ onmessage: (event: MessageEvent) => {
116
+ if (!this._stream) {
117
+ log.warn('ignoring message on a closed channel');
118
+ return;
119
+ }
120
+
121
+ let data = event.data;
122
+ if (data instanceof ArrayBuffer) {
123
+ data = Buffer.from(data);
124
+ }
125
+ this._stream.push(data);
126
+ },
127
+
128
+ onerror: (event: Event & any) => {
129
+ if (this.isOpen) {
130
+ const err = event.error instanceof Error ? event.error : new Error(`Datachannel error: ${event.type}.`);
131
+ this.errors.raise(err);
132
+ }
133
+ },
134
+
135
+ onbufferedamountlow: () => {
136
+ const cb = this._streamDataFlushedCallback;
137
+ this._streamDataFlushedCallback = null;
138
+ cb?.();
139
+ },
140
+ });
141
+ }
142
+
143
+ private async _handleChannelWrite(chunk: any, callback: PendingStreamFlushedCallback) {
144
+ if (!this._channel) {
145
+ log.warn('writing to a channel after a connection was closed');
146
+ return;
147
+ }
148
+
149
+ if (chunk.length > MAX_MESSAGE_SIZE) {
150
+ const error = new Error(`Message too large: ${chunk.length} > ${MAX_MESSAGE_SIZE}.`);
151
+ this.errors.raise(error);
152
+ callback();
153
+ return;
154
+ }
155
+
156
+ try {
157
+ this._channel.send(chunk);
158
+ } catch (err: any) {
159
+ this.errors.raise(err);
160
+ callback();
161
+ return;
162
+ }
163
+
164
+ if (this._channel.bufferedAmount > MAX_BUFFERED_AMOUNT) {
165
+ if (this._streamDataFlushedCallback !== null) {
166
+ log.error('consumer trying to write before we are ready for more data');
167
+ }
168
+ this._streamDataFlushedCallback = callback;
169
+ } else {
170
+ callback();
171
+ }
172
+ }
173
+
174
+ private _safeCloseChannel(channel: RTCDataChannel) {
175
+ try {
176
+ channel.close();
177
+ } catch (error: any) {
178
+ log.catch(error);
179
+ }
180
+ }
181
+
182
+ public onSignal(signal: Signal): Promise<void> {
183
+ return this._connection.onSignal(signal);
184
+ }
185
+
186
+ async getDetails(): Promise<string> {
187
+ return describeSelectedRemoteCandidate(this._connection.currentConnection);
188
+ }
189
+
190
+ async getStats(): Promise<TransportStats> {
191
+ return createRtcTransportStats(this._connection.currentConnection, this._options.topic);
192
+ }
193
+ }
194
+
195
+ type PendingStreamFlushedCallback = () => void;
@@ -0,0 +1,28 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { getRtcConnectionFactory } from './rtc-connection-factory';
6
+ import { RtcPeerConnection } from './rtc-peer-connection';
7
+ import type { IceProvider } from '../../signal';
8
+ import type { TransportFactory } from '../transport';
9
+
10
+ export const createRtcTransportFactory = (
11
+ webrtcConfig?: RTCConfiguration,
12
+ iceProvider?: IceProvider,
13
+ ): TransportFactory => {
14
+ const connectionFactory = getRtcConnectionFactory();
15
+ return {
16
+ createTransport: (options) => {
17
+ // TODO(yaroslav): sendSignal is scoped to a swarm, RtcConnections can be cached if it's scoped to a peer
18
+ const connection = new RtcPeerConnection(connectionFactory, {
19
+ ownPeerKey: options.ownPeerKey,
20
+ remotePeerKey: options.remotePeerKey,
21
+ sendSignal: options.sendSignal,
22
+ webrtcConfig,
23
+ iceProvider,
24
+ });
25
+ return connection.createTransportChannel(options);
26
+ },
27
+ };
28
+ };