@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.
@@ -1703,18 +1703,19 @@ var AriClient = class {
1703
1703
  this.bridges = new Bridges(this.baseClient);
1704
1704
  }
1705
1705
  eventListeners = /* @__PURE__ */ new Map();
1706
- wsClient = null;
1706
+ wsClients = /* @__PURE__ */ new Map();
1707
+ // Map para armazenar conexões por app
1707
1708
  baseClient;
1708
- isReconnecting = false;
1709
- isWebSocketConnectedFlag = false;
1710
- webSocketReady = null;
1711
- // Promise para rastrear o estado do WebSocket
1709
+ isReconnecting = /* @__PURE__ */ new Map();
1710
+ // Estado de reconexão por app
1711
+ webSocketReady = /* @__PURE__ */ new Map();
1712
+ // Rastreamento do estado de cada conexão
1712
1713
  channelInstances = /* @__PURE__ */ new Map();
1713
1714
  pendingListeners = [];
1714
1715
  processPendingListeners() {
1715
- if (!this.wsClient || !this.isWebSocketConnectedFlag) {
1716
+ if (this.wsClients.size === 0) {
1716
1717
  console.warn(
1717
- "WebSocket ainda n\xE3o est\xE1 pronto. N\xE3o \xE9 poss\xEDvel processar a fila."
1718
+ "Nenhuma conex\xE3o WebSocket est\xE1 pronta. N\xE3o \xE9 poss\xEDvel processar a fila."
1718
1719
  );
1719
1720
  return;
1720
1721
  }
@@ -1724,7 +1725,12 @@ var AriClient = class {
1724
1725
  while (this.pendingListeners.length > 0) {
1725
1726
  const { event, callback } = this.pendingListeners.shift();
1726
1727
  console.log(`Registrando listener pendente para evento: ${event}`);
1727
- this.wsClient.on(event, callback);
1728
+ for (const [app, wsClient] of this.wsClients.entries()) {
1729
+ console.log(
1730
+ `Registrando listener no app '${app}' para evento: ${event}`
1731
+ );
1732
+ wsClient.on(event, callback);
1733
+ }
1728
1734
  }
1729
1735
  }
1730
1736
  channels;
@@ -1740,14 +1746,24 @@ var AriClient = class {
1740
1746
  * @param callback Callback a ser executado quando o evento for recebido.
1741
1747
  */
1742
1748
  onChannelEvent(eventType, callback) {
1743
- this.wsClient?.on(eventType, callback);
1749
+ if (this.wsClients.size === 0) {
1750
+ console.warn(
1751
+ "Nenhuma conex\xE3o WebSocket est\xE1 ativa. O listener ser\xE1 pendente."
1752
+ );
1753
+ this.pendingListeners.push({ event: eventType, callback });
1754
+ return;
1755
+ }
1756
+ for (const [app, wsClient] of this.wsClients.entries()) {
1757
+ console.log(`Registrando evento '${eventType}' no app '${app}'`);
1758
+ wsClient.on(eventType, callback);
1759
+ }
1744
1760
  }
1745
1761
  /**
1746
1762
  * Registra um listener para eventos globais de WebSocket.
1747
1763
  * O channel no evento será automaticamente transformado em uma instância de ChannelInstance.
1748
1764
  */
1749
1765
  on(eventType, callback) {
1750
- console.log(`Registrando listener no AriClient para evento: ${eventType}`);
1766
+ console.log(`Registrando listener global para evento: ${eventType}`);
1751
1767
  const wrappedCallback = (event) => {
1752
1768
  if (isChannelEvent(event)) {
1753
1769
  const channelId = event.channel.id;
@@ -1811,70 +1827,84 @@ var AriClient = class {
1811
1827
  * @returns A Promise that resolves when the WebSocket connection is successfully established and the application is registered.
1812
1828
  * @throws Error if the 'app' parameter is not provided, or if connection attempts fail after multiple retries.
1813
1829
  */
1814
- async connectWebSocket(app, subscribedEvents) {
1830
+ /**
1831
+ * Connects to the ARI WebSocket for one or more applications.
1832
+ * Establishes a WebSocket connection for each app and subscribes to events.
1833
+ *
1834
+ * @param apps - Array of application names to connect to.
1835
+ * @param subscribedEvents - Optional array of events to subscribe to.
1836
+ * If not provided or empty, subscribes to all events.
1837
+ * @returns A Promise that resolves when all connections are established.
1838
+ */
1839
+ async connectWebSocket(apps, subscribedEvents) {
1840
+ if (!Array.isArray(apps) || apps.length === 0) {
1841
+ throw new Error("\xC9 necess\xE1rio fornecer pelo menos um aplicativo.");
1842
+ }
1843
+ return Promise.all(
1844
+ apps.map((app) => this.connectSingleWebSocket(app, subscribedEvents))
1845
+ );
1846
+ }
1847
+ /**
1848
+ * Establishes a single WebSocket connection for a given app.
1849
+ */
1850
+ async connectSingleWebSocket(app, subscribedEvents) {
1815
1851
  if (!app) {
1816
- throw new Error(
1817
- "O par\xE2metro 'app' \xE9 obrigat\xF3rio para conectar ao WebSocket."
1818
- );
1852
+ throw new Error("O nome do aplicativo \xE9 obrigat\xF3rio.");
1819
1853
  }
1820
- if (this.webSocketReady) {
1821
- console.log("J\xE1 existe uma tentativa de conex\xE3o ativa. Aguardando...");
1822
- return this.webSocketReady;
1854
+ if (this.webSocketReady.get(app)) {
1855
+ console.log(`Conex\xE3o WebSocket para '${app}' j\xE1 est\xE1 ativa.`);
1856
+ return this.webSocketReady.get(app);
1823
1857
  }
1824
- this.webSocketReady = new Promise(async (resolve, reject) => {
1858
+ const protocol = this.config.secure ? "wss" : "ws";
1859
+ const eventsParam = subscribedEvents && subscribedEvents.length > 0 ? `&event=${subscribedEvents.join(",")}` : "&subscribeAll=true";
1860
+ const wsUrl = `${protocol}://${encodeURIComponent(
1861
+ this.config.username
1862
+ )}:${encodeURIComponent(this.config.password)}@${this.config.host}:${this.config.port}/ari/events?app=${app}${eventsParam}`;
1863
+ const backoffOptions = {
1864
+ delayFirstAttempt: false,
1865
+ startingDelay: 1e3,
1866
+ timeMultiple: 2,
1867
+ maxDelay: 3e4,
1868
+ numOfAttempts: 10,
1869
+ jitter: "full",
1870
+ retry: (error, attemptNumber) => {
1871
+ console.warn(`Tentativa ${attemptNumber} falhou: ${error.message}`);
1872
+ return Array.from(this.wsClients.values()).some(
1873
+ (wsClient) => !wsClient.isConnected()
1874
+ );
1875
+ }
1876
+ };
1877
+ const webSocketPromise = new Promise(async (resolve, reject) => {
1825
1878
  try {
1826
- if (this.isReconnecting) {
1827
- console.warn(
1828
- "J\xE1 est\xE1 tentando reconectar. Ignorando esta tentativa."
1829
- );
1879
+ if (this.isReconnecting.get(app)) {
1880
+ console.warn(`J\xE1 est\xE1 tentando reconectar para o app '${app}'.`);
1830
1881
  return;
1831
1882
  }
1832
- this.isReconnecting = true;
1833
- const eventsParam = subscribedEvents && subscribedEvents.length > 0 ? `&event=${subscribedEvents.join(",")}` : "&subscribeAll=true";
1834
- const protocol = this.config.secure ? "wss" : "ws";
1835
- const wsUrl = `${protocol}://${encodeURIComponent(this.config.username)}:${encodeURIComponent(this.config.password)}@${this.config.host}:${this.config.port}/ari/events?app=${app}${eventsParam}`;
1836
- const backoffOptions = {
1837
- delayFirstAttempt: false,
1838
- startingDelay: 1e3,
1839
- timeMultiple: 2,
1840
- maxDelay: 3e4,
1841
- numOfAttempts: 10,
1842
- jitter: "full",
1843
- retry: (error, attemptNumber) => {
1844
- console.warn(`Tentativa ${attemptNumber} falhou: ${error.message}`);
1845
- return !this.wsClient?.isConnected();
1846
- }
1847
- };
1848
- if (this.wsClient?.isConnected()) {
1849
- console.log("WebSocket j\xE1 conectado. Removendo listeners antigos...");
1850
- this.wsClient.removeAllListeners();
1851
- this.wsClient.close();
1852
- }
1853
- this.wsClient = new WebSocketClient(wsUrl);
1883
+ this.isReconnecting.set(app, true);
1884
+ const wsClient = new WebSocketClient(wsUrl);
1854
1885
  await (0, import_exponential_backoff.backOff)(async () => {
1855
- if (!this.wsClient) {
1886
+ if (!wsClient) {
1856
1887
  throw new Error("WebSocketClient instance is null.");
1857
1888
  }
1858
- await this.wsClient.connect();
1859
- this.integrateWebSocketEvents(app, this.wsClient);
1889
+ await wsClient.connect();
1890
+ this.integrateWebSocketEvents(app, wsClient);
1860
1891
  console.log(`WebSocket conectado para o app: ${app}`);
1861
1892
  await this.ensureAppRegistered(app);
1862
- this.isWebSocketConnectedFlag = true;
1863
- this.processPendingListeners();
1893
+ this.wsClients.set(app, wsClient);
1864
1894
  }, backoffOptions);
1865
1895
  resolve();
1866
- } catch (err) {
1896
+ } catch (error) {
1867
1897
  console.error(
1868
- "N\xE3o foi poss\xEDvel conectar ao WebSocket ap\xF3s m\xFAltiplas tentativas:",
1869
- err
1898
+ `Erro ao conectar o WebSocket para o app '${app}':`,
1899
+ error
1870
1900
  );
1871
- reject(err);
1901
+ reject(error);
1872
1902
  } finally {
1873
- this.isReconnecting = false;
1874
- this.webSocketReady = null;
1903
+ this.isReconnecting.delete(app);
1875
1904
  }
1876
1905
  });
1877
- return this.webSocketReady;
1906
+ this.webSocketReady.set(app, webSocketPromise);
1907
+ return webSocketPromise;
1878
1908
  }
1879
1909
  /**
1880
1910
  * Integrates WebSocket events with playback listeners.
@@ -1946,8 +1976,14 @@ var AriClient = class {
1946
1976
  *
1947
1977
  * @returns {boolean} True if connected, false otherwise.
1948
1978
  */
1949
- isWebSocketConnected() {
1950
- return this.wsClient ? this.wsClient.isConnected() : false;
1979
+ anyWebSocketConnected() {
1980
+ return Array.from(this.wsClients.values()).every(
1981
+ (wsClient) => wsClient.isConnected()
1982
+ );
1983
+ }
1984
+ isWebSocketConnected(app) {
1985
+ const wsClient = this.wsClients.get(app);
1986
+ return wsClient ? wsClient.isConnected() : false;
1951
1987
  }
1952
1988
  /**
1953
1989
  * Closes the WebSocket connection and removes all associated listeners.
@@ -1959,12 +1995,24 @@ var AriClient = class {
1959
1995
  *
1960
1996
  * @returns {void} This function doesn't return a value.
1961
1997
  */
1962
- closeWebSocket() {
1963
- if (this.wsClient) {
1964
- this.wsClient.close();
1965
- this.wsClient = null;
1998
+ closeWebSocket(app) {
1999
+ const wsClient = this.wsClients.get(app);
2000
+ if (wsClient) {
2001
+ wsClient.close();
2002
+ this.wsClients.delete(app);
2003
+ console.log(`WebSocket para o app '${app}' foi fechado.`);
2004
+ } else {
2005
+ console.warn(`WebSocket para o app '${app}' n\xE3o encontrado.`);
1966
2006
  }
1967
2007
  }
2008
+ closeAllWebSockets() {
2009
+ this.wsClients.forEach((wsClient, app) => {
2010
+ wsClient.close();
2011
+ console.log(`WebSocket para o app '${app}' foi fechado.`);
2012
+ });
2013
+ this.wsClients.clear();
2014
+ console.log("Todos os WebSockets foram fechados.");
2015
+ }
1968
2016
  /**
1969
2017
  * Retrieves a list of active channels from the Asterisk ARI.
1970
2018
  *