@webex/plugin-meetings 3.10.0-next.8 → 3.10.0-webex-services-ready.1
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/dist/annotation/annotation.types.js.map +1 -1
- package/dist/annotation/constants.js.map +1 -1
- package/dist/annotation/index.js +19 -22
- package/dist/annotation/index.js.map +1 -1
- package/dist/breakouts/breakout.js +6 -6
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/collection.js.map +1 -1
- package/dist/breakouts/edit-lock-error.js +9 -11
- package/dist/breakouts/edit-lock-error.js.map +1 -1
- package/dist/breakouts/events.js.map +1 -1
- package/dist/breakouts/index.js +126 -127
- package/dist/breakouts/index.js.map +1 -1
- package/dist/breakouts/request.js +6 -8
- package/dist/breakouts/request.js.map +1 -1
- package/dist/breakouts/utils.js.map +1 -1
- package/dist/common/browser-detection.js.map +1 -1
- package/dist/common/collection.js +1 -2
- package/dist/common/collection.js.map +1 -1
- package/dist/common/config.js.map +1 -1
- package/dist/common/errors/captcha-error.js +9 -11
- package/dist/common/errors/captcha-error.js.map +1 -1
- package/dist/common/errors/intent-to-join.js +10 -12
- package/dist/common/errors/intent-to-join.js.map +1 -1
- package/dist/common/errors/join-forbidden-error.js +10 -12
- package/dist/common/errors/join-forbidden-error.js.map +1 -1
- package/dist/common/errors/join-meeting.js +10 -12
- package/dist/common/errors/join-meeting.js.map +1 -1
- package/dist/common/errors/join-webinar-error.js +9 -11
- package/dist/common/errors/join-webinar-error.js.map +1 -1
- package/dist/common/errors/media.js +9 -11
- package/dist/common/errors/media.js.map +1 -1
- package/dist/common/errors/multistream-not-supported-error.js +9 -11
- package/dist/common/errors/multistream-not-supported-error.js.map +1 -1
- package/dist/common/errors/no-meeting-info.js +9 -11
- package/dist/common/errors/no-meeting-info.js.map +1 -1
- package/dist/common/errors/parameter.js +11 -14
- package/dist/common/errors/parameter.js.map +1 -1
- package/dist/common/errors/password-error.js +9 -11
- package/dist/common/errors/password-error.js.map +1 -1
- package/dist/common/errors/permission.js +9 -11
- package/dist/common/errors/permission.js.map +1 -1
- package/dist/common/errors/reclaim-host-role-errors.js +32 -38
- package/dist/common/errors/reclaim-host-role-errors.js.map +1 -1
- package/dist/common/errors/reconnection-not-started.js +5 -6
- package/dist/common/errors/reconnection-not-started.js.map +1 -1
- package/dist/common/errors/reconnection.js +9 -11
- package/dist/common/errors/reconnection.js.map +1 -1
- package/dist/common/errors/stats.js +9 -11
- package/dist/common/errors/stats.js.map +1 -1
- package/dist/common/errors/webex-errors.js +20 -29
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/errors/webex-meetings-error.js +9 -12
- package/dist/common/errors/webex-meetings-error.js.map +1 -1
- package/dist/common/events/events-scope.js +9 -10
- package/dist/common/events/events-scope.js.map +1 -1
- package/dist/common/events/events.js +9 -10
- package/dist/common/events/events.js.map +1 -1
- package/dist/common/events/trigger-proxy.js.map +1 -1
- package/dist/common/events/util.js.map +1 -1
- package/dist/common/logs/logger-config.js.map +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.js +17 -17
- package/dist/common/logs/request.js.map +1 -1
- package/dist/common/queue.js +1 -2
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js +0 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +11 -8
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/constants.js.map +1 -1
- package/dist/controls-options-manager/enums.js.map +1 -1
- package/dist/controls-options-manager/index.js +1 -2
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/controls-options-manager/types.js.map +1 -1
- package/dist/controls-options-manager/util.js +1 -2
- package/dist/controls-options-manager/util.js.map +1 -1
- package/dist/hashTree/constants.js +20 -0
- package/dist/hashTree/constants.js.map +1 -0
- package/dist/hashTree/hashTree.js +515 -0
- package/dist/hashTree/hashTree.js.map +1 -0
- package/dist/hashTree/hashTreeParser.js +1266 -0
- package/dist/hashTree/hashTreeParser.js.map +1 -0
- package/dist/hashTree/types.js +21 -0
- package/dist/hashTree/types.js.map +1 -0
- package/dist/hashTree/utils.js +48 -0
- package/dist/hashTree/utils.js.map +1 -0
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/interceptors/index.js.map +1 -1
- package/dist/interceptors/locusRetry.js +6 -8
- package/dist/interceptors/locusRetry.js.map +1 -1
- package/dist/interceptors/locusRouteToken.js +6 -8
- package/dist/interceptors/locusRouteToken.js.map +1 -1
- package/dist/interpretation/collection.js.map +1 -1
- package/dist/interpretation/index.js +1 -2
- package/dist/interpretation/index.js.map +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/interpretation/siLanguage.js.map +1 -1
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/embeddedAppsUtils.js.map +1 -1
- package/dist/locus-info/fullState.js.map +1 -1
- package/dist/locus-info/hostUtils.js.map +1 -1
- package/dist/locus-info/index.js +551 -94
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js +3 -4
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/locus-info/types.js +7 -0
- package/dist/locus-info/types.js.map +1 -0
- package/dist/media/MediaConnectionAwaiter.js +1 -2
- package/dist/media/MediaConnectionAwaiter.js.map +1 -1
- package/dist/media/index.js +0 -2
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js +15 -17
- package/dist/media/properties.js.map +1 -1
- package/dist/media/util.js.map +1 -1
- package/dist/meeting/brbState.js +8 -9
- package/dist/meeting/brbState.js.map +1 -1
- package/dist/meeting/connectionStateHandler.js +10 -13
- package/dist/meeting/connectionStateHandler.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +1555 -1527
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/locusMediaRequest.js +13 -17
- package/dist/meeting/locusMediaRequest.js.map +1 -1
- package/dist/meeting/muteState.js +11 -12
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +101 -104
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/request.type.js.map +1 -1
- package/dist/meeting/state.js.map +1 -1
- package/dist/meeting/type.js.map +1 -1
- package/dist/meeting/util.js +24 -23
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting/voicea-meeting.js +3 -3
- package/dist/meeting/voicea-meeting.js.map +1 -1
- package/dist/meeting-info/collection.js +7 -10
- package/dist/meeting-info/collection.js.map +1 -1
- package/dist/meeting-info/index.js +1 -2
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +135 -146
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/request.js +1 -2
- package/dist/meeting-info/request.js.map +1 -1
- package/dist/meeting-info/util.js +36 -37
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +30 -31
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js +6 -8
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +179 -141
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/meetings.types.js.map +1 -1
- package/dist/meetings/request.js +6 -8
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.js +25 -23
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js +1 -2
- package/dist/member/index.js.map +1 -1
- package/dist/member/types.js +6 -3
- package/dist/member/types.js.map +1 -1
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js +1 -2
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js +18 -21
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js +8 -11
- package/dist/members/request.js.map +1 -1
- package/dist/members/types.js.map +1 -1
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +3 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.js +3 -4
- package/dist/metrics/index.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +1 -2
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/receiveSlot.js +34 -45
- package/dist/multistream/receiveSlot.js.map +1 -1
- package/dist/multistream/receiveSlotManager.js +8 -9
- package/dist/multistream/receiveSlotManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js +12 -15
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +1 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/multistream/remoteMediaManager.js +122 -123
- package/dist/multistream/remoteMediaManager.js.map +1 -1
- package/dist/multistream/sendSlotManager.js +29 -30
- package/dist/multistream/sendSlotManager.js.map +1 -1
- package/dist/personal-meeting-room/index.js +16 -19
- package/dist/personal-meeting-room/index.js.map +1 -1
- package/dist/personal-meeting-room/request.js +7 -10
- package/dist/personal-meeting-room/request.js.map +1 -1
- package/dist/personal-meeting-room/util.js.map +1 -1
- package/dist/reachability/clusterReachability.js +56 -373
- package/dist/reachability/clusterReachability.js.map +1 -1
- package/dist/reachability/index.js +203 -205
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/reachability.types.js +14 -1
- package/dist/reachability/reachability.types.js.map +1 -1
- package/dist/reachability/reachabilityPeerConnection.js +445 -0
- package/dist/reachability/reachabilityPeerConnection.js.map +1 -0
- package/dist/reachability/request.js.map +1 -1
- package/dist/reachability/util.js.map +1 -1
- package/dist/reactions/constants.js.map +1 -1
- package/dist/reactions/reactions.js.map +1 -1
- package/dist/reactions/reactions.type.js.map +1 -1
- package/dist/reconnection-manager/index.js +178 -176
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/recording-controller/enums.js.map +1 -1
- package/dist/recording-controller/index.js +1 -2
- package/dist/recording-controller/index.js.map +1 -1
- package/dist/recording-controller/util.js.map +1 -1
- package/dist/roap/index.js +12 -15
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +24 -26
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/turnDiscovery.js +75 -76
- package/dist/roap/turnDiscovery.js.map +1 -1
- package/dist/roap/types.js.map +1 -1
- package/dist/transcription/index.js +4 -5
- package/dist/transcription/index.js.map +1 -1
- package/dist/types/constants.d.ts +26 -21
- package/dist/types/hashTree/constants.d.ts +8 -0
- package/dist/types/hashTree/hashTree.d.ts +129 -0
- package/dist/types/hashTree/hashTreeParser.d.ts +260 -0
- package/dist/types/hashTree/types.d.ts +25 -0
- package/dist/types/hashTree/utils.d.ts +9 -0
- package/dist/types/locus-info/index.d.ts +91 -42
- package/dist/types/locus-info/types.d.ts +46 -0
- package/dist/types/meeting/index.d.ts +22 -9
- package/dist/types/meetings/index.d.ts +9 -2
- package/dist/types/metrics/constants.d.ts +2 -0
- package/dist/types/reachability/clusterReachability.d.ts +10 -88
- package/dist/types/reachability/reachability.types.d.ts +12 -1
- package/dist/types/reachability/reachabilityPeerConnection.d.ts +111 -0
- package/dist/webinar/collection.js +1 -2
- package/dist/webinar/collection.js.map +1 -1
- package/dist/webinar/index.js +148 -158
- package/dist/webinar/index.js.map +1 -1
- package/package.json +22 -21
- package/src/constants.ts +13 -1
- package/src/hashTree/constants.ts +9 -0
- package/src/hashTree/hashTree.ts +463 -0
- package/src/hashTree/hashTreeParser.ts +1161 -0
- package/src/hashTree/types.ts +30 -0
- package/src/hashTree/utils.ts +42 -0
- package/src/locus-info/index.ts +556 -85
- package/src/locus-info/types.ts +48 -0
- package/src/meeting/index.ts +58 -26
- package/src/meeting/util.ts +1 -0
- package/src/meetings/index.ts +104 -51
- package/src/metrics/constants.ts +2 -0
- package/src/reachability/clusterReachability.ts +50 -347
- package/src/reachability/reachability.types.ts +15 -1
- package/src/reachability/reachabilityPeerConnection.ts +416 -0
- package/test/unit/spec/hashTree/hashTree.ts +655 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +1532 -0
- package/test/unit/spec/hashTree/utils.ts +103 -0
- package/test/unit/spec/locus-info/index.js +667 -1
- package/test/unit/spec/meeting/index.js +91 -20
- package/test/unit/spec/meeting/utils.js +77 -0
- package/test/unit/spec/meetings/index.js +71 -26
- package/test/unit/spec/reachability/clusterReachability.ts +281 -138
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import {Defer} from '@webex/common';
|
|
2
|
+
|
|
3
|
+
import LoggerProxy from '../common/logs/logger-proxy';
|
|
4
|
+
import {ClusterNode} from './request';
|
|
5
|
+
import {convertStunUrlToTurn, convertStunUrlToTurnTls} from './util';
|
|
6
|
+
import EventsScope from '../common/events/events-scope';
|
|
7
|
+
|
|
8
|
+
import {CONNECTION_STATE, ICE_GATHERING_STATE} from '../constants';
|
|
9
|
+
import {
|
|
10
|
+
ClusterReachabilityResult,
|
|
11
|
+
NatType,
|
|
12
|
+
Protocol,
|
|
13
|
+
ReachabilityPeerConnectionEvents,
|
|
14
|
+
} from './reachability.types';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A class to handle RTCPeerConnection lifecycle and ICE candidate gathering for reachability checks.
|
|
18
|
+
* It will do all the work like PeerConnection lifecycle, candidate processing, result management, and event emission.
|
|
19
|
+
*/
|
|
20
|
+
export class ReachabilityPeerConnection extends EventsScope {
|
|
21
|
+
public numUdpUrls: number;
|
|
22
|
+
public numTcpUrls: number;
|
|
23
|
+
public numXTlsUrls: number;
|
|
24
|
+
private pc: RTCPeerConnection | null;
|
|
25
|
+
private defer: Defer;
|
|
26
|
+
private startTimestamp: number;
|
|
27
|
+
private srflxIceCandidates: RTCIceCandidate[] = [];
|
|
28
|
+
private clusterName: string;
|
|
29
|
+
private result: ClusterReachabilityResult;
|
|
30
|
+
private emittedSubnets: Set<string> = new Set();
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Constructor for ReachabilityPeerConnection
|
|
34
|
+
* @param {string} clusterName name of the cluster
|
|
35
|
+
* @param {ClusterNode} clusterInfo information about the media cluster
|
|
36
|
+
*/
|
|
37
|
+
constructor(clusterName: string, clusterInfo: ClusterNode) {
|
|
38
|
+
super();
|
|
39
|
+
this.clusterName = clusterName;
|
|
40
|
+
this.numUdpUrls = clusterInfo.udp.length;
|
|
41
|
+
this.numTcpUrls = clusterInfo.tcp.length;
|
|
42
|
+
this.numXTlsUrls = clusterInfo.xtls.length;
|
|
43
|
+
|
|
44
|
+
this.pc = this.createPeerConnection(clusterInfo);
|
|
45
|
+
|
|
46
|
+
this.defer = new Defer();
|
|
47
|
+
this.result = {
|
|
48
|
+
udp: {
|
|
49
|
+
result: 'untested',
|
|
50
|
+
},
|
|
51
|
+
tcp: {
|
|
52
|
+
result: 'untested',
|
|
53
|
+
},
|
|
54
|
+
xtls: {
|
|
55
|
+
result: 'untested',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Gets total elapsed time, can be called only after start() is called
|
|
62
|
+
* @returns {number} Milliseconds
|
|
63
|
+
*/
|
|
64
|
+
private getElapsedTime() {
|
|
65
|
+
return Math.round(performance.now() - this.startTimestamp);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Generate peerConnection config settings
|
|
70
|
+
* @param {ClusterNode} cluster
|
|
71
|
+
* @returns {RTCConfiguration} peerConnectionConfig
|
|
72
|
+
*/
|
|
73
|
+
private static buildPeerConnectionConfig(cluster: ClusterNode): RTCConfiguration {
|
|
74
|
+
const udpIceServers = cluster.udp.map((url) => ({
|
|
75
|
+
username: '',
|
|
76
|
+
credential: '',
|
|
77
|
+
urls: [url],
|
|
78
|
+
}));
|
|
79
|
+
|
|
80
|
+
// STUN servers are contacted only using UDP, so in order to test TCP reachability
|
|
81
|
+
// we pretend that Linus is a TURN server, because we can explicitly say "transport=tcp" in TURN urls.
|
|
82
|
+
// We then check for relay candidates to know if TURN-TCP worked (see registerIceCandidateListener()).
|
|
83
|
+
const tcpIceServers = cluster.tcp.map((urlString: string) => {
|
|
84
|
+
return {
|
|
85
|
+
username: 'webexturnreachuser',
|
|
86
|
+
credential: 'webexturnreachpwd',
|
|
87
|
+
urls: [convertStunUrlToTurn(urlString, 'tcp')],
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const turnTlsIceServers = cluster.xtls.map((urlString: string) => {
|
|
92
|
+
return {
|
|
93
|
+
username: 'webexturnreachuser',
|
|
94
|
+
credential: 'webexturnreachpwd',
|
|
95
|
+
urls: [convertStunUrlToTurnTls(urlString)],
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
iceServers: [...udpIceServers, ...tcpIceServers, ...turnTlsIceServers],
|
|
101
|
+
iceCandidatePoolSize: 0,
|
|
102
|
+
iceTransportPolicy: 'all',
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Creates an RTCPeerConnection
|
|
108
|
+
* @param {ClusterNode} clusterInfo information about the media cluster
|
|
109
|
+
* @returns {RTCPeerConnection|null} peerConnection
|
|
110
|
+
*/
|
|
111
|
+
private createPeerConnection(clusterInfo: ClusterNode): RTCPeerConnection | null {
|
|
112
|
+
try {
|
|
113
|
+
const config = ReachabilityPeerConnection.buildPeerConnectionConfig(clusterInfo);
|
|
114
|
+
|
|
115
|
+
const peerConnection = new RTCPeerConnection(config);
|
|
116
|
+
|
|
117
|
+
return peerConnection;
|
|
118
|
+
} catch (peerConnectionError) {
|
|
119
|
+
LoggerProxy.logger.warn(
|
|
120
|
+
`Reachability:ReachabilityPeerConnection#createPeerConnection --> Error creating peerConnection:`,
|
|
121
|
+
peerConnectionError
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* @returns {ClusterReachabilityResult} reachability result for this instance
|
|
130
|
+
*/
|
|
131
|
+
getResult() {
|
|
132
|
+
return this.result;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Closes the peerConnection
|
|
137
|
+
* @returns {void}
|
|
138
|
+
*/
|
|
139
|
+
private closePeerConnection() {
|
|
140
|
+
if (this.pc) {
|
|
141
|
+
this.pc.onicecandidate = null;
|
|
142
|
+
this.pc.onicegatheringstatechange = null;
|
|
143
|
+
this.pc.close();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Resolves the defer, indicating that reachability checks for this cluster are completed
|
|
149
|
+
*
|
|
150
|
+
* @returns {void}
|
|
151
|
+
*/
|
|
152
|
+
private finishReachabilityCheck() {
|
|
153
|
+
this.defer.resolve();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Aborts the cluster reachability checks by closing the peer connection
|
|
158
|
+
*
|
|
159
|
+
* @returns {void}
|
|
160
|
+
*/
|
|
161
|
+
public abort() {
|
|
162
|
+
const {CLOSED} = CONNECTION_STATE;
|
|
163
|
+
|
|
164
|
+
if (this.pc && this.pc.connectionState !== CLOSED) {
|
|
165
|
+
this.closePeerConnection();
|
|
166
|
+
this.finishReachabilityCheck();
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Adds public IP (client media IPs)
|
|
172
|
+
* @param {string} protocol
|
|
173
|
+
* @param {string} publicIp
|
|
174
|
+
* @returns {void}
|
|
175
|
+
*/
|
|
176
|
+
private addPublicIp(protocol: Protocol, publicIp?: string | null) {
|
|
177
|
+
if (!publicIp) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const result = this.result[protocol];
|
|
182
|
+
let ipAdded = false;
|
|
183
|
+
|
|
184
|
+
if (result.clientMediaIPs) {
|
|
185
|
+
if (!result.clientMediaIPs.includes(publicIp)) {
|
|
186
|
+
result.clientMediaIPs.push(publicIp);
|
|
187
|
+
ipAdded = true;
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
result.clientMediaIPs = [publicIp];
|
|
191
|
+
ipAdded = true;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (ipAdded) {
|
|
195
|
+
this.emit(
|
|
196
|
+
{
|
|
197
|
+
file: 'reachabilityPeerConnection',
|
|
198
|
+
function: 'addPublicIp',
|
|
199
|
+
},
|
|
200
|
+
ReachabilityPeerConnectionEvents.clientMediaIpsUpdated,
|
|
201
|
+
{
|
|
202
|
+
protocol,
|
|
203
|
+
clientMediaIPs: result.clientMediaIPs,
|
|
204
|
+
}
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Registers a listener for the iceGatheringStateChange event
|
|
211
|
+
*
|
|
212
|
+
* @returns {void}
|
|
213
|
+
*/
|
|
214
|
+
private registerIceGatheringStateChangeListener() {
|
|
215
|
+
this.pc.onicegatheringstatechange = () => {
|
|
216
|
+
if (this.pc.iceGatheringState === ICE_GATHERING_STATE.COMPLETE) {
|
|
217
|
+
this.closePeerConnection();
|
|
218
|
+
this.defer.resolve();
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Saves the latency in the result for the given protocol and marks it as reachable,
|
|
225
|
+
* emits the "resultReady" event if this is the first result for that protocol,
|
|
226
|
+
* emits the "clientMediaIpsUpdated" event if we already had a result and only found
|
|
227
|
+
* a new client IP
|
|
228
|
+
*
|
|
229
|
+
* @param {string} protocol
|
|
230
|
+
* @param {number} latency
|
|
231
|
+
* @param {string|null} [publicIp]
|
|
232
|
+
* @param {string|null} [serverIp]
|
|
233
|
+
* @returns {void}
|
|
234
|
+
*/
|
|
235
|
+
private saveResult(
|
|
236
|
+
protocol: Protocol,
|
|
237
|
+
latency: number,
|
|
238
|
+
publicIp?: string | null,
|
|
239
|
+
serverIp?: string | null
|
|
240
|
+
) {
|
|
241
|
+
const result = this.result[protocol];
|
|
242
|
+
|
|
243
|
+
if (result.latencyInMilliseconds === undefined) {
|
|
244
|
+
LoggerProxy.logger.log(
|
|
245
|
+
// @ts-ignore
|
|
246
|
+
`Reachability:ReachabilityPeerConnection#saveResult --> Successfully reached ${this.clusterName} over ${protocol}: ${latency}ms`
|
|
247
|
+
);
|
|
248
|
+
result.latencyInMilliseconds = latency;
|
|
249
|
+
result.result = 'reachable';
|
|
250
|
+
if (publicIp) {
|
|
251
|
+
result.clientMediaIPs = [publicIp];
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
this.emit(
|
|
255
|
+
{
|
|
256
|
+
file: 'reachabilityPeerConnection',
|
|
257
|
+
function: 'saveResult',
|
|
258
|
+
},
|
|
259
|
+
ReachabilityPeerConnectionEvents.resultReady,
|
|
260
|
+
{
|
|
261
|
+
protocol,
|
|
262
|
+
...result,
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
} else {
|
|
266
|
+
this.addPublicIp(protocol, publicIp);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (serverIp) {
|
|
270
|
+
if (!this.emittedSubnets.has(serverIp)) {
|
|
271
|
+
this.emittedSubnets.add(serverIp);
|
|
272
|
+
this.emit(
|
|
273
|
+
{
|
|
274
|
+
file: 'reachabilityPeerConnection',
|
|
275
|
+
function: 'saveResult',
|
|
276
|
+
},
|
|
277
|
+
ReachabilityPeerConnectionEvents.reachedSubnets,
|
|
278
|
+
{
|
|
279
|
+
subnets: [serverIp],
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Determines NAT type by analyzing server reflexive candidate patterns
|
|
288
|
+
* @param {RTCIceCandidate} candidate server reflexive candidate
|
|
289
|
+
* @returns {void}
|
|
290
|
+
*/
|
|
291
|
+
private determineNatTypeForSrflxCandidate(candidate: RTCIceCandidate) {
|
|
292
|
+
this.srflxIceCandidates.push(candidate);
|
|
293
|
+
|
|
294
|
+
if (this.srflxIceCandidates.length > 1) {
|
|
295
|
+
const portsFound: Record<string, Set<number>> = {};
|
|
296
|
+
|
|
297
|
+
this.srflxIceCandidates.forEach((c) => {
|
|
298
|
+
const key = `${c.address}:${c.relatedPort}`;
|
|
299
|
+
if (!portsFound[key]) {
|
|
300
|
+
portsFound[key] = new Set();
|
|
301
|
+
}
|
|
302
|
+
portsFound[key].add(c.port);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
Object.entries(portsFound).forEach(([, ports]) => {
|
|
306
|
+
if (ports.size > 1) {
|
|
307
|
+
// Found candidates with the same address and relatedPort, but different ports
|
|
308
|
+
this.emit(
|
|
309
|
+
{
|
|
310
|
+
file: 'reachabilityPeerConnection',
|
|
311
|
+
function: 'determineNatTypeForSrflxCandidate',
|
|
312
|
+
},
|
|
313
|
+
ReachabilityPeerConnectionEvents.natTypeUpdated,
|
|
314
|
+
{
|
|
315
|
+
natType: NatType.SymmetricNat,
|
|
316
|
+
}
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Registers a listener for the icecandidate event
|
|
325
|
+
*
|
|
326
|
+
* @returns {void}
|
|
327
|
+
*/
|
|
328
|
+
private registerIceCandidateListener() {
|
|
329
|
+
this.pc.onicecandidate = (e) => {
|
|
330
|
+
const TURN_TLS_PORT = 443;
|
|
331
|
+
const CANDIDATE_TYPES = {
|
|
332
|
+
SERVER_REFLEXIVE: 'srflx',
|
|
333
|
+
RELAY: 'relay',
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const latencyInMilliseconds = this.getElapsedTime();
|
|
337
|
+
|
|
338
|
+
if (e.candidate) {
|
|
339
|
+
if (e.candidate.type === CANDIDATE_TYPES.SERVER_REFLEXIVE) {
|
|
340
|
+
let serverIp = null;
|
|
341
|
+
if ('url' in e.candidate) {
|
|
342
|
+
const stunServerUrlRegex = /stun:([\d.]+):\d+/;
|
|
343
|
+
|
|
344
|
+
const match = (e.candidate as any).url.match(stunServerUrlRegex);
|
|
345
|
+
serverIp = match && match[1];
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
this.saveResult('udp', latencyInMilliseconds, e.candidate.address, serverIp);
|
|
349
|
+
|
|
350
|
+
this.determineNatTypeForSrflxCandidate(e.candidate);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (e.candidate.type === CANDIDATE_TYPES.RELAY) {
|
|
354
|
+
const protocol = e.candidate.port === TURN_TLS_PORT ? 'xtls' : 'tcp';
|
|
355
|
+
this.saveResult(protocol, latencyInMilliseconds, null, e.candidate.address);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Starts the process of doing UDP, TCP, and XTLS reachability checks.
|
|
363
|
+
* @returns {Promise<ClusterReachabilityResult>}
|
|
364
|
+
*/
|
|
365
|
+
async start(): Promise<ClusterReachabilityResult> {
|
|
366
|
+
if (!this.pc) {
|
|
367
|
+
LoggerProxy.logger.warn(
|
|
368
|
+
`Reachability:ReachabilityPeerConnection#start --> Error: peerConnection is undefined`
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
return this.result;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Initialize this.result as saying that nothing is reachable.
|
|
375
|
+
// It will get updated as we go along and successfully gather ICE candidates.
|
|
376
|
+
this.result.udp = {
|
|
377
|
+
result: this.numUdpUrls > 0 ? 'unreachable' : 'untested',
|
|
378
|
+
};
|
|
379
|
+
this.result.tcp = {
|
|
380
|
+
result: this.numTcpUrls > 0 ? 'unreachable' : 'untested',
|
|
381
|
+
};
|
|
382
|
+
this.result.xtls = {
|
|
383
|
+
result: this.numXTlsUrls > 0 ? 'unreachable' : 'untested',
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
try {
|
|
387
|
+
const offer = await this.pc.createOffer({offerToReceiveAudio: true});
|
|
388
|
+
|
|
389
|
+
this.startTimestamp = performance.now();
|
|
390
|
+
|
|
391
|
+
// Set up the state change listeners before triggering the ICE gathering
|
|
392
|
+
const gatherIceCandidatePromise = this.gatherIceCandidates();
|
|
393
|
+
|
|
394
|
+
// not awaiting the next call on purpose, because we're not sending the offer anywhere and there won't be any answer
|
|
395
|
+
// we just need to make this call to trigger the ICE gathering process
|
|
396
|
+
this.pc.setLocalDescription(offer);
|
|
397
|
+
|
|
398
|
+
await gatherIceCandidatePromise;
|
|
399
|
+
} catch (error) {
|
|
400
|
+
LoggerProxy.logger.warn(`Reachability:ReachabilityPeerConnection#start --> Error: `, error);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return this.result;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Starts the process of gathering ICE candidates
|
|
408
|
+
* @returns {Promise} promise that's resolved once reachability checks are completed or timeout is reached
|
|
409
|
+
*/
|
|
410
|
+
private gatherIceCandidates() {
|
|
411
|
+
this.registerIceGatheringStateChangeListener();
|
|
412
|
+
this.registerIceCandidateListener();
|
|
413
|
+
|
|
414
|
+
return this.defer.promise;
|
|
415
|
+
}
|
|
416
|
+
}
|