Skip to content

Commit

Permalink
Merge pull request #131 from CS3219-AY2425S1/jmsandiegoo/bugfix
Browse files Browse the repository at this point in the history
Collaboration Bug Fixes
  • Loading branch information
rickkoh authored Nov 12, 2024
2 parents 2dad575 + 98b5bc7 commit 71fae00
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -105,23 +105,16 @@ 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
});

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}`,
};
});
}
}

Expand Down Expand Up @@ -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}`,
};
});
}
}

Expand Down Expand Up @@ -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}`,
};
});
}
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 <div>Loading user profile...</div>;
Expand Down
137 changes: 72 additions & 65 deletions frontend/src/contexts/SessionContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,104 +162,76 @@ export const SessionProvider: React.FC<SessionProviderProps> = ({

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]
);

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,
sessionMessages,
sessionUserProfiles,
}: {
userId: string;
language: string;
sessionMessages: ChatMessages;
sessionUserProfiles: SessionUserProfiles;
}) => {
console.log("sessionJoined occured");
try {
_setLanguage(language);
if (userProfile.id === userId) {
setConnectionStatus("connected");
const currentMessages = ChatMessagesSchema.parse(
sessionMessages.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);
}
},
[]
[userProfile.id]
);

const onChatReceiveMessage = useCallback(
(newMessage: ChatMessage) => {
console.log("chatReceiveMessage occured");
try {
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) {
Expand Down Expand Up @@ -370,7 +342,7 @@ export const SessionProvider: React.FC<SessionProviderProps> = ({
userId: userProfile.id,
sessionId,
});
}, [socket]);
}, [sessionId, socket, userProfile.id]);

const onSessionEnded = useCallback(
({ endedBy }: { endedBy: string; message: string }) => {
Expand All @@ -386,7 +358,39 @@ export const SessionProvider: React.FC<SessionProviderProps> = ({
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 === "chatSendMessage") {
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
Expand All @@ -412,6 +416,7 @@ export const SessionProvider: React.FC<SessionProviderProps> = ({
socket.on("submitted", onSubmitted);

socket.on("sessionEnded", onSessionEnded);
socket.on("sessionError", onSessionError);

return () => {
socket.emit("sessionLeave", {
Expand All @@ -432,6 +437,8 @@ export const SessionProvider: React.FC<SessionProviderProps> = ({
onSessionJoined,
onSessionLeft,
onLanguageChanged,
onSessionEnded,
onSessionError,
]);

const contextValue: SessionContextType = useMemo(
Expand Down Expand Up @@ -463,7 +470,6 @@ export const SessionProvider: React.FC<SessionProviderProps> = ({
}),
[
connectionStatus,
codeReview,
sessionId,
sessionUserProfiles,
getUserProfileDetailByUserId,
Expand All @@ -476,7 +482,8 @@ export const SessionProvider: React.FC<SessionProviderProps> = ({
submitting,
submissionResult,
testResultPanel,
setTestResultPanel,
endSession,
codeReview,
setCurrentClientCode,
generateCodeReview,
]
Expand Down

0 comments on commit 71fae00

Please sign in to comment.