From 977d1c9700ceaf25f5e84127f3a092c938be20b1 Mon Sep 17 00:00:00 2001 From: MathieuSevignyLavallee <89943988+MathieuSevignyLavallee@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:44:15 -0500 Subject: [PATCH] added jwt token to room routes --- .../pages/Teacher/ManageRoom/ManageRoom.tsx | 2 +- client/src/services/ApiService.tsx | 73 ++++++++++ client/src/services/WebsocketService.tsx | 3 +- nginx/njs/main.js | 12 +- server/app.js | 22 --- server/middleware/jwtToken.js | 2 +- server/roomsProviders/docker-provider.js | 3 +- server/routers/rooms.js | 8 +- server/socket/socket.js | 125 ------------------ 9 files changed, 88 insertions(+), 162 deletions(-) delete mode 100644 server/socket/socket.js diff --git a/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx b/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx index c577f34..d337c10 100644 --- a/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx +++ b/client/src/pages/Teacher/ManageRoom/ManageRoom.tsx @@ -81,7 +81,7 @@ const ManageRoom: React.FC = () => { const createWebSocketRoom = async () => { setConnectingError(''); - const room = await (await fetch('/api/room', { method: 'post' })).json(); + const room = await ApiService.createRoom(); const socket = webSocketService.connect(`/api/room/${room.id}/socket`); socket.on('connect', () => { diff --git a/client/src/services/ApiService.tsx b/client/src/services/ApiService.tsx index ea0d79d..6ccee33 100644 --- a/client/src/services/ApiService.tsx +++ b/client/src/services/ApiService.tsx @@ -80,6 +80,78 @@ class ApiService { return localStorage.removeItem("jwt"); } + + //Socket Route + + /** + * Creates a new room. + * @returns The room object if successful + * @returns An error string if unsuccessful + */ + public async createRoom(): Promise { + try { + const url: string = this.constructRequestUrl(`/room`); + const headers = this.constructRequestHeaders(); + + const response = await fetch(url, { + method: 'POST', + headers: headers, + }); + + if (!response.ok) { + throw new Error(`La création de la salle a échoué. Status: ${response.status}`); + } + + const room = await response.json(); + return room; + + } catch (error) { + console.log("Error details: ", error); + + if (error instanceof Error) { + return error.message || 'Erreur serveur inconnue lors de la requête.'; + } + + return `Une erreur inattendue s'est produite.`; + } + } + + + /** + * Deletes a room by its name. + * @param roomName - The name of the room to delete. + * @returns true if successful + * @returns An error string if unsuccessful + */ + public async deleteRoom(roomName: string): Promise { + try { + if (!roomName) { + throw new Error(`Le nom de la salle est requis.`); + } + + const url = this.constructRequestUrl(`/room/${roomName}`); + const headers = this.constructRequestHeaders(); + fetch(url, { + method: 'DELETE', + headers: headers, + }); + + return true; + + } catch (error) { + console.log("Error details: ", error); + + if (error instanceof Error) { + return error.message || 'Erreur serveur inconnue lors de la requête.'; + } + + return `Une erreur inattendue s'est produite.`; + } + } + + + + // User Routes /** @@ -302,6 +374,7 @@ class ApiService { } } + /** * @returns folder array if successful * @returns A error string if unsuccessful, diff --git a/client/src/services/WebsocketService.tsx b/client/src/services/WebsocketService.tsx index c99e858..f19bce5 100644 --- a/client/src/services/WebsocketService.tsx +++ b/client/src/services/WebsocketService.tsx @@ -1,5 +1,6 @@ // WebSocketService.tsx import { io, Socket } from 'socket.io-client'; +import apiService from './ApiService'; // Must (manually) sync these types to server/socket/socket.js @@ -63,7 +64,7 @@ class WebSocketService { if (this.socket) { this.socket.emit('end-quiz', { roomName }); //Delete room in mongoDb, roomContainer will be deleted in cleanup - fetch(`/api/room/${roomName}`, { method: 'DELETE' }); + apiService.deleteRoom(roomName); } } diff --git a/nginx/njs/main.js b/nginx/njs/main.js index 82b6548..d824272 100644 --- a/nginx/njs/main.js +++ b/nginx/njs/main.js @@ -4,12 +4,12 @@ async function fetchRoomInfo(r) { let res = await r.subrequest('/api/room/' + r.variables.room_id, { method: 'GET' }); - + if (res.status !== 200) { r.error(`Failed to fetch room info: ${res.status}`); return null; } - + let room = JSON.parse(res.responseText); r.error(`Debug: Room info: ${JSON.stringify(room)}`); // Debug log return room; @@ -22,7 +22,7 @@ async function fetchRoomInfo(r) { async function routeWebSocket(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'); @@ -38,13 +38,13 @@ async function routeWebSocket(r) { 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'); diff --git a/server/app.js b/server/app.js index 9e8ea1b..afba445 100644 --- a/server/app.js +++ b/server/app.js @@ -3,10 +3,6 @@ const express = require("express"); const http = require("http"); const dotenv = require('dotenv'); -// Import Sockets -const { setupWebsocket } = require("./socket/socket"); -const { Server } = require("socket.io"); - // instantiate the db const db = require('./config/db.js'); // instantiate the models @@ -61,28 +57,10 @@ const app = express(); const cors = require("cors"); const bodyParser = require('body-parser'); - -const configureServer = (httpServer, isDev) => { - return new Server(httpServer, { - path: "/socket.io", - cors: { - origin: "*", - methods: ["GET", "POST"], - credentials: true, - }, - secure: !isDev, // true for https, false for http - }); -}; - -// Start sockets (depending on the dev or prod environment) let server = http.createServer(app); let isDev = process.env.NODE_ENV === 'development'; - console.log(`Environnement: ${process.env.NODE_ENV} (${isDev ? 'dev' : 'prod'})`); -const io = configureServer(server); - -setupWebsocket(io); app.use(cors()); app.use(bodyParser.urlencoded({ extended: true })); app.use(bodyParser.json()); diff --git a/server/middleware/jwtToken.js b/server/middleware/jwtToken.js index 292e591..10eb97b 100644 --- a/server/middleware/jwtToken.js +++ b/server/middleware/jwtToken.js @@ -22,7 +22,7 @@ class Token { if (error) { throw new AppError(UNAUTHORIZED_INVALID_TOKEN) } - + req.user = payload; }); diff --git a/server/roomsProviders/docker-provider.js b/server/roomsProviders/docker-provider.js index 9589c52..fb7fc53 100644 --- a/server/roomsProviders/docker-provider.js +++ b/server/roomsProviders/docker-provider.js @@ -1,5 +1,5 @@ const Docker = require("dockerode"); -const { Room, RoomRepository } = require("../models/room.js"); +const { Room } = require("../models/room.js"); const BaseRoomProvider = require("./base-provider.js"); class DockerRoomProvider extends BaseRoomProvider { @@ -126,7 +126,6 @@ class DockerRoomProvider extends BaseRoomProvider { } } - async deleteRoom(roomId) { const container_name = `room_${roomId}`; await this.roomRepository.delete(roomId); diff --git a/server/routers/rooms.js b/server/routers/rooms.js index 1fc1f9e..b34b7d9 100644 --- a/server/routers/rooms.js +++ b/server/routers/rooms.js @@ -4,7 +4,7 @@ const jwt = require('../middleware/jwtToken.js'); const router = Router(); -router.get("/", async (req, res)=> { +router.get("/",jwt.authenticate, async (req, res)=> { try { const data = await roomsController.listRooms(); res.json(data); @@ -14,7 +14,7 @@ router.get("/", async (req, res)=> { }); -router.post("/", async (req, res) => { +router.post("/",jwt.authenticate, async (req, res) => { try { const data = await roomsController.createRoom(); res.json(data); @@ -24,7 +24,7 @@ router.post("/", async (req, res) => { } }); -router.put("/:id", async (req, res) => { +router.put("/:id",jwt.authenticate, async (req, res) => { try { const data = await roomsController.updateRoom(req.params.id); res.json(data); @@ -33,7 +33,7 @@ router.put("/:id", async (req, res) => { } }); -router.delete("/:id", async (req, res) => { +router.delete("/:id",jwt.authenticate, async (req, res) => { try { const data = await roomsController.deleteRoom(req.params.id); res.json(data); diff --git a/server/socket/socket.js b/server/socket/socket.js deleted file mode 100644 index 3bb0a76..0000000 --- a/server/socket/socket.js +++ /dev/null @@ -1,125 +0,0 @@ -const MAX_USERS_PER_ROOM = 60; -const MAX_TOTAL_CONNECTIONS = 2000; - -const setupWebsocket = (io) => { - let totalConnections = 0; - - io.on("connection", (socket) => { - if (totalConnections >= MAX_TOTAL_CONNECTIONS) { - console.log("Connection limit reached. Disconnecting client."); - socket.emit( - "join-failure", - "Le nombre maximum de connexions a été atteint" - ); - socket.disconnect(true); - return; - } - - totalConnections++; - // console.log( - // "A user connected:", - // socket.id, - // "| Total connections:", - // totalConnections - // ); - - socket.on("create-room", (sentRoomName) => { - if (sentRoomName) { - const roomName = sentRoomName.toUpperCase(); - if (!io.sockets.adapter.rooms.get(roomName)) { - socket.join(roomName); - socket.emit("create-success", roomName); - } else { - socket.emit("create-failure"); - } - } else { - const roomName = generateRoomName(); - if (!io.sockets.adapter.rooms.get(roomName)) { - socket.join(roomName); - socket.emit("create-success", roomName); - } else { - socket.emit("create-failure"); - } - } - }); - - socket.on("join-room", ({ enteredRoomName, username }) => { - if (io.sockets.adapter.rooms.has(enteredRoomName)) { - const clientsInRoom = - io.sockets.adapter.rooms.get(enteredRoomName).size; - - if (clientsInRoom <= MAX_USERS_PER_ROOM) { - const newStudent = { - id: socket.id, - name: username, - answers: [], - }; - socket.join(enteredRoomName); - socket - .to(enteredRoomName) - .emit("user-joined", newStudent); - socket.emit("join-success"); - } else { - socket.emit("join-failure", "La salle est remplie"); - } - } else { - socket.emit("join-failure", "Le nom de la salle n'existe pas"); - } - }); - - socket.on("next-question", ({ roomName, question }) => { - // console.log("next-question", roomName, question); - socket.to(roomName).emit("next-question", question); - }); - - socket.on("launch-student-mode", ({ roomName, questions }) => { - socket.to(roomName).emit("launch-student-mode", questions); - }); - - socket.on("end-quiz", ({ roomName }) => { - socket.to(roomName).emit("end-quiz"); - }); - - socket.on("message", (data) => { - console.log("Received message from", socket.id, ":", data); - }); - - socket.on("disconnect", () => { - totalConnections--; - console.log( - "A user disconnected:", - socket.id, - "| Total connections:", - totalConnections - ); - - for (const [room] of io.sockets.adapter.rooms) { - if (room !== socket.id) { - io.to(room).emit("user-disconnected", socket.id); - } - } - }); - - socket.on("submit-answer", ({ roomName, username, answer, idQuestion }) => { - socket.to(roomName).emit("submit-answer-room", { - idUser: socket.id, - username, - answer, - idQuestion, - }); - }); - }); - - const generateRoomName = (length = 6) => { - const characters = "0123456789"; - let result = ""; - for (let i = 0; i < length; i++) { - result += characters.charAt( - Math.floor(Math.random() * characters.length) - ); - } - return result; - }; -}; - -module.exports = { setupWebsocket };