From 49fbdb1ffdab00e8a2ca0083c0bf39bfb9bd8788 Mon Sep 17 00:00:00 2001 From: MathieuSevignyLavallee <89943988+MathieuSevignyLavallee@users.noreply.github.com> Date: Wed, 27 Nov 2024 18:36:59 -0500 Subject: [PATCH] refactor --- quizRoom/socket/setupWebSocket.ts | 10 +- test/stressTest/class/roomParticipant.js | 72 ++++++ test/stressTest/class/student.js | 77 +++--- test/stressTest/class/teacher.js | 64 ++--- test/stressTest/class/watcher.js | 54 ++++ test/stressTest/main.js | 306 ++++++++++------------- test/stressTest/package-lock.json | 26 ++ test/stressTest/package.json | 1 + test/stressTest/utility/apiServices.js | 90 +------ 9 files changed, 355 insertions(+), 345 deletions(-) create mode 100644 test/stressTest/class/roomParticipant.js create mode 100644 test/stressTest/class/watcher.js diff --git a/quizRoom/socket/setupWebSocket.ts b/quizRoom/socket/setupWebSocket.ts index a5ea04c..edeeee3 100644 --- a/quizRoom/socket/setupWebSocket.ts +++ b/quizRoom/socket/setupWebSocket.ts @@ -24,6 +24,7 @@ export const setupWebsocket = (io: Server): void => { ? sentRoomName.toUpperCase() : generateRoomName(); + console.log(`Created room with name: ${roomName}`); if (!io.sockets.adapter.rooms.get(roomName)) { socket.join(roomName); socket.emit("create-success", roomName); @@ -101,9 +102,14 @@ export const setupWebsocket = (io: Server): void => { // Stress Testing - socket.on("message-test", ({ roomName, message }: { roomName: string; message: string }) => { + socket.on("message-from-teacher", ({ roomName, message }: { roomName: string; message: string }) => { console.log(`Message reçu dans la salle ${roomName} : ${message}`); - socket.to(roomName).emit("message", { id: socket.id, message }); + socket.to(roomName).emit("message-sent-teacher", { message }); + }); + + socket.on("message-from-student", ({ roomName, message }: { roomName: string; message: string }) => { + console.log(`Message reçu dans la salle ${roomName} : ${message}`); + socket.to(roomName).emit("message-sent-student", { message }); }); socket.on("get-usage", () => { diff --git a/test/stressTest/class/roomParticipant.js b/test/stressTest/class/roomParticipant.js new file mode 100644 index 0000000..a0a231f --- /dev/null +++ b/test/stressTest/class/roomParticipant.js @@ -0,0 +1,72 @@ +import { io } from "socket.io-client"; + +export class RoomParticipant { + constructor(username, roomName) { + this.username = username; + this.roomName = roomName; + this.socket = null; + this.maxRetries = 3; + this.retryDelay = 1000; + } + + async connectToRoom(baseUrl, onConnectCallback) { + let retries = 0; + + const connect = () => { + return new Promise((resolve, reject) => { + try { + const socket = io(baseUrl, { + path: `/api/room/${this.roomName}/socket`, + transports: ['websocket'], + timeout: 5000, + reconnection: true, + reconnectionAttempts: 3, + reconnectionDelay: 1000, + }); + + const connectionTimeout = setTimeout(() => { + socket.close(); + reject(new Error('Connection timeout')); + }, 5000); + + socket.on('connect', () => { + clearTimeout(connectionTimeout); + this.socket = socket; + if (onConnectCallback) { + onConnectCallback(); + } + resolve(socket); + }); + + socket.on('connect_error', (error) => { + clearTimeout(connectionTimeout); + reject(new Error(`Connection error: ${error.message}`)); + }); + + } catch (error) { + reject(error); + } + }); + }; + + while (retries < this.maxRetries) { + try { + return await connect(); + } catch (error) { + retries++; + if (retries === this.maxRetries) { + throw new Error(`Failed to connect ${this.username} after ${this.maxRetries} attempts: ${error.message}`); + } + console.warn(`Retry ${retries}/${this.maxRetries} for ${this.username}`); + await new Promise(resolve => setTimeout(resolve, this.retryDelay)); + } + } + } + + disconnect() { + if (this.socket) { + this.socket.disconnect(); + this.socket = null; + } + } +} \ No newline at end of file diff --git a/test/stressTest/class/student.js b/test/stressTest/class/student.js index 639d17c..a876a6b 100644 --- a/test/stressTest/class/student.js +++ b/test/stressTest/class/student.js @@ -1,59 +1,42 @@ -import { io } from "socket.io-client"; +// student.js +import { RoomParticipant } from './roomParticipant.js'; -export class Student { +export class Student extends RoomParticipant { constructor(username, roomName) { - this.username = username; - this.roomName = roomName; - this.socket = null; + super(username, roomName); } connectToRoom(baseUrl) { - return new Promise((resolve, reject) => { - try { - this.socket = io(baseUrl, { - path: `/api/room/${this.roomName}/socket`, - transports: ['websocket'], - autoConnect: true, - reconnection: true, - reconnectionAttempts: 10, - reconnectionDelay: 10000, - timeout: 20000, - }); - - this.socket.on('connect', () => { - this.joinRoom(this.roomName, this.username); - this.listenForMessages(); // Start listening for messages - resolve(this.socket); - }); - - this.socket.on('error', (error) => { - reject(new Error(`Connection error: ${error.message}`)); - }); - - } catch (error) { - console.error(`Error connecting ${this.name} to room ${this.roomName}:`, error.message); - reject(error); - } + return super.connectToRoom(baseUrl, () => { + this.joinRoom(); + this.listenForTeacherMessage(); }); } - joinRoom(roomName, username) { + joinRoom() { if (this.socket) { - this.socket.emit('join-room', { roomName, username }); - } - } - - sendMessage(message) { - if (this.socket && this.socket.connected) { - this.socket.emit('message-test', { room: this.roomName, message }); - } - } - - listenForMessages() { - if (this.socket) { - this.socket.on('message-test', (data) => { - console.log(`Message received in room ${this.roomName} by ${this.username}:`, data.message); + this.socket.emit('join-room', { + enteredRoomName: this.roomName, + username: this.username }); } } -} + + listenForTeacherMessage() { + if (this.socket) { + this.socket.on('message-sent-teacher', ({ message }) => { + this.respondToTeacher(message); + }); + } + } + + respondToTeacher(message) { + const reply = `${this.username} replying to: "${message}"`; + if (this.socket) { + this.socket.emit('message-from-student', { + roomName: this.roomName, + message: reply + }); + } + } +} \ No newline at end of file diff --git a/test/stressTest/class/teacher.js b/test/stressTest/class/teacher.js index 6660e50..6546798 100644 --- a/test/stressTest/class/teacher.js +++ b/test/stressTest/class/teacher.js @@ -1,58 +1,46 @@ -import { io } from "socket.io-client"; +import { RoomParticipant } from './roomParticipant.js'; -export class Teacher { +export class Teacher extends RoomParticipant { constructor(username, roomName) { - this.username = username; - this.roomName = roomName; - this.socket = null; + super(username, roomName); + this.ready = false; } connectToRoom(baseUrl) { - return new Promise((resolve, reject) => { - try { - this.socket = io(baseUrl, { - path: `/api/room/${this.roomName}/socket`, - transports: ['websocket'], - autoConnect: true, - reconnection: true, - reconnectionAttempts: 10, - reconnectionDelay: 10000, - timeout: 20000, - }); - - this.socket.on('connect', () => { - this.createRoom(this.roomName); - this.listenForMessages(); // Start listening for messages - resolve(this.socket); - }); - - this.socket.on('error', (error) => { - reject(new Error(`Connection error: ${error.message}`)); - }); - } catch (error) { - console.error(`Error connecting ${this.name} to room ${this.roomName}:`, error.message); - reject(error); - } + return super.connectToRoom(baseUrl, () => { + this.createRoom(); + this.listenForStudentMessage(); + + // Add room creation confirmation listener + this.socket.on('create-success', () => { + console.log(`Room ${this.roomName} created by teacher ${this.username}`); + this.ready = true; + }); }); } createRoom() { if (this.socket) { - this.socket.emit('create-room', this.roomName || undefined); + this.socket.emit('create-room', this.roomName); } } - sendMessage(message) { - if (this.socket && this.socket.connected) { - this.socket.emit('message-test', { room: this.roomName, message }); + broadcastMessage(message) { + if (this.socket && this.ready) { + this.socket.emit('message-from-teacher', { + roomName: this.roomName, + message + }); + } else { + console.warn(`Teacher ${this.username} not ready to broadcast yet`); } } - listenForMessages() { + listenForStudentMessage() { if (this.socket) { - this.socket.on('message-test', (data) => { - console.log(`Message received in room ${this.roomName} by ${this.username}:`, data.message); + this.socket.on('message-sent-student', ({ message }) => { + //console.log(`Teacher ${this.username} received: "${message}"`); }); } } -} +} \ No newline at end of file diff --git a/test/stressTest/class/watcher.js b/test/stressTest/class/watcher.js new file mode 100644 index 0000000..24ed359 --- /dev/null +++ b/test/stressTest/class/watcher.js @@ -0,0 +1,54 @@ +import { RoomParticipant } from './roomParticipant.js'; + +export class Watcher extends RoomParticipant { + + roomRessourcesData = []; + checkRessourceInterval = null; + + constructor(username, roomName) { + super(username, roomName); + } + + async connectToRoom(baseUrl) { + await super.connectToRoom(baseUrl); + this.startCheckingResources(); + } + + checkRessource() { + if (this.socket?.connected) { + try { + this.socket.emit("get-usage"); + this.socket.once("usage-data", (data) => { + this.roomRessourcesData.push({ timestamp: Date.now(), ...data }); + }); + } catch (error) { + console.warn(`Error capturing metrics for room ${this.roomName}:`, error.message); + } + } else { + console.warn(`Socket not connected for room ${this.roomName}`); + } + } + + startCheckingResources(intervalMs = 500) { + if (this.checkRessourceInterval) { + console.warn(`Resource checking is already running for room ${this.roomName}.`); + return; + } + + this.checkRessourceInterval = setInterval(() => this.checkRessource(), intervalMs); + console.log(`Started resource checking for room ${this.roomName}.`); + } + + stopCheckingResources() { + if (this.checkRessourceInterval) { + clearInterval(this.checkRessourceInterval); + this.checkRessourceInterval = null; + console.log(`Stopped resource checking for room ${this.roomName}.`); + } + } + + disconnect() { + this.stopCheckingResources(); + super.disconnect(); + } +} diff --git a/test/stressTest/main.js b/test/stressTest/main.js index f9a1d78..5091167 100644 --- a/test/stressTest/main.js +++ b/test/stressTest/main.js @@ -1,227 +1,187 @@ -import { attemptLoginOrRegister, createRoomContainer, captureResourceUsageForContainers } from './utility/apiServices.js'; +import { attemptLoginOrRegister, createRoomContainer } from './utility/apiServices.js'; import { Student } from './class/student.js'; import { Teacher } from './class/teacher.js'; -import { writeMetricsToFile, generateGraphs } from './utility/writeMetrics.js'; +import { Watcher } from './class/watcher.js'; const BASE_URL = 'http://localhost'; const user = { username: 'admin@example.com', password: 'adminPassword' }; const numberRooms = 20; -const studentPerRoom = 58; // Max: 60, 1 reserved for teacher +const usersPerRoom = 60; const roomAssociations = {}; -const allSockets = []; // Tracks all active WebSocket connections +const maxMessages = 20; // Number of conversation rounds +const conversationInterval = 1000; // Interval between teacher messages (ms) +const batchSize = 10; // Number of simultaneous connections +const batchDelay = 500; -const metrics = { - roomsCreated: 0, - roomsFailed: 0, - teachersConnected: 0, - teachersFailed: 0, - studentsConnected: 0, - studentsFailed: 0, - messagesSent: 0, - messagesReceived: 0, - totalLatency: 0, - maxLatency: 0, - minLatency: Number.MAX_SAFE_INTEGER, - throughput: 0, - startTime: null, - endTime: null, -}; +/** + * Creates rooms with controlled concurrency. + */ +async function createRoomContainers() { + console.log('Attempting login or register to get token'); + const token = await attemptLoginOrRegister(BASE_URL, user.username, user.password); + if (!token) throw new Error('Failed to login or register.'); -// Creates rooms and tracks their creation -async function createRoomContainers(token) { - console.time('Room creation time'); - const roomCreationPromises = Array.from({ length: numberRooms }, async () => { + console.log('Room creation'); + const roomPromises = Array.from({ length: numberRooms }, async (_, index) => { try { const room = await createRoomContainer(BASE_URL, token); if (room?.id) { - roomAssociations[room.id] = { teacher: null, students: [] }; - metrics.roomsCreated++; - console.log(`Room created with ID: ${room.id}`); + roomAssociations[room.id] = { watcher: null, teacher: null, students: [] }; + console.log(`Room ${index + 1} created with ID: ${room.id}`); } - } catch { - metrics.roomsFailed++; - console.warn('Failed to create a room.'); + } catch (err) { + console.warn(`Failed to create room ${index + 1}:`, err.message); } }); - await Promise.allSettled(roomCreationPromises); - console.timeEnd('Room creation time'); + // Use Promise.allSettled to ensure all promises complete + await Promise.allSettled(roomPromises); + console.log(`Total rooms created: ${Object.keys(roomAssociations).length}`); + console.log('Finished room creation'); } -// Connects teachers to their respective rooms -async function addAndConnectTeachers() { - console.time('Teacher connection time'); - const teacherPromises = Object.keys(roomAssociations).map(async (roomId, index) => { - const teacher = new Teacher(`teacher_${index}`, roomId); - const start = Date.now(); - const socket = await teacher.connectToRoom(BASE_URL); - const latency = Date.now() - start; +/** + * Adds participants (teacher, watcher, students) to rooms. + */ +function addUsersToRoom() { + console.log('Adding room participants'); + Object.keys(roomAssociations).forEach((roomId, roomIndex) => { + const participants = roomAssociations[roomId]; - metrics.totalLatency += latency; - metrics.maxLatency = Math.max(metrics.maxLatency, latency); - metrics.minLatency = Math.min(metrics.minLatency, latency); + // Assign a teacher and watcher + console.log('adding users to room ' + roomId); + participants.teacher = new Teacher(`teacher_${roomIndex}`, roomId); + participants.watcher = new Watcher(`watcher_${roomIndex}`, roomId); - if (socket.connected) { - allSockets.push(socket); - roomAssociations[roomId].teacher = teacher; - metrics.teachersConnected++; - console.log(`Teacher ${teacher.username} connected to room ${roomId}. Latency: ${latency}ms`); - } else { - metrics.teachersFailed++; - console.warn(`Failed to connect teacher ${index} to room ${roomId}`); + // Add students + for (let i = 0; i < usersPerRoom - 2; i++) { + participants.students.push(new Student(`student_${roomIndex}_${i}`, roomId)); } }); - - await Promise.allSettled(teacherPromises); - console.timeEnd('Teacher connection time'); - console.log('All teachers connected to their respective rooms.'); + console.log('Finished adding room participants'); } -// Connects students to their respective rooms -async function addAndConnectStudents() { - console.time('Student connection time'); - const studentPromises = Object.entries(roomAssociations).flatMap(([roomId, association], roomIndex) => - Array.from({ length: studentPerRoom }, async (_, i) => { - const student = new Student(`student_${roomIndex}_${i}`, roomId); - const start = Date.now(); - const socket = await student.connectToRoom(BASE_URL); - const latency = Date.now() - start; +/** + * Connects participants to their respective rooms. + */ +async function connectParticipants(baseUrl) { + console.log('Connecting participants in batches'); + const batchSize = 10; // Connect 10 participants at a time + const batchDelay = 500; // Wait 500ms between batches - metrics.totalLatency += latency; - metrics.maxLatency = Math.max(metrics.maxLatency, latency); - metrics.minLatency = Math.min(metrics.minLatency, latency); + for (const [roomId, participants] of Object.entries(roomAssociations)) { + console.log(`Processing room ${roomId}`); + + // Collect all participants for this room + const allParticipants = [ + participants.teacher, + participants.watcher, + ...participants.students + ].filter(Boolean); - if (socket.connected) { - allSockets.push(socket); - association.students.push(student); - metrics.studentsConnected++; - } else { - metrics.studentsFailed++; - console.warn(`Failed to connect student ${roomIndex}_${i} to room ${roomId}`); - } - }) - ); + // Process participants in batches + for (let i = 0; i < allParticipants.length; i += batchSize) { + const batch = allParticipants.slice(i, i + batchSize); + const batchPromises = batch.map(participant => + participant.connectToRoom(baseUrl) + .catch(err => { + console.warn( + `Failed to connect ${participant.username} in room ${roomId}:`, + err.message + ); + return null; + }) + ); - await Promise.allSettled(studentPromises); - console.timeEnd('Student connection time'); - console.log('All students connected to their respective rooms.'); -} - -// Simulates conversations in all rooms -async function simulateConversation() { - console.log("Conversation simulation started..."); - const messages = [ - "Bonjour, tout le monde !", - "Pouvez-vous répondre à la question 1 ?", - "J'ai une question sur l'exercice.", - "Voici la réponse à la question 1.", - "Merci pour vos réponses, continuons avec la question 2.", - "Je ne comprends pas bien, pouvez-vous expliquer à nouveau ?", - ]; - - const interval = 1000; - const duration = 10000; - const startTime = Date.now(); - - while (Date.now() - startTime < duration) { - for (const [roomId, association] of Object.entries(roomAssociations)) { - if (association.teacher) { - const teacherMessage = `Teacher says: ${messages[Math.floor(Math.random() * messages.length)]}`; - association.teacher.sendMessage(teacherMessage); - metrics.messagesSent++; - } - - for (const student of association.students) { - const studentMessage = `${student.username} says: ${messages[Math.floor(Math.random() * messages.length)]}`; - student.sendMessage(studentMessage); - metrics.messagesSent++; - } + await Promise.all(batchPromises); + await new Promise(resolve => setTimeout(resolve, batchDelay)); } - await new Promise((resolve) => setTimeout(resolve, interval)); } - - console.log("Conversation simulation ended."); + + console.log('Finished connecting participants'); } -// Closes all active WebSocket connections -function closeAllSockets() { - console.log('Closing all Socket.IO connections...'); - allSockets.forEach((socket) => { - if (socket && socket.connected) { - try { - socket.disconnect(); - console.log('Socket.IO connection disconnected.'); - } catch (error) { - console.error('Error disconnecting Socket.IO connection:', error.message); - } +/** + * Simulates a conversation between the teacher and students in each room. + */ +async function simulateParticipants() { + const conversationPromises = Object.entries(roomAssociations).map(async ([roomId, participants]) => { + const { teacher, students } = participants; + + if (!teacher || students.length === 0) { + console.warn(`Room ${roomId} has no teacher or students to simulate.`); + return; } + + console.log(`Starting simulation for room ${roomId}`); + + // Wait for room creation and joins to complete + await new Promise(resolve => setTimeout(resolve, 2000)); + + for (let i = 0; i < maxMessages; i++) { + const teacherMessage = `Message ${i + 1} from ${teacher.username}`; + teacher.broadcastMessage(teacherMessage); + // Add delay between messages + await new Promise(resolve => setTimeout(resolve, conversationInterval)); + } + + console.log(`Finished simulation for room ${roomId}`); }); - console.log('All Socket.IO connections have been disconnected.'); + + await Promise.all(conversationPromises); } -// Main function to orchestrate the workflow +/** + * Disconnects all participants from rooms. + */ +function disconnectParticipants() { + console.time('Disconnecting participants'); + Object.values(roomAssociations).forEach(participants => { + participants.teacher?.disconnect(); + participants.watcher?.disconnect(); + participants.students.forEach(student => student.disconnect()); + }); + console.timeEnd('Disconnecting participants'); + console.log('All participants disconnected successfully.'); +} + +/** + * Main orchestration function. + */ async function main() { try { - metrics.startTime = new Date(); + await createRoomContainers(); + addUsersToRoom(); + await connectParticipants(BASE_URL); + await simulateParticipants(); - // Login or register - const token = await attemptLoginOrRegister(BASE_URL, user.username, user.password); - if (!token) throw new Error('Failed to login or register.'); - - // Room creation - await createRoomContainers(token); - - // Resource monitoring and test activities - const roomIds = Object.keys(roomAssociations); - const usageCaptureInterval = 100; - let testCompleted = false; - - const resourceCapturePromise = captureResourceUsageForContainers( - BASE_URL, - roomIds, - usageCaptureInterval, - () => testCompleted, - metrics - ); - - const testPromise = (async () => { - await addAndConnectTeachers(); - await addAndConnectStudents(); - await simulateConversation(); - testCompleted = true; - await new Promise((resolve) => setTimeout(resolve, 5000)); - })(); - - await Promise.all([resourceCapturePromise, testPromise]); - - metrics.endTime = new Date(); - writeMetricsToFile(metrics); - await generateGraphs(metrics.resourceUsage, metrics); - - console.log("All tasks completed successfully!"); + console.log('All tasks completed successfully!'); } catch (error) { console.error('Error:', error.message); } } -// Handle process interruptions +// Graceful shutdown handlers process.on('SIGINT', () => { console.log('Process interrupted (Ctrl+C).'); - closeAllSockets(); + disconnectParticipants(); process.exit(0); }); -process.on('exit', () => closeAllSockets()); -process.on('uncaughtException', (err) => { +process.on('exit', disconnectParticipants); + +process.on('uncaughtException', err => { console.error('Uncaught Exception:', err); - closeAllSockets(); - process.exit(1); -}); -process.on('unhandledRejection', (reason, promise) => { - console.error('Unhandled Rejection:', promise, 'reason:', reason); - closeAllSockets(); + disconnectParticipants(); process.exit(1); }); +process.on('unhandledRejection', (reason, promise) => { + console.error('Unhandled Rejection at:', promise, 'reason:', reason); + disconnectParticipants(); + process.exit(1); +}); + +// Execute the main function main(); diff --git a/test/stressTest/package-lock.json b/test/stressTest/package-lock.json index b5eb2f0..b57e90d 100644 --- a/test/stressTest/package-lock.json +++ b/test/stressTest/package-lock.json @@ -12,6 +12,7 @@ "axios": "^1.7.7", "chartjs-node-canvas": "^4.1.6", "dockerode": "^4.0.2", + "p-limit": "^6.1.0", "socket.io": "^4.8.1", "socket.io-client": "^4.8.1" } @@ -814,6 +815,20 @@ "wrappy": "1" } }, + "node_modules/p-limit": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.1.0.tgz", + "integrity": "sha512-H0jc0q1vOzlEk0TqAKXKZxdl7kX3OFUzCnNVUnq5Pc3DGo0kpeaMuPqxQn235HibwBEb0/pm9dgKTjXy66fBkg==", + "dependencies": { + "yocto-queue": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1186,6 +1201,17 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yocto-queue": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", + "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/test/stressTest/package.json b/test/stressTest/package.json index 0ed6014..128e17c 100644 --- a/test/stressTest/package.json +++ b/test/stressTest/package.json @@ -13,6 +13,7 @@ "axios": "^1.7.7", "chartjs-node-canvas": "^4.1.6", "dockerode": "^4.0.2", + "p-limit": "^6.1.0", "socket.io": "^4.8.1", "socket.io-client": "^4.8.1" } diff --git a/test/stressTest/utility/apiServices.js b/test/stressTest/utility/apiServices.js index 34cce33..36d8472 100644 --- a/test/stressTest/utility/apiServices.js +++ b/test/stressTest/utility/apiServices.js @@ -1,13 +1,6 @@ import axios from "axios"; -import { io } from "socket.io-client"; -/** - * Logs in a user. - * @param {string} baseUrl - The base URL of the API. - * @param {string} email - The user's email. - * @param {string} password - The user's password. - * @returns {Promise} - The authentication token if successful. - */ +// Logs in a user. async function login(baseUrl, email, password) { if (!email || !password) throw new Error("Email and password are required."); @@ -27,13 +20,7 @@ async function login(baseUrl, email, password) { } } -/** - * Registers a new user. - * @param {string} baseUrl - The base URL of the API. - * @param {string} email - The user's email. - * @param {string} password - The user's password. - * @returns {Promise} - A success message if registration is successful. - */ +// Registers a new user. async function register(baseUrl, email, password) { if (!email || !password) throw new Error("Email and password are required."); @@ -53,13 +40,7 @@ async function register(baseUrl, email, password) { } } -/** - * Attempts to log in a user, or registers and logs in if the login fails. - * @param {string} baseUrl - The base URL of the API. - * @param {string} username - The user's email/username. - * @param {string} password - The user's password. - * @returns {Promise} - The authentication token if successful, otherwise null. - */ +// Attempts to log in a user, or registers and logs in if the login fails. export async function attemptLoginOrRegister(baseUrl, username, password) { try { return await login(baseUrl, username, password); @@ -75,12 +56,7 @@ export async function attemptLoginOrRegister(baseUrl, username, password) { } } -/** - * Creates a new room. - * @param {string} baseUrl - The base URL of the API. - * @param {string} token - The authorization token. - * @returns {Promise} - The created room object if successful. - */ +// Creates a new room export async function createRoomContainer(baseUrl, token) { if (!token) throw new Error("Authorization token is required."); @@ -98,60 +74,4 @@ export async function createRoomContainer(baseUrl, token) { console.error("Room creation error:", error.message); throw error; } -} - -/** - * Captures resource usage from multiple containers via WebSocket. - * @param {string} baseUrl - The base URL of the API. - * @param {string[]} roomIds - List of room IDs. - * @param {number} interval - Time interval between captures (ms). - * @param {function} shouldStop - Callback to determine if capturing should stop. - * @param {object} metrics - Metrics object to store resource usage. - */ -export async function captureResourceUsageForContainers(baseUrl, roomIds, interval, shouldStop, metrics) { - console.log("Starting resource usage capture..."); - - const sockets = {}; - const resourceData = {}; - - // Initialize WebSocket connections for each room - roomIds.forEach((id) => { - resourceData[id] = []; - const socket = io(baseUrl, { - path: `/api/room/${id}/socket`, - transports: ["websocket"], - autoConnect: true, - reconnection: true, - }); - - socket.on("connect", () => console.log(`Connected to room ${id}`)); - socket.on("connect_error", (err) => console.error(`Connection error for room ${id}:`, err.message)); - sockets[id] = socket; - }); - - // Capture resource usage periodically - while (!shouldStop()) { - for (const id of roomIds) { - const socket = sockets[id]; - if (socket?.connected) { - try { - socket.emit("get-usage"); - socket.once("usage-data", (data) => { - resourceData[id].push({ timestamp: Date.now(), ...data }); - }); - } catch (error) { - console.warn(`Error capturing metrics for room ${id}:`, error.message); - } - } else { - console.warn(`Socket not connected for room ${id}`); - } - } - await new Promise((resolve) => setTimeout(resolve, interval)); - } - - // Close all WebSocket connections - Object.values(sockets).forEach((socket) => socket.close()); - console.log("Resource usage capture completed."); - - metrics.resourceUsage = resourceData; -} +} \ No newline at end of file