equal
deleted
inserted
replaced
1 use anyhow::{bail, Result}; |
1 use anyhow::{bail, Result}; |
2 use argparse::{ArgumentParser, Store}; |
2 use argparse::{ArgumentParser, Store}; |
|
3 use base64::{engine::general_purpose, Engine}; |
3 use hedgewars_network_protocol::{ |
4 use hedgewars_network_protocol::{ |
4 messages::HwProtocolMessage as ClientMessage, messages::HwServerMessage::*, parser, |
5 messages::HwProtocolMessage as ClientMessage, messages::HwServerMessage::*, parser, |
5 }; |
6 }; |
6 use ini::Ini; |
7 use ini::Ini; |
7 use log::{debug, info, warn}; |
8 use log::{debug, info, warn}; |
10 use tokio::{io, io::AsyncWriteExt, net::TcpStream, process::Command, sync::mpsc}; |
11 use tokio::{io, io::AsyncWriteExt, net::TcpStream, process::Command, sync::mpsc}; |
11 |
12 |
12 async fn check(executable: &str, data_prefix: &str, buffer: &[String]) -> Result<Vec<String>> { |
13 async fn check(executable: &str, data_prefix: &str, buffer: &[String]) -> Result<Vec<String>> { |
13 let mut replay = tempfile::NamedTempFile::new()?; |
14 let mut replay = tempfile::NamedTempFile::new()?; |
14 |
15 |
15 for line in buffer.into_iter() { |
16 for line in buffer.iter() { |
16 replay.write(&base64::decode(line)?)?; |
17 replay.write_all(&general_purpose::STANDARD.decode(line)?)?; |
17 } |
18 } |
18 |
19 |
19 let temp_file_path = replay.path(); |
20 let temp_file_path = replay.path(); |
20 |
21 |
21 let mut home_dir = dirs::home_dir().unwrap(); |
22 let mut home_dir = dirs::home_dir().unwrap(); |
41 |
42 |
42 let mut result = Vec::new(); |
43 let mut result = Vec::new(); |
43 |
44 |
44 let mut engine_lines = output |
45 let mut engine_lines = output |
45 .stderr |
46 .stderr |
46 .split(|b| *b == '\n' as u8) |
47 .split(|b| *b == b'\n') |
47 .skip_while(|l| *l != b"WINNERS" && *l != b"DRAW"); |
48 .skip_while(|l| *l != b"WINNERS" && *l != b"DRAW"); |
48 |
49 |
49 // debug!("Engine lines: {:?}", &engine_lines); |
50 // debug!("Engine lines: {:?}", &engine_lines); |
50 |
51 |
51 loop { |
52 loop { |
81 } |
82 } |
82 } |
83 } |
83 |
84 |
84 // println!("Engine lines: {:?}", &result); |
85 // println!("Engine lines: {:?}", &result); |
85 |
86 |
86 if result.len() > 0 { |
87 if !result.is_empty() { |
87 Ok(result) |
88 Ok(result) |
88 } else { |
89 } else { |
89 bail!("no data from engine") |
90 bail!("no data from engine") |
90 } |
91 } |
91 } |
92 } |
131 Ok(result) => { |
132 Ok(result) => { |
132 info!("Checked"); |
133 info!("Checked"); |
133 debug!("Check result: [{:?}]", result); |
134 debug!("Check result: [{:?}]", result); |
134 |
135 |
135 stream |
136 stream |
136 .write( |
137 .write_all( |
137 ClientMessage::CheckedOk(result) |
138 ClientMessage::CheckedOk(result) |
138 .to_raw_protocol() |
139 .to_raw_protocol() |
139 .as_bytes(), |
140 .as_bytes(), |
140 ) |
141 ) |
141 .await?; |
142 .await?; |
142 stream |
143 stream |
143 .write(ClientMessage::CheckerReady.to_raw_protocol().as_bytes()) |
144 .write_all(ClientMessage::CheckerReady.to_raw_protocol().as_bytes()) |
144 .await?; |
145 .await?; |
145 } |
146 } |
146 Err(e) => { |
147 Err(e) => { |
147 info!("Check failed: {:?}", e); |
148 info!("Check failed: {:?}", e); |
148 stream |
149 stream |
149 .write( |
150 .write_all( |
150 ClientMessage::CheckedFail("error".to_owned()) |
151 ClientMessage::CheckedFail("error".to_owned()) |
151 .to_raw_protocol() |
152 .to_raw_protocol() |
152 .as_bytes(), |
153 .as_bytes(), |
153 ) |
154 ) |
154 .await?; |
155 .await?; |
155 stream |
156 stream |
156 .write(ClientMessage::CheckerReady.to_raw_protocol().as_bytes()) |
157 .write_all(ClientMessage::CheckerReady.to_raw_protocol().as_bytes()) |
157 .await?; |
158 .await?; |
158 } |
159 } |
159 } |
160 } |
160 } else { |
161 } else { |
161 let mut msg = [0; 4096]; |
162 let mut msg = [0; 4096]; |
181 |
182 |
182 match msg { |
183 match msg { |
183 Connected(_, _) => { |
184 Connected(_, _) => { |
184 info!("Connected"); |
185 info!("Connected"); |
185 stream |
186 stream |
186 .write( |
187 .write_all( |
187 ClientMessage::Checker( |
188 ClientMessage::Checker( |
188 protocol_number, |
189 protocol_number, |
189 username.to_owned(), |
190 username.to_owned(), |
190 password.to_owned(), |
191 password.to_owned(), |
191 ) |
192 ) |
194 ) |
195 ) |
195 .await?; |
196 .await?; |
196 } |
197 } |
197 Ping => { |
198 Ping => { |
198 stream |
199 stream |
199 .write(ClientMessage::Pong.to_raw_protocol().as_bytes()) |
200 .write_all(ClientMessage::Pong.to_raw_protocol().as_bytes()) |
200 .await?; |
201 .await?; |
201 } |
202 } |
202 LogonPassed => { |
203 LogonPassed => { |
203 stream |
204 stream |
204 .write(ClientMessage::CheckerReady.to_raw_protocol().as_bytes()) |
205 .write_all(ClientMessage::CheckerReady.to_raw_protocol().as_bytes()) |
205 .await?; |
206 .await?; |
206 } |
207 } |
207 Replay(lines) => { |
208 Replay(lines) => { |
208 info!("Got a replay"); |
209 info!("Got a replay"); |
209 replay_sender.send(lines).await?; |
210 replay_sender.send(lines).await?; |
214 } |
215 } |
215 ChatMsg { nick, msg } => { |
216 ChatMsg { nick, msg } => { |
216 info!("Chat [{}]: {}", nick, msg); |
217 info!("Chat [{}]: {}", nick, msg); |
217 } |
218 } |
218 RoomAdd(fields) => { |
219 RoomAdd(fields) => { |
219 let l = fields.into_iter(); |
220 let mut l = fields.into_iter(); |
220 info!("Room added: {}", l.skip(1).next().unwrap()); |
221 info!("Room added: {}", l.nth(1).unwrap()); |
221 } |
222 } |
222 RoomUpdated(name, fields) => { |
223 RoomUpdated(name, fields) => { |
223 let l = fields.into_iter(); |
224 let mut l = fields.into_iter(); |
224 let new_name = l.skip(1).next().unwrap(); |
225 let new_name = l.nth(1).unwrap(); |
225 |
226 |
226 if name != new_name { |
227 if name != new_name { |
227 info!("Room renamed: {}", new_name); |
228 info!("Room renamed: {}", new_name); |
228 } |
229 } |
229 } |
230 } |
243 } |
244 } |
244 |
245 |
245 async fn get_protocol_number(executable: &str) -> Result<u16> { |
246 async fn get_protocol_number(executable: &str) -> Result<u16> { |
246 let output = Command::new(executable).arg("--protocol").output().await?; |
247 let output = Command::new(executable).arg("--protocol").output().await?; |
247 |
248 |
248 Ok(u16::from_str(&String::from_utf8(output.stdout).unwrap().trim()).unwrap_or(55)) |
249 Ok(u16::from_str(String::from_utf8(output.stdout).unwrap().trim()).unwrap_or(55)) |
249 } |
250 } |
250 |
251 |
251 #[tokio::main] |
252 #[tokio::main] |
252 async fn main() -> Result<()> { |
253 async fn main() -> Result<()> { |
253 stderrlog::new() |
254 stderrlog::new() |
277 } |
278 } |
278 |
279 |
279 info!("Executable: {}", exe); |
280 info!("Executable: {}", exe); |
280 info!("Data dir: {}", prefix); |
281 info!("Data dir: {}", prefix); |
281 |
282 |
282 let protocol_number = get_protocol_number(&exe.as_str()).await.unwrap_or_default(); |
283 let protocol_number = get_protocol_number(exe.as_str()).await.unwrap_or_default(); |
283 |
284 |
284 info!("Using protocol number {}", protocol_number); |
285 info!("Using protocol number {}", protocol_number); |
285 |
286 |
286 let (replay_sender, replay_receiver) = mpsc::channel(1); |
287 let (replay_sender, replay_receiver) = mpsc::channel(1); |
287 let (results_sender, results_receiver) = mpsc::channel(1); |
288 let (results_sender, results_receiver) = mpsc::channel(1); |
288 |
289 |
289 let (network_result, checker_result) = tokio::join!( |
290 let (network_result, checker_result) = tokio::join!( |
290 connect_and_run( |
291 connect_and_run( |
291 &username, |
292 username, |
292 &password, |
293 password, |
293 protocol_number, |
294 protocol_number, |
294 replay_sender, |
295 replay_sender, |
295 results_receiver |
296 results_receiver |
296 ), |
297 ), |
297 check_loop(&exe, &prefix, results_sender, replay_receiver) |
298 check_loop(&exe, &prefix, results_sender, replay_receiver) |