csa-backend-test/app/services/socket.services.js

148 lines
4.7 KiB
JavaScript

const { PrismaClient: MSGClient } = require("../../prisma/clients/msg");
const logger = require("./logger.services.js");
const msgPrisma = new MSGClient();
class SocketService {
constructor(io) {
this.io = io;
this.setupSocketHandlers();
}
setupSocketHandlers() {
this.io.on('connection', (socket) => {
logger.info(`New client connected: ${socket.id}`);
socket.on('join_conversation', (data) => {
this.handleJoinConversation(socket, data);
});
socket.on('send_message', async (data) => {
await this.handleSendMessage(socket, data);
});
socket.on('typing_start', (data) => {
this.handleTypingStart(socket, data);
});
socket.on('typing_stop', (data) => {
this.handleTypingStop(socket, data);
});
socket.on('disconnect', () => {
this.handleDisconnect(socket);
});
});
}
handleJoinConversation(socket, data) {
const { conversationId, userId, userType } = data;
socket.join(conversationId);
socket.userId = userId;
socket.userType = userType;
logger.info(`${userType} ${userId} joined conversation ${conversationId}`);
socket.to(conversationId).emit('user_joined', {
userId,
userType,
message: `${userType} joined the conversation`
});
}
async handleSendMessage(socket, data) {
try {
const { conversationId, message, senderId, senderType, messageType = 'text' } = data;
const savedMessage = await this.saveMessageToDatabase({
conversationId,
message,
senderId,
senderType,
messageType
});
this.io.to(conversationId).emit('receive_message', savedMessage);
logger.info(`Message sent in conversation ${conversationId} by ${senderType} ${senderId}`);
} catch (error) {
logger.error('Error sending message:', error);
socket.emit('message_error', {
error: 'Failed to send message',
details: error.message
});
}
}
handleTypingStart(socket, data) {
const { conversationId, userId, userType } = data;
socket.to(conversationId).emit('user_typing', { userId, userType });
}
handleTypingStop(socket, data) {
const { conversationId, userId, userType } = data;
socket.to(conversationId).emit('user_stopped_typing', { userId, userType });
}
handleDisconnect(socket) {
logger.info(`Client disconnected: ${socket.id}`);
if (socket.userId && socket.userType) {
// You might want to emit to specific rooms the user was in
// This would require tracking which rooms the user was in
}
}
async saveMessageToDatabase(messageData) {
try {
const message = await msgPrisma.messages.create({
data: {
conversationId: messageData.conversationId,
content: messageData.message,
messageType: messageData.messageType || 'text',
senderId: messageData.senderId,
senderType: messageData.senderType,
senderName: messageData.senderName,
status: 'sent',
metadata: messageData.metadata || {}
},
include: {
conversation: true
}
});
await msgPrisma.conversations.update({
where: { id: messageData.conversationId },
data: { lastMessageAt: new Date() }
});
return {
id: message.id,
conversationId: message.conversationId,
message: message.content,
senderId: message.senderId,
senderType: message.senderType,
senderName: message.senderName,
messageType: message.messageType,
timestamp: message.createdAt.toISOString(),
status: message.status
};
} catch (error) {
logger.error('Error saving message to database:', error);
throw error;
}
}
sendMessageToConversation(conversationId, messageData) {
this.io.to(conversationId).emit('receive_message', messageData);
}
sendNotificationToUser(userId, notificationData) {
this.io.emit('notification', {
userId,
...notificationData
});
}
}
module.exports = SocketService;