import { Server as SocketIOServer, Socket } from 'socket.io'; import { upsertPixels, getAllPixels, db } from './database'; import { Cursor, Pixel } from '../shared/types'; import passport from 'passport'; function generateRandomColor(): string { const colors = [ '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7', '#DDA0DD', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E2' ]; return colors[Math.floor(Math.random() * colors.length)]; } interface UserSocket extends Socket { userId: string; username: string; color: string; user?: any; } // Helper function to get user data from db function getUserById(userId: number) { try { const stmt = db.prepare('SELECT * FROM users WHERE id = ?'); return stmt.get(userId); } catch (error) { console.error('Error fetching user:', error); return null; } } export function setupSocketIO(io: SocketIOServer): void { const connectedUsers = new Map(); io.on('connection', (socket: Socket) => { const userSocket = socket as UserSocket; socket.on('join-canvas', (token: string) => { try { const decoded = JSON.parse(Buffer.from(token, 'base64').toString()); if (Date.now() - decoded.timestamp > 5 * 60 * 1000) { socket.emit('error', 'Token expired'); socket.disconnect(); return; } const userData = getUserById(decoded.userId); if (userData) { userSocket.user = userData; const userId = `auth_${userData.id}`; const username = userData.username || userData.display_name; const color = generateRandomColor(); connectedUsers.set(userId, { x: 0, y: 0, color: color, username: username, userId: userData.id.toString() }); socket.emit('canvas-state', getAllPixels()); socket.emit('cursor-update', Array.from(connectedUsers.values())); socket.emit('auth-success', { user: userData }); socket.broadcast.emit('cursor-update', Array.from(connectedUsers.values())); socket.on('cursor-move', (cursor: Cursor) => { const user = connectedUsers.get(userId); if (user) { user.x = cursor.x; user.y = cursor.y; socket.broadcast.emit('cursor-update', Array.from(connectedUsers.values())); } }); socket.on('paint-pixels', async (pixels: Pixel[]) => { try { if (!userSocket.user) { socket.emit('error', 'Authentication required to paint pixels'); return; } upsertPixels(pixels); socket.broadcast.emit('canvas-update', { pixels }); } catch (error) { console.error('Error saving pixels:', error); socket.emit('error', 'Failed to save pixels'); } }); socket.on('disconnect', () => { connectedUsers.delete(userId); socket.broadcast.emit('cursor-update', Array.from(connectedUsers.values())); }); } else { console.error('User not found for token:', decoded.userId); socket.emit('error', 'Invalid user'); socket.disconnect(); } } catch (error) { console.error('Token verification failed:', error); socket.emit('error', 'Invalid token'); socket.disconnect(); } }); }); }