mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 13:02:49 +08:00
fix: resolve critical race conditions and high-severity bugs
- Add isAdvancing guard to playNext() to prevent concurrent calls from skipping songs (trackEnd + user !next race condition) - Replace removeAllListeners in WebSocket setup with tracked named listeners, attach only once per bot instead of every 5 seconds - Add .catch() to unhandled playNext() in cmdVote - Add sessionId counter to AudioPlayer to discard stale setTimeout callbacks after stop()+play() transitions - Defer nulling TS3 client until disconnect() promise resolves - Add null checks for providers in play-by-id and add-by-id endpoints - Add PCM buffer backpressure (pause FFmpeg at 960KB, resume at 480KB) - Change volume slider from @input to @change to avoid flooding server - Wrap error-reporting sendTextMessage in try/catch to prevent unhandled rejection in error handler - Clamp elapsed getter to song duration - Log FFmpeg stderr at debug level instead of swallowing - Return null from prev() in Sequential mode instead of wrapping Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
4c71a0a37f
commit
17991b936a
8 files changed
+150
-57
No files matched your search
+60
-28
@@ -1,5 +1,6 @@
|
||||
import { WebSocketServer, WebSocket } from "ws";
|
||||
import type { BotManager } from "../bot/manager.js";
|
||||
import type { BotInstance } from "../bot/instance.js";
|
||||
import type { Logger } from "../logger.js";
|
||||
|
||||
export function setupWebSocket(
|
||||
@@ -9,6 +10,13 @@ export function setupWebSocket(
|
||||
): () => void {
|
||||
const clients = new Set<WebSocket>();
|
||||
|
||||
/** Track which bots already have listeners attached */
|
||||
const attachedBots = new Map<string, {
|
||||
stateChange: () => void;
|
||||
connected: () => void;
|
||||
disconnected: () => void;
|
||||
}>();
|
||||
|
||||
wss.on("connection", (ws) => {
|
||||
clients.add(ws);
|
||||
logger.debug("WebSocket client connected");
|
||||
@@ -36,39 +44,63 @@ export function setupWebSocket(
|
||||
}
|
||||
};
|
||||
|
||||
const attachBotListeners = () => {
|
||||
function attachBotListener(bot: BotInstance): void {
|
||||
if (attachedBots.has(bot.id)) return;
|
||||
|
||||
const onStateChange = () => {
|
||||
broadcast({
|
||||
type: "stateChange",
|
||||
botId: bot.id,
|
||||
status: bot.getStatus(),
|
||||
queue: bot.getQueue(),
|
||||
});
|
||||
};
|
||||
|
||||
const onConnected = () => {
|
||||
broadcast({
|
||||
type: "botConnected",
|
||||
botId: bot.id,
|
||||
status: bot.getStatus(),
|
||||
});
|
||||
};
|
||||
|
||||
const onDisconnected = () => {
|
||||
broadcast({ type: "botDisconnected", botId: bot.id });
|
||||
};
|
||||
|
||||
bot.on("stateChange", onStateChange);
|
||||
bot.on("connected", onConnected);
|
||||
bot.on("disconnected", onDisconnected);
|
||||
|
||||
attachedBots.set(bot.id, {
|
||||
stateChange: onStateChange,
|
||||
connected: onConnected,
|
||||
disconnected: onDisconnected,
|
||||
});
|
||||
}
|
||||
|
||||
/** Attach listeners for any new bots that don't have them yet */
|
||||
function ensureAllBotsAttached(): void {
|
||||
for (const bot of botManager.getAllBots()) {
|
||||
bot.removeAllListeners("stateChange");
|
||||
bot.removeAllListeners("connected");
|
||||
bot.removeAllListeners("disconnected");
|
||||
|
||||
bot.on("stateChange", () => {
|
||||
broadcast({
|
||||
type: "stateChange",
|
||||
botId: bot.id,
|
||||
status: bot.getStatus(),
|
||||
queue: bot.getQueue(),
|
||||
});
|
||||
});
|
||||
|
||||
bot.on("connected", () => {
|
||||
broadcast({
|
||||
type: "botConnected",
|
||||
botId: bot.id,
|
||||
status: bot.getStatus(),
|
||||
});
|
||||
});
|
||||
|
||||
bot.on("disconnected", () => {
|
||||
broadcast({ type: "botDisconnected", botId: bot.id });
|
||||
});
|
||||
attachBotListener(bot);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const intervalId = setInterval(attachBotListeners, 5000);
|
||||
attachBotListeners();
|
||||
// Check for newly added bots periodically
|
||||
const intervalId = setInterval(ensureAllBotsAttached, 5000);
|
||||
ensureAllBotsAttached();
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
// Clean up named listeners
|
||||
for (const bot of botManager.getAllBots()) {
|
||||
const listeners = attachedBots.get(bot.id);
|
||||
if (listeners) {
|
||||
bot.removeListener("stateChange", listeners.stateChange);
|
||||
bot.removeListener("connected", listeners.connected);
|
||||
bot.removeListener("disconnected", listeners.disconnected);
|
||||
}
|
||||
}
|
||||
attachedBots.clear();
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user