feature/IO-3096-GlobalNotifications - Check-point

This commit is contained in:
Dave Richer
2025-02-10 11:24:20 -05:00
parent 6d343e9b7f
commit ba2d03176f
8 changed files with 203 additions and 51 deletions

View File

@@ -2,7 +2,13 @@ const { admin } = require("../firebase/firebase-handler");
const redisSocketEvents = ({
io,
redisHelpers: { setSessionData, clearSessionData }, // Note: Used if we persist user to Redis
redisHelpers: {
setSessionData,
clearSessionData,
addUserSocketMapping,
removeUserSocketMapping,
getUserSocketMapping
}, // Note: Used if we persist user to Redis
ioHelpers: { getBodyshopRoom, getBodyshopConversationRoom },
logger
}) => {
@@ -12,30 +18,20 @@ const redisSocketEvents = ({
};
// Socket Auth Middleware
const authMiddleware = (socket, next) => {
const authMiddleware = async (socket, next) => {
if (!socket.handshake.auth.token) {
return next(new Error("Authentication error - no authorization token."));
}
try {
if (socket.handshake.auth.token) {
admin
.auth()
.verifyIdToken(socket.handshake.auth.token)
.then((user) => {
socket.user = user;
// Note: if we ever want to capture user data across sockets
// Uncomment the following line and then remove the next() to a second then()
// return setSessionData(socket.id, "user", user);
next();
})
.catch((error) => {
next(new Error(`Authentication error: ${error.message}`));
});
} else {
next(new Error("Authentication error - no authorization token."));
}
const user = await admin.auth().verifyIdToken(socket.handshake.auth.token);
socket.user = user;
// Persist the user data in Redis for this socket
await setSessionData(socket.id, "user", user);
// Store a mapping from the user's email to the socket id
// await addUserSocketMapping(user.email, socket.id);
next();
} catch (error) {
logger.log("websocket-connection-error", "error", null, null, {
...error
});
next(new Error(`Authentication error ${error}`));
next(new Error(`Authentication error: ${error.message}`));
}
};
@@ -44,6 +40,10 @@ const redisSocketEvents = ({
// Uncomment for further testing
// createLogEvent(socket, "debug", `Registering RedisIO Socket Events.`);
getUserSocketMapping(socket.user.email).then((socketIds) => {
console.log(socketIds);
});
// Token Update Events
const registerUpdateEvents = (socket) => {
let latestTokenTimestamp = 0;
@@ -53,37 +53,29 @@ const redisSocketEvents = ({
latestTokenTimestamp = currentTimestamp;
try {
// Verify token with Firebase Admin SDK
const user = await admin.auth().verifyIdToken(newToken, true);
// Skip outdated token validations
if (currentTimestamp < latestTokenTimestamp) {
createLogEvent(socket, "warn", "Outdated token validation skipped.");
return;
}
socket.user = user;
// Update the session data in Redis with the new token info
// await setSessionData(socket.id, "user", user);
// Update the mapping with the user's email
// await addUserSocketMapping(user.email, socket.id);
createLogEvent(socket, "debug", `Token updated successfully for socket ID: ${socket.id}`);
socket.emit("token-updated", { success: true });
} catch (error) {
if (error.code === "auth/id-token-expired") {
createLogEvent(socket, "warn", "Stale token received, waiting for new token");
socket.emit("token-updated", {
success: false,
error: "Stale token."
});
return; // Avoid disconnecting for expired tokens
socket.emit("token-updated", { success: false, error: "Stale token." });
return;
}
createLogEvent(socket, "error", `Token update failed for socket ID: ${socket.id}, Error: ${error.message}`);
socket.emit("token-updated", { success: false, error: error.message });
// Optionally disconnect for invalid tokens or other errors
socket.disconnect();
}
};
socket.on("update-token", updateToken);
};
@@ -127,16 +119,20 @@ const redisSocketEvents = ({
// Disconnect Events
const registerDisconnectEvents = (socket) => {
const disconnect = () => {
// Uncomment for further testing
// createLogEvent(socket, "debug", `User disconnected.`);
const disconnect = async () => {
// Remove session data from Redis
// await clearSessionData(socket.id);
// Remove the mapping from user email to this socket id, if available
// if (socket.user?.email) {
// await removeUserSocketMapping(socket.user.email, socket.id);
// }
// Leave all joined rooms
const rooms = Array.from(socket.rooms).filter((room) => room !== socket.id);
for (const room of rooms) {
socket.leave(room);
}
// If we ever want to persist the user across workers
// clearSessionData(socket.id);
};
socket.on("disconnect", disconnect);