@ipcom/asterisk-ari 0.0.67 → 0.0.68
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 +110 -62
- package/dist/cjs/index.cjs.map +2 -2
- package/dist/esm/index.js +110 -62
- package/dist/esm/index.js.map +2 -2
- package/dist/types/ari-client/ariClient.d.ts +20 -12
- package/dist/types/ari-client/ariClient.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/esm/index.js
CHANGED
|
@@ -1681,18 +1681,19 @@ var AriClient = class {
|
|
|
1681
1681
|
this.bridges = new Bridges(this.baseClient);
|
|
1682
1682
|
}
|
|
1683
1683
|
eventListeners = /* @__PURE__ */ new Map();
|
|
1684
|
-
|
|
1684
|
+
wsClients = /* @__PURE__ */ new Map();
|
|
1685
|
+
// Map para armazenar conexões por app
|
|
1685
1686
|
baseClient;
|
|
1686
|
-
isReconnecting =
|
|
1687
|
-
|
|
1688
|
-
webSocketReady =
|
|
1689
|
-
//
|
|
1687
|
+
isReconnecting = /* @__PURE__ */ new Map();
|
|
1688
|
+
// Estado de reconexão por app
|
|
1689
|
+
webSocketReady = /* @__PURE__ */ new Map();
|
|
1690
|
+
// Rastreamento do estado de cada conexão
|
|
1690
1691
|
channelInstances = /* @__PURE__ */ new Map();
|
|
1691
1692
|
pendingListeners = [];
|
|
1692
1693
|
processPendingListeners() {
|
|
1693
|
-
if (
|
|
1694
|
+
if (this.wsClients.size === 0) {
|
|
1694
1695
|
console.warn(
|
|
1695
|
-
"
|
|
1696
|
+
"Nenhuma conex\xE3o WebSocket est\xE1 pronta. N\xE3o \xE9 poss\xEDvel processar a fila."
|
|
1696
1697
|
);
|
|
1697
1698
|
return;
|
|
1698
1699
|
}
|
|
@@ -1702,7 +1703,12 @@ var AriClient = class {
|
|
|
1702
1703
|
while (this.pendingListeners.length > 0) {
|
|
1703
1704
|
const { event, callback } = this.pendingListeners.shift();
|
|
1704
1705
|
console.log(`Registrando listener pendente para evento: ${event}`);
|
|
1705
|
-
this.
|
|
1706
|
+
for (const [app, wsClient] of this.wsClients.entries()) {
|
|
1707
|
+
console.log(
|
|
1708
|
+
`Registrando listener no app '${app}' para evento: ${event}`
|
|
1709
|
+
);
|
|
1710
|
+
wsClient.on(event, callback);
|
|
1711
|
+
}
|
|
1706
1712
|
}
|
|
1707
1713
|
}
|
|
1708
1714
|
channels;
|
|
@@ -1718,14 +1724,24 @@ var AriClient = class {
|
|
|
1718
1724
|
* @param callback Callback a ser executado quando o evento for recebido.
|
|
1719
1725
|
*/
|
|
1720
1726
|
onChannelEvent(eventType, callback) {
|
|
1721
|
-
this.
|
|
1727
|
+
if (this.wsClients.size === 0) {
|
|
1728
|
+
console.warn(
|
|
1729
|
+
"Nenhuma conex\xE3o WebSocket est\xE1 ativa. O listener ser\xE1 pendente."
|
|
1730
|
+
);
|
|
1731
|
+
this.pendingListeners.push({ event: eventType, callback });
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1734
|
+
for (const [app, wsClient] of this.wsClients.entries()) {
|
|
1735
|
+
console.log(`Registrando evento '${eventType}' no app '${app}'`);
|
|
1736
|
+
wsClient.on(eventType, callback);
|
|
1737
|
+
}
|
|
1722
1738
|
}
|
|
1723
1739
|
/**
|
|
1724
1740
|
* Registra um listener para eventos globais de WebSocket.
|
|
1725
1741
|
* O channel no evento será automaticamente transformado em uma instância de ChannelInstance.
|
|
1726
1742
|
*/
|
|
1727
1743
|
on(eventType, callback) {
|
|
1728
|
-
console.log(`Registrando listener
|
|
1744
|
+
console.log(`Registrando listener global para evento: ${eventType}`);
|
|
1729
1745
|
const wrappedCallback = (event) => {
|
|
1730
1746
|
if (isChannelEvent(event)) {
|
|
1731
1747
|
const channelId = event.channel.id;
|
|
@@ -1789,70 +1805,84 @@ var AriClient = class {
|
|
|
1789
1805
|
* @returns A Promise that resolves when the WebSocket connection is successfully established and the application is registered.
|
|
1790
1806
|
* @throws Error if the 'app' parameter is not provided, or if connection attempts fail after multiple retries.
|
|
1791
1807
|
*/
|
|
1792
|
-
|
|
1808
|
+
/**
|
|
1809
|
+
* Connects to the ARI WebSocket for one or more applications.
|
|
1810
|
+
* Establishes a WebSocket connection for each app and subscribes to events.
|
|
1811
|
+
*
|
|
1812
|
+
* @param apps - Array of application names to connect to.
|
|
1813
|
+
* @param subscribedEvents - Optional array of events to subscribe to.
|
|
1814
|
+
* If not provided or empty, subscribes to all events.
|
|
1815
|
+
* @returns A Promise that resolves when all connections are established.
|
|
1816
|
+
*/
|
|
1817
|
+
async connectWebSocket(apps, subscribedEvents) {
|
|
1818
|
+
if (!Array.isArray(apps) || apps.length === 0) {
|
|
1819
|
+
throw new Error("\xC9 necess\xE1rio fornecer pelo menos um aplicativo.");
|
|
1820
|
+
}
|
|
1821
|
+
return Promise.all(
|
|
1822
|
+
apps.map((app) => this.connectSingleWebSocket(app, subscribedEvents))
|
|
1823
|
+
);
|
|
1824
|
+
}
|
|
1825
|
+
/**
|
|
1826
|
+
* Establishes a single WebSocket connection for a given app.
|
|
1827
|
+
*/
|
|
1828
|
+
async connectSingleWebSocket(app, subscribedEvents) {
|
|
1793
1829
|
if (!app) {
|
|
1794
|
-
throw new Error(
|
|
1795
|
-
"O par\xE2metro 'app' \xE9 obrigat\xF3rio para conectar ao WebSocket."
|
|
1796
|
-
);
|
|
1830
|
+
throw new Error("O nome do aplicativo \xE9 obrigat\xF3rio.");
|
|
1797
1831
|
}
|
|
1798
|
-
if (this.webSocketReady) {
|
|
1799
|
-
console.log(
|
|
1800
|
-
return this.webSocketReady;
|
|
1832
|
+
if (this.webSocketReady.get(app)) {
|
|
1833
|
+
console.log(`Conex\xE3o WebSocket para '${app}' j\xE1 est\xE1 ativa.`);
|
|
1834
|
+
return this.webSocketReady.get(app);
|
|
1801
1835
|
}
|
|
1802
|
-
|
|
1836
|
+
const protocol = this.config.secure ? "wss" : "ws";
|
|
1837
|
+
const eventsParam = subscribedEvents && subscribedEvents.length > 0 ? `&event=${subscribedEvents.join(",")}` : "&subscribeAll=true";
|
|
1838
|
+
const wsUrl = `${protocol}://${encodeURIComponent(
|
|
1839
|
+
this.config.username
|
|
1840
|
+
)}:${encodeURIComponent(this.config.password)}@${this.config.host}:${this.config.port}/ari/events?app=${app}${eventsParam}`;
|
|
1841
|
+
const backoffOptions = {
|
|
1842
|
+
delayFirstAttempt: false,
|
|
1843
|
+
startingDelay: 1e3,
|
|
1844
|
+
timeMultiple: 2,
|
|
1845
|
+
maxDelay: 3e4,
|
|
1846
|
+
numOfAttempts: 10,
|
|
1847
|
+
jitter: "full",
|
|
1848
|
+
retry: (error, attemptNumber) => {
|
|
1849
|
+
console.warn(`Tentativa ${attemptNumber} falhou: ${error.message}`);
|
|
1850
|
+
return Array.from(this.wsClients.values()).some(
|
|
1851
|
+
(wsClient) => !wsClient.isConnected()
|
|
1852
|
+
);
|
|
1853
|
+
}
|
|
1854
|
+
};
|
|
1855
|
+
const webSocketPromise = new Promise(async (resolve, reject) => {
|
|
1803
1856
|
try {
|
|
1804
|
-
if (this.isReconnecting) {
|
|
1805
|
-
console.warn(
|
|
1806
|
-
"J\xE1 est\xE1 tentando reconectar. Ignorando esta tentativa."
|
|
1807
|
-
);
|
|
1857
|
+
if (this.isReconnecting.get(app)) {
|
|
1858
|
+
console.warn(`J\xE1 est\xE1 tentando reconectar para o app '${app}'.`);
|
|
1808
1859
|
return;
|
|
1809
1860
|
}
|
|
1810
|
-
this.isReconnecting
|
|
1811
|
-
const
|
|
1812
|
-
const protocol = this.config.secure ? "wss" : "ws";
|
|
1813
|
-
const wsUrl = `${protocol}://${encodeURIComponent(this.config.username)}:${encodeURIComponent(this.config.password)}@${this.config.host}:${this.config.port}/ari/events?app=${app}${eventsParam}`;
|
|
1814
|
-
const backoffOptions = {
|
|
1815
|
-
delayFirstAttempt: false,
|
|
1816
|
-
startingDelay: 1e3,
|
|
1817
|
-
timeMultiple: 2,
|
|
1818
|
-
maxDelay: 3e4,
|
|
1819
|
-
numOfAttempts: 10,
|
|
1820
|
-
jitter: "full",
|
|
1821
|
-
retry: (error, attemptNumber) => {
|
|
1822
|
-
console.warn(`Tentativa ${attemptNumber} falhou: ${error.message}`);
|
|
1823
|
-
return !this.wsClient?.isConnected();
|
|
1824
|
-
}
|
|
1825
|
-
};
|
|
1826
|
-
if (this.wsClient?.isConnected()) {
|
|
1827
|
-
console.log("WebSocket j\xE1 conectado. Removendo listeners antigos...");
|
|
1828
|
-
this.wsClient.removeAllListeners();
|
|
1829
|
-
this.wsClient.close();
|
|
1830
|
-
}
|
|
1831
|
-
this.wsClient = new WebSocketClient(wsUrl);
|
|
1861
|
+
this.isReconnecting.set(app, true);
|
|
1862
|
+
const wsClient = new WebSocketClient(wsUrl);
|
|
1832
1863
|
await (0, import_exponential_backoff.backOff)(async () => {
|
|
1833
|
-
if (!
|
|
1864
|
+
if (!wsClient) {
|
|
1834
1865
|
throw new Error("WebSocketClient instance is null.");
|
|
1835
1866
|
}
|
|
1836
|
-
await
|
|
1837
|
-
this.integrateWebSocketEvents(app,
|
|
1867
|
+
await wsClient.connect();
|
|
1868
|
+
this.integrateWebSocketEvents(app, wsClient);
|
|
1838
1869
|
console.log(`WebSocket conectado para o app: ${app}`);
|
|
1839
1870
|
await this.ensureAppRegistered(app);
|
|
1840
|
-
this.
|
|
1841
|
-
this.processPendingListeners();
|
|
1871
|
+
this.wsClients.set(app, wsClient);
|
|
1842
1872
|
}, backoffOptions);
|
|
1843
1873
|
resolve();
|
|
1844
|
-
} catch (
|
|
1874
|
+
} catch (error) {
|
|
1845
1875
|
console.error(
|
|
1846
|
-
|
|
1847
|
-
|
|
1876
|
+
`Erro ao conectar o WebSocket para o app '${app}':`,
|
|
1877
|
+
error
|
|
1848
1878
|
);
|
|
1849
|
-
reject(
|
|
1879
|
+
reject(error);
|
|
1850
1880
|
} finally {
|
|
1851
|
-
this.isReconnecting
|
|
1852
|
-
this.webSocketReady = null;
|
|
1881
|
+
this.isReconnecting.delete(app);
|
|
1853
1882
|
}
|
|
1854
1883
|
});
|
|
1855
|
-
|
|
1884
|
+
this.webSocketReady.set(app, webSocketPromise);
|
|
1885
|
+
return webSocketPromise;
|
|
1856
1886
|
}
|
|
1857
1887
|
/**
|
|
1858
1888
|
* Integrates WebSocket events with playback listeners.
|
|
@@ -1924,8 +1954,14 @@ var AriClient = class {
|
|
|
1924
1954
|
*
|
|
1925
1955
|
* @returns {boolean} True if connected, false otherwise.
|
|
1926
1956
|
*/
|
|
1927
|
-
|
|
1928
|
-
return
|
|
1957
|
+
anyWebSocketConnected() {
|
|
1958
|
+
return Array.from(this.wsClients.values()).every(
|
|
1959
|
+
(wsClient) => wsClient.isConnected()
|
|
1960
|
+
);
|
|
1961
|
+
}
|
|
1962
|
+
isWebSocketConnected(app) {
|
|
1963
|
+
const wsClient = this.wsClients.get(app);
|
|
1964
|
+
return wsClient ? wsClient.isConnected() : false;
|
|
1929
1965
|
}
|
|
1930
1966
|
/**
|
|
1931
1967
|
* Closes the WebSocket connection and removes all associated listeners.
|
|
@@ -1937,12 +1973,24 @@ var AriClient = class {
|
|
|
1937
1973
|
*
|
|
1938
1974
|
* @returns {void} This function doesn't return a value.
|
|
1939
1975
|
*/
|
|
1940
|
-
closeWebSocket() {
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1976
|
+
closeWebSocket(app) {
|
|
1977
|
+
const wsClient = this.wsClients.get(app);
|
|
1978
|
+
if (wsClient) {
|
|
1979
|
+
wsClient.close();
|
|
1980
|
+
this.wsClients.delete(app);
|
|
1981
|
+
console.log(`WebSocket para o app '${app}' foi fechado.`);
|
|
1982
|
+
} else {
|
|
1983
|
+
console.warn(`WebSocket para o app '${app}' n\xE3o encontrado.`);
|
|
1944
1984
|
}
|
|
1945
1985
|
}
|
|
1986
|
+
closeAllWebSockets() {
|
|
1987
|
+
this.wsClients.forEach((wsClient, app) => {
|
|
1988
|
+
wsClient.close();
|
|
1989
|
+
console.log(`WebSocket para o app '${app}' foi fechado.`);
|
|
1990
|
+
});
|
|
1991
|
+
this.wsClients.clear();
|
|
1992
|
+
console.log("Todos os WebSockets foram fechados.");
|
|
1993
|
+
}
|
|
1946
1994
|
/**
|
|
1947
1995
|
* Retrieves a list of active channels from the Asterisk ARI.
|
|
1948
1996
|
*
|