Add rate limiting, improve memory usage
This commit is contained in:
@@ -1,11 +1,18 @@
|
||||
import socket from "./socket.js";
|
||||
import {
|
||||
hexToU32,
|
||||
u32ToHex,
|
||||
getColorFromElementCSS,
|
||||
rgbToHex,
|
||||
} from "./utils.js";
|
||||
import { pixelSize, pixelCooldown } from "./constants.js";
|
||||
import {
|
||||
pixelSize,
|
||||
pixelCooldown,
|
||||
canvasEndpoint,
|
||||
WIDTH,
|
||||
HEIGHT,
|
||||
} from "./constants.js";
|
||||
|
||||
let socket = null;
|
||||
|
||||
const canvas = document.getElementById("canvas");
|
||||
const ctx = canvas.getContext("2d");
|
||||
@@ -97,37 +104,29 @@ const handleColorPicker = () => {
|
||||
});
|
||||
};
|
||||
|
||||
handleColorPicker();
|
||||
const fetchCanvasState = async () => {
|
||||
fetch(canvasEndpoint)
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
canvasState = data;
|
||||
drawCanvasState(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
alert("Error fetching canvas state from server. Please try again later.");
|
||||
});
|
||||
};
|
||||
|
||||
const drawCanvasState = (canvasState) => {
|
||||
for (let y = 0; y < canvasState.length; y++) {
|
||||
for (let x = 0; x < canvasState[y].length; x++) {
|
||||
const color = u32ToHex(canvasState[y][x]);
|
||||
for (let y = 0; y < HEIGHT; y++) {
|
||||
for (let x = 0; x < WIDTH; x++) {
|
||||
const index = y * WIDTH + x;
|
||||
const color = u32ToHex(canvasState[index]);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
socket.on("init-canvas", (data) => {
|
||||
const canvasData = JSON.parse(data);
|
||||
drawCanvasState(canvasData);
|
||||
canvasState = canvasData;
|
||||
});
|
||||
|
||||
socket.on("pixel-updated", (update) => {
|
||||
const color = u32ToHex(update.color);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(
|
||||
update.x * pixelSize,
|
||||
update.y * pixelSize,
|
||||
pixelSize,
|
||||
pixelSize
|
||||
);
|
||||
|
||||
canvasState[update.y][update.x] = update.color;
|
||||
});
|
||||
|
||||
const checkIfCanPlacePixel = () => {
|
||||
const now = Date.now();
|
||||
return now - lastPixelTime >= pixelCooldown;
|
||||
@@ -145,7 +144,8 @@ const handlePlacePixel = (pixelData) => {
|
||||
}
|
||||
|
||||
socket.emit("place-pixel", pixelData);
|
||||
canvasState[pixelData.y][pixelData.x] = pixelData.color;
|
||||
const index = pixelData.y * WIDTH + pixelData.x;
|
||||
canvasState[index] = pixelData.color;
|
||||
setLastPixelTime();
|
||||
pixelData = null;
|
||||
};
|
||||
@@ -218,8 +218,6 @@ const handleToggleGrid = () => {
|
||||
});
|
||||
};
|
||||
|
||||
handleToggleGrid();
|
||||
|
||||
window.onkeydown = (event) => {
|
||||
// on enter (keycode 13 is enter)
|
||||
if (event.keyCode === 13) {
|
||||
@@ -243,3 +241,27 @@ saveCanvasButton.addEventListener("click", () => {
|
||||
a.download = "canvas.png";
|
||||
a.click();
|
||||
});
|
||||
|
||||
handleColorPicker();
|
||||
handleToggleGrid();
|
||||
|
||||
export const handleSocketEvents = (_socket) => {
|
||||
socket = _socket;
|
||||
socket.on("connect", () => {
|
||||
fetchCanvasState();
|
||||
});
|
||||
|
||||
socket.on("pixel-updated", (update) => {
|
||||
const color = u32ToHex(update.color);
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(
|
||||
update.x * pixelSize,
|
||||
update.y * pixelSize,
|
||||
pixelSize,
|
||||
pixelSize
|
||||
);
|
||||
|
||||
const index = update.y * WIDTH + update.x;
|
||||
canvasState[index] = update.color;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
export const pixelSize = 10;
|
||||
export const pixelCooldown = 60 * 1000; // 1 minute
|
||||
export const pixelCooldown = 10 * 1000; // 10 seconds
|
||||
export const canvasEndpoint = "http://localhost:3000/canvas/";
|
||||
export const checkEndpoint = "http://localhost:3000/check/";
|
||||
export const WIDTH = 500;
|
||||
export const HEIGHT = 500;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import socket from "./socket.js";
|
||||
import { connectToWS } from "./socket.js";
|
||||
import "./canvas.js";
|
||||
import "./counter.js";
|
||||
import { updateCountdown } from "./counter.js";
|
||||
import { pixelSize } from "./constants.js";
|
||||
import { checkEndpoint, pixelSize } from "./constants.js";
|
||||
import { handleSocketEvents } from "./canvas.js";
|
||||
|
||||
const isDebug = import.meta.env.VITE_IS_DEBUG === "true";
|
||||
|
||||
@@ -11,27 +12,46 @@ const currentSoldiersSpan = document.getElementById("current-soldiers");
|
||||
let coords = [];
|
||||
const canvas = document.getElementById("canvas");
|
||||
const coordsText = document.getElementById("coords");
|
||||
const ogCanvasStyle = canvas.style.display;
|
||||
canvas.style.display = "none";
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log("connect");
|
||||
});
|
||||
fetch(checkEndpoint)
|
||||
.then((response) => {
|
||||
if (response.ok) {
|
||||
const socket = connectToWS();
|
||||
|
||||
socket.on("error", (message) => {
|
||||
alert(message);
|
||||
});
|
||||
socket.on("connect", () => {
|
||||
canvas.style.display = ogCanvasStyle;
|
||||
console.log("connect");
|
||||
});
|
||||
|
||||
socket.on("current_soldiers", (currentSoldiers) => {
|
||||
currentSoldiersSpan.textContent = currentSoldiers;
|
||||
});
|
||||
socket.on("error", (message) => {
|
||||
alert(message);
|
||||
});
|
||||
|
||||
requestAnimationFrame(updateCountdown);
|
||||
socket.on("current_soldiers", (currentSoldiers) => {
|
||||
currentSoldiersSpan.textContent = currentSoldiers;
|
||||
});
|
||||
|
||||
window.addEventListener("mousemove", (event) => {
|
||||
// get coordinates of the mouse inside the canvas
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const x = Math.floor((event.clientX - rect.left) / pixelSize);
|
||||
const y = Math.floor((event.clientY - rect.top) / pixelSize);
|
||||
coords = [x, y];
|
||||
handleSocketEvents(socket);
|
||||
|
||||
coordsText.textContent = `${x}, ${y}`;
|
||||
});
|
||||
requestAnimationFrame(updateCountdown);
|
||||
|
||||
window.addEventListener("mousemove", (event) => {
|
||||
// get coordinates of the mouse inside the canvas
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
const x = Math.floor((event.clientX - rect.left) / pixelSize);
|
||||
const y = Math.floor((event.clientY - rect.top) / pixelSize);
|
||||
coords = [x, y];
|
||||
|
||||
coordsText.textContent = `${x}, ${y}`;
|
||||
});
|
||||
} else {
|
||||
throw new Error("Can't connect to the server");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
alert(
|
||||
"You have already connected to the server from another tab or window. Please close the other tab or window and refresh this page."
|
||||
);
|
||||
});
|
||||
|
||||
@@ -6,12 +6,16 @@ const wsHost = window.location.host;
|
||||
|
||||
let socket;
|
||||
|
||||
if (isDebug) {
|
||||
socket = io("ws://localhost:3000");
|
||||
} else {
|
||||
socket = io(`${wsProtocol}//${wsHost}`, {
|
||||
transports: ["websocket"],
|
||||
});
|
||||
}
|
||||
export const connectToWS = () => {
|
||||
if (isDebug) {
|
||||
socket = io("ws://localhost:3000");
|
||||
} else {
|
||||
socket = io(`${wsProtocol}//${wsHost}`, {
|
||||
transports: ["websocket"],
|
||||
});
|
||||
}
|
||||
|
||||
return socket;
|
||||
};
|
||||
|
||||
export default socket;
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
.rainbow-border {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
border-radius: 0.5rem; /* Rounded corners */
|
||||
padding: 5px; /* Space for the border */
|
||||
background: linear-gradient(to right, red, orange, yellow, green, blue, indigo, violet);
|
||||
}
|
||||
.rainbow-border::before {
|
||||
@@ -17,8 +15,6 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: -5px; /* Negative margin to overlap the gradient */
|
||||
border-radius: 0.5rem; /* Match the rounded corners */
|
||||
background: white;
|
||||
z-index: -1; /* Place behind the content */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user