mockrtc 0.2.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/dist/client/mockrtc-admin-request-builder.d.ts +7 -1
- package/dist/client/mockrtc-admin-request-builder.js +30 -0
- package/dist/client/mockrtc-admin-request-builder.js.map +1 -1
- package/dist/client/mockrtc-client.d.ts +8 -4
- package/dist/client/mockrtc-client.js +21 -9
- package/dist/client/mockrtc-client.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 +40 -23
- 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 +26 -16
- package/dist/handling/handler-steps.js.map +1 -1
- package/dist/main-browser.d.ts +1 -0
- package/dist/main-browser.js +2 -1
- package/dist/main-browser.js.map +1 -1
- package/dist/main.d.ts +5 -3
- package/dist/main.js +2 -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 +9 -2
- package/dist/mockrtc.d.ts +62 -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.js +18 -1
- package/dist/server/mockrtc-admin-plugin.js.map +1 -1
- package/dist/server/mockrtc-server-peer.d.ts +1 -1
- package/dist/server/mockrtc-server-peer.js +19 -7
- package/dist/server/mockrtc-server-peer.js.map +1 -1
- package/dist/server/mockrtc-server.d.ts +12 -5
- package/dist/server/mockrtc-server.js +53 -18
- package/dist/server/mockrtc-server.js.map +1 -1
- package/dist/webrtc/datachannel-stream.d.ts +2 -0
- package/dist/webrtc/datachannel-stream.js +15 -1
- package/dist/webrtc/datachannel-stream.js.map +1 -1
- package/dist/webrtc/mediatrack-stream.d.ts +2 -0
- package/dist/webrtc/mediatrack-stream.js +15 -1
- package/dist/webrtc/mediatrack-stream.js.map +1 -1
- package/dist/webrtc/mockrtc-connection.js +1 -1
- package/dist/webrtc/mockrtc-connection.js.map +1 -1
- package/dist/webrtc/rtc-connection.d.ts +6 -2
- package/dist/webrtc/rtc-connection.js +20 -20
- package/dist/webrtc/rtc-connection.js.map +1 -1
- package/dist/webrtc-hooks.js +8 -2
- package/dist/webrtc-hooks.js.map +1 -1
- package/package.json +1 -1
- package/src/client/mockrtc-admin-request-builder.ts +49 -1
- package/src/client/mockrtc-client.ts +28 -10
- package/src/handling/handler-builder.ts +22 -10
- package/src/handling/handler-step-definitions.ts +81 -23
- package/src/handling/handler-steps.ts +28 -15
- package/src/main-browser.ts +1 -0
- package/src/main.ts +5 -1
- 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 +9 -2
- package/src/mockrtc.ts +72 -0
- package/src/rule-builder.ts +142 -0
- package/src/server/mockrtc-admin-plugin.ts +41 -3
- package/src/server/mockrtc-server-peer.ts +28 -18
- package/src/server/mockrtc-server.ts +71 -15
- package/src/webrtc/datachannel-stream.ts +15 -1
- package/src/webrtc/mediatrack-stream.ts +15 -1
- package/src/webrtc/mockrtc-connection.ts +1 -1
- package/src/webrtc/rtc-connection.ts +36 -19
- package/src/webrtc-hooks.ts +8 -2
- package/test/integration/events.spec.ts +3 -1
- package/test/integration/matching.spec.ts +189 -0
- package/test/integration/proxy.spec.ts +4 -2
- package/test/integration/send-steps.spec.ts +25 -0
|
@@ -20,76 +20,125 @@ export class WaitForDurationStepDefinition extends Serializable implements Handl
|
|
|
20
20
|
readonly type = 'wait-for-duration';
|
|
21
21
|
|
|
22
22
|
constructor(
|
|
23
|
-
|
|
23
|
+
public readonly durationMs: number
|
|
24
24
|
) {
|
|
25
25
|
super();
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
explain() {
|
|
29
|
+
return `wait for ${this.durationMs}ms`;
|
|
30
|
+
}
|
|
31
|
+
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
export class WaitForChannelStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
31
35
|
|
|
32
|
-
readonly type = 'wait-for-channel';
|
|
36
|
+
readonly type = 'wait-for-rtc-data-channel';
|
|
33
37
|
|
|
34
38
|
constructor(
|
|
35
|
-
|
|
39
|
+
public readonly channelLabel?: string
|
|
36
40
|
) {
|
|
37
41
|
super();
|
|
38
42
|
}
|
|
43
|
+
|
|
44
|
+
explain() {
|
|
45
|
+
return `wait for an RTC channel${this.channelLabel ? ` labelled '${this.channelLabel}'` : ''}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
export class WaitForMessageStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
42
51
|
|
|
43
|
-
readonly type = 'wait-for-message';
|
|
52
|
+
readonly type = 'wait-for-rtc-message';
|
|
44
53
|
|
|
45
54
|
constructor(
|
|
46
|
-
|
|
55
|
+
public readonly channelLabel?: string
|
|
47
56
|
) {
|
|
48
57
|
super();
|
|
49
58
|
}
|
|
50
59
|
|
|
60
|
+
explain() {
|
|
61
|
+
return `wait for an RTC message${this.channelLabel ? ` on channel '${this.channelLabel}'` : ''}`;
|
|
62
|
+
}
|
|
63
|
+
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
export class WaitForTrackStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
54
67
|
|
|
55
|
-
readonly type = 'wait-for-track';
|
|
68
|
+
readonly type = 'wait-for-rtc-track';
|
|
69
|
+
|
|
70
|
+
explain() {
|
|
71
|
+
return `wait for an RTC track`;
|
|
72
|
+
}
|
|
56
73
|
|
|
57
74
|
}
|
|
58
75
|
|
|
59
76
|
export class WaitForMediaStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
60
77
|
|
|
61
|
-
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
|
+
}
|
|
62
99
|
|
|
63
100
|
}
|
|
64
101
|
|
|
65
102
|
export class SendStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
66
103
|
|
|
67
|
-
readonly type = 'send-message';
|
|
104
|
+
readonly type = 'send-rtc-data-message';
|
|
68
105
|
|
|
69
106
|
constructor(
|
|
70
|
-
|
|
71
|
-
|
|
107
|
+
public readonly channelLabel: string | undefined,
|
|
108
|
+
public readonly message: string | Buffer
|
|
72
109
|
) {
|
|
73
110
|
super();
|
|
74
111
|
}
|
|
75
112
|
|
|
113
|
+
explain() {
|
|
114
|
+
return `send an RTC data message${this.channelLabel ? ` on channel '${this.channelLabel}'` : ''}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
76
117
|
}
|
|
77
118
|
|
|
78
119
|
export class CloseStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
79
120
|
|
|
80
|
-
readonly type = 'close-connection';
|
|
121
|
+
readonly type = 'close-rtc-connection';
|
|
122
|
+
|
|
123
|
+
explain() {
|
|
124
|
+
return `close the RTC connection`;
|
|
125
|
+
}
|
|
81
126
|
|
|
82
127
|
}
|
|
83
128
|
|
|
84
129
|
export class EchoStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
85
130
|
|
|
86
|
-
readonly type = 'echo-
|
|
131
|
+
readonly type = 'echo-rtc';
|
|
132
|
+
|
|
133
|
+
explain() {
|
|
134
|
+
return `echo all RTC media & data`;
|
|
135
|
+
}
|
|
87
136
|
|
|
88
137
|
}
|
|
89
138
|
|
|
90
139
|
export class PeerProxyStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
91
140
|
|
|
92
|
-
readonly type = 'peer-proxy';
|
|
141
|
+
readonly type = 'rtc-peer-proxy';
|
|
93
142
|
|
|
94
143
|
protected getAnswer: (offer: MockRTCSessionDescription) => Promise<RTCSessionDescriptionInit>;
|
|
95
144
|
|
|
@@ -111,6 +160,10 @@ export class PeerProxyStepDefinition extends Serializable implements HandlerStep
|
|
|
111
160
|
}
|
|
112
161
|
}
|
|
113
162
|
|
|
163
|
+
explain() {
|
|
164
|
+
return `proxy the RTC connection to the configured peer`;
|
|
165
|
+
}
|
|
166
|
+
|
|
114
167
|
serialize(channel: ClientServerChannel): {} {
|
|
115
168
|
channel.onRequest<
|
|
116
169
|
{ offer: MockRTCSessionDescription },
|
|
@@ -126,19 +179,24 @@ export class PeerProxyStepDefinition extends Serializable implements HandlerStep
|
|
|
126
179
|
|
|
127
180
|
export class DynamicProxyStepDefinition extends Serializable implements HandlerStepDefinition {
|
|
128
181
|
|
|
129
|
-
readonly type = 'dynamic-proxy';
|
|
182
|
+
readonly type = 'rtc-dynamic-proxy';
|
|
183
|
+
|
|
184
|
+
explain() {
|
|
185
|
+
return `proxy the RTC connection to a remote peer`;
|
|
186
|
+
}
|
|
130
187
|
|
|
131
188
|
}
|
|
132
189
|
|
|
133
190
|
export const StepDefinitionLookup = {
|
|
134
191
|
'wait-for-duration': WaitForDurationStepDefinition,
|
|
135
|
-
'wait-for-channel': WaitForChannelStepDefinition,
|
|
136
|
-
'wait-for-track': WaitForTrackStepDefinition,
|
|
137
|
-
'wait-for-media': WaitForMediaStepDefinition,
|
|
138
|
-
'wait-for-message': WaitForMessageStepDefinition,
|
|
139
|
-
'
|
|
140
|
-
'
|
|
141
|
-
'
|
|
142
|
-
'
|
|
143
|
-
'
|
|
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
|
|
144
202
|
};
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
EchoStepDefinition,
|
|
18
18
|
HandlerStepDefinition,
|
|
19
19
|
PeerProxyStepDefinition,
|
|
20
|
+
CreateChannelStepDefinition,
|
|
20
21
|
SendStepDefinition,
|
|
21
22
|
WaitForChannelStepDefinition,
|
|
22
23
|
WaitForDurationStepDefinition,
|
|
@@ -70,7 +71,7 @@ export class WaitForMessageStep extends WaitForMessageStepDefinition {
|
|
|
70
71
|
async handle(connection: MockRTCConnection): Promise<void> {
|
|
71
72
|
return new Promise<void>((resolve) => {
|
|
72
73
|
const messageReceived = () => {
|
|
73
|
-
connection.removeListener('channel-
|
|
74
|
+
connection.removeListener('channel-created', listenForMessage);
|
|
74
75
|
connection.channels.forEach((channel) => {
|
|
75
76
|
channel.removeListener('data', messageReceived);
|
|
76
77
|
channel.pause();
|
|
@@ -85,7 +86,7 @@ export class WaitForMessageStep extends WaitForMessageStepDefinition {
|
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
connection.on('channel-
|
|
89
|
+
connection.on('channel-created', listenForMessage);
|
|
89
90
|
connection.channels.forEach(listenForMessage);
|
|
90
91
|
});
|
|
91
92
|
}
|
|
@@ -108,7 +109,7 @@ export class WaitForMediaStep extends WaitForMediaStepDefinition {
|
|
|
108
109
|
async handle(connection: MockRTCConnection): Promise<void> {
|
|
109
110
|
return new Promise<void>((resolve) => {
|
|
110
111
|
const messageReceived = () => {
|
|
111
|
-
connection.removeListener('track-
|
|
112
|
+
connection.removeListener('track-created', listenForData);
|
|
112
113
|
connection.mediaTracks.forEach((track) => {
|
|
113
114
|
track.removeListener('data', messageReceived);
|
|
114
115
|
track.pause();
|
|
@@ -121,13 +122,24 @@ export class WaitForMediaStep extends WaitForMediaStepDefinition {
|
|
|
121
122
|
track.once('data', messageReceived);
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
connection.on('track-
|
|
125
|
+
connection.on('track-created', listenForData);
|
|
125
126
|
connection.mediaTracks.forEach(listenForData);
|
|
126
127
|
});
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
}
|
|
130
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
|
+
|
|
131
143
|
export class SendStep extends SendStepDefinition {
|
|
132
144
|
|
|
133
145
|
private matchesChannel(channel: DataChannelStream) {
|
|
@@ -166,8 +178,8 @@ export class EchoStep extends EchoStepDefinition {
|
|
|
166
178
|
stream.pipe(stream);
|
|
167
179
|
};
|
|
168
180
|
|
|
169
|
-
connection.on('channel-
|
|
170
|
-
connection.on('track-
|
|
181
|
+
connection.on('channel-created', echoContent);
|
|
182
|
+
connection.on('track-created', echoContent);
|
|
171
183
|
connection.channels.forEach(echoContent);
|
|
172
184
|
connection.mediaTracks.forEach(echoContent);
|
|
173
185
|
|
|
@@ -243,13 +255,14 @@ export class DynamicProxyStep extends DynamicProxyStepDefinition {
|
|
|
243
255
|
|
|
244
256
|
export const StepLookup: typeof StepDefinitionLookup = {
|
|
245
257
|
'wait-for-duration': WaitForDurationStep,
|
|
246
|
-
'wait-for-channel': WaitForChannelStep,
|
|
247
|
-
'wait-for-track': WaitForTrackStep,
|
|
248
|
-
'wait-for-media': WaitForMediaStep,
|
|
249
|
-
'wait-for-message': WaitForMessageStep,
|
|
250
|
-
'
|
|
251
|
-
'
|
|
252
|
-
'
|
|
253
|
-
'
|
|
254
|
-
'
|
|
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
|
|
255
268
|
};
|
package/src/main-browser.ts
CHANGED
|
@@ -11,6 +11,7 @@ import { MockRTCClient, MockRTCClientOptions } from "./client/mockrtc-client";
|
|
|
11
11
|
|
|
12
12
|
// Export the required structures to remotely build and send rules to the admin API:
|
|
13
13
|
export * as HandlerStepDefinitions from "./handling/handler-step-definitions";
|
|
14
|
+
export * as MatcherDefinitions from "./matching/matcher-definitions";
|
|
14
15
|
export { MockRTCAdminRequestBuilder } from "./client/mockrtc-admin-request-builder";
|
|
15
16
|
|
|
16
17
|
export type {
|
package/src/main.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
MockRTCPeerBuilder,
|
|
10
10
|
MockRTCEvent,
|
|
11
11
|
MockRTCEventData,
|
|
12
|
+
MockRTCRuleDefinition,
|
|
12
13
|
MockRTCSessionDescription,
|
|
13
14
|
SelectedRTCCandidate,
|
|
14
15
|
TimingEvents
|
|
@@ -22,16 +23,18 @@ import { MockRTCClient, MockRTCClientOptions } from "./client/mockrtc-client";
|
|
|
22
23
|
|
|
23
24
|
// Export the required structures to remotely build and send rules to the admin API:
|
|
24
25
|
export * as HandlerStepDefinitions from "./handling/handler-step-definitions";
|
|
26
|
+
export * as MatcherDefinitions from "./matching/matcher-definitions";
|
|
25
27
|
export { MockRTCAdminRequestBuilder } from "./client/mockrtc-admin-request-builder";
|
|
26
28
|
|
|
27
29
|
// Re-export lots of types are used in various APIs (mostly to make TypeDoc happy):
|
|
28
30
|
export type { HandlerStep } from "./handling/handler-steps";
|
|
29
31
|
export type { MockRTCHandlerBuilder } from "./handling/handler-builder";
|
|
32
|
+
export type { MockRTCRuleBuilder, RuleHandlerBuilder } from "./rule-builder";
|
|
30
33
|
|
|
31
34
|
export type { MockRTCServerPeer } from "./server/mockrtc-server-peer";
|
|
32
35
|
export type { SessionData } from "./server/mockrtc-admin-plugin";
|
|
33
36
|
|
|
34
|
-
export type { RTCConnection } from "./webrtc/rtc-connection";
|
|
37
|
+
export type { RTCConnection, ParsedSDP } from "./webrtc/rtc-connection";
|
|
35
38
|
export type { MockRTCConnection } from "./webrtc/mockrtc-connection";
|
|
36
39
|
export type { DataChannelStream } from "./webrtc/datachannel-stream";
|
|
37
40
|
export type { MediaTrackStream } from "./webrtc/mediatrack-stream";
|
|
@@ -46,6 +49,7 @@ export type {
|
|
|
46
49
|
MockRTCAdminServer,
|
|
47
50
|
MockRTCEvent,
|
|
48
51
|
MockRTCEventData,
|
|
52
|
+
MockRTCRuleDefinition,
|
|
49
53
|
MockRTCSessionDescription,
|
|
50
54
|
SelectedRTCCandidate,
|
|
51
55
|
TimingEvents
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as PluggableAdmin from 'mockttp/dist/pluggable-admin-api/pluggable-admin.browser';
|
|
7
|
+
|
|
8
|
+
export type Serializable = PluggableAdmin.Serialization.Serializable;
|
|
9
|
+
export const { Serializable } = PluggableAdmin.Serialization;
|
|
10
|
+
|
|
11
|
+
export interface MatcherDefinition extends Serializable {
|
|
12
|
+
readonly type: keyof typeof MatcherDefinitionLookup;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class HasDataChannelMatcherDefinition extends Serializable implements MatcherDefinition {
|
|
16
|
+
readonly type = 'has-rtc-data-channel';
|
|
17
|
+
|
|
18
|
+
explain() {
|
|
19
|
+
return `with a data channel`;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class HasVideoTrackMatcherDefinition extends Serializable implements MatcherDefinition {
|
|
24
|
+
readonly type = 'has-rtc-video-track';
|
|
25
|
+
|
|
26
|
+
explain() {
|
|
27
|
+
return `with a video track`;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class HasAudioTrackMatcherDefinition extends Serializable implements MatcherDefinition {
|
|
32
|
+
readonly type = 'has-rtc-audio-track';
|
|
33
|
+
|
|
34
|
+
explain() {
|
|
35
|
+
return `with an audio track`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class HasMediaTrackMatcherDefinition extends Serializable implements MatcherDefinition {
|
|
40
|
+
readonly type = 'has-rtc-media-track';
|
|
41
|
+
|
|
42
|
+
explain() {
|
|
43
|
+
return `with any media track`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export class HostnameMatcherDefinition extends Serializable implements MatcherDefinition {
|
|
48
|
+
|
|
49
|
+
readonly type = 'rtc-page-hostname';
|
|
50
|
+
|
|
51
|
+
constructor(
|
|
52
|
+
public readonly hostname: string
|
|
53
|
+
) {
|
|
54
|
+
super();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
explain() {
|
|
58
|
+
return `from a page on ${this.hostname}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class UrlRegexMatcherDefinition extends Serializable implements MatcherDefinition {
|
|
64
|
+
|
|
65
|
+
readonly type = 'rtc-page-regex';
|
|
66
|
+
|
|
67
|
+
readonly regexSource: string;
|
|
68
|
+
readonly regexFlags: string;
|
|
69
|
+
|
|
70
|
+
constructor(regex: RegExp) {
|
|
71
|
+
super();
|
|
72
|
+
this.regexSource = regex.source;
|
|
73
|
+
this.regexFlags = regex.flags;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
explain() {
|
|
77
|
+
return `from a page with URL matching /${this.regexSource}/${this.regexFlags}`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export class UserAgentRegexMatcherDefinition extends Serializable implements MatcherDefinition {
|
|
83
|
+
|
|
84
|
+
readonly type = 'rtc-user-agent-regex';
|
|
85
|
+
|
|
86
|
+
readonly regexSource: string;
|
|
87
|
+
readonly regexFlags: string;
|
|
88
|
+
|
|
89
|
+
constructor(regex: RegExp) {
|
|
90
|
+
super();
|
|
91
|
+
this.regexSource = regex.source;
|
|
92
|
+
this.regexFlags = regex.flags;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
explain() {
|
|
96
|
+
return `from a user agent matching /${this.regexSource}/${this.regexFlags}`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const MatcherDefinitionLookup = {
|
|
102
|
+
'has-rtc-data-channel': HasDataChannelMatcherDefinition,
|
|
103
|
+
'has-rtc-video-track': HasVideoTrackMatcherDefinition,
|
|
104
|
+
'has-rtc-audio-track': HasAudioTrackMatcherDefinition,
|
|
105
|
+
'has-rtc-media-track': HasMediaTrackMatcherDefinition,
|
|
106
|
+
'rtc-page-hostname': HostnameMatcherDefinition,
|
|
107
|
+
'rtc-page-regex': UrlRegexMatcherDefinition,
|
|
108
|
+
'rtc-user-agent-regex': UserAgentRegexMatcherDefinition
|
|
109
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { RTCConnection } from "../webrtc/rtc-connection";
|
|
7
|
+
import {
|
|
8
|
+
MatcherDefinition,
|
|
9
|
+
MatcherDefinitionLookup,
|
|
10
|
+
HasAudioTrackMatcherDefinition,
|
|
11
|
+
HasDataChannelMatcherDefinition,
|
|
12
|
+
HasMediaTrackMatcherDefinition,
|
|
13
|
+
HasVideoTrackMatcherDefinition,
|
|
14
|
+
HostnameMatcherDefinition,
|
|
15
|
+
UrlRegexMatcherDefinition,
|
|
16
|
+
UserAgentRegexMatcherDefinition
|
|
17
|
+
} from "./matcher-definitions";
|
|
18
|
+
|
|
19
|
+
export interface Matcher extends MatcherDefinition {
|
|
20
|
+
matches(connection: RTCConnection): boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class HasDataChannelMatcher extends HasDataChannelMatcherDefinition {
|
|
24
|
+
|
|
25
|
+
matches(connection: RTCConnection): boolean {
|
|
26
|
+
return [
|
|
27
|
+
...connection.getLocalDescription()!.parsedSdp.media,
|
|
28
|
+
...connection.getRemoteDescription()!.parsedSdp.media
|
|
29
|
+
].some(media => media.type === 'application');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class HasVideoTrackMatcher extends HasVideoTrackMatcherDefinition {
|
|
35
|
+
|
|
36
|
+
matches(connection: RTCConnection): boolean {
|
|
37
|
+
return [
|
|
38
|
+
...connection.getLocalDescription()!.parsedSdp.media,
|
|
39
|
+
...connection.getRemoteDescription()!.parsedSdp.media
|
|
40
|
+
].some(media => media.type === 'video');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class HasAudioTrackMatcher extends HasAudioTrackMatcherDefinition {
|
|
46
|
+
|
|
47
|
+
matches(connection: RTCConnection): boolean {
|
|
48
|
+
return [
|
|
49
|
+
...connection.getLocalDescription()!.parsedSdp.media,
|
|
50
|
+
...connection.getRemoteDescription()!.parsedSdp.media
|
|
51
|
+
].some(media => media.type === 'audio');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export class HasMediaTrackMatcher extends HasMediaTrackMatcherDefinition {
|
|
57
|
+
|
|
58
|
+
matches(connection: RTCConnection): boolean {
|
|
59
|
+
return [
|
|
60
|
+
...connection.getLocalDescription()!.parsedSdp.media,
|
|
61
|
+
...connection.getRemoteDescription()!.parsedSdp.media
|
|
62
|
+
].some(media => media.type === 'video' || media.type === 'audio');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const getConnectionSourceURL = (connection: RTCConnection): URL | undefined => {
|
|
68
|
+
const { sourceURL } = connection.metadata;
|
|
69
|
+
if (!sourceURL) return;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
return new URL(sourceURL);
|
|
73
|
+
} catch (e) {
|
|
74
|
+
console.warn('Unparseable RTC source URL:', e);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export class HostnameMatcher extends HostnameMatcherDefinition {
|
|
80
|
+
|
|
81
|
+
matches(connection: RTCConnection): boolean {
|
|
82
|
+
const url = getConnectionSourceURL(connection);
|
|
83
|
+
return url?.hostname === this.hostname;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export class UrlRegexMatcher extends UrlRegexMatcherDefinition {
|
|
89
|
+
|
|
90
|
+
matches(connection: RTCConnection): boolean {
|
|
91
|
+
const url = getConnectionSourceURL(connection);
|
|
92
|
+
return !!url?.toString().match(
|
|
93
|
+
new RegExp(this.regexSource, this.regexFlags)
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export class UserAgentRegexMatcher extends UserAgentRegexMatcherDefinition {
|
|
100
|
+
|
|
101
|
+
matches(connection: RTCConnection): boolean {
|
|
102
|
+
const userAgent = connection.metadata.userAgent;
|
|
103
|
+
return !!userAgent?.match(
|
|
104
|
+
new RegExp(this.regexSource, this.regexFlags)
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const MatcherLookup: typeof MatcherDefinitionLookup = {
|
|
111
|
+
'has-rtc-data-channel': HasDataChannelMatcher,
|
|
112
|
+
'has-rtc-video-track': HasVideoTrackMatcher,
|
|
113
|
+
'has-rtc-audio-track': HasAudioTrackMatcher,
|
|
114
|
+
'has-rtc-media-track': HasMediaTrackMatcher,
|
|
115
|
+
'rtc-page-hostname': HostnameMatcher,
|
|
116
|
+
'rtc-page-regex': UrlRegexMatcher,
|
|
117
|
+
'rtc-user-agent-regex': UserAgentRegexMatcher
|
|
118
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* SPDX-FileCopyrightText: 2022 Tim Perry <tim@httptoolkit.tech>
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
MockRTC,
|
|
8
|
+
MockRTCEventData,
|
|
9
|
+
MockRTCPeerBuilder,
|
|
10
|
+
MockRTCRuleDefinition
|
|
11
|
+
} from "./mockrtc";
|
|
12
|
+
import { MockRTCPeer } from "./mockrtc-peer";
|
|
13
|
+
import { MockRTCHandlerBuilder } from "./handling/handler-builder";
|
|
14
|
+
import { HandlerStepDefinition } from "./handling/handler-step-definitions";
|
|
15
|
+
import { MatcherDefinition } from "./matching/matcher-definitions";
|
|
16
|
+
import { MockRTCRuleBuilder } from "./rule-builder";
|
|
17
|
+
|
|
18
|
+
export abstract class MockRTCBase implements MockRTC {
|
|
19
|
+
|
|
20
|
+
abstract getMatchingPeer(): MockRTCPeer;
|
|
21
|
+
abstract start(): Promise<void>;
|
|
22
|
+
abstract stop(): Promise<void>;
|
|
23
|
+
abstract on<E extends keyof MockRTCEventData>(
|
|
24
|
+
event: E,
|
|
25
|
+
callback: (param: MockRTCEventData[E]) => void
|
|
26
|
+
): Promise<void>;
|
|
27
|
+
|
|
28
|
+
buildPeer(): MockRTCPeerBuilder {
|
|
29
|
+
return new MockRTCHandlerBuilder(this.buildPeerFromDefinition.bind(this));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
abstract buildPeerFromDefinition(
|
|
33
|
+
handlerStepDefinitions: HandlerStepDefinition[]
|
|
34
|
+
): Promise<MockRTCPeer>;
|
|
35
|
+
|
|
36
|
+
forConnections(): MockRTCRuleBuilder {
|
|
37
|
+
return new MockRTCRuleBuilder(this.addRuleFromDefinition.bind(this));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
abstract addRuleFromDefinition(
|
|
41
|
+
matcherDefinitions: MatcherDefinition[],
|
|
42
|
+
handlerStepDefinitions: HandlerStepDefinition[]
|
|
43
|
+
): Promise<void>;
|
|
44
|
+
|
|
45
|
+
abstract setRulesFromDefinitions(
|
|
46
|
+
ruleDefinitions: Array<MockRTCRuleDefinition>
|
|
47
|
+
): Promise<void>;
|
|
48
|
+
|
|
49
|
+
}
|
package/src/mockrtc-peer.ts
CHANGED
|
@@ -189,11 +189,18 @@ export interface AnswerOptions {
|
|
|
189
189
|
* Extra metadata to associate with the connection. This will be exposed on
|
|
190
190
|
* events like peer-connected, and can be used to add context to connections.
|
|
191
191
|
*
|
|
192
|
-
* The
|
|
193
|
-
*
|
|
192
|
+
* The defined fields may only be used as defined here, but all values are
|
|
193
|
+
* optional, and any other metadata may be attached in any format here.
|
|
194
|
+
*
|
|
195
|
+
* The only defined values are:
|
|
196
|
+
* - `userAgent` - a client user-agent string (in a browser, the value of
|
|
197
|
+
* `navigator.userAgent`)
|
|
198
|
+
* - `sourceURL` - the URL of the referring page, when the request is sent by
|
|
199
|
+
* a browser
|
|
194
200
|
*/
|
|
195
201
|
export interface ConnectionMetadata {
|
|
196
202
|
userAgent?: string;
|
|
203
|
+
sourceURL?: string;
|
|
197
204
|
[k: string]: any;
|
|
198
205
|
}
|
|
199
206
|
|