From 624de993c972d2e8da10e5a9acf50f815519f8e0 Mon Sep 17 00:00:00 2001 From: ZQ Date: Wed, 15 Nov 2023 16:54:23 +0800 Subject: [PATCH] fix submission --- code_execution/src/executor_client.ts | 13 ++++- code_execution/src/index.ts | 4 +- frontend/src/contexts/matchmake.context.tsx | 6 +-- .../src/contexts/sharededitor.context.tsx | 9 ++-- matching_service/src/engine.ts | 6 +-- matching_service/src/shared.ts | 4 +- matching_service/src/sockethandlers.ts | 51 ++++++++++--------- matching_service/src/types.ts | 6 +-- 8 files changed, 56 insertions(+), 43 deletions(-) diff --git a/code_execution/src/executor_client.ts b/code_execution/src/executor_client.ts index 3f531cf2..69a04950 100644 --- a/code_execution/src/executor_client.ts +++ b/code_execution/src/executor_client.ts @@ -149,7 +149,7 @@ export async function runSubmission( lang: string, qn__id: string, source_code: string, - userid: number + userids: number[] ) { const submissionTime = new Date(); const resDat: submissionResult = { @@ -186,5 +186,14 @@ export async function runSubmission( resDat.verdict = resDat.verdict === "Unknown" ? "Accepted" : resDat.verdict; resDat.completed = true; - submitSubmission(resDat.verdict, lang, qn__id, userid, source_code, submissionTime); // runs in the bg + for (const userid of userids) { + submitSubmission( + resDat.verdict, + lang, + qn__id, + userid, + source_code, + submissionTime + ); // runs in the bg + } } diff --git a/code_execution/src/index.ts b/code_execution/src/index.ts index cbfb2055..330a1eb6 100644 --- a/code_execution/src/index.ts +++ b/code_execution/src/index.ts @@ -14,10 +14,10 @@ app.use(bodyParser.urlencoded({ extended: true })); app.post("/api/code/submit", async (req, res) => { try { // Extracts these 4 variables - const { lang, source_code, qn__id, uid } = req.body; + const { lang, source_code, qn__id, uids } = req.body; const randid = uuidv4(); - runSubmission(randid, lang, qn__id, source_code, uid); + runSubmission(randid, lang, qn__id, source_code, uids); res.json({ token: randid }); } catch (error) { console.error(error); diff --git a/frontend/src/contexts/matchmake.context.tsx b/frontend/src/contexts/matchmake.context.tsx index 4dd511bc..8883485a 100644 --- a/frontend/src/contexts/matchmake.context.tsx +++ b/frontend/src/contexts/matchmake.context.tsx @@ -13,7 +13,7 @@ import { wsMatchMakeURL } from "../api/gateway"; import { ToastId, useToast, UseToastOptions } from "@chakra-ui/react"; export interface Match { - user: string; + userId: number; room: string; questionId: string; isMaster: boolean; @@ -204,7 +204,7 @@ export const MatchmakeProvider = ({ duration: null, }); socket.emit("findMatch", { - username: user.username, + uid: user.id, preferredQn: qn__id, from: diffStart, to: diffEnd, @@ -233,7 +233,7 @@ export const MatchmakeProvider = ({ const restoreRoom = () => { if (!socket || !user) return; if (!socket.connected) socket.connect(); - socket.emit("restore", user.username); + socket.emit("restore", user.id); }; const reloadRoom = () => { diff --git a/frontend/src/contexts/sharededitor.context.tsx b/frontend/src/contexts/sharededitor.context.tsx index 3e557272..41f0e274 100644 --- a/frontend/src/contexts/sharededitor.context.tsx +++ b/frontend/src/contexts/sharededitor.context.tsx @@ -50,7 +50,7 @@ export type SubmissionResult = { export type submissionRecord = { time: number; - userId: number; + userIds: number[]; qn_id: string; code: string; lang: language; @@ -156,7 +156,7 @@ export const SharedEditorProvider = ({ lang: submission.lang, source_code: submission.code, qn__id: submission.qn_id, - uid: submission.userId, + uids: submission.userIds, }); const token = res.data.token as string; @@ -200,7 +200,7 @@ export const SharedEditorProvider = ({ if (!state || currSubmission || !lang || !ycode) return; const tmp: submissionRecord = { time: Date.now(), - userId: user.id, + userIds: matchedRoom ? [user.id, matchedRoom.userId] : [user.id], code: ycode.toString(), lang: lang, qn_id: qn?._id ?? "-1", // in case we implement a sandbox code editor @@ -276,7 +276,7 @@ export const SharedEditorProvider = ({ (ystates.get(SUBMISSION_STATE) as submissionRecord) ?? null; setCurrSubmission(newSubmission); // if react changes are propageted in the next cycle. - if (newSubmission && newSubmission.userId !== user.id) { + if (newSubmission && newSubmission.userIds[0] !== user.id) { if (!matchedRoom || matchedRoom.isMaster) { // if a master receive it if (!currSubmission) { @@ -425,7 +425,6 @@ export const SharedEditorProvider = ({ }; const observeDocLoad = (e: Y.YMapEvent, t: Y.Transaction) => { - if (t.local) return; // wait for our local change to propagaate back to us if (ystates.has(CODE_STATE)) { setCodeFromMap(); } diff --git a/matching_service/src/engine.ts b/matching_service/src/engine.ts index 7af3ace7..b0aa3e12 100644 --- a/matching_service/src/engine.ts +++ b/matching_service/src/engine.ts @@ -48,7 +48,7 @@ export const findMatch = (user: UserInterval): UserInterval | null => { return null; }; -export const createMatch = async (potMatch: UserInterval, user: string) => { +export const createMatch = async (potMatch: UserInterval, uid: number) => { // interleaving can occur here const qn = potMatch.preferredQn ?? @@ -58,7 +58,7 @@ export const createMatch = async (potMatch: UserInterval, user: string) => { return { questionId: qn, - room: Buffer.from(`${user}${potMatch.user}/${qn}`).toString("base64"), - user: potMatch.user, + room: Buffer.from(`${uid}${potMatch.user}/${qn}`).toString("base64"), + userId: potMatch.user, }; }; diff --git a/matching_service/src/shared.ts b/matching_service/src/shared.ts index fe676360..0dd03bc4 100644 --- a/matching_service/src/shared.ts +++ b/matching_service/src/shared.ts @@ -1,4 +1,4 @@ import { socketDetail } from "./types"; -export const socketDetails: Record = {}; -export const sockToUser: Record = {}; +export const socketDetails: Record = {}; +export const sockToUser: Record = {}; diff --git a/matching_service/src/sockethandlers.ts b/matching_service/src/sockethandlers.ts index 09b92d91..a61c47f5 100644 --- a/matching_service/src/sockethandlers.ts +++ b/matching_service/src/sockethandlers.ts @@ -11,7 +11,7 @@ import { sockToUser, socketDetails } from "./shared"; const removeUser = ( io: Server, - user: string, + user: number, allowJoinbackIfInMatch: boolean = false ) => { const detail = socketDetails[user]; @@ -22,7 +22,7 @@ const removeUser = ( if (detail.joinbackTimer) clearTimeout(detail.joinbackTimer); delete socketDetails[user]; console.log("disconnecting all instances of", user); - io.in(user).disconnectSockets(); + io.in(user.toString()).disconnectSockets(); return; } @@ -32,12 +32,12 @@ const removeUser = ( // promote the other user the master to handle submission event match.isMaster = false; - const matchedDetail = socketDetails[match.user]; + const matchedDetail = socketDetails[match.userId]; if (matchedDetail?.joinbackTimer) { // the other user disconnected too, so we just remove both removeUser(io, user); - removeUser(io, match.user); + removeUser(io, match.userId); return; } @@ -47,7 +47,7 @@ const removeUser = ( } // match.user is the user that is matched with - io.to(match.user).emit("matchEnded", { + io.to(match.userId.toString()).emit("matchEnded", { joinback: true, reason: "Opponent disconnected", match: opponentRoom, @@ -55,21 +55,21 @@ const removeUser = ( detail.joinbackTimer = setTimeout(() => { removeUser(io, user); - io.to(match.user).emit("matchEnded", { + io.to(match.userId.toString()).emit("matchEnded", { joinback: false, reason: "Opponent did not join back", } as RoomCloseResponse); - removeUser(io, match.user); + removeUser(io, match.userId); }, 10000); }; // restore user to queue or match -const restore = (socket: Socket, user: string) => { +const restore = (socket: Socket, user: number) => { console.log("restore match received from", socket.id, "for", user); const detail = socketDetails[user]; if (!detail) return false; - socket.join(user); + socket.join(user.toString()); sockToUser[socket.id] = user; detail.connectionCount++; if (!detail.match) { @@ -103,11 +103,11 @@ const quitRoom = (io: Server, socket: Socket) => { const match = socketDetails[user]?.match; if (!match) return; // this shouldnt happen, but safe guard removeUser(io, user); - io.to(match.user).emit("matchEnded", { + io.to(match.userId.toString()).emit("matchEnded", { joinback: false, reason: "Opponent left the room", } as RoomCloseResponse); - removeUser(io, match.user); + removeUser(io, match.userId); }; const handleMatchRequest = async ( @@ -115,24 +115,24 @@ const handleMatchRequest = async ( socket: Socket, req: MatchRequest ) => { - console.log(`Match request received from ${req.username}`); + console.log(`Match request received from ${req.uid}`); - if (restore(socket, req.username)) return; + if (restore(socket, req.uid)) return; // no interleaving between sync blocks in Nodejs let detail: socketDetail = { UserDetail: { low: req.from, high: req.to, preferredQn: req.preferredQn, - user: req.username, + user: req.uid, }, countdown: undefined, inQueue: false, connectionCount: 1, }; - socketDetails[req.username] = detail; - sockToUser[socket.id] = req.username; - socket.join(req.username); + socketDetails[req.uid] = detail; + sockToUser[socket.id] = req.uid; + socket.join(req.uid.toString()); let userInterval: UserInterval | undefined = detail.UserDetail; @@ -153,12 +153,17 @@ const handleMatchRequest = async ( clearInterval(userDet.countdown); return; } - io.to(userDet.UserDetail.user).emit("countdown", countdown--); + io.to(userDet.UserDetail.user.toString()).emit( + "countdown", + countdown-- + ); }, 1000); return; } - io.to([potMatch.user, userInterval.user]).emit("potentialMatch"); + io.to([potMatch.user.toString(), userInterval.user.toString()]).emit( + "potentialMatch" + ); let matchedUserDetail = socketDetails[potMatch.user]; if (!matchedUserDetail) continue; // this shouldnt happen, but safe guard @@ -174,7 +179,7 @@ const handleMatchRequest = async ( ...match, isMaster: true, }; - matchedUserDetail = socketDetails[match.user]; + matchedUserDetail = socketDetails[match.userId]; // matched user left/disconnected if (!matchedUserDetail) continue; @@ -189,12 +194,12 @@ const handleMatchRequest = async ( matchedUserDetail.match = { // update for matched user from interval tree ...match, - user: userInterval.user, + userId: userInterval.user, isMaster: false, }; // update for this user from this socket - io.to(userInterval.user) + io.to(userInterval.user.toString()) // .except(socket.id) .emit("matchFound", { ...detail.match, @@ -202,7 +207,7 @@ const handleMatchRequest = async ( } as Match); // update for matched partner from this socket - io.to(match.user).emit("matchFound", { + io.to(match.userId.toString()).emit("matchFound", { ...matchedUserDetail.match, init: false, } as Match); diff --git a/matching_service/src/types.ts b/matching_service/src/types.ts index 74be55ac..317af812 100644 --- a/matching_service/src/types.ts +++ b/matching_service/src/types.ts @@ -1,7 +1,7 @@ import { Interval } from "node-interval-tree"; export interface EngineMatch { - user: string; + userId: number; room: string; questionId: string; isMaster: boolean; @@ -18,14 +18,14 @@ export interface RoomCloseResponse { } export interface MatchRequest { - username: string; + uid: number; preferredQn?: string; from: number; to: number; } export interface UserInterval extends Interval { - user: string; + user: number; preferredQn?: string; }