use reqwest::{header::HeaderValue, Client}; use serde::Deserialize; use url::Url; use crate::types::{PlayerList, ServerInfo, ServerOnlineResponse, ServerResponse}; #[derive(Deserialize, Debug)] struct ApiResponse { online: bool, version: Option, players: Option, motd: Option, } #[derive(Deserialize, Debug, Clone)] struct ApiResponsePlayers { online: u64, max: u64, list: Option>, } #[derive(Deserialize, Debug, Clone)] struct ApiResponsePlayerEntry { name: String, #[allow(dead_code)] uuid: String, } #[derive(Deserialize, Debug)] #[allow(dead_code)] struct Motd { raw: Vec, clean: Vec, html: Vec, } #[derive(Debug)] #[allow(dead_code)] pub struct OnlineResponse { searchable_name: String, reported_name: String, clean_name: String, players_online: u64, player_limit: u64, version: String, players: Vec, } impl ServerOnlineResponse for OnlineResponse { fn players_online(&self) -> u64 { self.players_online } fn player_limit(&self) -> u64 { self.player_limit } fn version(&self) -> &String { &self.version } fn readable_name(&self) -> &String { &self.clean_name } fn searchable_name(&self) -> &String { &self.searchable_name } } impl PlayerList for OnlineResponse { fn players(&self) -> &Vec { &self.players } } pub struct Server { #[allow(dead_code)] token: String, addr: Url, } impl ServerInfo for Server { fn new(token: String, addr: Url) -> Self { Server { token, addr } } type OnlineResponse = OnlineResponse; type AddressableName = Url; fn addressable_name(&self) -> &Self::AddressableName { &self.addr } fn app_token(&self) -> String { self.token.clone() } async fn poll(&self) -> ServerResponse { use reqwest; let url_string = format!("https://api.mcsrvstat.us/3/{}", self.addr.host().unwrap()); let url = Url::try_from(url_string.as_str()).unwrap(); let mut request = reqwest::Request::new(reqwest::Method::GET, url); request.headers_mut().append("User-Agent", HeaderValue::from_str("Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36").unwrap()); let client = Client::new(); match client.execute(request).await { Err(error) => ServerResponse::Error(anyhow::anyhow!(error)), Ok(answer) => { let json = answer.json::().await.unwrap(); //println!("{}", answer.text().await.unwrap()); //ServerResponse::Offline match json.online { true => { let players = json.players.unwrap(); let motd = json.motd.as_ref().unwrap(); self::ServerResponse::Online(OnlineResponse { searchable_name: self.addr.host().unwrap().to_string(), reported_name: motd.clean.first().unwrap().into(), clean_name: motd.clean.first().unwrap().into(), players_online: players.online, player_limit: players.max, version: json.version.unwrap(), players: players .list .unwrap_or(Vec::::new()) .iter() .map(|e| e.name.clone()) .collect(), }) } false => ServerResponse::Offline, } } } } }