diff options
| author | seth <[email protected]> | 2024-04-20 02:31:40 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-04-19 22:31:40 -0400 |
| commit | 3d07413690c551d9f034c93af85ae8da5a495e14 (patch) | |
| tree | 517d2e053ebdeb9a3be0ffce6dec36cbc4ce316e /src/main.rs | |
| parent | 1b92b254bc64b356f5c59657d2f0acc767bb2964 (diff) | |
spring cleaning (#165)
* treewide: lightly refactor everything
* once_cell -> std::sync
* remove build.rs
we can get our target at runtime
* commands::copypasta: refactor selection
* drop owo_colors
* reactboard: always remove author from count
* commands: better handle behavior outside of guilds
* ci: garnix -> gha
* nix: drop flake-parts & pre-commit-hooks
* nix: fix rust flags in derivation
* add gha badge to readme
* ci: fail when format changes are made
* ci: only run on push to main
* nix: fix nil script
* nix: add libiconv to darwin deps
* ci: disable fail-fast
* nix: fix actionlint & static checks
* ci: add release gates
* nix: fix nil check again
* ci: give release gates unique names
* ci: only build static packages in docker workflow
* nix: move dev outputs to subflake
* fix some typos
* nix: cleanup checks & dev shell
* add editorconfig
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 113 |
1 files changed, 52 insertions, 61 deletions
diff --git a/src/main.rs b/src/main.rs index 806c7b3..7f19b9e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,106 +1,94 @@ -#![warn(clippy::all, clippy::pedantic, clippy::perf)] -#![allow(clippy::missing_errors_doc, clippy::used_underscore_binding)] -#![forbid(unsafe_code)] - -use std::sync::Arc; -use std::time::Duration; - -use eyre::{eyre, Context as _, Report, Result}; -use log::{info, warn}; -use owo_colors::OwoColorize; -use poise::serenity_prelude as serenity; -use poise::{EditTracker, Framework, FrameworkOptions, PrefixFrameworkOptions}; -use redis::ConnectionLike; -use storage::Storage; +use std::{sync::Arc, time::Duration}; + +use eyre::{Context as _, Report, Result}; +use log::{info, trace, warn}; +use poise::{ + serenity_prelude::{self as serenity}, + EditTracker, Framework, FrameworkOptions, PrefixFrameworkOptions, +}; use tokio::signal::ctrl_c; +#[cfg(target_family = "unix")] use tokio::signal::unix::{signal, SignalKind}; +#[cfg(target_family = "windows")] +use tokio::signal::windows::ctrl_close; mod api; -mod colors; mod commands; mod consts; mod handlers; mod storage; mod utils; -type Context<'a> = poise::Context<'a, Data, Report>; +use storage::Storage; + +type Error = Box<dyn std::error::Error + Send + Sync>; +type Context<'a> = poise::Context<'a, Data, Error>; -#[derive(Clone)] +#[derive(Clone, Debug, Default)] pub struct Data { - storage: Storage, + storage: Option<Storage>, } -impl Data { - pub fn new() -> Result<Self> { - let redis_url = - std::env::var("REDIS_URL").wrap_err("Couldn't find Redis URL in environment!")?; - - let storage = Storage::new(&redis_url)?; - - Ok(Self { storage }) - } -} +async fn setup(ctx: &serenity::Context) -> Result<Data, Error> { + let storage = Storage::from_env().ok(); -async fn setup( - ctx: &serenity::Context, - _ready: &serenity::Ready, - framework: &Framework<Data, Report>, -) -> Result<Data> { - let data = Data::new()?; - let mut client = data.storage.client.clone(); - - if !client.check_connection() { - return Err(eyre!( - "Couldn't connect to storage! Is your daemon running?" - )); - } + if let Some(storage) = storage.as_ref() { + if !storage.clone().is_connected() { + return Err( + "You specified a storage backend but there's no connection! Is it running?".into(), + ); + } + trace!("Storage backend connected!"); - poise::builtins::register_globally(ctx, &framework.options().commands).await?; - info!("Registered global commands!"); + poise::builtins::register_globally(ctx, &commands::to_vec_global()).await?; + info!("Registered global commands!"); - // register "extra" commands in guilds that allow it - let guilds = data.storage.get_opted_guilds().await?; + // register "extra" commands in guilds that allow it + let guilds = storage.get_opted_guilds().await?; - for guild in guilds { - poise::builtins::register_in_guild(ctx, &commands::optional(), guild).await?; + for guild in guilds { + poise::builtins::register_in_guild(ctx, &commands::to_vec_optional(), guild).await?; - info!("Registered guild commands to {}", guild); + info!("Registered guild commands to {}", guild); + } + } else { + warn!("No storage backend was specified. Features requiring storage will be disabled"); + warn!("Registering optional commands globally since there's no storage backend"); + poise::builtins::register_globally(ctx, &commands::to_vec()).await?; } + let data = Data { storage }; + Ok(data) } async fn handle_shutdown(shard_manager: Arc<serenity::ShardManager>, reason: &str) { warn!("{reason}! Shutting down bot..."); shard_manager.shutdown_all().await; - println!("{}", "Everything is shutdown. Goodbye!".green()); + println!("Everything is shutdown. Goodbye!"); } #[tokio::main] async fn main() -> Result<()> { - color_eyre::install()?; dotenvy::dotenv().ok(); + color_eyre::install()?; env_logger::init(); - let token = std::env::var("TOKEN").wrap_err_with(|| "Couldn't find token in environment!")?; + let token = std::env::var("TOKEN").wrap_err("Couldn't find bot token in environment!")?; let intents = serenity::GatewayIntents::non_privileged() | serenity::GatewayIntents::MESSAGE_CONTENT; let options = FrameworkOptions { - commands: { - let mut commands = commands::global(); - commands.append(&mut commands::moderation()); - commands - }, - on_error: |error| Box::pin(handlers::handle_error(error)), + commands: commands::to_vec(), + on_error: |error| Box::pin(handlers::error::handle(error)), command_check: Some(|ctx| { Box::pin(async move { Ok(ctx.author().id != ctx.framework().bot_id) }) }), - event_handler: |ctx, event, framework, data| { - Box::pin(handlers::handle_event(ctx, event, framework, data)) + event_handler: |ctx, event, _framework, data| { + Box::pin(handlers::event::handle(ctx, event, data)) }, prefix_options: PrefixFrameworkOptions { @@ -116,7 +104,7 @@ async fn main() -> Result<()> { let framework = Framework::builder() .options(options) - .setup(|ctx, ready, framework| Box::pin(setup(ctx, ready, framework))) + .setup(|ctx, _ready, _framework| Box::pin(setup(ctx))) .build(); let mut client = serenity::ClientBuilder::new(token, intents) @@ -124,12 +112,15 @@ async fn main() -> Result<()> { .await?; let shard_manager = client.shard_manager.clone(); + #[cfg(target_family = "unix")] let mut sigterm = signal(SignalKind::terminate())?; + #[cfg(target_family = "windows")] + let mut sigterm = ctrl_close()?; tokio::select! { result = client.start() => result.map_err(Report::from), _ = sigterm.recv() => { - handle_shutdown(shard_manager, "Recieved SIGTERM").await; + handle_shutdown(shard_manager, "Received SIGTERM").await; std::process::exit(0); }, _ = ctrl_c() => { |
