import { Server, Socket } from 'socket.io' import jwt from 'jsonwebtoken' interface AuthenticatedSocket extends Socket { userId?: string user?: any } // Store active connections const activeConnections = new Map() export function setupSocketHandlers(io: Server) { // Authentication middleware io.use(async (socket: AuthenticatedSocket, next) => { try { const token = socket.handshake.auth.token || socket.handshake.headers.authorization?.replace('Bearer ', '') if (!token) { return next(new Error('Authentication error: No token provided')) } // TODO: Verify JWT token and get user // For now, just mock the authentication const decoded = { userId: 'user-1', email: 'user@example.com' } socket.userId = decoded.userId socket.user = decoded next() } catch (error) { next(new Error('Authentication error: Invalid token')) } }) io.on('connection', (socket: AuthenticatedSocket) => { console.log(`User ${socket.userId} connected`) // Store the connection if (socket.userId) { activeConnections.set(socket.userId, socket) } // Join user to their personal room if (socket.userId) { socket.join(`user:${socket.userId}`) } // Handle joining chat rooms socket.on('join_chat', (chatId: string) => { socket.join(`chat:${chatId}`) console.log(`User ${socket.userId} joined chat ${chatId}`) }) // Handle leaving chat rooms socket.on('leave_chat', (chatId: string) => { socket.leave(`chat:${chatId}`) console.log(`User ${socket.userId} left chat ${chatId}`) }) // Handle sending messages socket.on('send_message', async (data: { chatId: string content: string type?: string replyTo?: string }) => { try { // TODO: Save message to database const message = { id: `msg-${Date.now()}`, chatId: data.chatId, senderId: socket.userId, content: data.content, type: data.type || 'text', replyTo: data.replyTo, createdAt: new Date(), sender: socket.user } // Broadcast to all users in the chat socket.to(`chat:${data.chatId}`).emit('new_message', message) // Send confirmation back to sender socket.emit('message_sent', { messageId: message.id, status: 'sent' }) console.log(`Message sent in chat ${data.chatId} by user ${socket.userId}`) } catch (error) { socket.emit('error', { message: 'Failed to send message' }) } }) // Handle typing indicators socket.on('typing_start', (chatId: string) => { socket.to(`chat:${chatId}`).emit('user_typing', { userId: socket.userId, chatId, isTyping: true }) }) socket.on('typing_stop', (chatId: string) => { socket.to(`chat:${chatId}`).emit('user_typing', { userId: socket.userId, chatId, isTyping: false }) }) // Handle message reactions socket.on('add_reaction', async (data: { messageId: string emoji: string }) => { try { // TODO: Save reaction to database const reaction = { messageId: data.messageId, userId: socket.userId, emoji: data.emoji, createdAt: new Date() } // Broadcast to all connected users io.emit('reaction_added', reaction) console.log(`Reaction ${data.emoji} added to message ${data.messageId} by user ${socket.userId}`) } catch (error) { socket.emit('error', { message: 'Failed to add reaction' }) } }) // Handle message status updates socket.on('message_read', async (data: { messageId: string chatId: string }) => { try { // TODO: Update message read status in database // Notify sender that message was read socket.to(`chat:${data.chatId}`).emit('message_status_updated', { messageId: data.messageId, status: 'read', readBy: socket.userId, readAt: new Date() }) console.log(`Message ${data.messageId} marked as read by user ${socket.userId}`) } catch (error) { socket.emit('error', { message: 'Failed to update message status' }) } }) // Handle user presence socket.on('update_presence', (status: 'online' | 'away' | 'busy' | 'offline') => { // TODO: Update user presence in database // Broadcast presence update to all connected users socket.broadcast.emit('user_presence_updated', { userId: socket.userId, status, lastSeen: new Date() }) console.log(`User ${socket.userId} presence updated to ${status}`) }) // Handle disconnection socket.on('disconnect', (reason) => { console.log(`User ${socket.userId} disconnected: ${reason}`) // Remove from active connections if (socket.userId) { activeConnections.delete(socket.userId) } // Update user presence to offline socket.broadcast.emit('user_presence_updated', { userId: socket.userId, status: 'offline', lastSeen: new Date() }) }) // Handle errors socket.on('error', (error) => { console.error(`Socket error for user ${socket.userId}:`, error) }) }) // Helper function to send message to specific user const sendToUser = (userId: string, event: string, data: any) => { const userSocket = activeConnections.get(userId) if (userSocket) { userSocket.emit(event, data) return true } return false } // Helper function to send message to chat const sendToChat = (chatId: string, event: string, data: any) => { io.to(`chat:${chatId}`).emit(event, data) } // Export helper functions for use in other parts of the application return { sendToUser, sendToChat, getActiveConnections: () => activeConnections, getConnectionCount: () => activeConnections.size } }