@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/cjs/index.cjs
CHANGED
|
@@ -936,16 +936,6 @@ var Asterisk = class {
|
|
|
936
936
|
var import_events = require("events");
|
|
937
937
|
var import_axios2 = require("axios");
|
|
938
938
|
|
|
939
|
-
// src/ari-client/interfaces/events.types.ts
|
|
940
|
-
var bridgeEvents = [
|
|
941
|
-
"BridgeCreated",
|
|
942
|
-
"BridgeDestroyed",
|
|
943
|
-
"BridgeMerged",
|
|
944
|
-
"BridgeBlindTransfer",
|
|
945
|
-
"BridgeAttendedTransfer",
|
|
946
|
-
"BridgeVideoSourceChanged"
|
|
947
|
-
];
|
|
948
|
-
|
|
949
939
|
// src/ari-client/utils.ts
|
|
950
940
|
function toQueryParams2(options) {
|
|
951
941
|
return new URLSearchParams(
|
|
@@ -975,9 +965,10 @@ var BridgeInstance = class {
|
|
|
975
965
|
this.client = client;
|
|
976
966
|
this.baseClient = baseClient;
|
|
977
967
|
this.id = bridgeId || `bridge-${Date.now()}`;
|
|
978
|
-
console.log(`BridgeInstance inicializada com ID: ${this.id}`);
|
|
979
968
|
}
|
|
980
969
|
eventEmitter = new import_events.EventEmitter();
|
|
970
|
+
listenersMap = /* @__PURE__ */ new Map();
|
|
971
|
+
// 🔹 Guarda listeners para remoção posterior
|
|
981
972
|
bridgeData = null;
|
|
982
973
|
id;
|
|
983
974
|
/**
|
|
@@ -998,7 +989,7 @@ var BridgeInstance = class {
|
|
|
998
989
|
*
|
|
999
990
|
* @example
|
|
1000
991
|
* bridge.on('BridgeCreated', (event) => {
|
|
1001
|
-
*
|
|
992
|
+
*
|
|
1002
993
|
* });
|
|
1003
994
|
* @param event
|
|
1004
995
|
* @param listener
|
|
@@ -1007,13 +998,23 @@ var BridgeInstance = class {
|
|
|
1007
998
|
if (!event) {
|
|
1008
999
|
throw new Error("Event type is required");
|
|
1009
1000
|
}
|
|
1001
|
+
const existingListeners = this.listenersMap.get(event) || [];
|
|
1002
|
+
if (existingListeners.includes(listener)) {
|
|
1003
|
+
console.warn(
|
|
1004
|
+
`Listener j\xE1 registrado para evento ${event}, reutilizando.`
|
|
1005
|
+
);
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1010
1008
|
const wrappedListener = (data) => {
|
|
1011
1009
|
if ("bridge" in data && data.bridge?.id === this.id) {
|
|
1012
1010
|
listener(data);
|
|
1013
1011
|
}
|
|
1014
1012
|
};
|
|
1015
1013
|
this.eventEmitter.on(event, wrappedListener);
|
|
1016
|
-
|
|
1014
|
+
if (!this.listenersMap.has(event)) {
|
|
1015
|
+
this.listenersMap.set(event, []);
|
|
1016
|
+
}
|
|
1017
|
+
this.listenersMap.get(event).push(wrappedListener);
|
|
1017
1018
|
}
|
|
1018
1019
|
/**
|
|
1019
1020
|
* Registers a one-time listener for specific bridge events.
|
|
@@ -1025,15 +1026,25 @@ var BridgeInstance = class {
|
|
|
1025
1026
|
if (!event) {
|
|
1026
1027
|
throw new Error("Event type is required");
|
|
1027
1028
|
}
|
|
1029
|
+
const eventKey = `${event}-${this.id}`;
|
|
1030
|
+
const existingListeners = this.listenersMap.get(eventKey) || [];
|
|
1031
|
+
if (existingListeners.includes(listener)) {
|
|
1032
|
+
console.warn(
|
|
1033
|
+
`One-time listener j\xE1 registrado para evento ${eventKey}, reutilizando.`
|
|
1034
|
+
);
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1028
1037
|
const wrappedListener = (data) => {
|
|
1029
1038
|
if ("bridge" in data && data.bridge?.id === this.id) {
|
|
1030
1039
|
listener(data);
|
|
1040
|
+
this.off(event, wrappedListener);
|
|
1031
1041
|
}
|
|
1032
1042
|
};
|
|
1033
1043
|
this.eventEmitter.once(event, wrappedListener);
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1044
|
+
if (!this.listenersMap.has(eventKey)) {
|
|
1045
|
+
this.listenersMap.set(eventKey, []);
|
|
1046
|
+
}
|
|
1047
|
+
this.listenersMap.get(eventKey).push(wrappedListener);
|
|
1037
1048
|
}
|
|
1038
1049
|
/**
|
|
1039
1050
|
* Removes event listener(s) from the bridge.
|
|
@@ -1047,14 +1058,25 @@ var BridgeInstance = class {
|
|
|
1047
1058
|
}
|
|
1048
1059
|
if (listener) {
|
|
1049
1060
|
this.eventEmitter.off(event, listener);
|
|
1050
|
-
|
|
1051
|
-
|
|
1061
|
+
const storedListeners = this.listenersMap.get(event) || [];
|
|
1062
|
+
this.listenersMap.set(
|
|
1063
|
+
event,
|
|
1064
|
+
storedListeners.filter((l) => l !== listener)
|
|
1052
1065
|
);
|
|
1053
1066
|
} else {
|
|
1054
1067
|
this.eventEmitter.removeAllListeners(event);
|
|
1055
|
-
|
|
1068
|
+
this.listenersMap.delete(event);
|
|
1056
1069
|
}
|
|
1057
1070
|
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Cleans up the BridgeInstance, resetting its state and clearing resources.
|
|
1073
|
+
*/
|
|
1074
|
+
cleanup() {
|
|
1075
|
+
this.bridgeData = null;
|
|
1076
|
+
this.removeAllListeners();
|
|
1077
|
+
this.listenersMap.clear();
|
|
1078
|
+
console.log(`Bridge instance ${this.id} cleaned up`);
|
|
1079
|
+
}
|
|
1058
1080
|
/**
|
|
1059
1081
|
* Emits an event if it corresponds to the current bridge.
|
|
1060
1082
|
*
|
|
@@ -1067,15 +1089,23 @@ var BridgeInstance = class {
|
|
|
1067
1089
|
}
|
|
1068
1090
|
if ("bridge" in event && event.bridge?.id === this.id) {
|
|
1069
1091
|
this.eventEmitter.emit(event.type, event);
|
|
1070
|
-
console.log(`Event ${event.type} emitted for bridge ${this.id}`);
|
|
1071
1092
|
}
|
|
1072
1093
|
}
|
|
1073
1094
|
/**
|
|
1074
1095
|
* Removes all event listeners from this bridge instance.
|
|
1075
1096
|
*/
|
|
1076
1097
|
removeAllListeners() {
|
|
1098
|
+
console.log(`Removing all event listeners for bridge ${this.id}`);
|
|
1099
|
+
this.listenersMap.forEach((listeners, event) => {
|
|
1100
|
+
listeners.forEach((listener) => {
|
|
1101
|
+
this.eventEmitter.off(
|
|
1102
|
+
event,
|
|
1103
|
+
listener
|
|
1104
|
+
);
|
|
1105
|
+
});
|
|
1106
|
+
});
|
|
1107
|
+
this.listenersMap.clear();
|
|
1077
1108
|
this.eventEmitter.removeAllListeners();
|
|
1078
|
-
console.log(`All listeners removed from bridge ${this.id}`);
|
|
1079
1109
|
}
|
|
1080
1110
|
/**
|
|
1081
1111
|
* Retrieves the current details of the bridge.
|
|
@@ -1091,7 +1121,6 @@ var BridgeInstance = class {
|
|
|
1091
1121
|
this.bridgeData = await this.baseClient.get(
|
|
1092
1122
|
`/bridges/${this.id}`
|
|
1093
1123
|
);
|
|
1094
|
-
console.log(`Details retrieved for bridge ${this.id}`);
|
|
1095
1124
|
return this.bridgeData;
|
|
1096
1125
|
} catch (error) {
|
|
1097
1126
|
const message = getErrorMessage(error);
|
|
@@ -1114,7 +1143,6 @@ var BridgeInstance = class {
|
|
|
1114
1143
|
await this.baseClient.post(
|
|
1115
1144
|
`/bridges/${this.id}/addChannel?${queryParams}`
|
|
1116
1145
|
);
|
|
1117
|
-
console.log(`Channels added to bridge ${this.id}`);
|
|
1118
1146
|
} catch (error) {
|
|
1119
1147
|
const message = getErrorMessage(error);
|
|
1120
1148
|
console.error(`Error adding channels to bridge ${this.id}:`, message);
|
|
@@ -1135,7 +1163,6 @@ var BridgeInstance = class {
|
|
|
1135
1163
|
await this.baseClient.post(
|
|
1136
1164
|
`/bridges/${this.id}/removeChannel?${queryParams}`
|
|
1137
1165
|
);
|
|
1138
|
-
console.log(`Channels removed from bridge ${this.id}`);
|
|
1139
1166
|
} catch (error) {
|
|
1140
1167
|
const message = getErrorMessage(error);
|
|
1141
1168
|
console.error(`Error removing channels from bridge ${this.id}:`, message);
|
|
@@ -1161,7 +1188,6 @@ var BridgeInstance = class {
|
|
|
1161
1188
|
`/bridges/${this.id}/play?${queryParams}`,
|
|
1162
1189
|
{ media: request.media }
|
|
1163
1190
|
);
|
|
1164
|
-
console.log(`Media playback started on bridge ${this.id}`);
|
|
1165
1191
|
return result;
|
|
1166
1192
|
} catch (error) {
|
|
1167
1193
|
const message = getErrorMessage(error);
|
|
@@ -1180,7 +1206,6 @@ var BridgeInstance = class {
|
|
|
1180
1206
|
await this.baseClient.delete(
|
|
1181
1207
|
`/bridges/${this.id}/play/${playbackId}`
|
|
1182
1208
|
);
|
|
1183
|
-
console.log(`Playback ${playbackId} stopped on bridge ${this.id}`);
|
|
1184
1209
|
} catch (error) {
|
|
1185
1210
|
const message = getErrorMessage(error);
|
|
1186
1211
|
console.error(`Error stopping playback on bridge ${this.id}:`, message);
|
|
@@ -1198,7 +1223,6 @@ var BridgeInstance = class {
|
|
|
1198
1223
|
await this.baseClient.post(
|
|
1199
1224
|
`/bridges/${this.id}/videoSource/${channelId}`
|
|
1200
1225
|
);
|
|
1201
|
-
console.log(`Video source set for bridge ${this.id}`);
|
|
1202
1226
|
} catch (error) {
|
|
1203
1227
|
const message = getErrorMessage(error);
|
|
1204
1228
|
console.error(
|
|
@@ -1216,7 +1240,6 @@ var BridgeInstance = class {
|
|
|
1216
1240
|
async clearVideoSource() {
|
|
1217
1241
|
try {
|
|
1218
1242
|
await this.baseClient.delete(`/bridges/${this.id}/videoSource`);
|
|
1219
|
-
console.log(`Video source removed from bridge ${this.id}`);
|
|
1220
1243
|
} catch (error) {
|
|
1221
1244
|
const message = getErrorMessage(error);
|
|
1222
1245
|
console.error(
|
|
@@ -1250,6 +1273,7 @@ var Bridges = class {
|
|
|
1250
1273
|
this.client = client;
|
|
1251
1274
|
}
|
|
1252
1275
|
bridgeInstances = /* @__PURE__ */ new Map();
|
|
1276
|
+
eventQueue = /* @__PURE__ */ new Map();
|
|
1253
1277
|
/**
|
|
1254
1278
|
* Creates or retrieves a Bridge instance.
|
|
1255
1279
|
*
|
|
@@ -1270,23 +1294,41 @@ var Bridges = class {
|
|
|
1270
1294
|
if (!id) {
|
|
1271
1295
|
const instance = new BridgeInstance(this.client, this.baseClient);
|
|
1272
1296
|
this.bridgeInstances.set(instance.id, instance);
|
|
1273
|
-
console.log(`New bridge instance created with ID: ${instance.id}`);
|
|
1274
1297
|
return instance;
|
|
1275
1298
|
}
|
|
1276
1299
|
if (!this.bridgeInstances.has(id)) {
|
|
1277
1300
|
const instance = new BridgeInstance(this.client, this.baseClient, id);
|
|
1278
1301
|
this.bridgeInstances.set(id, instance);
|
|
1279
|
-
console.log(`New bridge instance created with provided ID: ${id}`);
|
|
1280
1302
|
return instance;
|
|
1281
1303
|
}
|
|
1282
|
-
console.log(`Returning existing bridge instance: ${id}`);
|
|
1283
1304
|
return this.bridgeInstances.get(id);
|
|
1284
1305
|
} catch (error) {
|
|
1285
1306
|
const message = getErrorMessage(error);
|
|
1286
|
-
console.
|
|
1307
|
+
console.warn(`Error creating/retrieving bridge instance:`, message);
|
|
1287
1308
|
throw new Error(`Failed to manage bridge instance: ${message}`);
|
|
1288
1309
|
}
|
|
1289
1310
|
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Removes all bridge instances and cleans up their resources.
|
|
1313
|
+
* This method ensures proper cleanup of all bridges and their associated listeners.
|
|
1314
|
+
*/
|
|
1315
|
+
remove() {
|
|
1316
|
+
const bridgeIds = Array.from(this.bridgeInstances.keys());
|
|
1317
|
+
for (const bridgeId of bridgeIds) {
|
|
1318
|
+
try {
|
|
1319
|
+
const instance = this.bridgeInstances.get(bridgeId);
|
|
1320
|
+
if (instance) {
|
|
1321
|
+
instance.cleanup();
|
|
1322
|
+
this.bridgeInstances.delete(bridgeId);
|
|
1323
|
+
console.log(`Bridge instance ${bridgeId} removed and cleaned up`);
|
|
1324
|
+
}
|
|
1325
|
+
} catch (error) {
|
|
1326
|
+
console.error(`Error cleaning up bridge ${bridgeId}:`, error);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
this.bridgeInstances.clear();
|
|
1330
|
+
console.log("All bridge instances have been removed and cleaned up");
|
|
1331
|
+
}
|
|
1290
1332
|
/**
|
|
1291
1333
|
* Removes a bridge instance from the collection of managed bridges.
|
|
1292
1334
|
*
|
|
@@ -1299,15 +1341,20 @@ var Bridges = class {
|
|
|
1299
1341
|
*/
|
|
1300
1342
|
removeBridgeInstance(bridgeId) {
|
|
1301
1343
|
if (!bridgeId) {
|
|
1302
|
-
throw new Error("ID
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1344
|
+
throw new Error("Bridge ID is required");
|
|
1345
|
+
}
|
|
1346
|
+
const instance = this.bridgeInstances.get(bridgeId);
|
|
1347
|
+
if (instance) {
|
|
1348
|
+
try {
|
|
1349
|
+
instance.cleanup();
|
|
1350
|
+
this.bridgeInstances.delete(bridgeId);
|
|
1351
|
+
console.log(`Bridge instance ${bridgeId} removed from memory`);
|
|
1352
|
+
} catch (error) {
|
|
1353
|
+
console.error(`Error removing bridge instance ${bridgeId}:`, error);
|
|
1354
|
+
throw error;
|
|
1355
|
+
}
|
|
1309
1356
|
} else {
|
|
1310
|
-
console.warn(`
|
|
1357
|
+
console.warn(`Attempt to remove non-existent instance: ${bridgeId}`);
|
|
1311
1358
|
}
|
|
1312
1359
|
}
|
|
1313
1360
|
/**
|
|
@@ -1324,28 +1371,51 @@ var Bridges = class {
|
|
|
1324
1371
|
*
|
|
1325
1372
|
* @remarks
|
|
1326
1373
|
* - If the event is invalid (null or undefined), a warning is logged and the function returns early.
|
|
1327
|
-
* - The function checks if the event is bridge-related and if the event
|
|
1374
|
+
* - The function checks if the event is bridge-related and if the event contains a valid bridge ID.
|
|
1328
1375
|
* - If a matching bridge instance is found, the event is emitted to that instance.
|
|
1329
1376
|
* - If no matching bridge instance is found, a warning is logged.
|
|
1330
1377
|
*/
|
|
1331
1378
|
propagateEventToBridge(event) {
|
|
1332
|
-
if (!event) {
|
|
1333
|
-
console.warn("
|
|
1379
|
+
if (!event || !("bridge" in event) || !event.bridge?.id) {
|
|
1380
|
+
console.warn("Invalid WebSocket event received");
|
|
1334
1381
|
return;
|
|
1335
1382
|
}
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1383
|
+
const key = `${event.type}-${event.bridge.id}`;
|
|
1384
|
+
const existing = this.eventQueue.get(key);
|
|
1385
|
+
if (existing) {
|
|
1386
|
+
clearTimeout(existing);
|
|
1387
|
+
}
|
|
1388
|
+
this.eventQueue.set(
|
|
1389
|
+
key,
|
|
1390
|
+
setTimeout(() => {
|
|
1391
|
+
const instance = this.bridgeInstances.get(event.bridge.id);
|
|
1392
|
+
if (instance) {
|
|
1393
|
+
instance.emitEvent(event);
|
|
1394
|
+
} else {
|
|
1395
|
+
console.warn(
|
|
1396
|
+
`No instance found for bridge ${event.bridge.id}. Event ignored.`
|
|
1397
|
+
);
|
|
1398
|
+
}
|
|
1399
|
+
this.eventQueue.delete(key);
|
|
1400
|
+
}, 100)
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Performs a cleanup of the Bridges instance, clearing all event queues and removing all bridge instances.
|
|
1405
|
+
*
|
|
1406
|
+
* This method is responsible for:
|
|
1407
|
+
* 1. Clearing all pending timeouts in the event queue.
|
|
1408
|
+
* 2. Removing all bridge instances managed by this Bridges object.
|
|
1409
|
+
*
|
|
1410
|
+
* It should be called when the Bridges instance is no longer needed or before reinitializing
|
|
1411
|
+
* to ensure all resources are properly released.
|
|
1412
|
+
*
|
|
1413
|
+
* @returns {void}
|
|
1414
|
+
*/
|
|
1415
|
+
cleanup() {
|
|
1416
|
+
this.eventQueue.forEach((timeout) => clearTimeout(timeout));
|
|
1417
|
+
this.eventQueue.clear();
|
|
1418
|
+
this.remove();
|
|
1349
1419
|
}
|
|
1350
1420
|
/**
|
|
1351
1421
|
* Lists all active bridges in the system.
|
|
@@ -1361,7 +1431,7 @@ var Bridges = class {
|
|
|
1361
1431
|
* @example
|
|
1362
1432
|
* try {
|
|
1363
1433
|
* const bridges = await bridgesInstance.list();
|
|
1364
|
-
*
|
|
1434
|
+
*
|
|
1365
1435
|
* } catch (error) {
|
|
1366
1436
|
* console.error('Failed to fetch bridges:', error);
|
|
1367
1437
|
* }
|
|
@@ -1606,7 +1676,7 @@ var Bridges = class {
|
|
|
1606
1676
|
};
|
|
1607
1677
|
|
|
1608
1678
|
// src/ari-client/resources/channels.ts
|
|
1609
|
-
var
|
|
1679
|
+
var import_events2 = require("events");
|
|
1610
1680
|
var import_axios3 = require("axios");
|
|
1611
1681
|
|
|
1612
1682
|
// node_modules/uuid/dist/esm/stringify.js
|
|
@@ -1670,8 +1740,10 @@ var ChannelInstance = class {
|
|
|
1670
1740
|
this.baseClient = baseClient;
|
|
1671
1741
|
this.id = channelId || `channel-${Date.now()}`;
|
|
1672
1742
|
}
|
|
1673
|
-
eventEmitter = new
|
|
1743
|
+
eventEmitter = new import_events2.EventEmitter();
|
|
1674
1744
|
channelData = null;
|
|
1745
|
+
listenersMap = /* @__PURE__ */ new Map();
|
|
1746
|
+
// 🔹 Guarda listeners para remoção posterior
|
|
1675
1747
|
id;
|
|
1676
1748
|
/**
|
|
1677
1749
|
* Registers an event listener for specific channel events
|
|
@@ -1680,12 +1752,23 @@ var ChannelInstance = class {
|
|
|
1680
1752
|
if (!event) {
|
|
1681
1753
|
throw new Error("Event type is required");
|
|
1682
1754
|
}
|
|
1755
|
+
const existingListeners = this.listenersMap.get(event) || [];
|
|
1756
|
+
if (existingListeners.includes(listener)) {
|
|
1757
|
+
console.warn(
|
|
1758
|
+
`Listener j\xE1 registrado para evento ${event}, reutilizando.`
|
|
1759
|
+
);
|
|
1760
|
+
return;
|
|
1761
|
+
}
|
|
1683
1762
|
const wrappedListener = (data) => {
|
|
1684
1763
|
if ("channel" in data && data.channel?.id === this.id) {
|
|
1685
1764
|
listener(data);
|
|
1686
1765
|
}
|
|
1687
1766
|
};
|
|
1688
1767
|
this.eventEmitter.on(event, wrappedListener);
|
|
1768
|
+
if (!this.listenersMap.has(event)) {
|
|
1769
|
+
this.listenersMap.set(event, []);
|
|
1770
|
+
}
|
|
1771
|
+
this.listenersMap.get(event).push(wrappedListener);
|
|
1689
1772
|
}
|
|
1690
1773
|
/**
|
|
1691
1774
|
* Registers a one-time event listener
|
|
@@ -1694,12 +1777,25 @@ var ChannelInstance = class {
|
|
|
1694
1777
|
if (!event) {
|
|
1695
1778
|
throw new Error("Event type is required");
|
|
1696
1779
|
}
|
|
1780
|
+
const eventKey = `${event}-${this.id}`;
|
|
1781
|
+
const existingListeners = this.listenersMap.get(eventKey) || [];
|
|
1782
|
+
if (existingListeners.includes(listener)) {
|
|
1783
|
+
console.warn(
|
|
1784
|
+
`One-time listener j\xE1 registrado para evento ${eventKey}, reutilizando.`
|
|
1785
|
+
);
|
|
1786
|
+
return;
|
|
1787
|
+
}
|
|
1697
1788
|
const wrappedListener = (data) => {
|
|
1698
1789
|
if ("channel" in data && data.channel?.id === this.id) {
|
|
1699
1790
|
listener(data);
|
|
1791
|
+
this.off(event, wrappedListener);
|
|
1700
1792
|
}
|
|
1701
1793
|
};
|
|
1702
1794
|
this.eventEmitter.once(event, wrappedListener);
|
|
1795
|
+
if (!this.listenersMap.has(eventKey)) {
|
|
1796
|
+
this.listenersMap.set(eventKey, []);
|
|
1797
|
+
}
|
|
1798
|
+
this.listenersMap.get(eventKey).push(wrappedListener);
|
|
1703
1799
|
}
|
|
1704
1800
|
/**
|
|
1705
1801
|
* Removes event listener(s) for a specific WebSocket event type.
|
|
@@ -1716,10 +1812,25 @@ var ChannelInstance = class {
|
|
|
1716
1812
|
}
|
|
1717
1813
|
if (listener) {
|
|
1718
1814
|
this.eventEmitter.off(event, listener);
|
|
1815
|
+
const storedListeners = this.listenersMap.get(event) || [];
|
|
1816
|
+
this.listenersMap.set(
|
|
1817
|
+
event,
|
|
1818
|
+
storedListeners.filter((l) => l !== listener)
|
|
1819
|
+
);
|
|
1719
1820
|
} else {
|
|
1720
1821
|
this.eventEmitter.removeAllListeners(event);
|
|
1822
|
+
this.listenersMap.delete(event);
|
|
1721
1823
|
}
|
|
1722
1824
|
}
|
|
1825
|
+
/**
|
|
1826
|
+
* Cleans up the ChannelInstance, resetting its state and clearing resources.
|
|
1827
|
+
*/
|
|
1828
|
+
cleanup() {
|
|
1829
|
+
this.channelData = null;
|
|
1830
|
+
this.removeAllListeners();
|
|
1831
|
+
this.listenersMap.clear();
|
|
1832
|
+
console.log(`Channel instance ${this.id} cleaned up`);
|
|
1833
|
+
}
|
|
1723
1834
|
/**
|
|
1724
1835
|
* Emits an event if it matches the current channel
|
|
1725
1836
|
*/
|
|
@@ -1739,6 +1850,16 @@ var ChannelInstance = class {
|
|
|
1739
1850
|
* @return {void} This method does not return a value.
|
|
1740
1851
|
*/
|
|
1741
1852
|
removeAllListeners() {
|
|
1853
|
+
console.log(`Removing all event listeners for channel ${this.id}`);
|
|
1854
|
+
this.listenersMap.forEach((listeners, event) => {
|
|
1855
|
+
listeners.forEach((listener) => {
|
|
1856
|
+
this.eventEmitter.off(
|
|
1857
|
+
event,
|
|
1858
|
+
listener
|
|
1859
|
+
);
|
|
1860
|
+
});
|
|
1861
|
+
});
|
|
1862
|
+
this.listenersMap.clear();
|
|
1742
1863
|
this.eventEmitter.removeAllListeners();
|
|
1743
1864
|
}
|
|
1744
1865
|
/**
|
|
@@ -2027,6 +2148,7 @@ var Channels = class {
|
|
|
2027
2148
|
this.client = client;
|
|
2028
2149
|
}
|
|
2029
2150
|
channelInstances = /* @__PURE__ */ new Map();
|
|
2151
|
+
eventQueue = /* @__PURE__ */ new Map();
|
|
2030
2152
|
/**
|
|
2031
2153
|
* Creates or retrieves a ChannelInstance.
|
|
2032
2154
|
*
|
|
@@ -2062,6 +2184,32 @@ var Channels = class {
|
|
|
2062
2184
|
throw new Error(`Failed to manage channel instance: ${message}`);
|
|
2063
2185
|
}
|
|
2064
2186
|
}
|
|
2187
|
+
cleanup() {
|
|
2188
|
+
this.eventQueue.forEach((timeout) => clearTimeout(timeout));
|
|
2189
|
+
this.eventQueue.clear();
|
|
2190
|
+
this.remove();
|
|
2191
|
+
}
|
|
2192
|
+
/**
|
|
2193
|
+
* Removes all channel instances and cleans up their resources.
|
|
2194
|
+
* This method ensures proper cleanup of all channels and their associated listeners.
|
|
2195
|
+
*/
|
|
2196
|
+
remove() {
|
|
2197
|
+
const channelIds = Array.from(this.channelInstances.keys());
|
|
2198
|
+
for (const channelId of channelIds) {
|
|
2199
|
+
try {
|
|
2200
|
+
const instance = this.channelInstances.get(channelId);
|
|
2201
|
+
if (instance) {
|
|
2202
|
+
instance.cleanup();
|
|
2203
|
+
this.channelInstances.delete(channelId);
|
|
2204
|
+
console.log(`Channel instance ${channelId} removed and cleaned up`);
|
|
2205
|
+
}
|
|
2206
|
+
} catch (error) {
|
|
2207
|
+
console.error(`Error cleaning up channel ${channelId}:`, error);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
this.channelInstances.clear();
|
|
2211
|
+
console.log("All channel instances have been removed and cleaned up");
|
|
2212
|
+
}
|
|
2065
2213
|
/**
|
|
2066
2214
|
* Retrieves the details of a specific channel.
|
|
2067
2215
|
*
|
|
@@ -2088,10 +2236,16 @@ var Channels = class {
|
|
|
2088
2236
|
if (!channelId) {
|
|
2089
2237
|
throw new Error("Channel ID is required");
|
|
2090
2238
|
}
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2239
|
+
const instance = this.channelInstances.get(channelId);
|
|
2240
|
+
if (instance) {
|
|
2241
|
+
try {
|
|
2242
|
+
instance.cleanup();
|
|
2243
|
+
this.channelInstances.delete(channelId);
|
|
2244
|
+
console.log(`Channel instance ${channelId} removed from memory`);
|
|
2245
|
+
} catch (error) {
|
|
2246
|
+
console.error(`Error removing channel instance ${channelId}:`, error);
|
|
2247
|
+
throw error;
|
|
2248
|
+
}
|
|
2095
2249
|
} else {
|
|
2096
2250
|
console.warn(`Attempt to remove non-existent instance: ${channelId}`);
|
|
2097
2251
|
}
|
|
@@ -2100,18 +2254,29 @@ var Channels = class {
|
|
|
2100
2254
|
* Propagates a WebSocket event to a specific channel.
|
|
2101
2255
|
*/
|
|
2102
2256
|
propagateEventToChannel(event) {
|
|
2103
|
-
if (!event) {
|
|
2257
|
+
if (!event || !("channel" in event) || !event.channel?.id) {
|
|
2104
2258
|
console.warn("Invalid WebSocket event received");
|
|
2105
2259
|
return;
|
|
2106
2260
|
}
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2261
|
+
const key = `${event.type}-${event.channel.id}`;
|
|
2262
|
+
const existing = this.eventQueue.get(key);
|
|
2263
|
+
if (existing) {
|
|
2264
|
+
clearTimeout(existing);
|
|
2265
|
+
}
|
|
2266
|
+
this.eventQueue.set(
|
|
2267
|
+
key,
|
|
2268
|
+
setTimeout(() => {
|
|
2269
|
+
const instance = this.channelInstances.get(event.channel.id);
|
|
2270
|
+
if (instance) {
|
|
2271
|
+
instance.emitEvent(event);
|
|
2272
|
+
} else {
|
|
2273
|
+
console.warn(
|
|
2274
|
+
`No instance found for channel ${event.channel.id}. Event ignored.`
|
|
2275
|
+
);
|
|
2276
|
+
}
|
|
2277
|
+
this.eventQueue.delete(key);
|
|
2278
|
+
}, 100)
|
|
2279
|
+
);
|
|
2115
2280
|
}
|
|
2116
2281
|
/**
|
|
2117
2282
|
* Initiates a new channel.
|
|
@@ -2566,7 +2731,7 @@ var Endpoints = class {
|
|
|
2566
2731
|
};
|
|
2567
2732
|
|
|
2568
2733
|
// src/ari-client/resources/playbacks.ts
|
|
2569
|
-
var
|
|
2734
|
+
var import_events3 = require("events");
|
|
2570
2735
|
var import_axios4 = require("axios");
|
|
2571
2736
|
var getErrorMessage3 = (error) => {
|
|
2572
2737
|
if ((0, import_axios4.isAxiosError)(error)) {
|
|
@@ -2591,7 +2756,9 @@ var PlaybackInstance = class {
|
|
|
2591
2756
|
this.playbackId = playbackId;
|
|
2592
2757
|
this.id = playbackId;
|
|
2593
2758
|
}
|
|
2594
|
-
eventEmitter = new
|
|
2759
|
+
eventEmitter = new import_events3.EventEmitter();
|
|
2760
|
+
listenersMap = /* @__PURE__ */ new Map();
|
|
2761
|
+
// 🔹 Guarda listeners para remoção posterior
|
|
2595
2762
|
playbackData = null;
|
|
2596
2763
|
id;
|
|
2597
2764
|
/**
|
|
@@ -2604,12 +2771,23 @@ var PlaybackInstance = class {
|
|
|
2604
2771
|
if (!event) {
|
|
2605
2772
|
throw new Error("Event type is required");
|
|
2606
2773
|
}
|
|
2774
|
+
const existingListeners = this.listenersMap.get(event) || [];
|
|
2775
|
+
if (existingListeners.includes(listener)) {
|
|
2776
|
+
console.warn(
|
|
2777
|
+
`Listener j\xE1 registrado para evento ${event}, reutilizando.`
|
|
2778
|
+
);
|
|
2779
|
+
return;
|
|
2780
|
+
}
|
|
2607
2781
|
const wrappedListener = (data) => {
|
|
2608
2782
|
if ("playback" in data && data.playback?.id === this.id) {
|
|
2609
2783
|
listener(data);
|
|
2610
2784
|
}
|
|
2611
2785
|
};
|
|
2612
2786
|
this.eventEmitter.on(event, wrappedListener);
|
|
2787
|
+
if (!this.listenersMap.has(event)) {
|
|
2788
|
+
this.listenersMap.set(event, []);
|
|
2789
|
+
}
|
|
2790
|
+
this.listenersMap.get(event).push(wrappedListener);
|
|
2613
2791
|
}
|
|
2614
2792
|
/**
|
|
2615
2793
|
* Registers a one-time event listener for a specific WebSocket event type.
|
|
@@ -2621,12 +2799,25 @@ var PlaybackInstance = class {
|
|
|
2621
2799
|
if (!event) {
|
|
2622
2800
|
throw new Error("Event type is required");
|
|
2623
2801
|
}
|
|
2802
|
+
const eventKey = `${event}-${this.id}`;
|
|
2803
|
+
const existingListeners = this.listenersMap.get(eventKey) || [];
|
|
2804
|
+
if (existingListeners.includes(listener)) {
|
|
2805
|
+
console.warn(
|
|
2806
|
+
`One-time listener j\xE1 registrado para evento ${eventKey}, reutilizando.`
|
|
2807
|
+
);
|
|
2808
|
+
return;
|
|
2809
|
+
}
|
|
2624
2810
|
const wrappedListener = (data) => {
|
|
2625
2811
|
if ("playback" in data && data.playback?.id === this.id) {
|
|
2626
2812
|
listener(data);
|
|
2813
|
+
this.off(event, wrappedListener);
|
|
2627
2814
|
}
|
|
2628
2815
|
};
|
|
2629
2816
|
this.eventEmitter.once(event, wrappedListener);
|
|
2817
|
+
if (!this.listenersMap.has(eventKey)) {
|
|
2818
|
+
this.listenersMap.set(eventKey, []);
|
|
2819
|
+
}
|
|
2820
|
+
this.listenersMap.get(eventKey).push(wrappedListener);
|
|
2630
2821
|
}
|
|
2631
2822
|
/**
|
|
2632
2823
|
* Removes event listener(s) for a specific WebSocket event type.
|
|
@@ -2640,10 +2831,25 @@ var PlaybackInstance = class {
|
|
|
2640
2831
|
}
|
|
2641
2832
|
if (listener) {
|
|
2642
2833
|
this.eventEmitter.off(event, listener);
|
|
2834
|
+
const storedListeners = this.listenersMap.get(event) || [];
|
|
2835
|
+
this.listenersMap.set(
|
|
2836
|
+
event,
|
|
2837
|
+
storedListeners.filter((l) => l !== listener)
|
|
2838
|
+
);
|
|
2643
2839
|
} else {
|
|
2644
2840
|
this.eventEmitter.removeAllListeners(event);
|
|
2841
|
+
this.listenersMap.delete(event);
|
|
2645
2842
|
}
|
|
2646
2843
|
}
|
|
2844
|
+
/**
|
|
2845
|
+
* Cleans up the PlaybackInstance, resetting its state and clearing resources.
|
|
2846
|
+
*/
|
|
2847
|
+
cleanup() {
|
|
2848
|
+
this.playbackData = null;
|
|
2849
|
+
this.removeAllListeners();
|
|
2850
|
+
this.listenersMap.clear();
|
|
2851
|
+
console.log(`Playback instance ${this.id} cleaned up`);
|
|
2852
|
+
}
|
|
2647
2853
|
/**
|
|
2648
2854
|
* Emits a WebSocket event if it matches the current playback instance.
|
|
2649
2855
|
*
|
|
@@ -2717,9 +2923,29 @@ var PlaybackInstance = class {
|
|
|
2717
2923
|
}
|
|
2718
2924
|
}
|
|
2719
2925
|
/**
|
|
2720
|
-
* Removes all event listeners
|
|
2926
|
+
* Removes all event listeners associated with this playback instance.
|
|
2927
|
+
* This method clears both the internal listener map and the event emitter.
|
|
2928
|
+
*
|
|
2929
|
+
* @remarks
|
|
2930
|
+
* This method performs the following actions:
|
|
2931
|
+
* 1. Logs a message indicating the removal of listeners.
|
|
2932
|
+
* 2. Iterates through all stored listeners and removes them from the event emitter.
|
|
2933
|
+
* 3. Clears the internal listener map.
|
|
2934
|
+
* 4. Removes all listeners from the event emitter.
|
|
2935
|
+
*
|
|
2936
|
+
* @returns {void} This method doesn't return a value.
|
|
2721
2937
|
*/
|
|
2722
2938
|
removeAllListeners() {
|
|
2939
|
+
console.log(`Removing all event listeners for playback ${this.id}`);
|
|
2940
|
+
this.listenersMap.forEach((listeners, event) => {
|
|
2941
|
+
listeners.forEach((listener) => {
|
|
2942
|
+
this.eventEmitter.off(
|
|
2943
|
+
event,
|
|
2944
|
+
listener
|
|
2945
|
+
);
|
|
2946
|
+
});
|
|
2947
|
+
});
|
|
2948
|
+
this.listenersMap.clear();
|
|
2723
2949
|
this.eventEmitter.removeAllListeners();
|
|
2724
2950
|
}
|
|
2725
2951
|
/**
|
|
@@ -2746,6 +2972,7 @@ var Playbacks = class {
|
|
|
2746
2972
|
this.client = client;
|
|
2747
2973
|
}
|
|
2748
2974
|
playbackInstances = /* @__PURE__ */ new Map();
|
|
2975
|
+
eventQueue = /* @__PURE__ */ new Map();
|
|
2749
2976
|
/**
|
|
2750
2977
|
* Gets or creates a playback instance
|
|
2751
2978
|
* @param {Object} [params] - Optional parameters for getting/creating a playback instance
|
|
@@ -2772,6 +2999,43 @@ var Playbacks = class {
|
|
|
2772
2999
|
throw new Error(`Failed to manage playback instance: ${message}`);
|
|
2773
3000
|
}
|
|
2774
3001
|
}
|
|
3002
|
+
/**
|
|
3003
|
+
* Cleans up resources associated with the Playbacks instance.
|
|
3004
|
+
* This method performs the following cleanup operations:
|
|
3005
|
+
* 1. Clears all pending timeouts in the event queue.
|
|
3006
|
+
* 2. Removes all playback instances.
|
|
3007
|
+
*
|
|
3008
|
+
* @remarks
|
|
3009
|
+
* This method should be called when the Playbacks instance is no longer needed
|
|
3010
|
+
* to ensure proper resource management and prevent memory leaks.
|
|
3011
|
+
*
|
|
3012
|
+
* @returns {void} This method doesn't return a value.
|
|
3013
|
+
*/
|
|
3014
|
+
cleanup() {
|
|
3015
|
+
this.eventQueue.forEach((timeout) => clearTimeout(timeout));
|
|
3016
|
+
this.eventQueue.clear();
|
|
3017
|
+
this.remove();
|
|
3018
|
+
}
|
|
3019
|
+
/**
|
|
3020
|
+
* Removes all playback instances and cleans up their resources.
|
|
3021
|
+
*/
|
|
3022
|
+
remove() {
|
|
3023
|
+
const playbackIds = Array.from(this.playbackInstances.keys());
|
|
3024
|
+
for (const playbackId of playbackIds) {
|
|
3025
|
+
try {
|
|
3026
|
+
const instance = this.playbackInstances.get(playbackId);
|
|
3027
|
+
if (instance) {
|
|
3028
|
+
instance.cleanup();
|
|
3029
|
+
this.playbackInstances.delete(playbackId);
|
|
3030
|
+
console.log(`Playback instance ${playbackId} removed and cleaned up`);
|
|
3031
|
+
}
|
|
3032
|
+
} catch (error) {
|
|
3033
|
+
console.error(`Error cleaning up playback ${playbackId}:`, error);
|
|
3034
|
+
}
|
|
3035
|
+
}
|
|
3036
|
+
this.playbackInstances.clear();
|
|
3037
|
+
console.log("All playback instances have been removed and cleaned up");
|
|
3038
|
+
}
|
|
2775
3039
|
/**
|
|
2776
3040
|
* Removes a playback instance and cleans up its resources
|
|
2777
3041
|
* @param {string} playbackId - ID of the playback instance to remove
|
|
@@ -2781,10 +3045,16 @@ var Playbacks = class {
|
|
|
2781
3045
|
if (!playbackId) {
|
|
2782
3046
|
throw new Error("Playback ID is required");
|
|
2783
3047
|
}
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
3048
|
+
const instance = this.playbackInstances.get(playbackId);
|
|
3049
|
+
if (instance) {
|
|
3050
|
+
try {
|
|
3051
|
+
instance.cleanup();
|
|
3052
|
+
this.playbackInstances.delete(playbackId);
|
|
3053
|
+
console.log(`Playback instance ${playbackId} removed from memory`);
|
|
3054
|
+
} catch (error) {
|
|
3055
|
+
console.error(`Error removing playback instance ${playbackId}:`, error);
|
|
3056
|
+
throw error;
|
|
3057
|
+
}
|
|
2788
3058
|
} else {
|
|
2789
3059
|
console.warn(`Attempt to remove non-existent instance: ${playbackId}`);
|
|
2790
3060
|
}
|
|
@@ -2794,17 +3064,29 @@ var Playbacks = class {
|
|
|
2794
3064
|
* @param {WebSocketEvent} event - The WebSocket event to propagate
|
|
2795
3065
|
*/
|
|
2796
3066
|
propagateEventToPlayback(event) {
|
|
2797
|
-
if (!event) {
|
|
3067
|
+
if (!event || !("playback" in event) || !event.playback?.id) {
|
|
3068
|
+
console.warn("Invalid WebSocket event received");
|
|
2798
3069
|
return;
|
|
2799
3070
|
}
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
3071
|
+
const key = `${event.type}-${event.playback.id}`;
|
|
3072
|
+
const existing = this.eventQueue.get(key);
|
|
3073
|
+
if (existing) {
|
|
3074
|
+
clearTimeout(existing);
|
|
3075
|
+
}
|
|
3076
|
+
this.eventQueue.set(
|
|
3077
|
+
key,
|
|
3078
|
+
setTimeout(() => {
|
|
3079
|
+
const instance = this.playbackInstances.get(event.playback.id);
|
|
3080
|
+
if (instance) {
|
|
3081
|
+
instance.emitEvent(event);
|
|
3082
|
+
} else {
|
|
3083
|
+
console.warn(
|
|
3084
|
+
`No instance found for playback ${event.playback.id}. Event ignored.`
|
|
3085
|
+
);
|
|
3086
|
+
}
|
|
3087
|
+
this.eventQueue.delete(key);
|
|
3088
|
+
}, 100)
|
|
3089
|
+
);
|
|
2808
3090
|
}
|
|
2809
3091
|
/**
|
|
2810
3092
|
* Retrieves details of a specific playback
|
|
@@ -2910,13 +3192,13 @@ var Sounds = class {
|
|
|
2910
3192
|
};
|
|
2911
3193
|
|
|
2912
3194
|
// src/ari-client/websocketClient.ts
|
|
2913
|
-
var
|
|
3195
|
+
var import_events4 = require("events");
|
|
2914
3196
|
var import_exponential_backoff = __toESM(require_backoff(), 1);
|
|
2915
3197
|
var import_ws = __toESM(require("ws"), 1);
|
|
2916
3198
|
var DEFAULT_MAX_RECONNECT_ATTEMPTS = 30;
|
|
2917
3199
|
var DEFAULT_STARTING_DELAY = 500;
|
|
2918
3200
|
var DEFAULT_MAX_DELAY = 1e4;
|
|
2919
|
-
var WebSocketClient = class extends
|
|
3201
|
+
var WebSocketClient = class extends import_events4.EventEmitter {
|
|
2920
3202
|
/**
|
|
2921
3203
|
* Creates a new WebSocketClient instance.
|
|
2922
3204
|
*
|
|
@@ -2942,9 +3224,57 @@ var WebSocketClient = class extends import_events5.EventEmitter {
|
|
|
2942
3224
|
}
|
|
2943
3225
|
ws;
|
|
2944
3226
|
isReconnecting = false;
|
|
3227
|
+
isConnecting = false;
|
|
3228
|
+
// 🔹 Evita múltiplas conexões simultâneas
|
|
3229
|
+
shouldReconnect = true;
|
|
3230
|
+
// 🔹 Nova flag para impedir reconexão se for um fechamento intencional
|
|
2945
3231
|
maxReconnectAttempts = DEFAULT_MAX_RECONNECT_ATTEMPTS;
|
|
2946
3232
|
reconnectionAttempts = 0;
|
|
2947
3233
|
lastWsUrl = "";
|
|
3234
|
+
eventQueue = /* @__PURE__ */ new Map();
|
|
3235
|
+
/**
|
|
3236
|
+
* Logs the current connection status of the WebSocket client at regular intervals.
|
|
3237
|
+
*
|
|
3238
|
+
* This method sets up an interval that logs various connection-related metrics every 60 seconds.
|
|
3239
|
+
* The logged information includes:
|
|
3240
|
+
* - The number of active connections (0 or 1)
|
|
3241
|
+
* - The current state of the WebSocket connection
|
|
3242
|
+
* - The number of reconnection attempts made
|
|
3243
|
+
* - The size of the event queue
|
|
3244
|
+
*
|
|
3245
|
+
* This can be useful for monitoring the health and status of the WebSocket connection over time.
|
|
3246
|
+
*
|
|
3247
|
+
* @private
|
|
3248
|
+
* @returns {void}
|
|
3249
|
+
*/
|
|
3250
|
+
logConnectionStatus() {
|
|
3251
|
+
setInterval(() => {
|
|
3252
|
+
console.log({
|
|
3253
|
+
connections: this.ws ? 1 : 0,
|
|
3254
|
+
state: this.getState(),
|
|
3255
|
+
reconnectAttempts: this.reconnectionAttempts,
|
|
3256
|
+
eventQueueSize: this.eventQueue.size
|
|
3257
|
+
});
|
|
3258
|
+
}, 6e4);
|
|
3259
|
+
}
|
|
3260
|
+
/**
|
|
3261
|
+
* Sets up a heartbeat mechanism for the WebSocket connection.
|
|
3262
|
+
*
|
|
3263
|
+
* This method creates an interval that sends a ping message every 30 seconds
|
|
3264
|
+
* to keep the connection alive. The heartbeat is automatically cleared when
|
|
3265
|
+
* the WebSocket connection is closed.
|
|
3266
|
+
*
|
|
3267
|
+
* @private
|
|
3268
|
+
* @returns {void}
|
|
3269
|
+
*/
|
|
3270
|
+
setupHeartbeat() {
|
|
3271
|
+
const interval = setInterval(() => {
|
|
3272
|
+
if (this.ws?.readyState === import_ws.default.OPEN) {
|
|
3273
|
+
this.ws.ping();
|
|
3274
|
+
}
|
|
3275
|
+
}, 3e4);
|
|
3276
|
+
this.ws.once("close", () => clearInterval(interval));
|
|
3277
|
+
}
|
|
2948
3278
|
backOffOptions = {
|
|
2949
3279
|
numOfAttempts: DEFAULT_MAX_RECONNECT_ATTEMPTS,
|
|
2950
3280
|
startingDelay: DEFAULT_STARTING_DELAY,
|
|
@@ -2971,21 +3301,29 @@ var WebSocketClient = class extends import_events5.EventEmitter {
|
|
|
2971
3301
|
* @throws Will throw an error if the connection cannot be established.
|
|
2972
3302
|
*/
|
|
2973
3303
|
async connect() {
|
|
3304
|
+
if (this.isConnecting || this.isConnected()) {
|
|
3305
|
+
console.warn(
|
|
3306
|
+
"WebSocket is already connecting or connected. Skipping new connection."
|
|
3307
|
+
);
|
|
3308
|
+
return;
|
|
3309
|
+
}
|
|
3310
|
+
this.shouldReconnect = true;
|
|
3311
|
+
this.isConnecting = true;
|
|
2974
3312
|
const { baseUrl, username, password } = this.baseClient.getCredentials();
|
|
2975
3313
|
const protocol = baseUrl.startsWith("https") ? "wss" : "ws";
|
|
2976
3314
|
const normalizedHost = baseUrl.replace(/^https?:\/\//, "").replace(/\/ari$/, "");
|
|
2977
3315
|
const queryParams = new URLSearchParams();
|
|
2978
3316
|
queryParams.append("app", this.apps.join(","));
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
);
|
|
2983
|
-
} else {
|
|
2984
|
-
queryParams.append("subscribeAll", "true");
|
|
2985
|
-
}
|
|
3317
|
+
this.subscribedEvents?.forEach(
|
|
3318
|
+
(event) => queryParams.append("event", event)
|
|
3319
|
+
);
|
|
2986
3320
|
this.lastWsUrl = `${protocol}://${encodeURIComponent(username)}:${encodeURIComponent(password)}@${normalizedHost}/ari/events?${queryParams.toString()}`;
|
|
2987
3321
|
console.log("Connecting to WebSocket...");
|
|
2988
|
-
|
|
3322
|
+
try {
|
|
3323
|
+
await this.initializeWebSocket(this.lastWsUrl);
|
|
3324
|
+
} finally {
|
|
3325
|
+
this.isConnecting = false;
|
|
3326
|
+
}
|
|
2989
3327
|
}
|
|
2990
3328
|
/**
|
|
2991
3329
|
* Initializes a WebSocket connection with exponential backoff retry mechanism.
|
|
@@ -3007,8 +3345,9 @@ var WebSocketClient = class extends import_events5.EventEmitter {
|
|
|
3007
3345
|
return new Promise((resolve, reject) => {
|
|
3008
3346
|
try {
|
|
3009
3347
|
this.ws = new import_ws.default(wsUrl);
|
|
3010
|
-
this.ws.
|
|
3348
|
+
this.ws.once("open", () => {
|
|
3011
3349
|
console.log("WebSocket connection established successfully");
|
|
3350
|
+
this.setupHeartbeat();
|
|
3012
3351
|
if (this.isReconnecting) {
|
|
3013
3352
|
this.emit("reconnected", {
|
|
3014
3353
|
apps: this.apps,
|
|
@@ -3021,7 +3360,7 @@ var WebSocketClient = class extends import_events5.EventEmitter {
|
|
|
3021
3360
|
resolve();
|
|
3022
3361
|
});
|
|
3023
3362
|
this.ws.on("message", (data) => this.handleMessage(data.toString()));
|
|
3024
|
-
this.ws.
|
|
3363
|
+
this.ws.once("close", (code) => {
|
|
3025
3364
|
console.warn(
|
|
3026
3365
|
`WebSocket disconnected with code ${code}. Attempting to reconnect...`
|
|
3027
3366
|
);
|
|
@@ -3029,7 +3368,7 @@ var WebSocketClient = class extends import_events5.EventEmitter {
|
|
|
3029
3368
|
this.reconnect(this.lastWsUrl);
|
|
3030
3369
|
}
|
|
3031
3370
|
});
|
|
3032
|
-
this.ws.
|
|
3371
|
+
this.ws.once("error", (err) => {
|
|
3033
3372
|
console.error("WebSocket error:", err.message);
|
|
3034
3373
|
if (!this.isReconnecting) {
|
|
3035
3374
|
this.reconnect(this.lastWsUrl);
|
|
@@ -3042,6 +3381,34 @@ var WebSocketClient = class extends import_events5.EventEmitter {
|
|
|
3042
3381
|
});
|
|
3043
3382
|
}, this.backOffOptions);
|
|
3044
3383
|
}
|
|
3384
|
+
getEventKey(event) {
|
|
3385
|
+
const ids = [];
|
|
3386
|
+
if ("channel" in event && event.channel?.id) ids.push(event.channel.id);
|
|
3387
|
+
if ("playback" in event && event.playback?.id) ids.push(event.playback.id);
|
|
3388
|
+
if ("bridge" in event && event.bridge?.id) ids.push(event.bridge.id);
|
|
3389
|
+
return `${event.type}-${ids.join("-")}`;
|
|
3390
|
+
}
|
|
3391
|
+
processEvent(event) {
|
|
3392
|
+
if (this.subscribedEvents?.length && !this.subscribedEvents.includes(event.type)) {
|
|
3393
|
+
return;
|
|
3394
|
+
}
|
|
3395
|
+
if ("channel" in event && event.channel?.id && this.ariClient) {
|
|
3396
|
+
const instanceChannel = this.ariClient.Channel(event.channel.id);
|
|
3397
|
+
instanceChannel.emitEvent(event);
|
|
3398
|
+
event.instanceChannel = instanceChannel;
|
|
3399
|
+
}
|
|
3400
|
+
if ("playback" in event && event.playback?.id && this.ariClient) {
|
|
3401
|
+
const instancePlayback = this.ariClient.Playback(event.playback.id);
|
|
3402
|
+
instancePlayback.emitEvent(event);
|
|
3403
|
+
event.instancePlayback = instancePlayback;
|
|
3404
|
+
}
|
|
3405
|
+
if ("bridge" in event && event.bridge?.id && this.ariClient) {
|
|
3406
|
+
const instanceBridge = this.ariClient.Bridge(event.bridge.id);
|
|
3407
|
+
instanceBridge.emitEvent(event);
|
|
3408
|
+
event.instanceBridge = instanceBridge;
|
|
3409
|
+
}
|
|
3410
|
+
this.emit(event.type, event);
|
|
3411
|
+
}
|
|
3045
3412
|
/**
|
|
3046
3413
|
* Handles incoming WebSocket messages by parsing and processing events.
|
|
3047
3414
|
*
|
|
@@ -3057,30 +3424,20 @@ var WebSocketClient = class extends import_events5.EventEmitter {
|
|
|
3057
3424
|
handleMessage(rawMessage) {
|
|
3058
3425
|
try {
|
|
3059
3426
|
const event = JSON.parse(rawMessage);
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
const instanceChannel = this.ariClient.Channel(event.channel.id);
|
|
3065
|
-
instanceChannel.emitEvent(event);
|
|
3066
|
-
event.instanceChannel = instanceChannel;
|
|
3067
|
-
}
|
|
3068
|
-
if ("playback" in event && event.playback?.id && this.ariClient) {
|
|
3069
|
-
const instancePlayback = this.ariClient.Playback(event.playback.id);
|
|
3070
|
-
instancePlayback.emitEvent(event);
|
|
3071
|
-
event.instancePlayback = instancePlayback;
|
|
3072
|
-
}
|
|
3073
|
-
if ("bridge" in event && event.bridge?.id && this.ariClient) {
|
|
3074
|
-
const instanceBridge = this.ariClient.Bridge(event.bridge.id);
|
|
3075
|
-
instanceBridge.emitEvent(event);
|
|
3076
|
-
event.instanceBridge = instanceBridge;
|
|
3427
|
+
const key = this.getEventKey(event);
|
|
3428
|
+
const existing = this.eventQueue.get(key);
|
|
3429
|
+
if (existing) {
|
|
3430
|
+
clearTimeout(existing);
|
|
3077
3431
|
}
|
|
3078
|
-
this.
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3432
|
+
this.eventQueue.set(
|
|
3433
|
+
key,
|
|
3434
|
+
setTimeout(() => {
|
|
3435
|
+
this.processEvent(event);
|
|
3436
|
+
this.eventQueue.delete(key);
|
|
3437
|
+
}, 100)
|
|
3083
3438
|
);
|
|
3439
|
+
} catch (error) {
|
|
3440
|
+
console.error("Error processing WebSocket message:", error);
|
|
3084
3441
|
this.emit("error", new Error("Failed to decode WebSocket message"));
|
|
3085
3442
|
}
|
|
3086
3443
|
}
|
|
@@ -3096,21 +3453,26 @@ var WebSocketClient = class extends import_events5.EventEmitter {
|
|
|
3096
3453
|
*
|
|
3097
3454
|
* @emits reconnectFailed - Emitted if all reconnection attempts fail.
|
|
3098
3455
|
*/
|
|
3099
|
-
reconnect(wsUrl) {
|
|
3456
|
+
async reconnect(wsUrl) {
|
|
3457
|
+
if (!this.shouldReconnect) {
|
|
3458
|
+
console.warn(
|
|
3459
|
+
"Reconnection skipped because WebSocket was intentionally closed."
|
|
3460
|
+
);
|
|
3461
|
+
return;
|
|
3462
|
+
}
|
|
3463
|
+
if (this.isReconnecting) {
|
|
3464
|
+
console.warn("J\xE1 h\xE1 uma tentativa de reconex\xE3o em andamento.");
|
|
3465
|
+
return;
|
|
3466
|
+
}
|
|
3100
3467
|
this.isReconnecting = true;
|
|
3101
3468
|
this.reconnectionAttempts++;
|
|
3102
|
-
console.log(
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
3110
|
-
);
|
|
3111
|
-
this.emit("reconnectFailed", error);
|
|
3112
|
-
}
|
|
3113
|
-
);
|
|
3469
|
+
console.log(`Tentando reconex\xE3o #${this.reconnectionAttempts}...`);
|
|
3470
|
+
(0, import_exponential_backoff.backOff)(() => this.initializeWebSocket(wsUrl), this.backOffOptions).catch((error) => {
|
|
3471
|
+
console.error(`Falha ao reconectar: ${error.message}`);
|
|
3472
|
+
this.emit("reconnectFailed", error);
|
|
3473
|
+
}).finally(() => {
|
|
3474
|
+
this.isReconnecting = false;
|
|
3475
|
+
});
|
|
3114
3476
|
}
|
|
3115
3477
|
/**
|
|
3116
3478
|
* Closes the WebSocket connection if it exists.
|
|
@@ -3121,18 +3483,34 @@ var WebSocketClient = class extends import_events5.EventEmitter {
|
|
|
3121
3483
|
*
|
|
3122
3484
|
* @throws {Error} Logs an error message if closing the WebSocket fails.
|
|
3123
3485
|
*/
|
|
3124
|
-
close() {
|
|
3486
|
+
async close() {
|
|
3487
|
+
if (!this.ws) {
|
|
3488
|
+
console.warn("No WebSocket connection to close");
|
|
3489
|
+
return;
|
|
3490
|
+
}
|
|
3491
|
+
console.log("Closing WebSocket connection.");
|
|
3492
|
+
this.shouldReconnect = false;
|
|
3493
|
+
this.eventQueue.forEach((timeout) => clearTimeout(timeout));
|
|
3494
|
+
this.eventQueue.clear();
|
|
3495
|
+
const closeTimeout = setTimeout(() => {
|
|
3496
|
+
if (this.ws && this.ws.readyState !== import_ws.default.CLOSED) {
|
|
3497
|
+
this.ws.terminate();
|
|
3498
|
+
}
|
|
3499
|
+
}, 5e3);
|
|
3125
3500
|
try {
|
|
3126
|
-
|
|
3501
|
+
this.ws.removeAllListeners();
|
|
3502
|
+
await new Promise((resolve) => {
|
|
3503
|
+
this.ws.once("close", () => {
|
|
3504
|
+
clearTimeout(closeTimeout);
|
|
3505
|
+
resolve();
|
|
3506
|
+
});
|
|
3127
3507
|
this.ws.close();
|
|
3128
|
-
|
|
3129
|
-
console.log("WebSocket connection closed");
|
|
3130
|
-
}
|
|
3508
|
+
});
|
|
3131
3509
|
} catch (error) {
|
|
3132
|
-
console.error(
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
);
|
|
3510
|
+
console.error("Error closing WebSocket:", error);
|
|
3511
|
+
} finally {
|
|
3512
|
+
this.ws = void 0;
|
|
3513
|
+
this.emit("disconnected");
|
|
3136
3514
|
}
|
|
3137
3515
|
}
|
|
3138
3516
|
/**
|
|
@@ -3164,6 +3542,30 @@ var WebSocketClient = class extends import_events5.EventEmitter {
|
|
|
3164
3542
|
getState() {
|
|
3165
3543
|
return this.ws?.readyState ?? import_ws.default.CLOSED;
|
|
3166
3544
|
}
|
|
3545
|
+
/**
|
|
3546
|
+
* Cleans up the WebSocketClient instance, resetting its state and clearing resources.
|
|
3547
|
+
*
|
|
3548
|
+
* This method performs the following cleanup operations:
|
|
3549
|
+
* - Clears the event queue and cancels any pending timeouts.
|
|
3550
|
+
* - Stops any ongoing reconnection attempts.
|
|
3551
|
+
* - Clears the stored WebSocket URL.
|
|
3552
|
+
* - Resets the reconnection attempt counter.
|
|
3553
|
+
* - Removes all event listeners attached to this instance.
|
|
3554
|
+
*
|
|
3555
|
+
* This method is typically called when the WebSocketClient is no longer needed or
|
|
3556
|
+
* before reinitializing the client to ensure a clean slate.
|
|
3557
|
+
*
|
|
3558
|
+
* @returns {void} This method doesn't return a value.
|
|
3559
|
+
*/
|
|
3560
|
+
cleanup() {
|
|
3561
|
+
this.eventQueue.forEach((timeout) => clearTimeout(timeout));
|
|
3562
|
+
this.eventQueue.clear();
|
|
3563
|
+
this.shouldReconnect = false;
|
|
3564
|
+
this.isReconnecting = false;
|
|
3565
|
+
this.lastWsUrl = "";
|
|
3566
|
+
this.reconnectionAttempts = 0;
|
|
3567
|
+
this.removeAllListeners();
|
|
3568
|
+
}
|
|
3167
3569
|
};
|
|
3168
3570
|
|
|
3169
3571
|
// src/ari-client/ariClient.ts
|
|
@@ -3194,6 +3596,8 @@ var AriClient = class {
|
|
|
3194
3596
|
}
|
|
3195
3597
|
baseClient;
|
|
3196
3598
|
webSocketClient;
|
|
3599
|
+
eventListeners = /* @__PURE__ */ new Map();
|
|
3600
|
+
// Armazena os listeners para limpeza
|
|
3197
3601
|
channels;
|
|
3198
3602
|
endpoints;
|
|
3199
3603
|
applications;
|
|
@@ -3201,6 +3605,50 @@ var AriClient = class {
|
|
|
3201
3605
|
sounds;
|
|
3202
3606
|
asterisk;
|
|
3203
3607
|
bridges;
|
|
3608
|
+
async cleanup() {
|
|
3609
|
+
try {
|
|
3610
|
+
console.log("Starting ARI Client cleanup...");
|
|
3611
|
+
if (this.webSocketClient) {
|
|
3612
|
+
await this.closeWebSocket();
|
|
3613
|
+
}
|
|
3614
|
+
await Promise.all([
|
|
3615
|
+
// Cleanup de channels
|
|
3616
|
+
(async () => {
|
|
3617
|
+
try {
|
|
3618
|
+
this.channels.cleanup();
|
|
3619
|
+
} catch (error) {
|
|
3620
|
+
console.error("Error cleaning up channels:", error);
|
|
3621
|
+
}
|
|
3622
|
+
})(),
|
|
3623
|
+
// Cleanup de playbacks
|
|
3624
|
+
(async () => {
|
|
3625
|
+
try {
|
|
3626
|
+
this.playbacks.cleanup();
|
|
3627
|
+
} catch (error) {
|
|
3628
|
+
console.error("Error cleaning up playbacks:", error);
|
|
3629
|
+
}
|
|
3630
|
+
})(),
|
|
3631
|
+
// Cleanup de bridges
|
|
3632
|
+
(async () => {
|
|
3633
|
+
try {
|
|
3634
|
+
this.bridges.cleanup();
|
|
3635
|
+
} catch (error) {
|
|
3636
|
+
console.error("Error cleaning up bridges:", error);
|
|
3637
|
+
}
|
|
3638
|
+
})()
|
|
3639
|
+
]);
|
|
3640
|
+
this.eventListeners.forEach((listeners, event) => {
|
|
3641
|
+
listeners.forEach((listener) => {
|
|
3642
|
+
this.off(event, listener);
|
|
3643
|
+
});
|
|
3644
|
+
});
|
|
3645
|
+
this.eventListeners.clear();
|
|
3646
|
+
console.log("ARI Client cleanup completed successfully");
|
|
3647
|
+
} catch (error) {
|
|
3648
|
+
console.error("Error during ARI Client cleanup:", error);
|
|
3649
|
+
throw error;
|
|
3650
|
+
}
|
|
3651
|
+
}
|
|
3204
3652
|
/**
|
|
3205
3653
|
* Initializes a WebSocket connection for receiving events.
|
|
3206
3654
|
*
|
|
@@ -3210,14 +3658,14 @@ var AriClient = class {
|
|
|
3210
3658
|
* @throws {Error} If connection fails or if WebSocket is already connected
|
|
3211
3659
|
*/
|
|
3212
3660
|
async connectWebSocket(apps, subscribedEvents) {
|
|
3213
|
-
if (!apps.length) {
|
|
3214
|
-
throw new Error("At least one application name is required");
|
|
3215
|
-
}
|
|
3216
|
-
if (this.webSocketClient) {
|
|
3217
|
-
console.warn("WebSocket is already connected");
|
|
3218
|
-
return;
|
|
3219
|
-
}
|
|
3220
3661
|
try {
|
|
3662
|
+
if (!apps.length) {
|
|
3663
|
+
throw new Error("At least one application name is required.");
|
|
3664
|
+
}
|
|
3665
|
+
if (this.webSocketClient) {
|
|
3666
|
+
await this.closeWebSocket();
|
|
3667
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
3668
|
+
}
|
|
3221
3669
|
this.webSocketClient = new WebSocketClient(
|
|
3222
3670
|
this.baseClient,
|
|
3223
3671
|
apps,
|
|
@@ -3225,13 +3673,38 @@ var AriClient = class {
|
|
|
3225
3673
|
this
|
|
3226
3674
|
);
|
|
3227
3675
|
await this.webSocketClient.connect();
|
|
3228
|
-
console.log("WebSocket connection established successfully");
|
|
3676
|
+
console.log("WebSocket connection established successfully.");
|
|
3229
3677
|
} catch (error) {
|
|
3230
3678
|
console.error("Failed to establish WebSocket connection:", error);
|
|
3231
3679
|
this.webSocketClient = void 0;
|
|
3232
3680
|
throw error;
|
|
3233
3681
|
}
|
|
3234
3682
|
}
|
|
3683
|
+
/**
|
|
3684
|
+
* Destroys the ARI Client instance, cleaning up all resources and removing circular references.
|
|
3685
|
+
* This method should be called when the ARI Client is no longer needed to ensure proper cleanup.
|
|
3686
|
+
*
|
|
3687
|
+
* @returns {Promise<void>} A promise that resolves when the destruction process is complete.
|
|
3688
|
+
* @throws {Error} If an error occurs during the destruction process.
|
|
3689
|
+
*/
|
|
3690
|
+
async destroy() {
|
|
3691
|
+
try {
|
|
3692
|
+
console.log("Destroying ARI Client...");
|
|
3693
|
+
await this.cleanup();
|
|
3694
|
+
this.webSocketClient = void 0;
|
|
3695
|
+
this.channels = null;
|
|
3696
|
+
this.playbacks = null;
|
|
3697
|
+
this.bridges = null;
|
|
3698
|
+
this.endpoints = null;
|
|
3699
|
+
this.applications = null;
|
|
3700
|
+
this.sounds = null;
|
|
3701
|
+
this.asterisk = null;
|
|
3702
|
+
console.log("ARI Client destroyed successfully");
|
|
3703
|
+
} catch (error) {
|
|
3704
|
+
console.error("Error destroying ARI Client:", error);
|
|
3705
|
+
throw error;
|
|
3706
|
+
}
|
|
3707
|
+
}
|
|
3235
3708
|
/**
|
|
3236
3709
|
* Registers an event listener for WebSocket events.
|
|
3237
3710
|
*
|
|
@@ -3243,8 +3716,15 @@ var AriClient = class {
|
|
|
3243
3716
|
if (!this.webSocketClient) {
|
|
3244
3717
|
throw new Error("WebSocket is not connected");
|
|
3245
3718
|
}
|
|
3719
|
+
const existingListeners = this.eventListeners.get(event) || [];
|
|
3720
|
+
if (existingListeners.includes(listener)) {
|
|
3721
|
+
console.warn(`Listener already registered for event ${event}, reusing.`);
|
|
3722
|
+
return;
|
|
3723
|
+
}
|
|
3246
3724
|
this.webSocketClient.on(event, listener);
|
|
3247
|
-
|
|
3725
|
+
existingListeners.push(listener);
|
|
3726
|
+
this.eventListeners.set(event, existingListeners);
|
|
3727
|
+
console.log(`Event listener successfully registered for ${event}`);
|
|
3248
3728
|
}
|
|
3249
3729
|
/**
|
|
3250
3730
|
* Registers a one-time event listener for WebSocket events.
|
|
@@ -3257,7 +3737,19 @@ var AriClient = class {
|
|
|
3257
3737
|
if (!this.webSocketClient) {
|
|
3258
3738
|
throw new Error("WebSocket is not connected");
|
|
3259
3739
|
}
|
|
3260
|
-
this.
|
|
3740
|
+
const existingListeners = this.eventListeners.get(event) || [];
|
|
3741
|
+
if (existingListeners.includes(listener)) {
|
|
3742
|
+
console.warn(
|
|
3743
|
+
`One-time listener already registered for event ${event}, reusing.`
|
|
3744
|
+
);
|
|
3745
|
+
return;
|
|
3746
|
+
}
|
|
3747
|
+
const wrappedListener = (data) => {
|
|
3748
|
+
listener(data);
|
|
3749
|
+
this.off(event, wrappedListener);
|
|
3750
|
+
};
|
|
3751
|
+
this.webSocketClient.once(event, wrappedListener);
|
|
3752
|
+
this.eventListeners.set(event, [...existingListeners, wrappedListener]);
|
|
3261
3753
|
console.log(`One-time event listener registered for ${event}`);
|
|
3262
3754
|
}
|
|
3263
3755
|
/**
|
|
@@ -3272,19 +3764,57 @@ var AriClient = class {
|
|
|
3272
3764
|
return;
|
|
3273
3765
|
}
|
|
3274
3766
|
this.webSocketClient.off(event, listener);
|
|
3767
|
+
const existingListeners = this.eventListeners.get(event) || [];
|
|
3768
|
+
this.eventListeners.set(
|
|
3769
|
+
event,
|
|
3770
|
+
existingListeners.filter((l) => l !== listener)
|
|
3771
|
+
);
|
|
3275
3772
|
console.log(`Event listener removed for ${event}`);
|
|
3276
3773
|
}
|
|
3277
3774
|
/**
|
|
3278
3775
|
* Closes the WebSocket connection if one exists.
|
|
3279
3776
|
*/
|
|
3280
3777
|
closeWebSocket() {
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3778
|
+
return new Promise((resolve) => {
|
|
3779
|
+
if (!this.webSocketClient) {
|
|
3780
|
+
console.warn("No WebSocket connection to close");
|
|
3781
|
+
resolve();
|
|
3782
|
+
return;
|
|
3783
|
+
}
|
|
3784
|
+
console.log("Closing WebSocket connection and cleaning up listeners.");
|
|
3785
|
+
const closeTimeout = setTimeout(() => {
|
|
3786
|
+
if (this.webSocketClient) {
|
|
3787
|
+
this.webSocketClient.removeAllListeners();
|
|
3788
|
+
this.webSocketClient = void 0;
|
|
3789
|
+
}
|
|
3790
|
+
resolve();
|
|
3791
|
+
}, 5e3);
|
|
3792
|
+
this.eventListeners.forEach((listeners, event) => {
|
|
3793
|
+
listeners.forEach((listener) => {
|
|
3794
|
+
this.webSocketClient?.off(
|
|
3795
|
+
event,
|
|
3796
|
+
listener
|
|
3797
|
+
);
|
|
3798
|
+
});
|
|
3799
|
+
});
|
|
3800
|
+
this.eventListeners.clear();
|
|
3801
|
+
this.webSocketClient.once("close", () => {
|
|
3802
|
+
clearTimeout(closeTimeout);
|
|
3803
|
+
this.webSocketClient = void 0;
|
|
3804
|
+
console.log("WebSocket connection closed");
|
|
3805
|
+
resolve();
|
|
3806
|
+
});
|
|
3807
|
+
this.webSocketClient.close().then(() => {
|
|
3808
|
+
clearTimeout(closeTimeout);
|
|
3809
|
+
this.webSocketClient = void 0;
|
|
3810
|
+
resolve();
|
|
3811
|
+
}).catch((error) => {
|
|
3812
|
+
console.error("Error during WebSocket close:", error);
|
|
3813
|
+
clearTimeout(closeTimeout);
|
|
3814
|
+
this.webSocketClient = void 0;
|
|
3815
|
+
resolve();
|
|
3816
|
+
});
|
|
3817
|
+
});
|
|
3288
3818
|
}
|
|
3289
3819
|
/**
|
|
3290
3820
|
* Creates or retrieves a Channel instance.
|
|
@@ -3325,7 +3855,7 @@ var AriClient = class {
|
|
|
3325
3855
|
* @returns {boolean} True if WebSocket is connected, false otherwise
|
|
3326
3856
|
*/
|
|
3327
3857
|
isWebSocketConnected() {
|
|
3328
|
-
return !!this.webSocketClient;
|
|
3858
|
+
return !!this.webSocketClient && this.webSocketClient.isConnected();
|
|
3329
3859
|
}
|
|
3330
3860
|
};
|
|
3331
3861
|
// Annotate the CommonJS export names for ESM import in node:
|