d6d9c63b3d
Fixes the frequent disconnection issue, by adding a ping. The "version" call works without authentication and is lightweight. Passing the "true" flag, prevents delivery of cached results. This keeps the socket always connected. Feature may be removed in the future if the upstream library has a proper fix for the issue. Reviewed-on: #121 Co-authored-by: Timo Behrendt <t.behrendt@t00n.de> Co-committed-by: Timo Behrendt <t.behrendt@t00n.de>
129 lines
3.1 KiB
TypeScript
129 lines
3.1 KiB
TypeScript
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<typeof ts3gotifyFactory>;
|