From a0b5e970587c53ee316baabc83e9d2e5a40cb033 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Fri, 15 May 2026 22:59:15 +0200 Subject: [PATCH 01/15] kkk --- src/rooms/index.js | 16 ++++++++++++++++ src/utils/auth.js | 26 ++++++++++---------------- src/utils/streams.js | 33 ++++++++++++++++++++++++++------- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/rooms/index.js b/src/rooms/index.js index 42b9eca..f70fe6e 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -8,3 +8,19 @@ // - createRoom (create a room) // - updateRoom (update a room's configuration) // - deleteRoom (delete a room) +// + +// joinRoom notes +// io.on('connection', (socket) => { +// // join the room named 'some room' +// socket.join('some room'); + +// // broadcast to all connected clients in the room +// io.to('some room').emit('hello', 'world'); + +// // broadcast to all connected clients except those in the room +// io.except('some room').emit('hello', 'world'); + +// // leave the room +// socket.leave('some room'); +// }); diff --git a/src/utils/auth.js b/src/utils/auth.js index 3dfa666..015db2a 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -144,32 +144,26 @@ async function authedAPIRequest(endpoint, options) { } options.headers.Authorization = "Bearer " + localStorage.getItem("token"); - options.mode = "cors"; const full_endpoint = import.meta.env.VITE_URL + "/api" + endpoint; let response; - try { - response = await fetch(full_endpoint, options); - if (!response.ok) { - throw new Error(response.statusText); - } - } catch (err) { - if (response.status === 401) { - const response_err = await response.text(); + response = await fetch(full_endpoint, options); + if (response.status === 401) { + const response_err = await response.text(); - if (response_err.includes("Token expired")) { - await refreshToken(null); - return null; + if (response_err.includes("Token expired")) { + if (await refreshToken(null)) { + return await authedAPIRequest(endpoint, options); } - localStorage.clear(); - alert("Redirecting to logging page"); - redirect.redirectToLoginPage(); return null; } - console.error(err); + localStorage.clear(); + alert("Redirecting to logging page"); + redirect.redirectToLoginPage(); + return null; } return response; diff --git a/src/utils/streams.js b/src/utils/streams.js index 8b01319..938f0dd 100644 --- a/src/utils/streams.js +++ b/src/utils/streams.js @@ -1,5 +1,5 @@ import { io } from "socket.io-client"; -// import { v4 as uuidv4 } from "uuid"; +import { v4 as uuidv4 } from "uuid"; // FIXME: This file should handle the sockets and the subscriptions // Exports must include @@ -12,13 +12,18 @@ import { io } from "socket.io-client"; // - sendMessage (send a message to a room's chat) let socket = null; -// let uuid = uuidv4(); +const uuid = uuidv4(); /** * Initializes the socket when authenticated * returns {Promise} */ async function initSocket() { + if (socket !== null) { + console.warn("Blocked attempt to re-init socket connection"); + return; + } + console.debug("Initializing socket connection"); const token = localStorage.getItem("token"); @@ -38,13 +43,27 @@ async function initSocket() { } // TODO -// async function subscribe(room) { +async function subscribe(room) { + if (!room) { + room = "epi-place"; + } -// if (!room) -// room = "epi-place" + // console.warn("Skipping room susbscription (not implemented)") + const msg = { + id: uuid, + method: "subscription", + params: { + path: "rooms.canvas.getStream" | "rooms.getChat", + input: { + json: { + roomSlug: room, + }, + }, + }, + }; -// console.warn("Skipping room susbscription (not implemented)") -// } + socket.send(msg); +} // async function unsubscribe() { From 2b7b6b8684c5cf365908025f4f1d49bec1b2c6d6 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 11:14:39 +0200 Subject: [PATCH 02/15] no moulinette ? --- src/pages/index.js | 12 ++++++++++-- src/rooms/index.js | 20 ++++++++++++++++++++ src/utils/auth.js | 14 ++++++-------- src/utils/redirect.js | 2 +- src/utils/streams.js | 18 +++++++++++++----- 5 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index f09dade..c839e35 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -1,6 +1,7 @@ -import { initSocket } from "../utils/streams"; +import { initSocket, subscribe } from "../utils/streams"; import { calculateLayout } from "./utils"; import { authenticate } from "../utils/auth"; +import { fetchRoomConfig } from "../rooms"; // Initialize the layout calculateLayout(); @@ -11,6 +12,13 @@ async () => { return; } + let room = window.location.pathname.split("/")[1]; + + if (room === "") { + room = "epi-place"; + } + initSocket(); - // subscribe() + subscribe(room, "pixel-update"); + fetchRoomConfig(room); }; diff --git a/src/rooms/index.js b/src/rooms/index.js index f70fe6e..00afe91 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -1,3 +1,4 @@ +import { authedAPIRequest } from "../utils/auth"; // FIXME: This file should handle the rooms API // Functions may include: // - fetchRoomConfig (get the configuration of a room) @@ -24,3 +25,22 @@ // // leave the room // socket.leave('some room'); // }); +// + +async function fetchRoomConfig(room) { + const response = await authedAPIRequest("/rooms/" + room + "/config"); + + if (!response.ok) { + console.error("Could not retrieve room config: " + response.statusText); + console.debug(await response.text()); + return; + } + + const obj = await response.json(); + + console.debug(`Retrieved config for room ${room}: ${obj}`); + + // Update HTML +} + +export { fetchRoomConfig }; diff --git a/src/utils/auth.js b/src/utils/auth.js index 015db2a..f0f1005 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -134,10 +134,10 @@ async function authedAPIRequest(endpoint, options) { return null; } - if (!options.method) { - console.error("Invalid parameter: options (missing method)"); - return null; - } + // if (!options.method) { + // console.error("Invalid parameter: options (missing method)"); + // return null; + // } if (!options.headers) { options.headers = {}; @@ -146,9 +146,9 @@ async function authedAPIRequest(endpoint, options) { options.headers.Authorization = "Bearer " + localStorage.getItem("token"); const full_endpoint = import.meta.env.VITE_URL + "/api" + endpoint; - let response; - response = await fetch(full_endpoint, options); + const response = await fetch(full_endpoint, options); + if (response.status === 401) { const response_err = await response.text(); @@ -156,8 +156,6 @@ async function authedAPIRequest(endpoint, options) { if (await refreshToken(null)) { return await authedAPIRequest(endpoint, options); } - - return null; } localStorage.clear(); diff --git a/src/utils/redirect.js b/src/utils/redirect.js index 9c0a6d3..1be53f8 100644 --- a/src/utils/redirect.js +++ b/src/utils/redirect.js @@ -21,7 +21,7 @@ function createLink() { function redirectToLoginPage() { const redirectUrl = createLink(); - window.location.href = redirectUrl; + window.location.href = redirectUrl.href; } export { createLink, redirectToLoginPage }; diff --git a/src/utils/streams.js b/src/utils/streams.js index 938f0dd..b269f45 100644 --- a/src/utils/streams.js +++ b/src/utils/streams.js @@ -42,18 +42,26 @@ async function initSocket() { return; } -// TODO -async function subscribe(room) { +async function subscribe(room, channel) { if (!room) { room = "epi-place"; } - // console.warn("Skipping room susbscription (not implemented)") + if (!channel) { + channel = "message"; + } + + let path = "rooms.canvas.getStream"; + + if (channel.includes("chat") || channel.includes("message")) { + path = "rooms.getChat"; + } + const msg = { id: uuid, method: "subscription", params: { - path: "rooms.canvas.getStream" | "rooms.getChat", + path: path, input: { json: { roomSlug: room, @@ -72,4 +80,4 @@ async function subscribe(room) { // } -export { initSocket, socket }; +export { socket, initSocket, subscribe }; From 02ac670fe18a33000af5b7daae4f11e8fee66d8e Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 12:18:35 +0200 Subject: [PATCH 03/15] join the channel of the room you want to subscribe on the server you just initialized a socket on --- src/pages/index.js | 21 ++++-------- src/rooms/index.js | 79 ++++++++++++++++++++++++++++++++++---------- src/utils/auth.js | 12 ++++--- src/utils/streams.js | 4 +++ 4 files changed, 81 insertions(+), 35 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index c839e35..dbdb46e 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -1,24 +1,17 @@ import { initSocket, subscribe } from "../utils/streams"; import { calculateLayout } from "./utils"; import { authenticate } from "../utils/auth"; -import { fetchRoomConfig } from "../rooms"; // Initialize the layout calculateLayout(); -async () => { - // ? Not sure - if (!(await authenticate())) { - return; - } +await authenticate(); - let room = window.location.pathname.split("/")[1]; +let room = window.location.pathname.split("/")[1]; - if (room === "") { - room = "epi-place"; - } +if (!room) { + room = "epi-place"; +} - initSocket(); - subscribe(room, "pixel-update"); - fetchRoomConfig(room); -}; +await initSocket(); +await subscribe(room, "pixel-update"); diff --git a/src/rooms/index.js b/src/rooms/index.js index 00afe91..f4c36c0 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -1,4 +1,5 @@ import { authedAPIRequest } from "../utils/auth"; +import { socket } from "../pages/index"; // FIXME: This file should handle the rooms API // Functions may include: // - fetchRoomConfig (get the configuration of a room) @@ -9,26 +10,55 @@ import { authedAPIRequest } from "../utils/auth"; // - createRoom (create a room) // - updateRoom (update a room's configuration) // - deleteRoom (delete a room) -// -// joinRoom notes -// io.on('connection', (socket) => { -// // join the room named 'some room' -// socket.join('some room'); +const roomsConfig = null; -// // broadcast to all connected clients in the room -// io.to('some room').emit('hello', 'world'); +function setCurrentRoomConfig(room, cfg) { + roomsConfig[room] = cfg; +} +function getCurrentRoomConfig(room) { + return roomsConfig[room]; +} +async function joinRoom(room) { + socket.on("connection", (sockett) => { + sockett.join(room); -// // broadcast to all connected clients except those in the room -// io.except('some room').emit('hello', 'world'); + // broadcast to all connected clients in the room + // socket.to('some room').emit('hello', 'world'); -// // leave the room -// socket.leave('some room'); -// }); -// + // broadcast to all connected clients except those in the room + // socket.except('some room').emit('hello', 'world'); + }); +} + +// async function leaveRoom(room) { +// io.on('connection', (socket) => { +// socket.leave(room); +// }) +// } + +// async function listRooms() { + +// } +// async function createRoom() { + +// } +// async function updateRoom() { + +// } +// async function deleteRoom() { + +// } async function fetchRoomConfig(room) { - const response = await authedAPIRequest("/rooms/" + room + "/config"); + if (!room) { + console.error("Cannot fetch an undefined room"); + return; + } + + const response = await authedAPIRequest("/rooms/" + room + "/config", { + method: "GET", + }); if (!response.ok) { console.error("Could not retrieve room config: " + response.statusText); @@ -36,11 +66,26 @@ async function fetchRoomConfig(room) { return; } - const obj = await response.json(); + const res = await response.json(); - console.debug(`Retrieved config for room ${room}: ${obj}`); + console.debug(`Retrieved config for room ${room}:`); + console.debug(res); + + setCurrentRoomConfig(res); // Update HTML + const roomNameElt = document.getElementById("room-name"); + + roomNameElt.innerText = res.metadata.name; } -export { fetchRoomConfig }; +export { + fetchRoomConfig, + setCurrentRoomConfig, + getCurrentRoomConfig, + joinRoom, + // listRooms, + // createRoom, + // updateRoom, + // deleteRoom +}; diff --git a/src/utils/auth.js b/src/utils/auth.js index f0f1005..6454ec3 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -139,15 +139,19 @@ async function authedAPIRequest(endpoint, options) { // return null; // } - if (!options.headers) { - options.headers = {}; + // Deep copy req + const request = JSON.parse(JSON.stringify(options)); + + if (!request.headers) { + request.headers = {}; } - options.headers.Authorization = "Bearer " + localStorage.getItem("token"); + // Pcq ce PUTAIN de js est pas foutu de faire ce qu'on lui demande + request.headers.Authorization = "Bearer " + localStorage.getItem("token"); const full_endpoint = import.meta.env.VITE_URL + "/api" + endpoint; - const response = await fetch(full_endpoint, options); + const response = await fetch(full_endpoint, request); if (response.status === 401) { const response_err = await response.text(); diff --git a/src/utils/streams.js b/src/utils/streams.js index b269f45..c707239 100644 --- a/src/utils/streams.js +++ b/src/utils/streams.js @@ -1,5 +1,6 @@ import { io } from "socket.io-client"; import { v4 as uuidv4 } from "uuid"; +import { fetchRoomConfig } from "../rooms"; // FIXME: This file should handle the sockets and the subscriptions // Exports must include @@ -71,6 +72,9 @@ async function subscribe(room, channel) { }; socket.send(msg); + socket.on("message", async () => { + await fetchRoomConfig(room); + }); } // async function unsubscribe() { From 814e559ccda57ad47e4c6088eaeb51f6ea8206b2 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 13:38:37 +0200 Subject: [PATCH 04/15] Join us --- src/pages/index.js | 33 ++++++++++++++++++++++++++-- src/rooms/canvas/index.js | 42 ++++++++++++++++++++++++++++++------ src/rooms/index.js | 45 +++++++++++++++++++++++++++------------ src/students/index.js | 40 +++++++++++++++++++++++++++++----- src/utils/streams.js | 4 ---- 5 files changed, 132 insertions(+), 32 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index dbdb46e..2d845f2 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -1,6 +1,9 @@ -import { initSocket, subscribe } from "../utils/streams"; +import { initSocket, socket, subscribe } from "../utils/streams"; import { calculateLayout } from "./utils"; -import { authenticate } from "../utils/auth"; +import { authenticate, refreshToken } from "../utils/auth"; +import { initCanvas } from "../rooms/canvas/utils"; +import { getCanvas } from "../rooms/canvas/index"; +import { fetchRoomConfig, getCurrentRoomConfig } from "../rooms/index"; // Initialize the layout calculateLayout(); @@ -15,3 +18,29 @@ if (!room) { await initSocket(); await subscribe(room, "pixel-update"); +// Main event +socket.on("message", async (response) => { + console.debug("Received server evemt: "); + console.debug(response); + if (response.error) { + console.error("Got server error: " + response.error.json.message); + + if (response.error.json.data.httpStatus === 401) { + await refreshToken(); + } + + return; + } + + if (response.result.type === "started") { + await fetchRoomConfig(room); + } + + const canvasResp = getCanvas(room); + + if (!canvasResp || canvasResp.pixels) { + return; + } + + initCanvas(getCurrentRoomConfig(), canvasResp.pixels); +}); diff --git a/src/rooms/canvas/index.js b/src/rooms/canvas/index.js index 628a6a5..3afd15c 100644 --- a/src/rooms/canvas/index.js +++ b/src/rooms/canvas/index.js @@ -1,7 +1,35 @@ -// FIXME: This file should handle the room canvas API -// Link buttons to their respective functions -// Functions may include: -// - getCanvas (get the canvas of a room and deserialize it) -// - subscribeToRoom (subscribe to the stream of a room) -// - getPixelInfo (get the pixel info of a room) -// - placePixel (place a pixel in a room) +import { authedAPIRequest } from "../../utils/auth"; + +// get the canvas of a room and deserialize it +async function getCanvas(room) { + if (!room) { + console.error("Cannot fetch canvas of an undefined room"); + return null; + } + + const response = await authedAPIRequest("/rooms/" + room + "/canvas", { + method: "GET", + }); + + if (!response.ok) { + console.error("Could not retrieve room canvas: " + response.statusText); + console.debug(await response.text()); + return null; + } + + const res = await response.json(); + + console.debug(`Retrieved canvas for room ${room}:`); + console.debug(res); + + return res; +} + +// subscribe to the stream of a room +function subscribeToRoom() {} +// get the pixel info of a room +function getPixelInfo() {} +// place a pixel in a room +function placePixel() {} + +export { getCanvas, subscribeToRoom, getPixelInfo, placePixel }; diff --git a/src/rooms/index.js b/src/rooms/index.js index f4c36c0..2a7345d 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -1,5 +1,6 @@ import { authedAPIRequest } from "../utils/auth"; -import { socket } from "../pages/index"; +import { subscribe } from "../utils/streams"; +import { resetValues } from "./canvas/utils"; // FIXME: This file should handle the rooms API // Functions may include: // - fetchRoomConfig (get the configuration of a room) @@ -11,7 +12,7 @@ import { socket } from "../pages/index"; // - updateRoom (update a room's configuration) // - deleteRoom (delete a room) -const roomsConfig = null; +const roomsConfig = {}; function setCurrentRoomConfig(room, cfg) { roomsConfig[room] = cfg; @@ -20,26 +21,42 @@ function getCurrentRoomConfig(room) { return roomsConfig[room]; } async function joinRoom(room) { - socket.on("connection", (sockett) => { - sockett.join(room); + // socket.on('connection', (sockett) => { + // sockett.join(room); + // broadcast to all connected clients in the room + // socket.to('some room').emit('hello', 'world'); + // broadcast to all connected clients except those in the room + // socket.except('some room').emit('hello', 'world'); + // }); - // broadcast to all connected clients in the room - // socket.to('some room').emit('hello', 'world'); - - // broadcast to all connected clients except those in the room - // socket.except('some room').emit('hello', 'world'); - }); + resetValues(); + subscribe(room); } // async function leaveRoom(room) { -// io.on('connection', (socket) => { +// socket.on('connection', (socket) => { // socket.leave(room); // }) // } -// async function listRooms() { +async function listRooms() { + const response = await authedAPIRequest("/rooms/", { method: "GET" }); -// } + if (!response.ok) { + console.error("Could not retrieve rooms list: " + response.statusText); + console.debug(await response.text()); + return; + } + + const res = await response.json(); + + console.debug("Retrieved rooms list"); + console.debug(res); + + // Update HTML + // const roomNameElt = document.getElementById("room-name"); + // roomNameElt.innerText = res.metadata.name; +} // async function createRoom() { // } @@ -84,7 +101,7 @@ export { setCurrentRoomConfig, getCurrentRoomConfig, joinRoom, - // listRooms, + listRooms, // createRoom, // updateRoom, // deleteRoom diff --git a/src/students/index.js b/src/students/index.js index 7b6a978..43a7ade 100644 --- a/src/students/index.js +++ b/src/students/index.js @@ -1,5 +1,35 @@ -// FIXME: This file should handle the students API -// Functions may include: -// - getStudent (get a student from the API by its uid or login) -// - getUserUidFromToken (get the user's uid from the token in local storage) -// - updateStudent (update the student's profile through the API) +import { authedAPIRequest } from "../utils/auth"; + +//get a student from the API by its uid or login +async function getStudent(login) { + if (!login) { + console.error("Cannot fetch an undefined student"); + return; + } + + const response = await authedAPIRequest("/students/" + login, { + method: "GET", + }); + + if (!response.ok) { + console.error("Could not retrieve student: " + response.statusText); + console.debug(await response.text()); + return; + } + + const res = await response.json(); + + console.debug(`Retrieved student ${login}:`); + console.debug(res); + + // Update HTML + // const roomNameElt = document.getElementById("room-name"); + // roomNameElt.innerText = res.metadata.name +} + +//// get the user's uid from the token in local storage +async function getUserUidFromToken() {} +// update the student's profile through the API +async function updateStudent() {} + +export { getStudent, getUserUidFromToken, updateStudent }; diff --git a/src/utils/streams.js b/src/utils/streams.js index c707239..b269f45 100644 --- a/src/utils/streams.js +++ b/src/utils/streams.js @@ -1,6 +1,5 @@ import { io } from "socket.io-client"; import { v4 as uuidv4 } from "uuid"; -import { fetchRoomConfig } from "../rooms"; // FIXME: This file should handle the sockets and the subscriptions // Exports must include @@ -72,9 +71,6 @@ async function subscribe(room, channel) { }; socket.send(msg); - socket.on("message", async () => { - await fetchRoomConfig(room); - }); } // async function unsubscribe() { From 8cab4ac558761d585afc8b53428f76a7a68a03f3 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 16:15:40 +0200 Subject: [PATCH 05/15] bouaaaaaaaaaaaah --- src/pages/index.js | 39 ++++++++++++++++++++++++++++----- src/rooms/canvas/index.js | 46 ++++++++++++++++++++++++++++++++++++--- src/rooms/index.js | 13 ++++++----- 3 files changed, 84 insertions(+), 14 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index 2d845f2..c555a68 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -1,7 +1,7 @@ import { initSocket, socket, subscribe } from "../utils/streams"; import { calculateLayout } from "./utils"; import { authenticate, refreshToken } from "../utils/auth"; -import { initCanvas } from "../rooms/canvas/utils"; +import { initCanvas, renderCanvasUpdate } from "../rooms/canvas/utils"; import { getCanvas } from "../rooms/canvas/index"; import { fetchRoomConfig, getCurrentRoomConfig } from "../rooms/index"; @@ -20,7 +20,7 @@ await initSocket(); await subscribe(room, "pixel-update"); // Main event socket.on("message", async (response) => { - console.debug("Received server evemt: "); + console.debug("Received server event on message: "); console.debug(response); if (response.error) { console.error("Got server error: " + response.error.json.message); @@ -36,11 +36,38 @@ socket.on("message", async (response) => { await fetchRoomConfig(room); } - const canvasResp = getCanvas(room); - - if (!canvasResp || canvasResp.pixels) { + const pixels = await getCanvas(room); + if (!pixels) { return; } + + initCanvas(await getCurrentRoomConfig(), pixels); + console.debug("Loaded canvas") - initCanvas(getCurrentRoomConfig(), canvasResp.pixels); }); + +socket.on("pixel-update", async (msg) => { + // console.debug("Received server event on pixel-update: "); + // console.debug(msg); + if (msg.error) { + console.error("Got server error: " + msg.error.json.message); + return; + } + // console.debug("Here is msg.data") + // console.debug(msg.result.data.json) + const { + roomSlug, + posX, + posY, + color + } = msg.result.data.json + + const cfg = await getCurrentRoomConfig() + if (!cfg || !cfg.settings || !cfg.settings.roomColors) { + console.error("Internal error: Cannot access config after retrieving it") + console.debug(cfg) + return; + } + + renderCanvasUpdate(color, posX, posY); +}) diff --git a/src/rooms/canvas/index.js b/src/rooms/canvas/index.js index 3afd15c..67d735e 100644 --- a/src/rooms/canvas/index.js +++ b/src/rooms/canvas/index.js @@ -1,7 +1,10 @@ import { authedAPIRequest } from "../../utils/auth"; -// get the canvas of a room and deserialize it -async function getCanvas(room) { +/** + * @param {string} room + * @return {Promise} The response Json object + */ +async function fetchCanvas(room) { if (!room) { console.error("Cannot fetch canvas of an undefined room"); return null; @@ -20,15 +23,52 @@ async function getCanvas(room) { const res = await response.json(); console.debug(`Retrieved canvas for room ${room}:`); - console.debug(res); + // console.debug(res); return res; } +// Splits a string into fixed length substrings +String.prototype.chunk = function(size) { + return [].concat.apply([], + this.split('').map(function(x,i){ return i%size ? [] : this.slice(i,i+size) }, this) + ) +} + +// get the canvas of a room and deserialize it +async function getCanvas(room) { + const raw_pixels = await fetchCanvas(room); + if (!raw_pixels || !raw_pixels.pixels) { + console.error("Aborting canvas deserialization") + return null; + } + + // Convert to a an array of strings representing binary (beurk) + let raw_binary_str = "" + for (let i = 0; i < raw_pixels.pixels.length; i++) { + raw_binary_str = raw_binary_str.concat(raw_pixels.pixels.charCodeAt(i).toString(2).padStart(8, "0")) + } + // console.debug(raw_binary_str) + + // Chunk it to an array of fixed-length string (5) + let pixel_array = raw_binary_str.chunk(5) + if (pixel_array[pixel_array.length-1].length < 5) + pixel_array.pop() + // console.debug(pixel_array) + + // Convert into numbers + pixel_array = pixel_array.map((pixel) => parseInt( pixel, 2 )) + // console.debug(pixel_array) + + return pixel_array +} + // subscribe to the stream of a room function subscribeToRoom() {} + // get the pixel info of a room function getPixelInfo() {} + // place a pixel in a room function placePixel() {} diff --git a/src/rooms/index.js b/src/rooms/index.js index 2a7345d..9fccaf8 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -12,13 +12,16 @@ import { resetValues } from "./canvas/utils"; // - updateRoom (update a room's configuration) // - deleteRoom (delete a room) -const roomsConfig = {}; -function setCurrentRoomConfig(room, cfg) { - roomsConfig[room] = cfg; +let roomConfig = null; + +function setCurrentRoomConfig(cfg) { + roomConfig = cfg; } -function getCurrentRoomConfig(room) { - return roomsConfig[room]; +async function getCurrentRoomConfig() { + if (!roomConfig) + await fetchRoomConfig(); + return roomConfig; } async function joinRoom(room) { // socket.on('connection', (sockett) => { From 50d46d0f0cc99c7abbf51d763c309f0b20f9ae73 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 16:25:05 +0200 Subject: [PATCH 06/15] hnininini --- src/pages/index.js | 26 ++++++++++++---------- src/rooms/canvas/index.js | 45 +++++++++++++++++++++++++-------------- src/rooms/index.js | 21 ++++++++++++------ 3 files changed, 59 insertions(+), 33 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index c555a68..d65784a 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -37,13 +37,13 @@ socket.on("message", async (response) => { } const pixels = await getCanvas(room); + if (!pixels) { return; } - - initCanvas(await getCurrentRoomConfig(), pixels); - console.debug("Loaded canvas") + initCanvas(await getCurrentRoomConfig(), pixels); + console.debug("Loaded canvas"); }); socket.on("pixel-update", async (msg) => { @@ -53,21 +53,25 @@ socket.on("pixel-update", async (msg) => { console.error("Got server error: " + msg.error.json.message); return; } + // console.debug("Here is msg.data") // console.debug(msg.result.data.json) const { - roomSlug, + // roomSlug, posX, posY, - color - } = msg.result.data.json + color, + } = msg.result.data.json; + + const cfg = await getCurrentRoomConfig(); - const cfg = await getCurrentRoomConfig() if (!cfg || !cfg.settings || !cfg.settings.roomColors) { - console.error("Internal error: Cannot access config after retrieving it") - console.debug(cfg) + console.error( + "Internal error: Cannot access config after retrieving it", + ); + console.debug(cfg); return; } - + renderCanvasUpdate(color, posX, posY); -}) +}); diff --git a/src/rooms/canvas/index.js b/src/rooms/canvas/index.js index 67d735e..7af13c2 100644 --- a/src/rooms/canvas/index.js +++ b/src/rooms/canvas/index.js @@ -14,8 +14,12 @@ async function fetchCanvas(room) { method: "GET", }); - if (!response.ok) { - console.error("Could not retrieve room canvas: " + response.statusText); + if (!response || !response.ok) { + console.error( + "Could not retrieve room canvas: " + response + ? response.statusText + : "null", + ); console.debug(await response.text()); return null; } @@ -29,38 +33,47 @@ async function fetchCanvas(room) { } // Splits a string into fixed length substrings -String.prototype.chunk = function(size) { - return [].concat.apply([], - this.split('').map(function(x,i){ return i%size ? [] : this.slice(i,i+size) }, this) - ) -} +String.prototype.chunk = function (size) { + return [].concat.apply( + [], + this.split("").map(function (x, i) { + return i % size ? [] : this.slice(i, i + size); + }, this), + ); +}; // get the canvas of a room and deserialize it async function getCanvas(room) { const raw_pixels = await fetchCanvas(room); + if (!raw_pixels || !raw_pixels.pixels) { - console.error("Aborting canvas deserialization") + console.error("Aborting canvas deserialization"); return null; } // Convert to a an array of strings representing binary (beurk) - let raw_binary_str = "" + let raw_binary_str = ""; + for (let i = 0; i < raw_pixels.pixels.length; i++) { - raw_binary_str = raw_binary_str.concat(raw_pixels.pixels.charCodeAt(i).toString(2).padStart(8, "0")) + raw_binary_str = raw_binary_str.concat( + raw_pixels.pixels.charCodeAt(i).toString(2).padStart(8, "0"), + ); } // console.debug(raw_binary_str) - + // Chunk it to an array of fixed-length string (5) - let pixel_array = raw_binary_str.chunk(5) - if (pixel_array[pixel_array.length-1].length < 5) - pixel_array.pop() + let pixel_array = raw_binary_str.chunk(5); + + if (pixel_array[pixel_array.length - 1].length < 5) { + pixel_array.pop(); + } // console.debug(pixel_array) // Convert into numbers - pixel_array = pixel_array.map((pixel) => parseInt( pixel, 2 )) + pixel_array = pixel_array.map((pixel) => parseInt(pixel, 2)); // console.debug(pixel_array) - return pixel_array + return pixel_array; } // subscribe to the stream of a room diff --git a/src/rooms/index.js b/src/rooms/index.js index 9fccaf8..c383c17 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -12,15 +12,16 @@ import { resetValues } from "./canvas/utils"; // - updateRoom (update a room's configuration) // - deleteRoom (delete a room) - let roomConfig = null; function setCurrentRoomConfig(cfg) { roomConfig = cfg; } async function getCurrentRoomConfig() { - if (!roomConfig) + if (!roomConfig) { await fetchRoomConfig(); + } + return roomConfig; } async function joinRoom(room) { @@ -45,8 +46,12 @@ async function joinRoom(room) { async function listRooms() { const response = await authedAPIRequest("/rooms/", { method: "GET" }); - if (!response.ok) { - console.error("Could not retrieve rooms list: " + response.statusText); + if (!response || !response.ok) { + console.error( + "Could not retrieve rooms list: " + response + ? response.statusText + : "null", + ); console.debug(await response.text()); return; } @@ -80,8 +85,12 @@ async function fetchRoomConfig(room) { method: "GET", }); - if (!response.ok) { - console.error("Could not retrieve room config: " + response.statusText); + if (!response || !response.ok) { + console.error( + "Could not retrieve room config" + response + ? response.statusText + : "null", + ); console.debug(await response.text()); return; } From c6f5ab3438d45fce0bcb6907e6e1466965ddcc03 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 17:18:47 +0200 Subject: [PATCH 07/15] c trop bieeeen --- src/pages/index.js | 30 ++++++++++++++++++++++++-- src/rooms/canvas/index.js | 44 +++++++++++++++++++++++++++++++++++---- src/rooms/canvas/utils.js | 2 +- src/rooms/index.js | 4 ++-- src/students/index.js | 8 +++++-- src/utils/auth.js | 8 +++++-- 6 files changed, 83 insertions(+), 13 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index d65784a..78eb488 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -1,15 +1,23 @@ import { initSocket, socket, subscribe } from "../utils/streams"; import { calculateLayout } from "./utils"; import { authenticate, refreshToken } from "../utils/auth"; -import { initCanvas, renderCanvasUpdate } from "../rooms/canvas/utils"; -import { getCanvas } from "../rooms/canvas/index"; +import { + getPlacementData, + initCanvas, + renderCanvasUpdate, +} from "../rooms/canvas/utils"; +import { getCanvas, placePixel } from "../rooms/canvas/index"; import { fetchRoomConfig, getCurrentRoomConfig } from "../rooms/index"; // Initialize the layout calculateLayout(); +// Auth await authenticate(); +//////////////////////////////////// +// Sockets +// let room = window.location.pathname.split("/")[1]; if (!room) { @@ -75,3 +83,21 @@ socket.on("pixel-update", async (msg) => { renderCanvasUpdate(color, posX, posY); }); + +//////////////////////////////////// +// Buttons +// +async function placePixelButton() { + const { posX, posY, color } = getPlacementData(); + + await placePixel(room, posX, posY, color); +} + +//////////////////////////////////// +// HTML +// +const placeButtonElt = document.getElementById("color-place-button"); + +placeButtonElt.addEventListener("click", () => { + placePixelButton(); +}); diff --git a/src/rooms/canvas/index.js b/src/rooms/canvas/index.js index 7af13c2..ff2681f 100644 --- a/src/rooms/canvas/index.js +++ b/src/rooms/canvas/index.js @@ -16,11 +16,11 @@ async function fetchCanvas(room) { if (!response || !response.ok) { console.error( - "Could not retrieve room canvas: " + response + "Could not retrieve room canvas: " + response && response.statusText ? response.statusText - : "null", + : "no more informations", ); - console.debug(await response.text()); + // console.debug(await response.text()); return null; } @@ -83,6 +83,42 @@ function subscribeToRoom() {} function getPixelInfo() {} // place a pixel in a room -function placePixel() {} +async function placePixel(room, posX, posY, color) { + if (!room) { + console.error("Cannot place pixel on an undefined room"); + return null; + } + + const response = await authedAPIRequest( + "/rooms/" + room + "/canvas/pixels", + { + method: "POST", + body: JSON.stringify({ + posX: posX, + posY: posY, + color: color, + }), + }, + ); + + if (!response || !response.ok) { + console.error( + "Could not place pixel on map: " + response && response.statusText + ? response.statusText + : "no more informations", + ); + // console.debug(await response.text()); + return null; + } + + const res = await response.json(); + + console.debug( + `Placed pixel on map at ${posX}:${posY} (${color}) in room ${room}:`, + ); + // console.debug(res); + + return res; +} export { getCanvas, subscribeToRoom, getPixelInfo, placePixel }; diff --git a/src/rooms/canvas/utils.js b/src/rooms/canvas/utils.js index c5e123d..c6feb9e 100644 --- a/src/rooms/canvas/utils.js +++ b/src/rooms/canvas/utils.js @@ -39,7 +39,7 @@ let isDrag = false; * Get the placement data, i.e. the color the user has selected and the * coordinates of the pixel he is focusing on. * - * @returns {{color: number, posX: number, posX: number}} the data + * @returns {{color: number, posX: number, posY: number}} the data */ export const getPlacementData = () => ({ color: selectedColorIdx, diff --git a/src/rooms/index.js b/src/rooms/index.js index c383c17..0364732 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -48,7 +48,7 @@ async function listRooms() { if (!response || !response.ok) { console.error( - "Could not retrieve rooms list: " + response + "Could not retrieve rooms list: " + response && response.statusText ? response.statusText : "null", ); @@ -87,7 +87,7 @@ async function fetchRoomConfig(room) { if (!response || !response.ok) { console.error( - "Could not retrieve room config" + response + "Could not retrieve room config" + response && response.statusText ? response.statusText : "null", ); diff --git a/src/students/index.js b/src/students/index.js index 43a7ade..b7fab1e 100644 --- a/src/students/index.js +++ b/src/students/index.js @@ -11,8 +11,12 @@ async function getStudent(login) { method: "GET", }); - if (!response.ok) { - console.error("Could not retrieve student: " + response.statusText); + if (!response || !response.ok) { + console.error( + "Could not retrieve student: " + response + ? response.statusText + : " no status text", + ); console.debug(await response.text()); return; } diff --git a/src/utils/auth.js b/src/utils/auth.js index 6454ec3..967b925 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -20,8 +20,12 @@ async function sendRequest(endpoint, body) { try { response = await fetch(endpoint, request); - if (!response.ok) { - throw new Error(response.statusText); + if (!response || !response.ok) { + if (response && response.statusText) { + throw new Error(response.statusText); + } else { + throw new Error("No status text"); + } } } catch (err) { console.error(err); From 3d1a427dcf6a3450d5982fff8db32f590d3d655c Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 17:37:42 +0200 Subject: [PATCH 08/15] amongous --- src/pages/index.js | 2 +- src/rooms/canvas/index.js | 44 +++++++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index 78eb488..18dd801 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -88,7 +88,7 @@ socket.on("pixel-update", async (msg) => { // Buttons // async function placePixelButton() { - const { posX, posY, color } = getPlacementData(); + const { color, posX, posY } = getPlacementData(); await placePixel(room, posX, posY, color); } diff --git a/src/rooms/canvas/index.js b/src/rooms/canvas/index.js index ff2681f..d3fe575 100644 --- a/src/rooms/canvas/index.js +++ b/src/rooms/canvas/index.js @@ -80,7 +80,40 @@ async function getCanvas(room) { function subscribeToRoom() {} // get the pixel info of a room -function getPixelInfo() {} +async function getPixelInfo(room, posX, posY) { + if (!room) { + console.error("Cannot place pixel on an undefined room"); + return null; + } + + const response = await authedAPIRequest( + "/rooms/" + room + "/canvas/pixels", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + posX, + posY, + }), + }, + ); + + if (!response || !response.ok) { + console.error( + "Could not retrieve pixel infos: " + response && response.statusText + ? response.statusText + : "no more informations", + ); + // console.debug(await response.text()); + return null; + } + + const res = await response.json(); + + return res; +} // place a pixel in a room async function placePixel(room, posX, posY, color) { @@ -93,10 +126,13 @@ async function placePixel(room, posX, posY, color) { "/rooms/" + room + "/canvas/pixels", { method: "POST", + headers: { + "Content-Type": "application/json", + }, body: JSON.stringify({ - posX: posX, - posY: posY, - color: color, + posX, + posY, + color, }), }, ); From 1e4cd71e06b26c4da07768862303b61a72c01c82 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 18:18:56 +0200 Subject: [PATCH 09/15] bk --- src/pages/index.js | 4 ++++ src/rooms/canvas/index.js | 2 +- src/rooms/canvas/utils.js | 6 ++++++ src/rooms/index.js | 3 ++- src/students/index.js | 2 +- 5 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index 18dd801..606bef0 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -101,3 +101,7 @@ const placeButtonElt = document.getElementById("color-place-button"); placeButtonElt.addEventListener("click", () => { placePixelButton(); }); + +export { + room +} diff --git a/src/rooms/canvas/index.js b/src/rooms/canvas/index.js index d3fe575..644a73b 100644 --- a/src/rooms/canvas/index.js +++ b/src/rooms/canvas/index.js @@ -89,7 +89,7 @@ async function getPixelInfo(room, posX, posY) { const response = await authedAPIRequest( "/rooms/" + room + "/canvas/pixels", { - method: "POST", + method: "GET", headers: { "Content-Type": "application/json", }, diff --git a/src/rooms/canvas/utils.js b/src/rooms/canvas/utils.js index c6feb9e..ba7fef5 100644 --- a/src/rooms/canvas/utils.js +++ b/src/rooms/canvas/utils.js @@ -6,6 +6,8 @@ // - toggleTooltip (toggle the tooltip and display the pixel's information) import $ from "jquery"; +import { getPixelInfo } from "./index"; +import { room } from "../../pages/index"; const canvasContainer = $("#canvas-container")?.[0]; const canvas = $("#canvas")?.[0]; @@ -60,6 +62,10 @@ export const toggleTooltip = async (state = false) => { if (state) { // FIXME: You should implement or call a function to get the pixel's information // and display it. Make use of target.x and target.y to get the pixel's position. + const response = await getPixelInfo(room, target.x, target.y); + if (!response) { + return; + } } }; diff --git a/src/rooms/index.js b/src/rooms/index.js index 0364732..1e53671 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -1,6 +1,7 @@ import { authedAPIRequest } from "../utils/auth"; import { subscribe } from "../utils/streams"; import { resetValues } from "./canvas/utils"; +import { room } from "../pages/index" // FIXME: This file should handle the rooms API // Functions may include: // - fetchRoomConfig (get the configuration of a room) @@ -19,7 +20,7 @@ function setCurrentRoomConfig(cfg) { } async function getCurrentRoomConfig() { if (!roomConfig) { - await fetchRoomConfig(); + await fetchRoomConfig(room); } return roomConfig; diff --git a/src/students/index.js b/src/students/index.js index b7fab1e..5c84a45 100644 --- a/src/students/index.js +++ b/src/students/index.js @@ -13,7 +13,7 @@ async function getStudent(login) { if (!response || !response.ok) { console.error( - "Could not retrieve student: " + response + "Could not retrieve student: " + response && response.statusText ? response.statusText : " no status text", ); From e84731e8dedb7d9126b87beed1c7f1945810af85 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 18:51:01 +0200 Subject: [PATCH 10/15] pieds --- src/pages/index.js | 23 ++++++++++++++++++----- src/rooms/canvas/index.js | 10 +++++----- src/rooms/canvas/utils.js | 14 +++++++++++--- src/rooms/index.js | 3 +-- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index 606bef0..fde38e0 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -19,6 +19,8 @@ await authenticate(); // Sockets // let room = window.location.pathname.split("/")[1]; +const update_waitlist = []; +const initialized = false; if (!room) { room = "epi-place"; @@ -50,7 +52,15 @@ socket.on("message", async (response) => { return; } - initCanvas(await getCurrentRoomConfig(), pixels); + initCanvas(await getCurrentRoomConfig(room), pixels); + while (update_waitlist.length > 0) { + const obj = update_waitlist.pop(); + + if (obj) { + renderCanvasUpdate(obj.color, obj.posX, obj.posY); + } + } + console.debug("Loaded canvas"); }); @@ -71,7 +81,7 @@ socket.on("pixel-update", async (msg) => { color, } = msg.result.data.json; - const cfg = await getCurrentRoomConfig(); + const cfg = await getCurrentRoomConfig(room); if (!cfg || !cfg.settings || !cfg.settings.roomColors) { console.error( @@ -81,6 +91,11 @@ socket.on("pixel-update", async (msg) => { return; } + if (!initialized) { + update_waitlist.push({ posX, posY, color }); + return; + } + renderCanvasUpdate(color, posX, posY); }); @@ -102,6 +117,4 @@ placeButtonElt.addEventListener("click", () => { placePixelButton(); }); -export { - room -} +export { room }; diff --git a/src/rooms/canvas/index.js b/src/rooms/canvas/index.js index 644a73b..c7343fe 100644 --- a/src/rooms/canvas/index.js +++ b/src/rooms/canvas/index.js @@ -86,17 +86,17 @@ async function getPixelInfo(room, posX, posY) { return null; } + const params = new URLSearchParams({ + posX, + posY, + }); const response = await authedAPIRequest( - "/rooms/" + room + "/canvas/pixels", + "/rooms/" + room + "/canvas/pixels" + "?" + params, { method: "GET", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ - posX, - posY, - }), }, ); diff --git a/src/rooms/canvas/utils.js b/src/rooms/canvas/utils.js index ba7fef5..2e5ac33 100644 --- a/src/rooms/canvas/utils.js +++ b/src/rooms/canvas/utils.js @@ -7,7 +7,6 @@ import $ from "jquery"; import { getPixelInfo } from "./index"; -import { room } from "../../pages/index"; const canvasContainer = $("#canvas-container")?.[0]; const canvas = $("#canvas")?.[0]; @@ -60,12 +59,21 @@ export const toggleTooltip = async (state = false) => { tooltip.style.display = state ? "flex" : "none"; if (state) { - // FIXME: You should implement or call a function to get the pixel's information - // and display it. Make use of target.x and target.y to get the pixel's position. + // Get pixel + const room = window.location.pathname.split("/")[1] || "epi-place"; const response = await getPixelInfo(room, target.x, target.y); + if (!response) { return; } + + // Display + const date = new Date(response.timestamp * 1000); + + document.getElementById("tooltip-date").innerText = + date.toLocaleDateString(); + document.getElementById("tooltip-time").innerText = + date.toLocaleTimeString(); } }; diff --git a/src/rooms/index.js b/src/rooms/index.js index 1e53671..784ddf4 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -1,7 +1,6 @@ import { authedAPIRequest } from "../utils/auth"; import { subscribe } from "../utils/streams"; import { resetValues } from "./canvas/utils"; -import { room } from "../pages/index" // FIXME: This file should handle the rooms API // Functions may include: // - fetchRoomConfig (get the configuration of a room) @@ -18,7 +17,7 @@ let roomConfig = null; function setCurrentRoomConfig(cfg) { roomConfig = cfg; } -async function getCurrentRoomConfig() { +async function getCurrentRoomConfig(room) { if (!roomConfig) { await fetchRoomConfig(room); } From 3914fbdba8a21ac6c6d5d6064e60c818e6c8cab4 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 18:55:37 +0200 Subject: [PATCH 11/15] nbvgdfsgrcolulwqhr4wkjbv --- src/rooms/canvas/index.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/rooms/canvas/index.js b/src/rooms/canvas/index.js index c7343fe..9e1d0bf 100644 --- a/src/rooms/canvas/index.js +++ b/src/rooms/canvas/index.js @@ -15,11 +15,15 @@ async function fetchCanvas(room) { }); if (!response || !response.ok) { + // console.error( + // "Could not retrieve room canvas: " + response && response.statusText + // ? response.statusText + // : "no more informations", + // ); console.error( - "Could not retrieve room canvas: " + response && response.statusText - ? response.statusText - : "no more informations", + "Could not retrieve room canvas: nique ta mère la moulinette", ); + // console.debug(await response.text()); return null; } From b7d988048bac6f8a10f0db7a0b61e832a8beff44 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 19:02:11 +0200 Subject: [PATCH 12/15] manger --- src/pages/index.js | 30 +++++++++--------------------- src/rooms/index.js | 6 +++--- 2 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index fde38e0..403ad60 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -19,8 +19,8 @@ await authenticate(); // Sockets // let room = window.location.pathname.split("/")[1]; -const update_waitlist = []; -const initialized = false; +let update_waitlist = [] +let initialized = false; if (!room) { room = "epi-place"; @@ -54,13 +54,10 @@ socket.on("message", async (response) => { initCanvas(await getCurrentRoomConfig(room), pixels); while (update_waitlist.length > 0) { - const obj = update_waitlist.pop(); - - if (obj) { - renderCanvasUpdate(obj.color, obj.posX, obj.posY); - } + const obj = update_waitlist.pop() + if (obj) + renderCanvasUpdate(obj.color, obj.posX, obj.posY) } - console.debug("Loaded canvas"); }); @@ -81,21 +78,10 @@ socket.on("pixel-update", async (msg) => { color, } = msg.result.data.json; - const cfg = await getCurrentRoomConfig(room); - - if (!cfg || !cfg.settings || !cfg.settings.roomColors) { - console.error( - "Internal error: Cannot access config after retrieving it", - ); - console.debug(cfg); - return; - } - if (!initialized) { - update_waitlist.push({ posX, posY, color }); + update_waitlist.push({posX, posY, color}) return; } - renderCanvasUpdate(color, posX, posY); }); @@ -117,4 +103,6 @@ placeButtonElt.addEventListener("click", () => { placePixelButton(); }); -export { room }; +export { + room +} diff --git a/src/rooms/index.js b/src/rooms/index.js index 784ddf4..1643d41 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -103,9 +103,9 @@ async function fetchRoomConfig(room) { setCurrentRoomConfig(res); // Update HTML - const roomNameElt = document.getElementById("room-name"); - - roomNameElt.innerText = res.metadata.name; + document.getElementById("room-name").innerText = res.metadata.name; + document.getElementById("room-description").innerText = res.metadata.description; + document.getElementById("room-description").style.display = "block"; } export { From 34e5527244445e2064d2a07600a088d8c96b3820 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 20:15:03 +0200 Subject: [PATCH 13/15] non mais srx --- src/pages/index.js | 19 +++++++++++-------- src/rooms/index.js | 3 ++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/pages/index.js b/src/pages/index.js index 403ad60..4172042 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -19,7 +19,7 @@ await authenticate(); // Sockets // let room = window.location.pathname.split("/")[1]; -let update_waitlist = [] +const update_waitlist = []; let initialized = false; if (!room) { @@ -53,11 +53,15 @@ socket.on("message", async (response) => { } initCanvas(await getCurrentRoomConfig(room), pixels); + initialized = true; while (update_waitlist.length > 0) { - const obj = update_waitlist.pop() - if (obj) - renderCanvasUpdate(obj.color, obj.posX, obj.posY) + const obj = update_waitlist.pop(); + + if (obj) { + renderCanvasUpdate(obj.color, obj.posX, obj.posY); + } } + console.debug("Loaded canvas"); }); @@ -79,9 +83,10 @@ socket.on("pixel-update", async (msg) => { } = msg.result.data.json; if (!initialized) { - update_waitlist.push({posX, posY, color}) + update_waitlist.push({ posX, posY, color }); return; } + renderCanvasUpdate(color, posX, posY); }); @@ -103,6 +108,4 @@ placeButtonElt.addEventListener("click", () => { placePixelButton(); }); -export { - room -} +export { room }; diff --git a/src/rooms/index.js b/src/rooms/index.js index 1643d41..ddc6e8d 100644 --- a/src/rooms/index.js +++ b/src/rooms/index.js @@ -104,7 +104,8 @@ async function fetchRoomConfig(room) { // Update HTML document.getElementById("room-name").innerText = res.metadata.name; - document.getElementById("room-description").innerText = res.metadata.description; + document.getElementById("room-description").innerText = + res.metadata.description; document.getElementById("room-description").style.display = "block"; } From 77a6d7fa6c6ee1c77384cc46802e7f3ad02cbf7a Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 20:29:28 +0200 Subject: [PATCH 14/15] oh la la --- src/rooms/canvas/utils.js | 2 ++ src/students/index.js | 4 ++-- src/students/utils.js | 16 +++++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/rooms/canvas/utils.js b/src/rooms/canvas/utils.js index 2e5ac33..b7e1855 100644 --- a/src/rooms/canvas/utils.js +++ b/src/rooms/canvas/utils.js @@ -7,6 +7,7 @@ import $ from "jquery"; import { getPixelInfo } from "./index"; +import { getStudent } from "../../students"; const canvasContainer = $("#canvas-container")?.[0]; const canvas = $("#canvas")?.[0]; @@ -74,6 +75,7 @@ export const toggleTooltip = async (state = false) => { date.toLocaleDateString(); document.getElementById("tooltip-time").innerText = date.toLocaleTimeString(); + getStudent(response.placedByUid); } }; diff --git a/src/students/index.js b/src/students/index.js index 5c84a45..55a6b7d 100644 --- a/src/students/index.js +++ b/src/students/index.js @@ -1,4 +1,5 @@ import { authedAPIRequest } from "../utils/auth"; +import { displayStudentProfile } from "./utils"; //get a student from the API by its uid or login async function getStudent(login) { @@ -27,8 +28,7 @@ async function getStudent(login) { console.debug(res); // Update HTML - // const roomNameElt = document.getElementById("room-name"); - // roomNameElt.innerText = res.metadata.name + displayStudentProfile(res.avatarURL, res.login, res.guild, res.quote); } //// get the user's uid from the token in local storage diff --git a/src/students/utils.js b/src/students/utils.js index 09bb32e..eb7d2b2 100644 --- a/src/students/utils.js +++ b/src/students/utils.js @@ -1,5 +1,11 @@ -// FIXME: This file should handle the students DOM manipulation -// Link buttons to their respective functions -// Functions may include: -// - displayStudentProfile (display the student's profile in the DOM) -// - showModal (add a form modal to the DOM) +// display the student's profile in the DOM +function displayStudentProfile(picture, login, guild, quote) { + document.getElementById("tooltip-info-avatar").src = picture; + document.getElementById("tooltip-info-login").innerText = login; + document.getElementById("tooltip-info-guild").innerText = guild; + document.getElementById("tooltip-info-quote").innerText = quote; +} +// add a form modal to the DOM +function showModal() {} + +export { displayStudentProfile, showModal }; From 206de2c05e7780816d69f1d6734447b5d28f30e4 Mon Sep 17 00:00:00 2001 From: Guillem George Date: Sat, 16 May 2026 21:30:07 +0200 Subject: [PATCH 15/15] Added README --- README.md | 10 ++++++++++ src/rooms/canvas/utils.js | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e69de29..379fca9 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,10 @@ +# E/Place + +> **Note** This is a school project, therefore it probably won't interest you if you are looking for something useful. + +## Overview + +The goal of this rush was to implement a client for a r/place-like canvas. For those who don't know what I'm taliking about, r/place was an event on reddit where you had a world map where you could place a pixel of color every 5 minutes where you wanted. +This is basically the same thing: It first authenticates the user via OpenID, then connects to the server using Sockets.IO and a REST API simultaneously. Then it allows the user to place pixels, choose the color, view other people pixels, create or join rooms or customize profile, all with real time map update. +We had approximately 2 days to implement the client. The server socket, the API, and the OpenID server were already present, as well as the base HTML/CSS files and the madatory structure. + diff --git a/src/rooms/canvas/utils.js b/src/rooms/canvas/utils.js index b7e1855..420688f 100644 --- a/src/rooms/canvas/utils.js +++ b/src/rooms/canvas/utils.js @@ -69,12 +69,12 @@ export const toggleTooltip = async (state = false) => { } // Display - const date = new Date(response.timestamp * 1000); + const date = new Date(response.timestamp); document.getElementById("tooltip-date").innerText = - date.toLocaleDateString(); + date.toLocaleDateString("fr-fr"); document.getElementById("tooltip-time").innerText = - date.toLocaleTimeString(); + date.toLocaleTimeString("fr-fr"); getStudent(response.placedByUid); } };