back_end refactorings
Have back_end cleanup stale players/games on an interval, not every iteration of its loop. Replace usage of recursion in db_handler.rs .
This commit is contained in:
parent
27ff10293a
commit
501ce91ac3
4 changed files with 110 additions and 82 deletions
2
back_end/Cargo.lock
generated
2
back_end/Cargo.lock
generated
|
@ -154,7 +154,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "four_line_dropper_backend"
|
name = "four_line_dropper_backend"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "four_line_dropper_backend"
|
name = "four_line_dropper_backend"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
|
@ -8,12 +8,13 @@
|
||||||
//You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
//You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
use crate::ai::{get_ai_choice, AIDifficulty};
|
use crate::ai::{get_ai_choice, AIDifficulty};
|
||||||
use crate::constants::{
|
use crate::constants::{
|
||||||
COLS, GAME_CLEANUP_TIMEOUT, PLAYER_CLEANUP_TIMEOUT, PLAYER_COUNT_LIMIT, ROWS, TURN_SECONDS,
|
BACKEND_CLEANUP_INTERVAL_SECONDS, COLS, GAME_CLEANUP_TIMEOUT, PLAYER_CLEANUP_TIMEOUT,
|
||||||
|
PLAYER_COUNT_LIMIT, ROWS, TURN_SECONDS,
|
||||||
};
|
};
|
||||||
use crate::state::{board_from_string, new_string_board, string_from_board, BoardState, Turn};
|
use crate::state::{board_from_string, new_string_board, string_from_board, BoardState, Turn};
|
||||||
|
|
||||||
use std::sync::mpsc::{Receiver, RecvTimeoutError, SyncSender};
|
use std::sync::mpsc::{Receiver, RecvTimeoutError, SyncSender};
|
||||||
use std::time::Duration;
|
use std::time::{Duration, Instant};
|
||||||
use std::{fmt, thread};
|
use std::{fmt, thread};
|
||||||
|
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
@ -314,10 +315,13 @@ impl DBHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_new_player(&self, conn: Option<&Connection>) -> Result<u32, String> {
|
fn create_new_player(&self, conn: Option<&Connection>) -> Result<u32, String> {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.create_new_player(Some(&self.get_conn(DBFirstRun::NotFirstRun)?));
|
let conn = if conn.is_none() {
|
||||||
}
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
let conn = conn.unwrap();
|
_conn_result.as_ref().unwrap()
|
||||||
|
} else {
|
||||||
|
conn.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let row_result: Result<usize, _> =
|
let row_result: Result<usize, _> =
|
||||||
conn.query_row("SELECT count(id) FROM players;", [], |row| row.get(0));
|
conn.query_row("SELECT count(id) FROM players;", [], |row| row.get(0));
|
||||||
|
@ -358,10 +362,14 @@ impl DBHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pair_up_players(&self, conn: Option<&Connection>) -> Result<(), String> {
|
fn pair_up_players(&self, conn: Option<&Connection>) -> Result<(), String> {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.pair_up_players(Some(&self.get_conn(DBFirstRun::NotFirstRun)?));
|
let conn = if conn.is_none() {
|
||||||
}
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
let conn = conn.unwrap();
|
_conn_result.as_ref().unwrap()
|
||||||
|
} else {
|
||||||
|
conn.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let mut to_pair: Option<u32> = None;
|
let mut to_pair: Option<u32> = None;
|
||||||
let mut unpaired_players_stmt = conn
|
let mut unpaired_players_stmt = conn
|
||||||
.prepare("SELECT id FROM players WHERE game_id ISNULL ORDER BY date_added;")
|
.prepare("SELECT id FROM players WHERE game_id ISNULL ORDER BY date_added;")
|
||||||
|
@ -388,10 +396,14 @@ impl DBHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_game(&self, conn: Option<&Connection>, players: &[u32; 2]) -> Result<u32, String> {
|
fn create_game(&self, conn: Option<&Connection>, players: &[u32; 2]) -> Result<u32, String> {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.create_game(Some(&self.get_conn(DBFirstRun::NotFirstRun)?), players);
|
let conn = if conn.is_none() {
|
||||||
}
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
let conn = conn.unwrap();
|
_conn_result.as_ref().unwrap()
|
||||||
|
} else {
|
||||||
|
conn.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let mut game_id: u32 = thread_rng().gen();
|
let mut game_id: u32 = thread_rng().gen();
|
||||||
{
|
{
|
||||||
let mut get_game_stmt = conn
|
let mut get_game_stmt = conn
|
||||||
|
@ -435,13 +447,13 @@ impl DBHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.check_if_player_is_paired(
|
let conn = if conn.is_none() {
|
||||||
Some(&self.get_conn(DBFirstRun::NotFirstRun)?),
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
player_id,
|
_conn_result.as_ref().unwrap()
|
||||||
);
|
} else {
|
||||||
}
|
conn.unwrap()
|
||||||
let conn = conn.unwrap();
|
};
|
||||||
|
|
||||||
let check_player_row = conn.query_row("SELECT games.cyan_player FROM players JOIN games where games.id = players.game_id AND players.id = ?;", [player_id], |row| row.get::<usize, u32>(0));
|
let check_player_row = conn.query_row("SELECT games.cyan_player FROM players JOIN games where games.id = players.game_id AND players.id = ?;", [player_id], |row| row.get::<usize, u32>(0));
|
||||||
if let Ok(cyan_player) = check_player_row {
|
if let Ok(cyan_player) = check_player_row {
|
||||||
|
@ -478,11 +490,14 @@ impl DBHandler {
|
||||||
conn: Option<&Connection>,
|
conn: Option<&Connection>,
|
||||||
player_id: u32,
|
player_id: u32,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self
|
let conn = if conn.is_none() {
|
||||||
.check_if_player_exists(Some(&self.get_conn(DBFirstRun::NotFirstRun)?), player_id);
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
}
|
_conn_result.as_ref().unwrap()
|
||||||
let conn = conn.unwrap();
|
} else {
|
||||||
|
conn.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let check_player_row: Result<u32, _> =
|
let check_player_row: Result<u32, _> =
|
||||||
conn.query_row("SELECT id FROM players WHERE id = ?;", [player_id], |row| {
|
conn.query_row("SELECT id FROM players WHERE id = ?;", [player_id], |row| {
|
||||||
row.get(0)
|
row.get(0)
|
||||||
|
@ -499,13 +514,13 @@ impl DBHandler {
|
||||||
conn: Option<&Connection>,
|
conn: Option<&Connection>,
|
||||||
player_id: u32,
|
player_id: u32,
|
||||||
) -> Result<bool, String> {
|
) -> Result<bool, String> {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.check_if_player_in_game(
|
let conn = if conn.is_none() {
|
||||||
Some(&self.get_conn(DBFirstRun::NotFirstRun)?),
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
player_id,
|
_conn_result.as_ref().unwrap()
|
||||||
);
|
} else {
|
||||||
}
|
conn.unwrap()
|
||||||
let conn = conn.unwrap();
|
};
|
||||||
|
|
||||||
let check_player_game_row: Result<u32, _> = conn.query_row(
|
let check_player_game_row: Result<u32, _> = conn.query_row(
|
||||||
"SELECT games.id FROM games JOIN players WHERE players.id = ? AND players.game_id NOTNULL AND players.game_id = games.id;",
|
"SELECT games.id FROM games JOIN players WHERE players.id = ? AND players.game_id NOTNULL AND players.game_id = games.id;",
|
||||||
|
@ -523,10 +538,13 @@ impl DBHandler {
|
||||||
conn: Option<&Connection>,
|
conn: Option<&Connection>,
|
||||||
player_id: u32,
|
player_id: u32,
|
||||||
) -> Result<BoardStateType, String> {
|
) -> Result<BoardStateType, String> {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.get_board_state(Some(&self.get_conn(DBFirstRun::NotFirstRun)?), player_id);
|
let conn = if conn.is_none() {
|
||||||
}
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
let conn = conn.unwrap();
|
_conn_result.as_ref().unwrap()
|
||||||
|
} else {
|
||||||
|
conn.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
// TODO maybe handle "opponent_disconnected" case
|
// TODO maybe handle "opponent_disconnected" case
|
||||||
let row_result: Result<(String, i64, Option<u32>, Option<u32>), RusqliteError> = conn.query_row(
|
let row_result: Result<(String, i64, Option<u32>, Option<u32>), RusqliteError> = conn.query_row(
|
||||||
|
@ -595,11 +613,13 @@ impl DBHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disconnect_player(&self, conn: Option<&Connection>, player_id: u32) -> Result<(), String> {
|
fn disconnect_player(&self, conn: Option<&Connection>, player_id: u32) -> Result<(), String> {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self
|
let conn = if conn.is_none() {
|
||||||
.disconnect_player(Some(&self.get_conn(DBFirstRun::NotFirstRun)?), player_id);
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
}
|
_conn_result.as_ref().unwrap()
|
||||||
let conn = conn.unwrap();
|
} else {
|
||||||
|
conn.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let stmt_result = conn.execute("DELETE FROM players WHERE id = ?;", [player_id]);
|
let stmt_result = conn.execute("DELETE FROM players WHERE id = ?;", [player_id]);
|
||||||
if let Ok(1) = stmt_result {
|
if let Ok(1) = stmt_result {
|
||||||
|
@ -610,10 +630,13 @@ impl DBHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_empty_games(&self, conn: Option<&Connection>) -> Result<(), String> {
|
fn clear_empty_games(&self, conn: Option<&Connection>) -> Result<(), String> {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.clear_empty_games(Some(&self.get_conn(DBFirstRun::NotFirstRun)?));
|
let conn = if conn.is_none() {
|
||||||
}
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
let conn = conn.unwrap();
|
_conn_result.as_ref().unwrap()
|
||||||
|
} else {
|
||||||
|
conn.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
// Only fails if no rows were removed, and that is not an issue
|
// Only fails if no rows were removed, and that is not an issue
|
||||||
conn.execute(
|
conn.execute(
|
||||||
|
@ -631,18 +654,13 @@ impl DBHandler {
|
||||||
player_id: u32,
|
player_id: u32,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
) -> PlaceResultType {
|
) -> PlaceResultType {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.place_token(
|
let conn = if conn.is_none() {
|
||||||
Some(
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
&self
|
_conn_result.as_ref().unwrap()
|
||||||
.get_conn(DBFirstRun::NotFirstRun)
|
} else {
|
||||||
.map_err(|_| DBPlaceError::InternalError)?,
|
conn.unwrap()
|
||||||
),
|
};
|
||||||
player_id,
|
|
||||||
pos,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
let conn = conn.unwrap();
|
|
||||||
|
|
||||||
// check if player exists
|
// check if player exists
|
||||||
let player_exist_check_result = self.check_if_player_exists(Some(conn), player_id);
|
let player_exist_check_result = self.check_if_player_exists(Some(conn), player_id);
|
||||||
|
@ -884,15 +902,13 @@ impl DBHandler {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.have_ai_take_players_turn(
|
let conn = if conn.is_none() {
|
||||||
Some(&self.get_conn(DBFirstRun::NotFirstRun)?),
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
game_id,
|
_conn_result.as_ref().unwrap()
|
||||||
status,
|
} else {
|
||||||
board_string,
|
conn.unwrap()
|
||||||
);
|
};
|
||||||
}
|
|
||||||
let conn = conn.unwrap();
|
|
||||||
|
|
||||||
let is_cyan = status == 0;
|
let is_cyan = status == 0;
|
||||||
let board = board_from_string(board_string);
|
let board = board_from_string(board_string);
|
||||||
|
@ -958,10 +974,13 @@ impl DBHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cleanup_stale_games(&self, conn: Option<&Connection>) -> Result<(), String> {
|
fn cleanup_stale_games(&self, conn: Option<&Connection>) -> Result<(), String> {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.cleanup_stale_games(Some(&self.get_conn(DBFirstRun::NotFirstRun)?));
|
let conn = if conn.is_none() {
|
||||||
}
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
let conn = conn.unwrap();
|
_conn_result.as_ref().unwrap()
|
||||||
|
} else {
|
||||||
|
conn.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"DELETE FROM games WHERE unixepoch() - unixepoch(date_added) > ?;",
|
"DELETE FROM games WHERE unixepoch() - unixepoch(date_added) > ?;",
|
||||||
|
@ -973,10 +992,13 @@ impl DBHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cleanup_stale_players(&self, conn: Option<&Connection>) -> Result<(), String> {
|
fn cleanup_stale_players(&self, conn: Option<&Connection>) -> Result<(), String> {
|
||||||
if conn.is_none() {
|
let mut _conn_result = Err(String::new());
|
||||||
return self.cleanup_stale_players(Some(&self.get_conn(DBFirstRun::NotFirstRun)?));
|
let conn = if conn.is_none() {
|
||||||
}
|
_conn_result = self.get_conn(DBFirstRun::NotFirstRun);
|
||||||
let conn = conn.unwrap();
|
_conn_result.as_ref().unwrap()
|
||||||
|
} else {
|
||||||
|
conn.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
conn.execute(
|
conn.execute(
|
||||||
"DELETE FROM players WHERE unixepoch() - unixepoch(date_added) > ? AND game_id ISNULL;",
|
"DELETE FROM players WHERE unixepoch() - unixepoch(date_added) > ? AND game_id ISNULL;",
|
||||||
|
@ -1007,6 +1029,8 @@ pub fn start_db_handler_thread(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut cleanup_instant = Instant::now();
|
||||||
|
let cleanup_duration = Duration::from_secs(BACKEND_CLEANUP_INTERVAL_SECONDS);
|
||||||
'outer: loop {
|
'outer: loop {
|
||||||
if handler.handle_request() {
|
if handler.handle_request() {
|
||||||
handler.shutdown_tx.send(()).ok();
|
handler.shutdown_tx.send(()).ok();
|
||||||
|
@ -1017,11 +1041,14 @@ pub fn start_db_handler_thread(
|
||||||
println!("{}", e);
|
println!("{}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(e) = handler.cleanup_stale_games(None) {
|
if cleanup_instant.elapsed() > cleanup_duration {
|
||||||
println!("{}", e);
|
cleanup_instant = Instant::now();
|
||||||
}
|
if let Err(e) = handler.cleanup_stale_games(None) {
|
||||||
if let Err(e) = handler.cleanup_stale_players(None) {
|
println!("{}", e);
|
||||||
println!("{}", e);
|
}
|
||||||
|
if let Err(e) = handler.cleanup_stale_players(None) {
|
||||||
|
println!("{}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub const GAME_CLEANUP_TIMEOUT: u64 = (TURN_SECONDS + 1) * ((ROWS * COLS) as u64
|
||||||
pub const PLAYER_CLEANUP_TIMEOUT: u64 = 300;
|
pub const PLAYER_CLEANUP_TIMEOUT: u64 = 300;
|
||||||
|
|
||||||
pub const BACKEND_TICK_DURATION_MILLIS: i32 = 500;
|
pub const BACKEND_TICK_DURATION_MILLIS: i32 = 500;
|
||||||
|
pub const BACKEND_CLEANUP_INTERVAL_SECONDS: u64 = 120;
|
||||||
|
|
||||||
// TODO: Change this to "https://asdm.seodisparate.com/api" when backend is installed
|
// TODO: Change this to "https://asdm.seodisparate.com/api" when backend is installed
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
|
Loading…
Reference in a new issue