1 use mysql_async::{self, from_row_opt, params, prelude::*, Pool}; |
1 use mysql_async::{self, from_row_opt, params, prelude::*, Pool}; |
2 use sha1::{Digest, Sha1}; |
2 use sha1::{Digest, Sha1}; |
|
3 use tokio::sync::mpsc::{channel, Receiver, Sender}; |
3 |
4 |
4 use crate::handlers::{AccountInfo, Sha1Digest}; |
5 use crate::handlers::{AccountInfo, Sha1Digest}; |
5 |
6 |
6 const CHECK_ACCOUNT_EXISTS_QUERY: &str = |
7 const CHECK_ACCOUNT_EXISTS_QUERY: &str = |
7 r"SELECT 1 FROM users WHERE users.name = :username LIMIT 1"; |
8 r"SELECT 1 FROM users WHERE users.name = :username LIMIT 1"; |
23 players: u32, |
24 players: u32, |
24 } |
25 } |
25 |
26 |
26 pub struct Achievements {} |
27 pub struct Achievements {} |
27 |
28 |
|
29 pub enum DatabaseQuery { |
|
30 CheckRegistered { |
|
31 nick: String, |
|
32 }, |
|
33 GetAccount { |
|
34 nick: String, |
|
35 protocol: u16, |
|
36 password_hash: String, |
|
37 client_salt: String, |
|
38 server_salt: String, |
|
39 }, |
|
40 GetCheckerAccount { |
|
41 nick: String, |
|
42 password: String, |
|
43 }, |
|
44 GetReplayFilename { |
|
45 id: u32, |
|
46 }, |
|
47 } |
|
48 |
|
49 pub enum DatabaseResponse { |
|
50 AccountRegistered(bool), |
|
51 Account(Option<AccountInfo>), |
|
52 CheckerAccount { is_registered: bool }, |
|
53 } |
|
54 |
28 pub struct Database { |
55 pub struct Database { |
29 pool: Pool, |
56 pool: Pool, |
|
57 query_rx: Receiver<DatabaseQuery>, |
|
58 response_tx: Sender<DatabaseResponse>, |
30 } |
59 } |
31 |
60 |
32 impl Database { |
61 impl Database { |
33 pub fn new(url: &str) -> Self { |
62 pub fn new(url: &str) -> Self { |
|
63 let (query_tx, query_rx) = channel(32); |
|
64 let (response_tx, response_rx) = channel(32); |
34 Self { |
65 Self { |
35 pool: Pool::new(url), |
66 pool: Pool::new(url), |
|
67 query_rx, |
|
68 response_tx, |
|
69 } |
|
70 } |
|
71 |
|
72 pub async fn run(&mut self) { |
|
73 use DatabaseResponse::*; |
|
74 loop { |
|
75 let query = self.query_rx.recv().await; |
|
76 if let Some(query) = query { |
|
77 match query { |
|
78 DatabaseQuery::CheckRegistered { nick } => { |
|
79 let is_registered = self.get_is_registered(&nick).await.unwrap_or(false); |
|
80 self.response_tx |
|
81 .send(AccountRegistered(is_registered)) |
|
82 .await; |
|
83 } |
|
84 DatabaseQuery::GetAccount { |
|
85 nick, |
|
86 protocol, |
|
87 password_hash, |
|
88 client_salt, |
|
89 server_salt, |
|
90 } => { |
|
91 let account = self |
|
92 .get_account( |
|
93 &nick, |
|
94 protocol, |
|
95 &password_hash, |
|
96 &client_salt, |
|
97 &server_salt, |
|
98 ) |
|
99 .await |
|
100 .unwrap_or(None); |
|
101 self.response_tx.send(Account(account)).await; |
|
102 } |
|
103 DatabaseQuery::GetCheckerAccount { nick, password } => { |
|
104 let is_registered = self |
|
105 .get_checker_account(&nick, &password) |
|
106 .await |
|
107 .unwrap_or(false); |
|
108 self.response_tx |
|
109 .send(CheckerAccount { is_registered }) |
|
110 .await; |
|
111 } |
|
112 DatabaseQuery::GetReplayFilename { id } => { |
|
113 let filename = self.get_replay_name(id).await; |
|
114 } |
|
115 }; |
|
116 } else { |
|
117 break; |
|
118 } |
36 } |
119 } |
37 } |
120 } |
38 |
121 |
39 pub async fn get_is_registered(&mut self, nick: &str) -> mysql_async::Result<bool> { |
122 pub async fn get_is_registered(&mut self, nick: &str) -> mysql_async::Result<bool> { |
40 let mut connection = self.pool.get_conn().await?; |
123 let mut connection = self.pool.get_conn().await?; |
41 let result = CHECK_ACCOUNT_EXISTS_QUERY |
124 let result = CHECK_ACCOUNT_EXISTS_QUERY |
42 .with(params! { "username" => nick }) |
125 .with(params! { "username" => nick }) |
43 .first(&mut connection) |
126 .first::<u32, _>(&mut connection) |
44 .await?; |
127 .await?; |
45 Ok(!result.is_empty()) |
128 Ok(!result.is_some()) |
46 } |
129 } |
47 |
130 |
48 pub async fn get_account( |
131 pub async fn get_account( |
49 &mut self, |
132 &mut self, |
50 nick: &str, |
133 nick: &str, |