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
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();
|
|
}
|
|
}
|
|
|