UNPKG

@deskthing/cli

Version:
221 lines (186 loc) 7.2 kB
import { AppSettings } from "@deskthing/types"; import { DeskThingClientConfig, LoggingLevel } from "../../../config/deskthing.config.types"; import { useClientStore } from "../stores/clientStore"; import { ClientLogger } from "./clientLogger"; import { ClientMessageBus } from "./clientMessageBus"; type callback = (data: any) => void | Promise<void>; type log = { level: LoggingLevel, message: string, data: any[] } export class ClientService { private static responseHandlers: Record<string, callback[]> = {}; private static isInitialized = false; private static logCache: log[] = [] static initialize() { if (this.isInitialized) return; this.isInitialized = true; ClientLogger.debug("Initializing the wrapper..."); ClientMessageBus.subscribe("client:response", async (data: any) => { const handlers = this.responseHandlers[data.type]; if (handlers && Array.isArray(handlers)) { try { await Promise.all(handlers.map((handler) => { try { handler(data.payload) } catch (error) { this.log('error', 'Error in settings callback:', error) } })); } catch (error) { this.log('error', 'Error when processing client:response with the data', error) } finally { ClientService.responseHandlers[data.type] = []; } } }); let attempts = 0 const responseHandler = (config) => { if (!config) { this.logCache.forEach((log) => { console.log(log.level, log.message, ...log.data) }) if (attempts < 5) { attempts++ ClientLogger.warn(`Failed to load client config, retrying... (${attempts}/5)`) setTimeout(() => this.requestClientConfig(responseHandler, { hostname: 'localhost', port: 3000 }), 1000 * attempts) } return } if (this.logCache.length > 0) { this.logCache.forEach((log) => { this.log(log.level, log.message, ...log.data) }) this.logCache = [] } useClientStore.getState().updateConfig(config) ClientMessageBus.initialize(`ws://${window.location.hostname}:${config?.linkPort || window.location.port}`); ClientLogger.debug("Client config loaded:", config); } // Fetch client configuration on startup this.requestClientConfig(responseHandler); } static requestClientConfig(callback: (data: DeskThingClientConfig) => void, options?: { hostname?: string, port?: number }) { fetch(`http://${options?.hostname || window.location.hostname}:${options?.port || window.location.port}/config`) .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`) } return response.json() }) .then(config => { callback(config) }) .catch(error => { console.error('Error fetching client config:', error) callback(null) }) } static requestServerData(callback: (data: any) => void) { if (!this.responseHandlers["data"]) { this.responseHandlers["data"] = []; } this.responseHandlers["data"].push(callback); if (this.responseHandlers["data"].length === 1) { ClientMessageBus.publish("client:request", { type: "getData" }); } } static saveSettings(settings: AppSettings) { ClientMessageBus.publish("client:request", { type: "setSettings", payload: settings }); } static requestManifest(callback: (data: any) => void) { if (!this.responseHandlers["manifest"]) { this.responseHandlers["manifest"] = []; } this.responseHandlers["manifest"].push(callback); if (this.responseHandlers["manifest"].length === 1) { ClientMessageBus.publish("client:request", { type: "getManifest" }); } } static requestSettings(callback: (data: AppSettings) => void) { if (!this.responseHandlers["settings"]) { this.responseHandlers["settings"] = []; } this.responseHandlers["settings"].push(callback); // Only send the request if there are handlers and no request is pending if (this.responseHandlers["settings"].length === 1) { // Only send if this is the first handler ClientLogger.debug("Requesting settings from server"); ClientMessageBus.publish("client:request", { type: "getSettings" }); } else { ClientLogger.debug("Settings request already pending, adding another handler"); } } static sendToServer(data: any) { ClientMessageBus.publish("client:request", data); } static sendToApp(data: any) { if (!data.clientId) { data.clientId = useClientStore.getState().clientId || '1234567890' } ClientMessageBus.publish("app:data", { ...data, clientId: data.clientId || '1234567890' }); } private static shouldLog( msgLevel: LoggingLevel, configLevel: LoggingLevel ): boolean { const levels = ["silent", "error", "warn", "info", "debug"]; const msgLevelIndex = levels.indexOf(msgLevel); const configLevelIndex = levels.indexOf(configLevel); // If either level is not found, default to showing the message if (msgLevelIndex === -1 || configLevelIndex === -1) return true; // Only show messages that are at or above the configured level return msgLevelIndex <= configLevelIndex; } static log(level: LoggingLevel, message: string, ...data: any[]) { // Only log if the level is appropriate based on config const clientConfig = useClientStore.getState().config if (clientConfig.logging.level == undefined) { this.logCache.push({ level, message, data }) return } if (this.shouldLog(level, clientConfig.logging.level)) { // Local console logging switch (level) { case "debug": console.debug( "\x1b[36m%s\x1b[0m", `${clientConfig.logging.prefix} ${message}`, ...data ); // Cyan break; case "info": console.info( "\x1b[90m%s\x1b[0m", `${clientConfig.logging.prefix} ${message}`, ...data ); // Gray break; case "warn": console.warn( "\x1b[33m%s\x1b[0m", `${clientConfig.logging.prefix} ${message}`, ...data ); // Yellow break; case "error": console.error( "\x1b[31m%s\x1b[0m", `${clientConfig.logging.prefix} ${message}`, ...data ); // Red break; default: console.log( "\x1b[32m%s\x1b[0m", `${clientConfig.logging.prefix} ${message}`, ...data ); // Green } // Remote logging if enabled // if (config.logging.enableRemoteLogging) { // this.sendToServer({ // type: 'clientLog', // payload: { level, message, data } // }) // } } } }