@deskthing/cli
Version:
An emulator for the DeskThing Server
94 lines (83 loc) • 3.13 kB
text/typescript
import { useClientStore } from "../stores/clientStore";
import { ClientLogger } from "./clientLogger"
export class ClientMessageBus {
private static subscribers = new Map<string, Function[]>();
private static ws: WebSocket | null;
private static queue: { event: string, data: any }[] = []
private static closeTimeoutId: NodeJS.Timeout | null = null
static initialize(url?: string) {
const getConfig = () => {
try {
// Dynamic import to avoid circular dependency
return useClientStore.getState().config
} catch (error) {
console.warn('Could not access client store, using defaults')
return { linkPort: 8080 }
}
}
const wsUrl = url || `ws://${window.location.hostname}:${getConfig().linkPort}`
if (this.ws) {
ClientLogger.debug('Closing the old websocket')
this.ws.close();
this.ws = null;
}
this.ws = new WebSocket(wsUrl);
this.ws.onopen = () => {
ClientLogger.debug('WebSocket connection established on port ', getConfig().linkPort);
if (this.queue.length > 0) {
this.queue.map((req) => this.publish(req.event, req.data))
this.queue = []
}
};
this.ws.onclose = () => {
ClientLogger.debug('WebSocket connection closed');
if (this.closeTimeoutId) {
clearTimeout(this.closeTimeoutId)
}
this.closeTimeoutId = setTimeout(() => {
this.initialize()
}, 5000)
};
this.ws.onerror = (error) => {
ClientLogger.error('WebSocket error:', error);
};
this.ws.onmessage = (event) => {
const { event: eventName, data } = JSON.parse(event.data.toString());
if (data.clientId && data.clientId !== useClientStore.getState().clientId) {
ClientLogger.debug('Received message for different client, ignoring', eventName, data);
return
}
ClientLogger.debug('Received message', eventName, data);
this.notify(eventName, data);
};
}
static subscribe(event: string, callback: Function) {
if (!this.subscribers.has(event)) {
this.subscribers.set(event, []);
}
this.subscribers.get(event)?.push(callback);
ClientLogger.debug('Subscribed to', event);
return () => this.unsubscribe(event, callback);
}
static notify(event: string, data: any) {
if (this.subscribers.has(event)) {
this.subscribers.get(event)?.forEach((callback) => callback(data));
}
}
static publish(event: string, data: any) {
if (this.ws?.readyState === WebSocket.OPEN) {
ClientLogger.debug('Publishing message', event, data);
this.ws.send(JSON.stringify({ event, data }));
} else {
this.queue.push({ event, data })
}
}
private static unsubscribe(event: string, callback: Function) {
const callbacks = this.subscribers.get(event);
const index = callbacks?.indexOf(callback);
if (callbacks && index !== undefined && index > -1) {
callbacks.splice(index, 1);
ClientLogger.debug('Unsubscribed from', event);
}
}
}