From bb6a961c223b3726a4913a363654fdfb6a826789 Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Sun, 28 Jun 2026 10:39:49 -0600 Subject: [PATCH] Refactor system listeners to be a config item --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/api/mod.rs | 39 +++++++++++++++------------------ src/config.rs | 46 +++++++++++---------------------------- src/discord/admin.rs | 16 +++++++++++++- src/discord/mod.rs | 7 ++---- src/discord/voices.rs | 15 ++++++++++--- src/event_listener/mod.rs | 1 + src/main.rs | 8 ++++--- 9 files changed, 68 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6f1723..96b7ccf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1403,7 +1403,7 @@ dependencies = [ [[package]] name = "fren" -version = "2.9.0" +version = "2.10.0" dependencies = [ "axum 0.8.1", "base64 0.22.1", diff --git a/Cargo.toml b/Cargo.toml index 97643d6..d2f4d60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fren" -version = "2.9.0" +version = "2.10.0" edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/api/mod.rs b/src/api/mod.rs index be6bf7d..bfc05ec 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -1,16 +1,16 @@ -use std::sync::Arc; use crate::config::GlobalData; use crate::discord::voices::speak; use crate::models::api_key::Apikey; use axum::extract::State; -use axum::{http::StatusCode, response::IntoResponse, routing::post, Json, Router}; +use axum::{Json, Router, http::StatusCode, response::IntoResponse, routing::post}; use log::info; use serde::Deserialize; +use std::sync::Arc; #[derive(Clone)] struct ApiContext { data: Arc, - ctx: poise::serenity_prelude::Context + ctx: poise::serenity_prelude::Context, } pub async fn web_server(data: Arc, ctx: poise::serenity_prelude::Context) { @@ -18,10 +18,7 @@ pub async fn web_server(data: Arc, ctx: poise::serenity_prelude::Con let app = Router::new() .route("/play", post(play_sound)) - .with_state(ApiContext { - data, - ctx - }); + .with_state(ApiContext { data, ctx }); info!("Serving bot api on: {}", addr); let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); @@ -39,21 +36,21 @@ async fn play_sound( State(ctx): State, Json(payload): Json, ) -> impl IntoResponse { - if let Some(api_key) = Apikey::find_key_from_secret(&ctx.data.db, &payload.api_key).unwrap() - && let Some(user_id) = api_key.user_id { - info!("Playing audio for {user_id}"); - speak( - &ctx.ctx, - &ctx.data, - ctx.data.cfg.guild_id, - user_id, - &payload.voice, - &payload.phrase, - ) - .await - .unwrap(); - } + && let Some(user_id) = api_key.user_id + { + info!("Playing audio for {user_id}"); + speak( + &ctx.ctx, + &ctx.data, + ctx.data.cfg.guild_id, + user_id, + &payload.voice, + &payload.phrase, + ) + .await + .unwrap(); + } StatusCode::ACCEPTED } diff --git a/src/config.rs b/src/config.rs index 5959bc9..eadfe1d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,6 @@ use crate::album_manager::AlbumManager; use crate::error::Error; -use crate::event_listener::{Action, Expiration, Listener, TriggerType}; +use crate::event_listener::Listener; use crate::migrations::{CURRENT_DB_VERSION, do_migration}; use config::{Config, File}; use cta_api::CTAClient; @@ -30,6 +30,11 @@ pub struct PicOxConfig { token: String, } +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct SystemListeners { + pub listeners: Vec, +} + #[derive(Debug, Deserialize, Serialize, Clone)] pub struct BotConfig { pub bot_token: String, @@ -51,6 +56,7 @@ pub struct BotConfig { pub music_streaming_site_urls: Vec, pub music_streaming_sites: Vec, pub picox: PicOxConfig, + pub listeners_cfg: SystemListeners, } impl BotConfig { @@ -93,43 +99,17 @@ pub struct GlobalData { } impl GlobalData { - fn setup_system_listeners(db: &Database) -> Result<(), Error> { + fn setup_system_listeners(db: &Database, cfg: &BotConfig) -> Result<(), Error> { db.filter(|_, listener: &Listener| listener.system_listener)? .for_each(|listener: Listener| { let _ = db.remove::(listener.id().unwrap()).is_ok(); }); info!("Adding system listeners..."); - Listener::add_listener( - db, - Listener::new( - TriggerType::OnMessage { - channel_id: None, - content: Some("bad bot".to_string()), - }, - vec![Action::React { - emoji: "😭".to_string(), - }], - 1.0, - Expiration::Never, - true, - ), - )?; - Listener::add_listener( - db, - Listener::new( - TriggerType::OnMessage { - channel_id: None, - content: None, - }, - vec![Action::UpdateFrenCoins { - fren_coin_diff: 100, - }], - 0.05, - Expiration::Never, - true, - ), - )?; + + for listener in &cfg.listeners_cfg.listeners { + Listener::add_listener(db, listener.clone())?; + } Ok(()) } @@ -148,7 +128,7 @@ impl GlobalData { do_migration(&db); - Self::setup_system_listeners(&db)?; + Self::setup_system_listeners(&db, &cfg)?; Ok(Self { args, diff --git a/src/discord/admin.rs b/src/discord/admin.rs index fc644b6..ac4fff7 100644 --- a/src/discord/admin.rs +++ b/src/discord/admin.rs @@ -350,7 +350,21 @@ pub async fn list_social_credit_phrases(ctx: Context<'_>) -> Result<(), Error> { )); } - ctx.reply(list.build()).await?; + let msg = list.build(); + + if msg.len() < MESSAGE_CODE_LIMIT { + ctx.reply(msg).await?; + } else { + ctx.send( + CreateReply::default() + .reply(true) + .attachment(CreateAttachment::bytes( + msg.as_bytes(), + "social_credit_phrases.md", + )), + ) + .await?; + } Ok(()) } diff --git a/src/discord/mod.rs b/src/discord/mod.rs index cc6832b..0694ed5 100644 --- a/src/discord/mod.rs +++ b/src/discord/mod.rs @@ -19,6 +19,7 @@ mod stonks; mod transit; pub(crate) mod voices; +use crate::api::web_server; use crate::config::GlobalData; use crate::discord::fren_coin::give_coin; use crate::discord::joke::random; @@ -39,7 +40,6 @@ use songbird::SerenityInit; use std::sync::Arc; use std::time::Duration; use url::Url; -use crate::api::web_server; pub type Context<'a> = poise::Context<'a, Arc, Error>; @@ -69,10 +69,7 @@ async fn event_handler( let ctx_web = ctx.clone(); tokio::spawn(async move { - web_server( - data_web, - ctx_web - ).await; + web_server(data_web, ctx_web).await; }); } } diff --git a/src/discord/voices.rs b/src/discord/voices.rs index 6684158..8d34410 100644 --- a/src/discord/voices.rs +++ b/src/discord/voices.rs @@ -1,3 +1,4 @@ +use crate::config::GlobalData; use crate::discord::Context; use crate::error::Error; use poise::async_trait; @@ -14,7 +15,6 @@ use std::collections::HashMap; use std::fmt::{Display, Formatter}; use std::path::{Path, PathBuf}; use std::sync::Arc; -use crate::config::GlobalData; async fn get_voice_dictionary(path: &Path) -> Result, tokio::io::Error> { let mut dir = tokio::fs::read_dir(path).await?; @@ -146,7 +146,7 @@ pub async fn speak( let word = word.to_lowercase(); if word.is_empty() || word == " " { - continue + continue; } let mut add_period = false; @@ -245,7 +245,16 @@ pub async fn say( ) -> Result<(), Error> { let guild_id = ctx.guild_id().unwrap(); - if let Err(err) = speak(ctx.serenity_context(), ctx.data(), guild_id, ctx.author().id, &voice, &phrase).await { + if let Err(err) = speak( + ctx.serenity_context(), + ctx.data(), + guild_id, + ctx.author().id, + &voice, + &phrase, + ) + .await + { match err { VoiceError::VoiceNotFound(_) | VoiceError::WordNotFound(_) diff --git a/src/event_listener/mod.rs b/src/event_listener/mod.rs index e06e9cf..0ff67a0 100644 --- a/src/event_listener/mod.rs +++ b/src/event_listener/mod.rs @@ -136,6 +136,7 @@ pub struct Listener { pub trigger_chance: f64, pub expiration: Expiration, pub system_listener: bool, + #[serde(default)] pub trigger_count: u64, } diff --git a/src/main.rs b/src/main.rs index bb89c58..29fd3c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ mod album_manager; +mod api; mod config; mod discord; mod error; @@ -9,14 +10,13 @@ mod migrations; mod models; mod music; mod user; -mod api; use crate::config::{Args, BotConfig, GlobalData}; use crate::discord::run_bot; use log::{error, info}; use magick_rust::magick_wand_genesis; -use std::sync::Once; use rustls::crypto; +use std::sync::Once; use structopt::StructOpt; use tracing_core::LevelFilter; use tracing_subscriber::EnvFilter; @@ -27,7 +27,9 @@ static START: Once = Once::new(); #[tokio::main] async fn main() { - crypto::aws_lc_rs::default_provider().install_default().expect("Unable to setup default Rustls provider"); + crypto::aws_lc_rs::default_provider() + .install_default() + .expect("Unable to setup default Rustls provider"); let args: Args = Args::from_args(); tracing_subscriber::fmt()