mirror of
https://github.com/ets-cfuhrman-pfe/EvalueTonSavoir.git
synced 2025-08-11 21:23:54 -04:00
nginx conf
This commit is contained in:
parent
49fbdb1ffd
commit
0af9b099fd
4 changed files with 148 additions and 93 deletions
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
|
||||||
|
|
@ -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();
|
||||||
Loading…
Reference in a new issue