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.
 
 
 
 
 

244 lines
7.2 KiB

// use sqlx::{pool::PoolConnection, prelude::*, query, query_as, SqliteConnection, SqlitePool};
// use tokio::stream::StreamExt;
use anyhow::Result;
use fallible_iterator::FallibleIterator;
use rusqlite::{params, Connection, Error as SqliteError, ErrorCode};
use server_client::encapsulate;
use tokio::task::spawn;
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().await;
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,);
#[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) -> Result<Uuid> {
loop {
let uuid = Uuid::new_v4();
// println!("{:?}", uuid.as_bytes().to_vec());
let res = self.conn.execute(
"INSERT INTO Users(uuid, name) VALUES(?, ?)",
params![uuid.as_bytes().to_vec(), name.to_string()],
); // Server crashes if uuids collide
if let Err(e) = res {
match e {
SqliteError::SqliteFailure(
rusqlite::ffi::Error {
code: ErrorCode::ConstraintViolation,
extended_code: _,
},
_,
) => {
log::error!("add_user db error (constraint violation): {}", e);
return Err(e.into());
}
e => {
log::error!("add_user db error: {}", e);
return Err(e.into());
}
}
}
return Ok(uuid);
}
}
// FIXME: return Results intead of crashing
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()
}
// FIXME: return Results intead of crashing
pub fn get_uuids_in_lobby_where_user_is(&mut self, uuid: Uuid) -> Vec<Uuid> {
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
.query(params![uuid.as_bytes().to_vec()])
.and_then(|r| {
r.map(|r| r.get::<_, Vec<u8>>(0))
.map(|x| Ok(Uuid::from_slice(&x).unwrap()))
.collect()
})
.unwrap()
}
// FIXME: return Results intead of crashing
pub fn get_name_for_uuid(&mut self, uuid: Uuid) -> String {
let mut prepared = self
.conn
.prepare_cached("SELECT Name FROM Users WHERE UUID = ?")
.unwrap();
prepared
.query(params![uuid.as_bytes().to_vec()])
.and_then(|mut r| r.next().and_then(|r| r.unwrap().get::<_, String>(0)))
.unwrap()
}
// FIXME: return Results intead of crashing
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
}
// FIXME: return Results intead of crashing
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);
}
// FIXME: return Results intead of crashing
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)
}
}
// FIXME: return Results intead of crashing
pub fn disconnect(&mut self, user: Uuid) {
self.leave_lobby(user);
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);
}
// FIXME: return Results intead of crashing
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()
}
// FIXME: return Results intead of crashing
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()
}
// FIXME: return Results intead of crashing
fn delete_vote(&mut self, user: Uuid) {
self.conn
.execute(
"DELETE FROM Votes WHERE UserId = ?",
params![user.as_bytes().to_vec()],
)
.unwrap();
}
// FIXME: return Results intead of crashing
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();
}
// FIXME: return Results intead of crashing
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();
}
// 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
.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()
}
// 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)",
params![lobby as i32, lobby as i32],
|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();
}
}