@ipcom/asterisk-ari 0.0.67 → 0.0.69

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