rust/hedgewars-checker/src/main.rs
author unC0Rr
Wed, 01 May 2024 16:49:16 +0200
changeset 16012 caba603f461f
parent 15980 39ae4ed7de6e
permissions -rw-r--r--
Allow to move camera by dragging mouse cursor over game field
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
     1
use anyhow::{anyhow, bail, Result};
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
     2
use argparse::{ArgumentParser, Store};
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
     3
use base64::{engine::general_purpose, Engine};
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
     4
use hedgewars_network_protocol::{
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
     5
    messages::HwProtocolMessage as ClientMessage, messages::HwServerMessage::*, parser,
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
     6
};
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
     7
use ini::Ini;
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
     8
use log::{debug, info, warn};
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
     9
use netbuf::Buf;
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
    10
use std::{io::Write, str::FromStr};
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
    11
use tokio::time::MissedTickBehavior;
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
    12
use tokio::{io, io::AsyncWriteExt, net::TcpStream, process::Command, sync::mpsc};
13953
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    13
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
    14
async fn check(executable: &str, data_prefix: &str, buffer: &[String]) -> Result<Vec<String>> {
13953
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    15
    let mut replay = tempfile::NamedTempFile::new()?;
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    16
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
    17
    for line in buffer.iter() {
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
    18
        replay.write_all(&general_purpose::STANDARD.decode(line)?)?;
13953
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    19
    }
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    20
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    21
    let temp_file_path = replay.path();
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    22
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
    23
    let mut home_dir = dirs::home_dir().ok_or(anyhow!("Home path not detected"))?;
13953
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    24
    home_dir.push(".hedgewars");
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    25
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    26
    debug!("Checking replay in {}", temp_file_path.to_string_lossy());
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    27
13953
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    28
    let output = Command::new(executable)
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    29
        .arg("--user-prefix")
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    30
        .arg(&home_dir)
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    31
        .arg("--prefix")
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    32
        .arg(data_prefix)
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    33
        .arg("--nomusic")
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    34
        .arg("--nosound")
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    35
        .arg("--stats-only")
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    36
        .arg(temp_file_path)
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
    37
        //.spawn()?
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
    38
        //.wait_with_output()
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
    39
        .output()
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
    40
        .await?;
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
    41
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
    42
    debug!("Engine finished!");
13953
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    43
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    44
    let mut result = Vec::new();
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    45
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    46
    let mut engine_lines = output
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    47
        .stderr
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
    48
        .split(|b| *b == b'\n')
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    49
        .skip_while(|l| *l != b"WINNERS" && *l != b"DRAW");
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    50
15888
0cd6996cd4c8 Remove stray debugging
unc0rr
parents: 15887
diff changeset
    51
    // debug!("Engine lines: {:?}", &engine_lines);
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
    52
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    53
    loop {
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    54
        match engine_lines.next() {
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
    55
            Some(b"DRAW") => result.push("DRAW".to_owned()),
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    56
            Some(b"WINNERS") => {
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
    57
                result.push("WINNERS".to_owned());
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    58
                let winners = engine_lines.next().unwrap();
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    59
                let winners_num = u32::from_str(&String::from_utf8(winners.to_vec())?)?;
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
    60
                result.push(String::from_utf8(winners.to_vec())?);
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    61
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    62
                for _i in 0..winners_num {
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
    63
                    result.push(String::from_utf8(engine_lines.next().unwrap().to_vec())?);
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    64
                }
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    65
            }
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    66
            Some(b"GHOST_POINTS") => {
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
    67
                result.push("GHOST_POINTS".to_owned());
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    68
                let points = engine_lines.next().unwrap();
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    69
                let points_num = u32::from_str(&String::from_utf8(points.to_vec())?)? * 2;
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
    70
                result.push(String::from_utf8(points.to_vec())?);
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    71
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    72
                for _i in 0..points_num {
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
    73
                    result.push(String::from_utf8(engine_lines.next().unwrap().to_vec())?);
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    74
                }
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    75
            }
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    76
            Some(b"ACHIEVEMENT") => {
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
    77
                result.push("ACHIEVEMENT".to_owned());
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    78
                for _i in 0..4 {
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
    79
                    result.push(String::from_utf8(engine_lines.next().unwrap().to_vec())?);
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    80
                }
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    81
            }
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    82
            _ => break,
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    83
        }
13953
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    84
    }
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    85
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
    86
    // println!("Engine lines: {:?}", &result);
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
    87
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
    88
    if !result.is_empty() {
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    89
        Ok(result)
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    90
    } else {
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
    91
        bail!("no data from engine")
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
    92
    }
13953
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    93
}
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
    94
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
    95
async fn check_loop(
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
    96
    executable: &str,
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
    97
    data_prefix: &str,
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
    98
    results_sender: mpsc::Sender<Result<Vec<String>>>,
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
    99
    mut replay_receiver: mpsc::Receiver<Vec<String>>,
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   100
) -> Result<()> {
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   101
    while let Some(replay) = replay_receiver.recv().await {
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   102
        results_sender
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   103
            .send(check(executable, data_prefix, &replay).await)
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   104
            .await?;
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   105
    }
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   106
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   107
    Ok(())
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   108
}
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   109
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   110
async fn connect_and_run(
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   111
    username: &str,
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   112
    password: &str,
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   113
    protocol_number: u16,
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   114
    replay_sender: mpsc::Sender<Vec<String>>,
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   115
    mut results_receiver: mpsc::Receiver<Result<Vec<String>>>,
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   116
) -> Result<()> {
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   117
    info!("Connecting...");
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   118
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   119
    let mut stream = TcpStream::connect("hedgewars.org:46631").await?;
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   120
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   121
    let mut buf = Buf::new();
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   122
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   123
    let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(30));
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   124
    interval.set_missed_tick_behavior(MissedTickBehavior::Delay);
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   125
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   126
    loop {
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   127
        let r = tokio::select! {
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   128
            _ = interval.tick() => {
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   129
                // Send Ping
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   130
                stream.write_all(ClientMessage::Ping.to_raw_protocol().as_bytes()).await?;
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   131
                None
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   132
            },
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   133
            _ = stream.readable() => None,
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   134
            r = results_receiver.recv() => r
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   135
        };
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   136
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   137
        //println!("Loop: {:?}", &r);
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   138
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   139
        if let Some(execution_result) = r {
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   140
            match execution_result {
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   141
                Ok(result) => {
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   142
                    info!("Checked");
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   143
                    debug!("Check result: [{:?}]", result);
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   144
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   145
                    stream
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   146
                        .write_all(
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   147
                            ClientMessage::CheckedOk(result)
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   148
                                .to_raw_protocol()
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   149
                                .as_bytes(),
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   150
                        )
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   151
                        .await?;
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   152
                    stream
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   153
                        .write_all(ClientMessage::CheckerReady.to_raw_protocol().as_bytes())
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   154
                        .await?;
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   155
                }
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   156
                Err(e) => {
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   157
                    info!("Check failed: {:?}", e);
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   158
                    stream
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   159
                        .write_all(
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   160
                            ClientMessage::CheckedFail("error".to_owned())
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   161
                                .to_raw_protocol()
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   162
                                .as_bytes(),
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   163
                        )
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   164
                        .await?;
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   165
                    stream
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   166
                        .write_all(ClientMessage::CheckerReady.to_raw_protocol().as_bytes())
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   167
                        .await?;
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   168
                }
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   169
            }
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   170
        } else {
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   171
            let mut msg = [0; 4096];
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   172
            // Try to read data, this may still fail with `WouldBlock`
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   173
            // if the readiness event is a false positive.
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   174
            match stream.try_read(&mut msg) {
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   175
                Ok(n) => {
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   176
                    //println!("{:?}", &msg);
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   177
                    buf.write_all(&msg[0..n])?;
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   178
                }
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   179
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   180
                Err(e) => {
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   181
                    return Err(e.into());
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   182
                }
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   183
            }
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   184
        }
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   185
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   186
        while let Ok((tail, msg)) = parser::server_message(buf.as_ref()) {
15812
8c39a11f7756 eat warnings
alfadur
parents: 15811
diff changeset
   187
            let tail_len = tail.len();
8c39a11f7756 eat warnings
alfadur
parents: 15811
diff changeset
   188
            buf.consume(buf.len() - tail_len);
13953
e98e2fc556a7 Create replay file, run engine, result from it and send it to the server. Not implemented: filtering of engine output.
unc0rr
parents: 13952
diff changeset
   189
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   190
            // println!("Message from server: {:?}", &msg);
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   191
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   192
            match msg {
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   193
                Connected(_, _) => {
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   194
                    info!("Connected");
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   195
                    stream
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   196
                        .write_all(
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   197
                            ClientMessage::Checker(
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   198
                                protocol_number,
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   199
                                username.to_owned(),
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   200
                                password.to_owned(),
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   201
                            )
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   202
                            .to_raw_protocol()
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   203
                            .as_bytes(),
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   204
                        )
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   205
                        .await?;
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   206
                }
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   207
                Ping => {
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   208
                    stream
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   209
                        .write_all(ClientMessage::Pong.to_raw_protocol().as_bytes())
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   210
                        .await?;
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   211
                }
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   212
                Pong => {
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   213
                    // do nothing
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   214
                }
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   215
                LogonPassed => {
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   216
                    stream
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   217
                        .write_all(ClientMessage::CheckerReady.to_raw_protocol().as_bytes())
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   218
                        .await?;
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   219
                }
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   220
                Replay(lines) => {
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   221
                    info!("Got a replay");
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   222
                    replay_sender.send(lines).await?;
13955
a857cd1cc3f0 Finish hedgewars-checker implementation
unc0rr
parents: 13953
diff changeset
   223
                }
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   224
                Bye(message) => {
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   225
                    warn!("Received BYE: {}", message);
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   226
                    return Ok(());
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   227
                }
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   228
                ChatMsg { nick, msg } => {
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   229
                    info!("Chat [{}]: {}", nick, msg);
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   230
                }
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   231
                RoomAdd(fields) => {
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   232
                    let mut l = fields.into_iter();
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   233
                    info!("Room added: {}", l.nth(1).unwrap());
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   234
                }
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   235
                RoomUpdated(name, fields) => {
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   236
                    let mut l = fields.into_iter();
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   237
                    let new_name = l.nth(1).unwrap();
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   238
15812
8c39a11f7756 eat warnings
alfadur
parents: 15811
diff changeset
   239
                    if name != new_name {
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   240
                        info!("Room renamed: {}", new_name);
13957
a4877a16564d Also report chat and added rooms in log
unc0rr
parents: 13955
diff changeset
   241
                    }
a4877a16564d Also report chat and added rooms in log
unc0rr
parents: 13955
diff changeset
   242
                }
15811
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   243
                RoomRemove(_) => {
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   244
                    // ignore
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   245
                }
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   246
                Error(message) => {
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   247
                    warn!("Received ERROR: {}", message);
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   248
                    return Ok(());
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   249
                }
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   250
                something => {
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   251
                    warn!("Unexpected protocol command: {:?}", something)
a855f32ab3ca - Update hedgewars-network-protocol library with messages needed for checker
unc0rr
parents: 14396
diff changeset
   252
                }
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   253
            }
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   254
        }
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   255
    }
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   256
}
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   257
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   258
async fn get_protocol_number(executable: &str) -> Result<u16> {
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   259
    let output = Command::new(executable).arg("--protocol").output().await?;
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   260
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   261
    Ok(u16::from_str(String::from_utf8(output.stdout)?.trim()).unwrap_or(55))
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   262
}
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   263
15813
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   264
#[tokio::main]
ad79e5c0885c Begin attempt to convert checker into async using tokio
unc0rr
parents: 15812
diff changeset
   265
async fn main() -> Result<()> {
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   266
    stderrlog::new()
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   267
        .verbosity(3)
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   268
        .timestamp(stderrlog::Timestamp::Second)
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   269
        .module(module_path!())
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   270
        .init()?;
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   271
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   272
    let mut frontend_settings = dirs::home_dir().ok_or(anyhow!("Home path not detected"))?;
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   273
    frontend_settings.push(".hedgewars/settings.ini");
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   274
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   275
    let i = Ini::load_from_file(frontend_settings.to_str().unwrap()).unwrap();
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   276
    let username = i
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   277
        .get_from(Some("net"), "nick")
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   278
        .ok_or(anyhow!("Nickname not found in frontend config"))?;
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   279
    let password = i
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   280
        .get_from(Some("net"), "passwordhash")
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   281
        .ok_or(anyhow!("Password not found in frontend config"))?;
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   282
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   283
    let mut exe = "/usr/local/bin/hwengine".to_string();
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   284
    let mut prefix = "/usr/local/share/hedgewars/Data".to_string();
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   285
    {
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   286
        let mut ap = ArgumentParser::new();
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   287
        ap.set_description("Game replay checker for hedgewars.");
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   288
        ap.refer(&mut exe)
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   289
            .add_option(&["--exe"], Store, "Path to hwengine executable");
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   290
        ap.refer(&mut prefix)
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   291
            .add_option(&["--prefix"], Store, "Path main Data dir");
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   292
        ap.parse_args_or_exit();
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   293
    }
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   294
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   295
    info!("Executable: {}", exe);
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   296
    info!("Data dir: {}", prefix);
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   297
15980
39ae4ed7de6e Implement pinging of the server every 30 seconds
unC0Rr
parents: 15979
diff changeset
   298
    let protocol_number = get_protocol_number(exe.as_str()).await?;
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   299
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   300
    info!("Using protocol number {}", protocol_number);
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   301
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   302
    let (replay_sender, replay_receiver) = mpsc::channel(1);
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   303
    let (results_sender, results_receiver) = mpsc::channel(1);
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   304
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   305
    let (network_result, checker_result) = tokio::join!(
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   306
        connect_and_run(
15979
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   307
            username,
1635ce22b214 Adopt more recent versions of dependencies, apply clippy fixes
unC0Rr
parents: 15888
diff changeset
   308
            password,
15887
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   309
            protocol_number,
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   310
            replay_sender,
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   311
            results_receiver
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   312
        ),
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   313
        check_loop(&exe, &prefix, results_sender, replay_receiver)
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   314
    );
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   315
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   316
    network_result?;
fe519de9c270 - Run engine and socket listener in parallel to avoid ping timeouts
unc0rr
parents: 15813
diff changeset
   317
    checker_result
13952
d12ca66054aa Start checker implementation in rust
unc0rr
parents:
diff changeset
   318
}