project changes in socket

This commit is contained in:
2025-05-17 18:02:09 +05:30
parent 611bffdaa9
commit 9be63d3459
6 changed files with 159 additions and 67 deletions

View File

@@ -99,6 +99,7 @@ export const GetAllProjects = async (data: GetProjectsInterface) => {
if (!existingUser) return { status: "User not found" };
const projectDatas = await projectModel(organization)
.find({
createdBy:userId,
isArchive: false,
})
.select("_id projectName createdBy thumbnail createdAt projectUuid");

View File

@@ -1,11 +1,14 @@
import { Socket, Server } from "socket.io";
import { createProject, DeleteProject, updateProject } from "../../../shared/services/project/project-Services.ts";
import { EVENTS } from "../../socket/events.ts";
import { emitEventResponse } from "../../utils/emitEventResponse.ts";
import { emitEventResponse, emitToSenderAndAdmins, } from "../../utils/emitEventResponse.ts";
export const projectHandleEvent = async ( event: string,socket: Socket,data: any,) => {
export const projectHandleEvent = async ( event: string,socket: Socket,io:Server,data: any, connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }, callback?: Function
) => {
console.log('event: ', event);
console.log('data:controller ', data);
if (event !== EVENTS.addProject || !data?.organization) return;
const requiredFields = ["projectUuid", "projectName", "userId", "thumbnail", "organization"];
const requiredFields = ["projectUuid", "userId", "thumbnail", "organization"];
const missingFields = requiredFields.filter(field => !data?.[field]);
if (missingFields.length > 0) {
@@ -17,7 +20,7 @@ export const projectHandleEvent = async ( event: string,socket: Socket,data: any
organization: data?.organization ?? "unknown",
};
emitEventResponse(socket, data?.organization, EVENTS.projectResponse, response);
emitToSenderAndAdmins(io, socket, data.organization, EVENTS.projectResponse, response, connectedUsersByOrg)
return;
}
const result = await createProject(data);
@@ -46,17 +49,35 @@ export const projectHandleEvent = async ( event: string,socket: Socket,data: any
...(status === "Success" ? { data: projectDatas, projectId: result.project._id } : {}),
};
emitEventResponse(socket, data.organization, EVENTS.projectResponse, response);
emitToSenderAndAdmins(io, socket, data.organization, EVENTS.projectResponse, response, connectedUsersByOrg)
}
export const projectDeleteHandleEvent = async (
event: string,
socket: Socket,
io:Server,
data: any,
connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] },
) => {
console.log('event: ', event);
if (event !== EVENTS.deleteProject || !data?.organization) return;
const requiredFields = ["projectId", "userId", "organization"];
const missingFields = requiredFields.filter(field => !data?.[field]);
if (missingFields.length > 0) {
const response = {
success: false,
message: `Missing required field(s): ${missingFields.join(", ")}`,
status: "MissingFields",
socketId: socket.id,
organization: data?.organization ?? "unknown",
};
emitToSenderAndAdmins(io, socket, data.organization, EVENTS.deleteProjectResponse, response, connectedUsersByOrg)
return;
}
const result = await DeleteProject(data);
console.log('result: ', result);
const status = typeof result?.status === "string" ? result.status : "unknown";
const messages: Record<string, { message: string }> = {
@@ -86,16 +107,32 @@ export const projectDeleteHandleEvent = async (
};
emitEventResponse(socket, data.organization, EVENTS.deleteProjectResponse, response);
}
emitToSenderAndAdmins(io, socket, data.organization, EVENTS.deleteProjectResponse, response, connectedUsersByOrg)}
export const projecUpdateHandleEvent = async (
event: string,
socket: Socket,
io:Server,
data: any,
connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] },
) => {
console.log('data: ', data);
console.log('data:update ', data);
if (event !== EVENTS.ProjectUpdate || !data?.organization) return;
const requiredFields = ["projectId", "userId", "organization"];
const missingFields = requiredFields.filter(field => !data?.[field]);
if (missingFields.length > 0) {
const response = {
success: false,
message: `Missing required field(s): ${missingFields.join(", ")}`,
status: "MissingFields",
socketId: socket.id,
organization: data?.organization ?? "unknown",
};
emitToSenderAndAdmins(io, socket, data.organization, EVENTS.projectUpdateResponse, response, connectedUsersByOrg)
return;
}
const result = await updateProject(data);
const status = typeof result?.status === "string" ? result.status : "unknown";
@@ -107,8 +144,8 @@ export const projecUpdateHandleEvent = async (
const msg = messages[status] || { message: "Internal server error" };
const projectDeleteDatas =
status === "Success" && result?.data
status === "Success" && result?.data
const response = {
success: status === "Success",
@@ -120,7 +157,7 @@ export const projecUpdateHandleEvent = async (
};
emitEventResponse(socket, data.organization, EVENTS.projectUpdateResponse, response);
emitToSenderAndAdmins(io, socket, data.organization, EVENTS.projectUpdateResponse, response, connectedUsersByOrg)
console.log('response: ', response);
}

View File

@@ -16,7 +16,6 @@ app.get('/', (req: Request, res: Response) => {
res.send('Hello, I am Major-Dwinzo RealTime!');
});
initSocketServer(server);
// SocketServer(server)
server.listen(PORT, () => {
console.log(`socket-Server is running on http://localhost:${PORT}`);
});

View File

@@ -14,6 +14,7 @@ import { addTemplate, addTemplateZone, TemplateZoneDelete } from '../services/vi
import { deleteAssetModel, replaceEventDatas, setAssetModel } from '../services/assets/asset-Controller.ts';
import { add3Dwidget, delete3Dwidget, update3D } from '../services/visualization/3dWidget-Service.ts';
import { projectDeleteHandleEvent, projectHandleEvent, projecUpdateHandleEvent } from '../controllers/project/projectController.ts';
import { getUserRole } from '../utils/getUsers.ts';
@@ -1065,6 +1066,13 @@ const emitEventResponse = (socket: Socket, organization: string, event: string,
console.warn(`Organization missing in response for event: ${event}`);
}
};
interface UserSocketInfo {
socketId: string;
userId: string;
role: string; // e.g., "admin" or "user"
}
const connectedUsersByOrg: { [organization: string]: UserSocketInfo[] } = {};
export const initSocketServer = (httpServer: any) => {
const io = new Server(httpServer, {
@@ -1075,44 +1083,12 @@ export const initSocketServer = (httpServer: any) => {
});
// Listen for new connections
// io.on(EVENTS.connection, (socket: Socket) => {
// // console.log(`New client connected: ${socket.id}`);
// // console.log(socket.handshake.auth);
// userStatus(EVENTS.connection, socket, socket.handshake.auth, io);
// // console.log('socket.handshake.auth: ', socket.handshake.auth);
// // Handle all incoming events with the handleEvent function
// socket.onAny((event: string, data: any,) => {
// cameraHandleEvent(event, socket, data, io);
// EnvironmentHandleEvent(event, socket, data, io);
// floorItemsHandleEvent(event, socket, data, io);
// wallItemsHandleEvent(event, socket, data, io);
// lineHandleEvent(event, socket, data, io);
// zoneHandleEvent(event, socket, data, io);
// });
// socket.on(EVENTS.disconnect, (reason: string) => {
// // console.log(`Client disconnected: ${socket.id}, Reason: ${reason}`);
// // console.log(socket.handshake.auth);
// userStatus(EVENTS.disconnect, socket, socket.handshake.auth, io);
// // Perform cleanup or other necessary actions
// });
// });
// 🔹 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"),
Builder: io.of('/Builder'),
visualization: io.of('/Visualization'),
project: io.of('/project'),
// widget:io.of('/widget')
};
// const onlineUsers = new Map<string, Set<string>>();
@@ -1121,14 +1097,13 @@ export const initSocketServer = (httpServer: any) => {
const handleNamespace = (namespaceName: string, namespace: any, ...eventHandlers: Function[]) => {
namespace.on("connection", (socket: Socket) => {
// console.log(`✅ Client connected to ${namespaceName}: ${socket.id}`);
// Extract organization from query parameters
namespace.on("connection", async (socket: Socket) => {
// const organization = socket.handshake.query.organization as string;
// const email = socket.handshake.query.email as string;
const { organization, email } = socket.handshake.auth
// console.log(`🔍 Received organization: ${organization}`);
const { organization, email, userId } = socket.handshake.auth
console.log(' socket.handshake.auth: ', socket.handshake.auth);
if (organization) {
socket.join(organization);
@@ -1140,24 +1115,49 @@ export const initSocketServer = (httpServer: any) => {
onlineUsers[organization] = new Set();
}
onlineUsers[organization].add(socket.id);
// console.log('onlineUsers: ', onlineUsers);
// console.log(`✅ User ${email} joined ${organization}. Active users:`, onlineUsers[organization]);
}
userStatus(EVENTS.connection, socket, socket.handshake.auth, socket);
const role = await getUserRole(userId, organization);
console.log('role: ', role);
if (role === "Admin") {
socket.join(`${organization}_admins`);
}
// Save user info somewhere
if (organization && userId && role) {
if (!connectedUsersByOrg[organization]) {
connectedUsersByOrg[organization] = [];
}
connectedUsersByOrg[organization].push({
socketId: socket.id,
userId,
role,
});
// console.log(`🔗 User connected: ${userId} with role ${role} in ${organization}`);
// console.log("🧩 connectedUsersByOrg: ", connectedUsersByOrg);
} else {
console.warn(`❌ Cannot store user. Missing data:`,);
}
userStatus(EVENTS.connection, socket, socket.handshake.auth, socket);
socket.onAny((event: string, data: any, callback: any) => {
eventHandlers.forEach(handler => handler(event, socket, data, namespace, io, callback));
eventHandlers.forEach(handler => handler(event, socket, io, data, connectedUsersByOrg, callback));
});
// Handle disconnection
socket.on("disconnect", () => {
onlineUsers[organization]?.delete(socket.id);
if (onlineUsers[organization]?.size === 0) delete onlineUsers[organization];
userStatus(EVENTS.disconnect, socket, socket.handshake.auth, socket);
// console.log(`❌ User ${email} disconnected. Remaining:`, onlineUsers[organization]);
// console.log(`❌ Client disconnected from ${namespaceName}: ${socket.id}, Reason: ${reason}`);
connectedUsersByOrg[organization] = connectedUsersByOrg[organization].filter(
(u) => u.socketId !== socket.id
);
});
// Handle reconnection (Auto rejoin)
@@ -1172,15 +1172,6 @@ export const initSocketServer = (httpServer: any) => {
};
// 🔹 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("visualization", namespaces.panel, panelHandleEvent);
// handleNamespace("widget", namespaces.visualization, widgetHandleEvent);
handleNamespace("Builder", namespaces.Builder, userStatus, modelAssetHandleEvent, cameraHandleEvent, EnvironmentHandleEvent, wallItemsHandleEvent, lineHandleEvent, zoneHandleEvent);
handleNamespace("Visualization", namespaces.visualization, panelHandleEvent, widgetHandleEvent, floatHandleEvent, templateHandleEvent, Widget3DHandleEvent);
handleNamespace("project", namespaces.project, projectHandleEvent, projectDeleteHandleEvent, projecUpdateHandleEvent)

View File

@@ -1,4 +1,4 @@
import { Socket } from "socket.io";
import { Socket,Server } from "socket.io";
interface EmitOptions {
success: boolean;
@@ -19,12 +19,13 @@ export const emitEventResponse = (
event: string,
result: EmitOptions
) => {
console.log('event: ', event);
if (!organization) {
console.log(`Organization missing in response for event: ${event}`);
return;
}
socket.emit(event, {
socket.to(organization).emit(event, {
// success: result.success,
message: result.message,
data: result.data ,
@@ -33,3 +34,55 @@ export const emitEventResponse = (
organization,
});
};
// interface EmitOptions {
// success: boolean;
// message: string;
// data?: any;
// error?: any;
// organization: string;
// socketId: string;
// status?: string;
// }
export const emitToSenderAndAdmins = (
io: Server,
socket: Socket,
organization: string,
event: string,
result: EmitOptions,
connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] }
) => {
console.log('result.data,: ', result.data,);
// Emit to sender directly
socket.emit(event, {
message: result.message,
data: result.data,
error: result.error,
socketId: result.socketId,
organization,
});
socket.to(`${organization}_admins`).emit(event, {
message: result.message,
data: result.data,
error: result.error,
socketId: result.socketId,
organization,
});
// Emit to all admin sockets in organization except sender
// const admins = connectedUsersByOrg[organization]?.filter(
// user => user.role === 'Admin' && user.socketId !== socket.id
// ) || [];
// console.log('admins: ', admins);
// admins.forEach(adminUser => {
// io.to(adminUser.socketId).emit(event, {
// message: result.message,
// data: result.data,
// error: result.error,
// socketId: result.socketId,
// organization,
// });
// });
};

View File

@@ -0,0 +1,11 @@
import userModel from "../../shared/model/user-Model.ts";
// Example function to get user role from DB
export async function getUserRole(userId: string, organization: string): Promise<string> {
console.log('userId: ', userId);
const user = await userModel(organization).findOne({ _id: userId });
console.log('user: ', user);
return user?.role || "User"; // default to 'user' if no role found
}