1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
pub mod error;
pub mod player_info;
pub mod server_info;
use crate::error::Q3Error;
use crate::server_info::ServerInfo;
use format_bytes::format_bytes;
use std::net;
#[derive(Debug)]
pub struct Q3Tool {
password: Option<String>,
host: String,
}
impl Q3Tool {
pub fn new(host: &str, password: Option<String>) -> Self {
Self {
host: host.to_owned(),
password,
}
}
pub fn get_status(&self) -> Result<ServerInfo, Q3Error> {
let info = self.send_request()?;
let info = Self::parse_response(info)?;
Ok(info)
}
pub fn rcon(&self, command: &str) -> Result<String, Q3Error> {
let socket = self.create_socket()?;
let mut buffer = [0; 2048];
let request = format_bytes!(
b"\xFF\xFF\xFF\xFFrcon {} {}",
self.password.as_ref().unwrap().as_bytes(),
command.as_bytes()
);
socket.send(&request)?;
socket.recv(&mut buffer)?;
let response = String::from_utf8_lossy(&buffer).into_owned();
Ok(response)
}
fn create_socket(&self) -> Result<net::UdpSocket, Q3Error> {
let socket = net::UdpSocket::bind("0.0.0.0:0")?;
socket.connect(&self.host)?;
Ok(socket)
}
fn send_request(&self) -> Result<String, Q3Error> {
let socket = self.create_socket()?;
let mut buffer = [0; 2048];
socket.send(b"\xFF\xFF\xFF\xFFgetstatus")?;
socket.recv(&mut buffer)?;
let info = String::from_utf8_lossy(&buffer).into_owned();
Ok(info)
}
fn parse_response(raw_info: String) -> Result<ServerInfo, Q3Error> {
if let Some((_header, info)) = raw_info.split_once('\n') {
Ok(ServerInfo::new(info.to_string())?)
} else {
Err(Q3Error::InvalidResponse)
}
}
}