Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
--- a/rust/hedgewars-checker/Cargo.toml Tue Oct 23 22:53:28 2018 +0200
+++ b/rust/hedgewars-checker/Cargo.toml Wed Oct 24 00:08:23 2018 +0200
@@ -1,7 +1,7 @@
[package]
name = "hedgewars-checker"
version = "0.1.0"
-authors = ["Andrei Korotaev <andrey.korotaev@aptomar.com>"]
+authors = ["Andrey Korotaev <a.korotaev@hedgewars.org>"]
[dependencies]
rust-ini = "0.13"
@@ -10,3 +10,5 @@
log = "0.4"
stderrlog = "0.4"
netbuf = "0.4"
+tempfile = "3.0"
+base64 = "0.9.3"
--- a/rust/hedgewars-checker/src/main.rs Tue Oct 23 22:53:28 2018 +0200
+++ b/rust/hedgewars-checker/src/main.rs Wed Oct 24 00:08:23 2018 +0200
@@ -1,19 +1,23 @@
#[macro_use]
extern crate log;
extern crate argparse;
+extern crate base64;
extern crate dirs;
extern crate ini;
extern crate netbuf;
extern crate stderrlog;
+extern crate tempfile;
use argparse::{ArgumentParser, Store};
use ini::Ini;
use netbuf::Buf;
-use std::io::{Result, Write};
+use std::io::Write;
use std::net::TcpStream;
use std::process::Command;
use std::str::FromStr;
+type CheckError = Box<std::error::Error>;
+
fn extract_packet(buf: &mut Buf) -> Option<netbuf::Buf> {
let packet_end = (&buf[..]).windows(2).position(|window| window == b"\n\n")?;
@@ -26,13 +30,44 @@
Some(tail)
}
+fn check(executable: &str, data_prefix: &str, buffer: &[u8]) -> Result<Vec<Vec<u8>>, CheckError> {
+ let mut replay = tempfile::NamedTempFile::new()?;
+
+ for line in buffer.split(|b| *b == '\n' as u8) {
+ replay.write(&base64::decode(line)?);
+ }
+
+ let temp_file_path = replay.path();
+
+ let mut home_dir = dirs::home_dir().unwrap();
+ home_dir.push(".hedgewars");
+
+ let output = Command::new(executable)
+ .arg("--user-prefix")
+ .arg(&home_dir)
+ .arg("--prefix")
+ .arg(data_prefix)
+ .arg("--nomusic")
+ .arg("--nosound")
+ .arg("--stats-only")
+ .arg(temp_file_path)
+ .output()?;
+
+ let mut result = Vec::new();
+ for line in output.stdout.split(|b| *b == '\n' as u8) {
+ result.push(line.to_vec());
+ }
+
+ Ok(result)
+}
+
fn connect_and_run(
username: &str,
password: &str,
protocol_number: u32,
executable: &str,
data_prefix: &str,
-) -> Result<()> {
+) -> Result<(), CheckError> {
info!("Connecting...");
let mut stream = TcpStream::connect("hedgewars.org:46631")?;
@@ -56,9 +91,23 @@
} else if msg[..].starts_with(b"LOGONPASSED") {
info!("Logged in");
stream.write(b"READY\n\n")?;
+ } else if msg[..].starts_with(b"REPLAY") {
+ info!("Got a replay");
+ let result = check(executable, data_prefix, &msg[7..])?;
+
+ debug!(
+ "Check result: [{}]",
+ String::from_utf8_lossy(&result.join(&(',' as u8)))
+ );
+
+ stream.write(&result.join(&('\n' as u8)))?;
+ stream.write(b"\n\n")?;
} else if msg[..].starts_with(b"BYE") {
warn!("Received BYE: {}", String::from_utf8_lossy(&msg[..]));
return Ok(());
+ } else if msg[..].starts_with(b"ERROR") {
+ warn!("Received ERROR: {}", String::from_utf8_lossy(&msg[..]));
+ return Ok(());
} else {
warn!(
"Unknown protocol command: {}",
@@ -69,7 +118,7 @@
}
}
-fn get_protocol_number(executable: &str) -> Result<u32> {
+fn get_protocol_number(executable: &str) -> std::io::Result<u32> {
let output = Command::new(executable).arg("--protocol").output()?;
Ok(u32::from_str(&String::from_utf8(output.stdout).unwrap().as_str()).unwrap_or(55))