Start checker implementation in rust
authorunc0rr
Tue, 23 Oct 2018 22:53:28 +0200
changeset 13952 d12ca66054aa
parent 13951 03e41712eef8
child 13953 e98e2fc556a7
Start checker implementation in rust
rust/hedgewars-checker/Cargo.toml
rust/hedgewars-checker/src/main.rs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hedgewars-checker/Cargo.toml	Tue Oct 23 22:53:28 2018 +0200
@@ -0,0 +1,12 @@
+[package]
+name = "hedgewars-checker"
+version = "0.1.0"
+authors = ["Andrei Korotaev <andrey.korotaev@aptomar.com>"]
+
+[dependencies]
+rust-ini = "0.13"
+dirs = "1.0"
+argparse = "0.2.2"
+log = "0.4"
+stderrlog = "0.4"
+netbuf = "0.4"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hedgewars-checker/src/main.rs	Tue Oct 23 22:53:28 2018 +0200
@@ -0,0 +1,133 @@
+#[macro_use]
+extern crate log;
+extern crate argparse;
+extern crate dirs;
+extern crate ini;
+extern crate netbuf;
+extern crate stderrlog;
+
+use argparse::{ArgumentParser, Store};
+use ini::Ini;
+use netbuf::Buf;
+use std::io::{Result, Write};
+use std::net::TcpStream;
+use std::process::Command;
+use std::str::FromStr;
+
+fn extract_packet(buf: &mut Buf) -> Option<netbuf::Buf> {
+    let packet_end = (&buf[..]).windows(2).position(|window| window == b"\n\n")?;
+
+    let mut tail = buf.split_off(packet_end);
+
+    std::mem::swap(&mut tail, buf);
+
+    buf.consume(2);
+
+    Some(tail)
+}
+
+fn connect_and_run(
+    username: &str,
+    password: &str,
+    protocol_number: u32,
+    executable: &str,
+    data_prefix: &str,
+) -> Result<()> {
+    info!("Connecting...");
+
+    let mut stream = TcpStream::connect("hedgewars.org:46631")?;
+    stream.set_nonblocking(false)?;
+
+    let mut buf = Buf::new();
+
+    loop {
+        buf.read_from(&mut stream)?;
+
+        while let Some(msg) = extract_packet(&mut buf) {
+            if msg[..].starts_with(b"CONNECTED") {
+                info!("Connected");
+                let p = format!(
+                    "CHECKER\n{}\n{}\n{}\n\n",
+                    protocol_number, username, password
+                );
+                stream.write(p.as_bytes())?;
+            } else if msg[..].starts_with(b"PING") {
+                stream.write(b"PONG\n\n")?;
+            } else if msg[..].starts_with(b"LOGONPASSED") {
+                info!("Logged in");
+                stream.write(b"READY\n\n")?;
+            } else if msg[..].starts_with(b"BYE") {
+                warn!("Received BYE: {}", String::from_utf8_lossy(&msg[..]));
+                return Ok(());
+            } else {
+                warn!(
+                    "Unknown protocol command: {}",
+                    String::from_utf8_lossy(&msg[..])
+                )
+            }
+        }
+    }
+}
+
+fn get_protocol_number(executable: &str) -> 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))
+}
+
+fn main() {
+    stderrlog::new()
+        .verbosity(3)
+        .timestamp(stderrlog::Timestamp::Second)
+        .module(module_path!())
+        .init()
+        .unwrap();
+
+    let mut frontend_settings = dirs::home_dir().unwrap();
+    frontend_settings.push(".hedgewars/settings.ini");
+
+    let i = Ini::load_from_file(frontend_settings.to_str().unwrap()).unwrap();
+    let username = i.get_from(Some("net"), "nick").unwrap();
+    let password = i.get_from(Some("net"), "passwordhash").unwrap();
+
+    let mut exe = "/usr/local/bin/hwengine".to_string();
+    let mut prefix = "/usr/local/share/hedgewars/Data".to_string();
+    {
+        let mut ap = ArgumentParser::new();
+        ap.set_description("Game replay checker for hedgewars.");
+        ap.refer(&mut exe)
+            .add_option(&["--exe"], Store, "Path to hwengine executable");
+        ap.refer(&mut prefix)
+            .add_option(&["--prefix"], Store, "Path main Data dir");
+        ap.parse_args_or_exit();
+    }
+
+    info!("Executable: {}", exe);
+    info!("Data dir: {}", prefix);
+
+    let protocol_number = get_protocol_number(&exe.as_str()).unwrap_or_default();
+
+    info!("Using protocol number {}", protocol_number);
+
+    connect_and_run(&username, &password, protocol_number, &exe, &prefix);
+}
+
+#[cfg(test)]
+#[test]
+fn test() {
+    let mut buf = Buf::new();
+    buf.extend(b"Hell");
+    if let Some(_) = extract_packet(&mut buf) {
+        assert!(false)
+    }
+
+    buf.extend(b"o\n\nWorld");
+
+    let packet2 = extract_packet(&mut buf).unwrap();
+    assert_eq!(&buf[..], b"World");
+    assert_eq!(&packet2[..], b"Hello");
+
+    if let Some(_) = extract_packet(&mut buf) {
+        assert!(false)
+    }
+}