mockrtc 0.1.0 → 0.3.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.
- package/.github/workflows/ci.yml +2 -2
- package/README.md +2 -2
- package/dist/client/mockrtc-admin-request-builder.d.ts +27 -0
- package/dist/client/mockrtc-admin-request-builder.js +201 -0
- package/dist/client/mockrtc-admin-request-builder.js.map +1 -0
- package/dist/client/mockrtc-client.d.ts +12 -4
- package/dist/client/mockrtc-client.js +38 -22
- package/dist/client/mockrtc-client.js.map +1 -1
- package/dist/client/mockrtc-remote-peer.d.ts +3 -2
- package/dist/client/mockrtc-remote-peer.js.map +1 -1
- package/dist/handling/handler-builder.d.ts +16 -9
- package/dist/handling/handler-builder.js +11 -1
- package/dist/handling/handler-builder.js.map +1 -1
- package/dist/handling/handler-step-definitions.d.ts +43 -25
- package/dist/handling/handler-step-definitions.js +61 -19
- package/dist/handling/handler-step-definitions.js.map +1 -1
- package/dist/handling/handler-steps.d.ts +4 -1
- package/dist/handling/handler-steps.js +27 -17
- package/dist/handling/handler-steps.js.map +1 -1
- package/dist/main-browser.d.ts +3 -0
- package/dist/main-browser.js +6 -1
- package/dist/main-browser.js.map +1 -1
- package/dist/main.d.ts +8 -5
- package/dist/main.js +6 -1
- package/dist/main.js.map +1 -1
- package/dist/matching/matcher-definitions.d.ts +51 -0
- package/dist/matching/matcher-definitions.js +94 -0
- package/dist/matching/matcher-definitions.js.map +1 -0
- package/dist/matching/matchers.d.ts +27 -0
- package/dist/matching/matchers.js +87 -0
- package/dist/matching/matchers.js.map +1 -0
- package/dist/mockrtc-base.d.ts +16 -0
- package/dist/mockrtc-base.js +19 -0
- package/dist/mockrtc-base.js.map +1 -0
- package/dist/mockrtc-peer.d.ts +44 -6
- package/dist/mockrtc.d.ts +200 -1
- package/dist/mockrtc.js +1 -0
- package/dist/mockrtc.js.map +1 -1
- package/dist/rule-builder.d.ts +86 -0
- package/dist/rule-builder.js +113 -0
- package/dist/rule-builder.js.map +1 -0
- package/dist/server/mockrtc-admin-plugin.d.ts +2 -2
- package/dist/server/mockrtc-admin-plugin.js +165 -3
- package/dist/server/mockrtc-admin-plugin.js.map +1 -1
- package/dist/server/mockrtc-server-peer.d.ts +8 -2
- package/dist/server/mockrtc-server-peer.js +119 -6
- package/dist/server/mockrtc-server-peer.js.map +1 -1
- package/dist/server/mockrtc-server.d.ts +20 -5
- package/dist/server/mockrtc-server.js +87 -14
- package/dist/server/mockrtc-server.js.map +1 -1
- package/dist/webrtc/datachannel-stream.d.ts +4 -0
- package/dist/webrtc/datachannel-stream.js +27 -1
- package/dist/webrtc/datachannel-stream.js.map +1 -1
- package/dist/webrtc/mediatrack-stream.d.ts +6 -0
- package/dist/webrtc/mediatrack-stream.js +28 -2
- package/dist/webrtc/mediatrack-stream.js.map +1 -1
- package/dist/webrtc/mockrtc-connection.d.ts +1 -1
- package/dist/webrtc/mockrtc-connection.js +77 -60
- package/dist/webrtc/mockrtc-connection.js.map +1 -1
- package/dist/webrtc/rtc-connection.d.ts +28 -5
- package/dist/webrtc/rtc-connection.js +62 -23
- package/dist/webrtc/rtc-connection.js.map +1 -1
- package/dist/webrtc-hooks.js +10 -2
- package/dist/webrtc-hooks.js.map +1 -1
- package/package.json +12 -6
- package/src/client/mockrtc-admin-request-builder.ts +232 -0
- package/src/client/mockrtc-client.ts +50 -28
- package/src/client/mockrtc-remote-peer.ts +9 -8
- package/src/handling/handler-builder.ts +22 -10
- package/src/handling/handler-step-definitions.ts +87 -27
- package/src/handling/handler-steps.ts +34 -20
- package/src/main-browser.ts +5 -0
- package/src/main.ts +23 -5
- package/src/matching/matcher-definitions.ts +109 -0
- package/src/matching/matchers.ts +118 -0
- package/src/mockrtc-base.ts +49 -0
- package/src/mockrtc-peer.ts +48 -6
- package/src/mockrtc.ts +235 -1
- package/src/rule-builder.ts +142 -0
- package/src/server/mockrtc-admin-plugin.ts +200 -9
- package/src/server/mockrtc-server-peer.ts +194 -7
- package/src/server/mockrtc-server.ts +136 -19
- package/src/webrtc/datachannel-stream.ts +31 -1
- package/src/webrtc/mediatrack-stream.ts +31 -4
- package/src/webrtc/mockrtc-connection.ts +22 -7
- package/src/webrtc/rtc-connection.ts +111 -29
- package/src/webrtc-hooks.ts +13 -4
- package/test/integration/events.spec.ts +538 -0
- package/test/integration/matching.spec.ts +257 -0
- package/test/integration/proxy.spec.ts +68 -1
- package/test/integration/send-steps.spec.ts +25 -0
- package/test/test-setup.ts +19 -0
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import gql from 'graphql-tag';
|
|
7
6
|
|
|
8
7
|
// Long-term, it'd be great to use the 'official' export path of mockttp/pluggable-admin, but
|
|
9
8
|
// if we do so, then TypeScript <4.7 doesn't understand it here or downstream, so we get errors.
|
|
@@ -12,61 +11,69 @@ import gql from 'graphql-tag';
|
|
|
12
11
|
import * as BrowserPluggableAdmin from 'mockttp/dist/pluggable-admin-api/pluggable-admin.browser';
|
|
13
12
|
import type { PluggableAdmin } from 'mockttp';
|
|
14
13
|
|
|
15
|
-
import { MockRTC, MockRTCOptions,
|
|
14
|
+
import { MockRTC, MockRTCEvent, MockRTCOptions, MockRTCRuleDefinition } from "../mockrtc";
|
|
15
|
+
import { MockRTCBase } from '../mockrtc-base';
|
|
16
16
|
|
|
17
|
-
import type { MockRTCAdminPlugin } from "../server/mockrtc-admin-plugin";
|
|
18
17
|
import type { MockRTCPeer } from '../mockrtc-peer';
|
|
19
18
|
import { MockRTCRemotePeer } from './mockrtc-remote-peer';
|
|
20
|
-
import {
|
|
19
|
+
import type { MockRTCAdminPlugin } from "../server/mockrtc-admin-plugin";
|
|
20
|
+
import { MockRTCAdminRequestBuilder } from './mockrtc-admin-request-builder';
|
|
21
21
|
import { HandlerStepDefinition } from '../handling/handler-step-definitions';
|
|
22
|
+
import { MatcherDefinition } from '../matching/matcher-definitions';
|
|
22
23
|
|
|
23
24
|
export type MockRTCClientOptions =
|
|
24
25
|
PluggableAdmin.AdminClientOptions &
|
|
25
26
|
MockRTCOptions;
|
|
26
27
|
|
|
27
|
-
export class MockRTCClient implements MockRTC {
|
|
28
|
+
export class MockRTCClient extends MockRTCBase implements MockRTC {
|
|
28
29
|
|
|
29
30
|
private adminClient: PluggableAdmin.AdminClient<{ webrtc: MockRTCAdminPlugin }>;
|
|
31
|
+
private requestBuilder: MockRTCAdminRequestBuilder;
|
|
30
32
|
|
|
31
33
|
constructor(
|
|
32
34
|
private options: MockRTCClientOptions = {}
|
|
33
35
|
) {
|
|
36
|
+
super();
|
|
37
|
+
|
|
34
38
|
this.adminClient = new BrowserPluggableAdmin.AdminClient(options);
|
|
39
|
+
this.requestBuilder = new MockRTCAdminRequestBuilder();
|
|
35
40
|
}
|
|
36
41
|
|
|
37
|
-
|
|
38
|
-
return new
|
|
42
|
+
getMatchingPeer(): MockRTCPeer {
|
|
43
|
+
return new MockRTCRemotePeer('matching-peer', this.adminClient);
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
async buildPeerFromDefinition(handlerSteps: HandlerStepDefinition[]): Promise<MockRTCPeer> {
|
|
42
47
|
const { adminStream } = this.adminClient;
|
|
43
48
|
|
|
44
|
-
const peerData = await this.adminClient.sendQuery
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
>({
|
|
48
|
-
query: gql`
|
|
49
|
-
mutation CreatePeer($peerData: RTCHandlerData!) {
|
|
50
|
-
createPeer(data: $peerData) {
|
|
51
|
-
peerId
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
`,
|
|
55
|
-
variables: {
|
|
56
|
-
peerData: {
|
|
57
|
-
steps: handlerSteps.map(step =>
|
|
58
|
-
BrowserPluggableAdmin.Serialization.serialize(step, adminStream)
|
|
59
|
-
)
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
transformResponse: ({ createPeer }) => createPeer
|
|
63
|
-
});
|
|
49
|
+
const peerData = await this.adminClient.sendQuery(
|
|
50
|
+
this.requestBuilder.buildCreatePeerQuery(handlerSteps, adminStream)
|
|
51
|
+
);
|
|
64
52
|
|
|
65
53
|
const { peerId } = peerData;
|
|
66
54
|
|
|
67
55
|
return new MockRTCRemotePeer(peerId, this.adminClient);
|
|
68
56
|
}
|
|
69
57
|
|
|
58
|
+
async addRuleFromDefinition(
|
|
59
|
+
matchers: MatcherDefinition[],
|
|
60
|
+
handlerSteps: HandlerStepDefinition[]
|
|
61
|
+
) {
|
|
62
|
+
const { adminStream } = this.adminClient;
|
|
63
|
+
|
|
64
|
+
await this.adminClient.sendQuery(
|
|
65
|
+
this.requestBuilder.buildAddRuleQuery(matchers, handlerSteps, adminStream)
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async setRulesFromDefinitions(rules: Array<MockRTCRuleDefinition>) {
|
|
70
|
+
const { adminStream } = this.adminClient;
|
|
71
|
+
|
|
72
|
+
await this.adminClient.sendQuery(
|
|
73
|
+
this.requestBuilder.buildSetRulesQuery(rules, adminStream)
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
70
77
|
async start(): Promise<void> {
|
|
71
78
|
await this.adminClient.start({
|
|
72
79
|
webrtc: this.options
|
|
@@ -76,4 +83,19 @@ export class MockRTCClient implements MockRTC {
|
|
|
76
83
|
async stop(): Promise<void> {
|
|
77
84
|
await this.adminClient.stop();
|
|
78
85
|
}
|
|
86
|
+
|
|
87
|
+
async on(event: MockRTCEvent, callback: any): Promise<void> {
|
|
88
|
+
const subscriptionRequest = this.requestBuilder.buildSubscriptionRequest(event);
|
|
89
|
+
|
|
90
|
+
if (!subscriptionRequest) {
|
|
91
|
+
// We just return an immediately promise if we don't recognize the event, which will quietly
|
|
92
|
+
// succeed but never call the corresponding callback (the same as the server and most event
|
|
93
|
+
// sources in the same kind of situation). This is what happens when the *client* doesn't
|
|
94
|
+
// recognize the event. Subscribe() below handles the unknown-to-server case.
|
|
95
|
+
console.warn(`Ignoring subscription for event unrecognized by MockRTC client: ${event}`);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return this.adminClient.subscribe(subscriptionRequest, callback);
|
|
100
|
+
}
|
|
79
101
|
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { gql } from 'graphql-tag';
|
|
7
7
|
import * as PluggableAdmin from 'mockttp/dist/pluggable-admin-api/pluggable-admin.browser';
|
|
8
8
|
|
|
9
|
+
import { MockRTCSessionDescription } from '../mockrtc';
|
|
9
10
|
import {
|
|
10
11
|
MockRTCPeer,
|
|
11
12
|
MockRTCOfferParams,
|
|
@@ -83,7 +84,7 @@ export class MockRTCRemotePeer implements MockRTCPeer {
|
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
async answerOffer(
|
|
86
|
-
offer:
|
|
87
|
+
offer: MockRTCSessionDescription,
|
|
87
88
|
options?: AnswerOptions
|
|
88
89
|
): Promise<MockRTCAnswerParams> {
|
|
89
90
|
return this.adminClient.sendQuery<
|
|
@@ -114,7 +115,7 @@ export class MockRTCRemotePeer implements MockRTCPeer {
|
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
async answerExternalOffer(
|
|
117
|
-
offer:
|
|
118
|
+
offer: MockRTCSessionDescription,
|
|
118
119
|
options?: AnswerOptions
|
|
119
120
|
): Promise<MockRTCExternalAnswerParams> {
|
|
120
121
|
return this.adminClient.sendQuery<
|
|
@@ -211,10 +212,10 @@ class RemoteSessionApi implements MockRTCSession {
|
|
|
211
212
|
public readonly sessionId: string
|
|
212
213
|
) {}
|
|
213
214
|
|
|
214
|
-
createOffer(options?: OfferOptions): Promise<
|
|
215
|
+
createOffer(options?: OfferOptions): Promise<MockRTCSessionDescription> {
|
|
215
216
|
return this.adminClient.sendQuery<
|
|
216
217
|
{ createOffer: SessionData },
|
|
217
|
-
|
|
218
|
+
MockRTCSessionDescription
|
|
218
219
|
>({
|
|
219
220
|
query: gql`
|
|
220
221
|
mutation GetPeerRTCSessionOffer($peerId: ID!, $sessionId: ID!, $options: Raw) {
|
|
@@ -231,7 +232,7 @@ class RemoteSessionApi implements MockRTCSession {
|
|
|
231
232
|
});
|
|
232
233
|
}
|
|
233
234
|
|
|
234
|
-
completeOffer(answer:
|
|
235
|
+
completeOffer(answer: MockRTCSessionDescription): Promise<void> {
|
|
235
236
|
return this.adminClient.sendQuery<void>({
|
|
236
237
|
query: gql`
|
|
237
238
|
mutation CompletePeerRTCOffer(
|
|
@@ -251,12 +252,12 @@ class RemoteSessionApi implements MockRTCSession {
|
|
|
251
252
|
}
|
|
252
253
|
|
|
253
254
|
answerOffer(
|
|
254
|
-
offer:
|
|
255
|
+
offer: MockRTCSessionDescription,
|
|
255
256
|
options?: AnswerOptions
|
|
256
|
-
): Promise<
|
|
257
|
+
): Promise<MockRTCSessionDescription> {
|
|
257
258
|
return this.adminClient.sendQuery<
|
|
258
259
|
{ answerOffer: SessionData },
|
|
259
|
-
|
|
260
|
+
MockRTCSessionDescription
|
|
260
261
|
>({
|
|
261
262
|
query: gql`
|
|
262
263
|
mutation GetPeerRTCAnswer(
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import {
|
|
7
7
|
type HandlerStepDefinition,
|
|
8
8
|
PeerProxyStepDefinition,
|
|
9
|
+
CreateChannelStepDefinition,
|
|
9
10
|
SendStepDefinition,
|
|
10
11
|
DynamicProxyStepDefinition,
|
|
11
12
|
WaitForChannelStepDefinition,
|
|
@@ -35,7 +36,7 @@ export class MockRTCHandlerBuilder<R> {
|
|
|
35
36
|
*
|
|
36
37
|
* @category Steps
|
|
37
38
|
*/
|
|
38
|
-
sleep(duration: number):
|
|
39
|
+
sleep(duration: number): MockRTCHandlerBuilder<R> {
|
|
39
40
|
this.handlerSteps.push(new WaitForDurationStepDefinition(duration));
|
|
40
41
|
return this;
|
|
41
42
|
}
|
|
@@ -45,7 +46,7 @@ export class MockRTCHandlerBuilder<R> {
|
|
|
45
46
|
*
|
|
46
47
|
* @category Steps
|
|
47
48
|
*/
|
|
48
|
-
waitForChannel(channelLabel?: string):
|
|
49
|
+
waitForChannel(channelLabel?: string): MockRTCHandlerBuilder<R> {
|
|
49
50
|
this.handlerSteps.push(new WaitForChannelStepDefinition(channelLabel));
|
|
50
51
|
return this;
|
|
51
52
|
}
|
|
@@ -55,7 +56,7 @@ export class MockRTCHandlerBuilder<R> {
|
|
|
55
56
|
*
|
|
56
57
|
* @category Steps
|
|
57
58
|
*/
|
|
58
|
-
waitForTrack():
|
|
59
|
+
waitForTrack(): MockRTCHandlerBuilder<R> {
|
|
59
60
|
this.handlerSteps.push(new WaitForTrackStepDefinition());
|
|
60
61
|
return this;
|
|
61
62
|
}
|
|
@@ -68,7 +69,7 @@ export class MockRTCHandlerBuilder<R> {
|
|
|
68
69
|
*
|
|
69
70
|
* @category Steps
|
|
70
71
|
*/
|
|
71
|
-
waitForNextMessage():
|
|
72
|
+
waitForNextMessage(): MockRTCHandlerBuilder<R> {
|
|
72
73
|
this.handlerSteps.push(new WaitForMessageStepDefinition());
|
|
73
74
|
return this;
|
|
74
75
|
}
|
|
@@ -80,7 +81,7 @@ export class MockRTCHandlerBuilder<R> {
|
|
|
80
81
|
*
|
|
81
82
|
* @category Steps
|
|
82
83
|
*/
|
|
83
|
-
waitForNextMedia():
|
|
84
|
+
waitForNextMedia(): MockRTCHandlerBuilder<R> {
|
|
84
85
|
this.handlerSteps.push(new WaitForMediaStepDefinition());
|
|
85
86
|
return this;
|
|
86
87
|
}
|
|
@@ -91,13 +92,24 @@ export class MockRTCHandlerBuilder<R> {
|
|
|
91
92
|
* This looks for new messages, ignoring any messages already consumed by
|
|
92
93
|
* previous steps.
|
|
93
94
|
*
|
|
94
|
-
|
|
95
|
+
* @category Steps
|
|
95
96
|
*/
|
|
96
|
-
waitForNextMessageOnChannel(channelLabel: string):
|
|
97
|
+
waitForNextMessageOnChannel(channelLabel: string): MockRTCHandlerBuilder<R> {
|
|
97
98
|
this.handlerSteps.push(new WaitForMessageStepDefinition(channelLabel));
|
|
98
99
|
return this;
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
/**
|
|
103
|
+
* Creates a new data channel with the given name, waiting until it opens
|
|
104
|
+
* before continuing.
|
|
105
|
+
*
|
|
106
|
+
* @category Steps
|
|
107
|
+
*/
|
|
108
|
+
createDataChannel(channelLabel: string): MockRTCHandlerBuilder<R> {
|
|
109
|
+
this.handlerSteps.push(new CreateChannelStepDefinition(channelLabel));
|
|
110
|
+
return this;
|
|
111
|
+
}
|
|
112
|
+
|
|
101
113
|
/**
|
|
102
114
|
* Send a message or buffer on the connection's data channels.
|
|
103
115
|
*
|
|
@@ -111,9 +123,9 @@ export class MockRTCHandlerBuilder<R> {
|
|
|
111
123
|
*
|
|
112
124
|
* @category Steps
|
|
113
125
|
*/
|
|
114
|
-
send(message: string | Buffer):
|
|
115
|
-
send(channel: string | undefined, message: string | Buffer):
|
|
116
|
-
send(...args: [string | undefined, string | Buffer] | [string | Buffer]):
|
|
126
|
+
send(message: string | Buffer): MockRTCHandlerBuilder<R>;
|
|
127
|
+
send(channel: string | undefined, message: string | Buffer): MockRTCHandlerBuilder<R>;
|
|
128
|
+
send(...args: [string | undefined, string | Buffer] | [string | Buffer]): MockRTCHandlerBuilder<R> {
|
|
117
129
|
if (args[1] !== undefined) {
|
|
118
130
|
const [channel, message] = args as [string, string | Buffer];
|
|
119
131
|
this.handlerSteps.push(new SendStepDefinition(channel, message));
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
import * as PluggableAdmin from 'mockttp/dist/pluggable-admin-api/pluggable-admin.browser';
|
|
7
7
|
|
|
8
|
+
import { MockRTCSessionDescription } from '../mockrtc';
|
|
9
|
+
|
|
8
10
|
export type Serializable = PluggableAdmin.Serialization.Serializable;
|
|
9
11
|
export const { Serializable } = PluggableAdmin.Serialization;
|
|
10
12
|
type ClientServerChannel = PluggableAdmin.Serialization.ClientServerChannel;
|
|
@@ -18,89 +20,138 @@ export class WaitForDurationStepDefinition extends Serializable implements Handl
|
|
|
18
20
|
readonly type = 'wait-for-duration';
|
|
19
21
|
|
|
20
22
|
constructor(
|
|
21
|
-
|
|
23
|
+
public readonly durationMs: number
|
|
22
24
|
) {
|
|
23
25
|
super();
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
explain() {
|
|
29
|
+
return `wait for ${this.durationMs}ms`;
|
|
30
|
+
}
|
|
31
|
+
|
|
26
32
|
}
|
|
27
33
|
|
|
28
34
|
export class WaitForChannelStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
29
35
|
|
|
30
|
-
readonly type = 'wait-for-channel';
|
|
36
|
+
readonly type = 'wait-for-rtc-data-channel';
|
|
31
37
|
|
|
32
38
|
constructor(
|
|
33
|
-
|
|
39
|
+
public readonly channelLabel?: string
|
|
34
40
|
) {
|
|
35
41
|
super();
|
|
36
42
|
}
|
|
43
|
+
|
|
44
|
+
explain() {
|
|
45
|
+
return `wait for an RTC channel${this.channelLabel ? ` labelled '${this.channelLabel}'` : ''}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
37
48
|
}
|
|
38
49
|
|
|
39
50
|
export class WaitForMessageStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
40
51
|
|
|
41
|
-
readonly type = 'wait-for-message';
|
|
52
|
+
readonly type = 'wait-for-rtc-message';
|
|
42
53
|
|
|
43
54
|
constructor(
|
|
44
|
-
|
|
55
|
+
public readonly channelLabel?: string
|
|
45
56
|
) {
|
|
46
57
|
super();
|
|
47
58
|
}
|
|
48
59
|
|
|
60
|
+
explain() {
|
|
61
|
+
return `wait for an RTC message${this.channelLabel ? ` on channel '${this.channelLabel}'` : ''}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
49
64
|
}
|
|
50
65
|
|
|
51
66
|
export class WaitForTrackStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
52
67
|
|
|
53
|
-
readonly type = 'wait-for-track';
|
|
68
|
+
readonly type = 'wait-for-rtc-track';
|
|
69
|
+
|
|
70
|
+
explain() {
|
|
71
|
+
return `wait for an RTC track`;
|
|
72
|
+
}
|
|
54
73
|
|
|
55
74
|
}
|
|
56
75
|
|
|
57
76
|
export class WaitForMediaStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
58
77
|
|
|
59
|
-
readonly type = 'wait-for-media';
|
|
78
|
+
readonly type = 'wait-for-rtc-media';
|
|
79
|
+
|
|
80
|
+
explain() {
|
|
81
|
+
return `wait for RTC media data`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class CreateChannelStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
87
|
+
|
|
88
|
+
readonly type = 'create-rtc-data-channel';
|
|
89
|
+
|
|
90
|
+
constructor(
|
|
91
|
+
public readonly channelLabel: string
|
|
92
|
+
) {
|
|
93
|
+
super();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
explain() {
|
|
97
|
+
return `create an RTC data channel labelled '${this.channelLabel}'`;
|
|
98
|
+
}
|
|
60
99
|
|
|
61
100
|
}
|
|
62
101
|
|
|
63
102
|
export class SendStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
64
103
|
|
|
65
|
-
readonly type = 'send-message';
|
|
104
|
+
readonly type = 'send-rtc-data-message';
|
|
66
105
|
|
|
67
106
|
constructor(
|
|
68
|
-
|
|
69
|
-
|
|
107
|
+
public readonly channelLabel: string | undefined,
|
|
108
|
+
public readonly message: string | Buffer
|
|
70
109
|
) {
|
|
71
110
|
super();
|
|
72
111
|
}
|
|
73
112
|
|
|
113
|
+
explain() {
|
|
114
|
+
return `send an RTC data message${this.channelLabel ? ` on channel '${this.channelLabel}'` : ''}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
74
117
|
}
|
|
75
118
|
|
|
76
119
|
export class CloseStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
77
120
|
|
|
78
|
-
readonly type = 'close-connection';
|
|
121
|
+
readonly type = 'close-rtc-connection';
|
|
122
|
+
|
|
123
|
+
explain() {
|
|
124
|
+
return `close the RTC connection`;
|
|
125
|
+
}
|
|
79
126
|
|
|
80
127
|
}
|
|
81
128
|
|
|
82
129
|
export class EchoStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
83
130
|
|
|
84
|
-
readonly type = 'echo-
|
|
131
|
+
readonly type = 'echo-rtc';
|
|
132
|
+
|
|
133
|
+
explain() {
|
|
134
|
+
return `echo all RTC media & data`;
|
|
135
|
+
}
|
|
85
136
|
|
|
86
137
|
}
|
|
87
138
|
|
|
88
139
|
export class PeerProxyStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
89
140
|
|
|
90
|
-
readonly type = 'peer-proxy';
|
|
141
|
+
readonly type = 'rtc-peer-proxy';
|
|
91
142
|
|
|
92
|
-
protected getAnswer: (offer:
|
|
143
|
+
protected getAnswer: (offer: MockRTCSessionDescription) => Promise<RTCSessionDescriptionInit>;
|
|
93
144
|
|
|
94
145
|
constructor(
|
|
95
146
|
connectionTarget:
|
|
96
147
|
| RTCPeerConnection
|
|
97
|
-
| ((offer:
|
|
148
|
+
| ((offer: MockRTCSessionDescription) => Promise<RTCSessionDescriptionInit>)
|
|
98
149
|
) {
|
|
99
150
|
super();
|
|
100
151
|
if (connectionTarget instanceof Function) {
|
|
101
152
|
this.getAnswer = connectionTarget;
|
|
102
153
|
} else {
|
|
103
|
-
this.getAnswer = async (offer:
|
|
154
|
+
this.getAnswer = async (offer: MockRTCSessionDescription) => {
|
|
104
155
|
await connectionTarget.setRemoteDescription(offer);
|
|
105
156
|
const answer = await connectionTarget.createAnswer();
|
|
106
157
|
await connectionTarget.setLocalDescription(answer);
|
|
@@ -109,9 +160,13 @@ export class PeerProxyStepDefinition extends Serializable implements HandlerStep
|
|
|
109
160
|
}
|
|
110
161
|
}
|
|
111
162
|
|
|
163
|
+
explain() {
|
|
164
|
+
return `proxy the RTC connection to the configured peer`;
|
|
165
|
+
}
|
|
166
|
+
|
|
112
167
|
serialize(channel: ClientServerChannel): {} {
|
|
113
168
|
channel.onRequest<
|
|
114
|
-
{ offer:
|
|
169
|
+
{ offer: MockRTCSessionDescription },
|
|
115
170
|
{ answer: RTCSessionDescriptionInit }
|
|
116
171
|
>(async (msg) => {
|
|
117
172
|
return { answer: await this.getAnswer(msg.offer) };
|
|
@@ -124,19 +179,24 @@ export class PeerProxyStepDefinition extends Serializable implements HandlerStep
|
|
|
124
179
|
|
|
125
180
|
export class DynamicProxyStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
126
181
|
|
|
127
|
-
readonly type = 'dynamic-proxy';
|
|
182
|
+
readonly type = 'rtc-dynamic-proxy';
|
|
183
|
+
|
|
184
|
+
explain() {
|
|
185
|
+
return `proxy the RTC connection to a remote peer`;
|
|
186
|
+
}
|
|
128
187
|
|
|
129
188
|
}
|
|
130
189
|
|
|
131
190
|
export const StepDefinitionLookup = {
|
|
132
191
|
'wait-for-duration': WaitForDurationStepDefinition,
|
|
133
|
-
'wait-for-channel': WaitForChannelStepDefinition,
|
|
134
|
-
'wait-for-track': WaitForTrackStepDefinition,
|
|
135
|
-
'wait-for-media': WaitForMediaStepDefinition,
|
|
136
|
-
'wait-for-message': WaitForMessageStepDefinition,
|
|
137
|
-
'
|
|
138
|
-
'
|
|
139
|
-
'
|
|
140
|
-
'
|
|
141
|
-
'
|
|
192
|
+
'wait-for-rtc-data-channel': WaitForChannelStepDefinition,
|
|
193
|
+
'wait-for-rtc-track': WaitForTrackStepDefinition,
|
|
194
|
+
'wait-for-rtc-media': WaitForMediaStepDefinition,
|
|
195
|
+
'wait-for-rtc-message': WaitForMessageStepDefinition,
|
|
196
|
+
'create-rtc-data-channel': CreateChannelStepDefinition,
|
|
197
|
+
'send-rtc-data-message': SendStepDefinition,
|
|
198
|
+
'close-rtc-connection': CloseStepDefinition,
|
|
199
|
+
'echo-rtc': EchoStepDefinition,
|
|
200
|
+
'rtc-peer-proxy': PeerProxyStepDefinition,
|
|
201
|
+
'rtc-dynamic-proxy': DynamicProxyStepDefinition
|
|
142
202
|
};
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { PluggableAdmin } from 'mockttp';
|
|
7
7
|
|
|
8
|
+
import { MockRTCSessionDescription } from '../mockrtc';
|
|
8
9
|
import type { DataChannelStream } from '../webrtc/datachannel-stream';
|
|
9
10
|
import type { MediaTrackStream } from '../webrtc/mediatrack-stream';
|
|
10
11
|
import type { MockRTCConnection } from '../webrtc/mockrtc-connection';
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
EchoStepDefinition,
|
|
17
18
|
HandlerStepDefinition,
|
|
18
19
|
PeerProxyStepDefinition,
|
|
20
|
+
CreateChannelStepDefinition,
|
|
19
21
|
SendStepDefinition,
|
|
20
22
|
WaitForChannelStepDefinition,
|
|
21
23
|
WaitForDurationStepDefinition,
|
|
@@ -69,7 +71,7 @@ export class WaitForMessageStep extends WaitForMessageStepDefinition {
|
|
|
69
71
|
async handle(connection: MockRTCConnection): Promise<void> {
|
|
70
72
|
return new Promise<void>((resolve) => {
|
|
71
73
|
const messageReceived = () => {
|
|
72
|
-
connection.removeListener('channel-
|
|
74
|
+
connection.removeListener('channel-created', listenForMessage);
|
|
73
75
|
connection.channels.forEach((channel) => {
|
|
74
76
|
channel.removeListener('data', messageReceived);
|
|
75
77
|
channel.pause();
|
|
@@ -84,7 +86,7 @@ export class WaitForMessageStep extends WaitForMessageStepDefinition {
|
|
|
84
86
|
}
|
|
85
87
|
}
|
|
86
88
|
|
|
87
|
-
connection.on('channel-
|
|
89
|
+
connection.on('channel-created', listenForMessage);
|
|
88
90
|
connection.channels.forEach(listenForMessage);
|
|
89
91
|
});
|
|
90
92
|
}
|
|
@@ -107,7 +109,7 @@ export class WaitForMediaStep extends WaitForMediaStepDefinition {
|
|
|
107
109
|
async handle(connection: MockRTCConnection): Promise<void> {
|
|
108
110
|
return new Promise<void>((resolve) => {
|
|
109
111
|
const messageReceived = () => {
|
|
110
|
-
connection.removeListener('track-
|
|
112
|
+
connection.removeListener('track-created', listenForData);
|
|
111
113
|
connection.mediaTracks.forEach((track) => {
|
|
112
114
|
track.removeListener('data', messageReceived);
|
|
113
115
|
track.pause();
|
|
@@ -120,13 +122,24 @@ export class WaitForMediaStep extends WaitForMediaStepDefinition {
|
|
|
120
122
|
track.once('data', messageReceived);
|
|
121
123
|
}
|
|
122
124
|
|
|
123
|
-
connection.on('track-
|
|
125
|
+
connection.on('track-created', listenForData);
|
|
124
126
|
connection.mediaTracks.forEach(listenForData);
|
|
125
127
|
});
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
}
|
|
129
131
|
|
|
132
|
+
export class CreateChannelStep extends CreateChannelStepDefinition {
|
|
133
|
+
|
|
134
|
+
async handle(conn: MockRTCConnection): Promise<void> {
|
|
135
|
+
const channel = conn.createDataChannel(this.channelLabel);
|
|
136
|
+
return new Promise<void>((resolve) =>
|
|
137
|
+
channel.once('channel-open', resolve)
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
130
143
|
export class SendStep extends SendStepDefinition {
|
|
131
144
|
|
|
132
145
|
private matchesChannel(channel: DataChannelStream) {
|
|
@@ -165,8 +178,8 @@ export class EchoStep extends EchoStepDefinition {
|
|
|
165
178
|
stream.pipe(stream);
|
|
166
179
|
};
|
|
167
180
|
|
|
168
|
-
connection.on('channel-
|
|
169
|
-
connection.on('track-
|
|
181
|
+
connection.on('channel-created', echoContent);
|
|
182
|
+
connection.on('track-created', echoContent);
|
|
170
183
|
connection.channels.forEach(echoContent);
|
|
171
184
|
connection.mediaTracks.forEach(echoContent);
|
|
172
185
|
|
|
@@ -190,7 +203,7 @@ export class PeerProxyStep extends PeerProxyStepDefinition {
|
|
|
190
203
|
);
|
|
191
204
|
externalConn.setRemoteDescription(await this.getAnswer(externalOffer));
|
|
192
205
|
|
|
193
|
-
connection.proxyTrafficTo(externalConn);
|
|
206
|
+
await connection.proxyTrafficTo(externalConn);
|
|
194
207
|
|
|
195
208
|
// This step keeps running indefinitely, until the connection closes
|
|
196
209
|
return new Promise<void>((resolve) => connection.on('connection-closed', resolve));
|
|
@@ -198,7 +211,7 @@ export class PeerProxyStep extends PeerProxyStepDefinition {
|
|
|
198
211
|
|
|
199
212
|
serialize(channel: ClientServerChannel): {} {
|
|
200
213
|
channel.onRequest<
|
|
201
|
-
{ offer:
|
|
214
|
+
{ offer: MockRTCSessionDescription },
|
|
202
215
|
{ answer: RTCSessionDescriptionInit }
|
|
203
216
|
>(async (msg) => {
|
|
204
217
|
return { answer: await this.getAnswer(msg.offer) };
|
|
@@ -208,10 +221,10 @@ export class PeerProxyStep extends PeerProxyStepDefinition {
|
|
|
208
221
|
}
|
|
209
222
|
|
|
210
223
|
static deserialize(_data: {}, channel: ClientServerChannel): PeerProxyStep {
|
|
211
|
-
return new PeerProxyStep(async (offer:
|
|
224
|
+
return new PeerProxyStep(async (offer: MockRTCSessionDescription) => {
|
|
212
225
|
const response = await channel.request<
|
|
213
|
-
{ offer:
|
|
214
|
-
{ answer:
|
|
226
|
+
{ offer: MockRTCSessionDescription },
|
|
227
|
+
{ answer: MockRTCSessionDescription }
|
|
215
228
|
>({ offer });
|
|
216
229
|
return response.answer;
|
|
217
230
|
});
|
|
@@ -242,13 +255,14 @@ export class DynamicProxyStep extends DynamicProxyStepDefinition {
|
|
|
242
255
|
|
|
243
256
|
export const StepLookup: typeof StepDefinitionLookup = {
|
|
244
257
|
'wait-for-duration': WaitForDurationStep,
|
|
245
|
-
'wait-for-channel': WaitForChannelStep,
|
|
246
|
-
'wait-for-track': WaitForTrackStep,
|
|
247
|
-
'wait-for-media': WaitForMediaStep,
|
|
248
|
-
'wait-for-message': WaitForMessageStep,
|
|
249
|
-
'
|
|
250
|
-
'
|
|
251
|
-
'
|
|
252
|
-
'
|
|
253
|
-
'
|
|
258
|
+
'wait-for-rtc-data-channel': WaitForChannelStep,
|
|
259
|
+
'wait-for-rtc-track': WaitForTrackStep,
|
|
260
|
+
'wait-for-rtc-media': WaitForMediaStep,
|
|
261
|
+
'wait-for-rtc-message': WaitForMessageStep,
|
|
262
|
+
'create-rtc-data-channel': CreateChannelStep,
|
|
263
|
+
'send-rtc-data-message': SendStep,
|
|
264
|
+
'close-rtc-connection': CloseStep,
|
|
265
|
+
'echo-rtc': EchoStep,
|
|
266
|
+
'rtc-peer-proxy': PeerProxyStep,
|
|
267
|
+
'rtc-dynamic-proxy': DynamicProxyStep
|
|
254
268
|
};
|
package/src/main-browser.ts
CHANGED
|
@@ -9,6 +9,11 @@ import type {
|
|
|
9
9
|
} from "./mockrtc";
|
|
10
10
|
import { MockRTCClient, MockRTCClientOptions } from "./client/mockrtc-client";
|
|
11
11
|
|
|
12
|
+
// Export the required structures to remotely build and send rules to the admin API:
|
|
13
|
+
export * as HandlerStepDefinitions from "./handling/handler-step-definitions";
|
|
14
|
+
export * as MatcherDefinitions from "./matching/matcher-definitions";
|
|
15
|
+
export { MockRTCAdminRequestBuilder } from "./client/mockrtc-admin-request-builder";
|
|
16
|
+
|
|
12
17
|
export type {
|
|
13
18
|
MockRTC,
|
|
14
19
|
MockRTCOptions
|