playerbot/src/handlers/minecraft.rs
2026-05-06 15:09:36 -04:00

141 lines
3.9 KiB
Rust

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<String>,
players: Option<ApiResponsePlayers>,
motd: Option<Motd>,
}
#[derive(Deserialize, Debug, Clone)]
struct ApiResponsePlayers {
online: u64,
max: u64,
list: Option<Vec<ApiResponsePlayerEntry>>,
}
#[derive(Deserialize, Debug, Clone)]
struct ApiResponsePlayerEntry {
name: String,
#[allow(dead_code)]
uuid: String,
}
#[derive(Deserialize, Debug)]
#[allow(dead_code)]
struct Motd {
raw: Vec<String>,
clean: Vec<String>,
html: Vec<String>,
}
#[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<String>,
}
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<String> {
&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<Self::OnlineResponse> {
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::<ApiResponse>().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::<ApiResponsePlayerEntry>::new())
.iter()
.map(|e| e.name.clone())
.collect(),
})
}
false => ServerResponse::Offline,
}
}
}
}
}