{"version":3,"file":"join.mjs","names":[],"sources":["../../../src/mixins/ratelimiters/join.ts"],"sourcesContent":["import { Sema } from \"async-sema\";\n\nimport type { ClientMixin } from \"../base-mixin\";\nimport type { ChatClient } from \"~/client/client\";\nimport { applyReplacements } from \"~/utils/apply-function-replacements\";\n\nexport class JoinRateLimiter implements ClientMixin {\n  private readonly client: ChatClient;\n  private readonly joinLimitsSemaphore: Sema;\n\n  public constructor(client: ChatClient) {\n    this.client = client;\n\n    this.joinLimitsSemaphore = new Sema(\n      this.client.configuration.rateLimits.joinLimits,\n    );\n  }\n\n  public applyToClient(client: ChatClient): void {\n    const joinReplacement = async <V, A extends unknown[]>(\n      oldFunction: (channelName: string, ...args: A) => Promise<V>,\n      channelName: string,\n      ...args: A\n    ): Promise<V> => {\n      const releaseFunction = await this.acquire();\n      try {\n        return await oldFunction(channelName, ...args);\n      } finally {\n        setTimeout(releaseFunction, 10 * 1000); // 10 seconds per 20 joined channels.\n      }\n    };\n\n    const joinAllReplacement = async <A extends unknown[]>(\n      oldFunction: (\n        channelNames: string[],\n        ...args: A\n      ) => Promise<Record<string, Error | undefined>>,\n      channelNames: string[],\n      ...args: A\n    ): Promise<Record<string, Error | undefined>> => {\n      const promiseResults = [];\n\n      for (\n        let index = 0;\n        index < channelNames.length;\n        index += this.client.configuration.rateLimits.joinLimits\n      ) {\n        const chunk = channelNames.slice(\n          index,\n          index + this.client.configuration.rateLimits.joinLimits,\n        );\n\n        const acquireFunctions = Array.from({ length: chunk.length }).fill(\n          this.acquire.bind(this),\n        ) as (() => Promise<() => void>)[];\n\n        const releaseFunctions = await Promise.all(\n          acquireFunctions.map(async (acquire) => acquire()),\n        );\n\n        try {\n          const result = await oldFunction(chunk, ...args);\n          promiseResults.push(result);\n        } finally {\n          for (const releaseFunction of releaseFunctions) {\n            setTimeout(releaseFunction, 10 * 1000); // 10 seconds per 20 joined channels.\n          }\n        }\n      }\n\n      return promiseResults.reduce(\n        (accumulator, object) => ({ ...accumulator, ...object }),\n        {},\n      );\n    };\n\n    applyReplacements(this, client, {\n      join: joinReplacement,\n      joinAll: joinAllReplacement,\n    });\n  }\n\n  private async acquire(): Promise<() => void> {\n    await this.joinLimitsSemaphore.acquire();\n    return () => this.joinLimitsSemaphore.release();\n  }\n}\n"],"mappings":";;;AAMA,IAAa,kBAAb,MAAoD;CAClD;CACA;CAEA,YAAmB,QAAoB;AACrC,OAAK,SAAS;AAEd,OAAK,sBAAsB,IAAI,KAC7B,KAAK,OAAO,cAAc,WAAW,WACtC;;CAGH,cAAqB,QAA0B;EAC7C,MAAM,kBAAkB,OACtB,aACA,aACA,GAAG,SACY;GACf,MAAM,kBAAkB,MAAM,KAAK,SAAS;AAC5C,OAAI;AACF,WAAO,MAAM,YAAY,aAAa,GAAG,KAAK;aACtC;AACR,eAAW,iBAAiB,KAAK,IAAK;;;EAI1C,MAAM,qBAAqB,OACzB,aAIA,cACA,GAAG,SAC4C;GAC/C,MAAM,iBAAiB,EAAE;AAEzB,QACE,IAAI,QAAQ,GACZ,QAAQ,aAAa,QACrB,SAAS,KAAK,OAAO,cAAc,WAAW,YAC9C;IACA,MAAM,QAAQ,aAAa,MACzB,OACA,QAAQ,KAAK,OAAO,cAAc,WAAW,WAC9C;IAED,MAAM,mBAAmB,MAAM,KAAK,EAAE,QAAQ,MAAM,QAAQ,CAAC,CAAC,KAC5D,KAAK,QAAQ,KAAK,KAAK,CACxB;IAED,MAAM,mBAAmB,MAAM,QAAQ,IACrC,iBAAiB,IAAI,OAAO,YAAY,SAAS,CAAC,CACnD;AAED,QAAI;KACF,MAAM,SAAS,MAAM,YAAY,OAAO,GAAG,KAAK;AAChD,oBAAe,KAAK,OAAO;cACnB;AACR,UAAK,MAAM,mBAAmB,iBAC5B,YAAW,iBAAiB,KAAK,IAAK;;;AAK5C,UAAO,eAAe,QACnB,aAAa,YAAY;IAAE,GAAG;IAAa,GAAG;IAAQ,GACvD,EAAE,CACH;;AAGH,oBAAkB,MAAM,QAAQ;GAC9B,MAAM;GACN,SAAS;GACV,CAAC;;CAGJ,MAAc,UAA+B;AAC3C,QAAM,KAAK,oBAAoB,SAAS;AACxC,eAAa,KAAK,oBAAoB,SAAS"}