rust/hedgewars-checker/src/main.rs
changeset 15813 ad79e5c0885c
parent 15812 8c39a11f7756
child 15887 fe519de9c270
equal deleted inserted replaced
15812:8c39a11f7756 15813:ad79e5c0885c
     4     messages::HwProtocolMessage as ClientMessage, messages::HwServerMessage::*, parser,
     4     messages::HwProtocolMessage as ClientMessage, messages::HwServerMessage::*, parser,
     5 };
     5 };
     6 use ini::Ini;
     6 use ini::Ini;
     7 use log::{debug, info, warn};
     7 use log::{debug, info, warn};
     8 use netbuf::Buf;
     8 use netbuf::Buf;
     9 use std::{io::Write, net::TcpStream, process::Command, str::FromStr};
     9 use std::{io::Write, str::FromStr};
    10 
    10 use tokio::{io, io::AsyncWriteExt, net::TcpStream, process::Command};
    11 fn check(executable: &str, data_prefix: &str, buffer: &[String]) -> Result<Vec<String>> {
    11 
       
    12 async fn check(executable: &str, data_prefix: &str, buffer: &[String]) -> Result<Vec<String>> {
    12     let mut replay = tempfile::NamedTempFile::new()?;
    13     let mut replay = tempfile::NamedTempFile::new()?;
    13 
    14 
    14     for line in buffer.into_iter() {
    15     for line in buffer.into_iter() {
    15         replay.write(&base64::decode(line)?)?;
    16         replay.write(&base64::decode(line)?)?;
    16     }
    17     }
    29         .arg(data_prefix)
    30         .arg(data_prefix)
    30         .arg("--nomusic")
    31         .arg("--nomusic")
    31         .arg("--nosound")
    32         .arg("--nosound")
    32         .arg("--stats-only")
    33         .arg("--stats-only")
    33         .arg(temp_file_path)
    34         .arg(temp_file_path)
    34         .output()?;
    35         //.spawn()?
       
    36         //.wait_with_output()
       
    37         .output()
       
    38         .await?;
       
    39 
       
    40     debug!("Engine finished!");
    35 
    41 
    36     let mut result = Vec::new();
    42     let mut result = Vec::new();
    37 
    43 
    38     let mut engine_lines = output
    44     let mut engine_lines = output
    39         .stderr
    45         .stderr
    40         .split(|b| *b == '\n' as u8)
    46         .split(|b| *b == '\n' as u8)
    41         .skip_while(|l| *l != b"WINNERS" && *l != b"DRAW");
    47         .skip_while(|l| *l != b"WINNERS" && *l != b"DRAW");
       
    48 
       
    49     debug!("Engine lines: {:?}", &engine_lines);
    42 
    50 
    43     loop {
    51     loop {
    44         match engine_lines.next() {
    52         match engine_lines.next() {
    45             Some(b"DRAW") => result.push("DRAW".to_owned()),
    53             Some(b"DRAW") => result.push("DRAW".to_owned()),
    46             Some(b"WINNERS") => {
    54             Some(b"WINNERS") => {
    71             }
    79             }
    72             _ => break,
    80             _ => break,
    73         }
    81         }
    74     }
    82     }
    75 
    83 
       
    84     println!("Engine lines: {:?}", &result);
       
    85 
    76     if result.len() > 0 {
    86     if result.len() > 0 {
    77         Ok(result)
    87         Ok(result)
    78     } else {
    88     } else {
    79         bail!("no data from engine")
    89         bail!("no data from engine")
    80     }
    90     }
    81 }
    91 }
    82 
    92 
    83 fn connect_and_run(
    93 async fn connect_and_run(
    84     username: &str,
    94     username: &str,
    85     password: &str,
    95     password: &str,
    86     protocol_number: u16,
    96     protocol_number: u16,
    87     executable: &str,
    97     executable: &str,
    88     data_prefix: &str,
    98     data_prefix: &str,
    89 ) -> Result<()> {
    99 ) -> Result<()> {
    90     info!("Connecting...");
   100     info!("Connecting...");
    91 
   101 
    92     let mut stream = TcpStream::connect("hedgewars.org:46631")?;
   102     let mut stream = TcpStream::connect("hedgewars.org:46631").await?;
    93     stream.set_nonblocking(false)?;
       
    94 
   103 
    95     let mut buf = Buf::new();
   104     let mut buf = Buf::new();
    96 
   105 
       
   106     let mut replay_lines: Option<Vec<String>> = None;
       
   107 
    97     loop {
   108     loop {
    98         buf.read_from(&mut stream)?;
   109         let r = if let Some(ref lines) = replay_lines {
       
   110             let r = tokio::select! {
       
   111                 _ = stream.readable() => None,
       
   112                 r = check(executable, data_prefix, &lines) => Some(r)
       
   113             };
       
   114 
       
   115             r
       
   116         } else {
       
   117             stream.readable().await?;
       
   118             None
       
   119         };
       
   120 
       
   121         println!("Loop: {:?}", &r);
       
   122 
       
   123         if let Some(execution_result) = r {
       
   124             replay_lines = None;
       
   125 
       
   126             match execution_result {
       
   127                 Ok(result) => {
       
   128                     info!("Checked");
       
   129                     debug!("Check result: [{:?}]", result);
       
   130 
       
   131                     stream
       
   132                         .write(
       
   133                             ClientMessage::CheckedOk(result)
       
   134                                 .to_raw_protocol()
       
   135                                 .as_bytes(),
       
   136                         )
       
   137                         .await?;
       
   138                     stream
       
   139                         .write(ClientMessage::CheckerReady.to_raw_protocol().as_bytes())
       
   140                         .await?;
       
   141                 }
       
   142                 Err(e) => {
       
   143                     info!("Check failed: {:?}", e);
       
   144                     stream
       
   145                         .write(
       
   146                             ClientMessage::CheckedFail("error".to_owned())
       
   147                                 .to_raw_protocol()
       
   148                                 .as_bytes(),
       
   149                         )
       
   150                         .await?;
       
   151                     stream
       
   152                         .write(ClientMessage::CheckerReady.to_raw_protocol().as_bytes())
       
   153                         .await?;
       
   154                 }
       
   155             }
       
   156         } else {
       
   157             let mut msg = [0; 4096];
       
   158             // Try to read data, this may still fail with `WouldBlock`
       
   159             // if the readiness event is a false positive.
       
   160             match stream.try_read(&mut msg) {
       
   161                 Ok(n) => {
       
   162                     //println!("{:?}", &msg);
       
   163                     buf.write_all(&msg[0..n])?;
       
   164                 }
       
   165                 Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
       
   166                 Err(e) => {
       
   167                     return Err(e.into());
       
   168                 }
       
   169             }
       
   170         }
    99 
   171 
   100         while let Ok((tail, msg)) = parser::server_message(buf.as_ref()) {
   172         while let Ok((tail, msg)) = parser::server_message(buf.as_ref()) {
   101             let tail_len = tail.len();
   173             let tail_len = tail.len();
   102             buf.consume(buf.len() - tail_len);
   174             buf.consume(buf.len() - tail_len);
   103 
   175 
       
   176             println!("Message from server: {:?}", &msg);
       
   177 
   104             match msg {
   178             match msg {
   105                 Connected(_, _) => {
   179                 Connected(_, _) => {
   106                     info!("Connected");
   180                     info!("Connected");
   107                     stream.write(
   181                     stream
   108                         ClientMessage::Checker(
   182                         .write(
   109                             protocol_number,
   183                             ClientMessage::Checker(
   110                             username.to_owned(),
   184                                 protocol_number,
   111                             password.to_owned(),
   185                                 username.to_owned(),
       
   186                                 password.to_owned(),
       
   187                             )
       
   188                             .to_raw_protocol()
       
   189                             .as_bytes(),
   112                         )
   190                         )
   113                         .to_raw_protocol()
   191                         .await?;
   114                         .as_bytes(),
       
   115                     )?;
       
   116                 }
   192                 }
   117                 Ping => {
   193                 Ping => {
   118                     stream.write(ClientMessage::Pong.to_raw_protocol().as_bytes())?;
   194                     stream
       
   195                         .write(ClientMessage::Pong.to_raw_protocol().as_bytes())
       
   196                         .await?;
   119                 }
   197                 }
   120                 LogonPassed => {
   198                 LogonPassed => {
   121                     stream.write(ClientMessage::CheckerReady.to_raw_protocol().as_bytes())?;
   199                     stream
       
   200                         .write(ClientMessage::CheckerReady.to_raw_protocol().as_bytes())
       
   201                         .await?;
   122                 }
   202                 }
   123                 Replay(lines) => {
   203                 Replay(lines) => {
   124                     info!("Got a replay");
   204                     info!("Got a replay");
   125                     match check(executable, data_prefix, &lines) {
   205                     replay_lines = Some(lines);
   126                         Ok(result) => {
       
   127                             info!("Checked");
       
   128                             debug!("Check result: [{:?}]", result);
       
   129 
       
   130                             stream.write(
       
   131                                 ClientMessage::CheckedOk(result)
       
   132                                     .to_raw_protocol()
       
   133                                     .as_bytes(),
       
   134                             )?;
       
   135                             stream
       
   136                                 .write(ClientMessage::CheckerReady.to_raw_protocol().as_bytes())?;
       
   137                         }
       
   138                         Err(e) => {
       
   139                             info!("Check failed: {:?}", e);
       
   140                             stream.write(
       
   141                                 ClientMessage::CheckedFail("error".to_owned())
       
   142                                     .to_raw_protocol()
       
   143                                     .as_bytes(),
       
   144                             )?;
       
   145                             stream
       
   146                                 .write(ClientMessage::CheckerReady.to_raw_protocol().as_bytes())?;
       
   147                         }
       
   148                     }
       
   149                 }
   206                 }
   150                 Bye(message) => {
   207                 Bye(message) => {
   151                     warn!("Received BYE: {}", message);
   208                     warn!("Received BYE: {}", message);
   152                     return Ok(());
   209                     return Ok(());
   153                 }
   210                 }
   179             }
   236             }
   180         }
   237         }
   181     }
   238     }
   182 }
   239 }
   183 
   240 
   184 fn get_protocol_number(executable: &str) -> std::io::Result<u16> {
   241 async fn get_protocol_number(executable: &str) -> Result<u16> {
   185     let output = Command::new(executable).arg("--protocol").output()?;
   242     let output = Command::new(executable).arg("--protocol").output().await?;
   186 
   243 
   187     Ok(u16::from_str(&String::from_utf8(output.stdout).unwrap().trim()).unwrap_or(55))
   244     Ok(u16::from_str(&String::from_utf8(output.stdout).unwrap().trim()).unwrap_or(55))
   188 }
   245 }
   189 
   246 
   190 fn main() {
   247 #[tokio::main]
       
   248 async fn main() -> Result<()> {
   191     stderrlog::new()
   249     stderrlog::new()
   192         .verbosity(3)
   250         .verbosity(3)
   193         .timestamp(stderrlog::Timestamp::Second)
   251         .timestamp(stderrlog::Timestamp::Second)
   194         .module(module_path!())
   252         .module(module_path!())
   195         .init()
   253         .init()
   215     }
   273     }
   216 
   274 
   217     info!("Executable: {}", exe);
   275     info!("Executable: {}", exe);
   218     info!("Data dir: {}", prefix);
   276     info!("Data dir: {}", prefix);
   219 
   277 
   220     let protocol_number = get_protocol_number(&exe.as_str()).unwrap_or_default();
   278     let protocol_number = get_protocol_number(&exe.as_str()).await.unwrap_or_default();
   221 
   279 
   222     info!("Using protocol number {}", protocol_number);
   280     info!("Using protocol number {}", protocol_number);
   223 
   281 
   224     connect_and_run(&username, &password, protocol_number, &exe, &prefix).unwrap();
   282     connect_and_run(&username, &password, protocol_number, &exe, &prefix).await
   225 }
   283 }