Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display question and swap question in collaboration rooms #185

Merged
merged 33 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
97d1fa9
Correct name of swagger file
gycgabriel Oct 25, 2023
f0a9b7c
Add questionAdapter
gycgabriel Oct 25, 2023
9a64657
Add questionid to response
gycgabriel Oct 25, 2023
7c7c29d
Update questionId in match
gycgabriel Oct 25, 2023
67359b7
Update
gycgabriel Oct 25, 2023
45d0346
Fix swagger port
gycgabriel Oct 26, 2023
69c675d
Fix set question Id on match
gycgabriel Oct 26, 2023
23da323
Connect frontend questionId
gycgabriel Oct 26, 2023
55fc615
Fetch question Id from db
gycgabriel Oct 26, 2023
94ac75a
Merge branch 'master' into collab-room-question
gycgabriel Oct 30, 2023
9b7b8c6
Change to yarnpkg to avoid conflict with hadoop
gycgabriel Oct 30, 2023
1b2a836
Merge branch 'master' into collab-room-question
gycgabriel Oct 31, 2023
730cff4
Add getmatch api to matching service
gycgabriel Oct 31, 2023
eb5b23d
Create match api in frontend
gycgabriel Oct 31, 2023
facf301
Add call to useMatchmaking
gycgabriel Oct 31, 2023
29034c2
remove todo
gycgabriel Oct 31, 2023
c6bffcd
Update question
gycgabriel Oct 31, 2023
e128f5b
Update
gycgabriel Oct 31, 2023
a861377
console log
gycgabriel Oct 31, 2023
396b82d
Try to fix frontend
gycgabriel Oct 31, 2023
0aaf70a
Try fix frontend
gycgabriel Oct 31, 2023
cbb9cb4
Add dev local for colab service
gycgabriel Oct 31, 2023
0b987ec
Fix match api
gycgabriel Oct 31, 2023
905cdc9
Fix
gycgabriel Oct 31, 2023
ad67536
Pass user token through match api
gycgabriel Oct 31, 2023
58a66cc
Prevent null crash in colab room update
gycgabriel Oct 31, 2023
2905fba
Fix frontend to set question id in colab
gycgabriel Oct 31, 2023
e7ee10d
Add update questionId to match api
gycgabriel Oct 31, 2023
380d61a
Add update questionId in match to hooks
gycgabriel Oct 31, 2023
9dedbea
Minor fix
gycgabriel Oct 31, 2023
b8a5b87
Add swap question functionality
gycgabriel Oct 31, 2023
3b9427f
Improve UI
gycgabriel Oct 31, 2023
9216c7b
Fix lint
gycgabriel Oct 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 21 additions & 22 deletions frontend/providers/MatchmakingProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import React, {
import { io, Socket } from "socket.io-client";
import { Match } from "@prisma/client";
import { AuthContext } from "@/contexts/AuthContext";
import {matchSocketAddress} from "@/gateway-address/gateway-address";
import { matchSocketAddress } from "@/gateway-address/gateway-address";

const SERVER_URL = matchSocketAddress;

Expand Down Expand Up @@ -49,27 +49,25 @@ export const MatchmakingProvider: React.FC<MatchmakingProviderProps> = ({
// Initialize socket connection
useEffect(() => {
if (currentUser) {
currentUser.getIdToken(true).then(
(token) => {
const newSocket = io(SERVER_URL, {
autoConnect: false,
// query: { username: currentUser?.email },
query: { username: generateRandomNumber() },
extraHeaders: {
"User-Id-Token": token
},
path: "/match/socket.io"
});
setSocket(newSocket);
newSocket.connect();

console.log("Socket connected");

return () => {
newSocket.close();
};
}
)
currentUser.getIdToken(true).then((token) => {
const newSocket = io(SERVER_URL, {
autoConnect: false,
// query: { username: currentUser?.email },
query: { username: generateRandomNumber() },
extraHeaders: {
"User-Id-Token": token,
},
path: "/match/socket.io",
});
setSocket(newSocket);
newSocket.connect();

console.log("Socket connected");

return () => {
newSocket.close();
};
});
}
}, [currentUser]);

Expand All @@ -82,6 +80,7 @@ export const MatchmakingProvider: React.FC<MatchmakingProviderProps> = ({

socket.on("matchFound", (match: Match) => {
console.log("Match found:", match);
console.log("QuestionId:", match.questionId);
setMatch(match);
});

Expand Down
149 changes: 77 additions & 72 deletions frontend/src/hooks/useCollaboration.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useEffect, useState, useRef, use, useContext} from "react";
import { useEffect, useState, useRef, use, useContext } from "react";
import { io, Socket } from "socket.io-client";
import { debounce } from "lodash";
import {
Expand All @@ -7,8 +7,8 @@ import {
} from "../../../utils/shared-ot";
import { TextOp } from "ot-text-unicode";
import { Room, connect } from "twilio-video";
import {collaborationSocketAddress} from "@/gateway-address/gateway-address";
import {AuthContext} from "@/contexts/AuthContext";
import { collaborationSocketAddress } from "@/gateway-address/gateway-address";
import { AuthContext } from "@/contexts/AuthContext";

type UseCollaborationProps = {
roomId: string;
Expand All @@ -26,98 +26,103 @@ enum SocketEvents {

var vers = 0;

const useCollaboration = ({ roomId, userId, disableVideo }: UseCollaborationProps) => {
const useCollaboration = ({
roomId,
userId,
disableVideo,
}: UseCollaborationProps) => {
const [socket, setSocket] = useState<Socket | null>(null);
const [text, setText] = useState<string>("#Write your solution here");
const [cursor, setCursor] = useState<number>(
"#Write your solution here".length
);
const [room, setRoom] = useState<Room | null>(null); // twilio room
const [questionId, setQuestionId] = useState<string>("1");
const textRef = useRef<string>(text);
const cursorRef = useRef<number>(cursor);
const prevCursorRef = useRef<number>(cursor);
const prevTextRef = useRef<string>(text);
const awaitingAck = useRef<boolean>(false); // ack from sending update
const awaitingSync = useRef<boolean>(false); // synced with server
const twilioTokenRef = useRef<string>("");
const questionId = "1";
const { user: currentUser, authIsReady } = useContext(AuthContext);

useEffect(() => {
if (currentUser) {
currentUser.getIdToken(true).then(
(token) => {
const socketConnection = io(collaborationSocketAddress, {
extraHeaders: {
"User-Id-Token": token
},
path: "/collaboration/socket.io"
});
setSocket(socketConnection);

socketConnection.emit(SocketEvents.ROOM_JOIN, roomId, userId);
socketConnection.emit(SocketEvents.QUESTION_SET, questionId);

socketConnection.on("twilio-token", (token: string) => {
twilioTokenRef.current = token;
if (disableVideo) return;
connect(token, {
name: roomId, audio: true,
video: {width: 640, height: 480, frameRate: 24}
}).then((room) => {
currentUser.getIdToken(true).then((token) => {
const socketConnection = io(collaborationSocketAddress, {
extraHeaders: {
"User-Id-Token": token,
},
path: "/collaboration/socket.io",
});
setSocket(socketConnection);

socketConnection.emit(SocketEvents.ROOM_JOIN, roomId, userId);
socketConnection.emit(SocketEvents.QUESTION_SET, questionId);

socketConnection.on("twilio-token", (token: string) => {
twilioTokenRef.current = token;
if (disableVideo) return;
connect(token, {
name: roomId,
audio: true,
video: { width: 640, height: 480, frameRate: 24 },
})
.then((room) => {
console.log("Connected to Room");
setRoom(room);
}).catch(err => {
})
.catch((err) => {
console.log(err, token, userId, roomId);
});
});

socketConnection.on(
SocketEvents.ROOM_UPDATE,
({
version,
text,
cursor,
}: {
version: number;
text: string;
cursor: number | undefined | null;
}) => {
prevCursorRef.current = cursorRef.current;
console.log("prevCursor: " + prevCursorRef.current);

console.log("cursor: " + cursor);

console.log("Update vers to " + version);
vers = version;

if (awaitingAck.current) return;

textRef.current = text;
prevTextRef.current = text;
setText(text);
if (cursor && cursor > -1) {
console.log("Update cursor to " + cursor);
cursorRef.current = cursor;
setCursor(cursor);
} else {
cursorRef.current = prevCursorRef.current;
cursor = prevCursorRef.current;
console.log("Update cursor to " + prevCursorRef.current);
setCursor(prevCursorRef.current);
}
awaitingSync.current = false;
});

socketConnection.on(
SocketEvents.ROOM_UPDATE,
({
version,
text,
cursor,
}: {
version: number;
text: string;
cursor: number | undefined | null;
}) => {
prevCursorRef.current = cursorRef.current;
console.log("prevCursor: " + prevCursorRef.current);

console.log("cursor: " + cursor);

console.log("Update vers to " + version);
vers = version;

if (awaitingAck.current) return;

textRef.current = text;
prevTextRef.current = text;
setText(text);
if (cursor && cursor > -1) {
console.log("Update cursor to " + cursor);
cursorRef.current = cursor;
setCursor(cursor);
} else {
cursorRef.current = prevCursorRef.current;
cursor = prevCursorRef.current;
console.log("Update cursor to " + prevCursorRef.current);
setCursor(prevCursorRef.current);
}
);
awaitingSync.current = false;
}
);

return () => {
socketConnection.disconnect();
if (room) {
room.disconnect();
}
return () => {
socketConnection.disconnect();
if (room) {
room.disconnect();
}
}
);
};
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [roomId, userId]);
Expand Down Expand Up @@ -162,7 +167,7 @@ const useCollaboration = ({ roomId, userId, disableVideo }: UseCollaborationProp
});
}, [text, socket]);

return { text, setText, cursor, setCursor, room };
return { text, setText, cursor, setCursor, room, setQuestionId };
};

export default useCollaboration;
33 changes: 20 additions & 13 deletions frontend/src/pages/room/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,38 @@ import { TypographyBody } from "@/components/ui/typography";
import { useRouter } from "next/router";
import VideoRoom from "../../components/room/video-room";
import { Question } from "../../types/QuestionTypes";
import { useQuestions } from "@/hooks/useQuestions";

export default function Room() {
const router = useRouter();

const roomId = router.query.id as string;
const userId = router.query.userId as string || "user1";
const disableVideo = (router.query.disableVideo as string)?.toLowerCase() === "true";
const userId = (router.query.userId as string) || "user1";
const disableVideo =
(router.query.disableVideo as string)?.toLowerCase() === "true";

const { text, setText, cursor, setCursor, room } = useCollaboration({
roomId: roomId as string,
userId,
disableVideo,
});
const { text, setText, cursor, setCursor, room, setQuestionId } =
useCollaboration({
roomId: roomId as string,
userId,
disableVideo,
});

// const { } = useQuestions();
// TODO fetch question by question ID provided by matching service
// setQuestionId

const question: Question = {
title: "Two Sum",
difficulty: "Easy",
topics: ["Array", "Hash Table"],
description: "Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.\n\nYou may assume that each input would have exactly one solution, and you may not use the same element twice.\n\nYou can return the answer in any order.",
solution: "var twoSum = function(nums, target) {\n for (let i = 0; i < nums.length; i++) {\n for (let j = i + 1; j < nums.length; j++) {\n if (nums[i] + nums[j] === target) {\n return [i, j];\n }\n }\n }\n};",
description:
"Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.\n\nYou may assume that each input would have exactly one solution, and you may not use the same element twice.\n\nYou can return the answer in any order.",
solution:
"var twoSum = function(nums, target) {\n for (let i = 0; i < nums.length; i++) {\n for (let j = i + 1; j < nums.length; j++) {\n if (nums[i] + nums[j] === target) {\n return [i, j];\n }\n }\n }\n};",
defaultCode: { python: "var twoSum = function(nums, target) {\n\n};" },
id: "",
author: ""
author: "",
};

if (!router.isReady) return null;
Expand All @@ -46,9 +55,7 @@ export default function Room() {
</TabsTrigger>
</TabsList>
<TabsContent value="description" className="h-[79vh]">
<Description
question={question}
/>
<Description question={question} />
</TabsContent>
<TabsContent value="solution">{question.solution}</TabsContent>
</Tabs>
Expand Down
2 changes: 1 addition & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ datasource db {
url = env("PRISMA_DATABASE_URL")
}

// todo rename for colalboration service
model User {
id String @id @default(uuid())
isLookingForMatch Boolean
Expand All @@ -24,6 +23,7 @@ model Match {
userId2 String
chosenDifficulty String
chosenProgrammingLanguage String
questionId String?
createdAt DateTime @default(now())
}

Expand Down
1 change: 1 addition & 0 deletions services/matching-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "0.0.0",
"private": true,
"scripts": {
"dev:local": "dotenv -e ../.env -- yarn dev",
"build": "yarn run swagger-autogen && tsc",
"start": "node ./dist/src/app.js",
"dev": "yarn run swagger-autogen && nodemon src/app.ts",
Expand Down
Loading