From 716f26cf0be4e6ece89644a518e17351f6c74081 Mon Sep 17 00:00:00 2001 From: jmsandiegoo Date: Wed, 13 Nov 2024 00:29:07 +0800 Subject: [PATCH 1/2] Fix collaboration service and session context bug --- .../collaborationws.controller.ts | 48 +++---- frontend/src/contexts/SessionContext.tsx | 134 +++++++++--------- 2 files changed, 92 insertions(+), 90 deletions(-) diff --git a/backend/gateway-service/src/modules/collaboration/collaborationws.controller.ts b/backend/gateway-service/src/modules/collaboration/collaborationws.controller.ts index 835b039257..a14375587c 100644 --- a/backend/gateway-service/src/modules/collaboration/collaborationws.controller.ts +++ b/backend/gateway-service/src/modules/collaboration/collaborationws.controller.ts @@ -109,19 +109,12 @@ export class CollaborationGateway implements OnGatewayDisconnect { language: existingLanguage || 'python3', // default language sessionUserProfiles, // returns the all session member profiles }); - - return { - success: true, - data: { - messages, // chat messages - }, - }; } catch (e) { console.log(e); - return { - success: false, + client.emit(SESSION_ERROR, { + event: SESSION_JOIN, error: `Failed to join session: ${e.message}`, - }; + }); } } @@ -158,10 +151,11 @@ export class CollaborationGateway implements OnGatewayDisconnect { sessionUserProfiles, }); } catch (e) { - return { - success: false, + console.log(e); + client.emit(SESSION_ERROR, { + event: SESSION_JOIN, error: `Failed to leave session: ${e.message}`, - }; + }); } } @@ -191,18 +185,13 @@ export class CollaborationGateway implements OnGatewayDisconnect { message, timestamp, }); - - return { - success: true, - data: { id }, - }; } catch (e) { console.log(e); - return { - success: false, - data: { id }, + client.emit(SESSION_ERROR, { + event: CHAT_SEND_MESSAGE, + data: { id, timestamp }, error: `Failed to send message: ${e.message}`, - }; + }); } } @@ -222,7 +211,10 @@ export class CollaborationGateway implements OnGatewayDisconnect { const { userId, sessionId, questionId, code, language } = payload; if (!userId || !sessionId || !code) { - client.emit(SESSION_ERROR, 'Invalid submit request payload.'); + client.emit(SESSION_ERROR, { + event: SUBMIT, + error: 'Invalid submit request payload.', + }); return; } @@ -316,7 +308,10 @@ export class CollaborationGateway implements OnGatewayDisconnect { const { userId, sessionId, language } = payload; if (!userId || !sessionId || !language) { - client.emit(SESSION_ERROR, 'Invalid change language request payload.'); + client.emit(SESSION_ERROR, { + event: CHANGE_LANGUAGE, + error: 'Invalid change language request payload.', + }); return; } @@ -345,7 +340,10 @@ export class CollaborationGateway implements OnGatewayDisconnect { const { userId, sessionId } = payload; if (!userId || !sessionId) { - client.emit(SESSION_ERROR, 'Invalid change language request payload.'); + client.emit(SESSION_ERROR, { + event: SESSION_END, + error: 'Invalid session end request payload.', + }); return; } diff --git a/frontend/src/contexts/SessionContext.tsx b/frontend/src/contexts/SessionContext.tsx index 1b662fe91b..da1bbfec28 100644 --- a/frontend/src/contexts/SessionContext.tsx +++ b/frontend/src/contexts/SessionContext.tsx @@ -162,39 +162,7 @@ export const SessionProvider: React.FC = ({ setMessages((prev) => [...prev, newMessage]); - socket.emit( - "chatSendMessage", - newMessage, - (ack: { - success: boolean; - data: { id: string; timestamp: string }; - error: string | undefined; - }) => { - setMessages((prev) => - prev.map((message) => { - if (message.id !== ack.data.id) return message; - if (ack.success) { - return { - ...message, - status: ChatMessageStatusEnum.enum.sent, - }; - } else { - return { - ...message, - status: ChatMessageStatusEnum.enum.failed, - }; - } - }) - ); - - if (ack.success) { - newMessage.status = ChatMessageStatusEnum.enum.sent; - newMessage.timestamp = ack.data.timestamp; - } else { - newMessage.status = ChatMessageStatusEnum.enum.failed; - } - } - ); + socket.emit("chatSendMessage", newMessage); }, [sessionId, socket, userProfile.id] ); @@ -202,55 +170,44 @@ export const SessionProvider: React.FC = ({ const handleJoinSession = useCallback( (payload: SessionJoinRequest) => { if (!socket.connected) return; - - socket.emit( - "sessionJoin", - payload, - (ack: { - success: boolean; - data: { messages: ChatMessages }; - error: string | undefined; - }) => { - try { - if (!ack.success) throw new Error(ack.error); - setConnectionStatus("connected"); - const currentMessages = ChatMessagesSchema.parse( - ack.data.messages.map((message: ChatMessage) => ({ - ...message, - status: ChatMessageStatusEnum.enum.sent, - })) - ); - setMessages([...currentMessages]); - } catch (e) { - setConnectionStatus("failed"); - } - } - ); + socket.emit("sessionJoin", payload); }, [socket] ); const onSessionJoined = useCallback( ({ + userId, language, sessionUserProfiles, }: { + userId: string; language: string; + messages: ChatMessages; sessionUserProfiles: SessionUserProfiles; }) => { console.log("sessionJoined occured"); try { - _setLanguage(language); + if (userProfile.id === userId) { + setConnectionStatus("connected"); + const currentMessages = ChatMessagesSchema.parse( + messages.map((message: ChatMessage) => ({ + ...message, + status: ChatMessageStatusEnum.enum.sent, + })) + ); + setMessages([...currentMessages]); + } + _setLanguage(language); const currentSessionUserProfiles = SessionUserProfilesSchema.parse(sessionUserProfiles); setSessionUserProfiles([...currentSessionUserProfiles]); } catch (e) { - // TODO toast here console.log(e); } }, - [] + [messages, userProfile.id] ); const onChatReceiveMessage = useCallback( @@ -259,7 +216,19 @@ export const SessionProvider: React.FC = ({ newMessage["status"] = ChatMessageStatusEnum.enum.sent; const messageParsed = ChatMessageSchema.parse(newMessage); - if (messageParsed.userId === userProfile.id) return; + if (messageParsed.userId === userProfile.id) { + // set the loclly sent message + setMessages((prev) => + prev.map((message) => { + if (message.id !== messageParsed.id) return message; + return { + ...message, + status: ChatMessageStatusEnum.enum.sent, + }; + }) + ); + return; + } setMessages((prev) => [...prev, messageParsed]); } catch (e) { @@ -370,7 +339,7 @@ export const SessionProvider: React.FC = ({ userId: userProfile.id, sessionId, }); - }, [socket]); + }, [sessionId, socket, userProfile.id]); const onSessionEnded = useCallback( ({ endedBy }: { endedBy: string; message: string }) => { @@ -386,7 +355,39 @@ export const SessionProvider: React.FC = ({ router.push("/dashboard"); }, 4000); }, - [toast, router] + [toast, userProfile.id, router] + ); + + const onSessionError = useCallback( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ({ + event, + data, + error, + }: { + event: string; + data: undefined | { id: string; timestamp: string }; + error: string; + }) => { + console.log(`Session Error received ${error}`); + + if (event === "sessionJoin") { + setConnectionStatus("failed"); + } + + if (event === "chatReceiveMessage") { + setMessages((prev) => + prev.map((message) => { + if (message.id !== data?.id) return message; + return { + ...message, + status: ChatMessageStatusEnum.enum.failed, + }; + }) + ); + } + }, + [] ); // connect to the session socket on mount @@ -412,6 +413,7 @@ export const SessionProvider: React.FC = ({ socket.on("submitted", onSubmitted); socket.on("sessionEnded", onSessionEnded); + socket.on("sessionError", onSessionError); return () => { socket.emit("sessionLeave", { @@ -432,6 +434,8 @@ export const SessionProvider: React.FC = ({ onSessionJoined, onSessionLeft, onLanguageChanged, + onSessionEnded, + onSessionError, ]); const contextValue: SessionContextType = useMemo( @@ -463,7 +467,6 @@ export const SessionProvider: React.FC = ({ }), [ connectionStatus, - codeReview, sessionId, sessionUserProfiles, getUserProfileDetailByUserId, @@ -476,7 +479,8 @@ export const SessionProvider: React.FC = ({ submitting, submissionResult, testResultPanel, - setTestResultPanel, + endSession, + codeReview, setCurrentClientCode, generateCodeReview, ] From 98b5bc72e260ff9e1df46ceffe4be717afbdb71a Mon Sep 17 00:00:00 2001 From: jmsandiegoo Date: Wed, 13 Nov 2024 01:01:16 +0800 Subject: [PATCH 2/2] Fix more bugs with collaboration both fe and be --- .../collaboration/collaborationws.controller.ts | 2 +- .../CollaborativeEditor/CollaborativeEditorTab.tsx | 2 +- frontend/src/contexts/SessionContext.tsx | 11 +++++++---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/backend/gateway-service/src/modules/collaboration/collaborationws.controller.ts b/backend/gateway-service/src/modules/collaboration/collaborationws.controller.ts index a14375587c..e52e91aa3e 100644 --- a/backend/gateway-service/src/modules/collaboration/collaborationws.controller.ts +++ b/backend/gateway-service/src/modules/collaboration/collaborationws.controller.ts @@ -105,7 +105,7 @@ export class CollaborationGateway implements OnGatewayDisconnect { this.server.to(sessionId).emit(SESSION_JOINED, { userId, // the user who recently joined sessionId, - messages, // chat messages + sessionMessages: messages, // chat messages language: existingLanguage || 'python3', // default language sessionUserProfiles, // returns the all session member profiles }); diff --git a/frontend/src/app/collaboration/_components/Editor/CollaborativeEditor/CollaborativeEditorTab.tsx b/frontend/src/app/collaboration/_components/Editor/CollaborativeEditor/CollaborativeEditorTab.tsx index 8da6a0d5be..65901cabcf 100644 --- a/frontend/src/app/collaboration/_components/Editor/CollaborativeEditor/CollaborativeEditorTab.tsx +++ b/frontend/src/app/collaboration/_components/Editor/CollaborativeEditor/CollaborativeEditorTab.tsx @@ -5,7 +5,7 @@ import { useSessionContext } from "@/contexts/SessionContext"; export default function CollaborativeEditorTab() { const {sessionId, userProfile} = useSessionContext(); - const socketUrl = process.env.NEXT_PUBLIC_Y_WEBSOCKET_URL || "ws://localhost:4001"; + const socketUrl = process.env.PUBLIC_Y_WEBSOCKET_URL || "ws://localhost:4001"; if (!userProfile) { return
Loading user profile...
; diff --git a/frontend/src/contexts/SessionContext.tsx b/frontend/src/contexts/SessionContext.tsx index da1bbfec28..21fed6ea99 100644 --- a/frontend/src/contexts/SessionContext.tsx +++ b/frontend/src/contexts/SessionContext.tsx @@ -179,11 +179,12 @@ export const SessionProvider: React.FC = ({ ({ userId, language, + sessionMessages, sessionUserProfiles, }: { userId: string; language: string; - messages: ChatMessages; + sessionMessages: ChatMessages; sessionUserProfiles: SessionUserProfiles; }) => { console.log("sessionJoined occured"); @@ -191,11 +192,12 @@ export const SessionProvider: React.FC = ({ if (userProfile.id === userId) { setConnectionStatus("connected"); const currentMessages = ChatMessagesSchema.parse( - messages.map((message: ChatMessage) => ({ + sessionMessages.map((message: ChatMessage) => ({ ...message, status: ChatMessageStatusEnum.enum.sent, })) ); + setMessages([...currentMessages]); } @@ -207,11 +209,12 @@ export const SessionProvider: React.FC = ({ console.log(e); } }, - [messages, userProfile.id] + [userProfile.id] ); const onChatReceiveMessage = useCallback( (newMessage: ChatMessage) => { + console.log("chatReceiveMessage occured"); try { newMessage["status"] = ChatMessageStatusEnum.enum.sent; const messageParsed = ChatMessageSchema.parse(newMessage); @@ -375,7 +378,7 @@ export const SessionProvider: React.FC = ({ setConnectionStatus("failed"); } - if (event === "chatReceiveMessage") { + if (event === "chatSendMessage") { setMessages((prev) => prev.map((message) => { if (message.id !== data?.id) return message;