const path = require("path"); require("dotenv").config({ path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) }); const logger = require("../utils/logger"); const { admin } = require("../firebase/firebase-handler"); // Logging helper functions function createLogEvent(socket, level, message) { console.log(`[IOREDIS LOG EVENT] - ${socket.user.email} - ${socket.id} - ${message}`); logger.log("ioredis-log-event", level, socket.user.email, null, { wsmessage: message }); } const registerUpdateEvents = (socket) => { socket.on("update-token", async (newToken) => { try { socket.user = await admin.auth().verifyIdToken(newToken); createLogEvent(socket, "INFO", "Token updated successfully"); socket.emit("token-updated", { success: true }); } catch (error) { createLogEvent(socket, "ERROR", `Token update failed: ${error.message}`); socket.emit("token-updated", { success: false, error: error.message }); // Optionally disconnect the socket if token verification fails socket.disconnect(); } }); }; const redisSocketEvents = (io, { addUserToRoom, getUsersInRoom, removeUserFromRoom }, { getBodyshopRoom }) => { // Room management and broadcasting events function registerRoomAndBroadcastEvents(socket) { socket.on("join-bodyshop-room", async (bodyshopUUID) => { try { const room = getBodyshopRoom(bodyshopUUID); socket.join(room); await addUserToRoom(room, { uid: socket.user.uid, email: socket.user.email, socket: socket.id }); createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${room}`); // Notify all users in the room about the updated user list const usersInRoom = await getUsersInRoom(room); io.to(room).emit("room-users-updated", usersInRoom); } catch (error) { createLogEvent(socket, "ERROR", `Error joining room: ${error}`); } }); socket.on("leave-bodyshop-room", async (bodyshopUUID) => { try { const room = getBodyshopRoom(bodyshopUUID); socket.leave(room); createLogEvent(socket, "DEBUG", `Client left bodyshop room: ${room}`); } catch (error) { createLogEvent(socket, "ERROR", `Error joining room: ${error}`); } }); socket.on("get-room-users", async (bodyshopUUID, callback) => { try { const usersInRoom = await getUsersInRoom(getBodyshopRoom(bodyshopUUID)); callback(usersInRoom); } catch (error) { createLogEvent(socket, "ERROR", `Error getting room: ${error}`); } }); socket.on("broadcast-to-bodyshop", async (bodyshopUUID, message) => { try { const room = getBodyshopRoom(bodyshopUUID); io.to(room).emit("bodyshop-message", message); createLogEvent(socket, "INFO", `Broadcast message to bodyshop ${room}`); } catch (error) { createLogEvent(socket, "ERROR", `Error getting room: ${error}`); } }); socket.on("disconnect", async () => { try { createLogEvent(socket, "DEBUG", `User disconnected.`); // Get all rooms the socket is part of const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id); for (const room of rooms) { await removeUserFromRoom(room, { uid: socket.user.uid, email: socket.user.email, socket: socket.id }); } } catch (error) { createLogEvent(socket, "ERROR", `Error getting room: ${error}`); } }); } // Register all socket events for a given socket connection function registerSocketEvents(socket) { createLogEvent(socket, "DEBUG", `Registering RedisIO Socket Events.`); // Register room and broadcasting events registerRoomAndBroadcastEvents(socket); registerUpdateEvents(socket); } const authMiddleware = (socket, next) => { try { if (socket.handshake.auth.token) { admin .auth() .verifyIdToken(socket.handshake.auth.token) .then((user) => { socket.user = user; next(); }) .catch((error) => { next(new Error(`Authentication error: ${error.message}`)); }); } else { next(new Error("Authentication error - no authorization token.")); } } catch (error) { console.log("Uncaught connection error:::", error); logger.log("websocket-connection-error", "error", null, null, { ...error }); next(new Error(`Authentication error ${error}`)); } }; // Socket.IO Middleware and Connection io.use(authMiddleware); io.on("connection", registerSocketEvents); }; module.exports = { redisSocketEvents };