UNPKG

image-asset-manager

Version:

A comprehensive image asset management tool for frontend projects

223 lines 7.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebSocketClient = void 0; exports.createWebSocketClient = createWebSocketClient; exports.useWebSocketClient = useWebSocketClient; class WebSocketClient { constructor(options) { this.ws = null; this.handlers = {}; this.reconnectAttempts = 0; this.reconnectTimer = null; this.pingTimer = null; this.isConnected = false; this.isReconnecting = false; this.options = { reconnectInterval: 3000, maxReconnectAttempts: 10, pingInterval: 30000, ...options, }; } connect() { if (this.ws && this.ws.readyState === WebSocket.OPEN) { console.log("📡 WebSocket already connected"); return; } try { console.log(`📡 Connecting to WebSocket: ${this.options.url}`); this.ws = new WebSocket(this.options.url); this.setupEventHandlers(); } catch (error) { console.error("📡 Failed to create WebSocket connection:", error); this.scheduleReconnect(); } } disconnect() { this.isReconnecting = false; this.clearTimers(); if (this.ws) { this.ws.close(1000, "Client disconnect"); this.ws = null; } this.isConnected = false; console.log("📡 WebSocket disconnected"); } setupEventHandlers() { if (!this.ws) return; this.ws.onopen = () => { console.log("📡 WebSocket connected"); this.isConnected = true; this.isReconnecting = false; this.reconnectAttempts = 0; this.handlers.onConnect?.(); this.startPing(); }; this.ws.onclose = (event) => { console.log(`📡 WebSocket closed: ${event.code} - ${event.reason}`); this.isConnected = false; this.clearTimers(); this.handlers.onDisconnect?.(); // Attempt to reconnect unless it was a clean close if (event.code !== 1000 && !this.isReconnecting) { this.scheduleReconnect(); } }; this.ws.onerror = (error) => { console.error("📡 WebSocket error:", error); this.handlers.onError?.(error); }; this.ws.onmessage = (event) => { try { const message = JSON.parse(event.data); this.handleMessage(message); } catch (error) { console.error("📡 Failed to parse WebSocket message:", error); } }; } handleMessage(message) { // Call general message handler this.handlers.onMessage?.(message); // Call specific handlers based on message type switch (message.type) { case "initial-data": console.log("📡 Received initial data:", message.data); break; case "file-change": console.log("📡 File change detected:", message.data); this.handlers.onFileChange?.(message.data); break; case "stats-update": console.log("📡 Stats updated:", message.data); this.handlers.onStatsUpdate?.(message.data); break; case "data-updated": console.log("📡 Data updated:", message.data); this.handlers.onDataUpdated?.(message.data); break; case "pong": // Server responded to ping break; default: console.log(`📡 Received message: ${message.type}`, message.data); } } scheduleReconnect() { if (this.isReconnecting || this.reconnectAttempts >= this.options.maxReconnectAttempts) { if (this.reconnectAttempts >= this.options.maxReconnectAttempts) { console.error("📡 Max reconnection attempts reached"); } return; } this.isReconnecting = true; this.reconnectAttempts++; console.log(`📡 Scheduling reconnect attempt ${this.reconnectAttempts}/${this.options.maxReconnectAttempts} in ${this.options.reconnectInterval}ms`); this.reconnectTimer = setTimeout(() => { this.connect(); }, this.options.reconnectInterval); } startPing() { this.pingTimer = setInterval(() => { if (this.isConnected && this.ws?.readyState === WebSocket.OPEN) { this.send("ping", { timestamp: Date.now() }); } }, this.options.pingInterval); } clearTimers() { if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; } if (this.pingTimer) { clearInterval(this.pingTimer); this.pingTimer = null; } } send(type, data) { if (!this.ws || this.ws.readyState !== WebSocket.OPEN) { console.warn("📡 Cannot send message: WebSocket not connected"); return; } const message = { type, data, timestamp: Date.now(), }; try { this.ws.send(JSON.stringify(message)); } catch (error) { console.error("📡 Failed to send WebSocket message:", error); } } // Convenience methods for common operations subscribe(events) { this.send("subscribe", { events }); } requestData(type, params) { this.send("request-data", { type, ...params }); } requestImages(page = 1, limit = 20, filters = {}) { this.requestData("images", { page, limit, filters }); } requestStats() { this.requestData("stats"); } requestDuplicates() { this.requestData("duplicates"); } // Event handler registration on(event, handler) { this.handlers[event] = handler; } off(event) { delete this.handlers[event]; } // Status getters isConnectedStatus() { return this.isConnected; } getReconnectAttempts() { return this.reconnectAttempts; } getReadyState() { return this.ws?.readyState ?? WebSocket.CLOSED; } } exports.WebSocketClient = WebSocketClient; // Factory function for easy instantiation function createWebSocketClient(port = 3000, handlers = {}) { const client = new WebSocketClient({ url: `ws://localhost:${port}/ws`, }); // Register handlers Object.entries(handlers).forEach(([event, handler]) => { client.on(event, handler); }); return client; } // Example usage for React components function useWebSocketClient(port = 3000) { const client = new WebSocketClient({ url: `ws://localhost:${port}/ws`, }); const connect = () => client.connect(); const disconnect = () => client.disconnect(); const send = (type, data) => client.send(type, data); const subscribe = (events) => client.subscribe(events); return { client, connect, disconnect, send, subscribe, isConnected: () => client.isConnectedStatus(), on: (event, handler) => client.on(event, handler), }; } //# sourceMappingURL=WebSocketClient.js.map