From 24564afb32d2fd65c3d39d1114764bda831d1563 Mon Sep 17 00:00:00 2001 From: pommicket Date: Sat, 10 Aug 2024 20:37:29 -0400 Subject: delete old puzzles --- TODO.txt | 1 + game.js | 11 ++++++++--- server/src/main.rs | 39 +++++++++++++++++++++++++++++++-------- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/TODO.txt b/TODO.txt index b329a91..2379e47 100644 --- a/TODO.txt +++ b/TODO.txt @@ -2,3 +2,4 @@ - limit number of playres connected to a game (prevent contention) - congratualations - link to source image +- handle server errors on the client side diff --git a/game.js b/game.js index 6c3309b..77789b5 100644 --- a/game.js +++ b/game.js @@ -362,7 +362,7 @@ window.addEventListener('load', function () { console.assert(puzzleWidth === data[8]); console.assert(puzzleHeight === data[9]); } - const nibTypesOffset = 10; + const nibTypesOffset = 10 + 8 /* timestamp - not relevant to us */; const nibTypeCount = 2 * puzzleWidth * puzzleHeight - puzzleWidth - puzzleHeight; const nibTypes = new Uint16Array(payload, nibTypesOffset, nibTypeCount); const imageUrlOffset = nibTypesOffset + nibTypeCount * 2; @@ -378,8 +378,13 @@ window.addEventListener('load', function () { await loadImage(); } let nibTypeIndex = 0; - pieceWidth = 0.5 * playArea.clientWidth / puzzleWidth; - pieceHeight = pieceWidth * puzzleWidth * image.height / (puzzleHeight * image.width); + if (playArea.clientWidth / puzzleWidth < playArea.clientHeight / puzzleHeight) { + pieceWidth = 0.5 * playArea.clientWidth / puzzleWidth; + pieceHeight = pieceWidth * (puzzleWidth / puzzleHeight) * (image.height / image.width); + } else { + pieceHeight = 0.5 * playArea.clientHeight / puzzleHeight; + pieceWidth = pieceHeight * (puzzleHeight / puzzleWidth) * (image.width / image.height); + } nibSize = Math.min(pieceWidth / 4, pieceHeight / 4); document.body.style.setProperty('--piece-width', (pieceWidth) + 'px'); document.body.style.setProperty('--piece-height', (pieceHeight) + 'px'); diff --git a/server/src/main.rs b/server/src/main.rs index d6d85d3..1e734b9 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,18 +1,20 @@ use anyhow::anyhow; use futures_util::{SinkExt, StreamExt}; use rand::Rng; +use rand::seq::SliceRandom; use std::io::prelude::*; use std::net::SocketAddr; use std::sync::LazyLock; use tokio::io::AsyncWriteExt; use tungstenite::protocol::Message; +use std::time::{SystemTime, Duration}; const PUZZLE_ID_CHARSET: &[u8] = b"23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; -const PUZZLE_ID_LEN: usize = 6; +const PUZZLE_ID_LEN: usize = 7; fn generate_puzzle_id() -> [u8; PUZZLE_ID_LEN] { let mut rng = rand::thread_rng(); - [(); 6].map(|()| PUZZLE_ID_CHARSET[rng.gen_range(0..PUZZLE_ID_CHARSET.len())]) + [(); 7].map(|()| *PUZZLE_ID_CHARSET.choose(&mut rng).unwrap()) } struct Server { @@ -82,6 +84,10 @@ async fn handle_connection( return Err(anyhow!("too many pieces")); } let mut puzzle_data = vec![width, height]; + let timestamp: u64 = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).expect("time went backwards :/").as_secs(); + for byte in timestamp.to_le_bytes() { + puzzle_data.push(byte); + } // pick nib types { let mut rng = rand::thread_rng(); @@ -278,12 +284,6 @@ async fn main() { return; } }; - tokio::task::spawn(async { - loop { - // TODO : sweep - tokio::time::sleep(std::time::Duration::from_secs(3600)).await; - } - }); static SERVER_VALUE: LazyLock = LazyLock::new(|| { let wikimedia_featured = read_to_lines("featuredpictures.txt").expect("Couldn't read featuredpictures.txt"); @@ -301,6 +301,29 @@ async fn main() { } }); let server: &Server = &SERVER_VALUE; + tokio::task::spawn(async { + loop { + // TODO : sweep + let now = SystemTime::now(); + let mut to_delete = vec![]; + for item in server.puzzles.iter() { + let (key, value) = item.expect("sweep failed to read database"); + let timestamp: [u8; 8] = value[2..2 + 8].try_into().unwrap(); + let timestamp = SystemTime::UNIX_EPOCH + Duration::from_secs(u64::from_le_bytes(timestamp)); + if now.duration_since(timestamp).unwrap_or_default() >= Duration::from_secs(60 * 60 * 24 * 7) { + // delete puzzles created at least 1 week ago + to_delete.push(key); + } + } + for key in to_delete { + // technically there is a race condition here but stop being silly + server.puzzles.remove(&key).expect("sweep failed to delete entry"); + server.pieces.remove(&key).expect("sweep failed to delete entry"); + server.connectivity.remove(&key).expect("sweep failed to delete entry"); + } + tokio::time::sleep(std::time::Duration::from_secs(3600)).await; + } + }); loop { let (mut stream, addr) = match listener.accept().await { Ok(result) => result, -- cgit v1.2.3