You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

180 lines
6.2 KiB

// 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<types::User> {
// 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<String> {
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<u32> {
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<u32> {
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();
}
}