rust/hedgewars-checker/src/main.rs
changeset 16008 1635ce22b214
parent 15916 0cd6996cd4c8
child 16009 39ae4ed7de6e
equal deleted inserted replaced
16007:20adaa127663 16008:1635ce22b214
     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)