diff --git a/src/classes/SignatureClient.ts b/src/classes/SignatureClient.ts index 8293c88..c7c4485 100644 --- a/src/classes/SignatureClient.ts +++ b/src/classes/SignatureClient.ts @@ -4,6 +4,7 @@ import WebSocket from "ws"; import ffmpeg from "fluent-ffmpeg"; import { existsSync, mkdirSync, readdirSync, readFileSync, rmdirSync, rmSync, unlinkSync, writeFileSync } from "node:fs"; import { Readable } from "node:stream"; +import { Config } from "../utils/Config"; interface SignatureItem { name: string[]; @@ -17,10 +18,13 @@ mkdirSync(filePath, { recursive: true }); export class SignatureClient { private readonly myClientId = "bot-"+Math.random().toString(36).slice(2, 9); - private readonly host = `192.168.10.5:2967`; + private readonly host = Config.signatureHost; private readonly wsUrl = `ws://${this.host}?clientId=${this.myClientId}`; - private ws = new WebSocket(this.wsUrl); + private ws!: WebSocket; private signatureList: SignatureItem[] = []; + private reconnectDelayMs = 1000; + private readonly reconnectMaxMs = 30_000; + private reconnectTimer?: NodeJS.Timeout; get list() { return this.signatureList; @@ -36,8 +40,14 @@ export class SignatureClient { } constructor() { + this.connect(); + } + + private connect() { + this.ws = new WebSocket(this.wsUrl); this.ws.on("open", () => { Logger.ready("[WS] 서버 연결 성공"); + this.reconnectDelayMs = 1000; // reset backoff on successful connect const requestMessage = JSON.stringify({ type: "GET_LIST" }); this.ws.send(requestMessage); }); @@ -54,12 +64,27 @@ export class SignatureClient { }); this.ws.on("close", () => { Logger.info("[WS] 서버 연결 종료"); + this.scheduleReconnect(); }); this.ws.on("error", (error) => { Logger.error(`[WS] 오류 발생: ${String(error)}`); + // 'error' is typically followed by 'close' on the ws lib, but call + // out reconnect anyway in case the socket never closes cleanly. + try { this.ws.terminate(); } catch {} }); } + private scheduleReconnect() { + if (this.reconnectTimer) return; // already scheduled + const delay = this.reconnectDelayMs; + this.reconnectDelayMs = Math.min(this.reconnectDelayMs * 2, this.reconnectMaxMs); + Logger.info(`[WS] ${delay}ms 후 재연결 시도`); + this.reconnectTimer = setTimeout(() => { + this.reconnectTimer = undefined; + this.connect(); + }, delay); + } + async changeVolume(buffer: Buffer, volume: number) { try { const inputStream = Readable.from(buffer); diff --git a/src/utils/Config.ts b/src/utils/Config.ts index 2ef8424..185a315 100644 --- a/src/utils/Config.ts +++ b/src/utils/Config.ts @@ -13,6 +13,7 @@ export const Config = { nid_ses: process.env.CHZZK_NID_SES?.trim(), }, _ttsPath: process.env.TTSPATH?.trim(), + _signatureHost: process.env.SIGNATURE_HOST?.trim() || "192.168.10.5:2967", debug: process.env.DEBUG?.trim()?.toLocaleLowerCase() === "true", dev: process.env.DEV?.trim()?.toLocaleLowerCase() === "true", replaceObj: { ...def_replaceObj, ...JSON.parse(process.env.REPLACETEXT?.trim() || "[{}]")[0] }, @@ -48,6 +49,9 @@ export const Config = { get ttsPath() { if (!this._ttsPath) throw new ReferenceError("TTSPATH is missing"); return this._ttsPath; + }, + get signatureHost() { + return this._signatureHost; } };