Skip to content

Commit f167cb4

Browse files
committed
PEER-223: Add integration with other services
Signed-off-by: SeeuSim <[email protected]>
1 parent e7c229e commit f167cb4

File tree

18 files changed

+254
-111
lines changed

18 files changed

+254
-111
lines changed

backend/matching/.env.compose

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
# To be injected by Docker Compose
22
# PEERPREP_UI_HOST="http://frontend:3000"
3+
# MATCHING_DB_HOSTNAME="match-db"
4+
# MATCHING_DB_PORT=6379
35

46
EXPRESS_PORT=9004
57

6-
# MATCHING_DB_HOSTNAME="match-db"
7-
MATCHING_DB_PORT=6379
8-
9-
# MATCHING_DB_USERNAME="peerprep-match-express"
10-
# MATCHING_DB_PASSWORD="G7jBgyz9wGAFQ5La"
11-
# REDIS_ARGS="--requirepass G7jBgyz9wGAFQ5La --user ${MATCHING_DB_USERNAME} on >G7jBgyz9wGAFQ5La ~* allcommands --user default off nopass nocommands"
8+
MATCHING_DB_USERNAME=peerMatc
9+
MATCHING_DB_PASSWORD=iZnm6K5k
10+
REDIS_ARGS="--requirepass iZnm6K5k --user peerMatc on >iZnm6K5k ~* allcommands --user default off nopass nocommands"
1211

backend/matching/.env.docker

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ PEERPREP_USER_HOST=http://host.docker.internal:9001
99
PEERPREP_QUESTION_HOST=http://host.docker.internal:9002
1010
PEERPREP_COLLAB_HOST=http://host.docker.internal:9003
1111

12-
# MATCHING_DB_USERNAME=peerprep-match-express
13-
# MATCHING_DB_PASSWORD=G7jBgyz9wGAFQ5La
12+
MATCHING_DB_USERNAME=peerMatc
13+
MATCHING_DB_PASSWORD=iZnm6K5k
14+
REDIS_ARGS="--requirepass iZnm6K5k --user peerMatc on >iZnm6K5k ~* allcommands --user default off nopass nocommands"

backend/matching/.env.local

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@ EXPRESS_PORT=9004
55
MATCHING_DB_HOSTNAME=localhost
66
MATCHING_DB_PORT=6379
77

8+
PEERPREP_USER_HOST=http://localhost:9001
9+
PEERPREP_QUESTION_HOST=http://localhost:9002
10+
PEERPREP_COLLAB_HOST=http://localhost:9003
811

9-
PEERPREP_USER_HOST="http://localhost:9001"
10-
PEERPREP_QUESTION_HOST="http://localhost:9002"
11-
PEERPREP_COLLAB_HOST="http://localhost:9003"
12-
13-
14-
15-
# MATCHING_DB_USERNAME="peerprep-match-express"
16-
# MATCHING_DB_PASSWORD="G7jBgyz9wGAFQ5La"
17-
# REDIS_ARGS="--requirepass G7jBgyz9wGAFQ5La --user ${MATCHING_DB_USERNAME} on >G7jBgyz9wGAFQ5La ~* allcommands --user default off nopass nocommands"
12+
MATCHING_DB_USERNAME=peerMatc
13+
MATCHING_DB_PASSWORD=iZnm6K5k
14+
REDIS_ARGS="--requirepass iZnm6K5k --user peerMatc on >iZnm6K5k ~* allcommands --user default off nopass nocommands"

backend/matching/src/config.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@ export const PEERPREP_USER_HOST = process.env.PEERPREP_USER_HOST;
88
export const PEERPREP_QUESTION_HOST = process.env.PEERPREP_QUESTION_HOST;
99
export const PEERPREP_COLLAB_HOST = process.env.PEERPREP_COLLAB_HOST;
1010

11-
const DB_HOSTNAME = process.env.MATCHING_DB_HOSTNAME;
12-
const DB_PORT = Number.parseInt(process.env.MATCHING_DB_PORT ?? '6379');
11+
export const DB_HOSTNAME = process.env.MATCHING_DB_HOSTNAME;
12+
export const DB_PORT = Number.parseInt(process.env.MATCHING_DB_PORT ?? '6379');
13+
export const DB_USERNAME = process.env.MATCHING_DB_USERNAME;
14+
export const DB_PASSWORD = process.env.MATCHING_DB_PASSWORD;
1315
// export const DB_URL = `redis://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOSTNAME}:${DB_PORT}`;
14-
export const DB_URL = `redis://${DB_HOSTNAME}:${DB_PORT}`;
16+
// export const DB_URL = `redis://${DB_HOSTNAME}:${DB_PORT}`;
1517

1618
export const NODE_ENV = process.env.NODE_ENV;
1719

1820
export const IS_MILESTONE_D4 = true;
21+
22+
export const WORKER_SLEEP_TIME_IN_MILLIS = 500;

backend/matching/src/controllers/cancel-request.ts

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1-
import { Request, Response } from 'express';
1+
import type { Request, Response } from 'express';
2+
import { StatusCodes } from 'http-status-codes';
23

3-
import { client as redisClient } from '../lib/db';
4+
import { client as redisClient, logQueueStatus } from '@/lib/db';
5+
import { STREAM_NAME } from '@/lib/db/constants';
6+
import { getPoolKey, getStreamId, logger } from '@/lib/utils';
7+
import { io } from '@/server';
8+
import { MATCHING_EVENT } from '@/ws/events';
49

510
export const cancelMatchRequestController = async (req: Request, res: Response) => {
611
const { userId } = req.body; // Only check for userId
712

813
if (!userId) {
9-
return res.status(400).json({ message: 'User ID is required' }); // No need for roomId
14+
return res.status(StatusCodes.UNPROCESSABLE_ENTITY).json({ message: 'User ID is required' }); // No need for roomId
1015
}
1116

1217
try {
@@ -15,20 +20,52 @@ export const cancelMatchRequestController = async (req: Request, res: Response)
1520
}
1621

1722
// Check pending status using only userId
18-
const pendingStatus = await redisClient.hGet(`match:${userId}`, 'pending');
19-
console.log(pendingStatus);
20-
21-
if (pendingStatus === 'true') {
22-
// Allow cancellation and remove from queue based on userId
23-
await redisClient.del(`match:${userId}`);
24-
console.log(`User ${userId} has canceled their match.`);
25-
return res.status(200).json({ message: 'Match canceled successfully' });
26-
} else {
27-
// If the match is no longer pending, deny cancellation
28-
console.log(`User ${userId} is no longer pending and cannot cancel.`);
29-
return res
30-
.status(403)
31-
.json({ message: 'Match cancellation failed: Request is not pending.' });
23+
const result = await redisClient
24+
.hGetAll(getPoolKey(userId))
25+
.then(async (value) => {
26+
if (value.pending === 'true') {
27+
const timestamp = value.timestamp;
28+
await Promise.all([
29+
redisClient.del(getPoolKey(userId)),
30+
timestamp
31+
? redisClient.xDel(STREAM_NAME, getStreamId(value.timestamp))
32+
: Promise.resolve(),
33+
]);
34+
await logQueueStatus(
35+
logger,
36+
redisClient,
37+
'Queue Status after cancelling request: <PLACEHOLDER>'
38+
);
39+
logger.info(`Request cancellation successful`);
40+
const room = value.socketPort;
41+
42+
if (room) {
43+
io.sockets.in(room).socketsLeave(room);
44+
}
45+
46+
return {
47+
success: true,
48+
};
49+
}
50+
51+
return {
52+
success: false,
53+
error: `Match in ${MATCHING_EVENT.MATCHING} state.`,
54+
};
55+
})
56+
.catch((reason) => {
57+
if (reason) {
58+
return {
59+
success: false,
60+
error: reason,
61+
};
62+
}
63+
});
64+
65+
if (result?.success) {
66+
return res.status(StatusCodes.OK).end();
67+
} else if (!result?.success) {
68+
return res.status(StatusCodes.FORBIDDEN).json(result?.error);
3269
}
3370
} catch (error) {
3471
console.error('Error canceling match:', error);

backend/matching/src/lib/db/client.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import { createClient } from 'redis';
22

3-
import { DB_URL } from '@/config';
3+
import { DB_HOSTNAME, DB_PASSWORD, DB_PORT, DB_USERNAME } from '@/config';
44
import { logger } from '@/lib/utils';
55

66
class RedisClient {
77
client: ReturnType<typeof createClient>;
88
constructor() {
99
this.client = createClient({
10-
url: DB_URL,
10+
username: DB_USERNAME,
11+
password: DB_PASSWORD,
12+
socket: {
13+
host: DB_HOSTNAME,
14+
port: DB_PORT,
15+
},
1116
}).on('error', (err) => {
1217
logger.error(`Redis Client error: ${err}`);
1318
});

backend/matching/src/lib/db/log-queue-status.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import { STREAM_NAME } from './constants';
55

66
export const getQueueStatusLog = async (redisClient: typeof client) => {
77
const queueStatus = await redisClient.xRange(STREAM_NAME, '-', '+');
8-
const messages = queueStatus.map((v) => v.message);
8+
const messages = queueStatus
9+
.map((v) => v.message)
10+
.map(({ userId, topic, difficulty }) => ({ userId, topic, difficulty }));
911
return JSON.stringify(messages);
1012
};
1113

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import axios from 'axios';
2+
3+
import { PEERPREP_COLLAB_HOST, PEERPREP_QUESTION_HOST, PEERPREP_USER_HOST } from '@/config';
4+
5+
const basePostConfig = {
6+
withCredentials: true,
7+
headers: {
8+
'Content-Type': 'application/json',
9+
},
10+
};
11+
12+
export const userServiceClient = axios.create({
13+
baseURL: PEERPREP_USER_HOST,
14+
...basePostConfig,
15+
});
16+
17+
export const questionServiceClient = axios.create({
18+
baseURL: PEERPREP_QUESTION_HOST,
19+
...basePostConfig,
20+
});
21+
22+
export const collabServiceClient = axios.create({
23+
baseURL: PEERPREP_COLLAB_HOST,
24+
withCredentials: true,
25+
});
26+
27+
export const routes = {
28+
USER_SERVICE: {
29+
ATTEMPTED_QNS: {
30+
GET: {
31+
path: '/user/attempted-question/get',
32+
},
33+
ADD: {
34+
path: '/user/attempted-question/add',
35+
},
36+
},
37+
},
38+
QUESTION_SERVICE: {
39+
GET_RANDOM_QN: {
40+
path: '/questions/random',
41+
},
42+
},
43+
COLLAB_SERVICE: {
44+
GET_ROOM: {
45+
path: '/room',
46+
},
47+
},
48+
};
Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,24 @@
1-
import crypto from 'crypto';
1+
import { collabServiceClient, routes } from './_hosts';
22

33
export async function createRoom(
44
userId1: string,
55
userId2: string,
66
questionId: string
77
): Promise<string> {
8-
const combinedString = `uid1=${userId1}|uid2=${userId2}|qid=${questionId}`;
9-
const hash = crypto.createHash('sha256');
10-
const uniqueRoomName = hash.update(combinedString).digest('hex');
11-
return uniqueRoomName;
8+
const response = await collabServiceClient.get<{ roomName: string }>(
9+
routes.COLLAB_SERVICE.GET_ROOM.path,
10+
{
11+
params: {
12+
userid1: userId1,
13+
userid2: userId2,
14+
questionid: questionId,
15+
},
16+
}
17+
);
18+
19+
if (response.status !== 200 || !response.data?.roomName) {
20+
throw new Error('Failed to create room');
21+
}
22+
23+
return response?.data?.roomName ?? undefined;
1224
}

backend/matching/src/services/get-match-items.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ export async function getMatchItems(
5353
return {
5454
roomId,
5555
questionId: question.id,
56-
// question,
5756
};
5857
} catch (error) {
5958
logger.error('Error in getMatchItems:', error);

0 commit comments

Comments
 (0)