diff --git a/.vscode/settings.json b/.vscode/settings.json index be79998..faeed09 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,7 @@ "**/.DS_Store": true, "**/Thumbs.db": true, "**/.retool_types/**": true, - // "**/*tsconfig.json": true, + "**/*tsconfig.json": true, ".cache": true, "retool.config.json": true } diff --git a/src/api-server/Dockerfile b/src/api-server/Dockerfile index cd31368..942e1bd 100644 --- a/src/api-server/Dockerfile +++ b/src/api-server/Dockerfile @@ -7,7 +7,7 @@ ENV NODE_ENV development WORKDIR /usr/src/app -RUN npm install -g npm +RUN npm install -g tsx COPY package.json /usr/src/app/package.json diff --git a/src/socket-server/Dockerfile b/src/socket-server/Dockerfile index 5ecee54..f7863f6 100644 --- a/src/socket-server/Dockerfile +++ b/src/socket-server/Dockerfile @@ -7,7 +7,7 @@ ENV NODE_ENV development WORKDIR /usr/src/app -RUN npm install -g npm +RUN npm install -g tsx COPY package.json /usr/src/app/package.json diff --git a/src/socket-server/services/lines/zone-Services.ts b/src/socket-server/services/lines/zone-Services.ts index ea39d1b..938e7d1 100644 --- a/src/socket-server/services/lines/zone-Services.ts +++ b/src/socket-server/services/lines/zone-Services.ts @@ -1,80 +1,79 @@ -// import zoneModel from "../../../shared/model/builder/lines/zone-Model.ts"; +import zoneModel from "../../../shared/model/builder/lines/zone-Model.ts"; // export const setZone = async (data: any) => { // const { organization, userId, zoneData } = data -// // try { -// // console.log('data: ', data); -// // const zoneId = zoneData.zoneId -// // const points = zoneData.points -// // const zoneName = zoneData.zoneName -// // const layer = zoneData.layer -// // const viewPortCenter = zoneData.viewPortCenter -// // const viewPortposition = zoneData.viewPortposition -// // const findZoneId = await zoneModel(organization).findOne({ zoneId: zoneId }) - -// // } catch (error) { -// // console.log('error: ', error); -// // return { success: false, message: 'Zone not found', error } -// // } + // try { -// console.log('data: ', data); +// console.log('data: ', data); // const zoneId = zoneData.zoneId // const points = zoneData.points // const zoneName = zoneData.zoneName // const layer = zoneData.layer // const viewPortCenter = zoneData.viewPortCenter // const viewPortposition = zoneData.viewPortposition - +// const sceneID = zoneData.sceneID + // const existingZone = await zoneModel(organization).findOne({ -// zoneId:zoneId, -// isArchive: false, +// zoneId: zoneId, +// isArchive: false, // }); // if (!existingZone) { -// const newZone = await zoneModel(organization).create({ -// zoneName: zoneName, -// zoneId: zoneId, -// zonePoints: points, -// viewPortposition: viewPortposition, -// viewPortCenter: viewPortCenter, -// createdBy: userId, -// layer: layer, -// sceneID: sceneID, -// }); -// if (newZone) -// return res.status(200).json({ -// message: "Zone created successfully", -// zoneData: { -// zoneName: newZone.zoneName, -// points: newZone.zonePoints, +// const newZone = await zoneModel(organization).create({ +// zoneName: zoneName, +// zoneId: zoneId, +// zonePoints: points, // viewPortposition: viewPortposition, // viewPortCenter: viewPortCenter, -// }, +// createdBy: userId, +// layer: layer, +// sceneID: sceneID, // }); +// if (newZone) +// return { success: true, message: 'zone created', data: newZone, organization: organization } + // } else { -// const replaceZone = await zoneModel(organization).findOneAndUpdate( -// { zoneId: zoneId, isArchive: false }, -// { -// zonePoints: points, -// viewPortposition: viewPortposition, -// viewPortCenter: viewPortCenter, -// }, -// { new: true } -// ); -// if (!replaceZone) -// return res.status(404).json({ message: "Zone not updated" }); -// else -// return res.status(200).json({ -// message: "updated successfully", -// zoneData: { -// zoneName: replaceZone.zoneName, -// points: replaceZone.zonePoints, -// viewPortposition: replaceZone.viewPortposition, -// viewPortCenter: replaceZone.viewPortCenter, -// }, -// }); +// const replaceZone = await zoneModel(organization).findOneAndUpdate( +// { zoneId: zoneId, isArchive: false }, +// { +// zonePoints: points, +// viewPortposition: viewPortposition, +// viewPortCenter: viewPortCenter, +// }, +// { new: true } +// ); +// if (!replaceZone) +// return { success: false, message: 'Zone not updated',organization: organization } +// else +// return { success: true, message: 'zone updated', data: replaceZone, organization: organization } + // } -// } catch (error: any) { -// return res.status(500).send(error.message); -// } +// } catch (error: any) { +// return { success: false, message: 'Zone not found', error,organization: organization } +// } // } - \ No newline at end of file +// export const deleteZone = async (data: any) => { +// const { organization, userId, zoneId } = data +// try { +// const existingZone = await zoneModel(organization).findOne({ +// zoneId: zoneId, +// isArchive: false, +// }); +// if (!existingZone) { +// return { success: true, message: 'Invalid zone ID', organization: organization } +// } else { +// const deleteZone = await zoneModel(organization).findOneAndUpdate( +// { zoneId: zoneId, isArchive: false }, +// { +// isArchive: true, +// }, +// { new: true } +// ); + +// if (deleteZone) { +// return { success: true, message: 'zone deleted', data: deleteZone, organization: organization } +// } +// } +// } catch (error: any) { +// return { success: false, message: 'Zone not found', error,organization: organization } +// } +// } \ No newline at end of file diff --git a/src/socket-server/services/visualization/panel-Services.ts b/src/socket-server/services/visualization/panel-Services.ts new file mode 100644 index 0000000..89d06e3 --- /dev/null +++ b/src/socket-server/services/visualization/panel-Services.ts @@ -0,0 +1,105 @@ +import panelSchema from "../../../shared/model/vizualization/panelmodel.ts"; +import zoneSchema from "../../../shared/model/builder/lines/zone-Model.ts"; +import widgetSchema from "../../../shared/model/vizualization/widgemodel.ts"; + +export const addPanel = async (data: any) => { +const{organization,zoneId,panelName,panelOrder}=data +console.log('data: ', data); +try { + const findZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + console.log('findZone: ', findZone); + if (!findZone) { + return { success: false, message: 'Zone not found',organization: organization} + + } + const updatezone = await zoneSchema(organization).findOneAndUpdate( + { zoneId: zoneId, isArchive: false }, + { panelOrder: panelOrder }, + { new: true } + ); + const existingPanels = await panelSchema(organization).find({ + zoneId: zoneId, + isArchive: false, + }); + + const existingPanelNames = existingPanels.map( + (panel: any) => panel.panelName + ); + + const missingPanels = panelOrder.filter( + (panelName: string) => !existingPanelNames.includes(panelName) + ); + + const createdPanels = []; + for (const panelName of missingPanels) { + const newPanel = await panelSchema(organization).create({ + zoneId: zoneId, + panelName: panelName, + widgets: [], + isArchive: false, + }); + createdPanels.push(newPanel); + } + + if (createdPanels.length === 0) { + return { success: false, message: "No new panels were created. All panels already exist",organization: organization} + } + // const IDdata = createdPanels.map((ID: any) => { + // return ID._id; + // }); + console.log("IDdata: ", createdPanels); + createdPanels + return { success: true, message: "Panels created successfully", data: createdPanels, organization: organization } +}catch (error) { + return { success: false, message: 'Panel not found', error,organization: organization } + +} + +} +export const deletePanel = async (data: any) => { + const { organization, panelID, zoneId } = data; + try { + const existingZone = await zoneSchema(organization).findOne({ + zoneId: zoneId, + isArchive: false, + }); + if (!existingZone) + return { success: false, message: 'Zone not found',organization: organization} + + const existingPanel = await panelSchema(organization).findOne({ + zoneId: zoneId, + _id: panelID, + isArchive: false, + }); + if (!existingPanel) + return { success: false, message: 'Panel Already Deleted',organization: organization} + const updatePanel = await panelSchema(organization).updateOne( + { _id: panelID, isArchive: false }, + { $set: { isArchive: true } } + ); + const existingWidgets = await widgetSchema(organization).find({ + panelID: panelID, + isArchive: false, + }); + + for (const widgetData of existingWidgets) { + widgetData.isArchive = true; + await widgetData.save(); + } + + if (existingZone.panelOrder.includes(existingPanel.panelName)) { + existingZone.panelOrder = existingZone.panelOrder.filter( + (panel: any) => panel !== existingPanel.panelName + ); + + await existingZone.save(); + } + return { success: true, message: 'Panel deleted successfully',organization: organization} + + } catch (error) { + return { success: false, message: 'Panel not found', error,organization: organization } } + + } \ No newline at end of file diff --git a/src/socket-server/services/visualization/widge-Services.ts b/src/socket-server/services/visualization/widge-Services.ts new file mode 100644 index 0000000..0121277 --- /dev/null +++ b/src/socket-server/services/visualization/widge-Services.ts @@ -0,0 +1,5 @@ +import panelSchema from "../../../shared/model/vizualization/panelmodel.ts"; +import widgetSchema from "../../../shared/model/vizualization/widgemodel.ts"; +export const addPanel = async (data: any) => { + +} \ No newline at end of file diff --git a/src/socket-server/socket/events.ts b/src/socket-server/socket/events.ts index 86b7540..5f774e4 100644 --- a/src/socket-server/socket/events.ts +++ b/src/socket-server/socket/events.ts @@ -47,4 +47,10 @@ export const EVENTS = { zoneUpdateRespones:"zone:response:updates", deleteZone:"v2:zone:delete", ZoneDeleteRespones:"zone:response:delete", + + //visualization + addPanel:"v2:viz-panel:add", + panelUpdateRespones:"viz-panel:response:updates", + deletePanel:"v2:viz-panel:delete", + PanelDeleteRespones:"viz-panel:response:delete", } \ No newline at end of file diff --git a/src/socket-server/socket/socketManager.ts b/src/socket-server/socket/socketManager.ts index 5a6e158..9bfc3ab 100644 --- a/src/socket-server/socket/socketManager.ts +++ b/src/socket-server/socket/socketManager.ts @@ -7,6 +7,7 @@ import { deleteWallItems, setWallItems } from '../services/assets/wallitem-Contr import { deleteLineItems, deleteLinPoiteItems, updateLineItems ,createLineItems, deleteLayer} from '../services/lines/line-Controller.ts'; import { activeUserOffline, activeUsers } from '../services/users/user-controller.ts'; import { deleteZone, setZone } from '../services/lines/zone-controller.ts'; +import { addPanel } from '../services/visualization/panel-Services.ts'; @@ -423,7 +424,45 @@ switch (event) { break; } } - +const panelHandleEvent=async(event: string, socket: Socket, data: any,namespace: any, notifySender: boolean = false)=>{ + if (!data?.organization) { + console.warn(`Missing organization for event: ${event}`); + return; + } + + let result; + switch (event) { + case EVENTS.addPanel: + result = await addPanel(data); + console.log('result: ', result); + + if (result) { + console.log('result?.success: ', result.organization); + const responseEvent = EVENTS.panelUpdateRespones + console.log('responseEvent: ', responseEvent); + const organization=result?.organization + console.log('organization: ', organization); + // const emitTarget = notifySender ? socket.in(organization) : socket.to(organization); + console.log(`👀 Active sockets in room:`, namespace.adapter.rooms.get(organization)); + // console.log('emitTarget: ', emitTarget); + + socket.to(organization).emit(responseEvent, { + success: result.success, + message: result.message, + data: result.data, + error: result.error, + socketId: socket.id, + organization: result.organization, + }); + } + break; + + default: + return; + } + + + } export const initSocketServer = (httpServer: any) => { const io = new Server(httpServer, { cors: { @@ -432,6 +471,7 @@ export const initSocketServer = (httpServer: any) => { }, }); + // Listen for new connections io.on(EVENTS.connection, (socket: Socket) => { // console.log(`New client connected: ${socket.id}`); @@ -457,5 +497,68 @@ userStatus(EVENTS.connection, socket, socket.handshake.auth,io); }); }); + // 🔹 Create different namespaces + const namespaces = { + camera: io.of("/camera"), + environment: io.of("/environment"), + floorItems: io.of("/floorItems"), + wallItems: io.of("/wallItems"), + line: io.of("/line"), + zone: io.of("/zone"), + panel:io.of('/panel') + }; + // 🔹 Function to handle connections in a namespace + const handleNamespace = (namespaceName: string, namespace: any, eventHandler: Function) => { + namespace.on("connection", (socket: Socket) => { + console.log(`✅ Client connected to ${namespaceName}: ${socket.id}`); + + // Extract organization from query parameters + const organization = socket.handshake.query.organization as string; + console.log(`🔍 Received organization: ${organization}`); + + if (organization) { + socket.join(organization); + console.log(`🔹 Socket ${socket.id} joined room: ${organization}`); + + // Debug: Check rooms + console.log(`🛠️ Current rooms for ${socket.id}:`, socket.rooms); + } else { + console.warn(`⚠️ Warning: Socket ${socket.id} did not provide an organization`); + } + + socket.onAny((event: string, data: any) => { + console.log(`📩 Event received: ${event}, Data: ${JSON.stringify(data)}`); + eventHandler(event, socket, data, namespace); // Pass `namespace` instead of `io` + }); + + socket.on("disconnect", (reason: string) => { + console.log(`❌ Client disconnected from ${namespaceName}: ${socket.id}, Reason: ${reason}`); + }); + }); + }; + + // 🔹 Apply namespace handlers + handleNamespace("camera", namespaces.camera, cameraHandleEvent); + handleNamespace("environment", namespaces.environment, EnvironmentHandleEvent); + handleNamespace("floorItems", namespaces.floorItems, floorItemsHandleEvent); + handleNamespace("wallItems", namespaces.wallItems, wallItemsHandleEvent); + handleNamespace("line", namespaces.line, lineHandleEvent); + handleNamespace("zone", namespaces.zone, zoneHandleEvent); + handleNamespace("panel", namespaces.panel, panelHandleEvent); + // 📌 **Create a separate namespace for panels** + // const panelNamespace = io.of('/panel'); + + // panelNamespace.on(EVENTS.connection, (socket: Socket) => { + // console.log(`New client connected to /panel namespace: ${socket.id}`); + + // socket.onAny((event: string, data: any) => { + // panelHandleEvent(event, socket, data); + // }); + + // socket.on(EVENTS.disconnect, (reason: string) => { + // console.log(`Client disconnected from /panel namespace: ${socket.id}, Reason: ${reason}`); + // }); + // }) + return io; };