mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
optimize and cleanup
This commit is contained in:
parent
b608793ac3
commit
5c21b6a15f
6 changed files with 143 additions and 159 deletions
|
|
@ -59,9 +59,6 @@ RUN chown -R nginx:nginx /var/cache/nginx \
|
||||||
# Verify the configuration
|
# Verify the configuration
|
||||||
# RUN nginx -t --dry-run
|
# RUN nginx -t --dry-run
|
||||||
|
|
||||||
# Switch to non-root user
|
|
||||||
USER nginx
|
|
||||||
|
|
||||||
# Expose HTTP port
|
# Expose HTTP port
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
js_import njs/main.js;
|
js_import njs/main.js;
|
||||||
|
|
||||||
js_set $room_cache_check main.checkCache;
|
|
||||||
js_set $room_cache_set main.setCache;
|
|
||||||
|
|
||||||
map $http_upgrade $connection_upgrade {
|
map $http_upgrade $connection_upgrade {
|
||||||
default upgrade;
|
default upgrade;
|
||||||
'' close;
|
'' close;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
const roomCache = new Map();
|
|
||||||
|
|
||||||
async function fetchRoomInfo(r) {
|
async function fetchRoomInfo(r) {
|
||||||
try {
|
try {
|
||||||
let res = await r.subrequest(`/api/room/${r.variables.room_id}`, { method: 'GET' });
|
// Make request to API to get room info
|
||||||
|
let res = await r.subrequest('/api/room/' + r.variables.room_id, {
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
r.error(`Failed to fetch room info: ${res.status}`);
|
r.error(`Failed to fetch room info: ${res.status}`);
|
||||||
|
|
@ -10,7 +11,7 @@ async function fetchRoomInfo(r) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let room = JSON.parse(res.responseText);
|
let room = JSON.parse(res.responseText);
|
||||||
r.error(`Debug: Room info fetched: ${JSON.stringify(room)}`);
|
r.error(`Debug: Room info: ${JSON.stringify(room)}`); // Debug log
|
||||||
return room;
|
return room;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
r.error(`Error fetching room info: ${error}`);
|
r.error(`Error fetching room info: ${error}`);
|
||||||
|
|
@ -18,48 +19,36 @@ async function fetchRoomInfo(r) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkCache(r) {
|
|
||||||
let room = roomCache.get(r.variables.room_id);
|
|
||||||
if (room) {
|
|
||||||
r.error(`Cache hit for room_id: ${r.variables.room_id}`);
|
|
||||||
r.return(200, JSON.stringify(room));
|
|
||||||
} else {
|
|
||||||
r.error(`Cache miss for room_id: ${r.variables.room_id}`);
|
|
||||||
r.return(404);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCache(r) {
|
|
||||||
let room = JSON.parse(r.responseBody);
|
|
||||||
roomCache.set(r.variables.room_id, room);
|
|
||||||
r.error(`Cached room info: ${JSON.stringify(room)}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function routeWebSocket(r) {
|
async function routeWebSocket(r) {
|
||||||
let room = roomCache.get(r.variables.room_id);
|
try {
|
||||||
|
const roomInfo = await fetchRoomInfo(r);
|
||||||
|
|
||||||
if (!room) {
|
if (!roomInfo || !roomInfo.host) {
|
||||||
r.error(`Cache miss. Fetching room info for: ${r.variables.room_id}`);
|
r.error(`Debug: Invalid room info: ${JSON.stringify(roomInfo)}`);
|
||||||
room = await fetchRoomInfo(r);
|
|
||||||
|
|
||||||
if (!room || !room.host) {
|
|
||||||
r.error(`Invalid room info for room_id: ${r.variables.room_id}`);
|
|
||||||
r.return(404, 'Room not found or invalid');
|
r.return(404, 'Room not found or invalid');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
roomCache.set(r.variables.room_id, room); // Cache the result
|
// Make sure the host includes protocol if not already present
|
||||||
} else {
|
let proxyUrl = roomInfo.host;
|
||||||
r.error(`Cache hit for room_id: ${r.variables.room_id}`);
|
if (!proxyUrl.startsWith('http://') && !proxyUrl.startsWith('https://')) {
|
||||||
|
proxyUrl = 'http://' + proxyUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
let proxyUrl = room.host.startsWith('http://') || room.host.startsWith('https://')
|
r.error(`Debug: Original URL: ${r.uri}`);
|
||||||
? room.host
|
r.error(`Debug: Setting proxy target to: ${proxyUrl}`);
|
||||||
: `http://${room.host}`;
|
r.error(`Debug: Headers: ${JSON.stringify(r.headersIn)}`);
|
||||||
|
|
||||||
r.error(`Routing WebSocket to: ${proxyUrl}`);
|
// Set the proxy target variable
|
||||||
r.variables.proxy_target = proxyUrl;
|
r.variables.proxy_target = proxyUrl;
|
||||||
|
|
||||||
|
// Redirect to the websocket proxy
|
||||||
r.internalRedirect('@websocket_proxy');
|
r.internalRedirect('@websocket_proxy');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
r.error(`WebSocket routing error: ${error}`);
|
||||||
|
r.return(500, 'Internal routing error');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { routeWebSocket, checkCache, setCache };
|
export default { routeWebSocket };
|
||||||
|
|
@ -8,9 +8,12 @@ export class Student {
|
||||||
}
|
}
|
||||||
|
|
||||||
connectToRoom(baseUrl) {
|
connectToRoom(baseUrl) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
this.socket = io(baseUrl, {
|
this.socket = io(baseUrl, {
|
||||||
path: `/api/room/${this.roomName}/socket`,
|
path: `/api/room/${this.roomName}/socket`,
|
||||||
transports: ['websocket'],autoConnect: true,
|
transports: ['websocket'],
|
||||||
|
autoConnect: true,
|
||||||
reconnection: true,
|
reconnection: true,
|
||||||
reconnectionAttempts: 10,
|
reconnectionAttempts: 10,
|
||||||
reconnectionDelay: 10000,
|
reconnectionDelay: 10000,
|
||||||
|
|
@ -18,10 +21,19 @@ export class Student {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on('connect', () => {
|
this.socket.on('connect', () => {
|
||||||
this.joinRoom(this.roomName,this.username);
|
this.joinRoom(this.roomName, this.username);
|
||||||
|
resolve(this.socket);
|
||||||
});
|
});
|
||||||
|
|
||||||
return 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.roomId}:`, error.message);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
joinRoom(roomName, username) {
|
joinRoom(roomName, username) {
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,12 @@ export class Teacher {
|
||||||
}
|
}
|
||||||
|
|
||||||
connectToRoom(baseUrl) {
|
connectToRoom(baseUrl) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
this.socket = io(baseUrl, {
|
this.socket = io(baseUrl, {
|
||||||
path: `/api/room/${this.roomName}/socket`,
|
path: `/api/room/${this.roomName}/socket`,
|
||||||
transports: ['websocket'],autoConnect: true,
|
transports: ['websocket'],
|
||||||
|
autoConnect: true,
|
||||||
reconnection: true,
|
reconnection: true,
|
||||||
reconnectionAttempts: 10,
|
reconnectionAttempts: 10,
|
||||||
reconnectionDelay: 10000,
|
reconnectionDelay: 10000,
|
||||||
|
|
@ -19,12 +22,22 @@ export class Teacher {
|
||||||
|
|
||||||
this.socket.on('connect', () => {
|
this.socket.on('connect', () => {
|
||||||
this.createRoom(this.roomName);
|
this.createRoom(this.roomName);
|
||||||
|
resolve(this.socket);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.socket.on('error', (error) => {
|
||||||
|
reject(new Error(`Connection error: ${error.message}`));
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on('create-success', () => {
|
this.socket.on('create-success', () => {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return this.socket;
|
} catch (error) {
|
||||||
|
console.error(`Error connecting ${this.name} to room ${this.roomId}:`, error.message);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
createRoom() {
|
createRoom() {
|
||||||
|
|
|
||||||
|
|
@ -3,126 +3,102 @@ import { Student } from './class/student.js';
|
||||||
import { Teacher } from './class/teacher.js';
|
import { Teacher } from './class/teacher.js';
|
||||||
|
|
||||||
const BASE_URL = 'http://localhost';
|
const BASE_URL = 'http://localhost';
|
||||||
const user = {
|
const user = { username: 'admin@example.com', password: 'adminPassword' };
|
||||||
username: 'admin@example.com',
|
const numberRooms = 5;
|
||||||
password: 'adminPassword',
|
const studentPerRoom = 59; // Max is 60; 1 slot reserved for the teacher
|
||||||
};
|
|
||||||
|
|
||||||
const numberRooms = 30;
|
|
||||||
const studentPerRoom = 59; // Max is 60; 1 slot is reserved for the teacher
|
|
||||||
|
|
||||||
const roomAssociations = {};
|
const roomAssociations = {};
|
||||||
const allSockets = []; // Track all active WebSocket connections
|
const allSockets = []; // Track all active WebSocket connections
|
||||||
|
|
||||||
async function createRoomsAndTeachers(token) {
|
async function createRoomContainers(token) {
|
||||||
const roomCreationPromises = [];
|
const roomCreationPromises = Array.from({ length: numberRooms }, async () => {
|
||||||
const teachers = [];
|
const room = await createRoomContainer(BASE_URL, token);
|
||||||
|
|
||||||
for (let index = 0; index < numberRooms; index++) {
|
|
||||||
roomCreationPromises.push(
|
|
||||||
createRoomContainer(BASE_URL, token).then((room) => {
|
|
||||||
if (room?.id) {
|
if (room?.id) {
|
||||||
const teacher = new Teacher(`teacher_${index}`, room.id);
|
roomAssociations[room.id] = { teacher: null, students: [] };
|
||||||
teachers.push(teacher);
|
console.log(`Created room with ID: ${room.id}`);
|
||||||
|
} else {
|
||||||
roomAssociations[room.id] = {
|
console.warn('Failed to create a room.');
|
||||||
teacher,
|
|
||||||
students: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
// Track teacher WebSocket for cleanup
|
|
||||||
if (teacher.socket) {
|
|
||||||
allSockets.push(teacher.socket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.allSettled(roomCreationPromises);
|
|
||||||
console.log(`Created ${Object.keys(roomAssociations).length} rooms with associated teachers.`);
|
|
||||||
return teachers;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function connectTeachersToRooms(teachers) {
|
|
||||||
const teacherConnectionPromises = teachers.map(async (teacher) => {
|
|
||||||
await teacher.connectToRoom(BASE_URL);
|
|
||||||
if (teacher.socket) {
|
|
||||||
allSockets.push(teacher.socket); // Track WebSocket
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.allSettled(teacherConnectionPromises);
|
await Promise.allSettled(roomCreationPromises);
|
||||||
console.log('All teachers connected to their rooms.');
|
console.log(`Created ${Object.keys(roomAssociations).length} room containers.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addAndConnectTeachers() {
|
||||||
|
const teacherCreationPromises = Object.keys(roomAssociations).map(async (roomId, index) => {
|
||||||
|
const teacher = new Teacher(`teacher_${index}`, roomId);
|
||||||
|
const socket = await teacher.connectToRoom(BASE_URL);
|
||||||
|
|
||||||
|
if (socket.connected) {
|
||||||
|
allSockets.push(socket);
|
||||||
|
roomAssociations[roomId].teacher = teacher;
|
||||||
|
console.log(`Teacher ${teacher.username} connected to room ${roomId}.`);
|
||||||
|
} else {
|
||||||
|
console.warn(`Failed to connect teacher_${index} to room ${roomId}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.allSettled(teacherCreationPromises);
|
||||||
|
console.log('All teachers added and connected to their respective rooms.');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addAndConnectStudents() {
|
async function addAndConnectStudents() {
|
||||||
const studentCreationPromises = [];
|
const studentCreationPromises = Object.entries(roomAssociations).flatMap(([roomId, association], roomIndex) =>
|
||||||
|
Array.from({ length: studentPerRoom }, async (_, i) => {
|
||||||
Object.entries(roomAssociations).forEach(([roomId, association], roomIndex) => {
|
|
||||||
for (let i = 0; i < studentPerRoom; i++) {
|
|
||||||
const student = new Student(`student_${roomIndex}_${i}`, roomId);
|
const student = new Student(`student_${roomIndex}_${i}`, roomId);
|
||||||
association.students.push(student);
|
const socket = await student.connectToRoom(BASE_URL);
|
||||||
|
|
||||||
studentCreationPromises.push(
|
if (socket.connected) {
|
||||||
student.connectToRoom(BASE_URL).then(() => {
|
allSockets.push(socket);
|
||||||
if (student.socket) {
|
association.students.push(student);
|
||||||
allSockets.push(student.socket); // Track WebSocket
|
console.log(`Student ${student.username} connected to room ${roomId}.`);
|
||||||
|
} else {
|
||||||
|
console.warn(`Failed to connect student_${roomIndex}_${i} to room ${roomId}`);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.allSettled(studentCreationPromises);
|
await Promise.allSettled(studentCreationPromises);
|
||||||
console.log('All students connected to their respective rooms.');
|
console.log('All students added and connected to their respective rooms.');
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeAllSockets() {
|
function closeAllSockets() {
|
||||||
console.log('Closing all WebSocket connections...');
|
console.log('Closing all Socket.IO connections...');
|
||||||
allSockets.forEach((socket) => {
|
allSockets.forEach((socket) => {
|
||||||
|
if (socket && socket.connected) {
|
||||||
try {
|
try {
|
||||||
if (socket.readyState === socket.OPEN) {
|
socket.disconnect();
|
||||||
socket.close(); // Gracefully close the WebSocket
|
console.log('Disconnected Socket.IO connection.');
|
||||||
console.log('Closed WebSocket connection.');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error closing WebSocket:', error.message);
|
console.error('Error disconnecting Socket.IO socket:', error.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log('All WebSocket connections closed.');
|
console.log('All Socket.IO connections disconnected.');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
try {
|
try {
|
||||||
const token = await attemptLoginOrRegister(BASE_URL, user.username, user.password);
|
const token = await attemptLoginOrRegister(BASE_URL, user.username, user.password);
|
||||||
if (!token) {
|
if (!token) throw new Error('Failed to log in.');
|
||||||
console.error('Failed to log in. Exiting...');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const teachers = await createRoomsAndTeachers(token);
|
await createRoomContainers(token);
|
||||||
await connectTeachersToRooms(teachers);
|
await addAndConnectTeachers();
|
||||||
await addAndConnectStudents();
|
await addAndConnectStudents();
|
||||||
|
|
||||||
console.log('All tasks completed.');
|
console.log('All tasks completed.');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('An error occurred:', error.message);
|
console.error('An error occurred:', error.message);
|
||||||
} finally {
|
|
||||||
closeAllSockets();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle script termination (Ctrl+C)
|
// Handle script termination and exit
|
||||||
process.on('SIGINT', () => {
|
process.on('SIGINT', () => {
|
||||||
console.log('Script interrupted (Ctrl+C).');
|
console.log('Script interrupted (Ctrl+C).');
|
||||||
closeAllSockets();
|
closeAllSockets();
|
||||||
process.exit(0); // Exit cleanly
|
process.exit(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle script exit
|
process.on('exit', closeAllSockets);
|
||||||
process.on('exit', () => {
|
|
||||||
closeAllSockets();
|
|
||||||
});
|
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue