@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/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
- wsClient = null;
1684
+ wsClients = /* @__PURE__ */ new Map();
1685
+ // Map para armazenar conexões por app
1685
1686
  baseClient;
1686
- isReconnecting = false;
1687
- isWebSocketConnectedFlag = false;
1688
- webSocketReady = null;
1689
- // Promise para rastrear o estado do WebSocket
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 (!this.wsClient || !this.isWebSocketConnectedFlag) {
1694
+ if (this.wsClients.size === 0) {
1694
1695
  console.warn(
1695
- "WebSocket ainda n\xE3o est\xE1 pronto. N\xE3o \xE9 poss\xEDvel processar a fila."
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.wsClient.on(event, callback);
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.wsClient?.on(eventType, callback);
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 no AriClient para evento: ${eventType}`);
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
- async connectWebSocket(app, subscribedEvents) {
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("J\xE1 existe uma tentativa de conex\xE3o ativa. Aguardando...");
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
- this.webSocketReady = new Promise(async (resolve, reject) => {
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 = true;
1811
- const eventsParam = subscribedEvents && subscribedEvents.length > 0 ? `&event=${subscribedEvents.join(",")}` : "&subscribeAll=true";
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 (!this.wsClient) {
1864
+ if (!wsClient) {
1834
1865
  throw new Error("WebSocketClient instance is null.");
1835
1866
  }
1836
- await this.wsClient.connect();
1837
- this.integrateWebSocketEvents(app, this.wsClient);
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.isWebSocketConnectedFlag = true;
1841
- this.processPendingListeners();
1871
+ this.wsClients.set(app, wsClient);
1842
1872
  }, backoffOptions);
1843
1873
  resolve();
1844
- } catch (err) {
1874
+ } catch (error) {
1845
1875
  console.error(
1846
- "N\xE3o foi poss\xEDvel conectar ao WebSocket ap\xF3s m\xFAltiplas tentativas:",
1847
- err
1876
+ `Erro ao conectar o WebSocket para o app '${app}':`,
1877
+ error
1848
1878
  );
1849
- reject(err);
1879
+ reject(error);
1850
1880
  } finally {
1851
- this.isReconnecting = false;
1852
- this.webSocketReady = null;
1881
+ this.isReconnecting.delete(app);
1853
1882
  }
1854
1883
  });
1855
- return this.webSocketReady;
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
- isWebSocketConnected() {
1928
- return this.wsClient ? this.wsClient.isConnected() : false;
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
- if (this.wsClient) {
1942
- this.wsClient.close();
1943
- this.wsClient = null;
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
  *