@ipcom/asterisk-ari 0.0.66 → 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
@@ -868,6 +868,7 @@ var ChannelInstance = class extends EventEmitter2 {
868
868
  this.client = client;
869
869
  this.baseClient = baseClient;
870
870
  this.channelId = channelId;
871
+ this.id = channelId || `channel-${Date.now()}`;
871
872
  this.baseClient.onWebSocketEvent((event) => {
872
873
  if (this.isChannelEvent(event) && event.channel?.id === this.channelId) {
873
874
  this.emit(event.type, event);
@@ -875,6 +876,8 @@ var ChannelInstance = class extends EventEmitter2 {
875
876
  });
876
877
  }
877
878
  channelData = null;
879
+ id;
880
+ // ID do canal
878
881
  /**
879
882
  * Verifica se o evento possui a propriedade `channel`.
880
883
  * @param event Evento recebido.
@@ -903,12 +906,6 @@ var ChannelInstance = class extends EventEmitter2 {
903
906
  super.off(event, callback);
904
907
  return this;
905
908
  }
906
- /**
907
- * Getter para o ID do canal.
908
- */
909
- get id() {
910
- return this.channelId;
911
- }
912
909
  async answer() {
913
910
  await this.baseClient.post(`/channels/${this.id}/answer`);
914
911
  }
@@ -1684,18 +1681,19 @@ var AriClient = class {
1684
1681
  this.bridges = new Bridges(this.baseClient);
1685
1682
  }
1686
1683
  eventListeners = /* @__PURE__ */ new Map();
1687
- wsClient = null;
1684
+ wsClients = /* @__PURE__ */ new Map();
1685
+ // Map para armazenar conexões por app
1688
1686
  baseClient;
1689
- isReconnecting = false;
1690
- isWebSocketConnectedFlag = false;
1691
- webSocketReady = null;
1692
- // 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
1693
1691
  channelInstances = /* @__PURE__ */ new Map();
1694
1692
  pendingListeners = [];
1695
1693
  processPendingListeners() {
1696
- if (!this.wsClient || !this.isWebSocketConnectedFlag) {
1694
+ if (this.wsClients.size === 0) {
1697
1695
  console.warn(
1698
- "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."
1699
1697
  );
1700
1698
  return;
1701
1699
  }
@@ -1705,7 +1703,12 @@ var AriClient = class {
1705
1703
  while (this.pendingListeners.length > 0) {
1706
1704
  const { event, callback } = this.pendingListeners.shift();
1707
1705
  console.log(`Registrando listener pendente para evento: ${event}`);
1708
- 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
+ }
1709
1712
  }
1710
1713
  }
1711
1714
  channels;
@@ -1721,14 +1724,24 @@ var AriClient = class {
1721
1724
  * @param callback Callback a ser executado quando o evento for recebido.
1722
1725
  */
1723
1726
  onChannelEvent(eventType, callback) {
1724
- 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
+ }
1725
1738
  }
1726
1739
  /**
1727
1740
  * Registra um listener para eventos globais de WebSocket.
1728
1741
  * O channel no evento será automaticamente transformado em uma instância de ChannelInstance.
1729
1742
  */
1730
1743
  on(eventType, callback) {
1731
- console.log(`Registrando listener no AriClient para evento: ${eventType}`);
1744
+ console.log(`Registrando listener global para evento: ${eventType}`);
1732
1745
  const wrappedCallback = (event) => {
1733
1746
  if (isChannelEvent(event)) {
1734
1747
  const channelId = event.channel.id;
@@ -1792,70 +1805,84 @@ var AriClient = class {
1792
1805
  * @returns A Promise that resolves when the WebSocket connection is successfully established and the application is registered.
1793
1806
  * @throws Error if the 'app' parameter is not provided, or if connection attempts fail after multiple retries.
1794
1807
  */
1795
- 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) {
1796
1829
  if (!app) {
1797
- throw new Error(
1798
- "O par\xE2metro 'app' \xE9 obrigat\xF3rio para conectar ao WebSocket."
1799
- );
1830
+ throw new Error("O nome do aplicativo \xE9 obrigat\xF3rio.");
1800
1831
  }
1801
- if (this.webSocketReady) {
1802
- console.log("J\xE1 existe uma tentativa de conex\xE3o ativa. Aguardando...");
1803
- 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);
1804
1835
  }
1805
- 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) => {
1806
1856
  try {
1807
- if (this.isReconnecting) {
1808
- console.warn(
1809
- "J\xE1 est\xE1 tentando reconectar. Ignorando esta tentativa."
1810
- );
1857
+ if (this.isReconnecting.get(app)) {
1858
+ console.warn(`J\xE1 est\xE1 tentando reconectar para o app '${app}'.`);
1811
1859
  return;
1812
1860
  }
1813
- this.isReconnecting = true;
1814
- const eventsParam = subscribedEvents && subscribedEvents.length > 0 ? `&event=${subscribedEvents.join(",")}` : "&subscribeAll=true";
1815
- const protocol = this.config.secure ? "wss" : "ws";
1816
- const wsUrl = `${protocol}://${encodeURIComponent(this.config.username)}:${encodeURIComponent(this.config.password)}@${this.config.host}:${this.config.port}/ari/events?app=${app}${eventsParam}`;
1817
- const backoffOptions = {
1818
- delayFirstAttempt: false,
1819
- startingDelay: 1e3,
1820
- timeMultiple: 2,
1821
- maxDelay: 3e4,
1822
- numOfAttempts: 10,
1823
- jitter: "full",
1824
- retry: (error, attemptNumber) => {
1825
- console.warn(`Tentativa ${attemptNumber} falhou: ${error.message}`);
1826
- return !this.wsClient?.isConnected();
1827
- }
1828
- };
1829
- if (this.wsClient?.isConnected()) {
1830
- console.log("WebSocket j\xE1 conectado. Removendo listeners antigos...");
1831
- this.wsClient.removeAllListeners();
1832
- this.wsClient.close();
1833
- }
1834
- this.wsClient = new WebSocketClient(wsUrl);
1861
+ this.isReconnecting.set(app, true);
1862
+ const wsClient = new WebSocketClient(wsUrl);
1835
1863
  await (0, import_exponential_backoff.backOff)(async () => {
1836
- if (!this.wsClient) {
1864
+ if (!wsClient) {
1837
1865
  throw new Error("WebSocketClient instance is null.");
1838
1866
  }
1839
- await this.wsClient.connect();
1840
- this.integrateWebSocketEvents(app, this.wsClient);
1867
+ await wsClient.connect();
1868
+ this.integrateWebSocketEvents(app, wsClient);
1841
1869
  console.log(`WebSocket conectado para o app: ${app}`);
1842
1870
  await this.ensureAppRegistered(app);
1843
- this.isWebSocketConnectedFlag = true;
1844
- this.processPendingListeners();
1871
+ this.wsClients.set(app, wsClient);
1845
1872
  }, backoffOptions);
1846
1873
  resolve();
1847
- } catch (err) {
1874
+ } catch (error) {
1848
1875
  console.error(
1849
- "N\xE3o foi poss\xEDvel conectar ao WebSocket ap\xF3s m\xFAltiplas tentativas:",
1850
- err
1876
+ `Erro ao conectar o WebSocket para o app '${app}':`,
1877
+ error
1851
1878
  );
1852
- reject(err);
1879
+ reject(error);
1853
1880
  } finally {
1854
- this.isReconnecting = false;
1855
- this.webSocketReady = null;
1881
+ this.isReconnecting.delete(app);
1856
1882
  }
1857
1883
  });
1858
- return this.webSocketReady;
1884
+ this.webSocketReady.set(app, webSocketPromise);
1885
+ return webSocketPromise;
1859
1886
  }
1860
1887
  /**
1861
1888
  * Integrates WebSocket events with playback listeners.
@@ -1927,8 +1954,14 @@ var AriClient = class {
1927
1954
  *
1928
1955
  * @returns {boolean} True if connected, false otherwise.
1929
1956
  */
1930
- isWebSocketConnected() {
1931
- 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;
1932
1965
  }
1933
1966
  /**
1934
1967
  * Closes the WebSocket connection and removes all associated listeners.
@@ -1940,12 +1973,24 @@ var AriClient = class {
1940
1973
  *
1941
1974
  * @returns {void} This function doesn't return a value.
1942
1975
  */
1943
- closeWebSocket() {
1944
- if (this.wsClient) {
1945
- this.wsClient.close();
1946
- 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.`);
1947
1984
  }
1948
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
+ }
1949
1994
  /**
1950
1995
  * Retrieves a list of active channels from the Asterisk ARI.
1951
1996
  *