From 4e879c35a6c557991d381196a8db74ec1c250efb Mon Sep 17 00:00:00 2001 From: August Date: Sun, 10 May 2026 16:39:30 -0400 Subject: [PATCH] Schema update --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 17 ++++++++------- src/config_parser.rs | 46 +++++++++++++++++---------------------- src/handlers/minecraft.rs | 17 ++++++++------- src/main.rs | 7 +++--- 6 files changed, 43 insertions(+), 48 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6e9ba44..632f5ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1317,7 +1317,7 @@ checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "playerbot" -version = "1.0.1" +version = "1.1.0" dependencies = [ "anyhow", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index bdd49e7..7e8f4eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playerbot" -version = "1.0.1" +version = "1.1.0" edition = "2021" [dependencies] diff --git a/README.md b/README.md index ca7c1a1..0036bec 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Playerbot +# Playerbot 1.1.0 Playerbot is a utility to monitor the status of game servers through Discord bots. These bots provide a rich integration into your Discord server, including things like player counts, server status, game versions, and game server addresses. It's easy to configure, and runs as one process from one binary. @@ -16,15 +16,16 @@ The program requires a file named config.json to be present in its current worki ```json { - "version": "0.1.0", + "version": "0.2.0", "entries": [ { - "handler_type": "minecraft", - "address": { - "Domain": "mc.example.com" - }, - "token": "FAKEDISCORDAPPLICATIONTOKENPLACEHOLDER" - }, + "Minecraft": { + "host": { + "Domain": "10.0.0.2:233" + }, + "token": "FAKETOKENPLACEHOLDERWHICHISVERYLONG" + } + } ] } ``` diff --git a/src/config_parser.rs b/src/config_parser.rs index ff1431f..a805f93 100644 --- a/src/config_parser.rs +++ b/src/config_parser.rs @@ -1,40 +1,34 @@ -use crate::{handlers, types::ServerInfo}; +use crate::{handlers::{self, minecraft::Minecraft}, types::ServerInfo}; +use anyhow::anyhow; use serde::Deserialize; -use std::{fs::File, path::Path}; -use url::Host; +use std::{error::Error, fmt::Display, fs::File, path::Path}; -const SCHEMA_VERSION: &str = "0.1.0"; +const SCHEMA_VERSION: &str = "0.2.0"; #[derive(Deserialize)] -pub struct ConfigEntry { - handler_type: String, - address: Host, - token: String, +pub enum ConfigEntry { + Minecraft(handlers::minecraft::Minecraft), +} + +impl ConfigEntry { + pub fn inner(&self) -> impl ServerInfo { + match self { + ConfigEntry::Minecraft(mc) => mc.clone() + } + } } #[derive(Deserialize)] pub struct Config { - version: String, - entries: Vec, + pub version: String, + pub entries: Vec, } pub fn parse_configs(path: &Path) -> Result { let file_handle = File::open(path)?; - Ok(serde_json::from_reader::(file_handle)?) -} - -pub fn build_handlers(conf: Config) -> Vec> { - assert_eq!(conf.version, SCHEMA_VERSION); - let mut results: Vec> = vec![]; - for item in conf.entries { - #[allow(clippy::single_match)] - match item.handler_type.as_str() { - "minecraft" => results.push(Box::new(handlers::minecraft::Server::new( - item.token, - item.address, - ))), - _ => {} - } + let config = serde_json::from_reader::(file_handle)?; + if !(SCHEMA_VERSION == config.version) { + return Err(anyhow!(format!("Expected schema version {}, found {}", SCHEMA_VERSION, config.version))); } - results + Ok(config) } diff --git a/src/handlers/minecraft.rs b/src/handlers/minecraft.rs index e331569..3f502fb 100644 --- a/src/handlers/minecraft.rs +++ b/src/handlers/minecraft.rs @@ -46,19 +46,20 @@ pub struct OnlineResponse { players: Vec, } -pub struct Server { +#[derive(Deserialize, Clone)] +pub struct Minecraft { #[allow(dead_code)] token: String, - addr: Host, + host: Host, } -impl ServerInfo for Server { - fn new(token: String, addr: Host) -> Self { - Server { token, addr } +impl ServerInfo for Minecraft { + fn new(token: String, host: Host) -> Self { + Minecraft { token, host } } fn addressable_name(&self) -> String { - self.addr.to_string() + self.host.to_string() } fn app_token(&self) -> String { @@ -66,7 +67,7 @@ impl ServerInfo for Server { } fn api_address(&self) -> Url { - let url_string = format!("https://api.mcsrvstat.us/3/{}", self.addr); + let url_string = format!("https://api.mcsrvstat.us/3/{}", self.host); Url::parse(&url_string).expect("Could not parse URL") } @@ -83,7 +84,7 @@ impl ServerInfo for Server { .as_ref() .expect("MOTD field unexpectedly absent"); self::ServerResponse::Online(ServerOnlineResponse { - searchable_name: self.addr.to_string(), + searchable_name: self.host.to_string(), readable_name: motd.clean.first().unwrap_or(&"(no name)".to_owned()).into(), reported_name: motd.clean.first().unwrap_or(&"(no name)".to_owned()).into(), clean_name: motd.clean.first().unwrap_or(&"(no name)".to_owned()).into(), diff --git a/src/main.rs b/src/main.rs index ad66700..dd0c37b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,11 +17,10 @@ async fn main() { let config = config_parser::parse_configs(Path::new("config.json")) .expect("Could not parse config.json"); info!("Got config file"); - let handlers = config_parser::build_handlers(config); - info!("Parsed {} handlers", handlers.len()); + info!("Parsed {} handlers", config.entries.len()); let mut bots: Vec = vec![]; - for item in handlers { - bots.push(BotRunner::new(item).await); + for item in config.entries { + bots.push(BotRunner::new(Box::new(item.inner())).await); } let futures: Vec<_> = bots.iter_mut().map(|b| b.run()).collect(); let _ = try_join_all(futures).await;