project changes in socket
This commit is contained in:
@@ -99,6 +99,7 @@ export const GetAllProjects = async (data: GetProjectsInterface) => {
|
|||||||
if (!existingUser) return { status: "User not found" };
|
if (!existingUser) return { status: "User not found" };
|
||||||
const projectDatas = await projectModel(organization)
|
const projectDatas = await projectModel(organization)
|
||||||
.find({
|
.find({
|
||||||
|
createdBy:userId,
|
||||||
isArchive: false,
|
isArchive: false,
|
||||||
})
|
})
|
||||||
.select("_id projectName createdBy thumbnail createdAt projectUuid");
|
.select("_id projectName createdBy thumbnail createdAt projectUuid");
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import { Socket, Server } from "socket.io";
|
import { Socket, Server } from "socket.io";
|
||||||
import { createProject, DeleteProject, updateProject } from "../../../shared/services/project/project-Services.ts";
|
import { createProject, DeleteProject, updateProject } from "../../../shared/services/project/project-Services.ts";
|
||||||
import { EVENTS } from "../../socket/events.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;
|
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]);
|
const missingFields = requiredFields.filter(field => !data?.[field]);
|
||||||
|
|
||||||
if (missingFields.length > 0) {
|
if (missingFields.length > 0) {
|
||||||
@@ -17,7 +20,7 @@ export const projectHandleEvent = async ( event: string,socket: Socket,data: any
|
|||||||
organization: data?.organization ?? "unknown",
|
organization: data?.organization ?? "unknown",
|
||||||
};
|
};
|
||||||
|
|
||||||
emitEventResponse(socket, data?.organization, EVENTS.projectResponse, response);
|
emitToSenderAndAdmins(io, socket, data.organization, EVENTS.projectResponse, response, connectedUsersByOrg)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const result = await createProject(data);
|
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 } : {}),
|
...(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 (
|
export const projectDeleteHandleEvent = async (
|
||||||
event: string,
|
event: string,
|
||||||
socket: Socket,
|
socket: Socket,
|
||||||
|
io:Server,
|
||||||
data: any,
|
data: any,
|
||||||
|
connectedUsersByOrg: { [org: string]: { socketId: string; userId: string; role: string }[] },
|
||||||
) => {
|
) => {
|
||||||
|
console.log('event: ', event);
|
||||||
if (event !== EVENTS.deleteProject || !data?.organization) return;
|
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);
|
const result = await DeleteProject(data);
|
||||||
|
console.log('result: ', result);
|
||||||
const status = typeof result?.status === "string" ? result.status : "unknown";
|
const status = typeof result?.status === "string" ? result.status : "unknown";
|
||||||
|
|
||||||
const messages: Record<string, { message: string }> = {
|
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 (
|
export const projecUpdateHandleEvent = async (
|
||||||
event: string,
|
event: string,
|
||||||
socket: Socket,
|
socket: Socket,
|
||||||
|
io:Server,
|
||||||
data: any,
|
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;
|
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 result = await updateProject(data);
|
||||||
const status = typeof result?.status === "string" ? result.status : "unknown";
|
const status = typeof result?.status === "string" ? result.status : "unknown";
|
||||||
|
|
||||||
@@ -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);
|
console.log('response: ', response);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,6 @@ app.get('/', (req: Request, res: Response) => {
|
|||||||
res.send('Hello, I am Major-Dwinzo RealTime!');
|
res.send('Hello, I am Major-Dwinzo RealTime!');
|
||||||
});
|
});
|
||||||
initSocketServer(server);
|
initSocketServer(server);
|
||||||
// SocketServer(server)
|
|
||||||
server.listen(PORT, () => {
|
server.listen(PORT, () => {
|
||||||
console.log(`socket-Server is running on http://localhost:${PORT}`);
|
console.log(`socket-Server is running on http://localhost:${PORT}`);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { addTemplate, addTemplateZone, TemplateZoneDelete } from '../services/vi
|
|||||||
import { deleteAssetModel, replaceEventDatas, setAssetModel } from '../services/assets/asset-Controller.ts';
|
import { deleteAssetModel, replaceEventDatas, setAssetModel } from '../services/assets/asset-Controller.ts';
|
||||||
import { add3Dwidget, delete3Dwidget, update3D } from '../services/visualization/3dWidget-Service.ts';
|
import { add3Dwidget, delete3Dwidget, update3D } from '../services/visualization/3dWidget-Service.ts';
|
||||||
import { projectDeleteHandleEvent, projectHandleEvent, projecUpdateHandleEvent } from '../controllers/project/projectController.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}`);
|
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) => {
|
export const initSocketServer = (httpServer: any) => {
|
||||||
const io = new Server(httpServer, {
|
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
|
// 🔹 Create different namespaces
|
||||||
const 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'),
|
Builder: io.of('/Builder'),
|
||||||
visualization: io.of('/Visualization'),
|
visualization: io.of('/Visualization'),
|
||||||
project: io.of('/project'),
|
project: io.of('/project'),
|
||||||
|
|
||||||
// widget:io.of('/widget')
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// const onlineUsers = new Map<string, Set<string>>();
|
// const onlineUsers = new Map<string, Set<string>>();
|
||||||
@@ -1121,14 +1097,13 @@ export const initSocketServer = (httpServer: any) => {
|
|||||||
|
|
||||||
const handleNamespace = (namespaceName: string, namespace: any, ...eventHandlers: Function[]) => {
|
const handleNamespace = (namespaceName: string, namespace: any, ...eventHandlers: Function[]) => {
|
||||||
|
|
||||||
namespace.on("connection", (socket: Socket) => {
|
namespace.on("connection", async (socket: Socket) => {
|
||||||
// console.log(`✅ Client connected to ${namespaceName}: ${socket.id}`);
|
|
||||||
// Extract organization from query parameters
|
|
||||||
|
|
||||||
// const organization = socket.handshake.query.organization as string;
|
// const organization = socket.handshake.query.organization as string;
|
||||||
// const email = socket.handshake.query.email as string;
|
// const email = socket.handshake.query.email as string;
|
||||||
const { organization, email } = socket.handshake.auth
|
const { organization, email, userId } = socket.handshake.auth
|
||||||
// console.log(`🔍 Received organization: ${organization}`);
|
console.log(' socket.handshake.auth: ', socket.handshake.auth);
|
||||||
|
|
||||||
if (organization) {
|
if (organization) {
|
||||||
socket.join(organization);
|
socket.join(organization);
|
||||||
@@ -1140,24 +1115,49 @@ export const initSocketServer = (httpServer: any) => {
|
|||||||
onlineUsers[organization] = new Set();
|
onlineUsers[organization] = new Set();
|
||||||
}
|
}
|
||||||
onlineUsers[organization].add(socket.id);
|
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] = [];
|
||||||
|
}
|
||||||
|
|
||||||
socket.onAny((event: string, data: any, callback: any) => {
|
connectedUsersByOrg[organization].push({
|
||||||
eventHandlers.forEach(handler => handler(event, socket, data, namespace, io, callback));
|
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, io, data, connectedUsersByOrg, callback));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Handle disconnection
|
// Handle disconnection
|
||||||
socket.on("disconnect", () => {
|
socket.on("disconnect", () => {
|
||||||
onlineUsers[organization]?.delete(socket.id);
|
onlineUsers[organization]?.delete(socket.id);
|
||||||
if (onlineUsers[organization]?.size === 0) delete onlineUsers[organization];
|
if (onlineUsers[organization]?.size === 0) delete onlineUsers[organization];
|
||||||
userStatus(EVENTS.disconnect, socket, socket.handshake.auth, socket);
|
userStatus(EVENTS.disconnect, socket, socket.handshake.auth, socket);
|
||||||
// console.log(`❌ User ${email} disconnected. Remaining:`, onlineUsers[organization]);
|
connectedUsersByOrg[organization] = connectedUsersByOrg[organization].filter(
|
||||||
// console.log(`❌ Client disconnected from ${namespaceName}: ${socket.id}, Reason: ${reason}`);
|
(u) => u.socketId !== socket.id
|
||||||
|
);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle reconnection (Auto rejoin)
|
// 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("Builder", namespaces.Builder, userStatus, modelAssetHandleEvent, cameraHandleEvent, EnvironmentHandleEvent, wallItemsHandleEvent, lineHandleEvent, zoneHandleEvent);
|
||||||
handleNamespace("Visualization", namespaces.visualization, panelHandleEvent, widgetHandleEvent, floatHandleEvent, templateHandleEvent, Widget3DHandleEvent);
|
handleNamespace("Visualization", namespaces.visualization, panelHandleEvent, widgetHandleEvent, floatHandleEvent, templateHandleEvent, Widget3DHandleEvent);
|
||||||
handleNamespace("project", namespaces.project, projectHandleEvent, projectDeleteHandleEvent, projecUpdateHandleEvent)
|
handleNamespace("project", namespaces.project, projectHandleEvent, projectDeleteHandleEvent, projecUpdateHandleEvent)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Socket } from "socket.io";
|
import { Socket,Server } from "socket.io";
|
||||||
|
|
||||||
interface EmitOptions {
|
interface EmitOptions {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
@@ -19,12 +19,13 @@ export const emitEventResponse = (
|
|||||||
event: string,
|
event: string,
|
||||||
result: EmitOptions
|
result: EmitOptions
|
||||||
) => {
|
) => {
|
||||||
|
console.log('event: ', event);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
console.log(`Organization missing in response for event: ${event}`);
|
console.log(`Organization missing in response for event: ${event}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
socket.emit(event, {
|
socket.to(organization).emit(event, {
|
||||||
// success: result.success,
|
// success: result.success,
|
||||||
message: result.message,
|
message: result.message,
|
||||||
data: result.data ,
|
data: result.data ,
|
||||||
@@ -33,3 +34,55 @@ export const emitEventResponse = (
|
|||||||
organization,
|
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,
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
};
|
||||||
|
|||||||
11
src/socket-server/utils/getUsers.ts
Normal file
11
src/socket-server/utils/getUsers.ts
Normal 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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user