Skip to content

Commit

Permalink
Merge pull request #51 from CS3219-AY2425S1/delete-session-integration
Browse files Browse the repository at this point in the history
Add functionality to delete matching request and delete session
  • Loading branch information
sp4ce-cowboy authored Nov 5, 2024
2 parents c8f22c0 + a0b9629 commit f4c271c
Show file tree
Hide file tree
Showing 9 changed files with 326 additions and 68 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Request, Response } from 'express';
import { addToQueue} from '../services/queueManager2';
import { addToQueue, removeFromQueue, cancelSession} from '../services/queueManager2';
import ReqObj from '../models/ReqObj';

export const createRequest = async (req: Request, res: Response): Promise<void> => {
Expand Down Expand Up @@ -30,4 +30,32 @@ export const createRequest = async (req: Request, res: Response): Promise<void>
res.status(500).json({ message: 'Failed to add request to the queue due to an unknown error' });
}
}
};
};

export const deleteRequest = async (req: Request, res: Response): Promise<void> => {
const userId = req.params.userId as string; // Get userId from URL parameters

try {
// Try to remove the user from the queue
console.log("Attempting to remove user from queue");
await removeFromQueue(userId);
res.status(200).json({ message: 'Request successfully removed from the queue' });
} catch (error) {
console.error("Error in deleteRequest:", error);
res.status(500).json({ message: 'Failed to remove request from the queue due to an unknown error' });
}
}

// API to delete a session
export const deleteSession = async (req: Request, res: Response): Promise<void> => {
const sessionId = req.params.sessionId as string; // Get userId from URL parameters

try {
// Cancel the timeout and remove session from Redis
await cancelSession(sessionId);
res.status(200).json({ message: 'Session successfully deleted' });
} catch (error) {
console.error("Error in deleteSession:", error);
res.status(500).json({ message: 'Failed to delete session due to an unknown error' });
}
};
7 changes: 6 additions & 1 deletion peerprep/backend/matching-service/src/routes/apiRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express from 'express';
import { createRequest } from '../controllers/requestController2';
import { createRequest, deleteRequest, deleteSession } from '../controllers/requestController2';
import { matchStatusStream } from '../controllers/sseController'; // Import your SSE handler

const router = express.Router();
Expand All @@ -10,5 +10,10 @@ router.post('/matchingrequest', createRequest);
// Route for Server-Sent Events (SSE) to check match status
router.get('/matchingrequest/:userId', matchStatusStream); // Change to use `:userId` as a URL parameter

// Route to delete a matching request by userId
router.delete('/matchingrequest/:userId', deleteRequest);

// Route to delete a session by userId
router.delete('/matchingrequest/session/:sessionId', deleteSession);

export default router;
21 changes: 21 additions & 0 deletions peerprep/backend/matching-service/src/services/queueManager2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ export const addToQueue = async (userId: string, topic: string, difficulty: stri
}
};

export const removeFromQueue = async (userId: string) => {
try {
await redis.dequeueUser(userId);
}
catch (error) {
console.error('Error in removeFromQueue:', error);
throw new Error("Failed to remove user from the queue due to an unknown error");
}
};


export const findMatchInQueue = async (userId: string) => {
const topicTimeoutSeconds = MATCH_TIMEOUT_SECONDS / 2;
Expand Down Expand Up @@ -88,6 +98,17 @@ export const getStatus = async (userId: string) => {
}
}

// function to delete session
export const cancelSession = async (sessionId: string) => {
try {
await redis.deleteSession(sessionId);
}
catch (error) {
console.error('Error in cancelSession:', error);
throw new Error("Failed to cancel the user's session");
}
}

/*
export const getStatus = async (userId: string, topic: string, difficulty: string) => {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ import { getStatus, findMatchInQueue } from '../services/queueManager2';
// declare function to retrieve the user's match request status from the queue
export const updateStatus = async (userId: string) => {
try {
return await getStatus(userId);
const status = await getStatus(userId);
if (status.includes("request pending")) {
findMatchInQueue(userId);
}
return status;
} catch (error) {
console.error('Error in updateStatus:', error);
throw new Error("Failed to update the status of the user's match request");
} finally {
} /*finally {
// Find match
await findMatchInQueue(userId);
}
// Add session status check here
*/
};
149 changes: 148 additions & 1 deletion peerprep/backend/matching-service/src/utils/redisUtils3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,41 @@ export const enqueueUser = async (
}
};

export const dequeueUser = async (userId: string): Promise<void> => {
const redisClient: Redis = app.locals.redisClient;
const multi = redisClient.multi();

try {
// Retrieve the user's topic and difficulty from Redis
const topic = await redisClient.hget("user-topic", userId);
const difficulty = await redisClient.hget("user-difficulty", userId);

if (!topic || !difficulty) {
console.log(`User ${userId} not found in queue or missing topic/difficulty.`);
return;
}

// Remove the user from general and topic-difficulty specific queues
multi.zrem("queue2:users", userId);
multi.zrem(`queue1:${topic}:${difficulty}`, userId);
multi.zrem(`queue2:${topic}`, userId);

// Remove user-related entries in hash sets
multi.hdel("user-timestamp", userId);
multi.hdel("user-topic", userId);
multi.hdel("user-difficulty", userId);

await multi.exec();
console.log(`User ${userId} has been dequeued successfully.`);
} catch (error) {
console.error("Error in dequeueUser:", error);
if (multi) {
multi.discard();
}
throw error;
}
};

export const clearExpiredQueue = async () => {
const redisClient: Redis = app.locals.redisClient;
const expiredTime = Date.now();
Expand Down Expand Up @@ -309,7 +344,7 @@ const createSession = async (

/* RANDOM QUESTION STARTS HERE */
const randomQuestion = await getRandomQuestionFromQuestionService(topic, difficulty);
const randomQuestionTitle = randomQuestion?.title.replace(/ /g, "-");
const randomQuestionTitle = randomQuestion?.title.replace(/ /g, "_");
sessionId += randomQuestionTitle
console.log("UPDATED Session ID:", sessionId);

Expand Down Expand Up @@ -548,4 +583,116 @@ export const findSessionByUser = async (
}
};

export const findSessionIdByUser = async (
userId: string
): Promise<string | null> => {
const redisClient: Redis = app.locals.redisClient;
console.log("Finding session id by user" + userId);
try {
const sessionId = await redisClient.hget(`session:userId`, userId);
if (!sessionId) {
return null;
}
return sessionId;
} catch (error) {
console.error("Error in findSessionIdByUser:", error);
throw error;
}
};

export const findUserIdsBySessionId = async (
sessionId: string
): Promise<{ userId1: string; userId2: string } | null> => {
const redisClient: Redis = app.locals.redisClient;
try {
// Retrieve the session data from Redis
const sessionData = await redisClient.hget(`session:sessionId`, sessionId);
if (!sessionData) {
console.log(`No session found for sessionId ${sessionId}`);
return null;
}

// Parse the session JSON data
const session: Session = JSON.parse(sessionData);

// Return the userId1 and userId2 from the session
return { userId1: session.userId1, userId2: session.userId2 };
} catch (error) {
console.error("Error in findUserIdsBySessionId:", error);
throw error;
}
};



export const deleteSession = async (
sessionId: string
): Promise<void> => {
const redisClient: Redis = app.locals.redisClient;
// Find users based on sessionId
const userIds = await findUserIdsBySessionId(sessionId);
const userId1 = userIds?.userId1;
const userId2 = userIds?.userId2;
if (!userId1 || !userId2) {
console.log(`No users found for sessionId ${sessionId}`);
throw new Error("No users found for sessionId");
}

console.log(`Deleting session ${sessionId} and user1 ${userId1} and user2 ${userId2}`);

try {
const multi = redisClient.multi();

// Deleting session details by sessionId
multi.hdel("session:sessionId", sessionId);

// Deleting the user-session mapping entries
multi.hdel("session:userId", userId1);
multi.hdel("session:userId", userId2);

// Remove the user from general and topic-difficulty specific queues
multi.zrem("queue2:users", userId1);
multi.zrem("queue2:users", userId2);

// Remove user-related entries in hash sets
multi.hdel("user-timestamp", userId1);
multi.hdel("user-topic", userId1);
multi.hdel("user-difficulty", userId1);
multi.hdel("user-timestamp", userId2);
multi.hdel("user-topic", userId2);
multi.hdel("user-difficulty", userId2);

await multi.exec();
console.log(`Session ${sessionId} and associated user entries deleted.`);
} catch (error) {
console.error("Error in deleteSession:", error);
throw error;
}
};

export const deleteSessionByUserId = async (userId: string): Promise<void> => {
try {
// Step 1: Find sessionId by userId
const sessionId = await findSessionIdByUser(userId);
if (!sessionId) {
console.log(`No session found for userId ${userId}`);
return;
}

// Step 2: Find userId1 and userId2 by sessionId
const userIds = await findUserIdsBySessionId(sessionId);
if (!userIds) {
console.log(`No user IDs found for sessionId ${sessionId}`);
return;
}

// Step 3: Delete the session and all associated entries
await deleteSession(sessionId);
console.log(`Session and entries associated with userId ${userId} have been deleted.`);
} catch (error) {
console.error("Error in deleteSessionByUserId:", error);
throw error;
}
};


Loading

0 comments on commit f4c271c

Please sign in to comment.