diff -r a4d505a32879 -r 3511bacbd763 rust/hedgewars-server/src/server/database.rs --- a/rust/hedgewars-server/src/server/database.rs Tue Feb 01 20:58:35 2022 +0300 +++ b/rust/hedgewars-server/src/server/database.rs Thu Feb 03 01:48:31 2022 +0300 @@ -1,6 +1,5 @@ -use mysql; -use mysql::{error::DriverError, error::Error, from_row_opt, params}; -use openssl::sha::sha1; +use mysql_async::{self, from_row_opt, params, prelude::*, Pool}; +use sha1::{Digest, Sha1}; use crate::handlers::{AccountInfo, Sha1Digest}; @@ -27,120 +26,106 @@ pub struct Achievements {} pub struct Database { - pool: Option, + pool: Pool, } impl Database { - pub fn new() -> Self { - Self { pool: None } - } - - pub fn connect(&mut self, url: &str) -> Result<(), Error> { - self.pool = Some(mysql::Pool::new(url)?); - - Ok(()) - } - - pub fn is_registered(&mut self, nick: &str) -> Result { - if let Some(pool) = &self.pool { - let is_registered = pool - .first_exec(CHECK_ACCOUNT_EXISTS_QUERY, params! { "username" => nick })? - .is_some(); - Ok(is_registered) - } else { - Err(DriverError::SetupError.into()) + pub fn new(url: &str) -> Self { + Self { + pool: Pool::new(url), } } - pub fn get_account( + pub async fn get_is_registered(&mut self, nick: &str) -> mysql_async::Result { + let mut connection = self.pool.get_conn().await?; + let result = CHECK_ACCOUNT_EXISTS_QUERY + .with(params! { "username" => nick }) + .first(&mut connection) + .await?; + Ok(!result.is_empty()) + } + + pub async fn get_account( &mut self, nick: &str, protocol: u16, password_hash: &str, client_salt: &str, server_salt: &str, - ) -> Result, Error> { - if let Some(pool) = &self.pool { - if let Some(row) = pool.first_exec(GET_ACCOUNT_QUERY, params! { "username" => nick })? { - let (mut password, is_admin, is_contributor) = - from_row_opt::<(String, i32, i32)>(row)?; - let client_hash = get_hash(protocol, &password, &client_salt, &server_salt); - let server_hash = get_hash(protocol, &password, &server_salt, &client_salt); - password.replace_range(.., "🦔🦔🦔🦔🦔🦔🦔🦔"); + ) -> mysql_async::Result> { + let mut connection = self.pool.get_conn().await?; + if let Some((mut password, is_admin, is_contributor)) = GET_ACCOUNT_QUERY + .with(params! { "username" => nick }) + .first::<(String, i32, i32), _>(&mut connection) + .await? + { + let client_hash = get_hash(protocol, &password, &client_salt, &server_salt); + let server_hash = get_hash(protocol, &password, &server_salt, &client_salt); + password.replace_range(.., "🦔🦔🦔🦔🦔🦔🦔🦔"); - if client_hash == password_hash { - Ok(Some(AccountInfo { - is_registered: true, - is_admin: is_admin == 1, - is_contributor: is_contributor == 1, - server_hash, - })) - } else { - Ok(None) - } + if client_hash == password_hash { + Ok(Some(AccountInfo { + is_registered: true, + is_admin: is_admin == 1, + is_contributor: is_contributor == 1, + server_hash, + })) } else { Ok(None) } } else { - Err(DriverError::SetupError.into()) + Ok(None) } } - pub fn get_checker_account( + pub async fn get_checker_account( &mut self, nick: &str, checker_password: &str, - ) -> Result { - if let Some(pool) = &self.pool { - if let Some(row) = pool.first_exec(GET_ACCOUNT_QUERY, params! { "username" => nick })? { - let (mut password, _, _) = from_row_opt::<(String, i32, i32)>(row)?; - Ok(checker_password == password) - } else { - Ok(false) - } + ) -> mysql_async::Result { + let mut connection = self.pool.get_conn().await?; + if let Some((password, _, _)) = GET_ACCOUNT_QUERY + .with(params! { "username" => nick }) + .first::<(String, i32, i32), _>(&mut connection) + .await? + { + Ok(checker_password == password) } else { - Err(DriverError::SetupError.into()) + Ok(false) } } - pub fn store_stats(&mut self, stats: &ServerStatistics) -> Result<(), Error> { - if let Some(pool) = &self.pool { - for mut stmt in pool.prepare(STORE_STATS_QUERY) { - stmt.execute(params! { - "players" => stats.players, - "rooms" => stats.rooms, - })?; - } - Ok(()) - } else { - Err(DriverError::SetupError.into()) - } + pub async fn store_stats(&mut self, stats: &ServerStatistics) -> mysql_async::Result<()> { + let mut connection = self.pool.get_conn().await?; + STORE_STATS_QUERY + .with(params! { + "players" => stats.players, + "rooms" => stats.rooms, + }) + .ignore(&mut connection) + .await } - pub fn store_achievements(&mut self, achievements: &Achievements) -> Result<(), ()> { + pub async fn store_achievements(&mut self, achievements: &Achievements) -> mysql_async::Result<()> { Ok(()) } - pub fn get_replay_name(&mut self, replay_id: u32) -> Result, Error> { - if let Some(pool) = &self.pool { - if let Some(row) = - pool.first_exec(GET_REPLAY_NAME_QUERY, params! { "id" => replay_id })? - { - let filename = from_row_opt::(row)?; - Ok(Some(filename)) - } else { - Ok(None) - } - } else { - Err(DriverError::SetupError.into()) - } + pub async fn get_replay_name(&mut self, replay_id: u32) -> mysql_async::Result> { + let mut connection = self.pool.get_conn().await?; + GET_REPLAY_NAME_QUERY + .with(params! { "id" => replay_id }) + .first::(&mut connection) + .await } } fn get_hash(protocol_number: u16, web_password: &str, salt1: &str, salt2: &str) -> Sha1Digest { - let s = format!( + let data = format!( "{}{}{}{}{}", salt1, salt2, web_password, protocol_number, "!hedgewars" ); - Sha1Digest::new(sha1(s.as_bytes())) + + let mut sha1 = Sha1::new(); + sha1.update(&data); + Sha1Digest::new(sha1.finalize().try_into().unwrap()) }