Spaces:
Running
Running
Commit
·
cccfc29
1
Parent(s):
5d855d2
echo test
Browse files
trigo-web/app/src/composables/useSocket.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { ref, onUnmounted } from "vue";
|
| 2 |
+
import { io, Socket } from "socket.io-client";
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
// Singleton socket instance
|
| 6 |
+
let socketInstance: Socket | null = null;
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
export function useSocket() {
|
| 10 |
+
const connected = ref(false);
|
| 11 |
+
const error = ref<string | null>(null);
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
// Get or create socket instance
|
| 15 |
+
const getSocket = (): Socket => {
|
| 16 |
+
if (!socketInstance) {
|
| 17 |
+
// Determine the server URL based on environment
|
| 18 |
+
const isDev = import.meta.env?.DEV ?? (import.meta.env?.MODE === "development");
|
| 19 |
+
const serverUrl = isDev
|
| 20 |
+
? "http://localhost:3000" // Development: backend port
|
| 21 |
+
: window.location.origin; // Production: same origin
|
| 22 |
+
|
| 23 |
+
socketInstance = io(serverUrl, {
|
| 24 |
+
autoConnect: true,
|
| 25 |
+
reconnection: true,
|
| 26 |
+
reconnectionDelay: 1000,
|
| 27 |
+
reconnectionAttempts: 5
|
| 28 |
+
});
|
| 29 |
+
|
| 30 |
+
// Connection event handlers
|
| 31 |
+
socketInstance.on("connect", () => {
|
| 32 |
+
connected.value = true;
|
| 33 |
+
error.value = null;
|
| 34 |
+
console.log("[Socket.io] Connected:", socketInstance?.id);
|
| 35 |
+
});
|
| 36 |
+
|
| 37 |
+
socketInstance.on("disconnect", (reason) => {
|
| 38 |
+
connected.value = false;
|
| 39 |
+
console.log("[Socket.io] Disconnected:", reason);
|
| 40 |
+
});
|
| 41 |
+
|
| 42 |
+
socketInstance.on("connect_error", (err) => {
|
| 43 |
+
error.value = err.message;
|
| 44 |
+
console.error("[Socket.io] Connection error:", err.message);
|
| 45 |
+
});
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
return socketInstance;
|
| 49 |
+
};
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
// Send echo test message
|
| 53 |
+
const sendEcho = (message: string): Promise<string> => {
|
| 54 |
+
return new Promise((resolve, reject) => {
|
| 55 |
+
const socket = getSocket();
|
| 56 |
+
|
| 57 |
+
if (!socket.connected) {
|
| 58 |
+
reject(new Error("Socket not connected"));
|
| 59 |
+
return;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
// Send echo request and wait for response
|
| 63 |
+
socket.emit("echo", { message, timestamp: new Date().toISOString() }, (response: any) => {
|
| 64 |
+
if (response.error) {
|
| 65 |
+
reject(new Error(response.error));
|
| 66 |
+
} else {
|
| 67 |
+
resolve(response.message);
|
| 68 |
+
}
|
| 69 |
+
});
|
| 70 |
+
|
| 71 |
+
// Timeout after 5 seconds
|
| 72 |
+
setTimeout(() => {
|
| 73 |
+
reject(new Error("Echo request timeout"));
|
| 74 |
+
}, 5000);
|
| 75 |
+
});
|
| 76 |
+
};
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
// Clean up on unmount
|
| 80 |
+
onUnmounted(() => {
|
| 81 |
+
// Note: We don't disconnect the singleton instance
|
| 82 |
+
// It will be reused by other components
|
| 83 |
+
});
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
return {
|
| 87 |
+
socket: getSocket(),
|
| 88 |
+
connected,
|
| 89 |
+
error,
|
| 90 |
+
sendEcho
|
| 91 |
+
};
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
// Export function to manually disconnect (for cleanup)
|
| 96 |
+
export function disconnectSocket() {
|
| 97 |
+
if (socketInstance) {
|
| 98 |
+
socketInstance.disconnect();
|
| 99 |
+
socketInstance = null;
|
| 100 |
+
}
|
| 101 |
+
}
|
trigo-web/app/src/views/TrigoView.vue
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
<template>
|
| 2 |
<div class="trigo-view">
|
| 3 |
<div class="view-header">
|
| 4 |
-
<div class="logo-container"
|
| 5 |
<img :src="logoImage" alt="Trigo Logo" class="app-logo" />
|
| 6 |
</div>
|
| 7 |
<div class="view-status">
|
|
@@ -202,6 +202,7 @@ import { Stone, validateMove, StoneType, validateTGN } from "../../../inc/trigo"
|
|
| 202 |
import { TrigoGameFrontend } from "@/utils/TrigoGameFrontend";
|
| 203 |
import { encodeAb0yz } from "../../../inc/trigo/ab0yz";
|
| 204 |
import logoImage from "@/assets/logo.png";
|
|
|
|
| 205 |
|
| 206 |
// Helper functions for board shape parsing
|
| 207 |
const parseBoardShape = (shapeStr: string): BoardShape => {
|
|
@@ -253,6 +254,11 @@ const tgnValidationState = ref<'idle' | 'valid' | 'invalid'>('idle');
|
|
| 253 |
const tgnValidationError = ref<string>('');
|
| 254 |
let tgnValidationTimeout: ReturnType<typeof setTimeout> | null = null;
|
| 255 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 256 |
// Canvas reference and viewport
|
| 257 |
const viewportCanvas = ref<HTMLCanvasElement | null>(null);
|
| 258 |
const moveHistoryContainer = ref<HTMLDivElement | null>(null);
|
|
@@ -440,6 +446,20 @@ const handleInspectGroup = (groupSize: number, liberties: number) => {
|
|
| 440 |
};
|
| 441 |
|
| 442 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 443 |
// Game control methods
|
| 444 |
const newGame = () => {
|
| 445 |
// Parse selected board shape
|
|
|
|
| 1 |
<template>
|
| 2 |
<div class="trigo-view">
|
| 3 |
<div class="view-header">
|
| 4 |
+
<div class="logo-container" @click="handleLogoClick">
|
| 5 |
<img :src="logoImage" alt="Trigo Logo" class="app-logo" />
|
| 6 |
</div>
|
| 7 |
<div class="view-status">
|
|
|
|
| 202 |
import { TrigoGameFrontend } from "@/utils/TrigoGameFrontend";
|
| 203 |
import { encodeAb0yz } from "../../../inc/trigo/ab0yz";
|
| 204 |
import logoImage from "@/assets/logo.png";
|
| 205 |
+
import { useSocket } from "@/composables/useSocket";
|
| 206 |
|
| 207 |
// Helper functions for board shape parsing
|
| 208 |
const parseBoardShape = (shapeStr: string): BoardShape => {
|
|
|
|
| 254 |
const tgnValidationError = ref<string>('');
|
| 255 |
let tgnValidationTimeout: ReturnType<typeof setTimeout> | null = null;
|
| 256 |
|
| 257 |
+
|
| 258 |
+
// Socket.io connection
|
| 259 |
+
const { sendEcho, connected: socketConnected } = useSocket();
|
| 260 |
+
|
| 261 |
+
|
| 262 |
// Canvas reference and viewport
|
| 263 |
const viewportCanvas = ref<HTMLCanvasElement | null>(null);
|
| 264 |
const moveHistoryContainer = ref<HTMLDivElement | null>(null);
|
|
|
|
| 446 |
};
|
| 447 |
|
| 448 |
|
| 449 |
+
// Handle logo click - WebSocket echo test
|
| 450 |
+
const handleLogoClick = async () => {
|
| 451 |
+
try {
|
| 452 |
+
console.log("[Echo Test] Sending echo request...");
|
| 453 |
+
console.log("[Echo Test] Socket connected:", socketConnected.value);
|
| 454 |
+
|
| 455 |
+
const response = await sendEcho("Echo test from Trigo!");
|
| 456 |
+
console.log("[Echo Test] Response:", response);
|
| 457 |
+
} catch (error) {
|
| 458 |
+
console.error("[Echo Test] Error:", error);
|
| 459 |
+
}
|
| 460 |
+
};
|
| 461 |
+
|
| 462 |
+
|
| 463 |
// Game control methods
|
| 464 |
const newGame = () => {
|
| 465 |
// Parse selected board shape
|
trigo-web/backend/src/server.ts
CHANGED
|
@@ -46,6 +46,23 @@ app.get("/health", (_req: any, res: any) => {
|
|
| 46 |
io.on("connection", (socket: any) => {
|
| 47 |
console.log(`New client connected: ${socket.id}`);
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
socket.on("disconnect", () => {
|
| 50 |
console.log(`Client disconnected: ${socket.id}`);
|
| 51 |
});
|
|
|
|
| 46 |
io.on("connection", (socket: any) => {
|
| 47 |
console.log(`New client connected: ${socket.id}`);
|
| 48 |
|
| 49 |
+
// Echo test handler
|
| 50 |
+
socket.on("echo", (data: any, callback: any) => {
|
| 51 |
+
const timestamp = new Date().toISOString();
|
| 52 |
+
const responseMessage = `Hello from server! Received: "${data.message}" at ${timestamp}`;
|
| 53 |
+
|
| 54 |
+
console.log(`[Echo] Client ${socket.id}: ${data.message}`);
|
| 55 |
+
|
| 56 |
+
// Send response via callback
|
| 57 |
+
if (callback && typeof callback === "function") {
|
| 58 |
+
callback({
|
| 59 |
+
message: responseMessage,
|
| 60 |
+
serverTime: timestamp,
|
| 61 |
+
clientTime: data.timestamp
|
| 62 |
+
});
|
| 63 |
+
}
|
| 64 |
+
});
|
| 65 |
+
|
| 66 |
socket.on("disconnect", () => {
|
| 67 |
console.log(`Client disconnected: ${socket.id}`);
|
| 68 |
});
|