diff --git a/server/Cargo.toml b/server/Cargo.toml index 091af1a..6c1ec90 100644 --- a/server/Cargo.toml +++ b/server/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" rand = "0.8" image = "0.23" uuid = {version = "0.8", features = ["v4", "serde"]} +futures = "0.3" tokio = {version = "1", features = ["full"]} tokio-stream = "0.1" server_client = {git = "https://github.com/Mr-Llama-s-Wonderful-Soundboard/server_client.git", branch = "main", features = ["tokio1"]} diff --git a/server/src/db.rs b/server/src/db.rs index 07eb8a1..045a828 100644 --- a/server/src/db.rs +++ b/server/src/db.rs @@ -70,7 +70,7 @@ impl Db { Ok(uuid) } - // FIXME: return Results intead of crashing + pub fn get_users_in_lobby_where_user_is(&mut self, uuid: Uuid) -> Vec { let mut prepared = self.conn.prepare_cached("SELECT Name FROM Users WHERE UUID in (SELECT UserId FROM UsersInLobbies WHERE LobbyId = (SELECT LobbyId FROM UsersInLobbies WHERE UserId = ?))").unwrap(); prepared @@ -79,7 +79,7 @@ impl Db { .unwrap() } - // FIXME: return Results intead of crashing + pub fn get_uuids_in_lobby_where_user_is(&mut self, uuid: Uuid) -> Vec { let mut prepared = self.conn.prepare_cached("SELECT UUID FROM Users WHERE UUID in (SELECT UserId FROM UsersInLobbies WHERE LobbyId = (SELECT LobbyId FROM UsersInLobbies WHERE UserId = ?))").unwrap(); prepared @@ -92,7 +92,7 @@ impl Db { .unwrap() } - // FIXME: return Results intead of crashing + pub fn get_name_for_uuid(&mut self, uuid: Uuid) -> String { let mut prepared = self .conn @@ -104,7 +104,7 @@ impl Db { .unwrap() } - // FIXME: return Results intead of crashing + pub fn create_lobby(&mut self, public: bool) -> u32 { let id = rand::random(); @@ -117,7 +117,7 @@ impl Db { .unwrap(); // Server crashes if ids collide id } - // FIXME: return Results intead of crashing + pub fn join_lobby(&mut self, user: Uuid, lobby: u32) { self.conn .execute( @@ -127,7 +127,8 @@ impl Db { .unwrap(); // Server crashes if ids collide log::info!("{} joined the lobby {}", user, lobby); } - // FIXME: return Results intead of crashing + + pub fn leave_lobby(&mut self, user: Uuid) { log::info!("{} leaving the lobby", user); self.delete_vote(user); @@ -144,7 +145,8 @@ impl Db { log::info!("Deleted {} lobbies ({})", lines, id as u32) } } - // FIXME: return Results intead of crashing + + pub fn disconnect(&mut self, user: Uuid) { self.leave_lobby(user); log::info!("{} disconnecting", user); @@ -157,7 +159,8 @@ impl Db { // log::error!("Disconnect DB result{:?}", r); } - // FIXME: return Results intead of crashing + + pub fn get_lobby_for_user(&mut self, user: Uuid) -> Option { match self.conn.query_row( "SELECT LobbyID from UsersInLobbies WHERE UserID = ?", @@ -172,7 +175,7 @@ impl Db { } .unwrap() } - // FIXME: return Results intead of crashing + pub fn get_public_lobbies(&mut self) -> Vec { let mut prepared = self .conn @@ -183,7 +186,8 @@ impl Db { .and_then(|r| r.map(|r| r.get::<_, i32>(0).map(|x| x as u32)).collect()) .unwrap() } - // FIXME: return Results intead of crashing + + fn delete_vote(&mut self, user: Uuid) { self.conn .execute( @@ -192,7 +196,8 @@ impl Db { ) .unwrap(); } - // FIXME: return Results intead of crashing + + pub fn vote(&mut self, user: Uuid, game: u32) { self.delete_vote(user); self.conn @@ -202,7 +207,8 @@ impl Db { ) .unwrap(); } - // FIXME: return Results intead of crashing + + pub fn vote_ready(&mut self, user: Uuid) { // self.delete_vote(user); self.conn @@ -212,7 +218,8 @@ impl Db { ) .unwrap(); } - // FIXME: return Results intead of crashing + + pub fn get_votes(&mut self, lobby: u32) -> Vec<(String, u32, bool)> { let mut prepared = self.conn.prepare_cached("SELECT Users.Name, Votes.GameID, Votes.Ready FROM Votes JOIN Users ON Users.UUID = Votes.UserID WHERE Votes.UserID IN (SELECT UserID FROM UsersInLobbies WHERE LobbyID = ?)").unwrap(); prepared @@ -226,7 +233,8 @@ impl Db { }) .unwrap() } - // FIXME: return Results intead of crashing + + pub fn is_poll_finished(&mut self, lobby: u32) -> bool { self.conn.query_row( "SELECT (SELECT COUNT(*) FROM UsersInLobbies where LobbyID = ?) = (SELECT COUNT(*) FROM Votes WHERE UserID IN (SELECT UserID FROM UsersInLobbies WHERE LobbyID = ?) AND Ready = TRUE)", @@ -234,7 +242,8 @@ impl Db { |r| r.get(0) ).unwrap() } - // FIXME: return Results intead of crashing + + pub fn delete_votes(&mut self, lobby: u32) { self.conn .execute("DELETE FROM Votes WHERE UserId IN (SELECT UserID FROM UsersInLobbies WHERE LobbyID = ?)", params![lobby as i32]).unwrap(); diff --git a/server/src/games/config.rs b/server/src/games/config.rs index 8f24610..7a952ae 100644 --- a/server/src/games/config.rs +++ b/server/src/games/config.rs @@ -1,8 +1,10 @@ +use futures::stream::FuturesUnordered; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::io::Write; use std::path::PathBuf; use std::{collections::HashMap, fs::File, io::ErrorKind, path::Path}; +use tokio_stream::StreamExt; #[derive(Serialize, Deserialize, JsonSchema, Debug, Clone)] pub struct Config { @@ -71,11 +73,14 @@ impl Config { } fn start_image_caching(&self, folder: PathBuf) { - // TODO Add checks to say if it has finished + let mut join_handles = FuturesUnordered::new(); if let Some(p) = &self.default_back { let p = p.clone(); let folder = folder.clone(); - tokio::task::spawn_blocking(|| cache_image(p, folder)); + join_handles.push(tokio::task::spawn_blocking(|| { + cache_image(&p, folder); + p + })); } for Card { image, @@ -86,14 +91,31 @@ impl Config { { let folder = folder.clone(); let p = image.clone(); - tokio::task::spawn_blocking(|| cache_image(p, folder)); + join_handles.push(tokio::task::spawn_blocking(|| { + cache_image(&p, folder); + p + })); }; if let Some(back_image) = back_image { let p = back_image.clone(); let folder = folder.clone(); - tokio::task::spawn_blocking(|| cache_image(p, folder)); + join_handles.push(tokio::task::spawn_blocking(|| { + cache_image(&p, folder); + p + })); } } + tokio::spawn(async move { + let l = join_handles.len(); + let mut i = 1; + while let Some(r) = join_handles.next().await { + match r { + Ok(p) => log::info!("[{}/{}] Image {} cached!", i, l, p.display()), + Err(e) => log::error!("[{}/{}] Error chaching image: {}", i, l, e), + } + i += 1; + } + }); } pub fn reload_cache(&self, folder: PathBuf) { diff --git a/server/src/games/run/engine.rs b/server/src/games/run/engine.rs index df9a581..df90957 100644 --- a/server/src/games/run/engine.rs +++ b/server/src/games/run/engine.rs @@ -100,6 +100,16 @@ fn get_card_from_id(data: &mut Map, card: CardId) -> Result) -> std::fmt::Result { + write!(f, "RhaiError") + } +} + +impl std::error::Error for RhaiError {} fn pop_card_from_id(data_dyn: &mut Map, card: CardId) -> Result> { let mut dynamic: Dynamic = >::from(data_dyn.clone()); @@ -111,14 +121,29 @@ fn pop_card_from_id(data_dyn: &mut Map, card: CardId) -> Result to_dynamic(&pile.cards.remove(0)), + super::CardIdx::Top => { + if pile.cards.is_empty() { + return Err(Box::new(rhai::EvalAltResult::ErrorSystem( + "Tried to remove the top card from an empty pile".into(), + Box::new(RhaiError), + ))); + } + to_dynamic(&pile.cards.remove(0)) + } super::CardIdx::Bottom => pile .cards .pop() .map(to_dynamic) .unwrap_or_else(|| Ok(Dynamic::default())), - super::CardIdx::Indexed(i) => to_dynamic(&pile.cards.remove(i)), + super::CardIdx::Indexed(i) => { + if pile.cards.len() <= i { + return Err(Box::new(rhai::EvalAltResult::ErrorSystem( + "Tried to remove a card from a pile smaller than the index".into(), + Box::new(RhaiError), + ))); + } + to_dynamic(&pile.cards.remove(i)) + } }; dynamic = to_dynamic(&data)?; *data_dyn = dynamic.cast();