diff --git a/Cargo.lock b/Cargo.lock index 6238db1..f29d4e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,7 +263,7 @@ dependencies = [ "eyre", "indenter", "once_cell", - "owo-colors 3.5.0", + "owo-colors", "tracing-error", ] @@ -274,7 +274,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" dependencies = [ "once_cell", - "owo-colors 3.5.0", + "owo-colors", "tracing-core", "tracing-error", ] @@ -1235,12 +1235,6 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" -[[package]] -name = "owo-colors" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" - [[package]] name = "parking_lot" version = "0.12.1" @@ -1459,7 +1453,6 @@ dependencies = [ "gray_matter", "log", "octocrab", - "owo-colors 4.0.0", "poise", "redis", "regex", @@ -1467,7 +1460,6 @@ dependencies = [ "serde", "serde_json", "tokio", - "url", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index dd9eed8..388def1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ eyre = "0.6.11" log = "0.4.20" poise = "0.6.1" octocrab = "0.37.0" -owo-colors = "4.0.0" redis = { version = "0.25.2", features = ["tokio-comp", "tokio-rustls-comp"] } regex = "1.10.3" reqwest = { version = "0.12.2", default-features = false, features = [ @@ -37,7 +36,17 @@ tokio = { version = "1.35.1", features = [ "rt-multi-thread", "signal", ] } -url = { version = "2.5.0", features = ["serde"] } + +[lints.rust] +unsafe_code = "forbid" + +[lints.clippy] +complexity = "warn" +correctness = "deny" +pedantic = "warn" +perf = "warn" +style = "warn" +suspicious = "deny" [profile.release] codegen-units = 1 diff --git a/build.rs b/build.rs index 9925fb4..5638757 100644 --- a/build.rs +++ b/build.rs @@ -6,7 +6,7 @@ use gray_matter::{engine, Matter}; include!("src/tags.rs"); -/// generate the ChoiceParameter enum and tag data we will use in the `tag` command +/// generate the `ChoiceParameter` enum and tag data we will use in the `tag` command #[allow(dead_code)] fn main() { let out_dir = env::var_os("OUT_DIR").unwrap(); diff --git a/src/api/github.rs b/src/api/github.rs index 42f4a8b..f0a1fa4 100644 --- a/src/api/github.rs +++ b/src/api/github.rs @@ -1,12 +1,12 @@ -use std::sync::{Arc, OnceLock}; +use std::sync::OnceLock; use eyre::{Context, OptionExt, Result}; use log::debug; use octocrab::Octocrab; -fn octocrab() -> &'static Arc { - static OCTOCRAB: OnceLock> = OnceLock::new(); - OCTOCRAB.get_or_init(octocrab::instance) +fn octocrab() -> &'static Octocrab { + static OCTOCRAB: OnceLock = OnceLock::new(); + OCTOCRAB.get_or_init(Octocrab::default) } pub async fn get_latest_prism_version() -> Result { diff --git a/src/api/mod.rs b/src/api/mod.rs index 99d51fb..711334c 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -3,6 +3,7 @@ use std::sync::OnceLock; use eyre::Result; use log::debug; use reqwest::{Client, Response}; +use serde::de::DeserializeOwned; pub mod dadjoke; pub mod github; @@ -44,3 +45,10 @@ pub async fn bytes_from_url(url: &str) -> Result> { let bytes = resp.bytes().await?; Ok(bytes.to_vec()) } + +pub async fn json_from_url(url: &str) -> Result { + let resp = get_url(url).await?; + + let json = resp.json().await?; + Ok(json) +} diff --git a/src/api/paste_gg.rs b/src/api/paste_gg.rs index 4fdd59d..01df669 100644 --- a/src/api/paste_gg.rs +++ b/src/api/paste_gg.rs @@ -6,7 +6,7 @@ const PASTE_GG: &str = "https://api.paste.gg/v1"; const PASTES: &str = "/pastes"; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize, Serialize)] -enum Status { +pub enum Status { #[serde(rename = "success")] Success, #[serde(rename = "error")] @@ -15,10 +15,10 @@ enum Status { #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Response { - status: Status, + pub status: Status, pub result: Option>, - error: Option, - message: Option, + pub error: Option, + pub message: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] @@ -27,12 +27,11 @@ pub struct Files { pub name: Option, } -pub async fn get_files(id: &str) -> Result> { +pub async fn files_from(id: &str) -> Result> { let url = format!("{PASTE_GG}{PASTES}/{id}/files"); debug!("Making request to {url}"); - let resp = super::client().get(url).send().await?; - resp.error_for_status_ref()?; - let resp: Response = resp.json().await?; + + let resp: Response = super::json_from_url(&url).await?; if resp.status == Status::Error { let message = resp diff --git a/src/api/pluralkit.rs b/src/api/pluralkit.rs index 5e28512..2fdb4cb 100644 --- a/src/api/pluralkit.rs +++ b/src/api/pluralkit.rs @@ -11,17 +11,15 @@ pub struct Message { const PLURAL_KIT: &str = "https://api.pluralkit.me/v2"; const MESSAGES: &str = "/messages"; -pub async fn get_sender(message_id: MessageId) -> Result { +pub async fn sender_from(message_id: MessageId) -> Result { let url = format!("{PLURAL_KIT}{MESSAGES}/{message_id}"); - debug!("Making request to {url}"); - let resp = super::client().get(url).send().await?; - resp.error_for_status_ref()?; - let data: Message = resp.json().await?; + let resp: Message = super::json_from_url(&url).await?; + let id: u64 = - data.sender.parse().wrap_err_with(|| { - format!("Couldn't parse response from PluralKit as a UserId! Here's the response:\n{data:#?}") + resp.sender.parse().wrap_err_with(|| { + format!("Couldn't parse response from PluralKit as a UserId! Here's the response:\n{resp:#?}") })?; let sender = UserId::from(id); diff --git a/src/api/prism_meta.rs b/src/api/prism_meta.rs index 9b23fd4..e2114b7 100644 --- a/src/api/prism_meta.rs +++ b/src/api/prism_meta.rs @@ -14,7 +14,7 @@ pub struct MinecraftPackageJson { const META: &str = "https://meta.prismlauncher.org/v1"; const MINECRAFT_PACKAGEJSON: &str = "/net.minecraft/package.json"; -pub async fn get_latest_minecraft_version() -> Result { +pub async fn latest_minecraft_version() -> Result { let url = format!("{META}{MINECRAFT_PACKAGEJSON}"); debug!("Making request to {url}"); diff --git a/src/commands/general/help.rs b/src/commands/general/help.rs index f91d97d..bc6cb76 100644 --- a/src/commands/general/help.rs +++ b/src/commands/general/help.rs @@ -1,6 +1,5 @@ -use crate::Context; +use crate::{Context, Error}; -use eyre::Result; use log::trace; use poise::samples::HelpConfiguration; @@ -9,7 +8,7 @@ use poise::samples::HelpConfiguration; pub async fn help( ctx: Context<'_>, #[description = "Provide information about a specific command"] command: Option, -) -> Result<()> { +) -> Result<(), Error> { trace!("Running help command"); let configuration = HelpConfiguration { diff --git a/src/commands/general/joke.rs b/src/commands/general/joke.rs index fbced97..a064997 100644 --- a/src/commands/general/joke.rs +++ b/src/commands/general/joke.rs @@ -1,12 +1,11 @@ -use crate::api::dadjoke; -use crate::Context; +use crate::{api::dadjoke, Context, Error}; use eyre::Result; use log::trace; /// It's a joke #[poise::command(slash_command, prefix_command, track_edits = true)] -pub async fn joke(ctx: Context<'_>) -> Result<()> { +pub async fn joke(ctx: Context<'_>) -> Result<(), Error> { trace!("Running joke command"); ctx.defer().await?; diff --git a/src/commands/general/members.rs b/src/commands/general/members.rs index 483b1a3..0476972 100644 --- a/src/commands/general/members.rs +++ b/src/commands/general/members.rs @@ -1,13 +1,13 @@ -use crate::{consts::Colors, Context}; +use crate::{consts::Colors, Context, Error}; -use eyre::{eyre, Context as _, OptionExt, Result}; +use eyre::{eyre, Context as _, OptionExt}; use log::trace; use poise::serenity_prelude::CreateEmbed; use poise::CreateReply; /// Returns the number of members in the server #[poise::command(slash_command, prefix_command, guild_only = true, track_edits = true)] -pub async fn members(ctx: Context<'_>) -> Result<()> { +pub async fn members(ctx: Context<'_>) -> Result<(), Error> { trace!("Running members command"); ctx.defer().await?; @@ -29,7 +29,7 @@ pub async fn members(ctx: Context<'_>) -> Result<()> { let embed = CreateEmbed::new() .title(format!("{member_count} total members!",)) .description(format!("{online_count} online members",)) - .color(Colors::BLUE); + .color(Colors::Blue); let reply = CreateReply::default().embed(embed); ctx.send(reply).await?; diff --git a/src/commands/general/ping.rs b/src/commands/general/ping.rs index 90fc53f..09544ee 100644 --- a/src/commands/general/ping.rs +++ b/src/commands/general/ping.rs @@ -1,11 +1,10 @@ -use crate::Context; +use crate::{Context, Error}; -use eyre::Result; use log::trace; /// Replies with pong! #[poise::command(slash_command, prefix_command, track_edits = true, ephemeral)] -pub async fn ping(ctx: Context<'_>) -> Result<()> { +pub async fn ping(ctx: Context<'_>) -> Result<(), Error> { trace!("Running ping command!"); ctx.say("Pong!").await?; Ok(()) diff --git a/src/commands/general/rory.rs b/src/commands/general/rory.rs index 6bdc6f5..bc8cd63 100644 --- a/src/commands/general/rory.rs +++ b/src/commands/general/rory.rs @@ -1,7 +1,5 @@ -use crate::api::rory; -use crate::Context; +use crate::{api::rory, Context, Error}; -use eyre::Result; use log::trace; use poise::serenity_prelude::{CreateEmbed, CreateEmbedFooter}; use poise::CreateReply; @@ -11,7 +9,7 @@ use poise::CreateReply; pub async fn rory( ctx: Context<'_>, #[description = "specify a Rory ID"] id: Option, -) -> Result<()> { +) -> Result<(), Error> { trace!("Running rory command"); ctx.defer().await?; diff --git a/src/commands/general/say.rs b/src/commands/general/say.rs index 9aa8098..b873afd 100644 --- a/src/commands/general/say.rs +++ b/src/commands/general/say.rs @@ -1,6 +1,5 @@ -use crate::{utils, Context}; +use crate::{utils, Context, Error}; -use eyre::Result; use log::trace; use poise::serenity_prelude::{CreateEmbed, CreateMessage}; @@ -15,18 +14,12 @@ use poise::serenity_prelude::{CreateEmbed, CreateMessage}; pub async fn say( ctx: Context<'_>, #[description = "the message content"] content: String, -) -> Result<()> { +) -> Result<(), Error> { let channel = ctx.channel_id(); channel.say(ctx, &content).await?; ctx.say("I said what you said!").await?; - if let Some(channel_id) = ctx - .data() - .config - .discord_config() - .channels() - .log_channel_id() - { + if let Some(channel_id) = ctx.data().config.discord.channels.log_channel_id { let author = utils::embed_author_from_user(ctx.author()); let embed = CreateEmbed::default() diff --git a/src/commands/general/stars.rs b/src/commands/general/stars.rs index 916c03f..703586a 100644 --- a/src/commands/general/stars.rs +++ b/src/commands/general/stars.rs @@ -1,13 +1,12 @@ -use crate::{api, consts::Colors, Context}; +use crate::{api, consts::Colors, Context, Error}; -use eyre::Result; use log::trace; use poise::serenity_prelude::CreateEmbed; use poise::CreateReply; /// Returns GitHub stargazer count #[poise::command(slash_command, prefix_command, track_edits = true)] -pub async fn stars(ctx: Context<'_>) -> Result<()> { +pub async fn stars(ctx: Context<'_>) -> Result<(), Error> { trace!("Running stars command"); ctx.defer().await?; @@ -27,7 +26,7 @@ pub async fn stars(ctx: Context<'_>) -> Result<()> { let embed = CreateEmbed::new() .title(format!("⭐ {count} total stars!")) - .color(Colors::YELLOW); + .color(Colors::Yellow); let reply = CreateReply::default().embed(embed); ctx.send(reply).await?; diff --git a/src/commands/general/tag.rs b/src/commands/general/tag.rs index 607ba8e..3cfe1a1 100644 --- a/src/commands/general/tag.rs +++ b/src/commands/general/tag.rs @@ -1,10 +1,10 @@ #![allow(non_camel_case_types, clippy::upper_case_acronyms)] -use crate::{consts::Colors, tags::Tag, Context}; +use crate::{consts::Colors, tags::Tag, Context, Error}; use std::env; use std::str::FromStr; use std::sync::OnceLock; -use eyre::{eyre, Result}; +use eyre::eyre; use log::trace; use poise::serenity_prelude::{Color, CreateEmbed, User}; use poise::CreateReply; @@ -26,7 +26,7 @@ pub async fn tag( ctx: Context<'_>, #[description = "the tag to send"] name: Choice, #[description = "a user to mention"] user: Option, -) -> Result<()> { +) -> Result<(), Error> { trace!("Running tag command"); let tag_id = name.as_str(); diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 33216d3..a849933 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -1,6 +1,4 @@ -use crate::Data; - -use eyre::Report; +use crate::{Data, Error}; mod general; mod moderation; @@ -32,7 +30,7 @@ macro_rules! module_macro { module_macro!(general); module_macro!(moderation); -pub type Command = poise::Command; +pub type Command = poise::Command; pub fn get() -> Vec { vec![ diff --git a/src/commands/moderation/set_welcome.rs b/src/commands/moderation/set_welcome.rs index b10477a..4882af4 100644 --- a/src/commands/moderation/set_welcome.rs +++ b/src/commands/moderation/set_welcome.rs @@ -1,24 +1,23 @@ use std::{fmt::Write, str::FromStr}; -use crate::{api, utils, Context}; +use crate::{api, utils, Context, Error}; -use eyre::{bail, Result}; +use eyre::Result; use log::trace; use poise::serenity_prelude::{ futures::TryStreamExt, Attachment, CreateActionRow, CreateButton, CreateEmbed, CreateMessage, Mentionable, Message, ReactionType, }; use serde::{Deserialize, Serialize}; -use url::Url; #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(deny_unknown_fields)] struct WelcomeEmbed { title: String, description: Option, - url: Option, + url: Option, hex_color: Option, - image: Option, + image: Option, } impl From for CreateMessage { @@ -112,11 +111,11 @@ pub async fn set_welcome( ctx: Context<'_>, #[description = "A file to use"] file: Option, #[description = "A URL for a file to use"] url: Option, -) -> Result<()> { +) -> Result<(), Error> { trace!("Running set_welcome command!"); - let configured_channels = ctx.data().config.discord_config().channels(); - let Some(channel_id) = configured_channels.welcome_channel_id() else { + let configured_channels = ctx.data().config.discord.channels; + let Some(channel_id) = configured_channels.welcome_channel_id else { ctx.say("You don't have a welcome channel ID set, so I can't do anything :(") .await?; return Ok(()); @@ -127,7 +126,7 @@ pub async fn set_welcome( // download attachment from discord or URL let file = if let Some(attachment) = file { let Some(content_type) = &attachment.content_type else { - bail!("Welcome channel attachment was sent without a content type!"); + return Err("Welcome channel attachment was sent without a content type!".into()); }; if !content_type.starts_with("application/json;") { @@ -139,11 +138,6 @@ pub async fn set_welcome( let downloaded = attachment.download().await?; String::from_utf8(downloaded)? } else if let Some(url) = url { - if Url::parse(&url).is_err() { - ctx.say("Invalid url!").await?; - return Ok(()); - } - api::text_from_url(&url).await? } else { ctx.say("A text file or URL must be provided!").await?; @@ -180,7 +174,7 @@ pub async fn set_welcome( channel_id.say(ctx, message).await?; } - if let Some(log_channel) = configured_channels.log_channel_id() { + if let Some(log_channel) = configured_channels.log_channel_id { let author = utils::embed_author_from_user(ctx.author()); let embed = CreateEmbed::new() .title("set_welcome command used!") diff --git a/src/config/bot.rs b/src/config/bot.rs index ebad8fe..c34c5b0 100644 --- a/src/config/bot.rs +++ b/src/config/bot.rs @@ -2,7 +2,7 @@ use log::{info, warn}; #[derive(Clone, Debug, Default)] pub struct Config { - redis_url: Option, + pub redis_url: Option, } impl Config { @@ -21,8 +21,4 @@ impl Config { Self::new(redis_url) } - - pub fn redis_url(&self) -> Option<&str> { - self.redis_url.as_deref() - } } diff --git a/src/config/discord.rs b/src/config/discord.rs index 8ef8082..27782b1 100644 --- a/src/config/discord.rs +++ b/src/config/discord.rs @@ -5,13 +5,13 @@ use poise::serenity_prelude::ChannelId; #[derive(Clone, Copy, Debug, Default)] pub struct RefractionChannels { - log_channel_id: Option, - welcome_channel_id: Option, + pub log_channel_id: Option, + pub welcome_channel_id: Option, } #[derive(Clone, Debug, Default)] pub struct Config { - channels: RefractionChannels, + pub channels: RefractionChannels, } impl RefractionChannels { @@ -45,14 +45,6 @@ impl RefractionChannels { .ok() .and_then(|env_var| ChannelId::from_str(&env_var).ok()) } - - pub fn log_channel_id(&self) -> Option<&ChannelId> { - self.log_channel_id.as_ref() - } - - pub fn welcome_channel_id(&self) -> Option<&ChannelId> { - self.welcome_channel_id.as_ref() - } } impl Config { @@ -65,8 +57,4 @@ impl Config { Self::new(channels) } - - pub fn channels(&self) -> &RefractionChannels { - &self.channels - } } diff --git a/src/config/mod.rs b/src/config/mod.rs index 568a7e2..3507670 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -3,8 +3,8 @@ mod discord; #[derive(Debug, Clone, Default)] pub struct Config { - bot: bot::Config, - discord: discord::Config, + pub bot: bot::Config, + pub discord: discord::Config, } impl Config { @@ -21,12 +21,4 @@ impl Config { Self::new(bot, discord) } - - pub fn bot_config(&self) -> &bot::Config { - &self.bot - } - - pub fn discord_config(&self) -> &discord::Config { - &self.discord - } } diff --git a/src/consts.rs b/src/consts.rs index e53ae36..3b3f6e4 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -3,18 +3,31 @@ use std::str::FromStr; use poise::serenity_prelude::Colour; +const BLUE: u32 = 0x60A5FA; +const GREEN: u32 = 0x22C55E; +const ORANGE: u32 = 0xFB923C; +const RED: u32 = 0xEF4444; +const YELLOW: u32 = 0xFDE047; + #[derive(Clone, Copy, Debug, Default)] -pub struct Colors(i32); +pub enum Colors { + Blue, + #[default] + Green, + Orange, + Red, + Yellow, +} -impl Colors { - pub const RED: i32 = 0xEF4444; - pub const GREEN: i32 = 0x22C55E; - pub const BLUE: i32 = 0x60A5FA; - pub const YELLOW: i32 = 0xFDE047; - pub const ORANGE: i32 = 0xFB923C; - - pub fn as_i32(self) -> i32 { - self.0 +impl From for Colour { + fn from(value: Colors) -> Self { + Self::from(match &value { + Colors::Blue => BLUE, + Colors::Green => GREEN, + Colors::Orange => ORANGE, + Colors::Red => RED, + Colors::Yellow => YELLOW, + }) } } @@ -22,18 +35,12 @@ impl FromStr for Colors { type Err = (); fn from_str(s: &str) -> Result { match s.to_lowercase().as_str() { - "red" => Ok(Colors(Self::RED)), - "green" => Ok(Colors(Self::GREEN)), - "blue" => Ok(Colors(Self::BLUE)), - "yellow" => Ok(Colors(Self::YELLOW)), - "orange" => Ok(Colors(Self::ORANGE)), + "blue" => Ok(Self::Blue), + "green" => Ok(Self::Green), + "orange" => Ok(Self::Orange), + "red" => Ok(Self::Red), + "yellow" => Ok(Self::Yellow), _ => Err(()), } } } - -impl From for Colour { - fn from(value: Colors) -> Self { - Self::from(value.as_i32()) - } -} diff --git a/src/handlers/error.rs b/src/handlers/error.rs index 16fcda4..58d7a86 100644 --- a/src/handlers/error.rs +++ b/src/handlers/error.rs @@ -1,8 +1,7 @@ -use crate::{consts::Colors, Data}; +use crate::{consts::Colors, Data, Error}; use std::fmt::Write; -use eyre::Report; use log::error; use poise::serenity_prelude::{CreateEmbed, Timestamp}; use poise::{CreateReply, FrameworkError}; @@ -16,7 +15,7 @@ macro_rules! writelne { } } -pub async fn handle(error: FrameworkError<'_, Data, Report>) { +pub async fn handle(error: FrameworkError<'_, Data, Error>) { match error { FrameworkError::Setup { error, framework, .. @@ -34,7 +33,7 @@ pub async fn handle(error: FrameworkError<'_, Data, Report>) { .title("Something went wrong!") .description("oopsie") .timestamp(Timestamp::now()) - .color(Colors::RED); + .color(Colors::Red); let reply = CreateReply::default().embed(embed); diff --git a/src/handlers/event/analyze_logs/issues.rs b/src/handlers/event/analyze_logs/issues.rs index c2254bc..730c9e9 100644 --- a/src/handlers/event/analyze_logs/issues.rs +++ b/src/handlers/event/analyze_logs/issues.rs @@ -198,7 +198,9 @@ async fn outdated_launcher(log: &str, data: &Data) -> Result { if let Ok(version) = storage.launcher_version().await { version } else { - api::github::get_latest_prism_version().await? + let version = api::github::get_latest_prism_version().await?; + storage.cache_launcher_version(&version).await?; + version } } else { trace!("Not caching launcher version, as we're running without a storage backend"); diff --git a/src/handlers/event/analyze_logs/mod.rs b/src/handlers/event/analyze_logs/mod.rs index e490d09..cb2b0b4 100644 --- a/src/handlers/event/analyze_logs/mod.rs +++ b/src/handlers/event/analyze_logs/mod.rs @@ -48,10 +48,10 @@ pub async fn handle(ctx: &Context, message: &Message, data: &Data) -> Result<()> if issues.is_empty() { e = e - .color(Colors::GREEN) + .color(Colors::Green) .description("No issues found automatically"); } else { - e = e.color(Colors::RED); + e = e.color(Colors::Red); for (title, description) in issues { e = e.field(title, description, false); diff --git a/src/handlers/event/analyze_logs/providers/paste_gg.rs b/src/handlers/event/analyze_logs/providers/paste_gg.rs index 7ebead7..60f3c4b 100644 --- a/src/handlers/event/analyze_logs/providers/paste_gg.rs +++ b/src/handlers/event/analyze_logs/providers/paste_gg.rs @@ -19,7 +19,7 @@ impl super::LogProvider for PasteGG { } async fn fetch(&self, content: &str) -> Result { - let files = paste_gg::get_files(content).await?; + let files = paste_gg::files_from(content).await?; let result = files .result .ok_or_eyre("Got an empty result from paste.gg!")?; diff --git a/src/handlers/event/expand_link.rs b/src/handlers/event/expand_link.rs index ae73b56..8e3517f 100644 --- a/src/handlers/event/expand_link.rs +++ b/src/handlers/event/expand_link.rs @@ -4,7 +4,7 @@ use poise::serenity_prelude::{Context, CreateAllowedMentions, CreateMessage, Mes use crate::utils; pub async fn handle(ctx: &Context, message: &Message) -> Result<()> { - let embeds = utils::resolve_message::from_message(ctx, message).await?; + let embeds = utils::messages::from_message(ctx, message).await?; if !embeds.is_empty() { let allowed_mentions = CreateAllowedMentions::new().replied_user(false); diff --git a/src/handlers/event/mod.rs b/src/handlers/event/mod.rs index 89f69d6..dcbfc4d 100644 --- a/src/handlers/event/mod.rs +++ b/src/handlers/event/mod.rs @@ -1,6 +1,5 @@ -use crate::{api, Data}; +use crate::{api, Data, Error}; -use eyre::{Report, Result}; use log::{debug, info, trace}; use poise::serenity_prelude::{ActivityData, Context, FullEvent, OnlineStatus}; use poise::FrameworkContext; @@ -10,20 +9,20 @@ mod delete_on_reaction; mod eta; mod expand_link; mod give_role; -pub mod pluralkit; +mod pluralkit; mod support_onboard; pub async fn handle( ctx: &Context, event: &FullEvent, - _: FrameworkContext<'_, Data, Report>, + _: FrameworkContext<'_, Data, Error>, data: &Data, -) -> Result<()> { +) -> Result<(), Error> { match event { FullEvent::Ready { data_about_bot } => { info!("Logged in as {}!", data_about_bot.user.name); - let latest_minecraft_version = api::prism_meta::get_latest_minecraft_version().await?; + let latest_minecraft_version = api::prism_meta::latest_minecraft_version().await?; let activity = ActivityData::playing(format!("Minecraft {latest_minecraft_version}")); info!("Setting presence to activity {activity:#?}"); diff --git a/src/handlers/event/pluralkit.rs b/src/handlers/event/pluralkit.rs index 27bdba1..dce3c37 100644 --- a/src/handlers/event/pluralkit.rs +++ b/src/handlers/event/pluralkit.rs @@ -15,7 +15,7 @@ pub async fn is_message_proxied(message: &Message) -> Result { ); sleep(PK_DELAY).await; - let proxied = api::pluralkit::get_sender(message.id).await.is_ok(); + let proxied = api::pluralkit::sender_from(message.id).await.is_ok(); Ok(proxied) } @@ -36,7 +36,7 @@ pub async fn handle(_: &Context, msg: &Message, storage: &Storage) -> Result<()> ); sleep(PK_DELAY).await; - if let Ok(sender) = api::pluralkit::get_sender(msg.id).await { + if let Ok(sender) = api::pluralkit::sender_from(msg.id).await { storage.store_user_plurality(sender).await?; } diff --git a/src/main.rs b/src/main.rs index 3e0e101..09de4a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,10 @@ -#![warn(clippy::all, clippy::pedantic, clippy::perf)] -#![allow(clippy::missing_errors_doc)] -#![forbid(unsafe_code)] - use std::{sync::Arc, time::Duration}; -use eyre::{bail, Context as _, Report, Result}; +use eyre::Context as _; use log::{info, trace, warn}; - use poise::{ serenity_prelude as serenity, EditTracker, Framework, FrameworkOptions, PrefixFrameworkOptions, }; - -use owo_colors::OwoColorize; - use tokio::signal::ctrl_c; #[cfg(target_family = "unix")] use tokio::signal::unix::{signal, SignalKind}; @@ -31,7 +23,8 @@ mod utils; use config::Config; use storage::Storage; -type Context<'a> = poise::Context<'a, Data, Report>; +type Error = Box; +type Context<'a> = poise::Context<'a, Data, Error>; #[derive(Clone, Debug, Default)] pub struct Data { @@ -39,21 +32,14 @@ pub struct Data { storage: Option, } -impl Data { - #[must_use] - pub fn new(config: Config, storage: Option) -> Self { - Self { config, storage } - } -} - async fn setup( ctx: &serenity::Context, _: &serenity::Ready, - framework: &Framework, -) -> Result { + framework: &Framework, +) -> Result { let config = Config::new_from_env(); - let storage = if let Some(url) = config.bot_config().redis_url() { + let storage = if let Some(url) = &config.bot.redis_url { Some(Storage::from_url(url)?) } else { None @@ -61,13 +47,15 @@ async fn setup( if let Some(storage) = storage.as_ref() { if !storage.clone().has_connection() { - bail!("You specified a storage backend but there's no connection! Is it running?") + return Err( + "You specified a storage backend but there's no connection! Is it running?".into(), + ); } trace!("Redis connection looks good!"); } - let data = Data::new(config, storage); + let data = Data { config, storage }; poise::builtins::register_globally(ctx, &framework.options().commands).await?; info!("Registered global commands!"); @@ -78,11 +66,11 @@ async fn setup( async fn handle_shutdown(shard_manager: Arc, 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<()> { +async fn main() -> eyre::Result<()> { dotenvy::dotenv().ok(); color_eyre::install()?; env_logger::init(); @@ -134,7 +122,7 @@ async fn main() -> Result<()> { let mut sigterm = ctrl_close()?; tokio::select! { - result = client.start() => result.map_err(Report::from), + result = client.start() => result.map_err(eyre::Report::from), _ = sigterm.recv() => { handle_shutdown(shard_manager, "Received SIGTERM").await; std::process::exit(0); diff --git a/src/utils/resolve_message.rs b/src/utils/messages.rs similarity index 98% rename from src/utils/resolve_message.rs rename to src/utils/messages.rs index e6bd2dd..f82073a 100644 --- a/src/utils/resolve_message.rs +++ b/src/utils/messages.rs @@ -24,7 +24,7 @@ fn find_first_image(message: &Message) -> Option { } async fn find_real_author_id(message: &Message) -> UserId { - if let Ok(sender) = pluralkit::get_sender(message.id).await { + if let Ok(sender) = pluralkit::sender_from(message.id).await { sender } else { message.author.id diff --git a/src/utils/mod.rs b/src/utils/mod.rs index d12edb2..8d9dd97 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,6 +1,6 @@ use poise::serenity_prelude::{CreateEmbedAuthor, User}; -pub mod resolve_message; +pub mod messages; pub fn embed_author_from_user(user: &User) -> CreateEmbedAuthor { CreateEmbedAuthor::new(user.tag()).icon_url(