Kon/src/commands/status.rs

159 lines
4.6 KiB
Rust
Raw Normal View History

2024-01-30 07:17:59 -05:00
use crate::{
Error,
models::gameservers::Gameservers,
commands::gameserver::ac_server_name,
utils::BOT_VERSION,
utils::EMBED_COLOR
2024-01-30 07:17:59 -05:00
};
2023-12-07 22:01:13 -05:00
use std::{
collections::HashMap,
env::var
};
use reqwest::{
Client,
header::USER_AGENT
};
2024-02-05 06:49:04 -05:00
use tokio::join;
use poise::CreateReply;
use serenity::builder::CreateEmbed;
2024-01-01 22:42:40 -05:00
use once_cell::sync::Lazy;
2024-02-05 06:49:04 -05:00
use serde::Deserialize;
2023-12-07 22:01:13 -05:00
use serde_json::Value;
2024-01-01 22:42:40 -05:00
static PMS_BASE: Lazy<String> = Lazy::new(||
var("WG_PMS").expect("Expected a \"WG_PMS\" in the envvar but none was found")
);
2023-12-07 22:01:13 -05:00
2024-02-05 06:49:04 -05:00
#[derive(Deserialize)]
struct MinecraftQueryData {
motd: Option<MinecraftMotd>,
players: Option<MinecraftPlayers>,
version: Option<String>,
2024-02-05 06:49:04 -05:00
online: bool
}
2024-02-05 06:49:04 -05:00
#[derive(Deserialize)]
struct MinecraftMotd {
clean: Vec<String>
}
#[derive(Deserialize, Clone, Copy)]
2024-02-05 06:49:04 -05:00
struct MinecraftPlayers {
online: i32,
max: i32
}
async fn pms_serverstatus(url: &str) -> Result<Vec<Value>, Error> {
let client = Client::new();
let req = client.get(url)
.header(USER_AGENT, format!("Kon/{}/Rust", &**BOT_VERSION))
.send()
.await?;
let response = req.json::<HashMap<String, Value>>().await?;
let servers = response["data"].as_array().unwrap()[0]["servers_statuses"]["data"].as_array().unwrap().clone();
Ok(servers)
}
2024-02-05 06:49:04 -05:00
async fn gs_query_minecraft(server_ip: &str) -> Result<MinecraftQueryData, Error> {
let client = Client::new();
let req = client.get(format!("https://api.mcsrvstat.us/2/{}", server_ip))
.header(USER_AGENT, format!("Kon/{}/Rust", &**BOT_VERSION))
2024-02-05 06:49:04 -05:00
.send()
.await?;
if req.status().is_success() {
let data: MinecraftQueryData = req.json().await?;
Ok(data)
} else if req.status().is_server_error() {
Err(Error::from("Webserver returned a 5xx error."))
2024-02-05 06:49:04 -05:00
} else {
2024-02-23 09:03:03 -05:00
Err(Error::from("Failed to query the server."))
}
2024-02-05 06:49:04 -05:00
}
2024-02-05 06:49:04 -05:00
/// Query the server statuses
#[poise::command(slash_command, subcommands("wg", "gs"), subcommand_required)]
pub async fn status(_: poise::Context<'_, (), Error>) -> Result<(), Error> {
Ok(())
}
/// Retrieve the server statuses from Wargaming
2023-12-07 22:01:13 -05:00
#[poise::command(slash_command)]
pub async fn wg(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
let pms_asia = &PMS_BASE;
let pms_eu = PMS_BASE.replace("asia", "eu");
let embed = CreateEmbed::new().color(EMBED_COLOR);
2023-12-07 22:01:13 -05:00
let (servers_asia, servers_eu) = join!(pms_serverstatus(&pms_asia), pms_serverstatus(&pms_eu));
2023-12-07 22:01:13 -05:00
let mut embed_fields = Vec::new();
for server in servers_eu.unwrap() {
2023-12-07 22:01:13 -05:00
let name = server["name"].as_str().unwrap().to_owned();
let status = match server["availability"].as_str().unwrap() {
"1" => "Online",
"-1" => "Offline",
_ => "Unknown"
};
embed_fields.push((name, status, true));
2023-12-07 22:01:13 -05:00
}
for server in servers_asia.unwrap() {
2023-12-07 22:01:13 -05:00
let name = server["name"].as_str().unwrap().to_owned();
let status = match server["availability"].as_str().unwrap() {
"1" => "Online",
"-1" => "Offline",
_ => "Unknown"
};
embed_fields.push((name, status, true));
2023-12-07 22:01:13 -05:00
}
ctx.send(CreateReply::default().embed(embed.title("World of Tanks Server Status").fields(embed_fields))).await?;
2023-12-07 22:01:13 -05:00
Ok(())
}
2024-01-30 07:17:59 -05:00
2024-02-05 06:49:04 -05:00
/// Retrieve the given server data from gameservers DB
2024-01-30 07:17:59 -05:00
#[poise::command(slash_command, guild_only)]
2024-02-05 06:49:04 -05:00
pub async fn gs(
ctx: poise::Context<'_, (), Error>,
#[description = "Server name"] #[autocomplete = "ac_server_name"] server_name: String
) -> Result<(), Error> {
2024-02-05 06:49:04 -05:00
let server_data = Gameservers::get_server_data(ctx.guild_id().unwrap().into(), &server_name).await?;
// Extract values from a Vec above
let game_name = &server_data[1];
2024-02-23 09:03:03 -05:00
let ip_address = &server_data[2];
2024-02-05 06:49:04 -05:00
match game_name.as_str() {
"Minecraft" => {
let result = gs_query_minecraft(ip_address).await?;
let embed = CreateEmbed::new().color(EMBED_COLOR);
if result.online {
let mut embed_fields = Vec::new();
embed_fields.push(("Server IP".to_owned(), ip_address.to_owned(), true));
embed_fields.push((format!("\u{200b}"), format!("\u{200b}"), true));
embed_fields.push(("MOTD".to_owned(), format!("{}", result.motd.unwrap().clean[0]), true));
embed_fields.push(("Players".to_owned(), format!("**{}**/**{}**", result.players.unwrap().online, result.players.clone().unwrap().max), true));
embed_fields.push(("Version".to_owned(), result.version.unwrap(), true));
2024-02-05 06:49:04 -05:00
ctx.send(CreateReply::default()
.embed(embed
.title(server_name)
.fields(embed_fields)
)
).await?;
} else {
ctx.send(CreateReply::default()
.content(format!("**{}** (`{}`) is currently offline or unreachable.", server_name, ip_address))
2024-02-05 06:49:04 -05:00
).await?;
}
},
2024-02-23 09:03:03 -05:00
_ => {}
}
2024-02-05 06:49:04 -05:00
2024-01-30 07:17:59 -05:00
Ok(())
}