config deser
This commit is contained in:
parent
a493259f7f
commit
ec981ccb41
1082
Cargo.lock
generated
1082
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,9 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.102"
|
anyhow = "1.0.102"
|
||||||
|
poise = "0.6.2"
|
||||||
reqwest = {version = "0.13.3", features = ["json"]}
|
reqwest = {version = "0.13.3", features = ["json"]}
|
||||||
serde = {version = "1.0.215", features = ["derive", "serde_derive"]}
|
serde = {version = "1.0.215", features = ["derive", "serde_derive"]}
|
||||||
|
serde_json = "1.0.149"
|
||||||
tokio = {version = "1.41.1", features = ["full"]}
|
tokio = {version = "1.41.1", features = ["full"]}
|
||||||
url = "2.5.3"
|
url = "2.5.3"
|
||||||
|
|||||||
10
config.json
Normal file
10
config.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"version": "0.1.0",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"handler_type": "minecraft",
|
||||||
|
"address": "https://dawn.shibedrill.site",
|
||||||
|
"token": "foobar"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
use crate::types::*;
|
||||||
|
use poise;
|
||||||
|
|
||||||
|
struct BotRunner {
|
||||||
|
client: poise::serenity_prelude::Client,
|
||||||
|
server_data: dyn ServerInfo<OnlineResponse = dyn ServerOnlineResponse>,
|
||||||
|
}
|
||||||
26
src/config_parser.rs
Normal file
26
src/config_parser.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use std::{fs::File, path::Path};
|
||||||
|
use crate::types::{ServerInfo, ServerOnlineResponse};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct ConfigEntry {
|
||||||
|
handler_type: String,
|
||||||
|
address: String,
|
||||||
|
token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Config {
|
||||||
|
version: String,
|
||||||
|
entries: Vec<ConfigEntry>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_configs(path: &Path) -> Result<Config, anyhow::Error> {
|
||||||
|
let file_handle = File::open(path)?;
|
||||||
|
Ok(serde_json::from_reader::<File, Config>(file_handle)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_handlers(conf: Config) -> Vec<Box<dyn ServerInfo>> {
|
||||||
|
let mut results: Vec<Box<dyn ServerInfo>> = vec!();
|
||||||
|
results
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
use reqwest::{header::HeaderValue, Client};
|
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use serde_json;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::types::{PlayerList, ServerInfo, ServerOnlineResponse, ServerResponse};
|
use crate::types::{PlayerList, ServerInfo, ServerOnlineResponse, ServerResponse};
|
||||||
@ -46,28 +46,6 @@ pub struct OnlineResponse {
|
|||||||
players: Vec<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 {
|
impl PlayerList for OnlineResponse {
|
||||||
fn players(&self) -> &Vec<String> {
|
fn players(&self) -> &Vec<String> {
|
||||||
&self.players
|
&self.players
|
||||||
@ -85,56 +63,42 @@ impl ServerInfo for Server {
|
|||||||
Server { token, addr }
|
Server { token, addr }
|
||||||
}
|
}
|
||||||
|
|
||||||
type OnlineResponse = OnlineResponse;
|
fn addressable_name(&self) -> String {
|
||||||
|
self.addr.clone().into()
|
||||||
type AddressableName = Url;
|
|
||||||
|
|
||||||
fn addressable_name(&self) -> &Self::AddressableName {
|
|
||||||
&self.addr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn app_token(&self) -> String {
|
fn app_token(&self) -> String {
|
||||||
self.token.clone()
|
self.token.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn poll(&self) -> ServerResponse<Self::OnlineResponse> {
|
fn api_address(&self) -> Url {
|
||||||
use reqwest;
|
|
||||||
let url_string = format!("https://api.mcsrvstat.us/3/{}", self.addr.host().unwrap());
|
let url_string = format!("https://api.mcsrvstat.us/3/{}", self.addr.host().unwrap());
|
||||||
let url = Url::try_from(url_string.as_str()).unwrap();
|
Url::parse(&url_string).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();
|
fn parse(&self, response: String) -> ServerResponse {
|
||||||
|
let parsed_data: ApiResponse = serde_json::from_str(&response).unwrap();
|
||||||
match client.execute(request).await {
|
match parsed_data.online {
|
||||||
Err(error) => ServerResponse::Error(anyhow::anyhow!(error)),
|
true => {
|
||||||
Ok(answer) => {
|
let players = parsed_data.players.unwrap();
|
||||||
let json = answer.json::<ApiResponse>().await.unwrap();
|
let motd = parsed_data.motd.as_ref().unwrap();
|
||||||
//println!("{}", answer.text().await.unwrap());
|
self::ServerResponse::Online(ServerOnlineResponse {
|
||||||
//ServerResponse::Offline
|
searchable_name: self.addr.host().unwrap().to_string(),
|
||||||
|
readable_name: motd.clean.first().unwrap().into(),
|
||||||
match json.online {
|
reported_name: motd.clean.first().unwrap().into(),
|
||||||
true => {
|
clean_name: motd.clean.first().unwrap().into(),
|
||||||
let players = json.players.unwrap();
|
players_online: players.online,
|
||||||
let motd = json.motd.as_ref().unwrap();
|
player_limit: players.max,
|
||||||
self::ServerResponse::Online(OnlineResponse {
|
version: parsed_data.version.unwrap(),
|
||||||
searchable_name: self.addr.host().unwrap().to_string(),
|
players: Some(Box::new(players
|
||||||
reported_name: motd.clean.first().unwrap().into(),
|
.list
|
||||||
clean_name: motd.clean.first().unwrap().into(),
|
.unwrap_or_default()
|
||||||
players_online: players.online,
|
.iter()
|
||||||
player_limit: players.max,
|
.map(|e| e.name.clone())
|
||||||
version: json.version.unwrap(),
|
.collect())),
|
||||||
players: players
|
})
|
||||||
.list
|
|
||||||
.unwrap_or(Vec::<ApiResponsePlayerEntry>::new())
|
|
||||||
.iter()
|
|
||||||
.map(|e| e.name.clone())
|
|
||||||
.collect(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
false => ServerResponse::Offline,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
false => ServerResponse::Offline,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
src/main.rs
28
src/main.rs
@ -1,31 +1,31 @@
|
|||||||
|
mod bot_runner;
|
||||||
|
mod config_parser;
|
||||||
mod handlers;
|
mod handlers;
|
||||||
mod types;
|
mod types;
|
||||||
|
mod request;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
handlers::minecraft,
|
request::request, types::{ServerInfo, ServerResponse}
|
||||||
types::{PlayerList, ServerInfo, ServerOnlineResponse, ServerResponse},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let mc = minecraft::Server::new(
|
|
||||||
"foo".into(),
|
|
||||||
"http://dawn.shibedrill.site".try_into().unwrap(),
|
let http_response = request(mc.api_address()).await.unwrap();
|
||||||
);
|
let results = mc.parse(http_response.text().await.unwrap());
|
||||||
let results = mc.poll().await;
|
|
||||||
match results {
|
match results {
|
||||||
ServerResponse::Error(err) => println!("Error: {}", err),
|
|
||||||
ServerResponse::Offline => println!("Offline"),
|
ServerResponse::Offline => println!("Offline"),
|
||||||
ServerResponse::Online(online_info) => {
|
ServerResponse::Online(online_info) => {
|
||||||
println!(
|
println!(
|
||||||
"Name: {}\nAddress: {}\nVersion: {}\nPlayers: {}/{}",
|
"Name: {}\nAddress: {}\nVersion: {}\nPlayers: {}/{}",
|
||||||
online_info.readable_name(),
|
online_info.readable_name,
|
||||||
online_info.searchable_name(),
|
online_info.searchable_name,
|
||||||
online_info.version(),
|
online_info.version,
|
||||||
online_info.players_online(),
|
online_info.players_online,
|
||||||
online_info.player_limit()
|
online_info.player_limit
|
||||||
);
|
);
|
||||||
println!("Players online: {}", online_info.players().join(", "));
|
println!("Players online: {}", online_info.players.unwrap().join(", "));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
9
src/request.rs
Normal file
9
src/request.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use url::Url;
|
||||||
|
use reqwest::{Response, header::HeaderValue};
|
||||||
|
|
||||||
|
pub async fn request(url: Url) -> Result<Response, reqwest::Error> {
|
||||||
|
let client = reqwest::Client::new();
|
||||||
|
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());
|
||||||
|
client.execute(request).await
|
||||||
|
}
|
||||||
33
src/types.rs
33
src/types.rs
@ -1,18 +1,21 @@
|
|||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ServerResponse<T: ServerOnlineResponse> {
|
pub enum ServerResponse {
|
||||||
Offline,
|
Offline,
|
||||||
Online(T),
|
Online(ServerOnlineResponse),
|
||||||
Error(anyhow::Error),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ServerOnlineResponse {
|
#[derive(Debug)]
|
||||||
fn players_online(&self) -> u64;
|
pub struct ServerOnlineResponse {
|
||||||
fn player_limit(&self) -> u64;
|
pub players_online: u64,
|
||||||
fn version(&self) -> &String;
|
pub player_limit: u64,
|
||||||
fn searchable_name(&self) -> &String;
|
pub version: String,
|
||||||
fn readable_name(&self) -> &String;
|
pub searchable_name: String,
|
||||||
|
pub readable_name: String,
|
||||||
|
pub clean_name: String,
|
||||||
|
pub reported_name: String,
|
||||||
|
pub players: Option<Box<Vec<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PlayerList {
|
pub trait PlayerList {
|
||||||
@ -21,17 +24,19 @@ pub trait PlayerList {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub trait ServerInfo {
|
pub trait ServerInfo {
|
||||||
fn new(token: String, addr: Url) -> Self;
|
fn new(token: String, addr: Url) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
/// An addressable, unique identifier, used for its API.
|
/// An addressable, unique identifier, used for its API.
|
||||||
/// If it is a Minecraft server, this can be a fully qualified domain name or URL.
|
/// If it is a Minecraft server, this can be a fully qualified domain name or URL.
|
||||||
/// If this is an SCP secret laboratory server, it can be a server ID.
|
/// If this is an SCP secret laboratory server, it can be a server ID.
|
||||||
type AddressableName;
|
fn addressable_name(&self) -> String;
|
||||||
fn addressable_name(&self) -> &Self::AddressableName;
|
/// The address wrapped in the API URL.
|
||||||
|
fn api_address(&self) -> Url;
|
||||||
|
fn parse(&self, response: String) -> ServerResponse;
|
||||||
|
|
||||||
/// The app token used to send status updates.
|
/// The app token used to send status updates.
|
||||||
fn app_token(&self) -> String;
|
fn app_token(&self) -> String;
|
||||||
|
|
||||||
type OnlineResponse: ServerOnlineResponse;
|
|
||||||
async fn poll(&self) -> ServerResponse<Self::OnlineResponse>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user