Preserve input values and pair them to results
[hlquery.git] / src / main.rs
1 use std::fmt;
2 use std::fmt::Display;
3 use std::error::Error;
4 use std::env::args;
5 use std::net::{SocketAddr, SocketAddrV4, ToSocketAddrs};
6 use serde::{Serialize, Serializer};
7 use a2s::A2SClient;
8 use crate::HLQueryError::{IOError,A2SError};
9
10 #[derive(Debug, Serialize)]
11 struct HLQueryResult {
12 address: SocketAddrV4,
13 info: Result<a2s::info::Info, HLQueryError>,
14 rules: Result<Vec<a2s::rules::Rule>, HLQueryError>,
15 players: Result<Vec<a2s::players::Player>, HLQueryError>
16 }
17
18 impl HLQueryResult {
19 fn new(a2s_client: &A2SClient, server: SocketAddrV4) -> Self {
20 Self {
21 address: server,
22 info: a2s_client.info(server).map_err(From::from),
23 rules: a2s_client.rules(server).map_err(From::from),
24 players: a2s_client.players(server).map_err(From::from)
25 }
26 }
27 }
28
29 #[derive(Debug, Serialize)]
30 struct HLQuery {
31 input: String,
32 result: Result<Vec<HLQueryResult>, HLQueryError>
33 }
34
35 impl HLQuery {
36 fn new(input: String, result: Result<Vec<HLQueryResult>, HLQueryError>) -> Self {
37 Self { input, result }
38 }
39 }
40
41 #[derive(Debug)]
42 enum HLQueryError {
43 IOError(std::io::Error),
44 A2SError(a2s::errors::Error)
45 }
46
47 impl Display for HLQueryError {
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 match self {
50 IOError(e) => write!(f, "{:?}", e),
51 A2SError(e) => write!(f, "{:?}", e)
52 }
53 }
54 }
55
56 impl Error for HLQueryError {}
57
58 impl Serialize for HLQueryError {
59 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
60 where
61 S: Serializer,
62 {
63 serializer.serialize_str(&format!("{self}"))
64 }
65 }
66
67 impl From<std::io::Error> for HLQueryError {
68 fn from(e: std::io::Error) -> Self {
69 Self::IOError(e)
70 }
71 }
72
73 impl From<a2s::errors::Error> for HLQueryError {
74 fn from(e: a2s::errors::Error) -> Self {
75 Self::A2SError(e)
76 }
77 }
78
79
80 fn main() {
81 let client = A2SClient::new().unwrap();
82 let query_results: Vec<HLQuery> = args().skip(1)
83 .map(|arg| {
84 let addresses = arg.to_socket_addrs();
85 (arg, addresses)
86 })
87 .map(|lookup_result| match lookup_result {
88 (input, Ok(iter_addr)) => {
89 (input, Ok(iter_addr.filter_map(|sa| match sa {
90 SocketAddr::V4(sa4) => Some(sa4),
91 _ => None
92 })))
93 },
94 (input, Err(e)) => (input, Err(HLQueryError::IOError(e)))
95 })
96 .map(|(input, address_group)| HLQuery::new(input, address_group.map(
97 |addresses| addresses.map(|addr| HLQueryResult::new(&client, addr)).collect())))
98 .collect();
99
100 println!("{}\n", serde_json::to_string_pretty(&query_results).unwrap());
101 }