mirror of
https://github.com/Xevion/banner.git
synced 2025-12-06 01:14:22 -06:00
feat: basic activity status
This commit is contained in:
11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -184,6 +184,7 @@ dependencies = [
|
||||
"futures",
|
||||
"governor",
|
||||
"http 1.3.1",
|
||||
"num-format",
|
||||
"once_cell",
|
||||
"poise",
|
||||
"rand 0.9.2",
|
||||
@@ -1699,6 +1700,16 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
|
||||
|
||||
[[package]]
|
||||
name = "num-format"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.46"
|
||||
|
||||
@@ -44,5 +44,6 @@ url = "2.5"
|
||||
governor = "0.10.1"
|
||||
once_cell = "1.21.3"
|
||||
serde_path_to_error = "0.1.17"
|
||||
num-format = "0.4.4"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
41
src/main.rs
41
src/main.rs
@@ -1,5 +1,6 @@
|
||||
use figment::value::UncasedStr;
|
||||
use serenity::all::{ClientBuilder, GatewayIntents};
|
||||
use num_format::{Locale, ToFormattedString};
|
||||
use serenity::all::{ActivityData, ClientBuilder, GatewayIntents};
|
||||
use tokio::signal;
|
||||
use tracing::{error, info, warn};
|
||||
use tracing_subscriber::{EnvFilter, FmtSubscriber};
|
||||
@@ -27,6 +28,21 @@ mod services;
|
||||
mod state;
|
||||
mod web;
|
||||
|
||||
async fn update_bot_status(
|
||||
ctx: &serenity::all::Context,
|
||||
app_state: &AppState,
|
||||
) -> Result<(), anyhow::Error> {
|
||||
let course_count = app_state.get_course_count().await?;
|
||||
|
||||
ctx.set_activity(Some(ActivityData::playing(format!(
|
||||
"Querying {:} classes",
|
||||
course_count.to_formatted_string(&Locale::en)
|
||||
))));
|
||||
|
||||
tracing::info!(course_count = course_count, "Updated bot status");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
dotenvy::dotenv().ok();
|
||||
@@ -102,7 +118,7 @@ async fn main() {
|
||||
.expect("Failed to create BannerApi");
|
||||
|
||||
let banner_api_arc = Arc::new(banner_api);
|
||||
let app_state = AppState::new(banner_api_arc.clone(), &config.redis_url)
|
||||
let app_state = AppState::new(banner_api_arc.clone(), &config.redis_url, db_pool.clone())
|
||||
.expect("Failed to create AppState");
|
||||
|
||||
// Create BannerState for web service
|
||||
@@ -174,6 +190,27 @@ async fn main() {
|
||||
)
|
||||
.await?;
|
||||
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
||||
|
||||
// Start status update task
|
||||
let status_app_state = app_state.clone();
|
||||
let status_ctx = ctx.clone();
|
||||
tokio::spawn(async move {
|
||||
let mut interval = tokio::time::interval(std::time::Duration::from_secs(30));
|
||||
|
||||
// Update status immediately on startup
|
||||
if let Err(e) = update_bot_status(&status_ctx, &status_app_state).await {
|
||||
tracing::error!(error = %e, "Failed to update status on startup");
|
||||
}
|
||||
|
||||
loop {
|
||||
interval.tick().await;
|
||||
|
||||
if let Err(e) = update_bot_status(&status_ctx, &status_app_state).await {
|
||||
tracing::error!(error = %e, "Failed to update bot status");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(Data { app_state })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -86,7 +86,7 @@ impl SubjectJob {
|
||||
.execute(db_pool)
|
||||
.await
|
||||
.map(|result| {
|
||||
trace!(result = ?result, "Course upserted");
|
||||
trace!(subject = course.subject, crn = course.course_reference_number, result = ?result, "Course upserted");
|
||||
})
|
||||
.map_err(|e| anyhow::anyhow!("Failed to upsert course: {e}"))
|
||||
}
|
||||
|
||||
12
src/state.rs
12
src/state.rs
@@ -5,24 +5,28 @@ use crate::banner::Course;
|
||||
use anyhow::Result;
|
||||
use redis::AsyncCommands;
|
||||
use redis::Client;
|
||||
use sqlx::PgPool;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub banner_api: Arc<BannerApi>,
|
||||
pub redis: Arc<Client>,
|
||||
pub db_pool: PgPool,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new(
|
||||
banner_api: Arc<BannerApi>,
|
||||
redis_url: &str,
|
||||
db_pool: PgPool,
|
||||
) -> Result<Self, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let redis_client = Client::open(redis_url)?;
|
||||
|
||||
Ok(Self {
|
||||
banner_api,
|
||||
redis: Arc::new(redis_client),
|
||||
db_pool,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -45,4 +49,12 @@ impl AppState {
|
||||
|
||||
Err(anyhow::anyhow!("Course not found for CRN {crn}"))
|
||||
}
|
||||
|
||||
/// Get the total number of courses in the database
|
||||
pub async fn get_course_count(&self) -> Result<i64> {
|
||||
let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM courses")
|
||||
.fetch_one(&self.db_pool)
|
||||
.await?;
|
||||
Ok(count.0)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user