Refactor db_handler to use struct to split up code

Also refactored the GetID send value type.
This commit is contained in:
Stephen Seo 2022-03-29 15:02:20 +09:00
parent ec7f664c81
commit 40b2333767
2 changed files with 82 additions and 60 deletions

View file

@ -4,9 +4,11 @@ use std::thread;
use rand::{thread_rng, Rng};
use rusqlite::Connection;
pub type GetIDSenderType = (u32, Option<bool>);
#[derive(Clone, Debug)]
pub enum DBHandlerRequest {
GetID(SyncSender<u32>),
GetID(SyncSender<GetIDSenderType>),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -15,6 +17,71 @@ enum DBFirstRun {
NotFirstRun,
}
struct DBHandler {
rx: Receiver<DBHandlerRequest>,
sqlite_path: String,
shutdown_tx: SyncSender<()>,
}
impl DBHandler {
/// Returns true if should break out of outer loop
fn handle_request(&mut self) -> bool {
let rx_recv_result = self.rx.recv();
if let Err(e) = rx_recv_result {
println!("Failed to get DBHandlerRequest: {:?}", e);
self.shutdown_tx.send(()).ok();
return false;
}
let db_request = rx_recv_result.unwrap();
match db_request {
DBHandlerRequest::GetID(player_tx) => {
// got request to create new player, create new player
let mut player_id: u32 = thread_rng().gen();
let conn_result = init_conn(&self.sqlite_path, DBFirstRun::NotFirstRun);
if let Err(e) = conn_result {
println!("Failed to get sqlite db connection: {:?}", e);
self.shutdown_tx.send(()).ok();
return false;
}
let conn = conn_result.unwrap();
loop {
let stmt_result = conn.prepare("SELECT id FROM players WHERE id = ?;");
if let Err(e) = stmt_result {
println!("Failed to create sqlite statement: {:?}", e);
self.shutdown_tx.send(()).ok();
return true;
}
let mut stmt = stmt_result.unwrap();
match stmt.query_row([player_id], |_row| Ok(())) {
Ok(_) => {
player_id = thread_rng().gen();
}
Err(_) => break,
}
}
let insert_result = conn.execute(
"INSERT INTO players (id, date_added) VALUES (?, datetime());",
[player_id],
);
if let Err(e) = insert_result {
println!("Failed to insert into sqlite db: {:?}", e);
self.shutdown_tx.send(()).ok();
return true;
}
let send_result = player_tx.send((player_id, None));
if let Err(e) = send_result {
println!("Failed to send back player id: {:?}", e);
self.shutdown_tx.send(()).ok();
return true;
}
send_result.unwrap();
} // DBHandlerRequest::GetID(player_tx)
} // match db_request
false
}
}
fn init_conn(sqlite_path: &str, first_run: DBFirstRun) -> Result<Connection, String> {
if let Ok(conn) = Connection::open(sqlite_path) {
conn.execute("PRAGMA foreign_keys = ON;", [])
@ -67,70 +134,25 @@ pub fn start_db_handler_thread(
sqlite_path: String,
shutdown_tx: SyncSender<()>,
) {
let mut handler = DBHandler {
rx,
sqlite_path,
shutdown_tx,
};
thread::spawn(move || {
// temporarily get conn which should initialize on first setup of db
if let Ok(_conn) = init_conn(&sqlite_path, DBFirstRun::FirstRun) {
if let Ok(_conn) = init_conn(&handler.sqlite_path, DBFirstRun::FirstRun) {
} else {
println!("ERROR: Failed init sqlite db connection");
shutdown_tx.send(()).ok();
handler.shutdown_tx.send(()).ok();
return;
}
'outer: loop {
let rx_recv_result = rx.recv();
if let Err(e) = rx_recv_result {
println!("Failed to get DBHandlerRequest: {:?}", e);
shutdown_tx.send(()).ok();
break;
}
let db_request = rx_recv_result.unwrap();
match db_request {
DBHandlerRequest::GetID(player_tx) => {
// got request to create new player, create new player
let mut player_id: u32 = thread_rng().gen();
let conn_result = init_conn(&sqlite_path, DBFirstRun::NotFirstRun);
if let Err(e) = conn_result {
println!("Failed to get sqlite db connection: {:?}", e);
shutdown_tx.send(()).ok();
break;
}
let conn = conn_result.unwrap();
loop {
let stmt_result = conn.prepare("SELECT id FROM players WHERE id = ?;");
if let Err(e) = stmt_result {
println!("Failed to create sqlite statement: {:?}", e);
shutdown_tx.send(()).ok();
if handler.handle_request() {
handler.shutdown_tx.send(()).ok();
break 'outer;
}
let mut stmt = stmt_result.unwrap();
match stmt.query_row([player_id], |_row| Ok(())) {
Ok(_) => {
player_id = thread_rng().gen();
}
Err(_) => break,
}
}
let insert_result = conn.execute(
"INSERT INTO players (id, date_added) VALUES (?, datetime());",
[player_id],
);
if let Err(e) = insert_result {
println!("Failed to insert into sqlite db: {:?}", e);
shutdown_tx.send(()).ok();
break 'outer;
}
let send_result = player_tx.send(player_id);
if let Err(e) = send_result {
println!("Failed to send back player id: {:?}", e);
shutdown_tx.send(()).ok();
break 'outer;
}
send_result.unwrap();
}
}
// Pair up players
// TODO
} // loop end
});
}

View file

@ -1,4 +1,4 @@
use crate::db_handler::DBHandlerRequest;
use crate::db_handler::{DBHandlerRequest, GetIDSenderType};
use std::{
sync::mpsc::{sync_channel, SyncSender},
@ -27,11 +27,11 @@ pub fn handle_json(
}
fn handle_pairing_request(tx: SyncSender<DBHandlerRequest>) -> Result<String, String> {
let (player_tx, player_rx) = sync_channel::<u32>(1);
let (player_tx, player_rx) = sync_channel::<GetIDSenderType>(1);
if tx.send(DBHandlerRequest::GetID(player_tx)).is_err() {
return Err("{\"type\":\"pairing_response\", \"status\":\"internal_error\"}".into());
}
if let Ok(pid) = player_rx.recv_timeout(Duration::from_secs(5)) {
if let Ok((pid, is_cyan_opt)) = player_rx.recv_timeout(Duration::from_secs(5)) {
Ok(format!(
"{{\"type\":\"pairing_response\", \"id\": \"{}\", \"status\": \"waiting\"}}",
pid