From b04157e4aef58e5249a0bfce7989160cbe3d142e Mon Sep 17 00:00:00 2001 From: shibedrill Date: Mon, 21 Oct 2024 22:50:52 -0400 Subject: [PATCH] make things into types --- src/funcs.rs | 8 +++- src/main.rs | 21 +++++++-- src/minecraft.rs | 117 ++++++++++++++++++++++++++--------------------- src/scpsl.rs | 117 ++++++++++++++++++++++++++--------------------- src/types.rs | 16 ++++--- 5 files changed, 164 insertions(+), 115 deletions(-) diff --git a/src/funcs.rs b/src/funcs.rs index 0a26dd0..152f0d8 100644 --- a/src/funcs.rs +++ b/src/funcs.rs @@ -6,7 +6,11 @@ pub fn set_presence(ctx: &poise::serenity_prelude::Context, status: ServerRespon ctx.set_presence( Some(ActivityData::custom(match status.online() { true => { - format!("{}/{} players online", status.players(), status.max()) + format!( + "{}/{} players online", + status.players().unwrap(), + status.max().unwrap() + ) } false => "Server offline!".to_string(), })), @@ -18,4 +22,4 @@ pub fn set_presence(ctx: &poise::serenity_prelude::Context, status: ServerRespon false => OnlineStatus::DoNotDisturb, }, ); -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index d578756..dc9b148 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,12 @@ +mod funcs; mod minecraft; mod scpsl; mod types; -mod funcs; -use tokio::join; use dotenvy::{self, dotenv}; +use minecraft::Minecraft; +use scpsl::SCPSL; +use tokio::join; +use url::{self, Url}; #[macro_use] extern crate log; @@ -12,5 +15,17 @@ extern crate log; async fn main() { dotenv().ok(); pretty_env_logger::init(); - join!(scpsl::run(), minecraft::run()); + let gamerzone = Minecraft::new( + Url::try_from("https://api.mcstatus.io/v2/status/java/gamer.shibedrill.site").unwrap(), + std::env::var("TOKEN_BOT_MC_GAMER").unwrap(), + ); + let mchprs = Minecraft::new( + Url::try_from("https://api.mcstatus.io/v2/status/java/mchprs.shibedrill.site").unwrap(), + std::env::var("TOKEN_BOT_MC_MCHPRS").unwrap(), + ); + let scpsl = SCPSL::new( + Url::try_from("https://api.scplist.kr/api/servers/81460").unwrap(), + std::env::var("TOKEN_BOT_SCPSL").unwrap(), + ); + join!(scpsl.run(), mchprs.run(), gamerzone.run()); } diff --git a/src/minecraft.rs b/src/minecraft.rs index 16be965..aac5dd1 100644 --- a/src/minecraft.rs +++ b/src/minecraft.rs @@ -1,6 +1,7 @@ use poise::serenity_prelude as serenity; use reqwest::{Client, Request}; use serenity::*; +use url::Url; use crate::{funcs, types::ServerResponse}; @@ -16,25 +17,66 @@ struct Players { max: i32, } -pub struct Data {} +pub struct Data { + controller: Minecraft, +} -async fn get_status() -> Result { - let http_client = Client::new(); - let request = Request::new( - reqwest::Method::GET, - "https://api.mcstatus.io/v2/status/java/gamer.shibedrill.site" - .try_into()?, - ); - let response = http_client.execute(request).await?; - let data: ServerSummary = serde_json::from_str(&response.text().await?)?; - if let Some(players) = data.players { - Ok(ServerResponse::new( - data.online, - players.online as u32, - players.max as u32, - )) - } else { - Ok(ServerResponse::new(data.online, 0, 0)) +#[derive(Clone)] +pub struct Minecraft { + url: Url, + token: String, +} + +impl Minecraft { + pub fn new(url: Url, token: String) -> Self { + Self { url, token } + } + + pub async fn get_status(&self) -> Result { + let http_client = Client::new(); + let request = Request::new(reqwest::Method::GET, self.url.clone()); + let response = http_client.execute(request).await?; + let data: ServerSummary = serde_json::from_str(&response.text().await?)?; + if let Some(players) = data.players { + Ok(ServerResponse::new( + data.online, + Some(players.online as u32), + Some(players.max as u32), + )) + } else { + Ok(ServerResponse::new(data.online, None, None)) + } + } + pub async fn run(&self) { + let controller = self.clone(); + let framework = poise::Framework::builder() + .options(poise::FrameworkOptions { + event_handler: |ctx, event, framework, data| { + Box::pin(event_handler(ctx, event, framework, data)) + }, + ..Default::default() + }) + .setup(|ctx, _ready, framework| { + Box::pin(async move { + poise::builtins::register_globally(ctx, &framework.options().commands).await?; + Ok(Data { controller }) + }) + }) + .build(); + info!("Built framework successfully."); + + let mut discord_client = ClientBuilder::new( + self.token.clone(), + serenity::GatewayIntents::non_privileged(), + ) + .framework(framework) + .activity(ActivityData::custom("Waiting on initial status...")) + .await + .inspect_err(|e| error!("Failed to start client: {}", e)) + .unwrap(); + info!("Built client successfully."); + + let _ = discord_client.start().await; } } @@ -42,13 +84,15 @@ pub async fn event_handler( ctx: &serenity::Context, event: &serenity::FullEvent, _framework: poise::FrameworkContext<'_, Data, Error>, - _data: &Data, + data: &Data, ) -> Result<(), Error> { match event { serenity::FullEvent::Ready { - data_about_bot: _data, + data_about_bot: _bot_data, } => loop { - let status = get_status() + let status = data + .controller + .get_status() .await .inspect_err(|e| error!("Failed to get status: {}", e)) .unwrap(); @@ -60,34 +104,3 @@ pub async fn event_handler( _ => Ok(()), } } - -pub async fn run() { - let framework = poise::Framework::builder() - .options(poise::FrameworkOptions { - event_handler: |ctx, event, framework, data| { - Box::pin(event_handler(ctx, event, framework, data)) - }, - ..Default::default() - }) - .setup(|ctx, _ready, framework| { - Box::pin(async move { - poise::builtins::register_globally(ctx, &framework.options().commands).await?; - Ok(Data {}) - }) - }) - .build(); - info!("Built framework successfully."); - - let mut discord_client = ClientBuilder::new( - std::env::var("MINECRAFT_BOT_TOKEN").inspect_err(|e| {error!("Failed to get token: {}", e)}).unwrap(), - serenity::GatewayIntents::non_privileged(), - ) - .framework(framework) - .activity(ActivityData::custom("Waiting on initial status...")) - .await - .inspect_err(|e| error!("Failed to start client: {}", e)) - .unwrap(); - info!("Built client successfully."); - - let _ = discord_client.start().await; -} diff --git a/src/scpsl.rs b/src/scpsl.rs index 26dc830..52804ef 100644 --- a/src/scpsl.rs +++ b/src/scpsl.rs @@ -1,8 +1,8 @@ - use crate::{funcs, types::ServerResponse}; use poise::serenity_prelude as serenity; use reqwest::{Client, Request}; use serenity::*; +use url::Url; #[derive(serde::Deserialize)] #[allow(non_snake_case)] @@ -11,40 +11,85 @@ struct ServerSummary { players: String, } -pub struct Data {} +pub struct Data { + controller: SCPSL, +} -async fn get_status() -> Result { - let http_client = Client::new(); - let request = Request::new( - reqwest::Method::GET, - url::Url::try_from("https://api.scplist.kr/api/servers/81460")?, - ); - let response = http_client.execute(request).await?; - let data: ServerSummary = serde_json::from_str(&response.text().await?)?; +#[derive(Clone)] +pub struct SCPSL { + url: Url, + token: String, +} - let playercount: Result, _> = - data.players.split('/').map(|x| x.parse::()).collect(); +impl SCPSL { + pub fn new(url: Url, token: String) -> Self { + Self { url, token } + } + async fn get_status(&self) -> Result { + let http_client = Client::new(); + let request = Request::new(reqwest::Method::GET, self.url.clone()); + let response = http_client.execute(request).await?; + let data: ServerSummary = serde_json::from_str(&response.text().await?)?; - let playercount_unwrapped = playercount?; + let playercount: Result, _> = + data.players.split('/').map(|x| x.parse::()).collect(); - Ok(ServerResponse::new( - data.online, - playercount_unwrapped[0], - playercount_unwrapped[1], - )) + let playercount_unwrapped = playercount?; + + Ok(ServerResponse::new( + data.online, + playercount_unwrapped.get(0).map(|u| u.clone()), + playercount_unwrapped.get(1).map(|u| u.clone()), + )) + } + + pub async fn run(&self) { + let controller = self.clone(); + let framework = poise::Framework::builder() + .options(poise::FrameworkOptions { + initialize_owners: true, + event_handler: |ctx, event, framework, data| { + Box::pin(event_handler(ctx, event, framework, data)) + }, + ..Default::default() + }) + .setup(|ctx, _ready, framework| { + Box::pin(async move { + poise::builtins::register_globally(ctx, &framework.options().commands).await?; + Ok(Data { controller }) + }) + }) + .build(); + info!("Built framework successfully."); + + let mut discord_client = ClientBuilder::new( + self.token.clone(), + serenity::GatewayIntents::non_privileged(), + ) + .framework(framework) + .activity(ActivityData::custom("Waiting on initial status...")) + .await + .inspect_err(|e| error!("Failed to start client: {}", e)) + .unwrap(); + info!("Built client successfully."); + + let _ = discord_client.start().await; + } } pub async fn event_handler( ctx: &serenity::Context, event: &serenity::FullEvent, _framework: poise::FrameworkContext<'_, Data, Error>, - _data: &Data, + data: &Data, ) -> Result<(), Error> { match event { serenity::FullEvent::Ready { data_about_bot: _data, } => loop { - let status = get_status() + let status = data + .controller + .get_status() .await .inspect_err(|e| error!("Failed to get status: {}", e)) .unwrap(); @@ -56,35 +101,3 @@ pub async fn event_handler( _ => Ok(()), } } - -pub async fn run() { - let framework = poise::Framework::builder() - .options(poise::FrameworkOptions { - initialize_owners: true, - event_handler: |ctx, event, framework, data| { - Box::pin(event_handler(ctx, event, framework, data)) - }, - ..Default::default() - }) - .setup(|ctx, _ready, framework| { - Box::pin(async move { - poise::builtins::register_globally(ctx, &framework.options().commands).await?; - Ok(Data {}) - }) - }) - .build(); - info!("Built framework successfully."); - - let mut discord_client = ClientBuilder::new( - std::env::var("SCPSL_BOT_TOKEN").inspect_err(|e| {error!("Failed to get token: {}", e)}).unwrap(), - serenity::GatewayIntents::non_privileged(), - ) - .framework(framework) - .activity(ActivityData::custom("Waiting on initial status...")) - .await - .inspect_err(|e| error!("Failed to start client: {}", e)) - .unwrap(); - info!("Built client successfully."); - - let _ = discord_client.start().await; -} diff --git a/src/types.rs b/src/types.rs index e9aaadb..434d4ac 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,11 +1,11 @@ pub struct ServerResponse { online: bool, - players: u32, - max: u32, + players: Option, + max: Option, } impl ServerResponse { - pub fn new(online: bool, players: u32, max: u32) -> Self { + pub fn new(online: bool, players: Option, max: Option) -> Self { ServerResponse { online, players, @@ -17,11 +17,11 @@ impl ServerResponse { self.online } - pub fn players(&self) -> u32 { + pub fn players(&self) -> Option { self.players } - pub fn max(&self) -> u32 { + pub fn max(&self) -> Option { self.max } @@ -30,6 +30,10 @@ impl ServerResponse { } pub fn to_string(&self) -> String { - format!("{}/{} ({})", self.players, self.max, self.online) + if let (Some(players), Some(max)) = (self.players, self.max) { + format!("{}/{} ({})", players, max, self.online) + } else { + format!("N/A ({})", self.online) + } } }