Skip to content

Commit

Permalink
Fix blank screen issue on sync
Browse files Browse the repository at this point in the history
  • Loading branch information
Eclipse-Dominator committed Nov 14, 2023
1 parent 5213360 commit d1f7aa3
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
} from "@chakra-ui/react";
import { useMatchmake } from "../../contexts/matchmake.context";
import { AiOutlineDisconnect as DisconnectIcon } from "react-icons/ai";
import { useSelector } from "react-redux";
import { selectUser } from "../../reducers/authSlice";

const diffRange = [
[0, 2.9],
Expand All @@ -24,6 +26,7 @@ const diffRange = [
];

const MatchMakeBtn = () => {
const user = useSelector(selectUser);
const {
findMatch,
isMatching,
Expand All @@ -34,6 +37,8 @@ const MatchMakeBtn = () => {
quitRoom,
} = useMatchmake();

if (!user) return <></>;

return matchedRoom ? (
<ButtonGroup isAttached variant="outline">
<Tooltip label="Leave match" aria-label="collaborate">
Expand Down
13 changes: 11 additions & 2 deletions frontend/src/contexts/matchmake.context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ interface MatchmakeContextInterface {
quitRoom: () => void;
disconnectRoom: () => void;
restoreRoom: () => void;
reloadRoom: () => void;
isMatching: boolean;
timeLeft?: number;
matchedRoom?: Match;
Expand All @@ -43,6 +44,7 @@ const MatchmakeContext = createContext<MatchmakeContextInterface>({
quitRoom: () => {},
disconnectRoom: () => {},
restoreRoom: () => {},
reloadRoom: () => {},
isMatching: false,
});

Expand Down Expand Up @@ -230,18 +232,25 @@ export const MatchmakeProvider = ({
const restoreRoom = () => {
if (!socket || !user) return;
if (!socket.connected) socket.connect();
console.log("attempt to reconnect");
socket.emit("restore", user.username);
};

const reloadRoom = () => {
if (!socket || !user || !socket.connected || !matchedRoom) return;
console.log("attempting to reload");
setMatchedRoom({
...matchedRoom,
});
};

const memo = useMemo(() => {
console.log("matchmake update");
return {
findMatch,
cancelMatch,
quitRoom,
disconnectRoom,
restoreRoom,
reloadRoom,
isMatching,
matchedRoom,
timeLeft,
Expand Down
25 changes: 20 additions & 5 deletions frontend/src/contexts/sharededitor.context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const SharedEditorProvider = ({
const user = useSelector(selectUser) as User; // null check should be done before this

// exposed variables
const { matchedRoom, disconnectRoom } = useMatchmake();
const { matchedRoom, disconnectRoom, reloadRoom } = useMatchmake();
const [lang, setLang] = useState<language>();
const [codeUndo, setCodeUndo] = useState<Y.UndoManager>();
const [ycode, setycode] = useState<Y.Text>();
Expand All @@ -140,10 +140,12 @@ export const SharedEditorProvider = ({
const lastSubmissionToastId = useRef<ToastId | undefined>();
const lastLangSelected = useRef<language | undefined>();
const lastCode = useRef<string | undefined>();
const lastChat = useRef<chatRecord[]>([]);
const cachedPastSubmissions = useRef<submissionRecord[]>([]);
const _states = useRef<Y.Map<any> | undefined>();
const _submissions = useRef<Y.Array<any> | undefined>();
const _poll_interval = useRef<NodeJS.Timeout | undefined>();
const _reloadTimeout = useRef<NodeJS.Timeout | undefined>();

const myAvatar = getProfilePicUrl(user.profilePic);

Expand All @@ -155,7 +157,7 @@ export const SharedEditorProvider = ({
source_code: submission.code,
qn__id: submission.qn_id,
uid: submission.user,
})
});

const token = res.data.token as string;

Expand Down Expand Up @@ -254,6 +256,8 @@ export const SharedEditorProvider = ({
useEffect(() => {
const doc = new Y.Doc();
const ychat = doc.getArray<chatRecord>(CHAT_KEY);
if (!matchedRoom) lastChat.current = [];
ychat.push(lastChat.current);
_setChat(ychat);
const ysubmissions = doc.getArray<submissionRecord>(SUBMISSION_HISTORY_KEY);
_submissions.current = ysubmissions;
Expand Down Expand Up @@ -347,7 +351,6 @@ export const SharedEditorProvider = ({
lastLangSelected.current = randLang;
ystates.set(CURR_LANG_STATE, randLang);
ycode.insert(0, lastCode.current ?? LangDataMap[randLang]?.default ?? "");
ystates.set("SYNCEVENT", user.id + random.uint32().toString());
};

const setCodeFromMap = () => {
Expand Down Expand Up @@ -382,8 +385,12 @@ export const SharedEditorProvider = ({

const waitForInit = (e: Y.YMapEvent<any>, t: Y.Transaction) => {
// the initer have not initialized the code => wait for him to do so
if (!ystates.has(CODE_STATE)) return;
console.log("waiting for init");
if (!ystates.get(CODE_STATE)) return;
setCodeFromMap();
console.log("Success");
clearTimeout(_reloadTimeout.current);
_reloadTimeout.current = undefined;
ystates.unobserve(waitForInit); // remove this method from observer
ystates.observe(stateEventObserver);
};
Expand All @@ -405,6 +412,9 @@ export const SharedEditorProvider = ({
initStates();
} else {
ystates.observe(waitForInit);
_reloadTimeout.current = setTimeout(() => {
reloadRoom();
}, 2000); // reload if not connected after 2s
}

(async () => {
Expand Down Expand Up @@ -446,12 +456,17 @@ export const SharedEditorProvider = ({
});

return () => {
console.log("destroying provider");
lastCode.current = ycode?.toString();
lastChat.current = ychat.toArray();
console.log(lastChat.current, matchedRoom);
_states.current = undefined;
cachedPastSubmissions.current = cachedPastSubmissions.current.concat(
ysubmissions.toArray()
);
clearTimeout(_reloadTimeout.current);
_reloadTimeout.current = undefined;
clearInterval(_poll_interval.current);
_poll_interval.current = undefined;
_provider.destroy();
doc.destroy();

Expand Down
26 changes: 21 additions & 5 deletions frontend/src/pages/ViewQuestionPage/ViewQuestion.page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { redirect, LoaderFunction, useLoaderData } from "react-router-dom";
import { redirect, LoaderFunction } from "react-router-dom";
import {
HStack,
VStack,
Expand All @@ -12,6 +12,7 @@ import {
MenuButton,
MenuList,
MenuItem,
Skeleton,
} from "@chakra-ui/react";
import { Question } from "../../models/Question.model";
import { QnDrawer } from "../../components/QnDrawer/QnDrawer.component";
Expand All @@ -20,7 +21,6 @@ import "./ViewQuestion.page.css";
import store from "../../reducers/store";
import { loadQuestions } from "../../data/sampleqn";
import { fetchQuestion } from "../../api/questions";
import { useMatchmake } from "../../contexts/matchmake.context";
import CollabEditor from "../../components/CollabEditor/CollabEditor.component";
import { useContext } from "react";
import {
Expand Down Expand Up @@ -54,22 +54,38 @@ export const qnLoader: LoaderFunction<Question> = async ({ params }) => {
return qn ?? redirect("/");
};

const loadingSkeleton = () => {
return (
<HStack className="fit-parent" padding={2.5}>
<VStack className="fit-parent" gap="1">
<Skeleton width="100%" height="5%" speed={0.9}></Skeleton>
<Skeleton width="100%" height="95%" speed={1}></Skeleton>
</VStack>
<VStack h="100%" w="30%">
<Skeleton className="fit-parent" speed={1.1}></Skeleton>
<Skeleton className="fit-parent" speed={1.2}></Skeleton>
<Skeleton height="10%" width="100%" speed={1.3}></Skeleton>
</VStack>
</HStack>
);
};

const InnerViewQuestion = () => {
const {
qn,
chat,
lang,
replaceCode,
changeLang,
currSubmission,
submitCode,
ycode,
} = useContext(SharedEditorContext);

return (
<>
{qn ? <QnDrawer question={qn} size="xl" /> : <></>}
{!lang ? (
<></>
{!(lang && ycode) ? (
loadingSkeleton()
) : (
<HStack className="fit-parent" padding={2.5}>
<VStack className="fit-parent" gap="1">
Expand Down
20 changes: 12 additions & 8 deletions matching_service/src/sockethandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ const handleMatchRequest = async (
const match = await createMatch(potMatch, userInterval.user);

detail.match = {
// update for this socker user
...match,
isMaster: true,
};
Expand All @@ -186,27 +187,30 @@ const handleMatchRequest = async (
continue;
}
matchedUserDetail.match = {
// update for matched user from interval tree
...match,
user: userInterval.user,
isMaster: false,
};

// update for this user from this socket
io.to(userInterval.user)
.except(socket.id)
// .except(socket.id)
.emit("matchFound", {
...matchedUserDetail.match,
init: false,
...detail.match,
init: true,
} as Match);

// update for matched partner from this socket
io.to(match.user).emit("matchFound", {
...detail.match,
...matchedUserDetail.match,
init: false,
} as Match);

socket.emit("matchFound", {
...detail.match,
init: true,
} as Match);
// socket.emit("matchFound", {
// ...detail.match,
// init: true,
// } as Match);

return;
}
Expand Down

0 comments on commit d1f7aa3

Please sign in to comment.