UNPKG

@ngenux/ngage-whiteboarding

Version:

A collaborative whiteboard React component with real-time synchronization

178 lines (174 loc) 6.58 kB
'use strict'; var socket_ioClient = require('socket.io-client'); let socket = null; const joinedRooms = new Set(); const setupCallbacks = new Map(); let currentWebSocketUrl = undefined; // Initialize socket connection const initializeSocket = (webSocketUrl) => { // Use provided webSocketUrl or fallback to environment variable for backward compatibility const socketServerUrl = webSocketUrl || undefined?.VITE_WEBSOCKET_URL || ""; // If URL has changed or socket doesn't exist, create new connection if (!socket || (webSocketUrl && currentWebSocketUrl !== webSocketUrl)) { // Disconnect existing socket if URL changed if (socket && currentWebSocketUrl !== webSocketUrl) { socket.disconnect(); socket = null; joinedRooms.clear(); setupCallbacks.clear(); } currentWebSocketUrl = webSocketUrl; console.log('[SOCKET] Using socket server URL:', socketServerUrl); if (!socketServerUrl) { console.error('[SOCKET] No socket server URL provided'); } socket = socket_ioClient.io(socketServerUrl, { transports: ['websocket'], reconnection: true, reconnectionAttempts: 5, reconnectionDelay: 1000, }); socket.on('connect', () => { console.log('[SOCKET] Connected to server'); // Re-join all rooms after reconnection joinedRooms.forEach(roomId => { socket.emit('join-room', roomId); console.log('[SOCKET] Re-joined room:', roomId); }); }); socket.on('disconnect', () => { console.log('[SOCKET] Disconnected from server'); }); socket.on('connect_error', (error) => { console.error('[SOCKET] Connection error:', error); }); // Set up the global receive-message listener once socket.on('receive-message', (message) => { const callback = setupCallbacks.get(message.roomId); if (callback) { console.log('[SOCKET] Received message from room:', message.roomId, { compression: message.data.compressionType, originalSize: message.data.originalSize, compressedSize: message.data.compressedSize, from: message.from }); callback(message.data); } }); } return socket; }; const onSend = (roomId, data, webSocketUrl) => { const socketInstance = initializeSocket(webSocketUrl); // Check if socket is connected before sending if (!socketInstance.connected) { console.warn('[SOCKET] Socket not connected, cannot send message'); return; } const message = { roomId, data, timestamp: Date.now(), }; console.log('[SOCKET] Sending message to room:', roomId, { compression: data.compressionType, originalSize: data.originalSize, compressedSize: data.compressedSize, connected: socketInstance.connected, socketId: socketInstance.id, }); try { socketInstance.emit('send-message', message); console.log('[SOCKET] Message sent successfully'); } catch (error) { console.error('[SOCKET] Error sending message:', error); } }; const onReceive = (roomId, callback, webSocketUrl) => { const socketInstance = initializeSocket(webSocketUrl); // Store the callback for this room setupCallbacks.set(roomId, callback); // Only join the room if we haven't already if (!joinedRooms.has(roomId)) { socketInstance.emit('join-room', roomId); joinedRooms.add(roomId); console.log('[SOCKET] Joined room:', roomId); } else { console.log('[SOCKET] Already in room:', roomId); } }; const leaveRoom = (roomId) => { if (socket && joinedRooms.has(roomId)) { socket.emit('leave-room', roomId); joinedRooms.delete(roomId); setupCallbacks.delete(roomId); console.log('[SOCKET] Left room:', roomId); } }; const disconnectSocket = () => { if (socket) { socket.disconnect(); socket = null; joinedRooms.clear(); setupCallbacks.clear(); console.log('[SOCKET] Socket disconnected and cleaned up'); } }; // Get current socket connection status const isSocketConnected = () => { return socket?.connected ?? false; }; // Get current socket instance const getSocket = () => { return socket; }; // Subscribe to connection status changes const onSocketStatusChange = (callback) => { const socketInstance = socket || initializeSocket(); const handleConnect = () => callback(true); const handleDisconnect = () => callback(false); socketInstance.on('connect', handleConnect); socketInstance.on('disconnect', handleDisconnect); // Return unsubscribe function return () => { socketInstance.off('connect', handleConnect); socketInstance.off('disconnect', handleDisconnect); }; }; const waitForSocket = (webSocketUrl, timeoutMs = 5000) => { return new Promise((resolve) => { const socketInstance = initializeSocket(webSocketUrl); // If already connected, resolve immediately if (socketInstance.connected) { console.log('[SOCKET] Socket already connected, resolving immediately'); resolve(); return; } console.log('[SOCKET] Waiting for socket connection (timeout: ' + timeoutMs + 'ms)'); // Listen for connect event const handleConnect = () => { console.log('[SOCKET] Socket connection established'); socketInstance.off('connect', handleConnect); clearTimeout(timeoutHandle); resolve(); }; socketInstance.on('connect', handleConnect); // Safety net: resolve after timeout regardless const timeoutHandle = setTimeout(() => { console.log('[SOCKET] Connection timeout reached - resolving anyway (safety net)'); socketInstance.off('connect', handleConnect); resolve(); }, timeoutMs); }); }; exports.disconnectSocket = disconnectSocket; exports.getSocket = getSocket; exports.isSocketConnected = isSocketConnected; exports.leaveRoom = leaveRoom; exports.onReceive = onReceive; exports.onSend = onSend; exports.onSocketStatusChange = onSocketStatusChange; exports.waitForSocket = waitForSocket; //# sourceMappingURL=socket-utility.js.map