feat: add socket test route and echo event handler for debugging
This commit is contained in:
parent
12fdc6943c
commit
e2b06be6b6
5 changed files with 294 additions and 3 deletions
61
app/hooks/useDraftSocket.ts
Normal file
61
app/hooks/useDraftSocket.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import { io, Socket } from "socket.io-client";
|
||||
|
||||
interface UseDraftSocketReturn {
|
||||
socket: Socket | null;
|
||||
isConnected: boolean;
|
||||
on: (event: string, callback: (...args: any[]) => void) => void;
|
||||
off: (event: string, callback?: (...args: any[]) => void) => void;
|
||||
}
|
||||
|
||||
export function useDraftSocket(seasonId: string): UseDraftSocketReturn {
|
||||
const socketRef = useRef<Socket | null>(null);
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Connect to Socket.IO server
|
||||
const socket = io({
|
||||
path: "/socket.io",
|
||||
transports: ["websocket", "polling"],
|
||||
});
|
||||
|
||||
socketRef.current = socket;
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log("Connected to Socket.IO:", socket.id);
|
||||
setIsConnected(true);
|
||||
// Join the draft room
|
||||
socket.emit("join-draft", seasonId);
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
console.log("Disconnected from Socket.IO");
|
||||
setIsConnected(false);
|
||||
});
|
||||
|
||||
socket.on("connect_error", (error) => {
|
||||
console.error("Socket.IO connection error:", error);
|
||||
});
|
||||
|
||||
// Cleanup on unmount
|
||||
return () => {
|
||||
if (socket) {
|
||||
console.log("Leaving draft room:", seasonId);
|
||||
socket.emit("leave-draft", seasonId);
|
||||
socket.disconnect();
|
||||
}
|
||||
};
|
||||
}, [seasonId]);
|
||||
|
||||
// Helper to subscribe to events
|
||||
const on = (event: string, callback: (...args: any[]) => void) => {
|
||||
socketRef.current?.on(event, callback);
|
||||
};
|
||||
|
||||
// Helper to unsubscribe from events
|
||||
const off = (event: string, callback?: (...args: any[]) => void) => {
|
||||
socketRef.current?.off(event, callback);
|
||||
};
|
||||
|
||||
return { socket: socketRef.current, isConnected, on, off };
|
||||
}
|
||||
|
|
@ -10,7 +10,8 @@ export default [
|
|||
route("api/webhooks/clerk", "routes/api/webhooks/clerk.ts"),
|
||||
route("user-profile", "routes/user-profile.tsx"),
|
||||
route("how-to-play", "routes/how-to-play.tsx"),
|
||||
|
||||
route("test-socket", "routes/test-socket.tsx"),
|
||||
|
||||
// Admin routes
|
||||
route("admin", "routes/admin.tsx", [
|
||||
index("routes/admin._index.tsx"),
|
||||
|
|
@ -20,12 +21,18 @@ export default [
|
|||
route("sports-seasons", "routes/admin.sports-seasons.tsx"),
|
||||
route("sports-seasons/new", "routes/admin.sports-seasons.new.tsx"),
|
||||
route("sports-seasons/:id", "routes/admin.sports-seasons.$id.tsx"),
|
||||
route("sports-seasons/:id/participants", "routes/admin.sports-seasons.$id.participants.tsx"),
|
||||
route(
|
||||
"sports-seasons/:id/participants",
|
||||
"routes/admin.sports-seasons.$id.participants.tsx"
|
||||
),
|
||||
route("participants", "routes/admin.participants.tsx"),
|
||||
route("templates", "routes/admin.templates.tsx"),
|
||||
route("templates/new", "routes/admin.templates.new.tsx"),
|
||||
route("templates/:id", "routes/admin.templates.$id.tsx"),
|
||||
route("data-sync", "routes/admin.data-sync.tsx"),
|
||||
]),
|
||||
route("api/admin/export-sports-data", "routes/api.admin.export-sports-data.ts"),
|
||||
route(
|
||||
"api/admin/export-sports-data",
|
||||
"routes/api.admin.export-sports-data.ts"
|
||||
),
|
||||
] satisfies RouteConfig;
|
||||
|
|
|
|||
90
app/routes/test-socket.tsx
Normal file
90
app/routes/test-socket.tsx
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
import { useState, useEffect } from "react";
|
||||
import { useDraftSocket } from "~/hooks/useDraftSocket";
|
||||
|
||||
export default function TestSocket() {
|
||||
const [messages, setMessages] = useState<string[]>([]);
|
||||
const { socket, isConnected, on, off } = useDraftSocket("test-season-123");
|
||||
|
||||
useEffect(() => {
|
||||
// Listen for test messages
|
||||
const handleTestMessage = (data: any) => {
|
||||
console.log("Received test message:", data);
|
||||
setMessages((prev) => [...prev, JSON.stringify(data)]);
|
||||
};
|
||||
|
||||
on("test-message", handleTestMessage);
|
||||
|
||||
return () => {
|
||||
off("test-message", handleTestMessage);
|
||||
};
|
||||
}, [on, off]);
|
||||
|
||||
const sendTestMessage = () => {
|
||||
if (socket) {
|
||||
socket.emit("test-event", {
|
||||
message: "Hello from client!",
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
setMessages((prev) => [...prev, "Sent: Hello from client!"]);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="container mx-auto p-8">
|
||||
<h1 className="text-3xl font-bold mb-4">Socket.IO Test Page</h1>
|
||||
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`w-3 h-3 rounded-full ${
|
||||
isConnected ? "bg-green-500" : "bg-red-500"
|
||||
}`}
|
||||
/>
|
||||
<span className="font-semibold">
|
||||
Status: {isConnected ? "Connected" : "Disconnected"}
|
||||
</span>
|
||||
</div>
|
||||
{socket && (
|
||||
<p className="text-sm text-gray-600 mt-1">
|
||||
Socket ID: {socket.id}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={sendTestMessage}
|
||||
disabled={!isConnected}
|
||||
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:bg-gray-300 disabled:cursor-not-allowed"
|
||||
>
|
||||
Send Test Message
|
||||
</button>
|
||||
|
||||
<div className="mt-6">
|
||||
<h2 className="text-xl font-semibold mb-2">Messages:</h2>
|
||||
<div className="bg-gray-100 p-4 rounded max-h-96 overflow-y-auto">
|
||||
{messages.length === 0 ? (
|
||||
<p className="text-gray-500">No messages yet...</p>
|
||||
) : (
|
||||
<ul className="space-y-2">
|
||||
{messages.map((msg, idx) => (
|
||||
<li key={idx} className="text-sm font-mono bg-white p-2 rounded">
|
||||
{msg}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 p-4 bg-yellow-50 border border-yellow-200 rounded">
|
||||
<h3 className="font-semibold mb-2">Instructions:</h3>
|
||||
<ol className="list-decimal list-inside space-y-1 text-sm">
|
||||
<li>Check that the status shows "Connected"</li>
|
||||
<li>Open browser console to see connection logs</li>
|
||||
<li>Check server logs for "Client connected" message</li>
|
||||
<li>Click "Send Test Message" to test two-way communication</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
118
plans/phase-4-socket-test-instructions.md
Normal file
118
plans/phase-4-socket-test-instructions.md
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# Phase 4: Socket.IO Two-Way Communication Test
|
||||
|
||||
## What's Been Implemented:
|
||||
|
||||
### Server-Side (`server/socket.js`):
|
||||
- ✅ Listens for `test-event` from clients
|
||||
- ✅ Logs received message to console with 📨 emoji
|
||||
- ✅ Echoes back with `test-message` event containing:
|
||||
- Original client message
|
||||
- Server response: "Hello from server!"
|
||||
- Server timestamp
|
||||
- Socket ID
|
||||
- ✅ Logs sent response with ✅ emoji
|
||||
|
||||
### Client-Side (`app/routes/test-socket.tsx`):
|
||||
- ✅ Connects to Socket.IO server
|
||||
- ✅ Shows connection status (green dot = connected)
|
||||
- ✅ Displays Socket ID
|
||||
- ✅ "Send Test Message" button emits `test-event`
|
||||
- ✅ Listens for `test-message` responses
|
||||
- ✅ Displays all messages in a log
|
||||
|
||||
## How to Test:
|
||||
|
||||
### Step 1: Navigate to Test Page
|
||||
```
|
||||
http://localhost:3000/test-socket
|
||||
```
|
||||
|
||||
### Step 2: Verify Connection
|
||||
You should see:
|
||||
- ✅ Green dot with "Status: Connected"
|
||||
- ✅ Socket ID displayed (e.g., "Socket ID: abc123")
|
||||
|
||||
**Server Console Should Show:**
|
||||
```
|
||||
Client connected: abc123
|
||||
Socket abc123 joined draft-test-season-123
|
||||
```
|
||||
|
||||
### Step 3: Test Two-Way Communication
|
||||
|
||||
**Click the "Send Test Message" button**
|
||||
|
||||
**What Happens:**
|
||||
|
||||
1. **Client → Server:**
|
||||
- Client emits `test-event` with message and timestamp
|
||||
- Message appears in the Messages log: "Sent: Hello from client!"
|
||||
|
||||
2. **Server Logs:**
|
||||
```
|
||||
📨 Received test-event from client: abc123 { message: 'Hello from client!', timestamp: '...' }
|
||||
✅ Sent test-message response to client: abc123
|
||||
```
|
||||
|
||||
3. **Server → Client:**
|
||||
- Server emits `test-message` back to client
|
||||
- Client receives and displays the response in Messages log
|
||||
|
||||
4. **Browser Should Show:**
|
||||
```
|
||||
Sent: Hello from client!
|
||||
{"originalMessage":{"message":"Hello from client!","timestamp":"..."},"serverResponse":"Hello from server!","serverTimestamp":"...","socketId":"abc123"}
|
||||
```
|
||||
|
||||
### Step 4: Verify Multiple Messages
|
||||
- Click "Send Test Message" multiple times
|
||||
- Each click should:
|
||||
- Add a new message to the log
|
||||
- Show server response in console
|
||||
- Display echo response in browser
|
||||
|
||||
## Success Criteria:
|
||||
|
||||
✅ Connection established (green dot)
|
||||
✅ Socket ID displayed
|
||||
✅ Server logs show "Client connected"
|
||||
✅ Server logs show "joined draft-test-season-123"
|
||||
✅ Clicking button logs 📨 on server
|
||||
✅ Server logs ✅ after sending response
|
||||
✅ Browser displays both sent and received messages
|
||||
✅ Server response includes original message + server timestamp
|
||||
|
||||
## What This Proves:
|
||||
|
||||
1. ✅ **Client can connect to server** - WebSocket connection established
|
||||
2. ✅ **Client → Server** - Client can send events to server
|
||||
3. ✅ **Server receives events** - Server processes client messages
|
||||
4. ✅ **Server → Client** - Server can send events to specific clients
|
||||
5. ✅ **Client receives events** - Client processes server messages
|
||||
6. ✅ **Full round-trip** - Complete two-way communication working
|
||||
|
||||
## Next Steps:
|
||||
|
||||
Once this test passes, you're ready to:
|
||||
1. Implement draft room UI
|
||||
2. Add real-time pick broadcasting
|
||||
3. Implement timer updates
|
||||
4. Add queue management
|
||||
5. Deploy to production with confidence!
|
||||
|
||||
## Troubleshooting:
|
||||
|
||||
**If connection fails:**
|
||||
- Check server console for "Socket.IO initialized"
|
||||
- Check browser console for connection errors
|
||||
- Verify port 3000 is not blocked
|
||||
|
||||
**If messages don't appear:**
|
||||
- Check browser console for errors
|
||||
- Verify server logs show 📨 emoji
|
||||
- Check that `test-event` and `test-message` event names match
|
||||
|
||||
**If server doesn't respond:**
|
||||
- Restart dev server
|
||||
- Check server/socket.js has test-event handler
|
||||
- Verify no JavaScript errors in server console
|
||||
|
|
@ -46,6 +46,21 @@ export function initializeSocketIO(httpServer) {
|
|||
console.log(`Socket ${socket.id} left draft-${seasonId}`);
|
||||
});
|
||||
|
||||
// Test event handler - echo back with server timestamp
|
||||
socket.on("test-event", (data) => {
|
||||
console.log("📨 Received test-event from client:", socket.id, data);
|
||||
|
||||
// Echo back to the client with server response
|
||||
socket.emit("test-message", {
|
||||
originalMessage: data,
|
||||
serverResponse: "Hello from server!",
|
||||
serverTimestamp: new Date().toISOString(),
|
||||
socketId: socket.id,
|
||||
});
|
||||
|
||||
console.log("✅ Sent test-message response to client:", socket.id);
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
console.log("Client disconnected:", socket.id);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue