270 lines
9.5 KiB
JavaScript
270 lines
9.5 KiB
JavaScript
const path = require("path");
|
|
require("dotenv").config({
|
|
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
|
|
});
|
|
|
|
const {
|
|
io,
|
|
setSessionData,
|
|
clearSessionData,
|
|
getMultipleSessionData,
|
|
addItemToEndOfList,
|
|
pubClient
|
|
} = require("../../server");
|
|
|
|
const { admin } = require("../firebase/firebase-handler");
|
|
const logger = require("../utils/logger");
|
|
const { default: CdkJobExport, CdkSelectedCustomer } = require("../cdk/cdk-job-export");
|
|
const CdkGetMakes = require("../cdk/cdk-get-makes").default;
|
|
const CdkCalculateAllocations = require("../cdk/cdk-calculate-allocations").default;
|
|
const { default: PbsExportJob, PbsSelectedCustomer } = require("../accounting/pbs/pbs-job-export");
|
|
const { PbsCalculateAllocationsAp, PbsExportAp } = require("../accounting/pbs/pbs-ap-allocations");
|
|
|
|
// Middleware for verifying tokens via Firebase authentication
|
|
function socketAuthMiddleware(socket, next) {
|
|
const token = socket.handshake.auth.token;
|
|
|
|
if (!token) return next(new Error("Authentication error - no authorization token."));
|
|
|
|
admin
|
|
.auth()
|
|
.verifyIdToken(token)
|
|
.then((user) => {
|
|
socket.user = user;
|
|
next();
|
|
})
|
|
.catch((error) => {
|
|
next(new Error("Authentication error", JSON.stringify(error)));
|
|
});
|
|
}
|
|
|
|
// Register all socket events for a given socket connection
|
|
async function registerSocketEvents(socket) {
|
|
await setSessionData(socket.id, "log_level", "TRACE");
|
|
await createLogEvent(socket, "DEBUG", `Connected and Authenticated.`);
|
|
|
|
// Register CDK-related socket events
|
|
registerCdkEvents(socket);
|
|
|
|
// Register PBS AR-related socket events
|
|
registerPbsArEvents(socket);
|
|
|
|
// Register PBS AP-related socket events
|
|
registerPbsApEvents(socket);
|
|
|
|
// Register room and broadcasting events
|
|
registerRoomAndBroadcastEvents(socket);
|
|
|
|
// Register event to clear DMS session
|
|
registerDmsClearSessionEvent(socket);
|
|
|
|
// Register Production Board events
|
|
registerProductionBoardEvents(socket);
|
|
|
|
// Handle socket disconnection
|
|
socket.on("disconnect", async () => {
|
|
await createLogEvent(socket, "DEBUG", `User disconnected.`);
|
|
});
|
|
}
|
|
|
|
// CDK-specific socket events
|
|
function registerCdkEvents(socket) {
|
|
socket.on("cdk-export-job", (jobid) => CdkJobExport(socket, jobid));
|
|
socket.on("cdk-selected-customer", async (selectedCustomerId) => {
|
|
await createLogEvent(socket, "DEBUG", `User selected customer ID ${selectedCustomerId}`);
|
|
CdkSelectedCustomer(socket, selectedCustomerId).catch((err) =>
|
|
console.error(`Error in cdk-selected-customer: ${err}`)
|
|
);
|
|
await setSessionData(socket.id, "selectedCustomer", selectedCustomerId);
|
|
});
|
|
|
|
socket.on("cdk-get-makes", async (cdk_dealerid, callback) => {
|
|
try {
|
|
const makes = await CdkGetMakes(socket, cdk_dealerid);
|
|
callback(makes);
|
|
} catch (error) {
|
|
await createLogEvent(socket, "ERROR", `Error in cdk-get-makes WS call. ${JSON.stringify(error)}`);
|
|
}
|
|
});
|
|
|
|
socket.on("cdk-calculate-allocations", async (jobid, callback) => {
|
|
const allocations = await CdkCalculateAllocations(socket, jobid);
|
|
await createLogEvent(socket, "DEBUG", `Allocations calculated.`);
|
|
await createLogEvent(socket, "TRACE", `Allocations details: ${JSON.stringify(allocations)}`);
|
|
callback(allocations);
|
|
await setSessionData(socket.id, "cdk_allocations", allocations);
|
|
});
|
|
}
|
|
|
|
// PBS AR-specific socket events
|
|
function registerPbsArEvents(socket) {
|
|
socket.on("pbs-calculate-allocations", async (jobid, callback) => {
|
|
const allocations = await CdkCalculateAllocations(socket, jobid);
|
|
await createLogEvent(socket, "DEBUG", `PBS AR allocations calculated.`);
|
|
await createLogEvent(socket, "TRACE", `Allocations details: ${JSON.stringify(allocations)}`);
|
|
callback(allocations);
|
|
await setSessionData(socket.id, "pbs_allocations", allocations);
|
|
});
|
|
|
|
socket.on("pbs-export-job", (jobid) => PbsExportJob(socket, jobid));
|
|
socket.on("pbs-selected-customer", async (selectedCustomerId) => {
|
|
await createLogEvent(socket, "DEBUG", `PBS AR selected customer ID ${selectedCustomerId}`);
|
|
PbsSelectedCustomer(socket, selectedCustomerId).catch((err) =>
|
|
console.error(`Error in pbs-selected-customer: ${err}`)
|
|
);
|
|
await setSessionData(socket.id, "selectedCustomer", selectedCustomerId);
|
|
});
|
|
}
|
|
|
|
function registerProductionBoardEvents(socket) {}
|
|
|
|
// PBS AP-specific socket events
|
|
function registerPbsApEvents(socket) {
|
|
socket.on("pbs-calculate-allocations-ap", async (billids, callback) => {
|
|
const allocations = await PbsCalculateAllocationsAp(socket, billids);
|
|
await createLogEvent(socket, "DEBUG", `PBS AP allocations calculated.`);
|
|
await createLogEvent(socket, "TRACE", `Allocations details: ${JSON.stringify(allocations)}`);
|
|
callback(allocations);
|
|
await setSessionData(socket.id, "pbs_ap_allocations", allocations);
|
|
});
|
|
|
|
socket.on("pbs-export-ap", async ({ billids, txEnvelope }) => {
|
|
await setSessionData(socket.id, "pbs_txEnvelope", txEnvelope);
|
|
PbsExportAp(socket, {
|
|
billids,
|
|
txEnvelope
|
|
}).catch((err) => console.error(`Error in pbs-export-ap: ${err}`));
|
|
});
|
|
}
|
|
|
|
const getRedisKeyForSocket = (socketId) => `socket:${socketId}:rooms`;
|
|
|
|
// Room management and broadcasting events
|
|
function registerRoomAndBroadcastEvents(socket) {
|
|
// Rejoin rooms on reconnect
|
|
pubClient.lRange(getRedisKeyForSocket(socket.id), 0, -1, (err, rooms) => {
|
|
if (rooms && rooms.length > 0) {
|
|
rooms.forEach((room) => {
|
|
socket.join(room);
|
|
createLogEvent(socket, "DEBUG", `Client rejoined bodyshop room: ${room}`);
|
|
});
|
|
}
|
|
});
|
|
|
|
socket.on("join-bodyshop-room", async (bodyshopUUID) => {
|
|
socket.join(bodyshopUUID);
|
|
|
|
// Store room in Redis
|
|
pubClient.rPush(getRedisKeyForSocket(socket.id), bodyshopUUID);
|
|
|
|
await createLogEvent(socket, "DEBUG", `Client joined bodyshop room: ${bodyshopUUID}`);
|
|
});
|
|
|
|
socket.on("leave-bodyshop-room", async (bodyshopUUID) => {
|
|
socket.leave(bodyshopUUID);
|
|
|
|
// Remove room from Redis
|
|
pubClient.lRem(getRedisKeyForSocket(socket.id), 0, bodyshopUUID);
|
|
|
|
await createLogEvent(socket, "DEBUG", `Client left bodyshop room: ${bodyshopUUID}`);
|
|
});
|
|
|
|
socket.on("broadcast-to-bodyshop", async (bodyshopUUID, message) => {
|
|
io.to(bodyshopUUID).emit("bodyshop-message", message);
|
|
await createLogEvent(socket, "INFO", `Broadcast message to bodyshop ${bodyshopUUID}`);
|
|
});
|
|
|
|
socket.on("disconnect", () => {
|
|
// Optional: Cleanup Redis entry on disconnect if needed
|
|
createLogEvent(socket, "DEBUG", `Client disconnected: ${socket.id}`);
|
|
});
|
|
}
|
|
// DMS session clearing event
|
|
function registerDmsClearSessionEvent(socket) {
|
|
socket.on("clear-dms-session", async () => {
|
|
await clearSessionData(socket.id); // Clear all session data in Redis
|
|
await createLogEvent(socket, "INFO", `DMS session data cleared for socket ${socket.id}`);
|
|
});
|
|
}
|
|
|
|
// Logging helper functions
|
|
async function createLogEvent(socket, level, message) {
|
|
const { logLevel, recordid } = await getMultipleSessionData(socket.id, ["log_level", "recordid"]);
|
|
|
|
if (LogLevelHierarchy(logLevel) >= LogLevelHierarchy(level)) {
|
|
const logMessage = { timestamp: new Date(), level, message };
|
|
|
|
// Log the message to the console and emit it via the socket
|
|
console.log(`[WS LOG EVENT] ${level} - ${logMessage.timestamp} - ${socket.user.email} - ${socket.id} - ${message}`);
|
|
socket.emit("log-event", logMessage);
|
|
|
|
// Log the event via the logger
|
|
logger.log("ws-log-event", level, socket.user.email, recordid, { wsmessage: message });
|
|
|
|
// Add the log message to the Redis list using the helper function
|
|
await addItemToEndOfList(socket.id, "logEvents", logMessage);
|
|
}
|
|
}
|
|
|
|
async function createJsonEvent(socket, level, message, json) {
|
|
const { logLevel, recordid } = await getMultipleSessionData(socket.id, ["log_level", "recordid"]);
|
|
|
|
if (LogLevelHierarchy(logLevel) >= LogLevelHierarchy(level)) {
|
|
const logMessage = { timestamp: new Date(), level, message };
|
|
|
|
// Emit the log message via the socket
|
|
socket.emit("log-event", logMessage);
|
|
|
|
// Log the JSON event via the logger
|
|
logger.log("ws-log-event-json", level, socket.user.email, recordid, {
|
|
wsmessage: message,
|
|
json
|
|
});
|
|
|
|
// Use the helper function to append the log event to the Redis list
|
|
await addItemToEndOfList(socket.id, "logEvents", logMessage);
|
|
}
|
|
}
|
|
|
|
async function createXmlEvent(socket, xml, message, isError = false) {
|
|
const { logLevel, recordid } = await getMultipleSessionData(socket.id, ["log_level", "recordid"]);
|
|
|
|
if (LogLevelHierarchy(logLevel) >= LogLevelHierarchy("TRACE")) {
|
|
const logMessage = {
|
|
timestamp: new Date(),
|
|
level: isError ? "ERROR" : "TRACE",
|
|
message: `${message}: ${xml}`
|
|
};
|
|
|
|
// Emit the log message via the socket
|
|
socket.emit("log-event", logMessage);
|
|
|
|
// Log the XML event via the logger
|
|
logger.log(
|
|
isError ? "ws-log-event-xml-error" : "ws-log-event-xml",
|
|
isError ? "ERROR" : "TRACE",
|
|
socket.user.email,
|
|
recordid,
|
|
{ wsmessage: message, xml }
|
|
);
|
|
|
|
// Use the helper function to append the log event to the Redis list
|
|
await addItemToEndOfList(socket.id, "logEvents", { ...logMessage, xml });
|
|
}
|
|
}
|
|
|
|
// Log level hierarchy
|
|
function LogLevelHierarchy(level) {
|
|
const levels = { XML: 5, TRACE: 5, DEBUG: 4, INFO: 3, WARNING: 2, ERROR: 1 };
|
|
return levels[level] || 3;
|
|
}
|
|
|
|
// Socket.IO Middleware and Connection
|
|
io.use(socketAuthMiddleware);
|
|
io.on("connection", registerSocketEvents);
|
|
|
|
// Export logging helpers
|
|
exports.createLogEvent = createLogEvent;
|
|
exports.createXmlEvent = createXmlEvent;
|
|
exports.createJsonEvent = createJsonEvent;
|