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
# RUN nginx -t --dry-run
# Switch to non-root user
USER nginx
# Expose HTTP port
EXPOSE 80

View file

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

View file

@ -1,6 +1,50 @@
async function fetchRoomInfo(r) {
function get_cache_dict(r) {
return '';
}
function getCachedData(r, key) {
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, {
method: 'GET'
});
@ -11,44 +55,43 @@ async function fetchRoomInfo(r) {
}
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;
} catch (error) {
r.error(`Error fetching room info: ${error}`);
r.error(`Error fetching/caching room info: ${error}`);
return null;
}
}
async function routeWebSocket(r) {
try {
const roomInfo = await fetchRoomInfo(r);
export default {
get_cache_dict,
routeWebSocket: async function(r) {
try {
const roomInfo = await fetchRoomInfo(r);
if (!roomInfo || !roomInfo.host) {
r.error(`Debug: Invalid room info: ${JSON.stringify(roomInfo)}`);
r.return(404, 'Room not found or invalid');
return;
if (!roomInfo || !roomInfo.host) {
r.error(`Debug: Invalid room info: ${JSON.stringify(roomInfo)}`);
r.return(404, 'Room not found or invalid');
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 user = { username: 'admin@example.com', password: 'adminPassword' };
const numberRooms = 20;
const numberRooms = 10;
const usersPerRoom = 60;
const roomAssociations = {};
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 maxMessages = 20;
const conversationInterval = 1000;
const batchSize = 20;
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() {
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.');
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] = { 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);
}
});
console.log('Room creation with immediate teacher connection');
const roomPromises = Array.from({ length: numberRooms }, (_, index) =>
createRoomWithTeacher(token, index)
);
// Use Promise.allSettled to ensure all promises complete
await Promise.allSettled(roomPromises);
const results = 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('Finished room creation');
console.log(`Total rooms created and connected: ${successfulRooms}`);
console.log('Finished room creation and teacher connection');
}
/**
* Adds participants (teacher, watcher, students) to rooms.
* Adds remaining participants (watcher, students) to rooms.
*/
function addUsersToRoom() {
console.log('Adding room participants');
function addRemainingUsers() {
console.log('Adding remaining room participants');
Object.keys(roomAssociations).forEach((roomId, roomIndex) => {
const participants = roomAssociations[roomId];
// Assign a teacher and watcher
console.log('adding users to room ' + roomId);
participants.teacher = new Teacher(`teacher_${roomIndex}`, roomId);
// Add watcher
console.log('Adding users to room ' + roomId);
participants.watcher = new Watcher(`watcher_${roomIndex}`, roomId);
// Add students
@ -59,30 +81,26 @@ function addUsersToRoom() {
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) {
console.log('Connecting participants in batches');
const batchSize = 10; // Connect 10 participants at a time
const batchDelay = 500; // Wait 500ms between batches
async function connectRemainingParticipants(baseUrl) {
console.log('Connecting remaining participants in batches');
for (const [roomId, participants] of Object.entries(roomAssociations)) {
console.log(`Processing room ${roomId}`);
// Collect all participants for this room
const allParticipants = [
participants.teacher,
// Collect remaining participants for this room
const remainingParticipants = [
participants.watcher,
...participants.students
].filter(Boolean);
// Process participants in batches
for (let i = 0; i < allParticipants.length; i += batchSize) {
const batch = allParticipants.slice(i, i + batchSize);
for (let i = 0; i < remainingParticipants.length; i += batchSize) {
const batch = remainingParticipants.slice(i, i + batchSize);
const batchPromises = batch.map(participant =>
participant.connectToRoom(baseUrl)
.catch(err => {
@ -99,12 +117,10 @@ async function connectParticipants(baseUrl) {
}
}
console.log('Finished connecting participants');
console.log('Finished connecting remaining participants');
}
/**
* Simulates a conversation between the teacher and students in each room.
*/
// Rest of the code remains the same
async function simulateParticipants() {
const conversationPromises = Object.entries(roomAssociations).map(async ([roomId, participants]) => {
const { teacher, students } = participants;
@ -116,13 +132,11 @@ async function simulateParticipants() {
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));
}
@ -132,9 +146,6 @@ async function simulateParticipants() {
await Promise.all(conversationPromises);
}
/**
* Disconnects all participants from rooms.
*/
function disconnectParticipants() {
console.time('Disconnecting participants');
Object.values(roomAssociations).forEach(participants => {
@ -146,14 +157,11 @@ function disconnectParticipants() {
console.log('All participants disconnected successfully.');
}
/**
* Main orchestration function.
*/
async function main() {
try {
await createRoomContainers();
addUsersToRoom();
await connectParticipants(BASE_URL);
addRemainingUsers();
await connectRemainingParticipants(BASE_URL);
await simulateParticipants();
console.log('All tasks completed successfully!');
@ -183,5 +191,4 @@ process.on('unhandledRejection', (reason, promise) => {
process.exit(1);
});
// Execute the main function
main();