Browse Source

Add better panic & error handling

new_protocol
ThePerkinrex 5 years ago
parent
commit
4bf1f9c0f7
No known key found for this signature in database GPG Key ID: 1F45A7C4BFB41607
  1. 124
      server/src/db.rs
  2. 19
      server/src/logger.rs
  3. 1
      server/src/main.rs
  4. 2
      server/src/server/connection.rs

124
server/src/db.rs

@ -1,10 +1,11 @@
// 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 rusqlite::{params, Connection, Error as SqliteError, ErrorCode};
use server_client::encapsulate;
use tokio::task::spawn;
use tonic::Status;
use uuid::Uuid;
use std::convert::TryInto;
@ -22,6 +23,8 @@ pub async fn start() -> DbClient {
client
}
type Result<T> = std::result::Result<T, Status>;
pub struct Db {
conn: Connection,
}
@ -33,37 +36,53 @@ impl Db {
}
// 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 {
pub fn add_user(&mut self, name: String) -> Result<Uuid> {
loop {
let uuid = Uuid::new_v4();
// println!("{:?}", uuid.as_bytes().to_vec());
self.conn
.execute(
let res = 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
); // 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(Status::internal(e.to_string()));
}
e => {
log::error!("add_user db error: {}", e);
return Err(Status::internal(e.to_string()));
}
}
}
// 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()
// }
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()
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 create_lobby(&mut self, public: bool) -> u32 {
let id = rand::random();
@ -76,7 +95,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(
@ -86,7 +105,7 @@ 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);
@ -103,23 +122,25 @@ 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).await;
log::info!("{} disconnecting", user);
self.conn.execute(
self.conn
.execute(
"DELETE FROM Users WHERE UUID = ?",
params![user.as_bytes().to_vec()],
).unwrap();
)
.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),
|r| r.get::<_, i32>(0).map(|x| x as u32),
) {
Ok(v) => Ok(Some(v)),
Err(e) => match e {
@ -129,42 +150,61 @@ impl Db {
}
.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()
.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(
self.conn
.execute(
"DELETE FROM Votes WHERE UserId = ?",
params![user.as_bytes().to_vec()],
).unwrap();
)
.unwrap();
}
// FIXME: return Results intead of crashing
pub fn vote(&mut self, user: Uuid, game: u32) {
self.delete_vote(user);
self.conn.execute(
self.conn
.execute(
"INSERT INTO Votes(UserID, GameID) VALUES(?, ?)",
params![user.as_bytes().to_vec(), game as i32],
).unwrap();
)
.unwrap();
}
// FIXME: return Results intead of crashing
pub fn vote_ready(&mut self, user: Uuid) {
self.delete_vote(user);
self.conn.execute(
self.conn
.execute(
"UPDATE Votes SET Ready = TRUE WHERE UserID = ?",
params![user.as_bytes().to_vec()],
).unwrap();
)
.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()
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)",
@ -172,7 +212,7 @@ 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();

19
server/src/logger.rs

@ -170,7 +170,24 @@ where
}
}
cleanup();
});
std::panic::set_hook(Box::new(|info| {
let thread = std::thread::current();
let name = thread.name().unwrap_or("<unnamed>");
log::error!("thread '{}' {}", name, info);
log::info!("Press any key to exit");
loop {
match crossterm::event::read() {
// Event::Resize(_cols, rows) => self.lines.size = rows as usize - 1,
Ok(Event::Key(_)) => {break}
Ok(_) => (),
Err(e) => {log::error!("Errored while panicking, this is unrecoverable, exiting: {}", e); break}
}
}
cleanup();
std::process::exit(0)
}));
(stdout_send, stdin_recv, close_send, join_handle)
}
@ -381,3 +398,5 @@ impl<T> LimitedVec<T> {
self.pos = 0;
}
}

1
server/src/main.rs

@ -12,6 +12,7 @@ async fn main() {
server_properties::setup();
let p = server_properties::ServerProperties::load();
let (close, _stdin) = logger::setup(&p).unwrap();
info!(target: "setup", "Server name: `{}`", p.name);
info!(target: "setup", "Serving on address `{}`", p.addr);
// for i in 0..1000 {

2
server/src/server/connection.rs

@ -27,7 +27,7 @@ impl Connection for ConnectionService {
async fn connect(&self, request: Request<Name>) -> Result<Response<UserId>, Status> {
let name = request.into_inner().name;
// let mut conn = self.conn.acquire().await;
let uuid = self.conn.write().await.add_user(name.clone()).await;
let uuid = self.conn.write().await.add_user(name.clone()).await?;
info!("Connected {}[{}]", name, uuid);
Ok(Response::new(UserId {
id: uuid.to_hyphenated().to_string(),

Loading…
Cancel
Save