Skip to content

Commit 4fc49c1

Browse files
committed
Implement basic working websocket
1 parent 1f6ea49 commit 4fc49c1

File tree

11 files changed

+446
-230
lines changed

11 files changed

+446
-230
lines changed

frontend/components/matching/find-match.tsx

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ import { MatchForm } from "@/components/matching/matching-form";
44
import { SearchProgress } from "@/components/matching/search-progress";
55
import { SelectionSummary } from "@/components/matching/selection-summary";
66
import { useToast } from "@/components/hooks/use-toast";
7+
import { useAuth } from "@/app/auth/auth-context";
8+
import { joinMatchQueue } from "@/lib/join-match-queue";
79

810
export default function FindMatch() {
911
const [selectedDifficulty, setSelectedDifficulty] = useState<string>("");
1012
const [selectedTopic, setSelectedTopic] = useState<string>("");
1113
const [isSearching, setIsSearching] = useState<boolean>(false);
1214
const [waitTime, setWaitTime] = useState<number>(0);
15+
const [websocket, setWebsocket] = useState<WebSocket>();
1316
const { toast } = useToast();
17+
const auth = useAuth();
1418

1519
useEffect(() => {
1620
let interval: NodeJS.Timeout | undefined;
@@ -24,15 +28,78 @@ export default function FindMatch() {
2428
return () => clearInterval(interval);
2529
}, [isSearching]);
2630

27-
const handleSearch = () => {
28-
if (selectedDifficulty && selectedTopic) {
29-
setIsSearching(true);
30-
} else {
31+
useEffect(() => {
32+
return () => {
33+
if (websocket) {
34+
websocket.close();
35+
}
36+
};
37+
}, [websocket]);
38+
39+
const handleSearch = async () => {
40+
if (!selectedDifficulty || !selectedTopic) {
3141
toast({
3242
title: "Invalid Selection",
3343
description: "Please select both a difficulty level and a topic",
3444
variant: "destructive",
3545
});
46+
return;
47+
}
48+
49+
if (!auth || !auth.token) {
50+
toast({
51+
title: "Access denied",
52+
description: "No authentication token found",
53+
variant: "destructive",
54+
});
55+
return;
56+
}
57+
58+
if (!auth.user) {
59+
toast({
60+
title: "Access denied",
61+
description: "Not logged in",
62+
variant: "destructive",
63+
});
64+
return;
65+
}
66+
67+
const response = await joinMatchQueue(
68+
auth.token,
69+
auth?.user?.id,
70+
selectedTopic,
71+
selectedDifficulty
72+
);
73+
switch (response.status) {
74+
case 200:
75+
toast({
76+
title: "Matched",
77+
description: "Successfully matched",
78+
variant: "success",
79+
});
80+
return;
81+
case 202:
82+
setIsSearching(true);
83+
const ws = new WebSocket(
84+
`ws://localhost:6969/match/subscribe/${auth?.user?.id}/${selectedTopic}/${selectedDifficulty}`
85+
);
86+
ws.onmessage = () => {
87+
setIsSearching(false);
88+
toast({
89+
title: "Matched",
90+
description: "Successfully matched",
91+
variant: "success",
92+
});
93+
};
94+
setWebsocket(ws);
95+
return;
96+
default:
97+
toast({
98+
title: "Unknown Error",
99+
description: "An unexpected error has occured",
100+
variant: "destructive",
101+
});
102+
return;
36103
}
37104
};
38105

frontend/lib/join-match-queue.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { matchingServiceUri } from "@/lib/api-uri";
2+
3+
export const joinMatchQueue = async (
4+
jwtToken: string,
5+
userId: string,
6+
category: string,
7+
complexity: string
8+
) => {
9+
const params = new URLSearchParams({
10+
topic: category,
11+
difficulty: complexity,
12+
}).toString();
13+
const response = await fetch(
14+
`${matchingServiceUri(window.location.hostname)}/match/queue/${userId}?${params}`,
15+
{
16+
method: "POST",
17+
headers: {
18+
Authorization: `Bearer ${jwtToken}`,
19+
"Content-Type": "application/json",
20+
},
21+
}
22+
);
23+
return response;
24+
};

frontend/package-lock.json

Lines changed: 71 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)