2024-01-30 07:17:59 -05:00
|
|
|
use crate::{
|
2024-02-01 02:00:57 -05:00
|
|
|
Error,
|
|
|
|
models::gameservers::Gameservers,
|
2024-03-12 07:39:17 -04:00
|
|
|
commands::gameserver::ac_server_name,
|
2024-03-15 18:41:33 -04:00
|
|
|
internals::utils::EMBED_COLOR,
|
|
|
|
internals::http::HttpClient
|
2024-01-30 07:17:59 -05:00
|
|
|
};
|
2023-12-07 22:01:13 -05:00
|
|
|
|
2023-12-29 07:00:44 -05:00
|
|
|
use std::{
|
|
|
|
collections::HashMap,
|
|
|
|
env::var
|
|
|
|
};
|
2024-02-05 06:49:04 -05:00
|
|
|
use tokio::join;
|
2024-01-11 21:41:29 -05:00
|
|
|
use poise::CreateReply;
|
2024-03-20 17:35:44 -04:00
|
|
|
use poise::serenity_prelude::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 {
|
2024-03-10 19:04:12 -04:00
|
|
|
motd: Option<MinecraftMotd>,
|
|
|
|
players: Option<MinecraftPlayers>,
|
|
|
|
version: Option<String>,
|
2024-02-05 06:49:04 -05:00
|
|
|
online: bool
|
2023-12-30 23:57:27 -05:00
|
|
|
}
|
|
|
|
|
2024-02-05 06:49:04 -05:00
|
|
|
#[derive(Deserialize)]
|
|
|
|
struct MinecraftMotd {
|
|
|
|
clean: Vec<String>
|
|
|
|
}
|
2024-02-01 02:00:57 -05:00
|
|
|
|
2024-03-10 19:04:12 -04:00
|
|
|
#[derive(Deserialize, Clone, Copy)]
|
2024-02-05 06:49:04 -05:00
|
|
|
struct MinecraftPlayers {
|
|
|
|
online: i32,
|
|
|
|
max: i32
|
2024-02-01 02:00:57 -05:00
|
|
|
}
|
|
|
|
|
2024-03-22 19:06:05 -04:00
|
|
|
async fn pms_serverstatus(url: &str) -> Result<Vec<(String, Vec<Value>)>, Error> {
|
2024-03-15 18:41:33 -04:00
|
|
|
let client = HttpClient::new();
|
|
|
|
let req = client.get(url).await?;
|
|
|
|
|
2023-12-30 23:57:27 -05:00
|
|
|
let response = req.json::<HashMap<String, Value>>().await?;
|
2024-03-22 19:41:29 -04:00
|
|
|
let data = response["data"].as_array().unwrap();
|
2024-03-22 19:06:05 -04:00
|
|
|
|
|
|
|
let mut servers = Vec::new();
|
|
|
|
for item in data {
|
|
|
|
if let Some(title) = item["title"].as_str() {
|
|
|
|
if let Some(servers_statuses) = item["servers_statuses"]["data"].as_array() {
|
|
|
|
if !servers_statuses.is_empty() {
|
|
|
|
servers.push((title.to_owned(), servers_statuses.clone()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-12-30 23:57:27 -05:00
|
|
|
|
|
|
|
Ok(servers)
|
|
|
|
}
|
|
|
|
|
2024-03-22 19:06:05 -04:00
|
|
|
fn process_pms_statuses(servers: Vec<(String, Vec<Value>)>) -> Vec<(String, String, bool)> {
|
|
|
|
let mut server_map: HashMap<String, Vec<(String, String)>> = HashMap::new();
|
|
|
|
let id_name_map: HashMap<&str, &str> = [
|
|
|
|
("wotbsg", "ASIA"),
|
|
|
|
("wowssg", "WoWS (ASIA)"),
|
|
|
|
("wowseu", "WoWS (EU)")
|
|
|
|
].iter().cloned().collect();
|
|
|
|
|
|
|
|
for (title, mapped_servers) in servers {
|
|
|
|
for server in mapped_servers {
|
2024-03-20 17:55:48 -04:00
|
|
|
let name = server["name"].as_str().unwrap();
|
2024-03-22 19:06:05 -04:00
|
|
|
let id = server["id"].as_str().unwrap().split(":").next().unwrap_or("");
|
2024-03-20 17:55:48 -04:00
|
|
|
let status = match server["availability"].as_str().unwrap() {
|
|
|
|
"1" => "Online",
|
|
|
|
"-1" => "Offline",
|
|
|
|
_ => "Unknown"
|
|
|
|
};
|
2024-03-22 19:06:05 -04:00
|
|
|
let name = id_name_map.get(id).unwrap_or(&name);
|
|
|
|
server_map.entry(title.clone()).or_insert_with(Vec::new).push((name.to_owned().to_string(), status.to_owned()));
|
2024-03-20 17:55:48 -04:00
|
|
|
}
|
|
|
|
}
|
2024-03-22 19:06:05 -04:00
|
|
|
|
|
|
|
let mut statuses = Vec::new();
|
|
|
|
for (title, servers) in server_map {
|
|
|
|
let servers_str = servers.iter().map(|(name, status)| format!("{}: {}", name, status)).collect::<Vec<String>>().join("\n");
|
|
|
|
statuses.push((title, servers_str, true));
|
|
|
|
}
|
2024-03-20 17:55:48 -04:00
|
|
|
statuses
|
|
|
|
}
|
|
|
|
|
2024-02-05 06:49:04 -05:00
|
|
|
async fn gs_query_minecraft(server_ip: &str) -> Result<MinecraftQueryData, Error> {
|
2024-03-15 18:41:33 -04:00
|
|
|
let client = HttpClient::new();
|
|
|
|
let req = client.get(&format!("https://api.mcsrvstat.us/2/{}", server_ip)).await?;
|
2024-02-05 06:49:04 -05:00
|
|
|
|
|
|
|
if req.status().is_success() {
|
|
|
|
let data: MinecraftQueryData = req.json().await?;
|
|
|
|
Ok(data)
|
2024-03-10 19:04:12 -04:00
|
|
|
} 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."))
|
2023-12-30 23:57:27 -05:00
|
|
|
}
|
2024-02-05 06:49:04 -05:00
|
|
|
}
|
2023-12-30 23:57:27 -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> {
|
2023-12-30 23:57:27 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-12-08 06:25:44 -05:00
|
|
|
/// Retrieve the server statuses from Wargaming
|
2023-12-07 22:01:13 -05:00
|
|
|
#[poise::command(slash_command)]
|
2023-12-30 23:57:27 -05:00
|
|
|
pub async fn wg(ctx: poise::Context<'_, (), Error>) -> Result<(), Error> {
|
2023-12-08 06:25:44 -05:00
|
|
|
let pms_asia = &PMS_BASE;
|
|
|
|
let pms_eu = PMS_BASE.replace("asia", "eu");
|
2024-01-11 21:41:29 -05:00
|
|
|
let embed = CreateEmbed::new().color(EMBED_COLOR);
|
2023-12-07 22:01:13 -05:00
|
|
|
|
2023-12-08 06:25:44 -05:00
|
|
|
let (servers_asia, servers_eu) = join!(pms_serverstatus(&pms_asia), pms_serverstatus(&pms_eu));
|
2024-03-22 19:06:05 -04:00
|
|
|
let joined_pms_servers = [servers_eu.unwrap(), servers_asia.unwrap()].concat();
|
|
|
|
let pms_servers = process_pms_statuses(joined_pms_servers.to_vec());
|
2023-12-07 22:01:13 -05:00
|
|
|
|
2024-03-22 19:06:05 -04:00
|
|
|
ctx.send(CreateReply::default().embed(embed.title("Wargaming Server Status").fields(pms_servers))).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(
|
2024-02-01 02:00:57 -05:00
|
|
|
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));
|
2024-03-10 19:04:12 -04:00
|
|
|
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()
|
2024-03-10 19:04:12 -04:00
|
|
|
.content(format!("**{}** (`{}`) is currently offline or unreachable.", server_name, ip_address))
|
2024-02-05 06:49:04 -05:00
|
|
|
).await?;
|
|
|
|
}
|
2024-02-01 02:00:57 -05:00
|
|
|
},
|
2024-02-23 09:03:03 -05:00
|
|
|
_ => {}
|
2024-02-01 02:00:57 -05:00
|
|
|
}
|
2024-02-05 06:49:04 -05:00
|
|
|
|
2024-01-30 07:17:59 -05:00
|
|
|
Ok(())
|
|
|
|
}
|