mockrtc 0.1.0

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 (136) hide show
  1. package/.github/workflows/ci.yml +29 -0
  2. package/LICENSE +201 -0
  3. package/README.md +290 -0
  4. package/dist/admin-bin.d.ts +2 -0
  5. package/dist/admin-bin.js +67 -0
  6. package/dist/admin-bin.js.map +1 -0
  7. package/dist/client/mockrtc-client.d.ts +12 -0
  8. package/dist/client/mockrtc-client.js +67 -0
  9. package/dist/client/mockrtc-client.js.map +1 -0
  10. package/dist/client/mockrtc-remote-peer.d.ts +15 -0
  11. package/dist/client/mockrtc-remote-peer.js +246 -0
  12. package/dist/client/mockrtc-remote-peer.js.map +1 -0
  13. package/dist/control-channel.d.ts +8 -0
  14. package/dist/control-channel.js +11 -0
  15. package/dist/control-channel.js.map +1 -0
  16. package/dist/handling/handler-builder.d.ts +138 -0
  17. package/dist/handling/handler-builder.js +164 -0
  18. package/dist/handling/handler-builder.js.map +1 -0
  19. package/dist/handling/handler-step-definitions.d.ts +63 -0
  20. package/dist/handling/handler-step-definitions.js +123 -0
  21. package/dist/handling/handler-step-definitions.js.map +1 -0
  22. package/dist/handling/handler-steps.d.ts +48 -0
  23. package/dist/handling/handler-steps.js +218 -0
  24. package/dist/handling/handler-steps.js.map +1 -0
  25. package/dist/main-browser.d.ts +9 -0
  26. package/dist/main-browser.js +26 -0
  27. package/dist/main-browser.js.map +1 -0
  28. package/dist/main.d.ts +58 -0
  29. package/dist/main.js +67 -0
  30. package/dist/main.js.map +1 -0
  31. package/dist/mockrtc-admin-plugin.d.ts +56 -0
  32. package/dist/mockrtc-admin-plugin.js +151 -0
  33. package/dist/mockrtc-admin-plugin.js.map +1 -0
  34. package/dist/mockrtc-admin-server.d.ts +7 -0
  35. package/dist/mockrtc-admin-server.js +18 -0
  36. package/dist/mockrtc-admin-server.js.map +1 -0
  37. package/dist/mockrtc-client.d.ts +12 -0
  38. package/dist/mockrtc-client.js +64 -0
  39. package/dist/mockrtc-client.js.map +1 -0
  40. package/dist/mockrtc-handler-builder.d.ts +15 -0
  41. package/dist/mockrtc-handler-builder.js +24 -0
  42. package/dist/mockrtc-handler-builder.js.map +1 -0
  43. package/dist/mockrtc-peer.d.ts +147 -0
  44. package/dist/mockrtc-peer.js +7 -0
  45. package/dist/mockrtc-peer.js.map +1 -0
  46. package/dist/mockrtc-remote-peer.d.ts +15 -0
  47. package/dist/mockrtc-remote-peer.js +234 -0
  48. package/dist/mockrtc-remote-peer.js.map +1 -0
  49. package/dist/mockrtc-server-peer.d.ts +29 -0
  50. package/dist/mockrtc-server-peer.js +145 -0
  51. package/dist/mockrtc-server-peer.js.map +1 -0
  52. package/dist/mockrtc-server.d.ts +14 -0
  53. package/dist/mockrtc-server.js +53 -0
  54. package/dist/mockrtc-server.js.map +1 -0
  55. package/dist/mockrtc.d.ts +25 -0
  56. package/dist/mockrtc.js +7 -0
  57. package/dist/mockrtc.js.map +1 -0
  58. package/dist/package.json +52 -0
  59. package/dist/server/mockrtc-admin-plugin.d.ts +17 -0
  60. package/dist/server/mockrtc-admin-plugin.js +163 -0
  61. package/dist/server/mockrtc-admin-plugin.js.map +1 -0
  62. package/dist/server/mockrtc-admin-server.d.ts +7 -0
  63. package/dist/server/mockrtc-admin-server.js +18 -0
  64. package/dist/server/mockrtc-admin-server.js.map +1 -0
  65. package/dist/server/mockrtc-server-peer.d.ts +24 -0
  66. package/dist/server/mockrtc-server-peer.js +141 -0
  67. package/dist/server/mockrtc-server-peer.js.map +1 -0
  68. package/dist/server/mockrtc-server.d.ts +14 -0
  69. package/dist/server/mockrtc-server.js +53 -0
  70. package/dist/server/mockrtc-server.js.map +1 -0
  71. package/dist/src/main.d.ts +1 -0
  72. package/dist/src/main.js +24 -0
  73. package/dist/src/main.js.map +1 -0
  74. package/dist/src/mockrtc-peer.d.ts +0 -0
  75. package/dist/src/mockrtc-peer.js +2 -0
  76. package/dist/src/mockrtc-peer.js.map +1 -0
  77. package/dist/src/mockrtc.d.ts +0 -0
  78. package/dist/src/mockrtc.js +65 -0
  79. package/dist/src/mockrtc.js.map +1 -0
  80. package/dist/webrtc/control-channel.d.ts +8 -0
  81. package/dist/webrtc/control-channel.js +11 -0
  82. package/dist/webrtc/control-channel.js.map +1 -0
  83. package/dist/webrtc/datachannel-stream.d.ts +25 -0
  84. package/dist/webrtc/datachannel-stream.js +86 -0
  85. package/dist/webrtc/datachannel-stream.js.map +1 -0
  86. package/dist/webrtc/mediatrack-stream.d.ts +29 -0
  87. package/dist/webrtc/mediatrack-stream.js +109 -0
  88. package/dist/webrtc/mediatrack-stream.js.map +1 -0
  89. package/dist/webrtc/mockrtc-connection.d.ts +14 -0
  90. package/dist/webrtc/mockrtc-connection.js +147 -0
  91. package/dist/webrtc/mockrtc-connection.js.map +1 -0
  92. package/dist/webrtc/peer-connection.d.ts +16 -0
  93. package/dist/webrtc/peer-connection.js +81 -0
  94. package/dist/webrtc/peer-connection.js.map +1 -0
  95. package/dist/webrtc/rtc-connection.d.ts +47 -0
  96. package/dist/webrtc/rtc-connection.js +370 -0
  97. package/dist/webrtc/rtc-connection.js.map +1 -0
  98. package/dist/webrtc-hooks.d.ts +30 -0
  99. package/dist/webrtc-hooks.js +224 -0
  100. package/dist/webrtc-hooks.js.map +1 -0
  101. package/karma.conf.ts +89 -0
  102. package/ngi-eu-footer.png +0 -0
  103. package/package.json +86 -0
  104. package/src/admin-bin.ts +57 -0
  105. package/src/client/mockrtc-client.ts +79 -0
  106. package/src/client/mockrtc-remote-peer.ts +286 -0
  107. package/src/handling/handler-builder.ts +215 -0
  108. package/src/handling/handler-step-definitions.ts +142 -0
  109. package/src/handling/handler-steps.ts +254 -0
  110. package/src/main-browser.ts +44 -0
  111. package/src/main.ts +109 -0
  112. package/src/mockrtc-peer.ts +176 -0
  113. package/src/mockrtc.ts +36 -0
  114. package/src/server/mockrtc-admin-plugin.ts +196 -0
  115. package/src/server/mockrtc-admin-server.ts +17 -0
  116. package/src/server/mockrtc-server-peer.ts +159 -0
  117. package/src/server/mockrtc-server.ts +53 -0
  118. package/src/webrtc/control-channel.ts +13 -0
  119. package/src/webrtc/datachannel-stream.ts +102 -0
  120. package/src/webrtc/mediatrack-stream.ts +135 -0
  121. package/src/webrtc/mockrtc-connection.ts +164 -0
  122. package/src/webrtc/rtc-connection.ts +420 -0
  123. package/src/webrtc-hooks.ts +245 -0
  124. package/test/integration/close-steps.spec.ts +39 -0
  125. package/test/integration/connection-setup.spec.ts +230 -0
  126. package/test/integration/echo-steps.spec.ts +88 -0
  127. package/test/integration/proxy.spec.ts +526 -0
  128. package/test/integration/send-steps.spec.ts +76 -0
  129. package/test/integration/smoke-test.spec.ts +100 -0
  130. package/test/integration/wait-steps.spec.ts +225 -0
  131. package/test/start-test-admin-server.ts +12 -0
  132. package/test/test-setup.ts +136 -0
  133. package/test/tsconfig.json +11 -0
  134. package/tsconfig.json +14 -0
  135. package/typedoc.json +19 -0
  136. package/wallaby.js +41 -0
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ /*
3
+ * SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.DataChannelStream = void 0;
8
+ const stream = require("stream");
9
+ /**
10
+ * Turns a node-datachannel DataChannel into a real Node.js stream, complete with
11
+ * buffering, backpressure (up to a point - if the buffer fills up, messages are dropped),
12
+ * and support for piping data elsewhere.
13
+ *
14
+ * Read & written data may be either UTF-8 strings or Buffers - this difference exists at
15
+ * the protocol level, and is preserved here throughout.
16
+ */
17
+ class DataChannelStream extends stream.Duplex {
18
+ constructor(rawChannel, streamOptions = {}) {
19
+ super(Object.assign(Object.assign({ allowHalfOpen: false }, streamOptions), { objectMode: true // Preserve the string/buffer distinction (WebRTC treats them differently)
20
+ }));
21
+ this.rawChannel = rawChannel;
22
+ this._readActive = true;
23
+ rawChannel.onMessage((msg) => {
24
+ if (!this._readActive)
25
+ return; // If the buffer is full, drop messages.
26
+ // If the push is rejected, we pause reading until the next call to _read().
27
+ this._readActive = this.push(msg);
28
+ });
29
+ // When the DataChannel closes, the readable & writable ends close
30
+ rawChannel.onClosed(() => {
31
+ this.push(null);
32
+ this.destroy();
33
+ });
34
+ rawChannel.onError((errMsg) => {
35
+ this.destroy(new Error(`DataChannel error: ${errMsg}`));
36
+ });
37
+ // Buffer all writes until the DataChannel opens
38
+ if (!rawChannel.isOpen()) {
39
+ this.cork();
40
+ rawChannel.onOpen(() => this.uncork());
41
+ }
42
+ }
43
+ _read() {
44
+ // Stop dropping messages, if the buffer filling up meant we were doing so before.
45
+ this._readActive = true;
46
+ }
47
+ _write(chunk, encoding, callback) {
48
+ let sentOk;
49
+ try {
50
+ if (Buffer.isBuffer(chunk)) {
51
+ sentOk = this.rawChannel.sendMessageBinary(chunk);
52
+ }
53
+ else if (typeof chunk === 'string') {
54
+ sentOk = this.rawChannel.sendMessage(chunk);
55
+ }
56
+ else {
57
+ const typeName = chunk.constructor.name || typeof chunk;
58
+ throw new Error(`Cannot write ${typeName} to DataChannel stream`);
59
+ }
60
+ }
61
+ catch (err) {
62
+ return callback(err);
63
+ }
64
+ if (sentOk) {
65
+ callback(null);
66
+ }
67
+ else {
68
+ callback(new Error("Failed to write to DataChannel"));
69
+ }
70
+ }
71
+ _final(callback) {
72
+ if (!this.allowHalfOpen)
73
+ this.destroy();
74
+ callback(null);
75
+ }
76
+ _destroy(maybeErr, callback) {
77
+ // When the stream is destroyed, we close the DataChannel.
78
+ this.rawChannel.close();
79
+ callback(maybeErr);
80
+ }
81
+ get label() {
82
+ return this.rawChannel.getLabel();
83
+ }
84
+ }
85
+ exports.DataChannelStream = DataChannelStream;
86
+ //# sourceMappingURL=datachannel-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"datachannel-stream.js","sourceRoot":"","sources":["../../src/webrtc/datachannel-stream.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,iCAAiC;AAGjC;;;;;;;GAOG;AACH,MAAa,iBAAkB,SAAQ,MAAM,CAAC,MAAM;IAEhD,YACY,UAAuC,EAC/C,gBAKI,EAAE;QAEN,KAAK,+BACD,aAAa,EAAE,KAAK,IACjB,aAAa,KAChB,UAAU,EAAE,IAAI,CAAC,0EAA0E;YAC7F,CAAC;QAZK,eAAU,GAAV,UAAU,CAA6B;QAsC3C,gBAAW,GAAG,IAAI,CAAC;QAxBvB,UAAU,CAAC,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE;YACzB,IAAI,CAAC,IAAI,CAAC,WAAW;gBAAE,OAAO,CAAC,wCAAwC;YAEvE,4EAA4E;YAC5E,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,kEAAkE;QAClE,UAAU,CAAC,QAAQ,CAAC,GAAG,EAAE;YACrB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChB,IAAI,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC,CAAC,CAAC;QAEH,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,sBAAsB,MAAM,EAAE,CAAC,CAAC,CAAC;QAC5D,CAAC,CAAC,CAAC;QAEH,gDAAgD;QAChD,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE;YACtB,IAAI,CAAC,IAAI,EAAE,CAAC;YACZ,UAAU,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;SAC1C;IACL,CAAC;IAGD,KAAK;QACD,kFAAkF;QAClF,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;IAC5B,CAAC;IAED,MAAM,CAAC,KAAgC,EAAE,QAAgB,EAAE,QAAuC;QAC9F,IAAI,MAAe,CAAC;QAEpB,IAAI;YACA,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;gBACxB,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC;aACrD;iBAAM,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;gBAClC,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;aAC/C;iBAAM;gBACH,MAAM,QAAQ,GAAI,KAAgB,CAAC,WAAW,CAAC,IAAI,IAAI,OAAO,KAAK,CAAC;gBACpE,MAAM,IAAI,KAAK,CAAC,gBAAgB,QAAQ,wBAAwB,CAAC,CAAC;aACrE;SACJ;QAAC,OAAO,GAAQ,EAAE;YACf,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC;SACxB;QAED,IAAI,MAAM,EAAE;YACR,QAAQ,CAAC,IAAI,CAAC,CAAC;SAClB;aAAM;YACH,QAAQ,CAAC,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC,CAAC;SACzD;IACL,CAAC;IAED,MAAM,CAAC,QAAuC;QAC1C,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,IAAI,CAAC,OAAO,EAAE,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,QAAQ,CAAC,QAAsB,EAAE,QAAuC;QACpE,0DAA0D;QAC1D,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QACxB,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,KAAK;QACL,OAAO,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;IACtC,CAAC;CAEJ;AArFD,8CAqFC"}
@@ -0,0 +1,29 @@
1
+ /// <reference types="node" />
2
+ import * as stream from 'stream';
3
+ import * as NodeDataChannel from 'node-datachannel';
4
+ /**
5
+ * Turns a node-datachannel media track into a real Node.js stream, complete with
6
+ * buffering, backpressure (up to a point - if the buffer fills up, messages are dropped),
7
+ * and support for piping data elsewhere.
8
+ */
9
+ export declare class MediaTrackStream extends stream.Duplex {
10
+ private rawTrack;
11
+ constructor(rawTrack: NodeDataChannel.Track, streamOptions?: {
12
+ readableHighWaterMark?: number | undefined;
13
+ writableHighWaterMark?: number | undefined;
14
+ allowHalfOpen?: boolean;
15
+ });
16
+ private close;
17
+ private _readActive;
18
+ _read(): void;
19
+ _write(chunk: Buffer, _encoding: string, callback: (error: Error | null) => void): void;
20
+ _writev(chunks: Array<{
21
+ chunk: any;
22
+ encoding: BufferEncoding;
23
+ }>, callback: (error?: Error | null) => void): void;
24
+ _final(callback: (error: Error | null) => void): void;
25
+ _destroy(maybeErr: Error | null, callback: (error: Error | null) => void): void;
26
+ get direction(): NodeDataChannel.Direction;
27
+ get mid(): string;
28
+ get type(): string;
29
+ }
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ /*
3
+ * SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.MediaTrackStream = void 0;
8
+ const stream = require("stream");
9
+ const NodeDataChannel = require("node-datachannel");
10
+ const { Direction } = NodeDataChannel;
11
+ /**
12
+ * Turns a node-datachannel media track into a real Node.js stream, complete with
13
+ * buffering, backpressure (up to a point - if the buffer fills up, messages are dropped),
14
+ * and support for piping data elsewhere.
15
+ */
16
+ class MediaTrackStream extends stream.Duplex {
17
+ constructor(rawTrack, streamOptions = {}) {
18
+ super(Object.assign({ allowHalfOpen: false }, streamOptions));
19
+ this.rawTrack = rawTrack;
20
+ this._readActive = true;
21
+ rawTrack.onMessage((msg) => {
22
+ if (!this._readActive)
23
+ return; // If the buffer is full, drop messages.
24
+ // If the push is rejected, we pause reading until the next call to _read().
25
+ this._readActive = this.push(msg);
26
+ });
27
+ // When the DataChannel closes, the readable & writable ends close
28
+ rawTrack.onClosed(() => this.close());
29
+ rawTrack.onError((errMsg) => {
30
+ this.destroy(new Error(`Media track error: ${errMsg}`));
31
+ });
32
+ // Buffer all writes until the DataChannel opens
33
+ if (!rawTrack.isOpen()) {
34
+ this.cork();
35
+ rawTrack.onOpen(() => this.uncork());
36
+ }
37
+ }
38
+ close() {
39
+ this.push(null);
40
+ this.destroy();
41
+ }
42
+ _read() {
43
+ // Stop dropping messages, if the buffer filling up meant we were doing so before.
44
+ this._readActive = true;
45
+ }
46
+ _write(chunk, _encoding, callback) {
47
+ let sentOk;
48
+ if (this.rawTrack.isClosed()) {
49
+ // isClosed becomes true and writes start failing just before onClosed() fires, so here we
50
+ // drop pending writes as soon as we notice.
51
+ this.close();
52
+ return;
53
+ }
54
+ try {
55
+ sentOk = this.rawTrack.sendMessageBinary(chunk);
56
+ }
57
+ catch (err) {
58
+ return callback(err);
59
+ }
60
+ if (sentOk) {
61
+ callback(null);
62
+ }
63
+ else {
64
+ callback(new Error("Failed to write to media track"));
65
+ }
66
+ }
67
+ _writev(chunks, callback) {
68
+ let sentOk;
69
+ if (this.rawTrack.isClosed()) {
70
+ // isClosed becomes true and writes start failing just before onClosed() fires, so here we
71
+ // drop pending writes as soon as we notice.
72
+ this.close();
73
+ return;
74
+ }
75
+ try {
76
+ sentOk = this.rawTrack.sendMessageBinary(Buffer.concat(chunks.map(c => c.chunk)));
77
+ }
78
+ catch (err) {
79
+ return callback(err);
80
+ }
81
+ if (sentOk) {
82
+ callback(null);
83
+ }
84
+ else {
85
+ callback(new Error("Failed to write to media track"));
86
+ }
87
+ }
88
+ _final(callback) {
89
+ if (!this.allowHalfOpen)
90
+ this.destroy();
91
+ callback(null);
92
+ }
93
+ _destroy(maybeErr, callback) {
94
+ // When the stream is destroyed, we close the DataChannel.
95
+ this.rawTrack.close();
96
+ callback(maybeErr);
97
+ }
98
+ get direction() {
99
+ return this.rawTrack.direction();
100
+ }
101
+ get mid() {
102
+ return this.rawTrack.mid();
103
+ }
104
+ get type() {
105
+ return this.rawTrack.type();
106
+ }
107
+ }
108
+ exports.MediaTrackStream = MediaTrackStream;
109
+ //# sourceMappingURL=mediatrack-stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mediatrack-stream.js","sourceRoot":"","sources":["../../src/webrtc/mediatrack-stream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import * as NodeDataChannel from 'node-datachannel';
2
+ import { DataChannelStream } from './datachannel-stream';
3
+ import { RTCConnection } from './rtc-connection';
4
+ export declare class MockRTCConnection extends RTCConnection {
5
+ private getExternalConnection;
6
+ private controlChannel;
7
+ private externalConnection;
8
+ constructor(getExternalConnection: (id: string) => RTCConnection);
9
+ protected trackNewChannel(channel: NodeDataChannel.DataChannel, options: {
10
+ isLocal: boolean;
11
+ }): DataChannelStream;
12
+ proxyTrafficToExternalConnection(): Promise<void>;
13
+ proxyTrafficTo(externalConnection: RTCConnection): void;
14
+ }
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ /*
3
+ * SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
7
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
8
+ return new (P || (P = Promise))(function (resolve, reject) {
9
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
10
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
11
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
12
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
13
+ });
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.MockRTCConnection = void 0;
17
+ const control_channel_1 = require("./control-channel");
18
+ const datachannel_stream_1 = require("./datachannel-stream");
19
+ const rtc_connection_1 = require("./rtc-connection");
20
+ class MockRTCConnection extends rtc_connection_1.RTCConnection {
21
+ constructor(getExternalConnection) {
22
+ super();
23
+ this.getExternalConnection = getExternalConnection;
24
+ }
25
+ trackNewChannel(channel, options) {
26
+ if (channel.getLabel() === control_channel_1.MOCKRTC_CONTROL_CHANNEL && !options.isLocal) {
27
+ // We don't track the control channel like other channels - we handle it specially.
28
+ if (this.controlChannel) {
29
+ const error = new Error('Cannot open multiple control channels simultaneously');
30
+ channel.sendMessage(JSON.stringify({
31
+ type: 'error',
32
+ error: error.message
33
+ }));
34
+ setTimeout(() => channel.close(), 100);
35
+ throw error;
36
+ }
37
+ this.controlChannel = new datachannel_stream_1.DataChannelStream(channel);
38
+ this.controlChannel.on('data', (msg) => {
39
+ var _a;
40
+ try {
41
+ const controlMessage = JSON.parse(msg);
42
+ if (controlMessage.type === 'attach-external') {
43
+ if (this.externalConnection) {
44
+ throw new Error('Cannot attach mock connection to multiple external connections');
45
+ }
46
+ this.externalConnection = this.getExternalConnection(controlMessage.id);
47
+ this.emit('external-connection-attached');
48
+ // We don't necessarily proxy traffic through to the external connection at this point,
49
+ // that depends on the specific handling that's used here.
50
+ }
51
+ else {
52
+ throw new Error(`Unrecognized control channel message: ${controlMessage.type}`);
53
+ }
54
+ }
55
+ catch (e) {
56
+ console.warn("Failed to handle control channel message", e);
57
+ (_a = this.controlChannel) === null || _a === void 0 ? void 0 : _a.write(JSON.stringify({
58
+ type: 'error',
59
+ error: e.message || e
60
+ }));
61
+ }
62
+ });
63
+ this.controlChannel.on('close', () => {
64
+ this.controlChannel = undefined;
65
+ });
66
+ this.controlChannel.on('error', (error) => {
67
+ console.error('Control channel error:', error);
68
+ });
69
+ return this.controlChannel;
70
+ }
71
+ else {
72
+ return super.trackNewChannel(channel, options);
73
+ }
74
+ }
75
+ proxyTrafficToExternalConnection() {
76
+ return __awaiter(this, void 0, void 0, function* () {
77
+ if (!this.externalConnection) {
78
+ yield new Promise((resolve) => this.once('external-connection-attached', resolve));
79
+ }
80
+ this.proxyTrafficTo(this.externalConnection);
81
+ });
82
+ }
83
+ proxyTrafficTo(externalConnection) {
84
+ /**
85
+ * When proxying traffic, you effectively have four peers, each with a connection endpoint:
86
+ * - The incoming RTCPeerConnection that we're mocking ('internal')
87
+ * - This MockRTC connection, with an associated MockRTCPeer that it will actually connect to ('mock')
88
+ * - A MockRTC external connection that will connect to the remote peer ('external')
89
+ * - The original remote peer that we're connecting to ('remote')
90
+ *
91
+ * Once the proxy is set up, the the connection structure works like so:
92
+ * INTERNAL <--> MOCK <--> EXTERNAL <--> REMOTE
93
+ *
94
+ * Here we connect the internal & external connections together, proxying all behaviours between the
95
+ * two so that from this point forwards every event on one is reflected on the other.
96
+ *
97
+ * Note that this isn't necessarily the initialization of either connection: the remote peer could
98
+ * have been connected for a while (sending data with no response), and the internal peer could have
99
+ * been fully interacting with steps before this point.
100
+ */
101
+ // Mirror connection closure:
102
+ this.on('connection-closed', () => externalConnection.close());
103
+ externalConnection.on('connection-closed', () => this.close());
104
+ /// --- Data channels: --- ///
105
+ // Forward *all* existing internal channels to the external connection:
106
+ this.channels.forEach((channel) => {
107
+ const mirrorChannelStream = externalConnection.createDataChannel(channel.label);
108
+ channel.pipe(mirrorChannelStream).pipe(channel);
109
+ });
110
+ // Forward any existing external channels back to this peer connection. Note that we're mirroring
111
+ // *remote* channels only, so we skip the channels that we've just created above.
112
+ externalConnection.remoteChannels.forEach((channel) => {
113
+ const mirrorChannelStream = this.createDataChannel(channel.label);
114
+ channel.pipe(mirrorChannelStream).pipe(channel);
115
+ });
116
+ // If any new channels open in future, mirror them to the other peer:
117
+ [[this, externalConnection], [externalConnection, this]].forEach(([connA, connB]) => {
118
+ connA.on('remote-channel-open', (incomingChannel) => {
119
+ const mirrorChannelStream = connB.createDataChannel(incomingChannel.label);
120
+ incomingChannel.pipe(mirrorChannelStream).pipe(incomingChannel);
121
+ });
122
+ });
123
+ /// --- Media tracks: --- ///
124
+ // Note that while data channels will *not* have been negotiated before this point, so
125
+ // we can always assume that mock data channels need mirroring, media tracks are negotiated
126
+ // in the SDP, not in-band, and so any media track could already exist on the other side.
127
+ // For each track on the internal connection, proxy it to the corresponding external track:
128
+ this.mediaTracks.forEach((track) => {
129
+ const externalStream = externalConnection.mediaTracks.find(({ mid }) => mid === track.mid);
130
+ if (externalStream) {
131
+ if (externalStream.type === track.type) {
132
+ track.pipe(externalStream).pipe(track);
133
+ }
134
+ else {
135
+ throw new Error(`Mock & external streams with mid ${track.mid} have mismatched types (${track.type}/${externalStream.type})`);
136
+ }
137
+ }
138
+ else {
139
+ // A mismatch in media streams means the external & mock peer negotiation isn't in sync!
140
+ // For now we just reject this case - later we should try to prompt a renegotiation.
141
+ throw new Error(`Mock has ${track.type} ${track.mid} but external does not`);
142
+ }
143
+ });
144
+ }
145
+ }
146
+ exports.MockRTCConnection = MockRTCConnection;
147
+ //# sourceMappingURL=mockrtc-connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockrtc-connection.js","sourceRoot":"","sources":["../../src/webrtc/mockrtc-connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+ import { DataChannelStream } from './datachannel-stream';
4
+ export declare class MockRTCPeerConnection extends EventEmitter {
5
+ private rawConn;
6
+ readonly channels: Array<DataChannelStream>;
7
+ constructor();
8
+ setRemoteDescription(description: RTCSessionDescriptionInit): void;
9
+ /**
10
+ * Gets the local description for this connection, waiting until gathering is complete to provide a
11
+ * full result. Because this waits for gathering, it will not resolve if no DataChannel, other
12
+ * tracks or remote description have been provided beforehand.
13
+ */
14
+ getLocalDescription(): Promise<RTCSessionDescriptionInit>;
15
+ close(): Promise<void>;
16
+ }
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.MockRTCPeerConnection = void 0;
13
+ const events_1 = require("events");
14
+ const NodeDataChannel = require("node-datachannel");
15
+ const datachannel_stream_1 = require("./datachannel-stream");
16
+ class MockRTCPeerConnection extends events_1.EventEmitter {
17
+ constructor() {
18
+ super();
19
+ this.rawConn = new NodeDataChannel.PeerConnection("MockRTCPeer", { iceServers: [] });
20
+ this.channels = [];
21
+ this.rawConn.onDataChannel((channel) => {
22
+ const channelStream = new datachannel_stream_1.DataChannelStream(channel);
23
+ this.channels.push(channelStream);
24
+ channel.onClosed(() => {
25
+ const channelIndex = this.channels.findIndex(c => c === channelStream);
26
+ if (channelIndex !== -1) {
27
+ this.channels.splice(channelIndex, 1);
28
+ }
29
+ });
30
+ channelStream.on('error', (error) => {
31
+ console.error('Channel error:', error);
32
+ });
33
+ this.emit('channel-open', channelStream);
34
+ });
35
+ }
36
+ setRemoteDescription(description) {
37
+ const { type: offerType, sdp: offerSdp } = description;
38
+ if (!offerSdp)
39
+ throw new Error("Cannot set MockRTC peer description without providing an SDP");
40
+ this.rawConn.setRemoteDescription(offerSdp, offerType[0].toUpperCase() + offerType.slice(1));
41
+ }
42
+ /**
43
+ * Gets the local description for this connection, waiting until gathering is complete to provide a
44
+ * full result. Because this waits for gathering, it will not resolve if no DataChannel, other
45
+ * tracks or remote description have been provided beforehand.
46
+ */
47
+ getLocalDescription() {
48
+ return __awaiter(this, void 0, void 0, function* () {
49
+ // TODO: Detect offer vs answer case here.
50
+ const setupChannel = this.rawConn.createDataChannel('mockttp.setup.channel');
51
+ yield new Promise((resolve) => {
52
+ this.rawConn.onGatheringStateChange((state) => {
53
+ if (state === 'complete')
54
+ resolve();
55
+ });
56
+ // Handle race conditions where gathering has already completed
57
+ if (this.rawConn.gatheringState() === 'complete')
58
+ resolve();
59
+ });
60
+ const sessionDescription = this.rawConn.localDescription();
61
+ setupChannel.close(); // TODO: Does this work? Goal is to get a channel without actually sending open msg.
62
+ return sessionDescription;
63
+ });
64
+ }
65
+ close() {
66
+ return __awaiter(this, void 0, void 0, function* () {
67
+ const closedPromise = new Promise((resolve) => {
68
+ if (this.rawConn.state() === 'closed')
69
+ resolve();
70
+ this.rawConn.onStateChange((state) => {
71
+ if (state === 'closed')
72
+ resolve();
73
+ });
74
+ });
75
+ this.rawConn.close();
76
+ yield closedPromise;
77
+ });
78
+ }
79
+ }
80
+ exports.MockRTCPeerConnection = MockRTCPeerConnection;
81
+ //# sourceMappingURL=peer-connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peer-connection.js","sourceRoot":"","sources":["../../src/webrtc/peer-connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+ import * as NodeDataChannel from 'node-datachannel';
4
+ import { MockRTCSession } from '../mockrtc-peer';
5
+ import { DataChannelStream } from './datachannel-stream';
6
+ import { MediaTrackStream } from './mediatrack-stream';
7
+ /**
8
+ * An RTC connection is a single connection. This base class defines the raw connection management and
9
+ * tracking logic for a generic connection. The MockRTCConnection subclass extends this and adds
10
+ * logic to support control channels, proxying and other MockRTC-specific additions.
11
+ */
12
+ export declare class RTCConnection extends EventEmitter {
13
+ readonly id: string;
14
+ private rawConn;
15
+ private remoteDescription;
16
+ private readonly trackedChannels;
17
+ get channels(): ReadonlyArray<DataChannelStream>;
18
+ get localChannels(): ReadonlyArray<DataChannelStream>;
19
+ get remoteChannels(): ReadonlyArray<DataChannelStream>;
20
+ private readonly trackedMediaTracks;
21
+ get mediaTracks(): ReadonlyArray<MediaTrackStream>;
22
+ get localMediaTracks(): ReadonlyArray<MediaTrackStream>;
23
+ get remoteMediaTracks(): ReadonlyArray<MediaTrackStream>;
24
+ constructor();
25
+ createDataChannel(label: string): DataChannelStream;
26
+ protected trackNewChannel(channel: NodeDataChannel.DataChannel, options: {
27
+ isLocal: boolean;
28
+ }): DataChannelStream;
29
+ protected trackNewMediaTrack(track: NodeDataChannel.Track, options: {
30
+ isLocal: boolean;
31
+ }): MediaTrackStream;
32
+ setRemoteDescription(description: RTCSessionDescriptionInit): void;
33
+ /**
34
+ * Gets the local description for this connection, waiting until gathering is complete to provide a
35
+ * full result. Because this waits for gathering, it will not resolve if no DataChannel, other
36
+ * tracks or remote description have been provided beforehand.
37
+ */
38
+ getLocalDescription(): Promise<RTCSessionDescriptionInit>;
39
+ getRemoteDescription(): RTCSessionDescriptionInit | undefined;
40
+ getMirroredLocalOffer(sdpToMirror: string, options?: {
41
+ addDataStream?: boolean;
42
+ }): Promise<RTCSessionDescriptionInit>;
43
+ getMirroredLocalAnswer(sdpToMirror: string): Promise<RTCSessionDescriptionInit>;
44
+ waitUntilConnected(): Promise<void>;
45
+ readonly sessionApi: MockRTCSession;
46
+ close(): Promise<void>;
47
+ }