Spaces:
Running
Running
| import { ref, onUnmounted } from "vue"; | |
| import { io, Socket } from "socket.io-client"; | |
| // Singleton socket instance | |
| let socketInstance: Socket | null = null; | |
| export function useSocket() { | |
| const connected = ref(false); | |
| const error = ref<string | null>(null); | |
| // Get or create socket instance | |
| const getSocket = (): Socket => { | |
| if (!socketInstance) { | |
| // Determine the server URL based on environment | |
| const isDev = import.meta.env?.DEV ?? import.meta.env?.MODE === "development"; | |
| let serverUrl: string; | |
| if (isDev) { | |
| // Development: Use same host as frontend, port 3000 | |
| // This allows accessing from local IP (e.g., 192.168.x.x:5173) | |
| const currentHost = window.location.hostname; | |
| serverUrl = `http://${currentHost}:3000`; | |
| } else { | |
| // Production: same origin | |
| serverUrl = window.location.origin; | |
| } | |
| console.log("[Socket.io] Connecting to:", serverUrl); | |
| socketInstance = io(serverUrl, { | |
| autoConnect: true, | |
| reconnection: true, | |
| reconnectionDelay: 1000, | |
| reconnectionAttempts: 5 | |
| }); | |
| // Connection event handlers | |
| socketInstance.on("connect", () => { | |
| connected.value = true; | |
| error.value = null; | |
| console.log("[Socket.io] Connected:", socketInstance?.id); | |
| }); | |
| socketInstance.on("disconnect", (reason) => { | |
| connected.value = false; | |
| console.log("[Socket.io] Disconnected:", reason); | |
| }); | |
| socketInstance.on("connect_error", (err) => { | |
| error.value = err.message; | |
| console.error("[Socket.io] Connection error:", err.message); | |
| }); | |
| } | |
| return socketInstance; | |
| }; | |
| // Send echo test message | |
| const sendEcho = (message: string): Promise<string> => { | |
| return new Promise((resolve, reject) => { | |
| const socket = getSocket(); | |
| if (!socket.connected) { | |
| reject(new Error("Socket not connected")); | |
| return; | |
| } | |
| // Send echo request and wait for response | |
| socket.emit( | |
| "echo", | |
| { message, timestamp: new Date().toISOString() }, | |
| (response: any) => { | |
| if (response.error) { | |
| reject(new Error(response.error)); | |
| } else { | |
| resolve(response.message); | |
| } | |
| } | |
| ); | |
| // Timeout after 5 seconds | |
| setTimeout(() => { | |
| reject(new Error("Echo request timeout")); | |
| }, 5000); | |
| }); | |
| }; | |
| // Clean up on unmount | |
| onUnmounted(() => { | |
| // Note: We don't disconnect the singleton instance | |
| // It will be reused by other components | |
| }); | |
| return { | |
| socket: getSocket(), | |
| connected, | |
| error, | |
| sendEcho | |
| }; | |
| } | |
| // Export function to manually disconnect (for cleanup) | |
| export function disconnectSocket() { | |
| if (socketInstance) { | |
| socketInstance.disconnect(); | |
| socketInstance = null; | |
| } | |
| } | |