From 359603fbfe4e1405b0e98f1efa34768fc38805be Mon Sep 17 00:00:00 2001 From: pommicket Date: Fri, 9 Aug 2024 16:04:09 -0400 Subject: random featrued picture --- server/src/main.rs | 56 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 21 deletions(-) (limited to 'server/src') diff --git a/server/src/main.rs b/server/src/main.rs index 2693d5b..4e397f1 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -5,6 +5,7 @@ use std::net::SocketAddr; use std::sync::LazyLock; use tokio::io::AsyncWriteExt; use tungstenite::protocol::Message; +use std::io::prelude::*; const PUZZLE_ID_CHARSET: &[u8] = b"23456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"; const PUZZLE_ID_LEN: usize = 6; @@ -14,18 +15,19 @@ fn generate_puzzle_id() -> [u8; PUZZLE_ID_LEN] { [(); 6].map(|()| PUZZLE_ID_CHARSET[rng.gen_range(0..PUZZLE_ID_CHARSET.len())]) } -struct Database { +struct Server { puzzles: sled::Tree, pieces: sled::Tree, connectivity: sled::Tree, + wikimedia_featured: Vec, } -fn get_puzzle_info(database: &Database, id: &[u8]) -> anyhow::Result> { +fn get_puzzle_info(server: &Server, id: &[u8]) -> anyhow::Result> { if id.len() != PUZZLE_ID_LEN { return Err(anyhow!("bad puzzle ID")); } let mut data = vec![1, 0, 0, 0, 0, 0, 0, 0]; // opcode + padding - let puzzle = database + let puzzle = server .puzzles .get(id)? .ok_or_else(|| anyhow!("bad puzzle ID"))?; @@ -34,12 +36,12 @@ fn get_puzzle_info(database: &Database, id: &[u8]) -> anyhow::Result> { // padding data.push(0); } - let pieces = database + let pieces = server .pieces .get(id)? .ok_or_else(|| anyhow!("bad puzzle ID"))?; data.extend_from_slice(&pieces); - let connectivity = database + let connectivity = server .connectivity .get(id)? .ok_or_else(|| anyhow!("bad puzzle ID"))?; @@ -48,7 +50,7 @@ fn get_puzzle_info(database: &Database, id: &[u8]) -> anyhow::Result> { } async fn handle_connection( - database: &Database, + server: &Server, conn: &mut tokio::net::TcpStream, ) -> anyhow::Result<()> { let mut ws = tokio_tungstenite::accept_async_with_config( @@ -98,7 +100,7 @@ async fn handle_connection( loop { id = generate_puzzle_id(); let data = std::mem::take(&mut puzzle_data); - if database + if server .puzzles .compare_and_swap(id, None::<&'static [u8; 0]>, Some(&data[..]))? .is_ok() @@ -124,7 +126,7 @@ async fn handle_connection( *it.next().unwrap() = d; } } - database.pieces.insert(id, pieces_data)?; + server.pieces.insert(id, pieces_data)?; let mut connectivity_data = Vec::new(); connectivity_data.resize((width as usize) * (height as usize) * 2, 0); let mut it = connectivity_data.iter_mut(); @@ -133,15 +135,15 @@ async fn handle_connection( *it.next().unwrap() = a; *it.next().unwrap() = b; } - database.connectivity.insert(id, connectivity_data)?; + server.connectivity.insert(id, connectivity_data)?; ws.send(Message::Text(format!("id: {}", std::str::from_utf8(&id)?))) .await?; - let info = get_puzzle_info(&database, &id)?; + let info = get_puzzle_info(&server, &id)?; ws.send(Message::Binary(info)).await?; } else if let Some(id) = text.strip_prefix("join ") { let id = id.as_bytes().try_into()?; puzzle_id = Some(id); - let info = get_puzzle_info(&database, &id)?; + let info = get_puzzle_info(&server, &id)?; ws.send(Message::Binary(info)).await?; } else if text.starts_with("move ") { let puzzle_id = puzzle_id.ok_or_else(|| anyhow!("move without puzzle ID"))?; @@ -162,7 +164,7 @@ async fn handle_connection( motions.push(Motion { piece, x, y }); } loop { - let curr_pieces = database + let curr_pieces = server .pieces .get(&puzzle_id)? .ok_or_else(|| anyhow!("bad puzzle ID"))?; @@ -177,7 +179,7 @@ async fn handle_connection( .ok_or_else(|| anyhow!("bad piece ID"))? .copy_from_slice(&y.to_le_bytes()); } - if database + if server .pieces .compare_and_swap(&puzzle_id, Some(curr_pieces), Some(new_pieces))? .is_ok() @@ -193,7 +195,7 @@ async fn handle_connection( let piece1: usize = parts.next().ok_or_else(|| anyhow!("bad syntax"))?.parse()?; let piece2: usize = parts.next().ok_or_else(|| anyhow!("bad syntax"))?.parse()?; loop { - let curr_connectivity = database + let curr_connectivity = server .connectivity .get(&puzzle_id)? .ok_or_else(|| anyhow!("bad puzzle ID"))?; @@ -219,7 +221,7 @@ async fn handle_connection( new_connectivity[piece * 2 + 1] = b; } } - if database + if server .connectivity .compare_and_swap( &puzzle_id, @@ -234,11 +236,11 @@ async fn handle_connection( } } else if text == "poll" { let puzzle_id = puzzle_id.ok_or_else(|| anyhow!("poll without puzzle ID"))?; - let pieces = database + let pieces = server .pieces .get(&puzzle_id)? .ok_or_else(|| anyhow!("bad puzzle ID"))?; - let connectivity = database + let connectivity = server .connectivity .get(&puzzle_id)? .ok_or_else(|| anyhow!("bad puzzle ID"))?; @@ -246,12 +248,22 @@ async fn handle_connection( data.extend_from_slice(&pieces); data.extend_from_slice(&connectivity); ws.send(Message::Binary(data)).await?; + } else if text == "randomFeaturedWikimedia" { + let choice = rand::thread_rng().gen_range(0..server.wikimedia_featured.len()); + ws.send(Message::Text(format!("wikimediaImage {}", server.wikimedia_featured[choice]))).await?; } } } Ok(()) } + +fn read_to_lines(path: &str) -> std::io::Result> { + let file = std::fs::File::open(path)?; + let reader = std::io::BufReader::new(file); + reader.lines().collect() +} + #[tokio::main] async fn main() { let port = 3000; @@ -269,20 +281,22 @@ async fn main() { tokio::time::sleep(std::time::Duration::from_secs(3600)).await; } }); - static DATABASE_VALUE: LazyLock = LazyLock::new(|| { + static SERVER_VALUE: LazyLock = LazyLock::new(|| { + let wikimedia_featured = read_to_lines("featuredpictures.txt").expect("Couldn't read featuredpictures.txt"); let db = sled::open("database.sled").expect("error opening database"); let puzzles = db.open_tree("PUZZLES").expect("error opening puzzles tree"); let pieces = db.open_tree("PIECES").expect("error opening pieces tree"); let connectivity = db .open_tree("CONNECTIVITY") .expect("error opening connectivity tree"); - Database { + Server { puzzles, pieces, connectivity, + wikimedia_featured, } }); - let database: &Database = &DATABASE_VALUE; + let server: &Server = &SERVER_VALUE; loop { let (mut stream, addr) = match listener.accept().await { Ok(result) => result, @@ -292,7 +306,7 @@ async fn main() { } }; tokio::task::spawn(async move { - match handle_connection(database, &mut stream).await { + match handle_connection(server, &mut stream).await { Ok(()) => {} Err(e) => { eprintln!("Error handling connection to {addr}: {e}"); -- cgit v1.2.3