genesys-cloud-streaming-client 19.1.0-develop.137 → 19.1.0-double-feature.2
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/cjs/client.js +2 -0
- package/dist/cjs/connection-transfer.d.ts +7 -0
- package/dist/cjs/connection-transfer.js +19 -0
- package/dist/cjs/stanza-definitions/webrtc-signaling.d.ts +2 -0
- package/dist/cjs/stanza-definitions/xep0051.d.ts +19 -0
- package/dist/cjs/stanza-definitions/xep0051.js +28 -0
- package/dist/cjs/types/genesys-cloud-media-session.js +1 -2
- package/dist/cjs/types/named-agent.d.ts +2 -0
- package/dist/cjs/webrtc.d.ts +1 -1
- package/dist/cjs/webrtc.js +10 -3
- package/dist/deploy-info.json +3 -3
- package/dist/es/client.js +2 -0
- package/dist/es/connection-transfer.d.ts +7 -0
- package/dist/es/connection-transfer.js +15 -0
- package/dist/es/index.bundle.js +52 -5
- package/dist/es/stanza-definitions/webrtc-signaling.d.ts +2 -0
- package/dist/es/stanza-definitions/xep0051.d.ts +19 -0
- package/dist/es/stanza-definitions/xep0051.js +25 -0
- package/dist/es/types/genesys-cloud-media-session.js +1 -2
- package/dist/es/types/named-agent.d.ts +2 -0
- package/dist/es/webrtc.d.ts +1 -1
- package/dist/es/webrtc.js +10 -3
- package/dist/npm/CHANGELOG.md +4 -0
- package/dist/npm/client.js +2 -0
- package/dist/npm/connection-transfer.d.ts +7 -0
- package/dist/npm/connection-transfer.js +19 -0
- package/dist/npm/stanza-definitions/webrtc-signaling.d.ts +2 -0
- package/dist/npm/stanza-definitions/xep0051.d.ts +19 -0
- package/dist/npm/stanza-definitions/xep0051.js +28 -0
- package/dist/npm/types/genesys-cloud-media-session.js +1 -2
- package/dist/npm/types/named-agent.d.ts +2 -0
- package/dist/npm/webrtc.d.ts +1 -1
- package/dist/npm/webrtc.js +10 -3
- package/dist/streaming-client.browser.js +4 -4
- package/dist/v19/streaming-client.browser.js +4 -4
- package/dist/v19.1.0/streaming-client.browser.js +4 -4
- package/package.json +1 -1
package/dist/cjs/client.js
CHANGED
|
@@ -20,6 +20,7 @@ const sasl_error_1 = tslib_1.__importDefault(require("./types/sasl-error"));
|
|
|
20
20
|
const timeout_error_1 = require("./types/timeout-error");
|
|
21
21
|
const messenger_1 = require("./messenger");
|
|
22
22
|
const uuid_1 = require("uuid");
|
|
23
|
+
const connection_transfer_1 = require("./connection-transfer");
|
|
23
24
|
let extensions = {
|
|
24
25
|
notifications: notifications_1.Notifications,
|
|
25
26
|
webrtcSessions: webrtc_1.WebrtcExtension,
|
|
@@ -495,6 +496,7 @@ class Client extends events_1.default {
|
|
|
495
496
|
}
|
|
496
497
|
}
|
|
497
498
|
async setupConnectionMonitoring(stanzaInstance) {
|
|
499
|
+
stanzaInstance.connectionTransfer = new connection_transfer_1.ConnectionTransfer(this, stanzaInstance);
|
|
498
500
|
const setupClientPinger = (message) => {
|
|
499
501
|
const logMessage = `${message}, falling back to client-side pinging`;
|
|
500
502
|
this.logger.warn(logMessage, { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConnectionTransfer = void 0;
|
|
4
|
+
const xep0051_1 = require("./stanza-definitions/xep0051");
|
|
5
|
+
class ConnectionTransfer {
|
|
6
|
+
constructor(client, stanzaInstance) {
|
|
7
|
+
this.client = client;
|
|
8
|
+
this.stanzaInstance = stanzaInstance;
|
|
9
|
+
stanzaInstance.stanzas.define(xep0051_1.connectionTransfer);
|
|
10
|
+
// Hawk maps `v2.system.socket_closing` to XEP-0051 Connection Transfer
|
|
11
|
+
// The docs says we have up to one minute to disconnect and connect a new WebSocket, so we should be proactive in reconnecting.
|
|
12
|
+
stanzaInstance.on('iq:set:connectionTransfer', (iq) => {
|
|
13
|
+
client.logger.warn('connection transfer (socket_closing) event received', { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
|
|
14
|
+
void client.disconnect();
|
|
15
|
+
void client.connect({ keepTryingOnFailure: true });
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.ConnectionTransfer = ConnectionTransfer;
|
|
@@ -18,6 +18,8 @@ declare module 'stanza/protocol' {
|
|
|
18
18
|
interface ReceivedMessage {
|
|
19
19
|
mediaMessage?: GenesysMediaMessage;
|
|
20
20
|
}
|
|
21
|
+
}
|
|
22
|
+
declare module 'stanza' {
|
|
21
23
|
interface AgentEvents {
|
|
22
24
|
'iq:set:genesysWebrtc': Stanzas.ReceivedIQ & {
|
|
23
25
|
genesysWebrtc: GenesysWebrtcJsonRpcMessage;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Stanzas } from 'stanza';
|
|
2
|
+
import { DefinitionOptions } from 'stanza/jxt';
|
|
3
|
+
declare module 'stanza' {
|
|
4
|
+
interface AgentEvents {
|
|
5
|
+
'iq:set:connectionTransfer': Stanzas.ReceivedIQ & {
|
|
6
|
+
query: ConnectionTransfer;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
declare module 'stanza/protocol' {
|
|
11
|
+
interface IQPayload {
|
|
12
|
+
query?: ConnectionTransfer;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export interface ConnectionTransfer {
|
|
16
|
+
domain?: string;
|
|
17
|
+
server?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const connectionTransfer: DefinitionOptions;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.connectionTransfer = void 0;
|
|
4
|
+
const jxt_1 = require("stanza/jxt");
|
|
5
|
+
// XEP-0051: Connection Transfer
|
|
6
|
+
// Source: https://xmpp.org/extensions/xep-0051.html
|
|
7
|
+
// Version: 0.2.1 (2022-03-08)
|
|
8
|
+
// ---------------------------
|
|
9
|
+
// We don't currently use domain or server
|
|
10
|
+
const NS_CONNECTION_TRANSFER = 'urn:xmpp:cxfr';
|
|
11
|
+
/*
|
|
12
|
+
<iq xmlns="jabber:client" id="<someId>" to="<toJID>" type="set">
|
|
13
|
+
<query xmlns="urn:xmpp:cxfr">
|
|
14
|
+
<domain>jabber.org</domain>
|
|
15
|
+
<server>123.123.123.122</server>
|
|
16
|
+
</query>
|
|
17
|
+
</iq>
|
|
18
|
+
*/
|
|
19
|
+
exports.connectionTransfer = {
|
|
20
|
+
path: 'iq.query',
|
|
21
|
+
aliases: ['iq.connectionTransfer'],
|
|
22
|
+
namespace: NS_CONNECTION_TRANSFER,
|
|
23
|
+
element: 'query',
|
|
24
|
+
fields: {
|
|
25
|
+
domain: jxt_1.childText(null, 'domain'),
|
|
26
|
+
server: jxt_1.childText(null, 'server')
|
|
27
|
+
}
|
|
28
|
+
};
|
|
@@ -66,7 +66,6 @@ class GenesysCloudMediaSession {
|
|
|
66
66
|
// if we have a state mismatch
|
|
67
67
|
if (this.state !== 'ended' && ['failed', 'closed'].includes(this.peerConnection.connectionState)) {
|
|
68
68
|
this.log('warn', 'state mismatch between session.state and peerConnection.connectionState, manually terminating the session', { sessionId: this.id, conversationId: this.conversationId, sessionType: this.sessionType });
|
|
69
|
-
this.state = 'ended';
|
|
70
69
|
this.onSessionTerminate();
|
|
71
70
|
}
|
|
72
71
|
}
|
|
@@ -171,7 +170,6 @@ class GenesysCloudMediaSession {
|
|
|
171
170
|
}
|
|
172
171
|
else if (connectionState === 'failed') {
|
|
173
172
|
this.log('info', 'Connection was interrupted and failed to recover, cleaning up', { sessionId, conversationId, sessionType });
|
|
174
|
-
this.state = 'ended';
|
|
175
173
|
this.onSessionTerminate();
|
|
176
174
|
}
|
|
177
175
|
}
|
|
@@ -241,6 +239,7 @@ class GenesysCloudMediaSession {
|
|
|
241
239
|
});
|
|
242
240
|
}
|
|
243
241
|
onSessionTerminate(reason) {
|
|
242
|
+
this.state = 'ended';
|
|
244
243
|
if (this.peerConnection) {
|
|
245
244
|
this.peerConnection.close();
|
|
246
245
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Agent } from 'stanza';
|
|
2
2
|
import { Ping } from '../ping';
|
|
3
3
|
import { ServerMonitor } from '../server-monitor';
|
|
4
|
+
import { ConnectionTransfer } from '../connection-transfer';
|
|
4
5
|
export interface NamedAgent extends Omit<Agent, 'disconnect'> {
|
|
5
6
|
id: string;
|
|
6
7
|
channelId?: string;
|
|
7
8
|
originalEmitter?: Function;
|
|
8
9
|
pinger?: Ping;
|
|
9
10
|
serverMonitor?: ServerMonitor;
|
|
11
|
+
connectionTransfer?: ConnectionTransfer;
|
|
10
12
|
disconnect: () => Promise<void>;
|
|
11
13
|
}
|
package/dist/cjs/webrtc.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ export declare class WebrtcExtension extends EventEmitter implements StreamingCl
|
|
|
43
43
|
private stanzaInstance?;
|
|
44
44
|
private webrtcSessions;
|
|
45
45
|
private reinviteCache;
|
|
46
|
-
private
|
|
46
|
+
private sessionsMap;
|
|
47
47
|
get jid(): string | undefined;
|
|
48
48
|
constructor(client: Client, clientOptions: IClientOptions);
|
|
49
49
|
private onOnlineStatusChange;
|
package/dist/cjs/webrtc.js
CHANGED
|
@@ -63,7 +63,8 @@ class WebrtcExtension extends events_1.EventEmitter {
|
|
|
63
63
|
max: 5,
|
|
64
64
|
ttl: 1000 * 60 * 3
|
|
65
65
|
});
|
|
66
|
-
|
|
66
|
+
// private sdpOverXmpp = false;
|
|
67
|
+
this.sessionsMap = {};
|
|
67
68
|
this.client = client;
|
|
68
69
|
this.config = {
|
|
69
70
|
allowIPv6: clientOptions.allowIPv6 === true,
|
|
@@ -219,6 +220,7 @@ class WebrtcExtension extends events_1.EventEmitter {
|
|
|
219
220
|
this.webrtcSessions = this.webrtcSessions.filter(s => s.id !== session.id);
|
|
220
221
|
});
|
|
221
222
|
this.webrtcSessions.push(session);
|
|
223
|
+
// delete this.sessionsMap[session.id];
|
|
222
224
|
this.logger.info('emitting sdp media-session (offer');
|
|
223
225
|
this.applyEarlyIceCandidates(session);
|
|
224
226
|
return this.emit(events.INCOMING_RTCSESSION, session);
|
|
@@ -301,13 +303,14 @@ class WebrtcExtension extends events_1.EventEmitter {
|
|
|
301
303
|
}
|
|
302
304
|
}
|
|
303
305
|
prepareSession(options) {
|
|
304
|
-
if (this.
|
|
306
|
+
if (options.sid && this.sessionsMap[options.sid]) {
|
|
305
307
|
this.logger.debug('skipping creation of jingle webrtc session due to sdpOverXmpp');
|
|
306
308
|
return;
|
|
307
309
|
}
|
|
308
310
|
const pendingSession = this.pendingSessions[options.sid];
|
|
309
311
|
if (pendingSession) {
|
|
310
312
|
delete this.pendingSessions[pendingSession.sessionId];
|
|
313
|
+
// delete this.sessionsMap[pendingSession.sessionId];
|
|
311
314
|
}
|
|
312
315
|
const ignoreHostCandidatesForForceTurnFF = this.getIceTransportPolicy() === 'relay' && browserama_1.isFirefox;
|
|
313
316
|
const gcSessionOpts = {
|
|
@@ -524,7 +527,8 @@ class WebrtcExtension extends events_1.EventEmitter {
|
|
|
524
527
|
sdpOverXmpp: msg.propose.sdpOverXmpp,
|
|
525
528
|
privAnswerMode: msg.propose.privAnswerMode
|
|
526
529
|
};
|
|
527
|
-
this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
|
|
530
|
+
// this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
|
|
531
|
+
this.sessionsMap[sessionInfo.id] = !!sessionInfo.sdpOverXmpp;
|
|
528
532
|
this.pendingSessions[sessionId] = sessionInfo;
|
|
529
533
|
}
|
|
530
534
|
if (sessionInfo.accepted) {
|
|
@@ -536,6 +540,7 @@ class WebrtcExtension extends events_1.EventEmitter {
|
|
|
536
540
|
}
|
|
537
541
|
handleRetract(sessionId) {
|
|
538
542
|
this.logger.info('retract received', this.getLogDetailsForPendingSessionId(sessionId));
|
|
543
|
+
// delete this.sessionsMap[sessionId];
|
|
539
544
|
delete this.pendingSessions[sessionId];
|
|
540
545
|
return this.emit(events.CANCEL_INCOMING_RTCSESSION, sessionId);
|
|
541
546
|
}
|
|
@@ -633,6 +638,7 @@ class WebrtcExtension extends events_1.EventEmitter {
|
|
|
633
638
|
this.emit(events.RTCSESSION_ERROR, 'Cannot reject session because it is not pending or does not exist');
|
|
634
639
|
return;
|
|
635
640
|
}
|
|
641
|
+
// delete this.sessionsMap[sessionId];
|
|
636
642
|
delete this.pendingSessions[sessionId];
|
|
637
643
|
if (ignore) {
|
|
638
644
|
this.ignoredSessions.set(sessionId, true);
|
|
@@ -708,6 +714,7 @@ class WebrtcExtension extends events_1.EventEmitter {
|
|
|
708
714
|
}
|
|
709
715
|
};
|
|
710
716
|
delete this.pendingSessions[sessionId];
|
|
717
|
+
// delete this.sessionsMap[sessionId];
|
|
711
718
|
this.logger.info('sending jingle retract', logDetails);
|
|
712
719
|
await this.stanzaInstance.send('message', retract); // send as Message
|
|
713
720
|
this.logger.info('sent jingle retract', logDetails);
|
package/dist/deploy-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "developercenter-cdn/streaming-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "double-feature",
|
|
4
4
|
"ecosystem": "pc",
|
|
5
5
|
"team": "Client Streaming and Signaling",
|
|
6
6
|
"indexFiles": [
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"file": "v19/streaming-client.browser.js"
|
|
12
12
|
}
|
|
13
13
|
],
|
|
14
|
-
"build": "
|
|
15
|
-
"buildDate": "2025-05-
|
|
14
|
+
"build": "2",
|
|
15
|
+
"buildDate": "2025-05-30T16:57:36.877672642Z",
|
|
16
16
|
"appName": "developercenter-cdn/streaming-client",
|
|
17
17
|
"gcServiceName": "developercenter-cdn--streaming-client-webui"
|
|
18
18
|
}
|
package/dist/es/client.js
CHANGED
|
@@ -18,6 +18,7 @@ import SaslError from './types/sasl-error';
|
|
|
18
18
|
import { TimeoutError } from './types/timeout-error';
|
|
19
19
|
import { MessengerExtension } from './messenger';
|
|
20
20
|
import { v4 } from 'uuid';
|
|
21
|
+
import { ConnectionTransfer } from './connection-transfer';
|
|
21
22
|
let extensions = {
|
|
22
23
|
notifications: Notifications,
|
|
23
24
|
webrtcSessions: WebrtcExtension,
|
|
@@ -504,6 +505,7 @@ export class Client extends EventEmitter {
|
|
|
504
505
|
}
|
|
505
506
|
setupConnectionMonitoring(stanzaInstance) {
|
|
506
507
|
return __awaiter(this, void 0, void 0, function* () {
|
|
508
|
+
stanzaInstance.connectionTransfer = new ConnectionTransfer(this, stanzaInstance);
|
|
507
509
|
const setupClientPinger = (message) => {
|
|
508
510
|
const logMessage = `${message}, falling back to client-side pinging`;
|
|
509
511
|
this.logger.warn(logMessage, { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { connectionTransfer } from './stanza-definitions/xep0051';
|
|
2
|
+
export class ConnectionTransfer {
|
|
3
|
+
constructor(client, stanzaInstance) {
|
|
4
|
+
this.client = client;
|
|
5
|
+
this.stanzaInstance = stanzaInstance;
|
|
6
|
+
stanzaInstance.stanzas.define(connectionTransfer);
|
|
7
|
+
// Hawk maps `v2.system.socket_closing` to XEP-0051 Connection Transfer
|
|
8
|
+
// The docs says we have up to one minute to disconnect and connect a new WebSocket, so we should be proactive in reconnecting.
|
|
9
|
+
stanzaInstance.on('iq:set:connectionTransfer', (iq) => {
|
|
10
|
+
client.logger.warn('connection transfer (socket_closing) event received', { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
|
|
11
|
+
void client.disconnect();
|
|
12
|
+
void client.connect({ keepTryingOnFailure: true });
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
package/dist/es/index.bundle.js
CHANGED
|
@@ -31477,7 +31477,6 @@ class GenesysCloudMediaSession {
|
|
|
31477
31477
|
// if we have a state mismatch
|
|
31478
31478
|
if (this.state !== 'ended' && ['failed', 'closed'].includes(this.peerConnection.connectionState)) {
|
|
31479
31479
|
this.log('warn', 'state mismatch between session.state and peerConnection.connectionState, manually terminating the session', { sessionId: this.id, conversationId: this.conversationId, sessionType: this.sessionType });
|
|
31480
|
-
this.state = 'ended';
|
|
31481
31480
|
this.onSessionTerminate();
|
|
31482
31481
|
}
|
|
31483
31482
|
}
|
|
@@ -31590,7 +31589,6 @@ class GenesysCloudMediaSession {
|
|
|
31590
31589
|
}
|
|
31591
31590
|
else if (connectionState === 'failed') {
|
|
31592
31591
|
this.log('info', 'Connection was interrupted and failed to recover, cleaning up', { sessionId, conversationId, sessionType });
|
|
31593
|
-
this.state = 'ended';
|
|
31594
31592
|
this.onSessionTerminate();
|
|
31595
31593
|
}
|
|
31596
31594
|
}
|
|
@@ -31662,6 +31660,7 @@ class GenesysCloudMediaSession {
|
|
|
31662
31660
|
});
|
|
31663
31661
|
}
|
|
31664
31662
|
onSessionTerminate(reason) {
|
|
31663
|
+
this.state = 'ended';
|
|
31665
31664
|
if (this.peerConnection) {
|
|
31666
31665
|
this.peerConnection.close();
|
|
31667
31666
|
}
|
|
@@ -32001,7 +32000,8 @@ class WebrtcExtension extends EventEmitter {
|
|
|
32001
32000
|
max: 5,
|
|
32002
32001
|
ttl: 1000 * 60 * 3
|
|
32003
32002
|
});
|
|
32004
|
-
|
|
32003
|
+
// private sdpOverXmpp = false;
|
|
32004
|
+
this.sessionsMap = {};
|
|
32005
32005
|
this.client = client;
|
|
32006
32006
|
this.config = {
|
|
32007
32007
|
allowIPv6: clientOptions.allowIPv6 === true,
|
|
@@ -32156,6 +32156,7 @@ class WebrtcExtension extends EventEmitter {
|
|
|
32156
32156
|
this.webrtcSessions = this.webrtcSessions.filter(s => s.id !== session.id);
|
|
32157
32157
|
});
|
|
32158
32158
|
this.webrtcSessions.push(session);
|
|
32159
|
+
// delete this.sessionsMap[session.id];
|
|
32159
32160
|
this.logger.info('emitting sdp media-session (offer');
|
|
32160
32161
|
this.applyEarlyIceCandidates(session);
|
|
32161
32162
|
return this.emit(events.INCOMING_RTCSESSION, session);
|
|
@@ -32251,13 +32252,14 @@ class WebrtcExtension extends EventEmitter {
|
|
|
32251
32252
|
});
|
|
32252
32253
|
}
|
|
32253
32254
|
prepareSession(options) {
|
|
32254
|
-
if (this.
|
|
32255
|
+
if (options.sid && this.sessionsMap[options.sid]) {
|
|
32255
32256
|
this.logger.debug('skipping creation of jingle webrtc session due to sdpOverXmpp');
|
|
32256
32257
|
return;
|
|
32257
32258
|
}
|
|
32258
32259
|
const pendingSession = this.pendingSessions[options.sid];
|
|
32259
32260
|
if (pendingSession) {
|
|
32260
32261
|
delete this.pendingSessions[pendingSession.sessionId];
|
|
32262
|
+
// delete this.sessionsMap[pendingSession.sessionId];
|
|
32261
32263
|
}
|
|
32262
32264
|
const ignoreHostCandidatesForForceTurnFF = this.getIceTransportPolicy() === 'relay' && browserama_min.exports.isFirefox;
|
|
32263
32265
|
const gcSessionOpts = {
|
|
@@ -32467,7 +32469,8 @@ class WebrtcExtension extends EventEmitter {
|
|
|
32467
32469
|
sessionInfo = Object.assign(Object.assign({}, msg.propose), { toJid: msg.to, fromJid,
|
|
32468
32470
|
sessionType,
|
|
32469
32471
|
roomJid, id: sessionId, sdpOverXmpp: msg.propose.sdpOverXmpp, privAnswerMode: msg.propose.privAnswerMode });
|
|
32470
|
-
this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
|
|
32472
|
+
// this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
|
|
32473
|
+
this.sessionsMap[sessionInfo.id] = !!sessionInfo.sdpOverXmpp;
|
|
32471
32474
|
this.pendingSessions[sessionId] = sessionInfo;
|
|
32472
32475
|
}
|
|
32473
32476
|
if (sessionInfo.accepted) {
|
|
@@ -32480,6 +32483,7 @@ class WebrtcExtension extends EventEmitter {
|
|
|
32480
32483
|
}
|
|
32481
32484
|
handleRetract(sessionId) {
|
|
32482
32485
|
this.logger.info('retract received', this.getLogDetailsForPendingSessionId(sessionId));
|
|
32486
|
+
// delete this.sessionsMap[sessionId];
|
|
32483
32487
|
delete this.pendingSessions[sessionId];
|
|
32484
32488
|
return this.emit(events.CANCEL_INCOMING_RTCSESSION, sessionId);
|
|
32485
32489
|
}
|
|
@@ -32582,6 +32586,7 @@ class WebrtcExtension extends EventEmitter {
|
|
|
32582
32586
|
this.emit(events.RTCSESSION_ERROR, 'Cannot reject session because it is not pending or does not exist');
|
|
32583
32587
|
return;
|
|
32584
32588
|
}
|
|
32589
|
+
// delete this.sessionsMap[sessionId];
|
|
32585
32590
|
delete this.pendingSessions[sessionId];
|
|
32586
32591
|
if (ignore) {
|
|
32587
32592
|
this.ignoredSessions.set(sessionId, true);
|
|
@@ -32665,6 +32670,7 @@ class WebrtcExtension extends EventEmitter {
|
|
|
32665
32670
|
}
|
|
32666
32671
|
};
|
|
32667
32672
|
delete this.pendingSessions[sessionId];
|
|
32673
|
+
// delete this.sessionsMap[sessionId];
|
|
32668
32674
|
this.logger.info('sending jingle retract', logDetails);
|
|
32669
32675
|
yield this.stanzaInstance.send('message', retract); // send as Message
|
|
32670
32676
|
this.logger.info('sent jingle retract', logDetails);
|
|
@@ -42892,6 +42898,46 @@ class MessengerExtension extends Emitter {
|
|
|
42892
42898
|
}
|
|
42893
42899
|
}
|
|
42894
42900
|
|
|
42901
|
+
// XEP-0051: Connection Transfer
|
|
42902
|
+
// Source: https://xmpp.org/extensions/xep-0051.html
|
|
42903
|
+
// Version: 0.2.1 (2022-03-08)
|
|
42904
|
+
// ---------------------------
|
|
42905
|
+
// We don't currently use domain or server
|
|
42906
|
+
const NS_CONNECTION_TRANSFER = 'urn:xmpp:cxfr';
|
|
42907
|
+
/*
|
|
42908
|
+
<iq xmlns="jabber:client" id="<someId>" to="<toJID>" type="set">
|
|
42909
|
+
<query xmlns="urn:xmpp:cxfr">
|
|
42910
|
+
<domain>jabber.org</domain>
|
|
42911
|
+
<server>123.123.123.122</server>
|
|
42912
|
+
</query>
|
|
42913
|
+
</iq>
|
|
42914
|
+
*/
|
|
42915
|
+
const connectionTransfer = {
|
|
42916
|
+
path: 'iq.query',
|
|
42917
|
+
aliases: ['iq.connectionTransfer'],
|
|
42918
|
+
namespace: NS_CONNECTION_TRANSFER,
|
|
42919
|
+
element: 'query',
|
|
42920
|
+
fields: {
|
|
42921
|
+
domain: jxt.childText(null, 'domain'),
|
|
42922
|
+
server: jxt.childText(null, 'server')
|
|
42923
|
+
}
|
|
42924
|
+
};
|
|
42925
|
+
|
|
42926
|
+
class ConnectionTransfer {
|
|
42927
|
+
constructor(client, stanzaInstance) {
|
|
42928
|
+
this.client = client;
|
|
42929
|
+
this.stanzaInstance = stanzaInstance;
|
|
42930
|
+
stanzaInstance.stanzas.define(connectionTransfer);
|
|
42931
|
+
// Hawk maps `v2.system.socket_closing` to XEP-0051 Connection Transfer
|
|
42932
|
+
// The docs says we have up to one minute to disconnect and connect a new WebSocket, so we should be proactive in reconnecting.
|
|
42933
|
+
stanzaInstance.on('iq:set:connectionTransfer', (iq) => {
|
|
42934
|
+
client.logger.warn('connection transfer (socket_closing) event received', { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
|
|
42935
|
+
void client.disconnect();
|
|
42936
|
+
void client.connect({ keepTryingOnFailure: true });
|
|
42937
|
+
});
|
|
42938
|
+
}
|
|
42939
|
+
}
|
|
42940
|
+
|
|
42895
42941
|
let extensions = {
|
|
42896
42942
|
notifications: Notifications,
|
|
42897
42943
|
webrtcSessions: WebrtcExtension,
|
|
@@ -43378,6 +43424,7 @@ class Client extends EventEmitter {
|
|
|
43378
43424
|
}
|
|
43379
43425
|
setupConnectionMonitoring(stanzaInstance) {
|
|
43380
43426
|
return __awaiter$5(this, void 0, void 0, function* () {
|
|
43427
|
+
stanzaInstance.connectionTransfer = new ConnectionTransfer(this, stanzaInstance);
|
|
43381
43428
|
const setupClientPinger = (message) => {
|
|
43382
43429
|
const logMessage = `${message}, falling back to client-side pinging`;
|
|
43383
43430
|
this.logger.warn(logMessage, { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
|
|
@@ -18,6 +18,8 @@ declare module 'stanza/protocol' {
|
|
|
18
18
|
interface ReceivedMessage {
|
|
19
19
|
mediaMessage?: GenesysMediaMessage;
|
|
20
20
|
}
|
|
21
|
+
}
|
|
22
|
+
declare module 'stanza' {
|
|
21
23
|
interface AgentEvents {
|
|
22
24
|
'iq:set:genesysWebrtc': Stanzas.ReceivedIQ & {
|
|
23
25
|
genesysWebrtc: GenesysWebrtcJsonRpcMessage;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Stanzas } from 'stanza';
|
|
2
|
+
import { DefinitionOptions } from 'stanza/jxt';
|
|
3
|
+
declare module 'stanza' {
|
|
4
|
+
interface AgentEvents {
|
|
5
|
+
'iq:set:connectionTransfer': Stanzas.ReceivedIQ & {
|
|
6
|
+
query: ConnectionTransfer;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
declare module 'stanza/protocol' {
|
|
11
|
+
interface IQPayload {
|
|
12
|
+
query?: ConnectionTransfer;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export interface ConnectionTransfer {
|
|
16
|
+
domain?: string;
|
|
17
|
+
server?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const connectionTransfer: DefinitionOptions;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { childText } from 'stanza/jxt';
|
|
2
|
+
// XEP-0051: Connection Transfer
|
|
3
|
+
// Source: https://xmpp.org/extensions/xep-0051.html
|
|
4
|
+
// Version: 0.2.1 (2022-03-08)
|
|
5
|
+
// ---------------------------
|
|
6
|
+
// We don't currently use domain or server
|
|
7
|
+
const NS_CONNECTION_TRANSFER = 'urn:xmpp:cxfr';
|
|
8
|
+
/*
|
|
9
|
+
<iq xmlns="jabber:client" id="<someId>" to="<toJID>" type="set">
|
|
10
|
+
<query xmlns="urn:xmpp:cxfr">
|
|
11
|
+
<domain>jabber.org</domain>
|
|
12
|
+
<server>123.123.123.122</server>
|
|
13
|
+
</query>
|
|
14
|
+
</iq>
|
|
15
|
+
*/
|
|
16
|
+
export const connectionTransfer = {
|
|
17
|
+
path: 'iq.query',
|
|
18
|
+
aliases: ['iq.connectionTransfer'],
|
|
19
|
+
namespace: NS_CONNECTION_TRANSFER,
|
|
20
|
+
element: 'query',
|
|
21
|
+
fields: {
|
|
22
|
+
domain: childText(null, 'domain'),
|
|
23
|
+
server: childText(null, 'server')
|
|
24
|
+
}
|
|
25
|
+
};
|
|
@@ -63,7 +63,6 @@ export class GenesysCloudMediaSession {
|
|
|
63
63
|
// if we have a state mismatch
|
|
64
64
|
if (this.state !== 'ended' && ['failed', 'closed'].includes(this.peerConnection.connectionState)) {
|
|
65
65
|
this.log('warn', 'state mismatch between session.state and peerConnection.connectionState, manually terminating the session', { sessionId: this.id, conversationId: this.conversationId, sessionType: this.sessionType });
|
|
66
|
-
this.state = 'ended';
|
|
67
66
|
this.onSessionTerminate();
|
|
68
67
|
}
|
|
69
68
|
}
|
|
@@ -176,7 +175,6 @@ export class GenesysCloudMediaSession {
|
|
|
176
175
|
}
|
|
177
176
|
else if (connectionState === 'failed') {
|
|
178
177
|
this.log('info', 'Connection was interrupted and failed to recover, cleaning up', { sessionId, conversationId, sessionType });
|
|
179
|
-
this.state = 'ended';
|
|
180
178
|
this.onSessionTerminate();
|
|
181
179
|
}
|
|
182
180
|
}
|
|
@@ -248,6 +246,7 @@ export class GenesysCloudMediaSession {
|
|
|
248
246
|
});
|
|
249
247
|
}
|
|
250
248
|
onSessionTerminate(reason) {
|
|
249
|
+
this.state = 'ended';
|
|
251
250
|
if (this.peerConnection) {
|
|
252
251
|
this.peerConnection.close();
|
|
253
252
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Agent } from 'stanza';
|
|
2
2
|
import { Ping } from '../ping';
|
|
3
3
|
import { ServerMonitor } from '../server-monitor';
|
|
4
|
+
import { ConnectionTransfer } from '../connection-transfer';
|
|
4
5
|
export interface NamedAgent extends Omit<Agent, 'disconnect'> {
|
|
5
6
|
id: string;
|
|
6
7
|
channelId?: string;
|
|
7
8
|
originalEmitter?: Function;
|
|
8
9
|
pinger?: Ping;
|
|
9
10
|
serverMonitor?: ServerMonitor;
|
|
11
|
+
connectionTransfer?: ConnectionTransfer;
|
|
10
12
|
disconnect: () => Promise<void>;
|
|
11
13
|
}
|
package/dist/es/webrtc.d.ts
CHANGED
|
@@ -43,7 +43,7 @@ export declare class WebrtcExtension extends EventEmitter implements StreamingCl
|
|
|
43
43
|
private stanzaInstance?;
|
|
44
44
|
private webrtcSessions;
|
|
45
45
|
private reinviteCache;
|
|
46
|
-
private
|
|
46
|
+
private sessionsMap;
|
|
47
47
|
get jid(): string | undefined;
|
|
48
48
|
constructor(client: Client, clientOptions: IClientOptions);
|
|
49
49
|
private onOnlineStatusChange;
|
package/dist/es/webrtc.js
CHANGED
|
@@ -60,7 +60,8 @@ export class WebrtcExtension extends EventEmitter {
|
|
|
60
60
|
max: 5,
|
|
61
61
|
ttl: 1000 * 60 * 3
|
|
62
62
|
});
|
|
63
|
-
|
|
63
|
+
// private sdpOverXmpp = false;
|
|
64
|
+
this.sessionsMap = {};
|
|
64
65
|
this.client = client;
|
|
65
66
|
this.config = {
|
|
66
67
|
allowIPv6: clientOptions.allowIPv6 === true,
|
|
@@ -215,6 +216,7 @@ export class WebrtcExtension extends EventEmitter {
|
|
|
215
216
|
this.webrtcSessions = this.webrtcSessions.filter(s => s.id !== session.id);
|
|
216
217
|
});
|
|
217
218
|
this.webrtcSessions.push(session);
|
|
219
|
+
// delete this.sessionsMap[session.id];
|
|
218
220
|
this.logger.info('emitting sdp media-session (offer');
|
|
219
221
|
this.applyEarlyIceCandidates(session);
|
|
220
222
|
return this.emit(events.INCOMING_RTCSESSION, session);
|
|
@@ -310,13 +312,14 @@ export class WebrtcExtension extends EventEmitter {
|
|
|
310
312
|
});
|
|
311
313
|
}
|
|
312
314
|
prepareSession(options) {
|
|
313
|
-
if (this.
|
|
315
|
+
if (options.sid && this.sessionsMap[options.sid]) {
|
|
314
316
|
this.logger.debug('skipping creation of jingle webrtc session due to sdpOverXmpp');
|
|
315
317
|
return;
|
|
316
318
|
}
|
|
317
319
|
const pendingSession = this.pendingSessions[options.sid];
|
|
318
320
|
if (pendingSession) {
|
|
319
321
|
delete this.pendingSessions[pendingSession.sessionId];
|
|
322
|
+
// delete this.sessionsMap[pendingSession.sessionId];
|
|
320
323
|
}
|
|
321
324
|
const ignoreHostCandidatesForForceTurnFF = this.getIceTransportPolicy() === 'relay' && isFirefox;
|
|
322
325
|
const gcSessionOpts = {
|
|
@@ -526,7 +529,8 @@ export class WebrtcExtension extends EventEmitter {
|
|
|
526
529
|
sessionInfo = Object.assign(Object.assign({}, msg.propose), { toJid: msg.to, fromJid,
|
|
527
530
|
sessionType,
|
|
528
531
|
roomJid, id: sessionId, sdpOverXmpp: msg.propose.sdpOverXmpp, privAnswerMode: msg.propose.privAnswerMode });
|
|
529
|
-
this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
|
|
532
|
+
// this.sdpOverXmpp = !!sessionInfo.sdpOverXmpp;
|
|
533
|
+
this.sessionsMap[sessionInfo.id] = !!sessionInfo.sdpOverXmpp;
|
|
530
534
|
this.pendingSessions[sessionId] = sessionInfo;
|
|
531
535
|
}
|
|
532
536
|
if (sessionInfo.accepted) {
|
|
@@ -539,6 +543,7 @@ export class WebrtcExtension extends EventEmitter {
|
|
|
539
543
|
}
|
|
540
544
|
handleRetract(sessionId) {
|
|
541
545
|
this.logger.info('retract received', this.getLogDetailsForPendingSessionId(sessionId));
|
|
546
|
+
// delete this.sessionsMap[sessionId];
|
|
542
547
|
delete this.pendingSessions[sessionId];
|
|
543
548
|
return this.emit(events.CANCEL_INCOMING_RTCSESSION, sessionId);
|
|
544
549
|
}
|
|
@@ -641,6 +646,7 @@ export class WebrtcExtension extends EventEmitter {
|
|
|
641
646
|
this.emit(events.RTCSESSION_ERROR, 'Cannot reject session because it is not pending or does not exist');
|
|
642
647
|
return;
|
|
643
648
|
}
|
|
649
|
+
// delete this.sessionsMap[sessionId];
|
|
644
650
|
delete this.pendingSessions[sessionId];
|
|
645
651
|
if (ignore) {
|
|
646
652
|
this.ignoredSessions.set(sessionId, true);
|
|
@@ -724,6 +730,7 @@ export class WebrtcExtension extends EventEmitter {
|
|
|
724
730
|
}
|
|
725
731
|
};
|
|
726
732
|
delete this.pendingSessions[sessionId];
|
|
733
|
+
// delete this.sessionsMap[sessionId];
|
|
727
734
|
this.logger.info('sending jingle retract', logDetails);
|
|
728
735
|
yield this.stanzaInstance.send('message', retract); // send as Message
|
|
729
736
|
this.logger.info('sent jingle retract', logDetails);
|
package/dist/npm/CHANGELOG.md
CHANGED
|
@@ -9,9 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
9
9
|
* [STREAM-462](https://inindca.atlassian.net/browse/STREAM-462) - Update Stanza timeout timer to 35 seconds to align with the updated server timeout.
|
|
10
10
|
* [STREAM-461](https://inindca.atlassian.net/browse/STREAM-461) - Remove support for conferenceId in JWT auth (not breaking change, never released).
|
|
11
11
|
|
|
12
|
+
### Fixed
|
|
13
|
+
* [STREAM-262](https://inindca.atlassian.net/browse/STREAM-262) - Set the state of a GenesysCloudMediaSession to `ended` when a `terminate` is received (or we determine a hard closure of the PeerConnection is needed)
|
|
14
|
+
|
|
12
15
|
### Added
|
|
13
16
|
* [STREAM-461](https://inindca.atlassian.net/browse/STREAM-461) - Allow for conferenceId or JID to be used in JWT auth.
|
|
14
17
|
* [STREAM-523](https://inindca.atlassian.net/browse/STREAM-523) - Properly emit `connectionState` event while using SDP over XMPP
|
|
18
|
+
* [STREAM-85](https://inindca.atlassian.net/browse/STREAM-85) - Handle connection transfer (socket closing) message from Hawk signaling a reconnect is necessary
|
|
15
19
|
|
|
16
20
|
# [v19.1.0](https://github.com/purecloudlabs/genesys-cloud-streaming-client/compare/v19.0.1...v19.1.0)
|
|
17
21
|
* [STREAM-357](https://inindca.atlassian.net/browse/STREAM-357) - Maintain the same JID resource across hard reconnects/websockets/stanza instances so that reinvites can be sent to the new WS/stanza instance.
|
package/dist/npm/client.js
CHANGED
|
@@ -20,6 +20,7 @@ const sasl_error_1 = tslib_1.__importDefault(require("./types/sasl-error"));
|
|
|
20
20
|
const timeout_error_1 = require("./types/timeout-error");
|
|
21
21
|
const messenger_1 = require("./messenger");
|
|
22
22
|
const uuid_1 = require("uuid");
|
|
23
|
+
const connection_transfer_1 = require("./connection-transfer");
|
|
23
24
|
let extensions = {
|
|
24
25
|
notifications: notifications_1.Notifications,
|
|
25
26
|
webrtcSessions: webrtc_1.WebrtcExtension,
|
|
@@ -495,6 +496,7 @@ class Client extends events_1.default {
|
|
|
495
496
|
}
|
|
496
497
|
}
|
|
497
498
|
async setupConnectionMonitoring(stanzaInstance) {
|
|
499
|
+
stanzaInstance.connectionTransfer = new connection_transfer_1.ConnectionTransfer(this, stanzaInstance);
|
|
498
500
|
const setupClientPinger = (message) => {
|
|
499
501
|
const logMessage = `${message}, falling back to client-side pinging`;
|
|
500
502
|
this.logger.warn(logMessage, { stanzaInstanceId: stanzaInstance.id, channelId: stanzaInstance.channelId });
|