summaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorseth <[email protected]>2024-04-20 02:31:40 +0000
committerGitHub <[email protected]>2024-04-19 22:31:40 -0400
commit3d07413690c551d9f034c93af85ae8da5a495e14 (patch)
tree517d2e053ebdeb9a3be0ffce6dec36cbc4ce316e /src/main.rs
parent1b92b254bc64b356f5c59657d2f0acc767bb2964 (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.rs113
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() => {