feat(signature): make host configurable and add WS reconnect
- New optional env SIGNATURE_HOST overrides the hardcoded 192.168.10.5:2967 (defaults preserved for back-compat). - WebSocket now reconnects with exponential backoff (1s, 2s, 4s ... capped at 30s) on close/error. Previously a dropped signature server connection silently disabled signature playback until the bot was restarted.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user