nginx conf

This commit is contained in:
MathieuSevignyLavallee 2024-11-27 21:00:52 -05:00
parent 49fbdb1ffd
commit 0af9b099fd
4 changed files with 148 additions and 93 deletions

View file

@ -59,6 +59,9 @@ 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

View file

@ -1,4 +1,6 @@
js_shared_dict_zone zone=cache:10m;
js_import njs/main.js; js_import njs/main.js;
js_set $cache_dict main.get_cache_dict;
map $http_upgrade $connection_upgrade { map $http_upgrade $connection_upgrade {
default upgrade; default upgrade;

View file

@ -1,6 +1,50 @@
async function fetchRoomInfo(r) { function get_cache_dict(r) {
return '';
}
function getCachedData(r, key) {
try { try {
// Make request to API to get room info const cached = ngx.shared.cache.get(key);
if (cached) {
const data = JSON.parse(cached);
const now = Date.now();
// 2 minutes cache - let game rooms rotate
if (now - data.timestamp < 120000) {
r.error(`Debug: Cache hit for ${key}, age: ${(now - data.timestamp)/1000}s`);
return data.value;
}
r.error(`Debug: Cache expired for ${key}, age: ${(now - data.timestamp)/1000}s`);
}
return null;
} catch (error) {
r.error(`Cache read error: ${error}`);
return null;
}
}
function setCachedData(r, key, value) {
try {
const data = {
timestamp: Date.now(),
value: value
};
ngx.shared.cache.set(key, JSON.stringify(data));
r.error(`Debug: Cached ${key}`);
} catch (error) {
r.error(`Cache write error: ${error}`);
}
}
async function fetchRoomInfo(r) {
const cacheKey = `room:${r.variables.room_id}`;
try {
const cachedRoom = getCachedData(r, cacheKey);
if (cachedRoom) {
r.error(`Debug: Room info from cache: ${JSON.stringify(cachedRoom)}`);
return cachedRoom;
}
let res = await r.subrequest('/api/room/' + r.variables.room_id, { let res = await r.subrequest('/api/room/' + r.variables.room_id, {
method: 'GET' method: 'GET'
}); });
@ -11,44 +55,43 @@ async function fetchRoomInfo(r) {
} }
let room = JSON.parse(res.responseText); let room = JSON.parse(res.responseText);
r.error(`Debug: Room info: ${JSON.stringify(room)}`); // Debug log setCachedData(r, cacheKey, room);
r.error(`Debug: Room info fetched and cached: ${JSON.stringify(room)}`);
return room; return room;
} catch (error) { } catch (error) {
r.error(`Error fetching room info: ${error}`); r.error(`Error fetching/caching room info: ${error}`);
return null; return null;
} }
} }
async function routeWebSocket(r) { export default {
try { get_cache_dict,
const roomInfo = await fetchRoomInfo(r); routeWebSocket: async function(r) {
try {
const roomInfo = await fetchRoomInfo(r);
if (!roomInfo || !roomInfo.host) { if (!roomInfo || !roomInfo.host) {
r.error(`Debug: Invalid room info: ${JSON.stringify(roomInfo)}`); r.error(`Debug: Invalid room info: ${JSON.stringify(roomInfo)}`);
r.return(404, 'Room not found or invalid'); r.return(404, 'Room not found or invalid');
return; return;
}
let proxyUrl = roomInfo.host;
if (!proxyUrl.startsWith('http://') && !proxyUrl.startsWith('https://')) {
proxyUrl = 'http://' + proxyUrl;
}
r.error(`Debug: Original URL: ${r.uri}`);
r.error(`Debug: Setting proxy target to: ${proxyUrl}`);
r.error(`Debug: Headers: ${JSON.stringify(r.headersIn)}`);
r.variables.proxy_target = proxyUrl;
r.internalRedirect('@websocket_proxy');
} catch (error) {
r.error(`WebSocket routing error: ${error}`);
r.return(500, 'Internal routing error');
} }
// Make sure the host includes protocol if not already present
let proxyUrl = roomInfo.host;
if (!proxyUrl.startsWith('http://') && !proxyUrl.startsWith('https://')) {
proxyUrl = 'http://' + proxyUrl;
}
r.error(`Debug: Original URL: ${r.uri}`);
r.error(`Debug: Setting proxy target to: ${proxyUrl}`);
r.error(`Debug: Headers: ${JSON.stringify(r.headersIn)}`);
// Set the proxy target variable
r.variables.proxy_target = proxyUrl;
// Redirect to the websocket proxy
r.internalRedirect('@websocket_proxy');
} catch (error) {
r.error(`WebSocket routing error: ${error}`);
r.return(500, 'Internal routing error');
} }
} };
export default { routeWebSocket };

View file

@ -5,53 +5,75 @@ import { Watcher } from './class/watcher.js';
const BASE_URL = 'http://localhost'; const BASE_URL = 'http://localhost';
const user = { username: 'admin@example.com', password: 'adminPassword' }; const user = { username: 'admin@example.com', password: 'adminPassword' };
const numberRooms = 20; const numberRooms = 10;
const usersPerRoom = 60; const usersPerRoom = 60;
const roomAssociations = {}; const roomAssociations = {};
const maxMessages = 20; // Number of conversation rounds const maxMessages = 20;
const conversationInterval = 1000; // Interval between teacher messages (ms) const conversationInterval = 1000;
const batchSize = 10; // Number of simultaneous connections const batchSize = 20;
const batchDelay = 500; const batchDelay = 250;
/** /**
* Creates rooms with controlled concurrency. * Creates a room and immediately connects a teacher to it.
*/
async function createRoomWithTeacher(token, index) {
try {
const room = await createRoomContainer(BASE_URL, token);
if (!room?.id) {
throw new Error('Room creation failed');
}
console.log(`Room ${index + 1} created with ID: ${room.id}`);
// Initialize room associations
roomAssociations[room.id] = { watcher: null, teacher: null, students: [] };
// Create and connect teacher immediately
const teacher = new Teacher(`teacher_${index}`, room.id);
roomAssociations[room.id].teacher = teacher;
// Connect teacher to room
await teacher.connectToRoom(BASE_URL);
console.log(`Teacher connected to room ${room.id}`);
return room.id;
} catch (err) {
console.warn(`Failed to create/connect room ${index + 1}:`, err.message);
return null;
}
}
/**
* Creates rooms and connects teachers with controlled concurrency.
*/ */
async function createRoomContainers() { async function createRoomContainers() {
console.log('Attempting login or register to get token'); console.log('Attempting login or register to get token');
const token = await attemptLoginOrRegister(BASE_URL, user.username, user.password); const token = await attemptLoginOrRegister(BASE_URL, user.username, user.password);
if (!token) throw new Error('Failed to login or register.'); if (!token) throw new Error('Failed to login or register.');
console.log('Room creation'); console.log('Room creation with immediate teacher connection');
const roomPromises = Array.from({ length: numberRooms }, async (_, index) => { const roomPromises = Array.from({ length: numberRooms }, (_, index) =>
try { createRoomWithTeacher(token, index)
const room = await createRoomContainer(BASE_URL, token); );
if (room?.id) {
roomAssociations[room.id] = { watcher: null, teacher: null, students: [] };
console.log(`Room ${index + 1} created with ID: ${room.id}`);
}
} catch (err) {
console.warn(`Failed to create room ${index + 1}:`, err.message);
}
});
// Use Promise.allSettled to ensure all promises complete const results = await Promise.allSettled(roomPromises);
await Promise.allSettled(roomPromises); const successfulRooms = results.filter(r => r.status === 'fulfilled' && r.value).length;
console.log(`Total rooms created: ${Object.keys(roomAssociations).length}`); console.log(`Total rooms created and connected: ${successfulRooms}`);
console.log('Finished room creation'); console.log('Finished room creation and teacher connection');
} }
/** /**
* Adds participants (teacher, watcher, students) to rooms. * Adds remaining participants (watcher, students) to rooms.
*/ */
function addUsersToRoom() { function addRemainingUsers() {
console.log('Adding room participants'); console.log('Adding remaining room participants');
Object.keys(roomAssociations).forEach((roomId, roomIndex) => { Object.keys(roomAssociations).forEach((roomId, roomIndex) => {
const participants = roomAssociations[roomId]; const participants = roomAssociations[roomId];
// Assign a teacher and watcher // Add watcher
console.log('adding users to room ' + roomId); console.log('Adding users to room ' + roomId);
participants.teacher = new Teacher(`teacher_${roomIndex}`, roomId);
participants.watcher = new Watcher(`watcher_${roomIndex}`, roomId); participants.watcher = new Watcher(`watcher_${roomIndex}`, roomId);
// Add students // Add students
@ -59,30 +81,26 @@ function addUsersToRoom() {
participants.students.push(new Student(`student_${roomIndex}_${i}`, roomId)); participants.students.push(new Student(`student_${roomIndex}_${i}`, roomId));
} }
}); });
console.log('Finished adding room participants'); console.log('Finished adding remaining room participants');
} }
/** /**
* Connects participants to their respective rooms. * Connects remaining participants to their respective rooms.
*/ */
async function connectParticipants(baseUrl) { async function connectRemainingParticipants(baseUrl) {
console.log('Connecting participants in batches'); console.log('Connecting remaining participants in batches');
const batchSize = 10; // Connect 10 participants at a time
const batchDelay = 500; // Wait 500ms between batches
for (const [roomId, participants] of Object.entries(roomAssociations)) { for (const [roomId, participants] of Object.entries(roomAssociations)) {
console.log(`Processing room ${roomId}`); console.log(`Processing room ${roomId}`);
// Collect all participants for this room // Collect remaining participants for this room
const allParticipants = [ const remainingParticipants = [
participants.teacher,
participants.watcher, participants.watcher,
...participants.students ...participants.students
].filter(Boolean); ].filter(Boolean);
// Process participants in batches // Process participants in batches
for (let i = 0; i < allParticipants.length; i += batchSize) { for (let i = 0; i < remainingParticipants.length; i += batchSize) {
const batch = allParticipants.slice(i, i + batchSize); const batch = remainingParticipants.slice(i, i + batchSize);
const batchPromises = batch.map(participant => const batchPromises = batch.map(participant =>
participant.connectToRoom(baseUrl) participant.connectToRoom(baseUrl)
.catch(err => { .catch(err => {
@ -99,12 +117,10 @@ async function connectParticipants(baseUrl) {
} }
} }
console.log('Finished connecting participants'); console.log('Finished connecting remaining participants');
} }
/** // Rest of the code remains the same
* Simulates a conversation between the teacher and students in each room.
*/
async function simulateParticipants() { async function simulateParticipants() {
const conversationPromises = Object.entries(roomAssociations).map(async ([roomId, participants]) => { const conversationPromises = Object.entries(roomAssociations).map(async ([roomId, participants]) => {
const { teacher, students } = participants; const { teacher, students } = participants;
@ -116,13 +132,11 @@ async function simulateParticipants() {
console.log(`Starting simulation for room ${roomId}`); console.log(`Starting simulation for room ${roomId}`);
// Wait for room creation and joins to complete
await new Promise(resolve => setTimeout(resolve, 2000)); await new Promise(resolve => setTimeout(resolve, 2000));
for (let i = 0; i < maxMessages; i++) { for (let i = 0; i < maxMessages; i++) {
const teacherMessage = `Message ${i + 1} from ${teacher.username}`; const teacherMessage = `Message ${i + 1} from ${teacher.username}`;
teacher.broadcastMessage(teacherMessage); teacher.broadcastMessage(teacherMessage);
// Add delay between messages
await new Promise(resolve => setTimeout(resolve, conversationInterval)); await new Promise(resolve => setTimeout(resolve, conversationInterval));
} }
@ -132,9 +146,6 @@ async function simulateParticipants() {
await Promise.all(conversationPromises); await Promise.all(conversationPromises);
} }
/**
* Disconnects all participants from rooms.
*/
function disconnectParticipants() { function disconnectParticipants() {
console.time('Disconnecting participants'); console.time('Disconnecting participants');
Object.values(roomAssociations).forEach(participants => { Object.values(roomAssociations).forEach(participants => {
@ -146,14 +157,11 @@ function disconnectParticipants() {
console.log('All participants disconnected successfully.'); console.log('All participants disconnected successfully.');
} }
/**
* Main orchestration function.
*/
async function main() { async function main() {
try { try {
await createRoomContainers(); await createRoomContainers();
addUsersToRoom(); addRemainingUsers();
await connectParticipants(BASE_URL); await connectRemainingParticipants(BASE_URL);
await simulateParticipants(); await simulateParticipants();
console.log('All tasks completed successfully!'); console.log('All tasks completed successfully!');
@ -183,5 +191,4 @@ process.on('unhandledRejection', (reason, promise) => {
process.exit(1); process.exit(1);
}); });
// Execute the main function
main(); main();