import type { Gotify } from "gotify"; import type { Logger } from "pino"; import type { TeamSpeak, TextMessageTargetMode } from "ts3-nodejs-library"; import { ClientConnect, ClientDisconnect, ClientMoved, TextMessage, } from "ts3-nodejs-library/lib/types/Events"; import type { GotifyConfig, Mode } from "./types"; function resolveMessageTarget(target: TextMessageTargetMode): string { if (target === 1) { return "Client"; } else if (target === 2) { return "Channel"; } else { return "Server"; } } export function getModes(mode: Mode[]): { [key in Mode]: boolean; } { const modes = mode .map((mode) => { return { [mode]: true }; }) .reduce((acc, cur) => { return { ...acc, ...cur }; }); return { connect: false, disconnect: false, moved: false, message: false, ...modes, }; } export function ts3gotifyFactory( ts3Client: TeamSpeak, gotifyClient: Gotify, gotifyConfig: GotifyConfig, logger: Logger, pingInterval = 2_500 ) { let reconnectInProgress = false; function sendNotification(message: string) { gotifyClient .send({ ...gotifyConfig, message: message, }) .catch((error: Error) => { logger.error(`Error sending message to gotify: ${error.message}`); }); } function registerEventListenerForMode(mode: Mode) { switch (mode) { case "connect": ts3Client.on("clientconnect", (event: ClientConnect) => sendNotification(`${event.client.nickname} connected`) ); break; case "disconnect": ts3Client.on("clientdisconnect", (event: ClientDisconnect) => sendNotification(`${event.client?.nickname} disconnected`) ); break; case "moved": ts3Client.on("clientmoved", (event: ClientMoved) => sendNotification( `${event.client.nickname} got moved to ${event.channel.name}` ) ); break; case "message": ts3Client.on("textmessage", (event: TextMessage) => sendNotification( `${event.invoker.nickname} wrote ${ event.msg } to a ${resolveMessageTarget(event.targetmode)}` ) ); break; } } async function reconnectWithBackoff() { if (reconnectInProgress) { return; } reconnectInProgress = true; logger.info("disconnected, trying to reconnect..."); try { await ts3Client.reconnect(10, 2000); logger.info("reconnected!"); } catch (error) { const message = error instanceof Error ? error.message : String(error); logger.error(`Error reconnecting to TS3 server: ${message}`); } finally { reconnectInProgress = false; } } setInterval(() => ts3Client.version(true), pingInterval); ts3Client.on("close", async () => { await reconnectWithBackoff(); }); ts3Client.on("error", (error: Error) => { logger.error(`Error connecting to TS3 server: ${error.message}`); reconnectWithBackoff(); }); return { registerEventListenerForMode, }; } export type Ts3Gotify = ReturnType;