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[..]) |