k-l-lambda's picture
updated
502af73
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;
}
}