cnmksjs's picture
Upload 60 files
e3eb984 verified
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<string, AuthenticatedSocket>()
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
}
}