rust/hedgewars-checker/src/main.rs
changeset 13953 e98e2fc556a7
parent 13952 d12ca66054aa
child 13955 a857cd1cc3f0
equal deleted inserted replaced
13952:d12ca66054aa 13953:e98e2fc556a7
     1 #[macro_use]
     1 #[macro_use]
     2 extern crate log;
     2 extern crate log;
     3 extern crate argparse;
     3 extern crate argparse;
       
     4 extern crate base64;
     4 extern crate dirs;
     5 extern crate dirs;
     5 extern crate ini;
     6 extern crate ini;
     6 extern crate netbuf;
     7 extern crate netbuf;
     7 extern crate stderrlog;
     8 extern crate stderrlog;
       
     9 extern crate tempfile;
     8 
    10 
     9 use argparse::{ArgumentParser, Store};
    11 use argparse::{ArgumentParser, Store};
    10 use ini::Ini;
    12 use ini::Ini;
    11 use netbuf::Buf;
    13 use netbuf::Buf;
    12 use std::io::{Result, Write};
    14 use std::io::Write;
    13 use std::net::TcpStream;
    15 use std::net::TcpStream;
    14 use std::process::Command;
    16 use std::process::Command;
    15 use std::str::FromStr;
    17 use std::str::FromStr;
       
    18 
       
    19 type CheckError = Box<std::error::Error>;
    16 
    20 
    17 fn extract_packet(buf: &mut Buf) -> Option<netbuf::Buf> {
    21 fn extract_packet(buf: &mut Buf) -> Option<netbuf::Buf> {
    18     let packet_end = (&buf[..]).windows(2).position(|window| window == b"\n\n")?;
    22     let packet_end = (&buf[..]).windows(2).position(|window| window == b"\n\n")?;
    19 
    23 
    20     let mut tail = buf.split_off(packet_end);
    24     let mut tail = buf.split_off(packet_end);
    24     buf.consume(2);
    28     buf.consume(2);
    25 
    29 
    26     Some(tail)
    30     Some(tail)
    27 }
    31 }
    28 
    32 
       
    33 fn check(executable: &str, data_prefix: &str, buffer: &[u8]) -> Result<Vec<Vec<u8>>, CheckError> {
       
    34     let mut replay = tempfile::NamedTempFile::new()?;
       
    35 
       
    36     for line in buffer.split(|b| *b == '\n' as u8) {
       
    37         replay.write(&base64::decode(line)?);
       
    38     }
       
    39 
       
    40     let temp_file_path = replay.path();
       
    41 
       
    42     let mut home_dir = dirs::home_dir().unwrap();
       
    43     home_dir.push(".hedgewars");
       
    44 
       
    45     let output = Command::new(executable)
       
    46         .arg("--user-prefix")
       
    47         .arg(&home_dir)
       
    48         .arg("--prefix")
       
    49         .arg(data_prefix)
       
    50         .arg("--nomusic")
       
    51         .arg("--nosound")
       
    52         .arg("--stats-only")
       
    53         .arg(temp_file_path)
       
    54         .output()?;
       
    55 
       
    56     let mut result = Vec::new();
       
    57     for line in output.stdout.split(|b| *b == '\n' as u8) {
       
    58         result.push(line.to_vec());
       
    59     }
       
    60 
       
    61     Ok(result)
       
    62 }
       
    63 
    29 fn connect_and_run(
    64 fn connect_and_run(
    30     username: &str,
    65     username: &str,
    31     password: &str,
    66     password: &str,
    32     protocol_number: u32,
    67     protocol_number: u32,
    33     executable: &str,
    68     executable: &str,
    34     data_prefix: &str,
    69     data_prefix: &str,
    35 ) -> Result<()> {
    70 ) -> Result<(), CheckError> {
    36     info!("Connecting...");
    71     info!("Connecting...");
    37 
    72 
    38     let mut stream = TcpStream::connect("hedgewars.org:46631")?;
    73     let mut stream = TcpStream::connect("hedgewars.org:46631")?;
    39     stream.set_nonblocking(false)?;
    74     stream.set_nonblocking(false)?;
    40 
    75 
    54             } else if msg[..].starts_with(b"PING") {
    89             } else if msg[..].starts_with(b"PING") {
    55                 stream.write(b"PONG\n\n")?;
    90                 stream.write(b"PONG\n\n")?;
    56             } else if msg[..].starts_with(b"LOGONPASSED") {
    91             } else if msg[..].starts_with(b"LOGONPASSED") {
    57                 info!("Logged in");
    92                 info!("Logged in");
    58                 stream.write(b"READY\n\n")?;
    93                 stream.write(b"READY\n\n")?;
       
    94             } else if msg[..].starts_with(b"REPLAY") {
       
    95                 info!("Got a replay");
       
    96                 let result = check(executable, data_prefix, &msg[7..])?;
       
    97 
       
    98                 debug!(
       
    99                     "Check result: [{}]",
       
   100                     String::from_utf8_lossy(&result.join(&(',' as u8)))
       
   101                 );
       
   102 
       
   103                 stream.write(&result.join(&('\n' as u8)))?;
       
   104                 stream.write(b"\n\n")?;
    59             } else if msg[..].starts_with(b"BYE") {
   105             } else if msg[..].starts_with(b"BYE") {
    60                 warn!("Received BYE: {}", String::from_utf8_lossy(&msg[..]));
   106                 warn!("Received BYE: {}", String::from_utf8_lossy(&msg[..]));
       
   107                 return Ok(());
       
   108             } else if msg[..].starts_with(b"ERROR") {
       
   109                 warn!("Received ERROR: {}", String::from_utf8_lossy(&msg[..]));
    61                 return Ok(());
   110                 return Ok(());
    62             } else {
   111             } else {
    63                 warn!(
   112                 warn!(
    64                     "Unknown protocol command: {}",
   113                     "Unknown protocol command: {}",
    65                     String::from_utf8_lossy(&msg[..])
   114                     String::from_utf8_lossy(&msg[..])
    67             }
   116             }
    68         }
   117         }
    69     }
   118     }
    70 }
   119 }
    71 
   120 
    72 fn get_protocol_number(executable: &str) -> Result<u32> {
   121 fn get_protocol_number(executable: &str) -> std::io::Result<u32> {
    73     let output = Command::new(executable).arg("--protocol").output()?;
   122     let output = Command::new(executable).arg("--protocol").output()?;
    74 
   123 
    75     Ok(u32::from_str(&String::from_utf8(output.stdout).unwrap().as_str()).unwrap_or(55))
   124     Ok(u32::from_str(&String::from_utf8(output.stdout).unwrap().as_str()).unwrap_or(55))
    76 }
   125 }
    77 
   126