From 7362d80a9e6dfcb062f30de68b13f6ed55289cc8 Mon Sep 17 00:00:00 2001 From: Janis Date: Thu, 3 Aug 2023 00:12:57 +0200 Subject: [PATCH] add option to enable logger --- package.json | 2 +- src/handlers/teamspeak/connectionHandler.ts | 23 ++++---- src/handlers/teamspeak/dataHandler.ts | 63 +++++++++++---------- src/handlers/teamspeak/messageHandler.ts | 14 +++-- src/hooks/useTSRemoteApp.tsx | 2 + src/interfaces/api.ts | 1 + src/interfaces/teamspeak.ts | 4 ++ src/utils/logger.tsx | 36 +++++++++--- 8 files changed, 92 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index de04339..806dca5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-ts5-remote-app-api", - "version": "1.1.0", + "version": "1.1.1", "description": "React hook/api for the TeamSpeak5 remote app feature", "main": "dist/cjs/index.js", "module": "dist/esm/index.js", diff --git a/src/handlers/teamspeak/connectionHandler.ts b/src/handlers/teamspeak/connectionHandler.ts index 1d23e8f..b9b17e2 100644 --- a/src/handlers/teamspeak/connectionHandler.ts +++ b/src/handlers/teamspeak/connectionHandler.ts @@ -1,7 +1,7 @@ import { IAuthSenderPayload, IChannel, IClient, IConnection, ITS5ConnectionHandler, ITS5DataHandler, ITS5MessageHandler } from "../../interfaces/teamspeak"; import { TS5DataHandler } from "./dataHandler"; import { TS5MessageHandler } from "./messageHandler"; -import Logger from "../../utils/logger"; +import { ILogger } from "../../utils/logger"; import { ITSRemoteAppAuthPayloadOptions } from "../../interfaces/api"; @@ -11,6 +11,7 @@ export class TS5ConnectionHandler implements ITS5ConnectionHandler { ws: WebSocket; // Websocket connection to TS5 client authenticated = false; // Is the connection authenticated? remoteAppPort: number; // Port of TS5 client + logger: ILogger; // Logger authPayload: ITSRemoteAppAuthPayloadOptions; // Authentication payload dataHandler: ITS5DataHandler; // Handles data/lists and states messageHandler: ITS5MessageHandler; // Handles messages received from TS5 client @@ -19,6 +20,7 @@ export class TS5ConnectionHandler implements ITS5ConnectionHandler { // Port of TS5 client remoteAppPort: number, authPayload: ITSRemoteAppAuthPayloadOptions, + logger: ILogger, // State setters for dataHandler setConnections: React.Dispatch>, setChannels: React.Dispatch>, @@ -30,15 +32,16 @@ export class TS5ConnectionHandler implements ITS5ConnectionHandler { // Create websocket connection to TS5 client this.remoteAppPort = remoteAppPort; this.authPayload = authPayload; + this.logger = logger; this.ws = new WebSocket(`ws://localhost:${this.remoteAppPort}`); // Create dataHandler and messageHandler - this.dataHandler = new TS5DataHandler(setConnections, setChannels, setClients); - this.messageHandler = new TS5MessageHandler(this.ws, this.dataHandler, setActiveConnectionStateId); + this.dataHandler = new TS5DataHandler(setConnections, setChannels, setClients, logger); + this.messageHandler = new TS5MessageHandler(this.ws, this.dataHandler, setActiveConnectionStateId, logger); } reconnect() { - Logger.log("Reconnecting...") + this.logger.log("Reconnecting...") this.ws.close(); this.ws = new WebSocket(`ws://localhost:${this.remoteAppPort}`); @@ -50,7 +53,7 @@ export class TS5ConnectionHandler implements ITS5ConnectionHandler { // Connect to TS5 client connect() { - Logger.log('Connecting to TS5 client...'); + this.logger.log('Connecting to TS5 client...'); // Create authentication payload const initalPayload: IAuthSenderPayload = { @@ -66,16 +69,16 @@ export class TS5ConnectionHandler implements ITS5ConnectionHandler { this.ws.onopen = () => { // Send authentication payload to TS5 client this.ws.send(JSON.stringify(initalPayload)); - Logger.wsSent(initalPayload); + this.logger.wsSent(initalPayload); }; this.ws.onclose = (event) => { - Logger.log("WebSocket connection closed", event); + this.logger.log("WebSocket connection closed", event); // If the connection was closed before authentication, remove the API key from local storage // OBS weirdly caches the localstorage and is very stubborn about clearing it (even when clicken "Clear Cache") if (!this.authenticated) { - Logger.log("WebSocket connection closed before authentication"); + this.logger.log("WebSocket connection closed before authentication"); localStorage.removeItem("apiKey"); } @@ -89,7 +92,7 @@ export class TS5ConnectionHandler implements ITS5ConnectionHandler { this.ws.onmessage = (event) => { const data = JSON.parse(event.data); - Logger.wsReceived(data) + this.logger.wsReceived(data) switch (data.type) { case "auth": @@ -118,7 +121,7 @@ export class TS5ConnectionHandler implements ITS5ConnectionHandler { this.messageHandler.handleChannelsMessage(data); break; default: - Logger.log(`No handler for event type: ${data.type}`); + this.logger.log(`No handler for event type: ${data.type}`); break; } }; diff --git a/src/handlers/teamspeak/dataHandler.ts b/src/handlers/teamspeak/dataHandler.ts index 58e0a69..d7128af 100644 --- a/src/handlers/teamspeak/dataHandler.ts +++ b/src/handlers/teamspeak/dataHandler.ts @@ -1,4 +1,4 @@ -import Logger from "../..//utils/logger"; +import { ILogger } from "../..//utils/logger"; import { IConnection, IChannel, IClient, ITS5DataHandler } from "../../interfaces/teamspeak"; @@ -18,11 +18,14 @@ export class TS5DataHandler implements ITS5DataHandler { setChannels: React.Dispatch>; setClients: React.Dispatch>; + logger: ILogger; constructor( // State setters for App.tsx setConnections: React.Dispatch>, setChannels: React.Dispatch>, - setClients: React.Dispatch> + setClients: React.Dispatch>, + + logger: ILogger, ) { this.setConnections = setConnections; this.setChannels = setChannels; @@ -31,6 +34,8 @@ export class TS5DataHandler implements ITS5DataHandler { this.localConnections = []; this.localChannels = []; this.localClients = []; + + this.logger = logger; } // Update App.tsx states @@ -59,88 +64,88 @@ export class TS5DataHandler implements ITS5DataHandler { // Add data to local lists and update states addConnection(connection: IConnection) { - Logger.log("Adding connection...", connection) + this.logger.log("Adding connection...", connection) const existingConnection: IConnection | undefined = this.localConnections.find((localConnection: IConnection) => localConnection.id === connection.id); if (existingConnection == undefined) { this.localConnections.push(connection); this.updateConnectionsState(); - Logger.log("Connection added") + this.logger.log("Connection added") } else { - Logger.log("Connection already exists") + this.logger.log("Connection already exists") } } addChannel(channel: IChannel) { - Logger.log("Adding channel...", channel) + this.logger.log("Adding channel...", channel) const existingChannel: IChannel | undefined = this.localChannels.find((localChannel: IChannel) => localChannel.id === channel.id && localChannel.connection.id === channel.connection.id); if (existingChannel == undefined) { this.localChannels.push(channel); this.updateChannelsState(); - Logger.log("Channel added") + this.logger.log("Channel added") } else { - Logger.log("Channel already exists") + this.logger.log("Channel already exists") } } addClient(client: IClient) { - Logger.log("Adding client...", client) + this.logger.log("Adding client...", client) const existingClient: IClient | undefined = this.localClients.find((localClient: IClient) => localClient.id === client.id && localClient.channel?.connection.id === client.channel?.connection.id); if (existingClient == undefined) { this.localClients.push(client); this.updateClientsState(); - Logger.log("Client added") + this.logger.log("Client added") } else { - Logger.log("Client already exists") + this.logger.log("Client already exists") } } // Update data in local lists and update states updateConnection(connection: IConnection) { - Logger.log("Updating connection...", connection) + this.logger.log("Updating connection...", connection) const existingConnection: IConnection | undefined = this.localConnections.find((localConnection: IConnection) => localConnection.id === connection.id); if (existingConnection !== undefined) { this.localConnections[this.localConnections.indexOf(existingConnection)] = connection; this.updateConnectionsState(); - Logger.log("Connection updated") + this.logger.log("Connection updated") } else { - Logger.log("Connection does not exist") + this.logger.log("Connection does not exist") } } updateChannel(channel: IChannel) { - Logger.log("Updating channel...", channel) + this.logger.log("Updating channel...", channel) const existingChannel: IChannel | undefined = this.localChannels.find((localChannel: IChannel) => localChannel.id === channel.id && localChannel.connection.id === channel.connection.id); if (existingChannel !== undefined) { this.localChannels[this.localChannels.indexOf(existingChannel)] = channel; this.updateChannelsState(); - Logger.log("Channel updated") + this.logger.log("Channel updated") } else { - Logger.log("Channel does not exist") + this.logger.log("Channel does not exist") } } updateClient(client: IClient) { - Logger.log("Updating client...", client) + this.logger.log("Updating client...", client) const existingClient: IClient | undefined = this.localClients.find((localClient: IClient) => localClient.id === client.id && localClient.channel?.connection.id === client.channel?.connection.id); if (existingClient !== undefined) { this.localClients[this.localClients.indexOf(existingClient)] = client; this.updateClientsState(); - Logger.log("Client updated") + this.logger.log("Client updated") } else { - Logger.log("Client does not exist") + this.logger.log("Client does not exist") } } // Remove data from local lists and update states removeConnection(connection: IConnection) { - Logger.log("Removing connection...", connection) + this.logger.log("Removing connection...", connection) const existingConnection: IConnection | undefined = this.localConnections.find((localConnection: IConnection) => localConnection.id === connection.id); if (existingConnection !== undefined) { @@ -153,14 +158,14 @@ export class TS5DataHandler implements ITS5DataHandler { this.updateChannelsState(); this.updateClientsState(); this.updateConnectionsState(); - Logger.log("Connection removed") + this.logger.log("Connection removed") } else { - Logger.log("Connection does not exist") + this.logger.log("Connection does not exist") } } removeChannel(channel: IChannel) { - Logger.log("Removing channel...", channel) + this.logger.log("Removing channel...", channel) const existingChannel: IChannel | undefined = this.localChannels.find((localChannel: IChannel) => localChannel.id === channel.id && localChannel.connection.id === channel.connection.id); if (existingChannel !== undefined) { @@ -171,22 +176,22 @@ export class TS5DataHandler implements ITS5DataHandler { this.updateClientsState(); this.updateChannelsState(); - Logger.log("Channel removed") + this.logger.log("Channel removed") } else { - Logger.log("Channel does not exist") + this.logger.log("Channel does not exist") } } removeClient(client: IClient) { - Logger.log("Removing client...", client) + this.logger.log("Removing client...", client) const existingClient: IClient | undefined = this.localClients.find((localClient: IClient) => localClient.id === client.id && localClient.channel?.connection.id === client.channel?.connection.id); if (existingClient !== undefined) { this.localClients.splice(this.localClients.indexOf(existingClient), 1); this.updateClientsState(); - Logger.log("Client removed") + this.logger.log("Client removed") } else { - Logger.log("Client does not exist") + this.logger.log("Client does not exist") } } diff --git a/src/handlers/teamspeak/messageHandler.ts b/src/handlers/teamspeak/messageHandler.ts index e66c7cc..b16b063 100644 --- a/src/handlers/teamspeak/messageHandler.ts +++ b/src/handlers/teamspeak/messageHandler.ts @@ -1,18 +1,20 @@ -import Logger from "../../utils/logger"; +import { ILogger } from "../../utils/logger"; import { IChannelInfos, IConnection, IChannel, IAuthMessage, IClientInfo, IClientMovedMessage, IClient, IClientPropertiesUpdatedMessage, ITalkStatusChangedMessage, IClientSelfPropertyUpdatedMessage, IServerPropertiesUpdatedMessage, IConnectStatusChangedMessage, IChannelsMessage, ITS5MessageHandler, ITS5DataHandler } from "../../interfaces/teamspeak"; // Handle incoming messages from TS5 client export class TS5MessageHandler implements ITS5MessageHandler { ws: WebSocket; dataHandler: ITS5DataHandler; + logger: ILogger; setActiveConnectionStateId: React.Dispatch>; activeConnectionId = 0; - constructor(ws: WebSocket, dataHandler: ITS5DataHandler, setActiveConnectionStateId: React.Dispatch>) { + constructor(ws: WebSocket, dataHandler: ITS5DataHandler, setActiveConnectionStateId: React.Dispatch>, logger: ILogger) { this.ws = ws; this.dataHandler = dataHandler; this.setActiveConnectionStateId = setActiveConnectionStateId; + this.logger = logger; } setActiveConnection(connectionId: number) { @@ -82,7 +84,7 @@ export class TS5MessageHandler implements ITS5MessageHandler { channel: newChannel, properties: data.payload.properties, }); - Logger.ts(`New Client found (${data.payload.connectionId} - ${data.payload.clientId} - ${data.payload.properties.nickname})`) + this.logger.ts(`New Client found (${data.payload.connectionId} - ${data.payload.clientId} - ${data.payload.properties.nickname})`) } }, 2000); @@ -90,7 +92,7 @@ export class TS5MessageHandler implements ITS5MessageHandler { const newChannel: IChannel | undefined = this.dataHandler.getChannelById(data.payload.newChannelId, data.payload.connectionId); if (newChannel === undefined || newChannel.id === 0) { - Logger.ts(`Client left (${data.payload.connectionId} - ${data.payload.clientId} - ${data.payload.properties.nickname})`) + this.logger.ts(`Client left (${data.payload.connectionId} - ${data.payload.clientId} - ${data.payload.properties.nickname})`) if (client !== undefined) { this.dataHandler.removeClient(client); } @@ -98,7 +100,7 @@ export class TS5MessageHandler implements ITS5MessageHandler { } if (client !== undefined) { // Client already exists - Logger.ts(`Client moved (${client.channel.connection.id} - ${client.id} - ${client.properties.nickname})`) + this.logger.ts(`Client moved (${client.channel.connection.id} - ${client.id} - ${client.properties.nickname})`) this.dataHandler.updateClient({ ...client, @@ -107,7 +109,7 @@ export class TS5MessageHandler implements ITS5MessageHandler { } else { // Client does not exist // Client joined - Logger.ts(`Client joined (${data.payload.connectionId} - ${data.payload.clientId} - ${data.payload.properties.nickname})`) + this.logger.ts(`Client joined (${data.payload.connectionId} - ${data.payload.clientId} - ${data.payload.properties.nickname})`) this.dataHandler.addClient( { diff --git a/src/hooks/useTSRemoteApp.tsx b/src/hooks/useTSRemoteApp.tsx index aeb1629..1a264fe 100644 --- a/src/hooks/useTSRemoteApp.tsx +++ b/src/hooks/useTSRemoteApp.tsx @@ -3,6 +3,7 @@ import { TS5ConnectionHandler } from "../handlers/teamspeak/connectionHandler"; import { ITSRemoteAppOptions } from "../interfaces/api"; import { IClient, IChannel, IConnection, ITS5ConnectionHandler } from "../interfaces/teamspeak"; import { useEffect, useState } from "react"; +import Logger from "../utils/logger"; export default function useTSRemoteApp(options: ITSRemoteAppOptions) { const [clients, setClients] = useState([]); @@ -20,6 +21,7 @@ export default function useTSRemoteApp(options: ITSRemoteAppOptions) { const tsConnection: ITS5ConnectionHandler = new TS5ConnectionHandler( options.remoteAppPort ?? 5899, options.auth, + new Logger(options.logging ?? false), setConnections, setChannels, setClients, diff --git a/src/interfaces/api.ts b/src/interfaces/api.ts index 82b89a8..c4b8fd6 100644 --- a/src/interfaces/api.ts +++ b/src/interfaces/api.ts @@ -1,5 +1,6 @@ export interface ITSRemoteAppOptions { remoteAppPort: number; + logging: boolean; auth: ITSRemoteAppAuthPayloadOptions, } diff --git a/src/interfaces/teamspeak.ts b/src/interfaces/teamspeak.ts index d49bddb..c6b3e7d 100644 --- a/src/interfaces/teamspeak.ts +++ b/src/interfaces/teamspeak.ts @@ -1,3 +1,4 @@ +import { ILogger } from "../utils/logger"; import { ITSRemoteAppAuthPayloadOptions } from "./api"; // Classes @@ -5,6 +6,7 @@ export interface ITS5ConnectionHandler { ws: WebSocket; authenticated: boolean; remoteAppPort: number; + logger: ILogger; authPayload: ITSRemoteAppAuthPayloadOptions; dataHandler: ITS5DataHandler; messageHandler: ITS5MessageHandler; @@ -16,6 +18,7 @@ export interface ITS5DataHandler { localConnections: IConnection[]; localChannels: IChannel[]; localClients: IClient[]; + logger: ILogger; setConnections: React.Dispatch>; setChannels: React.Dispatch>; setClients: React.Dispatch>; @@ -37,6 +40,7 @@ export interface ITS5DataHandler { export interface ITS5MessageHandler { ws: WebSocket; dataHandler: ITS5DataHandler; + logger: ILogger; setActiveConnectionStateId: React.Dispatch>; activeConnectionId: number; setActiveConnection(connectionId: number): void; diff --git a/src/utils/logger.tsx b/src/utils/logger.tsx index d0f8bf2..3757956 100644 --- a/src/utils/logger.tsx +++ b/src/utils/logger.tsx @@ -1,31 +1,53 @@ -export default class Logger { +export interface ILogger { + enabled: boolean; + log(message: string, data?: object | null): void; + warn(message: string, data?: object | null): void; + error(message: string, data?: object | null): void; + wsReceived(data: object, message?: string | undefined): void; + wsSent(data: object, message?: string | undefined): void; + ts(message: string, data?: object | null): void; +} + +export default class Logger implements ILogger { + enabled: boolean; + + constructor(enabled: boolean) { + this.enabled = enabled; + } + // Log message to the console - public static log(message: string, data: object | null = null): void { + public log(message: string, data: object | null = null): void { + if (!this.enabled) return; console.log(`[Log] %c${message}`.trim(), "color: gray", data ?? ""); } // Log warning to the console - public static warn(message: string, data: object | null = null): void { + public warn(message: string, data: object | null = null): void { + if (!this.enabled) return; console.warn(`%c${message}`.trim(), data ?? ""); } // Log error to the console - public static error(message: string, data: object | null = null): void { + public error(message: string, data: object | null = null): void { + if (!this.enabled) return; console.error(`%c${message}`.trim(), data ?? ""); } // Log message received from the websocket to the console - public static wsReceived(data: object, message: string | undefined = undefined): void { + public wsReceived(data: object, message: string | undefined = undefined): void { + if (!this.enabled) return; console.log(`%c[WS Recieved] ${message ?? ""}`.trim(), "color: #8258c7", data); } // Log message sent to the websocket to the console - public static wsSent(data: object, message: string | undefined = undefined): void { + public wsSent(data: object, message: string | undefined = undefined): void { + if (!this.enabled) return; console.log(`%c[WS Sent] ${message ?? ""}`.trim(), "color: #4eb570", data); } // Log message to the console with a timestamp - public static ts(message: string, data: object | null = null): void { + public ts(message: string, data: object | null = null): void { + if (!this.enabled) return; console.log(`%c[TS] ${message}`.trim(), "color: #2e6bc7", data ?? ""); } }