diff --git a/src/main.rs b/src/main.rs index c5a602d..d7c0c40 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,18 +16,21 @@ use crate::ping::ping_server; async fn main() { // Handle config file let config_file: String = std::env::args().nth(1).unwrap_or("config.toml".to_string()); - let config: Config = load_config(config_file); + let config: &Config = &load_config(config_file); // Create database URL let database_url = format!("postgresql://{}:{}@{}/postgres", - &config.database.user, - &config.database.password, - &config.database.url); - - let mut conn: PgConnection = connect(&database_url); + config.database.user, + config.database.password, + config.database.url); // let address: &str = "192.168.1.220"; let address: &str = "51.161.87.128"; + // let address: &str = "127.0.0.1"; let port: u16 = 25565; let server = ping_server(&address, &port).await; + + if let Ok(server) = server { + println!("Server {:?} responded! Version: {:?}, MOTD: {:?}, Chat Reports: {:?}", &address, &server.version, &server.motd, &server.prevents_reports); + } } \ No newline at end of file diff --git a/src/ping.rs b/src/ping.rs index 9d86887..4abccd9 100644 --- a/src/ping.rs +++ b/src/ping.rs @@ -49,7 +49,7 @@ pub async fn ping_server(address: &str, port: &u16) -> Result { ] ).to_string(); - Ok(parse_response(response.as_str())) + Ok(parse_response(response.as_str())?) } Err(_) => { Err(Error::new(ErrorKind::NetworkUnreachable, "Server did not respond.")) diff --git a/src/response.rs b/src/response.rs index 1fd5c37..fc5ef45 100644 --- a/src/response.rs +++ b/src/response.rs @@ -5,7 +5,7 @@ use serde_json::Value; pub struct Server { pub version: Option, - pub protocol: Option, + pub protocol: Option, pub icon: Option, pub motd: Option, pub prevents_reports: Option, @@ -25,88 +25,106 @@ pub struct Mod { pub mod_name: String, } -// None values should insert NULL into the database if no value is found -impl Default for Server { - fn default() -> Self { - Server { - version: None, - protocol: None, - icon: None, - motd: None, - prevents_reports: None, - enforces_secure_chat: None, - mods: None, - players: None, +// Lifetimes *should* solve this mess +// Recursive JSON array/object parser +fn parse_motd(motd: &Value, mut current_motd: String) -> Result { + let mut current_motd = current_motd.clone(); + + if let Some(object) = motd.as_object() { + if object.contains_key("color") { + ¤t_motd.push_str(&object["color"].to_string()); } - } -} -// Lifetimes will solve this mess -fn parse_motd(motd: Value) -> Result { - if motd.is_array() { - for value in motd.as_array() { - // Recursion - if value.is_object() || value.is_array() { - parse_motd(value.clone())?; - } else {} + if object.contains_key("bold") { + ¤t_motd.push_str("§l"); } - } else { - if let Some(object) = motd.as_object() { - for value in object { - // Recursion - if value.is_object() || value.is_array() { - parse_motd(value.clone())?; - } - if let Some(color) = value.get("color") {} + if object.contains_key("underlined") { + ¤t_motd.push_str("§n"); + } - if let Some(bold) = value.get("bold") {} - - if let Some(text) = value.get("text") {} + if object.contains_key("text") { + if let Some(text) = object["text"].as_str() { + current_motd.push_str(text); } } + + if object.contains_key("extra") { + match object.get("extra") { + Some(extra) => parse_motd(extra, current_motd.clone())?, + None => Err(Error::new(ErrorKind::InvalidData, "Extra array malformed"))?, + }; + } + + Ok(current_motd) + } else { + if let Some(array) = motd.as_array() { + for value in array { + if value.is_object() || value.is_array() { + parse_motd(value, current_motd.clone())?; + } else { + ¤t_motd.push_str(value.as_str().unwrap()); + } + } + } + + Ok(current_motd) } } // I no longer care about trying to make the parsing code good, // there is no proper standard for how servers should respond so this is what you get pub fn parse_response(response: &str) -> Result { - let json = Value::from_str(response)?; + let json = match Value::from_str(response) { + Ok(json) => json, + Err(err) => return Err(Error::new(ErrorKind::InvalidData, format!("{:?}", err))) + }; - let mut version = (); - let mut protocol = (); + let mut version: Option = None; + let mut protocol: Option = None; + let mut icon: Option = None; + let mut motd: Option = None; + let mut prevents_reports: Option = None; + let mut enforces_secure_chat: Option = None; + let mut mods: Option> = None; + let mut players: Option> = None; // TODO! I think I can make this all better if let Some(value) = json.get("version") { - if let Some(name) = json.get("name") { - version = version.as_str(); + if let Some(name) = value.get("name") { + version = name.as_str().map(|s| s.to_string()); } - if let Some(value) = json.get("protocol") { + if let Some(value) = value.get("protocol") { protocol = value.as_i64() } } - let protocol = json["version"]["protocol"].as_i64(); - let icon = json["favicon"].to_string(); - let prevents_reports = json["preventsReports"].as_bool(); - let enforces_secure_chat = json["enforceSecure"].as_bool(); - - let motd: String; - if json["description"].is_object() { - // motd = parse_motd(json.get("description").clone(), &mut "".to_string()); - } else { - motd = json.get("description").unwrap().to_string(); + if let Some(value) = json.get("icon") { + icon = value.as_str().map(|s| s.to_string()) } - println!("{}", motd); + if let Some(value) = json.get("description") { + motd = match parse_motd(value, "".to_string()) { + Ok(description) => Some(description), + Err(_) => None, + }; + } + + if let Some(value) = json.get("preventsChatReports") { + prevents_reports = value.as_bool(); + } + + if let Some(value) = json.get("enforceSecureChat") { + enforces_secure_chat = value.as_bool(); + } Ok(Server { - version: None, - protocol: None, - icon: None, - motd: None, - prevents_reports: None, + version, + protocol, + icon, + motd, + prevents_reports, enforces_secure_chat, mods: None, players: None,