Skip to content

Commit 7f204bc

Browse files
committed
fixes
1 parent be927c4 commit 7f204bc

File tree

11 files changed

+153
-148
lines changed

11 files changed

+153
-148
lines changed

backend/matching/README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@
77
docker build \
88
-t match-express-local \
99
--build-arg port=9004 \
10-
--build-arg USER_SERVER_ENDPOINT=http://host.docker.internal:9001 \
11-
--build-arg QUESTION_SERVER_ENDPOINT=http://host.docker.internal:9002 \
12-
--build-arg COLLAB_SERVICE_ENDPOINT=http://host.docker.internal:9003 \
1310
-f express.Dockerfile .
1411
```
1512
2. Run this command, from the root folder:

backend/matching/src/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ export const UI_HOST = process.env.PEERPREP_UI_HOST!;
44

55
export const EXPRESS_PORT = process.env.EXPRESS_PORT;
66

7+
export const PEERPREP_USER_HOST = process.env.PEERPREP_USER_HOST;
8+
export const PEERPREP_QUESTION_HOST = process.env.PEERPREP_QUESTION_HOST;
9+
export const PEERPREP_COLLAB_HOST = process.env.PEERPREP_COLLAB_HOST;
10+
711
const DB_HOSTNAME = process.env.MATCHING_DB_HOSTNAME;
812
const DB_PORT = Number.parseInt(process.env.MATCHING_DB_PORT ?? '6379');
913
// export const DB_URL = `redis://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOSTNAME}:${DB_PORT}`;
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import axios from 'axios';
2+
3+
const collabServerEndpoint = `${process.env.COLLAB_SERVER_ENDPOINT}`;
4+
5+
export async function createRoom(userId1: string, userId2: string, questionId: string): Promise<string> {
6+
const response = await axios.get<{ roomName: string }>(
7+
`${collabServerEndpoint}/room`,
8+
{
9+
params: {
10+
userid1: userId1,
11+
userid2: userId2,
12+
questionid: questionId,
13+
}
14+
}
15+
);
16+
17+
if (response.status !== 200 || !response.data?.roomName) {
18+
throw new Error('Failed to create room');
19+
}
20+
21+
return response.data.roomName;
22+
}
Lines changed: 28 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,133 +1,49 @@
1-
import { IMatchType } from "@/types";
2-
import axios from 'axios';
3-
4-
interface IGetRandomQuestionPayload {
5-
attemptedQuestions: number[];
6-
difficulty?: string;
7-
topic?: string;
8-
}
9-
10-
11-
interface IServiceResponse<T> {
12-
success: boolean;
13-
data?: T;
14-
error?: { message: string };
15-
}
16-
17-
interface IQuestion {
18-
id: number;
19-
title: string;
20-
description: string;
21-
difficulty: string;
22-
topic: string[];
23-
}
24-
25-
interface IMatchItemsResponse {
26-
roomName: string;
27-
questionId: number;
28-
question: IQuestion;
29-
}
30-
31-
export const getMatchItems = async (
32-
searchIdentifier: IMatchType,
33-
topic?: string,
34-
difficulty?: string,
35-
userId1?: string,
36-
userId2?: string
37-
): Promise<IMatchItemsResponse | undefined> => {
38-
const userEndpoint = `${process.env.USER_SERVER_ENDPOINT}`;
39-
const questionEndpoint = `${process.env.QUESTION_SERVER_ENDPOINT}`;
40-
const collabServerEndpoint = `${process.env.COLLAB_SERVER_ENDPOINT}`;
41-
1+
import { IMatchType, IMatchItemsResponse } from '../types/index';
2+
import { fetchAttemptedQuestions, updateAttemptedQuestions } from './user';
3+
import { getRandomQuestion } from './question';
4+
import { createRoom } from './collab';
5+
6+
export async function getMatchItems(
7+
searchIdentifier: IMatchType,
8+
topic?: string,
9+
difficulty?: string,
10+
userId1?: string,
11+
userId2?: string
12+
): Promise<IMatchItemsResponse | undefined> {
4213
try {
4314
if (!userId1 || !userId2) {
4415
throw new Error('Both user IDs are required');
4516
}
4617

47-
// Fetch attempted questions for both users
4818
const [attemptedQuestions1, attemptedQuestions2] = await Promise.all([
49-
fetchAttemptedQuestions(userEndpoint, userId1),
50-
fetchAttemptedQuestions(userEndpoint, userId2)
19+
fetchAttemptedQuestions(userId1),
20+
fetchAttemptedQuestions(userId2)
5121
]);
5222

53-
// Combine attempted questions from both users
23+
5424
const allAttemptedQuestions = [...new Set([...attemptedQuestions1, ...attemptedQuestions2])];
5525

56-
// Prepare payload for the /random endpoint
57-
const payload: IGetRandomQuestionPayload = {
26+
const payload = {
5827
attemptedQuestions: allAttemptedQuestions,
28+
...(searchIdentifier === 'difficulty' && difficulty ? { difficulty } : {}),
29+
...(searchIdentifier === 'topic' && topic ? { topic } : {}),
30+
...(searchIdentifier === 'exact match' && topic && difficulty ? { topic, difficulty } : {}),
5931
};
6032

61-
if (searchIdentifier === 'difficulty' && difficulty) {
62-
payload.difficulty = difficulty;
63-
} else if (searchIdentifier === 'topic' && topic) {
64-
payload.topic = topic;
65-
} else if (searchIdentifier === 'exact match' && topic && difficulty) {
66-
payload.topic = topic;
67-
payload.difficulty = difficulty;
68-
}
69-
70-
// Query the question endpoint using the /random endpoint
71-
const questionResponse = await axios.post<IServiceResponse<{ question: IQuestion }>>(
72-
`${questionEndpoint}/questions/random`,
73-
payload
74-
);
75-
76-
if (questionResponse.status !== 200 || !questionResponse.data.data) {
77-
throw new Error(questionResponse.data.error?.message || 'Failed to get a random question');
78-
}
33+
// Get a random question
34+
const question = await getRandomQuestion(payload);
7935

80-
const questionId = questionResponse.data.data.question.id;
81-
82-
// Update attempted questions for both users
83-
await Promise.all([
84-
updateAttemptedQuestions(userEndpoint, userId1, questionId),
85-
updateAttemptedQuestions(userEndpoint, userId2, questionId)
86-
]);
8736

88-
// Query the collab server for the room ID
89-
const roomResponse = await axios.get<{ roomName: string }>(
90-
`${collabServerEndpoint}/room`,
91-
{
92-
params: {
93-
userid1: userId1,
94-
userid2: userId2,
95-
questionid: questionId.toString(),
96-
}
97-
}
98-
);
99-
if (roomResponse.status !== 200 || !roomResponse.data?.roomName) {
100-
throw new Error('Failed to create room');
101-
}
37+
const roomName = await createRoom(userId1, userId2, question.id.toString());
10238

103-
console.log("Succesfully got match items");
39+
console.log("Successfully got match items");
10440
return {
105-
roomName: roomResponse.data.roomName,
106-
questionId: questionId,
107-
question: questionResponse.data.data.question,
108-
}
41+
roomName,
42+
questionId: question.id,
43+
question,
44+
};
10945
} catch (error) {
11046
console.error('Error in getMatchItems:', error);
111-
};
112-
}
113-
114-
async function fetchAttemptedQuestions(userEndpoint: string, userId: string): Promise<number[]> {
115-
const response = await axios.get<number[]>(
116-
`${userEndpoint}/user/${userId}/attempted-questions`
117-
);
118-
if (response.status !== 200 || !response.data) {
119-
throw new Error(`Failed to fetch attempted questions for user ${userId}`);
120-
}
121-
return response.data || []
122-
}
123-
124-
async function updateAttemptedQuestions(userEndpoint: string, userId: string, questionId: number): Promise<void> {
125-
const response = await axios.post<unknown>(
126-
`${userEndpoint}/user/${userId}/attempt-question`,
127-
{ questionId }
128-
);
129-
if (response.status !== 200 || !response.data) {
130-
throw new Error(`Failed to fetch attempted questions for user ${userId}`);
47+
return undefined;
13148
}
132-
return;
13349
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import axios from 'axios';
2+
import { IServiceResponse, IQuestion, IGetRandomQuestionPayload } from '../types/index';
3+
4+
const questionEndpoint = `${process.env.QUESTION_SERVER_ENDPOINT}`;
5+
6+
export async function getRandomQuestion(payload: IGetRandomQuestionPayload): Promise<IQuestion> {
7+
const response = await axios.post<IServiceResponse<{ question: IQuestion }>>(
8+
`${questionEndpoint}/questions/random`,
9+
payload
10+
);
11+
12+
if (response.status !== 200 || !response.data.data) {
13+
throw new Error(response.data.error?.message || 'Failed to get a random question');
14+
}
15+
16+
return response.data.data.question;
17+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import axios from 'axios';
2+
3+
const userEndpoint = `${process.env.USER_SERVER_ENDPOINT}`;
4+
5+
export async function fetchAttemptedQuestions(userId: string): Promise<number[]> {
6+
const response = await axios.post<number[]>(
7+
`${userEndpoint}/user/attempted-question/get`,
8+
{userId}
9+
);
10+
if (response.status !== 200 || !response.data) {
11+
throw new Error(`Failed to fetch attempted questions for user ${userId}`);
12+
}
13+
return response.data || [];
14+
}
15+
16+
export async function updateAttemptedQuestions(userIds: string[], questionId: number): Promise<void> {
17+
const response = await axios.post<unknown>(
18+
`${userEndpoint}/user/attempted-question/add`,
19+
{ questionId, userIds }
20+
);
21+
if (response.status !== 200 || !response.data) {
22+
throw new Error(`Failed to update attempted questions for users ${userIds}`);
23+
}
24+
return;
25+
}

backend/matching/src/types/index.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,31 @@ export type IStreamMessage = {
2929
value?: Awaited<ReturnType<(typeof client)['ft']['search']>>['documents'][number]['value'];
3030
};
3131

32-
export type IMatchType = 'difficulty' | 'topic' | 'exact match' | undefined
32+
export type IMatchType = 'difficulty' | 'topic' | 'exact match' | undefined
33+
34+
35+
export interface IServiceResponse<T> {
36+
success: boolean;
37+
data?: T;
38+
error?: { message: string };
39+
}
40+
41+
export interface IQuestion {
42+
id: number;
43+
title: string;
44+
description: string;
45+
difficulty: string;
46+
topic: string[];
47+
}
48+
49+
export interface IGetRandomQuestionPayload {
50+
attemptedQuestions: number[];
51+
difficulty?: string;
52+
topic?: string;
53+
}
54+
55+
export interface IMatchItemsResponse {
56+
roomName: string;
57+
questionId: number;
58+
question: IQuestion;
59+
}

backend/matching/src/workers/matcher.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ async function processMatch(
7575

7676
// Notify both sockets
7777
const { ...matchItems } = await getMatchItems(searchIdentifier, topic, difficulty, requestorUserId, matchedUserId);
78-
logger.info(`matchItems: ${JSON.stringify(matchItems)}`);
78+
logger.info(`Generated Match - ${JSON.stringify(matchItems)}`);
7979

8080
sendNotif([requestorSocketPort, matchedSocketPort], MATCH_SVC_EVENT.SUCCESS, matchItems);
8181
sendNotif([requestorSocketPort, matchedSocketPort], MATCH_SVC_EVENT.DISCONNECT);

backend/user/src/controllers/questions/index.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@ import type { IRouteHandler } from '@/types';
33
import { getAttemptedQuestionsService, addAttemptedQuestionService } from '@/services/questions';
44

55
export const addAttemptedQuestion: IRouteHandler = async (req, res) => {
6-
const userId = req.params.userId; // Assuming the userId is passed as a route parameter
7-
const { questionId } = req.body; // Assuming the questionId is passed in the request body
6+
const { questionId, userIds } = req.body; // Assuming the questionId is passed in the request body
87

9-
if (!userId || !questionId) {
8+
if (!userIds || !questionId) {
109
return res.status(StatusCodes.BAD_REQUEST).json('User ID and Question ID are required');
1110
}
1211

13-
const { code, data, error } = await addAttemptedQuestionService(userId, questionId);
12+
const { code, data, error } = await addAttemptedQuestionService(userIds, questionId);
1413

1514
if (error || code !== StatusCodes.OK || !data) {
1615
const sanitizedErr = error?.message ?? 'An error occurred.';
@@ -21,7 +20,7 @@ export const addAttemptedQuestion: IRouteHandler = async (req, res) => {
2120
};
2221

2322
export const getAttemptedQuestions: IRouteHandler = async (req, res) => {
24-
const userId = req.params.userId; // Assuming the userId is passed as a route parameter
23+
const userId = req.body.userId;
2524

2625
if (!userId) {
2726
return res.status(StatusCodes.BAD_REQUEST).json('User ID is required');

backend/user/src/routes/user.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getAttemptedQuestions, addAttemptedQuestion } from '@/controllers/quest
55

66
const router = express.Router();
77

8-
router.get('/:userId/attempted-questions/', getAttemptedQuestions)
9-
router.post('/:userId/attempt-question', addAttemptedQuestion)
8+
router.post('/attempted-question/get', getAttemptedQuestions)
9+
router.post('/attempted-question/add', addAttemptedQuestion)
1010

1111
export default router;

0 commit comments

Comments
 (0)