@ipcom/asterisk-ari 0.0.155 → 0.0.157
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/index.cjs +693 -163
- package/dist/cjs/index.cjs.map +3 -3
- package/dist/esm/index.js +687 -157
- package/dist/esm/index.js.map +3 -3
- package/dist/types/ari-client/ariClient.d.ts +11 -1
- package/dist/types/ari-client/ariClient.d.ts.map +1 -1
- package/dist/types/ari-client/resources/baseResource.d.ts +6 -1
- package/dist/types/ari-client/resources/baseResource.d.ts.map +1 -1
- package/dist/types/ari-client/resources/bridges.d.ts +27 -3
- package/dist/types/ari-client/resources/bridges.d.ts.map +1 -1
- package/dist/types/ari-client/resources/channels.d.ts +12 -0
- package/dist/types/ari-client/resources/channels.d.ts.map +1 -1
- package/dist/types/ari-client/resources/playbacks.d.ts +34 -1
- package/dist/types/ari-client/resources/playbacks.d.ts.map +1 -1
- package/dist/types/ari-client/websocketClient.d.ts +49 -1
- package/dist/types/ari-client/websocketClient.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -915,16 +915,6 @@ var Asterisk = class {
|
|
|
915
915
|
import { EventEmitter } from "events";
|
|
916
916
|
import { isAxiosError as isAxiosError2 } from "axios";
|
|
917
917
|
|
|
918
|
-
// src/ari-client/interfaces/events.types.ts
|
|
919
|
-
var bridgeEvents = [
|
|
920
|
-
"BridgeCreated",
|
|
921
|
-
"BridgeDestroyed",
|
|
922
|
-
"BridgeMerged",
|
|
923
|
-
"BridgeBlindTransfer",
|
|
924
|
-
"BridgeAttendedTransfer",
|
|
925
|
-
"BridgeVideoSourceChanged"
|
|
926
|
-
];
|
|
927
|
-
|
|
928
918
|
// src/ari-client/utils.ts
|
|
929
919
|
function toQueryParams2(options) {
|
|
930
920
|
return new URLSearchParams(
|
|
@@ -954,9 +944,10 @@ var BridgeInstance = class {
|
|
|
954
944
|
this.client = client;
|
|
955
945
|
this.baseClient = baseClient;
|
|
956
946
|
this.id = bridgeId || `bridge-${Date.now()}`;
|
|
957
|
-
console.log(`BridgeInstance inicializada com ID: ${this.id}`);
|
|
958
947
|
}
|
|
959
948
|
eventEmitter = new EventEmitter();
|
|
949
|
+
listenersMap = /* @__PURE__ */ new Map();
|
|
950
|
+
// 🔹 Guarda listeners para remoção posterior
|
|
960
951
|
bridgeData = null;
|
|
961
952
|
id;
|
|
962
953
|
/**
|
|
@@ -977,7 +968,7 @@ var BridgeInstance = class {
|
|
|
977
968
|
*
|
|
978
969
|
* @example
|
|
979
970
|
* bridge.on('BridgeCreated', (event) => {
|
|
980
|
-
*
|
|
971
|
+
*
|
|
981
972
|
* });
|
|
982
973
|
* @param event
|
|
983
974
|
* @param listener
|
|
@@ -986,13 +977,23 @@ var BridgeInstance = class {
|
|
|
986
977
|
if (!event) {
|
|
987
978
|
throw new Error("Event type is required");
|
|
988
979
|
}
|
|
980
|
+
const existingListeners = this.listenersMap.get(event) || [];
|
|
981
|
+
if (existingListeners.includes(listener)) {
|
|
982
|
+
console.warn(
|
|
983
|
+
`Listener j\xE1 registrado para evento ${event}, reutilizando.`
|
|
984
|
+
);
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
989
987
|
const wrappedListener = (data) => {
|
|
990
988
|
if ("bridge" in data && data.bridge?.id === this.id) {
|
|
991
989
|
listener(data);
|
|
992
990
|
}
|
|
993
991
|
};
|
|
994
992
|
this.eventEmitter.on(event, wrappedListener);
|
|
995
|
-
|
|
993
|
+
if (!this.listenersMap.has(event)) {
|
|
994
|
+
this.listenersMap.set(event, []);
|
|
995
|
+
}
|
|
996
|
+
this.listenersMap.get(event).push(wrappedListener);
|
|
996
997
|
}
|
|
997
998
|
/**
|
|
998
999
|
* Registers a one-time listener for specific bridge events.
|
|
@@ -1004,15 +1005,25 @@ var BridgeInstance = class {
|
|
|
1004
1005
|
if (!event) {
|
|
1005
1006
|
throw new Error("Event type is required");
|
|
1006
1007
|
}
|
|
1008
|
+
const eventKey = `${event}-${this.id}`;
|
|
1009
|
+
const existingListeners = this.listenersMap.get(eventKey) || [];
|
|
1010
|
+
if (existingListeners.includes(listener)) {
|
|
1011
|
+
console.warn(
|
|
1012
|
+
`One-time listener j\xE1 registrado para evento ${eventKey}, reutilizando.`
|
|
1013
|
+
);
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1007
1016
|
const wrappedListener = (data) => {
|
|
1008
1017
|
if ("bridge" in data && data.bridge?.id === this.id) {
|
|
1009
1018
|
listener(data);
|
|
1019
|
+
this.off(event, wrappedListener);
|
|
1010
1020
|
}
|
|
1011
1021
|
};
|
|
1012
1022
|
this.eventEmitter.once(event, wrappedListener);
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1023
|
+
if (!this.listenersMap.has(eventKey)) {
|
|
1024
|
+
this.listenersMap.set(eventKey, []);
|
|
1025
|
+
}
|
|
1026
|
+
this.listenersMap.get(eventKey).push(wrappedListener);
|
|
1016
1027
|
}
|
|
1017
1028
|
/**
|
|
1018
1029
|
* Removes event listener(s) from the bridge.
|
|
@@ -1026,14 +1037,25 @@ var BridgeInstance = class {
|
|
|
1026
1037
|
}
|
|
1027
1038
|
if (listener) {
|
|
1028
1039
|
this.eventEmitter.off(event, listener);
|
|
1029
|
-
|
|
1030
|
-
|
|
1040
|
+
const storedListeners = this.listenersMap.get(event) || [];
|
|
1041
|
+
this.listenersMap.set(
|
|
1042
|
+
event,
|
|
1043
|
+
storedListeners.filter((l) => l !== listener)
|
|
1031
1044
|
);
|
|
1032
1045
|
} else {
|
|
1033
1046
|
this.eventEmitter.removeAllListeners(event);
|
|
1034
|
-
|
|
1047
|
+
this.listenersMap.delete(event);
|
|
1035
1048
|
}
|
|
1036
1049
|
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Cleans up the BridgeInstance, resetting its state and clearing resources.
|
|
1052
|
+
*/
|
|
1053
|
+
cleanup() {
|
|
1054
|
+
this.bridgeData = null;
|
|
1055
|
+
this.removeAllListeners();
|
|
1056
|
+
this.listenersMap.clear();
|
|
1057
|
+
console.log(`Bridge instance ${this.id} cleaned up`);
|
|
1058
|
+
}
|
|
1037
1059
|
/**
|
|
1038
1060
|
* Emits an event if it corresponds to the current bridge.
|
|
1039
1061
|
*
|
|
@@ -1046,15 +1068,23 @@ var BridgeInstance = class {
|
|
|
1046
1068
|
}
|
|
1047
1069
|
if ("bridge" in event && event.bridge?.id === this.id) {
|
|
1048
1070
|
this.eventEmitter.emit(event.type, event);
|
|
1049
|
-
console.log(`Event ${event.type} emitted for bridge ${this.id}`);
|
|
1050
1071
|
}
|
|
1051
1072
|
}
|
|
1052
1073
|
/**
|
|
1053
1074
|
* Removes all event listeners from this bridge instance.
|
|
1054
1075
|
*/
|
|
1055
1076
|
removeAllListeners() {
|
|
1077
|
+
console.log(`Removing all event listeners for bridge ${this.id}`);
|
|
1078
|
+
this.listenersMap.forEach((listeners, event) => {
|
|
1079
|
+
listeners.forEach((listener) => {
|
|
1080
|
+
this.eventEmitter.off(
|
|
1081
|
+
event,
|
|
1082
|
+
listener
|
|
1083
|
+
);
|
|
1084
|
+
});
|
|
1085
|
+
});
|
|
1086
|
+
this.listenersMap.clear();
|
|
1056
1087
|
this.eventEmitter.removeAllListeners();
|
|
1057
|
-
console.log(`All listeners removed from bridge ${this.id}`);
|
|
1058
1088
|
}
|
|
1059
1089
|
/**
|
|
1060
1090
|
* Retrieves the current details of the bridge.
|
|
@@ -1070,7 +1100,6 @@ var BridgeInstance = class {
|
|
|
1070
1100
|
this.bridgeData = await this.baseClient.get(
|
|
1071
1101
|
`/bridges/${this.id}`
|
|
1072
1102
|
);
|
|
1073
|
-
console.log(`Details retrieved for bridge ${this.id}`);
|
|
1074
1103
|
return this.bridgeData;
|
|
1075
1104
|
} catch (error) {
|
|
1076
1105
|
const message = getErrorMessage(error);
|
|
@@ -1093,7 +1122,6 @@ var BridgeInstance = class {
|
|
|
1093
1122
|
await this.baseClient.post(
|
|
1094
1123
|
`/bridges/${this.id}/addChannel?${queryParams}`
|
|
1095
1124
|
);
|
|
1096
|
-
console.log(`Channels added to bridge ${this.id}`);
|
|
1097
1125
|
} catch (error) {
|
|
1098
1126
|
const message = getErrorMessage(error);
|
|
1099
1127
|
console.error(`Error adding channels to bridge ${this.id}:`, message);
|
|
@@ -1114,7 +1142,6 @@ var BridgeInstance = class {
|
|
|
1114
1142
|
await this.baseClient.post(
|
|
1115
1143
|
`/bridges/${this.id}/removeChannel?${queryParams}`
|
|
1116
1144
|
);
|
|
1117
|
-
console.log(`Channels removed from bridge ${this.id}`);
|
|
1118
1145
|
} catch (error) {
|
|
1119
1146
|
const message = getErrorMessage(error);
|
|
1120
1147
|
console.error(`Error removing channels from bridge ${this.id}:`, message);
|
|
@@ -1140,7 +1167,6 @@ var BridgeInstance = class {
|
|
|
1140
1167
|
`/bridges/${this.id}/play?${queryParams}`,
|
|
1141
1168
|
{ media: request.media }
|
|
1142
1169
|
);
|
|
1143
|
-
console.log(`Media playback started on bridge ${this.id}`);
|
|
1144
1170
|
return result;
|
|
1145
1171
|
} catch (error) {
|
|
1146
1172
|
const message = getErrorMessage(error);
|
|
@@ -1159,7 +1185,6 @@ var BridgeInstance = class {
|
|
|
1159
1185
|
await this.baseClient.delete(
|
|
1160
1186
|
`/bridges/${this.id}/play/${playbackId}`
|
|
1161
1187
|
);
|
|
1162
|
-
console.log(`Playback ${playbackId} stopped on bridge ${this.id}`);
|
|
1163
1188
|
} catch (error) {
|
|
1164
1189
|
const message = getErrorMessage(error);
|
|
1165
1190
|
console.error(`Error stopping playback on bridge ${this.id}:`, message);
|
|
@@ -1177,7 +1202,6 @@ var BridgeInstance = class {
|
|
|
1177
1202
|
await this.baseClient.post(
|
|
1178
1203
|
`/bridges/${this.id}/videoSource/${channelId}`
|
|
1179
1204
|
);
|
|
1180
|
-
console.log(`Video source set for bridge ${this.id}`);
|
|
1181
1205
|
} catch (error) {
|
|
1182
1206
|
const message = getErrorMessage(error);
|
|
1183
1207
|
console.error(
|
|
@@ -1195,7 +1219,6 @@ var BridgeInstance = class {
|
|
|
1195
1219
|
async clearVideoSource() {
|
|
1196
1220
|
try {
|
|
1197
1221
|
await this.baseClient.delete(`/bridges/${this.id}/videoSource`);
|
|
1198
|
-
console.log(`Video source removed from bridge ${this.id}`);
|
|
1199
1222
|
} catch (error) {
|
|
1200
1223
|
const message = getErrorMessage(error);
|
|
1201
1224
|
console.error(
|
|
@@ -1229,6 +1252,7 @@ var Bridges = class {
|
|
|
1229
1252
|
this.client = client;
|
|
1230
1253
|
}
|
|
1231
1254
|
bridgeInstances = /* @__PURE__ */ new Map();
|
|
1255
|
+
eventQueue = /* @__PURE__ */ new Map();
|
|
1232
1256
|
/**
|
|
1233
1257
|
* Creates or retrieves a Bridge instance.
|
|
1234
1258
|
*
|
|
@@ -1249,23 +1273,41 @@ var Bridges = class {
|
|
|
1249
1273
|
if (!id) {
|
|
1250
1274
|
const instance = new BridgeInstance(this.client, this.baseClient);
|
|
1251
1275
|
this.bridgeInstances.set(instance.id, instance);
|
|
1252
|
-
console.log(`New bridge instance created with ID: ${instance.id}`);
|
|
1253
1276
|
return instance;
|
|
1254
1277
|
}
|
|
1255
1278
|
if (!this.bridgeInstances.has(id)) {
|
|
1256
1279
|
const instance = new BridgeInstance(this.client, this.baseClient, id);
|
|
1257
1280
|
this.bridgeInstances.set(id, instance);
|
|
1258
|
-
console.log(`New bridge instance created with provided ID: ${id}`);
|
|
1259
1281
|
return instance;
|
|
1260
1282
|
}
|
|
1261
|
-
console.log(`Returning existing bridge instance: ${id}`);
|
|
1262
1283
|
return this.bridgeInstances.get(id);
|
|
1263
1284
|
} catch (error) {
|
|
1264
1285
|
const message = getErrorMessage(error);
|
|
1265
|
-
console.
|
|
1286
|
+
console.warn(`Error creating/retrieving bridge instance:`, message);
|
|
1266
1287
|
throw new Error(`Failed to manage bridge instance: ${message}`);
|
|
1267
1288
|
}
|
|
1268
1289
|
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Removes all bridge instances and cleans up their resources.
|
|
1292
|
+
* This method ensures proper cleanup of all bridges and their associated listeners.
|
|
1293
|
+
*/
|
|
1294
|
+
remove() {
|
|
1295
|
+
const bridgeIds = Array.from(this.bridgeInstances.keys());
|
|
1296
|
+
for (const bridgeId of bridgeIds) {
|
|
1297
|
+
try {
|
|
1298
|
+
const instance = this.bridgeInstances.get(bridgeId);
|
|
1299
|
+
if (instance) {
|
|
1300
|
+
instance.cleanup();
|
|
1301
|
+
this.bridgeInstances.delete(bridgeId);
|
|
1302
|
+
console.log(`Bridge instance ${bridgeId} removed and cleaned up`);
|
|
1303
|
+
}
|
|
1304
|
+
} catch (error) {
|
|
1305
|
+
console.error(`Error cleaning up bridge ${bridgeId}:`, error);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
this.bridgeInstances.clear();
|
|
1309
|
+
console.log("All bridge instances have been removed and cleaned up");
|
|
1310
|
+
}
|
|
1269
1311
|
/**
|
|
1270
1312
|
* Removes a bridge instance from the collection of managed bridges.
|
|
1271
1313
|
*
|
|
@@ -1278,15 +1320,20 @@ var Bridges = class {
|
|
|
1278
1320
|
*/
|
|
1279
1321
|
removeBridgeInstance(bridgeId) {
|
|
1280
1322
|
if (!bridgeId) {
|
|
1281
|
-
throw new Error("ID
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1323
|
+
throw new Error("Bridge ID is required");
|
|
1324
|
+
}
|
|
1325
|
+
const instance = this.bridgeInstances.get(bridgeId);
|
|
1326
|
+
if (instance) {
|
|
1327
|
+
try {
|
|
1328
|
+
instance.cleanup();
|
|
1329
|
+
this.bridgeInstances.delete(bridgeId);
|
|
1330
|
+
console.log(`Bridge instance ${bridgeId} removed from memory`);
|
|
1331
|
+
} catch (error) {
|
|
1332
|
+
console.error(`Error removing bridge instance ${bridgeId}:`, error);
|
|
1333
|
+
throw error;
|
|
1334
|
+
}
|
|
1288
1335
|
} else {
|
|
1289
|
-
console.warn(`
|
|
1336
|
+
console.warn(`Attempt to remove non-existent instance: ${bridgeId}`);
|
|
1290
1337
|
}
|
|
1291
1338
|
}
|
|
1292
1339
|
/**
|
|
@@ -1303,28 +1350,51 @@ var Bridges = class {
|
|
|
1303
1350
|
*
|
|
1304
1351
|
* @remarks
|
|
1305
1352
|
* - If the event is invalid (null or undefined), a warning is logged and the function returns early.
|
|
1306
|
-
* - The function checks if the event is bridge-related and if the event
|
|
1353
|
+
* - The function checks if the event is bridge-related and if the event contains a valid bridge ID.
|
|
1307
1354
|
* - If a matching bridge instance is found, the event is emitted to that instance.
|
|
1308
1355
|
* - If no matching bridge instance is found, a warning is logged.
|
|
1309
1356
|
*/
|
|
1310
1357
|
propagateEventToBridge(event) {
|
|
1311
|
-
if (!event) {
|
|
1312
|
-
console.warn("
|
|
1358
|
+
if (!event || !("bridge" in event) || !event.bridge?.id) {
|
|
1359
|
+
console.warn("Invalid WebSocket event received");
|
|
1313
1360
|
return;
|
|
1314
1361
|
}
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1362
|
+
const key = `${event.type}-${event.bridge.id}`;
|
|
1363
|
+
const existing = this.eventQueue.get(key);
|
|
1364
|
+
if (existing) {
|
|
1365
|
+
clearTimeout(existing);
|
|
1366
|
+
}
|
|
1367
|
+
this.eventQueue.set(
|
|
1368
|
+
key,
|
|
1369
|
+
setTimeout(() => {
|
|
1370
|
+
const instance = this.bridgeInstances.get(event.bridge.id);
|
|
1371
|
+
if (instance) {
|
|
1372
|
+
instance.emitEvent(event);
|
|
1373
|
+
} else {
|
|
1374
|
+
console.warn(
|
|
1375
|
+
`No instance found for bridge ${event.bridge.id}. Event ignored.`
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
this.eventQueue.delete(key);
|
|
1379
|
+
}, 100)
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Performs a cleanup of the Bridges instance, clearing all event queues and removing all bridge instances.
|
|
1384
|
+
*
|
|
1385
|
+
* This method is responsible for:
|
|
1386
|
+
* 1. Clearing all pending timeouts in the event queue.
|
|
1387
|
+
* 2. Removing all bridge instances managed by this Bridges object.
|
|
1388
|
+
*
|
|
1389
|
+
* It should be called when the Bridges instance is no longer needed or before reinitializing
|
|
1390
|
+
* to ensure all resources are properly released.
|
|
1391
|
+
*
|
|
1392
|
+
* @returns {void}
|
|
1393
|
+
*/
|
|
1394
|
+
cleanup() {
|
|
1395
|
+
this.eventQueue.forEach((timeout) => clearTimeout(timeout));
|
|
1396
|
+
this.eventQueue.clear();
|
|
1397
|
+
this.remove();
|
|
1328
1398
|
}
|
|
1329
1399
|
/**
|
|
1330
1400
|
* Lists all active bridges in the system.
|
|
@@ -1340,7 +1410,7 @@ var Bridges = class {
|
|
|
1340
1410
|
* @example
|
|
1341
1411
|
* try {
|
|
1342
1412
|
* const bridges = await bridgesInstance.list();
|
|
1343
|
-
*
|
|
1413
|
+
*
|
|
1344
1414
|
* } catch (error) {
|
|
1345
1415
|
* console.error('Failed to fetch bridges:', error);
|
|
1346
1416
|
* }
|
|
@@ -1651,6 +1721,8 @@ var ChannelInstance = class {
|
|
|
1651
1721
|
}
|
|
1652
1722
|
eventEmitter = new EventEmitter2();
|
|
1653
1723
|
channelData = null;
|
|
1724
|
+
listenersMap = /* @__PURE__ */ new Map();
|
|
1725
|
+
// 🔹 Guarda listeners para remoção posterior
|
|
1654
1726
|
id;
|
|
1655
1727
|
/**
|
|
1656
1728
|
* Registers an event listener for specific channel events
|
|
@@ -1659,12 +1731,23 @@ var ChannelInstance = class {
|
|
|
1659
1731
|
if (!event) {
|
|
1660
1732
|
throw new Error("Event type is required");
|
|
1661
1733
|
}
|
|
1734
|
+
const existingListeners = this.listenersMap.get(event) || [];
|
|
1735
|
+
if (existingListeners.includes(listener)) {
|
|
1736
|
+
console.warn(
|
|
1737
|
+
`Listener j\xE1 registrado para evento ${event}, reutilizando.`
|
|
1738
|
+
);
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1662
1741
|
const wrappedListener = (data) => {
|
|
1663
1742
|
if ("channel" in data && data.channel?.id === this.id) {
|
|
1664
1743
|
listener(data);
|
|
1665
1744
|
}
|
|
1666
1745
|
};
|
|
1667
1746
|
this.eventEmitter.on(event, wrappedListener);
|
|
1747
|
+
if (!this.listenersMap.has(event)) {
|
|
1748
|
+
this.listenersMap.set(event, []);
|
|
1749
|
+
}
|
|
1750
|
+
this.listenersMap.get(event).push(wrappedListener);
|
|
1668
1751
|
}
|
|
1669
1752
|
/**
|
|
1670
1753
|
* Registers a one-time event listener
|
|
@@ -1673,12 +1756,25 @@ var ChannelInstance = class {
|
|
|
1673
1756
|
if (!event) {
|
|
1674
1757
|
throw new Error("Event type is required");
|
|
1675
1758
|
}
|
|
1759
|
+
const eventKey = `${event}-${this.id}`;
|
|
1760
|
+
const existingListeners = this.listenersMap.get(eventKey) || [];
|
|
1761
|
+
if (existingListeners.includes(listener)) {
|
|
1762
|
+
console.warn(
|
|
1763
|
+
`One-time listener j\xE1 registrado para evento ${eventKey}, reutilizando.`
|
|
1764
|
+
);
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1676
1767
|
const wrappedListener = (data) => {
|
|
1677
1768
|
if ("channel" in data && data.channel?.id === this.id) {
|
|
1678
1769
|
listener(data);
|
|
1770
|
+
this.off(event, wrappedListener);
|
|
1679
1771
|
}
|
|
1680
1772
|
};
|
|
1681
1773
|
this.eventEmitter.once(event, wrappedListener);
|
|
1774
|
+
if (!this.listenersMap.has(eventKey)) {
|
|
1775
|
+
this.listenersMap.set(eventKey, []);
|
|
1776
|
+
}
|
|
1777
|
+
this.listenersMap.get(eventKey).push(wrappedListener);
|
|
1682
1778
|
}
|
|
1683
1779
|
/**
|
|
1684
1780
|
* Removes event listener(s) for a specific WebSocket event type.
|
|
@@ -1695,10 +1791,25 @@ var ChannelInstance = class {
|
|
|
1695
1791
|
}
|
|
1696
1792
|
if (listener) {
|
|
1697
1793
|
this.eventEmitter.off(event, listener);
|
|
1794
|
+
const storedListeners = this.listenersMap.get(event) || [];
|
|
1795
|
+
this.listenersMap.set(
|
|
1796
|
+
event,
|
|
1797
|
+
storedListeners.filter((l) => l !== listener)
|
|
1798
|
+
);
|
|
1698
1799
|
} else {
|
|
1699
1800
|
this.eventEmitter.removeAllListeners(event);
|
|
1801
|
+
this.listenersMap.delete(event);
|
|
1700
1802
|
}
|
|
1701
1803
|
}
|
|
1804
|
+
/**
|
|
1805
|
+
* Cleans up the ChannelInstance, resetting its state and clearing resources.
|
|
1806
|
+
*/
|
|
1807
|
+
cleanup() {
|
|
1808
|
+
this.channelData = null;
|
|
1809
|
+
this.removeAllListeners();
|
|
1810
|
+
this.listenersMap.clear();
|
|
1811
|
+
console.log(`Channel instance ${this.id} cleaned up`);
|
|
1812
|
+
}
|
|
1702
1813
|
/**
|
|
1703
1814
|
* Emits an event if it matches the current channel
|
|
1704
1815
|
*/
|
|
@@ -1718,6 +1829,16 @@ var ChannelInstance = class {
|
|
|
1718
1829
|
* @return {void} This method does not return a value.
|
|
1719
1830
|
*/
|
|
1720
1831
|
removeAllListeners() {
|
|
1832
|
+
console.log(`Removing all event listeners for channel ${this.id}`);
|
|
1833
|
+
this.listenersMap.forEach((listeners, event) => {
|
|
1834
|
+
listeners.forEach((listener) => {
|
|
1835
|
+
this.eventEmitter.off(
|
|
1836
|
+
event,
|
|
1837
|
+
listener
|
|
1838
|
+
);
|
|
1839
|
+
});
|
|
1840
|
+
});
|
|
1841
|
+
this.listenersMap.clear();
|
|
1721
1842
|
this.eventEmitter.removeAllListeners();
|
|
1722
1843
|
}
|
|
1723
1844
|
/**
|
|
@@ -2006,6 +2127,7 @@ var Channels = class {
|
|
|
2006
2127
|
this.client = client;
|
|
2007
2128
|
}
|
|
2008
2129
|
channelInstances = /* @__PURE__ */ new Map();
|
|
2130
|
+
eventQueue = /* @__PURE__ */ new Map();
|
|
2009
2131
|
/**
|
|
2010
2132
|
* Creates or retrieves a ChannelInstance.
|
|
2011
2133
|
*
|
|
@@ -2041,6 +2163,32 @@ var Channels = class {
|
|
|
2041
2163
|
throw new Error(`Failed to manage channel instance: ${message}`);
|
|
2042
2164
|
}
|
|
2043
2165
|
}
|
|
2166
|
+
cleanup() {
|
|
2167
|
+
this.eventQueue.forEach((timeout) => clearTimeout(timeout));
|
|
2168
|
+
this.eventQueue.clear();
|
|
2169
|
+
this.remove();
|
|
2170
|
+
}
|
|
2171
|
+
/**
|
|
2172
|
+
* Removes all channel instances and cleans up their resources.
|
|
2173
|
+
* This method ensures proper cleanup of all channels and their associated listeners.
|
|
2174
|
+
*/
|
|
2175
|
+
remove() {
|
|
2176
|
+
const channelIds = Array.from(this.channelInstances.keys());
|
|
2177
|
+
for (const channelId of channelIds) {
|
|
2178
|
+
try {
|
|
2179
|
+
const instance = this.channelInstances.get(channelId);
|
|
2180
|
+
if (instance) {
|
|
2181
|
+
instance.cleanup();
|
|
2182
|
+
this.channelInstances.delete(channelId);
|
|
2183
|
+
console.log(`Channel instance ${channelId} removed and cleaned up`);
|
|
2184
|
+
}
|
|
2185
|
+
} catch (error) {
|
|
2186
|
+
console.error(`Error cleaning up channel ${channelId}:`, error);
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
this.channelInstances.clear();
|
|
2190
|
+
console.log("All channel instances have been removed and cleaned up");
|
|
2191
|
+
}
|
|
2044
2192
|
/**
|
|
2045
2193
|
* Retrieves the details of a specific channel.
|
|
2046
2194
|
*
|
|
@@ -2067,10 +2215,16 @@ var Channels = class {
|
|
|
2067
2215
|
if (!channelId) {
|
|
2068
2216
|
throw new Error("Channel ID is required");
|
|
2069
2217
|
}
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2218
|
+
const instance = this.channelInstances.get(channelId);
|
|
2219
|
+
if (instance) {
|
|
2220
|
+
try {
|
|
2221
|
+
instance.cleanup();
|
|
2222
|
+
this.channelInstances.delete(channelId);
|
|
2223
|
+
console.log(`Channel instance ${channelId} removed from memory`);
|
|
2224
|
+
} catch (error) {
|
|
2225
|
+
console.error(`Error removing channel instance ${channelId}:`, error);
|
|
2226
|
+
throw error;
|
|
2227
|
+
}
|
|
2074
2228
|
} else {
|
|
2075
2229
|
console.warn(`Attempt to remove non-existent instance: ${channelId}`);
|
|
2076
2230
|
}
|
|
@@ -2079,18 +2233,29 @@ var Channels = class {
|
|
|
2079
2233
|
* Propagates a WebSocket event to a specific channel.
|
|
2080
2234
|
*/
|
|
2081
2235
|
propagateEventToChannel(event) {
|
|
2082
|
-
if (!event) {
|
|
2236
|
+
if (!event || !("channel" in event) || !event.channel?.id) {
|
|
2083
2237
|
console.warn("Invalid WebSocket event received");
|
|
2084
2238
|
return;
|
|
2085
2239
|
}
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2240
|
+
const key = `${event.type}-${event.channel.id}`;
|
|
2241
|
+
const existing = this.eventQueue.get(key);
|
|
2242
|
+
if (existing) {
|
|
2243
|
+
clearTimeout(existing);
|
|
2244
|
+
}
|
|
2245
|
+
this.eventQueue.set(
|
|
2246
|
+
key,
|
|
2247
|
+
setTimeout(() => {
|
|
2248
|
+
const instance = this.channelInstances.get(event.channel.id);
|
|
2249
|
+
if (instance) {
|
|
2250
|
+
instance.emitEvent(event);
|
|
2251
|
+
} else {
|
|
2252
|
+
console.warn(
|
|
2253
|
+
`No instance found for channel ${event.channel.id}. Event ignored.`
|
|
2254
|
+
);
|
|
2255
|
+
}
|
|
2256
|
+
this.eventQueue.delete(key);
|
|
2257
|
+
}, 100)
|
|
2258
|
+
);
|
|
2094
2259
|
}
|
|
2095
2260
|
/**
|
|
2096
2261
|
* Initiates a new channel.
|
|
@@ -2571,6 +2736,8 @@ var PlaybackInstance = class {
|
|
|
2571
2736
|
this.id = playbackId;
|
|
2572
2737
|
}
|
|
2573
2738
|
eventEmitter = new EventEmitter3();
|
|
2739
|
+
listenersMap = /* @__PURE__ */ new Map();
|
|
2740
|
+
// 🔹 Guarda listeners para remoção posterior
|
|
2574
2741
|
playbackData = null;
|
|
2575
2742
|
id;
|
|
2576
2743
|
/**
|
|
@@ -2583,12 +2750,23 @@ var PlaybackInstance = class {
|
|
|
2583
2750
|
if (!event) {
|
|
2584
2751
|
throw new Error("Event type is required");
|
|
2585
2752
|
}
|
|
2753
|
+
const existingListeners = this.listenersMap.get(event) || [];
|
|
2754
|
+
if (existingListeners.includes(listener)) {
|
|
2755
|
+
console.warn(
|
|
2756
|
+
`Listener j\xE1 registrado para evento ${event}, reutilizando.`
|
|
2757
|
+
);
|
|
2758
|
+
return;
|
|
2759
|
+
}
|
|
2586
2760
|
const wrappedListener = (data) => {
|
|
2587
2761
|
if ("playback" in data && data.playback?.id === this.id) {
|
|
2588
2762
|
listener(data);
|
|
2589
2763
|
}
|
|
2590
2764
|
};
|
|
2591
2765
|
this.eventEmitter.on(event, wrappedListener);
|
|
2766
|
+
if (!this.listenersMap.has(event)) {
|
|
2767
|
+
this.listenersMap.set(event, []);
|
|
2768
|
+
}
|
|
2769
|
+
this.listenersMap.get(event).push(wrappedListener);
|
|
2592
2770
|
}
|
|
2593
2771
|
/**
|
|
2594
2772
|
* Registers a one-time event listener for a specific WebSocket event type.
|
|
@@ -2600,12 +2778,25 @@ var PlaybackInstance = class {
|
|
|
2600
2778
|
if (!event) {
|
|
2601
2779
|
throw new Error("Event type is required");
|
|
2602
2780
|
}
|
|
2781
|
+
const eventKey = `${event}-${this.id}`;
|
|
2782
|
+
const existingListeners = this.listenersMap.get(eventKey) || [];
|
|
2783
|
+
if (existingListeners.includes(listener)) {
|
|
2784
|
+
console.warn(
|
|
2785
|
+
`One-time listener j\xE1 registrado para evento ${eventKey}, reutilizando.`
|
|
2786
|
+
);
|
|
2787
|
+
return;
|
|
2788
|
+
}
|
|
2603
2789
|
const wrappedListener = (data) => {
|
|
2604
2790
|
if ("playback" in data && data.playback?.id === this.id) {
|
|
2605
2791
|
listener(data);
|
|
2792
|
+
this.off(event, wrappedListener);
|
|
2606
2793
|
}
|
|
2607
2794
|
};
|
|
2608
2795
|
this.eventEmitter.once(event, wrappedListener);
|
|
2796
|
+
if (!this.listenersMap.has(eventKey)) {
|
|
2797
|
+
this.listenersMap.set(eventKey, []);
|
|
2798
|
+
}
|
|
2799
|
+
this.listenersMap.get(eventKey).push(wrappedListener);
|
|
2609
2800
|
}
|
|
2610
2801
|
/**
|
|
2611
2802
|
* Removes event listener(s) for a specific WebSocket event type.
|
|
@@ -2619,10 +2810,25 @@ var PlaybackInstance = class {
|
|
|
2619
2810
|
}
|
|
2620
2811
|
if (listener) {
|
|
2621
2812
|
this.eventEmitter.off(event, listener);
|
|
2813
|
+
const storedListeners = this.listenersMap.get(event) || [];
|
|
2814
|
+
this.listenersMap.set(
|
|
2815
|
+
event,
|
|
2816
|
+
storedListeners.filter((l) => l !== listener)
|
|
2817
|
+
);
|
|
2622
2818
|
} else {
|
|
2623
2819
|
this.eventEmitter.removeAllListeners(event);
|
|
2820
|
+
this.listenersMap.delete(event);
|
|
2624
2821
|
}
|
|
2625
2822
|
}
|
|
2823
|
+
/**
|
|
2824
|
+
* Cleans up the PlaybackInstance, resetting its state and clearing resources.
|
|
2825
|
+
*/
|
|
2826
|
+
cleanup() {
|
|
2827
|
+
this.playbackData = null;
|
|
2828
|
+
this.removeAllListeners();
|
|
2829
|
+
this.listenersMap.clear();
|
|
2830
|
+
console.log(`Playback instance ${this.id} cleaned up`);
|
|
2831
|
+
}
|
|
2626
2832
|
/**
|
|
2627
2833
|
* Emits a WebSocket event if it matches the current playback instance.
|
|
2628
2834
|
*
|
|
@@ -2696,9 +2902,29 @@ var PlaybackInstance = class {
|
|
|
2696
2902
|
}
|
|
2697
2903
|
}
|
|
2698
2904
|
/**
|
|
2699
|
-
* Removes all event listeners
|
|
2905
|
+
* Removes all event listeners associated with this playback instance.
|
|
2906
|
+
* This method clears both the internal listener map and the event emitter.
|
|
2907
|
+
*
|
|
2908
|
+
* @remarks
|
|
2909
|
+
* This method performs the following actions:
|
|
2910
|
+
* 1. Logs a message indicating the removal of listeners.
|
|
2911
|
+
* 2. Iterates through all stored listeners and removes them from the event emitter.
|
|
2912
|
+
* 3. Clears the internal listener map.
|
|
2913
|
+
* 4. Removes all listeners from the event emitter.
|
|
2914
|
+
*
|
|
2915
|
+
* @returns {void} This method doesn't return a value.
|
|
2700
2916
|
*/
|
|
2701
2917
|
removeAllListeners() {
|
|
2918
|
+
console.log(`Removing all event listeners for playback ${this.id}`);
|
|
2919
|
+
this.listenersMap.forEach((listeners, event) => {
|
|
2920
|
+
listeners.forEach((listener) => {
|
|
2921
|
+
this.eventEmitter.off(
|
|
2922
|
+
event,
|
|
2923
|
+
listener
|
|
2924
|
+
);
|
|
2925
|
+
});
|
|
2926
|
+
});
|
|
2927
|
+
this.listenersMap.clear();
|
|
2702
2928
|
this.eventEmitter.removeAllListeners();
|
|
2703
2929
|
}
|
|
2704
2930
|
/**
|
|
@@ -2725,6 +2951,7 @@ var Playbacks = class {
|
|
|
2725
2951
|
this.client = client;
|
|
2726
2952
|
}
|
|
2727
2953
|
playbackInstances = /* @__PURE__ */ new Map();
|
|
2954
|
+
eventQueue = /* @__PURE__ */ new Map();
|
|
2728
2955
|
/**
|
|
2729
2956
|
* Gets or creates a playback instance
|
|
2730
2957
|
* @param {Object} [params] - Optional parameters for getting/creating a playback instance
|
|
@@ -2751,6 +2978,43 @@ var Playbacks = class {
|
|
|
2751
2978
|
throw new Error(`Failed to manage playback instance: ${message}`);
|
|
2752
2979
|
}
|
|
2753
2980
|
}
|
|
2981
|
+
/**
|
|
2982
|
+
* Cleans up resources associated with the Playbacks instance.
|
|
2983
|
+
* This method performs the following cleanup operations:
|
|
2984
|
+
* 1. Clears all pending timeouts in the event queue.
|
|
2985
|
+
* 2. Removes all playback instances.
|
|
2986
|
+
*
|
|
2987
|
+
* @remarks
|
|
2988
|
+
* This method should be called when the Playbacks instance is no longer needed
|
|
2989
|
+
* to ensure proper resource management and prevent memory leaks.
|
|
2990
|
+
*
|
|
2991
|
+
* @returns {void} This method doesn't return a value.
|
|
2992
|
+
*/
|
|
2993
|
+
cleanup() {
|
|
2994
|
+
this.eventQueue.forEach((timeout) => clearTimeout(timeout));
|
|
2995
|
+
this.eventQueue.clear();
|
|
2996
|
+
this.remove();
|
|
2997
|
+
}
|
|
2998
|
+
/**
|
|
2999
|
+
* Removes all playback instances and cleans up their resources.
|
|
3000
|
+
*/
|
|
3001
|
+
remove() {
|
|
3002
|
+
const playbackIds = Array.from(this.playbackInstances.keys());
|
|
3003
|
+
for (const playbackId of playbackIds) {
|
|
3004
|
+
try {
|
|
3005
|
+
const instance = this.playbackInstances.get(playbackId);
|
|
3006
|
+
if (instance) {
|
|
3007
|
+
instance.cleanup();
|
|
3008
|
+
this.playbackInstances.delete(playbackId);
|
|
3009
|
+
console.log(`Playback instance ${playbackId} removed and cleaned up`);
|
|
3010
|
+
}
|
|
3011
|
+
} catch (error) {
|
|
3012
|
+
console.error(`Error cleaning up playback ${playbackId}:`, error);
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
this.playbackInstances.clear();
|
|
3016
|
+
console.log("All playback instances have been removed and cleaned up");
|
|
3017
|
+
}
|
|
2754
3018
|
/**
|
|
2755
3019
|
* Removes a playback instance and cleans up its resources
|
|
2756
3020
|
* @param {string} playbackId - ID of the playback instance to remove
|
|
@@ -2760,10 +3024,16 @@ var Playbacks = class {
|
|
|
2760
3024
|
if (!playbackId) {
|
|
2761
3025
|
throw new Error("Playback ID is required");
|
|
2762
3026
|
}
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
3027
|
+
const instance = this.playbackInstances.get(playbackId);
|
|
3028
|
+
if (instance) {
|
|
3029
|
+
try {
|
|
3030
|
+
instance.cleanup();
|
|
3031
|
+
this.playbackInstances.delete(playbackId);
|
|
3032
|
+
console.log(`Playback instance ${playbackId} removed from memory`);
|
|
3033
|
+
} catch (error) {
|
|
3034
|
+
console.error(`Error removing playback instance ${playbackId}:`, error);
|
|
3035
|
+
throw error;
|
|
3036
|
+
}
|
|
2767
3037
|
} else {
|
|
2768
3038
|
console.warn(`Attempt to remove non-existent instance: ${playbackId}`);
|
|
2769
3039
|
}
|
|
@@ -2773,17 +3043,29 @@ var Playbacks = class {
|
|
|
2773
3043
|
* @param {WebSocketEvent} event - The WebSocket event to propagate
|
|
2774
3044
|
*/
|
|
2775
3045
|
propagateEventToPlayback(event) {
|
|
2776
|
-
if (!event) {
|
|
3046
|
+
if (!event || !("playback" in event) || !event.playback?.id) {
|
|
3047
|
+
console.warn("Invalid WebSocket event received");
|
|
2777
3048
|
return;
|
|
2778
3049
|
}
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
3050
|
+
const key = `${event.type}-${event.playback.id}`;
|
|
3051
|
+
const existing = this.eventQueue.get(key);
|
|
3052
|
+
if (existing) {
|
|
3053
|
+
clearTimeout(existing);
|
|
3054
|
+
}
|
|
3055
|
+
this.eventQueue.set(
|
|
3056
|
+
key,
|
|
3057
|
+
setTimeout(() => {
|
|
3058
|
+
const instance = this.playbackInstances.get(event.playback.id);
|
|
3059
|
+
if (instance) {
|
|
3060
|
+
instance.emitEvent(event);
|
|
3061
|
+
} else {
|
|
3062
|
+
console.warn(
|
|
3063
|
+
`No instance found for playback ${event.playback.id}. Event ignored.`
|
|
3064
|
+
);
|
|
3065
|
+
}
|
|
3066
|
+
this.eventQueue.delete(key);
|
|
3067
|
+
}, 100)
|
|
3068
|
+
);
|
|
2787
3069
|
}
|
|
2788
3070
|
/**
|
|
2789
3071
|
* Retrieves details of a specific playback
|
|
@@ -2921,9 +3203,57 @@ var WebSocketClient = class extends EventEmitter4 {
|
|
|
2921
3203
|
}
|
|
2922
3204
|
ws;
|
|
2923
3205
|
isReconnecting = false;
|
|
3206
|
+
isConnecting = false;
|
|
3207
|
+
// 🔹 Evita múltiplas conexões simultâneas
|
|
3208
|
+
shouldReconnect = true;
|
|
3209
|
+
// 🔹 Nova flag para impedir reconexão se for um fechamento intencional
|
|
2924
3210
|
maxReconnectAttempts = DEFAULT_MAX_RECONNECT_ATTEMPTS;
|
|
2925
3211
|
reconnectionAttempts = 0;
|
|
2926
3212
|
lastWsUrl = "";
|
|
3213
|
+
eventQueue = /* @__PURE__ */ new Map();
|
|
3214
|
+
/**
|
|
3215
|
+
* Logs the current connection status of the WebSocket client at regular intervals.
|
|
3216
|
+
*
|
|
3217
|
+
* This method sets up an interval that logs various connection-related metrics every 60 seconds.
|
|
3218
|
+
* The logged information includes:
|
|
3219
|
+
* - The number of active connections (0 or 1)
|
|
3220
|
+
* - The current state of the WebSocket connection
|
|
3221
|
+
* - The number of reconnection attempts made
|
|
3222
|
+
* - The size of the event queue
|
|
3223
|
+
*
|
|
3224
|
+
* This can be useful for monitoring the health and status of the WebSocket connection over time.
|
|
3225
|
+
*
|
|
3226
|
+
* @private
|
|
3227
|
+
* @returns {void}
|
|
3228
|
+
*/
|
|
3229
|
+
logConnectionStatus() {
|
|
3230
|
+
setInterval(() => {
|
|
3231
|
+
console.log({
|
|
3232
|
+
connections: this.ws ? 1 : 0,
|
|
3233
|
+
state: this.getState(),
|
|
3234
|
+
reconnectAttempts: this.reconnectionAttempts,
|
|
3235
|
+
eventQueueSize: this.eventQueue.size
|
|
3236
|
+
});
|
|
3237
|
+
}, 6e4);
|
|
3238
|
+
}
|
|
3239
|
+
/**
|
|
3240
|
+
* Sets up a heartbeat mechanism for the WebSocket connection.
|
|
3241
|
+
*
|
|
3242
|
+
* This method creates an interval that sends a ping message every 30 seconds
|
|
3243
|
+
* to keep the connection alive. The heartbeat is automatically cleared when
|
|
3244
|
+
* the WebSocket connection is closed.
|
|
3245
|
+
*
|
|
3246
|
+
* @private
|
|
3247
|
+
* @returns {void}
|
|
3248
|
+
*/
|
|
3249
|
+
setupHeartbeat() {
|
|
3250
|
+
const interval = setInterval(() => {
|
|
3251
|
+
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
3252
|
+
this.ws.ping();
|
|
3253
|
+
}
|
|
3254
|
+
}, 3e4);
|
|
3255
|
+
this.ws.once("close", () => clearInterval(interval));
|
|
3256
|
+
}
|
|
2927
3257
|
backOffOptions = {
|
|
2928
3258
|
numOfAttempts: DEFAULT_MAX_RECONNECT_ATTEMPTS,
|
|
2929
3259
|
startingDelay: DEFAULT_STARTING_DELAY,
|
|
@@ -2950,21 +3280,29 @@ var WebSocketClient = class extends EventEmitter4 {
|
|
|
2950
3280
|
* @throws Will throw an error if the connection cannot be established.
|
|
2951
3281
|
*/
|
|
2952
3282
|
async connect() {
|
|
3283
|
+
if (this.isConnecting || this.isConnected()) {
|
|
3284
|
+
console.warn(
|
|
3285
|
+
"WebSocket is already connecting or connected. Skipping new connection."
|
|
3286
|
+
);
|
|
3287
|
+
return;
|
|
3288
|
+
}
|
|
3289
|
+
this.shouldReconnect = true;
|
|
3290
|
+
this.isConnecting = true;
|
|
2953
3291
|
const { baseUrl, username, password } = this.baseClient.getCredentials();
|
|
2954
3292
|
const protocol = baseUrl.startsWith("https") ? "wss" : "ws";
|
|
2955
3293
|
const normalizedHost = baseUrl.replace(/^https?:\/\//, "").replace(/\/ari$/, "");
|
|
2956
3294
|
const queryParams = new URLSearchParams();
|
|
2957
3295
|
queryParams.append("app", this.apps.join(","));
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
);
|
|
2962
|
-
} else {
|
|
2963
|
-
queryParams.append("subscribeAll", "true");
|
|
2964
|
-
}
|
|
3296
|
+
this.subscribedEvents?.forEach(
|
|
3297
|
+
(event) => queryParams.append("event", event)
|
|
3298
|
+
);
|
|
2965
3299
|
this.lastWsUrl = `${protocol}://${encodeURIComponent(username)}:${encodeURIComponent(password)}@${normalizedHost}/ari/events?${queryParams.toString()}`;
|
|
2966
3300
|
console.log("Connecting to WebSocket...");
|
|
2967
|
-
|
|
3301
|
+
try {
|
|
3302
|
+
await this.initializeWebSocket(this.lastWsUrl);
|
|
3303
|
+
} finally {
|
|
3304
|
+
this.isConnecting = false;
|
|
3305
|
+
}
|
|
2968
3306
|
}
|
|
2969
3307
|
/**
|
|
2970
3308
|
* Initializes a WebSocket connection with exponential backoff retry mechanism.
|
|
@@ -2986,8 +3324,9 @@ var WebSocketClient = class extends EventEmitter4 {
|
|
|
2986
3324
|
return new Promise((resolve, reject) => {
|
|
2987
3325
|
try {
|
|
2988
3326
|
this.ws = new WebSocket(wsUrl);
|
|
2989
|
-
this.ws.
|
|
3327
|
+
this.ws.once("open", () => {
|
|
2990
3328
|
console.log("WebSocket connection established successfully");
|
|
3329
|
+
this.setupHeartbeat();
|
|
2991
3330
|
if (this.isReconnecting) {
|
|
2992
3331
|
this.emit("reconnected", {
|
|
2993
3332
|
apps: this.apps,
|
|
@@ -3000,7 +3339,7 @@ var WebSocketClient = class extends EventEmitter4 {
|
|
|
3000
3339
|
resolve();
|
|
3001
3340
|
});
|
|
3002
3341
|
this.ws.on("message", (data) => this.handleMessage(data.toString()));
|
|
3003
|
-
this.ws.
|
|
3342
|
+
this.ws.once("close", (code) => {
|
|
3004
3343
|
console.warn(
|
|
3005
3344
|
`WebSocket disconnected with code ${code}. Attempting to reconnect...`
|
|
3006
3345
|
);
|
|
@@ -3008,7 +3347,7 @@ var WebSocketClient = class extends EventEmitter4 {
|
|
|
3008
3347
|
this.reconnect(this.lastWsUrl);
|
|
3009
3348
|
}
|
|
3010
3349
|
});
|
|
3011
|
-
this.ws.
|
|
3350
|
+
this.ws.once("error", (err) => {
|
|
3012
3351
|
console.error("WebSocket error:", err.message);
|
|
3013
3352
|
if (!this.isReconnecting) {
|
|
3014
3353
|
this.reconnect(this.lastWsUrl);
|
|
@@ -3021,6 +3360,34 @@ var WebSocketClient = class extends EventEmitter4 {
|
|
|
3021
3360
|
});
|
|
3022
3361
|
}, this.backOffOptions);
|
|
3023
3362
|
}
|
|
3363
|
+
getEventKey(event) {
|
|
3364
|
+
const ids = [];
|
|
3365
|
+
if ("channel" in event && event.channel?.id) ids.push(event.channel.id);
|
|
3366
|
+
if ("playback" in event && event.playback?.id) ids.push(event.playback.id);
|
|
3367
|
+
if ("bridge" in event && event.bridge?.id) ids.push(event.bridge.id);
|
|
3368
|
+
return `${event.type}-${ids.join("-")}`;
|
|
3369
|
+
}
|
|
3370
|
+
processEvent(event) {
|
|
3371
|
+
if (this.subscribedEvents?.length && !this.subscribedEvents.includes(event.type)) {
|
|
3372
|
+
return;
|
|
3373
|
+
}
|
|
3374
|
+
if ("channel" in event && event.channel?.id && this.ariClient) {
|
|
3375
|
+
const instanceChannel = this.ariClient.Channel(event.channel.id);
|
|
3376
|
+
instanceChannel.emitEvent(event);
|
|
3377
|
+
event.instanceChannel = instanceChannel;
|
|
3378
|
+
}
|
|
3379
|
+
if ("playback" in event && event.playback?.id && this.ariClient) {
|
|
3380
|
+
const instancePlayback = this.ariClient.Playback(event.playback.id);
|
|
3381
|
+
instancePlayback.emitEvent(event);
|
|
3382
|
+
event.instancePlayback = instancePlayback;
|
|
3383
|
+
}
|
|
3384
|
+
if ("bridge" in event && event.bridge?.id && this.ariClient) {
|
|
3385
|
+
const instanceBridge = this.ariClient.Bridge(event.bridge.id);
|
|
3386
|
+
instanceBridge.emitEvent(event);
|
|
3387
|
+
event.instanceBridge = instanceBridge;
|
|
3388
|
+
}
|
|
3389
|
+
this.emit(event.type, event);
|
|
3390
|
+
}
|
|
3024
3391
|
/**
|
|
3025
3392
|
* Handles incoming WebSocket messages by parsing and processing events.
|
|
3026
3393
|
*
|
|
@@ -3036,30 +3403,20 @@ var WebSocketClient = class extends EventEmitter4 {
|
|
|
3036
3403
|
handleMessage(rawMessage) {
|
|
3037
3404
|
try {
|
|
3038
3405
|
const event = JSON.parse(rawMessage);
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
const instanceChannel = this.ariClient.Channel(event.channel.id);
|
|
3044
|
-
instanceChannel.emitEvent(event);
|
|
3045
|
-
event.instanceChannel = instanceChannel;
|
|
3406
|
+
const key = this.getEventKey(event);
|
|
3407
|
+
const existing = this.eventQueue.get(key);
|
|
3408
|
+
if (existing) {
|
|
3409
|
+
clearTimeout(existing);
|
|
3046
3410
|
}
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
const instanceBridge = this.ariClient.Bridge(event.bridge.id);
|
|
3054
|
-
instanceBridge.emitEvent(event);
|
|
3055
|
-
event.instanceBridge = instanceBridge;
|
|
3056
|
-
}
|
|
3057
|
-
this.emit(event.type, event);
|
|
3058
|
-
} catch (error) {
|
|
3059
|
-
console.error(
|
|
3060
|
-
"Error processing WebSocket message:",
|
|
3061
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
3411
|
+
this.eventQueue.set(
|
|
3412
|
+
key,
|
|
3413
|
+
setTimeout(() => {
|
|
3414
|
+
this.processEvent(event);
|
|
3415
|
+
this.eventQueue.delete(key);
|
|
3416
|
+
}, 100)
|
|
3062
3417
|
);
|
|
3418
|
+
} catch (error) {
|
|
3419
|
+
console.error("Error processing WebSocket message:", error);
|
|
3063
3420
|
this.emit("error", new Error("Failed to decode WebSocket message"));
|
|
3064
3421
|
}
|
|
3065
3422
|
}
|
|
@@ -3075,21 +3432,26 @@ var WebSocketClient = class extends EventEmitter4 {
|
|
|
3075
3432
|
*
|
|
3076
3433
|
* @emits reconnectFailed - Emitted if all reconnection attempts fail.
|
|
3077
3434
|
*/
|
|
3078
|
-
reconnect(wsUrl) {
|
|
3435
|
+
async reconnect(wsUrl) {
|
|
3436
|
+
if (!this.shouldReconnect) {
|
|
3437
|
+
console.warn(
|
|
3438
|
+
"Reconnection skipped because WebSocket was intentionally closed."
|
|
3439
|
+
);
|
|
3440
|
+
return;
|
|
3441
|
+
}
|
|
3442
|
+
if (this.isReconnecting) {
|
|
3443
|
+
console.warn("J\xE1 h\xE1 uma tentativa de reconex\xE3o em andamento.");
|
|
3444
|
+
return;
|
|
3445
|
+
}
|
|
3079
3446
|
this.isReconnecting = true;
|
|
3080
3447
|
this.reconnectionAttempts++;
|
|
3081
|
-
console.log(
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
3089
|
-
);
|
|
3090
|
-
this.emit("reconnectFailed", error);
|
|
3091
|
-
}
|
|
3092
|
-
);
|
|
3448
|
+
console.log(`Tentando reconex\xE3o #${this.reconnectionAttempts}...`);
|
|
3449
|
+
(0, import_exponential_backoff.backOff)(() => this.initializeWebSocket(wsUrl), this.backOffOptions).catch((error) => {
|
|
3450
|
+
console.error(`Falha ao reconectar: ${error.message}`);
|
|
3451
|
+
this.emit("reconnectFailed", error);
|
|
3452
|
+
}).finally(() => {
|
|
3453
|
+
this.isReconnecting = false;
|
|
3454
|
+
});
|
|
3093
3455
|
}
|
|
3094
3456
|
/**
|
|
3095
3457
|
* Closes the WebSocket connection if it exists.
|
|
@@ -3100,18 +3462,34 @@ var WebSocketClient = class extends EventEmitter4 {
|
|
|
3100
3462
|
*
|
|
3101
3463
|
* @throws {Error} Logs an error message if closing the WebSocket fails.
|
|
3102
3464
|
*/
|
|
3103
|
-
close() {
|
|
3465
|
+
async close() {
|
|
3466
|
+
if (!this.ws) {
|
|
3467
|
+
console.warn("No WebSocket connection to close");
|
|
3468
|
+
return;
|
|
3469
|
+
}
|
|
3470
|
+
console.log("Closing WebSocket connection.");
|
|
3471
|
+
this.shouldReconnect = false;
|
|
3472
|
+
this.eventQueue.forEach((timeout) => clearTimeout(timeout));
|
|
3473
|
+
this.eventQueue.clear();
|
|
3474
|
+
const closeTimeout = setTimeout(() => {
|
|
3475
|
+
if (this.ws && this.ws.readyState !== WebSocket.CLOSED) {
|
|
3476
|
+
this.ws.terminate();
|
|
3477
|
+
}
|
|
3478
|
+
}, 5e3);
|
|
3104
3479
|
try {
|
|
3105
|
-
|
|
3480
|
+
this.ws.removeAllListeners();
|
|
3481
|
+
await new Promise((resolve) => {
|
|
3482
|
+
this.ws.once("close", () => {
|
|
3483
|
+
clearTimeout(closeTimeout);
|
|
3484
|
+
resolve();
|
|
3485
|
+
});
|
|
3106
3486
|
this.ws.close();
|
|
3107
|
-
|
|
3108
|
-
console.log("WebSocket connection closed");
|
|
3109
|
-
}
|
|
3487
|
+
});
|
|
3110
3488
|
} catch (error) {
|
|
3111
|
-
console.error(
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
);
|
|
3489
|
+
console.error("Error closing WebSocket:", error);
|
|
3490
|
+
} finally {
|
|
3491
|
+
this.ws = void 0;
|
|
3492
|
+
this.emit("disconnected");
|
|
3115
3493
|
}
|
|
3116
3494
|
}
|
|
3117
3495
|
/**
|
|
@@ -3143,6 +3521,30 @@ var WebSocketClient = class extends EventEmitter4 {
|
|
|
3143
3521
|
getState() {
|
|
3144
3522
|
return this.ws?.readyState ?? WebSocket.CLOSED;
|
|
3145
3523
|
}
|
|
3524
|
+
/**
|
|
3525
|
+
* Cleans up the WebSocketClient instance, resetting its state and clearing resources.
|
|
3526
|
+
*
|
|
3527
|
+
* This method performs the following cleanup operations:
|
|
3528
|
+
* - Clears the event queue and cancels any pending timeouts.
|
|
3529
|
+
* - Stops any ongoing reconnection attempts.
|
|
3530
|
+
* - Clears the stored WebSocket URL.
|
|
3531
|
+
* - Resets the reconnection attempt counter.
|
|
3532
|
+
* - Removes all event listeners attached to this instance.
|
|
3533
|
+
*
|
|
3534
|
+
* This method is typically called when the WebSocketClient is no longer needed or
|
|
3535
|
+
* before reinitializing the client to ensure a clean slate.
|
|
3536
|
+
*
|
|
3537
|
+
* @returns {void} This method doesn't return a value.
|
|
3538
|
+
*/
|
|
3539
|
+
cleanup() {
|
|
3540
|
+
this.eventQueue.forEach((timeout) => clearTimeout(timeout));
|
|
3541
|
+
this.eventQueue.clear();
|
|
3542
|
+
this.shouldReconnect = false;
|
|
3543
|
+
this.isReconnecting = false;
|
|
3544
|
+
this.lastWsUrl = "";
|
|
3545
|
+
this.reconnectionAttempts = 0;
|
|
3546
|
+
this.removeAllListeners();
|
|
3547
|
+
}
|
|
3146
3548
|
};
|
|
3147
3549
|
|
|
3148
3550
|
// src/ari-client/ariClient.ts
|
|
@@ -3173,6 +3575,8 @@ var AriClient = class {
|
|
|
3173
3575
|
}
|
|
3174
3576
|
baseClient;
|
|
3175
3577
|
webSocketClient;
|
|
3578
|
+
eventListeners = /* @__PURE__ */ new Map();
|
|
3579
|
+
// Armazena os listeners para limpeza
|
|
3176
3580
|
channels;
|
|
3177
3581
|
endpoints;
|
|
3178
3582
|
applications;
|
|
@@ -3180,6 +3584,50 @@ var AriClient = class {
|
|
|
3180
3584
|
sounds;
|
|
3181
3585
|
asterisk;
|
|
3182
3586
|
bridges;
|
|
3587
|
+
async cleanup() {
|
|
3588
|
+
try {
|
|
3589
|
+
console.log("Starting ARI Client cleanup...");
|
|
3590
|
+
if (this.webSocketClient) {
|
|
3591
|
+
await this.closeWebSocket();
|
|
3592
|
+
}
|
|
3593
|
+
await Promise.all([
|
|
3594
|
+
// Cleanup de channels
|
|
3595
|
+
(async () => {
|
|
3596
|
+
try {
|
|
3597
|
+
this.channels.cleanup();
|
|
3598
|
+
} catch (error) {
|
|
3599
|
+
console.error("Error cleaning up channels:", error);
|
|
3600
|
+
}
|
|
3601
|
+
})(),
|
|
3602
|
+
// Cleanup de playbacks
|
|
3603
|
+
(async () => {
|
|
3604
|
+
try {
|
|
3605
|
+
this.playbacks.cleanup();
|
|
3606
|
+
} catch (error) {
|
|
3607
|
+
console.error("Error cleaning up playbacks:", error);
|
|
3608
|
+
}
|
|
3609
|
+
})(),
|
|
3610
|
+
// Cleanup de bridges
|
|
3611
|
+
(async () => {
|
|
3612
|
+
try {
|
|
3613
|
+
this.bridges.cleanup();
|
|
3614
|
+
} catch (error) {
|
|
3615
|
+
console.error("Error cleaning up bridges:", error);
|
|
3616
|
+
}
|
|
3617
|
+
})()
|
|
3618
|
+
]);
|
|
3619
|
+
this.eventListeners.forEach((listeners, event) => {
|
|
3620
|
+
listeners.forEach((listener) => {
|
|
3621
|
+
this.off(event, listener);
|
|
3622
|
+
});
|
|
3623
|
+
});
|
|
3624
|
+
this.eventListeners.clear();
|
|
3625
|
+
console.log("ARI Client cleanup completed successfully");
|
|
3626
|
+
} catch (error) {
|
|
3627
|
+
console.error("Error during ARI Client cleanup:", error);
|
|
3628
|
+
throw error;
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3183
3631
|
/**
|
|
3184
3632
|
* Initializes a WebSocket connection for receiving events.
|
|
3185
3633
|
*
|
|
@@ -3189,14 +3637,14 @@ var AriClient = class {
|
|
|
3189
3637
|
* @throws {Error} If connection fails or if WebSocket is already connected
|
|
3190
3638
|
*/
|
|
3191
3639
|
async connectWebSocket(apps, subscribedEvents) {
|
|
3192
|
-
if (!apps.length) {
|
|
3193
|
-
throw new Error("At least one application name is required");
|
|
3194
|
-
}
|
|
3195
|
-
if (this.webSocketClient) {
|
|
3196
|
-
console.warn("WebSocket is already connected");
|
|
3197
|
-
return;
|
|
3198
|
-
}
|
|
3199
3640
|
try {
|
|
3641
|
+
if (!apps.length) {
|
|
3642
|
+
throw new Error("At least one application name is required.");
|
|
3643
|
+
}
|
|
3644
|
+
if (this.webSocketClient) {
|
|
3645
|
+
await this.closeWebSocket();
|
|
3646
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3647
|
+
}
|
|
3200
3648
|
this.webSocketClient = new WebSocketClient(
|
|
3201
3649
|
this.baseClient,
|
|
3202
3650
|
apps,
|
|
@@ -3204,13 +3652,38 @@ var AriClient = class {
|
|
|
3204
3652
|
this
|
|
3205
3653
|
);
|
|
3206
3654
|
await this.webSocketClient.connect();
|
|
3207
|
-
console.log("WebSocket connection established successfully");
|
|
3655
|
+
console.log("WebSocket connection established successfully.");
|
|
3208
3656
|
} catch (error) {
|
|
3209
3657
|
console.error("Failed to establish WebSocket connection:", error);
|
|
3210
3658
|
this.webSocketClient = void 0;
|
|
3211
3659
|
throw error;
|
|
3212
3660
|
}
|
|
3213
3661
|
}
|
|
3662
|
+
/**
|
|
3663
|
+
* Destroys the ARI Client instance, cleaning up all resources and removing circular references.
|
|
3664
|
+
* This method should be called when the ARI Client is no longer needed to ensure proper cleanup.
|
|
3665
|
+
*
|
|
3666
|
+
* @returns {Promise<void>} A promise that resolves when the destruction process is complete.
|
|
3667
|
+
* @throws {Error} If an error occurs during the destruction process.
|
|
3668
|
+
*/
|
|
3669
|
+
async destroy() {
|
|
3670
|
+
try {
|
|
3671
|
+
console.log("Destroying ARI Client...");
|
|
3672
|
+
await this.cleanup();
|
|
3673
|
+
this.webSocketClient = void 0;
|
|
3674
|
+
this.channels = null;
|
|
3675
|
+
this.playbacks = null;
|
|
3676
|
+
this.bridges = null;
|
|
3677
|
+
this.endpoints = null;
|
|
3678
|
+
this.applications = null;
|
|
3679
|
+
this.sounds = null;
|
|
3680
|
+
this.asterisk = null;
|
|
3681
|
+
console.log("ARI Client destroyed successfully");
|
|
3682
|
+
} catch (error) {
|
|
3683
|
+
console.error("Error destroying ARI Client:", error);
|
|
3684
|
+
throw error;
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3214
3687
|
/**
|
|
3215
3688
|
* Registers an event listener for WebSocket events.
|
|
3216
3689
|
*
|
|
@@ -3222,8 +3695,15 @@ var AriClient = class {
|
|
|
3222
3695
|
if (!this.webSocketClient) {
|
|
3223
3696
|
throw new Error("WebSocket is not connected");
|
|
3224
3697
|
}
|
|
3698
|
+
const existingListeners = this.eventListeners.get(event) || [];
|
|
3699
|
+
if (existingListeners.includes(listener)) {
|
|
3700
|
+
console.warn(`Listener already registered for event ${event}, reusing.`);
|
|
3701
|
+
return;
|
|
3702
|
+
}
|
|
3225
3703
|
this.webSocketClient.on(event, listener);
|
|
3226
|
-
|
|
3704
|
+
existingListeners.push(listener);
|
|
3705
|
+
this.eventListeners.set(event, existingListeners);
|
|
3706
|
+
console.log(`Event listener successfully registered for ${event}`);
|
|
3227
3707
|
}
|
|
3228
3708
|
/**
|
|
3229
3709
|
* Registers a one-time event listener for WebSocket events.
|
|
@@ -3236,7 +3716,19 @@ var AriClient = class {
|
|
|
3236
3716
|
if (!this.webSocketClient) {
|
|
3237
3717
|
throw new Error("WebSocket is not connected");
|
|
3238
3718
|
}
|
|
3239
|
-
this.
|
|
3719
|
+
const existingListeners = this.eventListeners.get(event) || [];
|
|
3720
|
+
if (existingListeners.includes(listener)) {
|
|
3721
|
+
console.warn(
|
|
3722
|
+
`One-time listener already registered for event ${event}, reusing.`
|
|
3723
|
+
);
|
|
3724
|
+
return;
|
|
3725
|
+
}
|
|
3726
|
+
const wrappedListener = (data) => {
|
|
3727
|
+
listener(data);
|
|
3728
|
+
this.off(event, wrappedListener);
|
|
3729
|
+
};
|
|
3730
|
+
this.webSocketClient.once(event, wrappedListener);
|
|
3731
|
+
this.eventListeners.set(event, [...existingListeners, wrappedListener]);
|
|
3240
3732
|
console.log(`One-time event listener registered for ${event}`);
|
|
3241
3733
|
}
|
|
3242
3734
|
/**
|
|
@@ -3251,19 +3743,57 @@ var AriClient = class {
|
|
|
3251
3743
|
return;
|
|
3252
3744
|
}
|
|
3253
3745
|
this.webSocketClient.off(event, listener);
|
|
3746
|
+
const existingListeners = this.eventListeners.get(event) || [];
|
|
3747
|
+
this.eventListeners.set(
|
|
3748
|
+
event,
|
|
3749
|
+
existingListeners.filter((l) => l !== listener)
|
|
3750
|
+
);
|
|
3254
3751
|
console.log(`Event listener removed for ${event}`);
|
|
3255
3752
|
}
|
|
3256
3753
|
/**
|
|
3257
3754
|
* Closes the WebSocket connection if one exists.
|
|
3258
3755
|
*/
|
|
3259
3756
|
closeWebSocket() {
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3757
|
+
return new Promise((resolve) => {
|
|
3758
|
+
if (!this.webSocketClient) {
|
|
3759
|
+
console.warn("No WebSocket connection to close");
|
|
3760
|
+
resolve();
|
|
3761
|
+
return;
|
|
3762
|
+
}
|
|
3763
|
+
console.log("Closing WebSocket connection and cleaning up listeners.");
|
|
3764
|
+
const closeTimeout = setTimeout(() => {
|
|
3765
|
+
if (this.webSocketClient) {
|
|
3766
|
+
this.webSocketClient.removeAllListeners();
|
|
3767
|
+
this.webSocketClient = void 0;
|
|
3768
|
+
}
|
|
3769
|
+
resolve();
|
|
3770
|
+
}, 5e3);
|
|
3771
|
+
this.eventListeners.forEach((listeners, event) => {
|
|
3772
|
+
listeners.forEach((listener) => {
|
|
3773
|
+
this.webSocketClient?.off(
|
|
3774
|
+
event,
|
|
3775
|
+
listener
|
|
3776
|
+
);
|
|
3777
|
+
});
|
|
3778
|
+
});
|
|
3779
|
+
this.eventListeners.clear();
|
|
3780
|
+
this.webSocketClient.once("close", () => {
|
|
3781
|
+
clearTimeout(closeTimeout);
|
|
3782
|
+
this.webSocketClient = void 0;
|
|
3783
|
+
console.log("WebSocket connection closed");
|
|
3784
|
+
resolve();
|
|
3785
|
+
});
|
|
3786
|
+
this.webSocketClient.close().then(() => {
|
|
3787
|
+
clearTimeout(closeTimeout);
|
|
3788
|
+
this.webSocketClient = void 0;
|
|
3789
|
+
resolve();
|
|
3790
|
+
}).catch((error) => {
|
|
3791
|
+
console.error("Error during WebSocket close:", error);
|
|
3792
|
+
clearTimeout(closeTimeout);
|
|
3793
|
+
this.webSocketClient = void 0;
|
|
3794
|
+
resolve();
|
|
3795
|
+
});
|
|
3796
|
+
});
|
|
3267
3797
|
}
|
|
3268
3798
|
/**
|
|
3269
3799
|
* Creates or retrieves a Channel instance.
|
|
@@ -3304,7 +3834,7 @@ var AriClient = class {
|
|
|
3304
3834
|
* @returns {boolean} True if WebSocket is connected, false otherwise
|
|
3305
3835
|
*/
|
|
3306
3836
|
isWebSocketConnected() {
|
|
3307
|
-
return !!this.webSocketClient;
|
|
3837
|
+
return !!this.webSocketClient && this.webSocketClient.isConnected();
|
|
3308
3838
|
}
|
|
3309
3839
|
};
|
|
3310
3840
|
export {
|