Schema update

This commit is contained in:
August 2026-05-10 16:39:30 -04:00
parent 614b40ca08
commit 4e879c35a6
Signed by: shibedrill
SSH Key Fingerprint: SHA256:M0m3JW1s38BgO2t0fG146Yxd9OJ2IOqkvCAsuRHQ6Pw
6 changed files with 43 additions and 48 deletions

2
Cargo.lock generated
View File

@ -1317,7 +1317,7 @@ checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "playerbot"
version = "1.0.1"
version = "1.1.0"
dependencies = [
"anyhow",
"env_logger",

View File

@ -1,6 +1,6 @@
[package]
name = "playerbot"
version = "1.0.1"
version = "1.1.0"
edition = "2021"
[dependencies]

View File

@ -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"
}
}
]
}
```

View File

@ -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<ConfigEntry>,
pub version: String,
pub entries: Vec<ConfigEntry>,
}
pub fn parse_configs(path: &Path) -> Result<Config, anyhow::Error> {
let file_handle = File::open(path)?;
Ok(serde_json::from_reader::<File, Config>(file_handle)?)
}
pub fn build_handlers(conf: Config) -> Vec<Box<dyn ServerInfo>> {
assert_eq!(conf.version, SCHEMA_VERSION);
let mut results: Vec<Box<dyn ServerInfo>> = 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, Config>(file_handle)?;
if !(SCHEMA_VERSION == config.version) {
return Err(anyhow!(format!("Expected schema version {}, found {}", SCHEMA_VERSION, config.version)));
}
results
Ok(config)
}

View File

@ -46,19 +46,20 @@ pub struct OnlineResponse {
players: Vec<String>,
}
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(),

View File

@ -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<bot_runner::BotRunner> = 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;