From 6a12495686c6e41fef6e27a24ba3e8b543d5cb8c Mon Sep 17 00:00:00 2001 From: jakubmanczak Date: Wed, 9 Jul 2025 00:06:56 +0200 Subject: [PATCH] add discord membercount service & endpoint a background worker is added that sends an approximate member count request every 60 seconds, caches it into memory, and serves the cache on a public endpoint --- src/discordbot/events/mod.rs | 3 +-- src/discordbot/member_count/mod.rs | 22 +++++++++++++++++ src/discordbot/member_count/service.rs | 33 ++++++++++++++++++++++++++ src/discordbot/mod.rs | 9 ++++++- src/router/mod.rs | 16 +++++++++++-- 5 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 src/discordbot/member_count/mod.rs create mode 100644 src/discordbot/member_count/service.rs diff --git a/src/discordbot/events/mod.rs b/src/discordbot/events/mod.rs index b55ec1f..3b5a1da 100644 --- a/src/discordbot/events/mod.rs +++ b/src/discordbot/events/mod.rs @@ -1,3 +1,4 @@ +use crate::discordbot::MAIN_GUILD_ID; use chrono::{Datelike, Utc}; use chrono_tz::Europe::Warsaw; use rand::{SeedableRng, seq::IndexedRandom}; @@ -21,8 +22,6 @@ pub fn init_service(ctx: &Context, guild_id: &GuildId) { }); } -const MAIN_GUILD_ID: GuildId = GuildId::new(447075692664979466); - pub enum Event { Normal, PolskaGórą, diff --git a/src/discordbot/member_count/mod.rs b/src/discordbot/member_count/mod.rs new file mode 100644 index 0000000..c013675 --- /dev/null +++ b/src/discordbot/member_count/mod.rs @@ -0,0 +1,22 @@ +use crate::discordbot::MAIN_GUILD_ID; +use serenity::all::{Context, GuildId}; +use service::run_membercount_service; +use tracing::info; + +mod service; + +pub use service::get_member_count; + +pub fn init_service(ctx: &Context, guild_id: &GuildId) { + let (ctx, guild_id) = (ctx.clone(), guild_id.clone()); + info!("Initialising discord member count service..."); + + if guild_id != MAIN_GUILD_ID { + info!("Guild member count service not initialised; Bot not running on main guild."); + return; + } + + tokio::spawn(async move { + run_membercount_service(ctx, guild_id).await; + }); +} diff --git a/src/discordbot/member_count/service.rs b/src/discordbot/member_count/service.rs new file mode 100644 index 0000000..62376ee --- /dev/null +++ b/src/discordbot/member_count/service.rs @@ -0,0 +1,33 @@ +use serenity::all::{Context, GuildId}; +use std::{ + sync::{Arc, LazyLock}, + time::Duration, +}; +use tokio::{sync::RwLock, time::sleep}; +use tracing::error; + +static MEMBER_COUNT: LazyLock>>> = + LazyLock::new(|| Arc::new(RwLock::new(None))); + +pub async fn run_membercount_service(ctx: Context, guild_id: GuildId) { + loop { + update_member_count(&ctx, guild_id).await; + sleep(Duration::from_secs(60)).await; + } +} + +pub async fn get_member_count() -> Option { + *MEMBER_COUNT.read().await +} + +async fn update_member_count(ctx: &Context, guild_id: GuildId) { + let count = match ctx.http.get_guild_with_counts(guild_id).await { + Ok(guild) => guild.approximate_member_count, + Err(e) => { + error!("Could not fetch guild member count: {e}"); + None + } + }; + let mut member_count = MEMBER_COUNT.write().await; + *member_count = count; +} diff --git a/src/discordbot/mod.rs b/src/discordbot/mod.rs index f31129f..17c2958 100644 --- a/src/discordbot/mod.rs +++ b/src/discordbot/mod.rs @@ -1,5 +1,7 @@ use serenity::{ - all::{CreateInteractionResponse, CreateInteractionResponseMessage, Interaction, Ready}, + all::{ + CreateInteractionResponse, CreateInteractionResponseMessage, GuildId, Interaction, Ready, + }, async_trait, prelude::*, }; @@ -12,8 +14,12 @@ struct Handler; mod commands; mod events; +mod member_count; mod status; +const MAIN_GUILD_ID: GuildId = GuildId::new(447075692664979466); +pub use member_count::get_member_count; + #[async_trait] impl EventHandler for Handler { async fn ready(&self, ctx: Context, ready: Ready) { @@ -37,6 +43,7 @@ impl EventHandler for Handler { status::init_service(&ctx); events::init_service(&ctx, &guild_id); + member_count::init_service(&ctx, &guild_id); } async fn interaction_create(&self, ctx: Context, interaction: Interaction) { diff --git a/src/router/mod.rs b/src/router/mod.rs index 2fef589..69fdca5 100644 --- a/src/router/mod.rs +++ b/src/router/mod.rs @@ -1,5 +1,17 @@ -use axum::{Router, routing::get}; +use axum::{Router, http::StatusCode, routing::get}; pub fn init() -> Router { - Router::new().route("/", get(async || "root")) + Router::new() + .route("/", get(async || "root")) + .route("/discord/member-count", get(get_member_count)) +} + +async fn get_member_count() -> (StatusCode, String) { + match crate::discordbot::get_member_count().await { + Some(count) => (StatusCode::OK, format!("{count}")), + None => ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("An error occured - could not fetch discord member count."), + ), + } }