mirror of
https://github.com/itdoginfo/podkop.git
synced 2026-01-31 06:40:46 +03:00
122 lines
3.1 KiB
TypeScript
122 lines
3.1 KiB
TypeScript
// eslint-disable-next-line
|
|
type Listener = (data: any) => void;
|
|
type ErrorListener = (error: Event | string) => void;
|
|
|
|
class SocketManager {
|
|
private static instance: SocketManager;
|
|
private sockets = new Map<string, WebSocket>();
|
|
private listeners = new Map<string, Set<Listener>>();
|
|
private connected = new Map<string, boolean>();
|
|
private errorListeners = new Map<string, Set<ErrorListener>>();
|
|
|
|
private constructor() {}
|
|
|
|
static getInstance(): SocketManager {
|
|
if (!SocketManager.instance) {
|
|
SocketManager.instance = new SocketManager();
|
|
}
|
|
return SocketManager.instance;
|
|
}
|
|
|
|
connect(url: string): void {
|
|
if (this.sockets.has(url)) return;
|
|
|
|
const ws = new WebSocket(url);
|
|
this.sockets.set(url, ws);
|
|
this.connected.set(url, false);
|
|
this.listeners.set(url, new Set());
|
|
this.errorListeners.set(url, new Set());
|
|
|
|
ws.addEventListener('open', () => {
|
|
this.connected.set(url, true);
|
|
console.info(`Connected: ${url}`);
|
|
});
|
|
|
|
ws.addEventListener('message', (event) => {
|
|
const handlers = this.listeners.get(url);
|
|
if (handlers) {
|
|
for (const handler of handlers) {
|
|
try {
|
|
handler(event.data);
|
|
} catch (err) {
|
|
console.error(`Handler error for ${url}:`, err);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
ws.addEventListener('close', () => {
|
|
this.connected.set(url, false);
|
|
console.warn(`Disconnected: ${url}`);
|
|
this.triggerError(url, 'Connection closed');
|
|
});
|
|
|
|
ws.addEventListener('error', (err) => {
|
|
console.error(`Socket error for ${url}:`, err);
|
|
this.triggerError(url, err);
|
|
});
|
|
}
|
|
|
|
subscribe(url: string, listener: Listener, onError?: ErrorListener): void {
|
|
if (!this.sockets.has(url)) {
|
|
this.connect(url);
|
|
}
|
|
|
|
this.listeners.get(url)?.add(listener);
|
|
|
|
if (onError) {
|
|
this.errorListeners.get(url)?.add(onError);
|
|
}
|
|
}
|
|
|
|
unsubscribe(url: string, listener: Listener, onError?: ErrorListener): void {
|
|
this.listeners.get(url)?.delete(listener);
|
|
if (onError) {
|
|
this.errorListeners.get(url)?.delete(onError);
|
|
}
|
|
}
|
|
|
|
// eslint-disable-next-line
|
|
send(url: string, data: any): void {
|
|
const ws = this.sockets.get(url);
|
|
if (ws && this.connected.get(url)) {
|
|
ws.send(typeof data === 'string' ? data : JSON.stringify(data));
|
|
} else {
|
|
console.warn(`Cannot send: not connected to ${url}`);
|
|
this.triggerError(url, 'Not connected');
|
|
}
|
|
}
|
|
|
|
disconnect(url: string): void {
|
|
const ws = this.sockets.get(url);
|
|
if (ws) {
|
|
ws.close();
|
|
this.sockets.delete(url);
|
|
this.listeners.delete(url);
|
|
this.errorListeners.delete(url);
|
|
this.connected.delete(url);
|
|
}
|
|
}
|
|
|
|
disconnectAll(): void {
|
|
for (const url of this.sockets.keys()) {
|
|
this.disconnect(url);
|
|
}
|
|
}
|
|
|
|
private triggerError(url: string, err: Event | string): void {
|
|
const handlers = this.errorListeners.get(url);
|
|
if (handlers) {
|
|
for (const cb of handlers) {
|
|
try {
|
|
cb(err);
|
|
} catch (e) {
|
|
console.error(`Error handler threw for ${url}:`, e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export const socket = SocketManager.getInstance();
|