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 rand::{thread_rng, Rng};
use rusqlite::Connection; use rusqlite::Connection;
pub type GetIDSenderType = (u32, Option<bool>);
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum DBHandlerRequest { pub enum DBHandlerRequest {
GetID(SyncSender<u32>), GetID(SyncSender<GetIDSenderType>),
} }
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -15,6 +17,71 @@ enum DBFirstRun {
NotFirstRun, 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> { fn init_conn(sqlite_path: &str, first_run: DBFirstRun) -> Result<Connection, String> {
if let Ok(conn) = Connection::open(sqlite_path) { if let Ok(conn) = Connection::open(sqlite_path) {
conn.execute("PRAGMA foreign_keys = ON;", []) conn.execute("PRAGMA foreign_keys = ON;", [])
@ -67,70 +134,25 @@ pub fn start_db_handler_thread(
sqlite_path: String, sqlite_path: String,
shutdown_tx: SyncSender<()>, shutdown_tx: SyncSender<()>,
) { ) {
let mut handler = DBHandler {
rx,
sqlite_path,
shutdown_tx,
};
thread::spawn(move || { thread::spawn(move || {
// temporarily get conn which should initialize on first setup of db // 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 { } else {
println!("ERROR: Failed init sqlite db connection"); println!("ERROR: Failed init sqlite db connection");
shutdown_tx.send(()).ok(); handler.shutdown_tx.send(()).ok();
return; return;
} }
'outer: loop { 'outer: loop {
let rx_recv_result = rx.recv(); if handler.handle_request() {
if let Err(e) = rx_recv_result { handler.shutdown_tx.send(()).ok();
println!("Failed to get DBHandlerRequest: {:?}", e); break 'outer;
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();
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::{ use std::{
sync::mpsc::{sync_channel, SyncSender}, sync::mpsc::{sync_channel, SyncSender},
@ -27,11 +27,11 @@ pub fn handle_json(
} }
fn handle_pairing_request(tx: SyncSender<DBHandlerRequest>) -> Result<String, String> { 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() { if tx.send(DBHandlerRequest::GetID(player_tx)).is_err() {
return Err("{\"type\":\"pairing_response\", \"status\":\"internal_error\"}".into()); 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!( Ok(format!(
"{{\"type\":\"pairing_response\", \"id\": \"{}\", \"status\": \"waiting\"}}", "{{\"type\":\"pairing_response\", \"id\": \"{}\", \"status\": \"waiting\"}}",
pid pid