// use sqlx::{pool::PoolConnection, prelude::*, query, query_as, SqliteConnection, SqlitePool}; // use tokio::stream::StreamExt; use tokio::task::spawn; use rusqlite::{params, Connection, Error as SqliteError}; use server_client::encapsulate; use fallible_iterator::FallibleIterator; use uuid::Uuid; use std::convert::TryInto; pub async fn start() -> DbClient { let mut server = DbServer::new(Db::new(Connection::open_in_memory().unwrap())); let mut client = server.connection(); spawn(async move { loop { server.tick(); tokio::task::yield_now().await } }); client.load_setup().await; client } pub struct Db { conn: Connection, } impl Db { fn new(conn: Connection) -> Self { Self { conn } } } // type LobbyId = (i32,); // FIXME: return Results intead of crashing #[encapsulate(pub async ordered)] impl Db { pub fn load_setup(&mut self) { self.conn.execute_batch(include_str!("setup.sql")).unwrap() } pub fn add_user(&mut self, name: String) -> Uuid { let uuid = Uuid::new_v4(); // println!("{:?}", uuid.as_bytes().to_vec()); self.conn .execute( "INSERT INTO Users(uuid, name) VALUES(?, ?)", params![uuid.as_bytes().to_vec(), name.to_string()], ) .unwrap(); // Server crashes if uuids collide uuid } // pub async fn users(&mut self) -> Vec { // query_as::<_, types::User>("SELECT UUID, Name FROM Users") // .fetch_all(&mut self.conn) // .await // .unwrap() // } 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.query(params![uuid.as_bytes().to_vec()]).and_then(|r|r.map(|r|r.get(0)).collect()).unwrap() } pub fn create_lobby(&mut self, public: bool) -> u32 { let id = rand::random(); log::info!("Created the lobby {}", id); self.conn .execute( "INSERT INTO Lobbies(id, public) VALUES(?, ?)", params![id as i32, public], ) .unwrap(); // Server crashes if ids collide id } pub fn join_lobby(&mut self, user: Uuid, lobby: u32) { self.conn .execute( "INSERT INTO UsersInLobbies(UserId, LobbyId) VALUES(?, ?)", params![user.as_bytes().to_vec(), lobby as i32], ) .unwrap(); // Server crashes if ids collide log::info!("{} joined the lobby {}", user, lobby); } pub fn leave_lobby(&mut self, user: Uuid) { log::info!("{} leaving the lobby", user); self.delete_vote(user); let v = self.get_lobby_for_user(user); self.conn .execute( "DELETE FROM UsersInLobbies WHERE UserId = ?", params![user.as_bytes().to_vec()], ) .unwrap(); if let Some(id) = v { let lines = self.conn.execute("DELETE FROM Lobbies WHERE 0 = (SELECT count(*) FROM UsersInLobbies WHERE LobbyID = ?)", params![id]).unwrap(); log::info!("Deleted {} lobbies ({})", lines, id as u32) } } pub fn disconnect(&mut self, user: Uuid) { // self.leave_lobby(user).await; log::info!("{} disconnecting", user); self.conn.execute( "DELETE FROM Users WHERE UUID = ?", params![user.as_bytes().to_vec()], ).unwrap(); // log::error!("Disconnect DB result{:?}", r); } pub fn get_lobby_for_user(&mut self, user: Uuid) -> Option { match self.conn.query_row( "SELECT LobbyID from UsersInLobbies WHERE UserID = ?", params![user.as_bytes().to_vec()], |r| r.get::<_ ,i32>(0).map(|x| x as u32), ) { Ok(v) => Ok(Some(v)), Err(e) => match e { SqliteError::QueryReturnedNoRows => Ok(None), e => Err(e), }, } .unwrap() } pub fn get_public_lobbies(&mut self) -> Vec { let mut prepared = self .conn .prepare("SELECT ID FROM Lobbies WHERE Public = TRUE").unwrap(); prepared.query(params![]).and_then(|r| r.map(|r| r.get::<_, i32>(0).map(|x| x as u32)).collect()).unwrap() } fn delete_vote(&mut self, user: Uuid) { self.conn.execute( "DELETE FROM Votes WHERE UserId = ?", params![user.as_bytes().to_vec()], ).unwrap(); } pub fn vote(&mut self, user: Uuid, game: u32) { self.delete_vote(user); self.conn.execute( "INSERT INTO Votes(UserID, GameID) VALUES(?, ?)", params![user.as_bytes().to_vec(), game as i32], ).unwrap(); } pub fn vote_ready(&mut self, user: Uuid) { self.delete_vote(user); self.conn.execute( "UPDATE Votes SET Ready = TRUE WHERE UserID = ?", params![user.as_bytes().to_vec()], ).unwrap(); } 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.query(params![lobby as i32]).and_then(|r| r.map(|r| r.try_into().map(|(s, n, b): (String, i32, bool)| (s, n as u32, b))).collect()).unwrap() } 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)", params![lobby as i32, lobby as i32], |r| r.get(0) ).unwrap() } 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(); } }