PromucFlow_constructor/app/rts/src/controllers/socket.ts

129 lines
3.7 KiB
TypeScript
Raw Normal View History

fix: revamped rts server architecture (#15870) ## Description RTS node server was being used for Availability feature. Now we will be enhancing the server to utilise client side logic on the server side side like construction of AST, Evaluations logic etc. So, since our codebase was not structured for implementing such use case, so we had to revamp the structure of the codebase. #### Architecture - **Routes :** To define different paths to consume apis - **Controllers :** To capture the routing and formulate the logic to provide response to a particular request - **Middleware :** action functions that happen to be stitched in between the routes and controllers, or can be used as a part of logic that needs to be injected in between. - **Constants :** To keep static variables as per the usage without declaring it in other parts of the codebase - **Sockets :** Any socket apis exists inside this folder to properly structure every socket implementations - **Utils :** Helper functions which can be used at any stage of the application Fixes #15645 ## Type of change - New feature (non-breaking change which adds functionality) ## How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Provide instructions, so we can reproduce. > Please also list any relevant details for your test configuration. - Test A - Test B ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2022-08-11 09:36:02 +00:00
import { Server, Socket } from "socket.io";
import { tryAuth } from "@middlewares/socket-auth";
fix: revamped rts server architecture (#15870) ## Description RTS node server was being used for Availability feature. Now we will be enhancing the server to utilise client side logic on the server side side like construction of AST, Evaluations logic etc. So, since our codebase was not structured for implementing such use case, so we had to revamp the structure of the codebase. #### Architecture - **Routes :** To define different paths to consume apis - **Controllers :** To capture the routing and formulate the logic to provide response to a particular request - **Middleware :** action functions that happen to be stitched in between the routes and controllers, or can be used as a part of logic that needs to be injected in between. - **Constants :** To keep static variables as per the usage without declaring it in other parts of the codebase - **Sockets :** Any socket apis exists inside this folder to properly structure every socket implementations - **Utils :** Helper functions which can be used at any stage of the application Fixes #15645 ## Type of change - New feature (non-breaking change which adds functionality) ## How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Provide instructions, so we can reproduce. > Please also list any relevant details for your test configuration. - Test A - Test B ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2022-08-11 09:36:02 +00:00
import {
START_EDIT_EVENT_NAME,
LEAVE_EDIT_EVENT_NAME,
MOUSE_POINTER_EVENT_NAME,
PAGE_EDIT_NAMESPACE,
PAGE_ROOM_PREFIX,
EDITORS_EVENT_NAME,
} from "@constants/socket";
fix: revamped rts server architecture (#15870) ## Description RTS node server was being used for Availability feature. Now we will be enhancing the server to utilise client side logic on the server side side like construction of AST, Evaluations logic etc. So, since our codebase was not structured for implementing such use case, so we had to revamp the structure of the codebase. #### Architecture - **Routes :** To define different paths to consume apis - **Controllers :** To capture the routing and formulate the logic to provide response to a particular request - **Middleware :** action functions that happen to be stitched in between the routes and controllers, or can be used as a part of logic that needs to be injected in between. - **Constants :** To keep static variables as per the usage without declaring it in other parts of the codebase - **Sockets :** Any socket apis exists inside this folder to properly structure every socket implementations - **Utils :** Helper functions which can be used at any stage of the application Fixes #15645 ## Type of change - New feature (non-breaking change which adds functionality) ## How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Provide instructions, so we can reproduce. > Please also list any relevant details for your test configuration. - Test A - Test B ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2022-08-11 09:36:02 +00:00
import {
AppUser,
Policy,
CurrentEditorsEvent,
MousePointerEvent,
} from "@utils/models";
fix: revamped rts server architecture (#15870) ## Description RTS node server was being used for Availability feature. Now we will be enhancing the server to utilise client side logic on the server side side like construction of AST, Evaluations logic etc. So, since our codebase was not structured for implementing such use case, so we had to revamp the structure of the codebase. #### Architecture - **Routes :** To define different paths to consume apis - **Controllers :** To capture the routing and formulate the logic to provide response to a particular request - **Middleware :** action functions that happen to be stitched in between the routes and controllers, or can be used as a part of logic that needs to be injected in between. - **Constants :** To keep static variables as per the usage without declaring it in other parts of the codebase - **Sockets :** Any socket apis exists inside this folder to properly structure every socket implementations - **Utils :** Helper functions which can be used at any stage of the application Fixes #15645 ## Type of change - New feature (non-breaking change which adds functionality) ## How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Provide instructions, so we can reproduce. > Please also list any relevant details for your test configuration. - Test A - Test B ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes Co-authored-by: Aishwarya UR <aishwarya@appsmith.com>
2022-08-11 09:36:02 +00:00
function subscribeToEditEvents(socket: Socket, appRoomPrefix: string) {
socket.on(START_EDIT_EVENT_NAME, (resourceId) => {
if (socket.data.email) {
// user is authenticated, join the room now
joinEditRoom(socket, resourceId, appRoomPrefix);
} else {
// user not authenticated yet, save the resource id and room prefix to join later after auth
socket.data.pendingRoomId = resourceId;
socket.data.pendingRoomPrefix = appRoomPrefix;
}
});
socket.on(LEAVE_EDIT_EVENT_NAME, (resourceId) => {
let roomName = appRoomPrefix + resourceId;
socket.leave(roomName); // remove this socket from room
});
}
async function onAppSocketConnected(socket: Socket) {
let isAuthenticated = await tryAuthAndJoinPendingRoom(socket);
if (isAuthenticated) {
socket.join("email:" + socket.data.email);
}
}
async function onPageSocketConnected(socket: Socket, socketIo: Server) {
let isAuthenticated = await tryAuthAndJoinPendingRoom(socket);
if (isAuthenticated) {
socket.on(MOUSE_POINTER_EVENT_NAME, (event: MousePointerEvent) => {
event.user = new AppUser(socket.data.name, socket.data.email);
event.socketId = socket.id;
socketIo
.of(PAGE_EDIT_NAMESPACE)
.to(PAGE_ROOM_PREFIX + event.pageId)
.emit(MOUSE_POINTER_EVENT_NAME, event);
});
}
}
async function tryAuthAndJoinPendingRoom(socket: Socket) {
const isAuthenticated = await tryAuth(socket);
if (socket.data.pendingRoomId) {
// an appId or pageId is pending for this socket, join now
joinEditRoom(
socket,
socket.data.pendingRoomId,
socket.data.pendingRoomPrefix
);
}
return isAuthenticated;
}
function joinEditRoom(socket: Socket, roomId: string, roomPrefix: string) {
// remove this socket from any other rooms with roomPrefix
if (socket.rooms) {
socket.rooms.forEach((roomName) => {
if (roomName.startsWith(roomPrefix)) {
socket.leave(roomName);
}
});
}
// add this socket to room with application id
let roomName = roomPrefix + roomId;
socket.join(roomName);
}
function findPolicyEmails(policies: Policy[], permission: string): string[] {
const emails: string[] = [];
for (const policy of policies) {
if (policy.permission === permission) {
for (const email of policy.users) {
emails.push(email);
}
break;
}
}
return emails;
}
function sendCurrentUsers(socketIo, roomName: string, roomPrefix: string) {
if (roomName.startsWith(roomPrefix)) {
socketIo
.in(roomName)
.fetchSockets()
.then((sockets) => {
let onlineUsernames = new Set<string>();
let onlineUsers = new Array<AppUser>();
if (sockets) {
sockets.forEach((s) => {
if (!onlineUsernames.has(s.data.email)) {
onlineUsers.push(new AppUser(s.data.name, s.data.email));
}
onlineUsernames.add(s.data.email);
});
}
let resourceId = roomName.replace(roomPrefix, ""); // get resourceId from room name by removing the prefix
let response = new CurrentEditorsEvent(resourceId, onlineUsers);
socketIo.to(roomName).emit(EDITORS_EVENT_NAME, response);
});
}
}
export {
subscribeToEditEvents,
onAppSocketConnected,
onPageSocketConnected,
sendCurrentUsers,
findPolicyEmails,
};