diff --git a/Cargo.lock b/Cargo.lock index 0591b56..d470a45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -176,9 +176,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "block-buffer" @@ -541,7 +541,7 @@ version = "0.1.0" dependencies = [ "anyhow", "arrayvec", - "bitflags 2.4.1", + "bitflags 2.4.2", "bool_to_bitflags", "const_format", "dashmap", @@ -929,9 +929,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b553656127a00601c8ae5590fcfdc118e4083a7924b6cf4ffc1ea4b99dc429d7" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" dependencies = [ "bytes", "fnv", @@ -995,9 +995,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" [[package]] name = "hex" @@ -1215,9 +1215,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" @@ -1347,7 +1347,7 @@ version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "cfg-if", "libc", ] @@ -1561,9 +1561,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" [[package]] name = "pnet_base" @@ -1597,8 +1597,8 @@ dependencies = [ [[package]] name = "poise" -version = "0.6.0-rc1" -source = "git+https://github.com/serenity-rs/poise?branch=serenity-next#042072ca35f3724ef7c8a8e3fc4d6dad86d2e8b5" +version = "0.6.1" +source = "git+https://github.com/serenity-rs/poise?branch=serenity-next#53a4082259bf2151909b399413516cbee3053f8e" dependencies = [ "async-trait", "derivative", @@ -1613,8 +1613,8 @@ dependencies = [ [[package]] name = "poise_macros" -version = "0.6.0-rc1" -source = "git+https://github.com/serenity-rs/poise?branch=serenity-next#042072ca35f3724ef7c8a8e3fc4d6dad86d2e8b5" +version = "0.6.1" +source = "git+https://github.com/serenity-rs/poise?branch=serenity-next#53a4082259bf2151909b399413516cbee3053f8e" dependencies = [ "darling", "proc-macro2", @@ -1715,9 +1715,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" dependencies = [ "either", "rayon-core", @@ -1725,9 +1725,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -1915,7 +1915,7 @@ version = "0.38.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "errno", "libc", "linux-raw-sys", @@ -2180,12 +2180,12 @@ dependencies = [ [[package]] name = "serenity" version = "0.12.0" -source = "git+https://github.com/serenity-rs/serenity?branch=next#c9b6766941c8acc8c06c9451e3f4ca46db5d84d4" +source = "git+https://github.com/serenity-rs/serenity?branch=next#395bc9024ed07831a5c1069b09ff209b8e0dd2b5" dependencies = [ "arrayvec", "async-trait", "base64 0.21.7", - "bitflags 2.4.1", + "bitflags 2.4.2", "bool_to_bitflags", "bytes", "chrono", @@ -2206,7 +2206,6 @@ dependencies = [ "tokio", "tokio-tungstenite 0.20.1", "tracing", - "typemap_rev", "typesize", "url", ] @@ -2217,7 +2216,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "593682f6155d07c8b331b3d1060f5aab7e6796caca9f2f66bd9e6855c880e06b" dependencies = [ - "bitflags 2.4.1", + "bitflags 2.4.2", "num-traits", "serde", "serde_json", @@ -2301,9 +2300,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.12.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2593d31f82ead8df961d8bd23a64c2ccf2eb5dd34b0a34bfb4dd54011c72009e" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "socket2" @@ -2318,7 +2317,7 @@ dependencies = [ [[package]] name = "songbird" version = "0.4.0" -source = "git+https://github.com/serenity-rs/songbird?branch=serenity-next#201c4c215b3b3089b7065861446a1cfc56bb762e" +source = "git+https://github.com/GnomedDev/songbird?branch=fix-id#516c3cc400f9c7c7a905e53cbd0b6e50721469f7" dependencies = [ "async-trait", "audiopus", @@ -2330,6 +2329,7 @@ dependencies = [ "flume", "futures", "nohash-hasher", + "nonmax", "parking_lot", "pin-project", "rand", @@ -2352,7 +2352,6 @@ dependencies = [ "tracing", "tracing-futures", "twilight-gateway", - "typemap_rev", "url", "uuid", ] @@ -2483,7 +2482,7 @@ checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" dependencies = [ "atoi", "base64 0.21.7", - "bitflags 2.4.1", + "bitflags 2.4.2", "byteorder", "crc", "dotenvy", @@ -3145,12 +3144,6 @@ dependencies = [ "time", ] -[[package]] -name = "typemap_rev" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74b08b0c1257381af16a5c3605254d529d3e7e109f3c62befc5d168968192998" - [[package]] name = "typenum" version = "1.17.0" @@ -3200,9 +3193,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -3279,9 +3272,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "uuid" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" dependencies = [ "getrandom", ] diff --git a/Cargo.toml b/Cargo.toml index 71c5251..2060a90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ features = ["cache"] branch = "serenity-next" [dependencies.songbird] -git = "https://github.com/serenity-rs/songbird" +git = "https://github.com/GnomedDev/songbird" features = ["builtin-queue"] -branch = "serenity-next" +branch = "fix-id" version = "0.4" diff --git a/src/commands/main.rs b/src/commands/main.rs index f4bd42b..5301f8a 100644 --- a/src/commands/main.rs +++ b/src/commands/main.rs @@ -108,7 +108,7 @@ pub async fn join(ctx: Context<'_>) -> CommandResult { if let Some(bot_vc) = data.songbird.get(guild_id) { let bot_channel_id = bot_vc.lock().await.current_channel(); if let Some(bot_channel_id) = bot_channel_id { - if bot_channel_id.0.get() == author_vc.get() { + if bot_channel_id.get() == author_vc.get() { ctx.say(ctx.gettext("I am already in your voice channel!")) .await?; return Ok(()); @@ -116,7 +116,7 @@ pub async fn join(ctx: Context<'_>) -> CommandResult { ctx.say( ctx.gettext("I am already in <#{channel_id}>!") - .replace("{channel_id}", &bot_channel_id.0.to_string()), + .replace("{channel_id}", &bot_channel_id.to_string()), ) .await?; return Ok(()); @@ -126,7 +126,7 @@ pub async fn join(ctx: Context<'_>) -> CommandResult { { let _typing = ctx.defer_or_broadcast().await?; - let join_vc_lock = JoinVCToken::acquire(data, guild_id); + let join_vc_lock = JoinVCToken::acquire(&data, guild_id); let join_vc_result = data .songbird .join_vc(join_vc_lock.lock().await, author_vc) @@ -191,7 +191,7 @@ pub async fn leave(ctx: Context<'_>) -> CommandResult { if let Some(bot_vc) = bot_vc { if !channel_check(&ctx, author_vc).await? { - } else if author_vc.map_or(true, |author_vc| bot_vc.0.get() != author_vc.get()) { + } else if author_vc.map_or(true, |author_vc| bot_vc.get() != author_vc.get()) { ctx.say(ctx.gettext( "Error: You need to be in the same voice channel as me to make me leave!", )) diff --git a/src/commands/premium.rs b/src/commands/premium.rs index f3ac110..b53c98e 100644 --- a/src/commands/premium.rs +++ b/src/commands/premium.rs @@ -195,7 +195,7 @@ pub async fn premium_deactivate(ctx: Context<'_>) -> CommandResult { return Ok(()); } - remove_premium(data, guild_id).await?; + remove_premium(&data, guild_id).await?; let msg = ctx.gettext("Deactivated premium from this server."); ctx.say(msg).await?; diff --git a/src/commands/settings.rs b/src/commands/settings.rs index 3c85b56..c9578e0 100644 --- a/src/commands/settings.rs +++ b/src/commands/settings.rs @@ -104,7 +104,7 @@ pub async fn settings(ctx: Context<'_>) -> CommandResult { if guild_voice_row.guild_id.is_none() { Cow::Borrowed(guild_mode.default_voice()) } else { - format_voice(data, &guild_voice_row.voice, guild_mode) + format_voice(&data, &guild_voice_row.voice, guild_mode) } }; @@ -120,7 +120,7 @@ pub async fn settings(ctx: Context<'_>) -> CommandResult { .voice .as_ref() .map_or(Cow::Borrowed(none_str), |voice| { - format_voice(data, voice, currently_set_voice_mode) + format_voice(&data, voice, currently_set_voice_mode) }) }; @@ -353,15 +353,14 @@ async fn voice_autocomplete<'a>( ctx: ApplicationContext<'a>, searching: &'a str, ) -> Vec> { - let Ok((_, mode)) = ctx - .data + let data = ctx.data(); + let Ok((_, mode)) = data .parse_user_or_guild(ctx.interaction.user.id, ctx.interaction.guild_id) .await else { return Vec::new(); }; - let data = ctx.data; let (mut i1, mut i2, mut i3, mut i4); let voices: &mut dyn Iterator = match mode { TTSMode::gTTS => { @@ -420,7 +419,7 @@ async fn translation_languages_autocomplete<'a>( searching: &'a str, ) -> impl Iterator> { let mut filtered_languages = ctx - .data + .data() .translation_languages .iter() .filter(|(_, name)| name.starts_with(searching)) @@ -529,11 +528,11 @@ where let data = ctx.data(); let (_, mode) = data.parse_user_or_guild(author_id, Some(guild_id)).await?; Ok(if let Some(voice) = voice { - if check_valid_voice(data, &voice, mode) { + if check_valid_voice(&data, &voice, mode) { general_db.create_row(key).await?; voice_db.set_one((key, mode), "voice", &voice).await?; - let name = get_voice_name(data, &voice, mode).unwrap_or(&voice); + let name = get_voice_name(&data, &voice, mode).unwrap_or(&voice); Cow::Owned( match target { Target::Guild => ctx.gettext("Changed the server voice to: {voice}"), diff --git a/src/errors.rs b/src/errors.rs index 4899e3d..15ac305 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -5,8 +5,8 @@ use sha2::Digest; use tracing::error; use self::serenity::{ - small_fixed_array::TruncatingInto, CreateActionRow, CreateButton, CreateInteractionResponse, - FullEvent as Event, + small_fixed_array::{FixedString, TruncatingInto}, + CreateActionRow, CreateButton, CreateInteractionResponse, FullEvent as Event, }; use poise::serenity_prelude as serenity; @@ -148,17 +148,18 @@ async fn insert_traceback( } pub async fn handle_unexpected<'a>( - ctx: &serenity::Context, poise_context: FrameworkContext<'_>, event: &'a str, error: Error, // Split out logic if not reliant on this field, to prevent monomorphisation bloat extra_fields: impl IntoIterator, bool)>, - author_name: Option, - icon_url: Option, + author_name: Option<&str>, + icon_url: Option<&str>, ) -> Result<()> { - let data = poise_context.user_data; - let Some((traceback, traceback_hash)) = fetch_update_occurrences(ctx, data, &error).await? + let data = poise_context.user_data(); + let ctx = poise_context.serenity_context; + + let Some((traceback, traceback_hash)) = fetch_update_occurrences(ctx, &data, &error).await? else { return Ok(()); }; @@ -221,28 +222,27 @@ pub async fn handle_unexpected<'a>( embed = embed.author(author_builder); } - insert_traceback(ctx, data, embed, traceback, traceback_hash).await + insert_traceback(ctx, &data, embed, traceback, traceback_hash).await } pub async fn handle_unexpected_default( - ctx: &serenity::Context, framework: FrameworkContext<'_>, name: &str, result: Result<()>, ) -> Result<()> { let error = require!(result.err(), Ok(())); - handle_unexpected(ctx, framework, name, error, [], None, None).await + handle_unexpected(framework, name, error, [], None, None).await } // Listener Handlers pub async fn handle_message( - ctx: &serenity::Context, poise_context: FrameworkContext<'_>, message: &serenity::Message, result: Result, ) -> Result<()> { let error = require!(result.err(), Ok(())); + let ctx = poise_context.serenity_context; let mut extra_fields = Vec::with_capacity(3); if let Some(guild_id) = message.guild_id { @@ -259,19 +259,17 @@ pub async fn handle_message( true, )); handle_unexpected( - ctx, poise_context, "MessageCreate", error, extra_fields, - Some(message.author.name.to_string()), - Some(message.author.face()), + Some(&message.author.name), + Some(&message.author.face()), ) .await } pub async fn handle_member( - ctx: &serenity::Context, framework: FrameworkContext<'_>, member: &serenity::Member, result: Result<(), impl Into>, @@ -284,21 +282,11 @@ pub async fn handle_member( ("User ID", Cow::Owned(member.user.id.to_string()), true), ]; - handle_unexpected( - ctx, - framework, - "GuildMemberAdd", - error, - extra_fields, - None, - None, - ) - .await + handle_unexpected(framework, "GuildMemberAdd", error, extra_fields, None, None).await } pub async fn handle_guild( name: &str, - ctx: &serenity::Context, framework: FrameworkContext<'_>, guild: Option<&serenity::Guild>, result: Result<()>, @@ -306,13 +294,12 @@ pub async fn handle_guild( let error = require!(result.err(), Ok(())); handle_unexpected( - ctx, framework, name, error, [], - guild.as_ref().map(|g| g.name.to_string()), - guild.and_then(serenity::Guild::icon_url), + guild.as_ref().map(|g| g.name.as_str()), + guild.and_then(serenity::Guild::icon_url).as_deref(), ) .await } @@ -437,13 +424,12 @@ pub async fn handle(error: poise::FrameworkError<'_, Data, Error>) -> Result<()> } handle_unexpected( - ctx.serenity_context(), ctx.framework(), "command", error, extra_fields, - Some(author.name.to_string()), - Some(author.face()), + Some(&author.name), + Some(&author.face()), ) .await?; @@ -496,7 +482,6 @@ pub async fn handle(error: poise::FrameworkError<'_, Data, Error>) -> Result<()> } poise::FrameworkError::EventHandler { - ctx, error, event, framework, @@ -509,27 +494,25 @@ pub async fn handle(error: poise::FrameworkError<'_, Data, Error>) -> Result<()> match event { Event::Message { new_message } => { - handle_message(ctx, framework, new_message, Err(error)).await?; + handle_message(framework, new_message, Err(error)).await?; } Event::GuildMemberAddition { new_member } => { - handle_member(ctx, framework, new_member, Err(error)).await?; + handle_member(framework, new_member, Err(error)).await?; } Event::GuildCreate { guild, .. } => { - handle_guild("GuildCreate", ctx, framework, Some(guild), Err(error)).await?; + handle_guild("GuildCreate", framework, Some(guild), Err(error)).await?; } Event::GuildDelete { full, .. } => { - handle_guild("GuildDelete", ctx, framework, full.as_ref(), Err(error)).await?; + handle_guild("GuildDelete", framework, full.as_ref(), Err(error)).await?; } Event::VoiceStateUpdate { .. } => { - handle_unexpected_default(ctx, framework, "VoiceStateUpdate", Err(error)) - .await?; + handle_unexpected_default(framework, "VoiceStateUpdate", Err(error)).await?; } Event::InteractionCreate { .. } => { - handle_unexpected_default(ctx, framework, "InteractionCreate", Err(error)) - .await?; + handle_unexpected_default(framework, "InteractionCreate", Err(error)).await?; } Event::Ready { .. } => { - handle_unexpected_default(ctx, framework, "Ready", Err(error)).await?; + handle_unexpected_default(framework, "Ready", Err(error)).await?; } _ => { tracing::warn!("Unhandled {} error: {:?}", event.snake_case_name(), error); @@ -542,7 +525,8 @@ pub async fn handle(error: poise::FrameworkError<'_, Data, Error>) -> Result<()> | poise::FrameworkError::NotAnOwner { .. } | poise::FrameworkError::UnknownInteraction { .. } | poise::FrameworkError::SubcommandRequired { .. } - | poise::FrameworkError::UnknownCommand { .. } => {} + | poise::FrameworkError::UnknownCommand { .. } + | poise::FrameworkError::NonCommandMessage { .. } => {} poise::FrameworkError::GuildOnly { ctx, .. } => { let error = ctx .gettext("`/{command_name}` cannot be used in private messages, please run this command in a server channel.") @@ -559,13 +543,12 @@ pub async fn handle(error: poise::FrameworkError<'_, Data, Error>) -> Result<()> } pub async fn interaction_create( - ctx: &serenity::Context, - interaction: &serenity::Interaction, framework: FrameworkContext<'_>, + interaction: &serenity::Interaction, ) -> Result<(), Error> { if let serenity::Interaction::Component(interaction) = interaction { if interaction.data.custom_id == VIEW_TRACEBACK_CUSTOM_ID { - handle_traceback_button(ctx, framework.user_data, interaction).await?; + handle_traceback_button(framework, interaction).await?; }; }; @@ -573,14 +556,13 @@ pub async fn interaction_create( } pub async fn handle_traceback_button( - ctx: &serenity::Context, - data: &Data, + framework: FrameworkContext<'_>, interaction: &serenity::ComponentInteraction, ) -> Result<(), Error> { let row: Option = sqlx::query_as("SELECT traceback FROM errors WHERE message_id = $1") .bind(interaction.message.id.get() as i64) - .fetch_optional(&data.pool) + .fetch_optional(&framework.user_data().pool) .await?; let mut response_data = serenity::CreateInteractionResponseMessage::default().ephemeral(true); @@ -594,17 +576,19 @@ pub async fn handle_traceback_button( }; interaction - .create_response(&ctx.http, CreateInteractionResponse::Message(response_data)) + .create_response( + &framework.serenity_context, + CreateInteractionResponse::Message(response_data), + ) .await?; Ok(()) } struct TrackErrorHandler, bool)>> { ctx: serenity::Context, - data: Data, shard_manager: Arc, extra_fields: Iter, - author_name: String, + author_name: FixedString, icon_url: String, } @@ -619,17 +603,15 @@ where // HACK: Cannot get reference to options from here, so has to be faked. // This is fine because the options are not used in the error handler. let framework_context = FrameworkContext { - user_data: &self.data, + serenity_context: &self.ctx, shard_manager: &self.shard_manager, - bot_id: self.ctx.cache.current_user().id, options: &poise::FrameworkOptions::default(), }; - let author_name = Some(self.author_name.clone()); - let icon_url = Some(self.icon_url.clone()); + let author_name = Some(self.author_name.as_str()); + let icon_url = Some(self.icon_url.as_str()); let result = handle_unexpected( - &self.ctx, framework_context, "TrackError", error.into(), @@ -640,7 +622,7 @@ where .await; if let Err(err_err) = result { - tracing::error!("Songbird unhandled track error: {}", err_err); + tracing::error!("Songbird unhandled track error: {err_err}"); } } } @@ -654,9 +636,8 @@ where pub fn handle_track( ctx: serenity::Context, shard_manager: Arc, - data: Data, extra_fields: Iter, - author_name: String, + author_name: FixedString, icon_url: String, track: &songbird::tracks::TrackHandle, @@ -672,7 +653,6 @@ where songbird::Event::Track(songbird::TrackEvent::Error), TrackErrorHandler { ctx, - data, shard_manager, extra_fields, author_name, diff --git a/src/events/channel.rs b/src/events/channel.rs index eb42ea6..4f3affe 100644 --- a/src/events/channel.rs +++ b/src/events/channel.rs @@ -1,6 +1,6 @@ use poise::serenity_prelude as serenity; -use crate::{Data, Result}; +use crate::{structs::FrameworkContext, Result}; async fn guild_call_channel_id( songbird: &songbird::Songbird, @@ -11,11 +11,16 @@ async fn guild_call_channel_id( .lock() .await .current_channel() - .map(|c| serenity::ChannelId::new(c.0.get())) + .map(|c| serenity::ChannelId::new(c.get())) } // Check if the channel the bot was in was deleted. -pub async fn channel_delete(data: &Data, channel: &serenity::GuildChannel) -> Result<()> { +pub async fn channel_delete( + framework_ctx: FrameworkContext<'_>, + channel: &serenity::GuildChannel, +) -> Result<()> { + let data = framework_ctx.user_data(); + let call_channel_id = guild_call_channel_id(&data.songbird, channel.guild_id).await; if call_channel_id == Some(channel.id) { // Ignore errors from leaving the channel, probably already left. diff --git a/src/events/guild.rs b/src/events/guild.rs index 40e0592..4cb88bf 100644 --- a/src/events/guild.rs +++ b/src/events/guild.rs @@ -5,11 +5,10 @@ use tracing::info; use serenity::builder::*; -use crate::{serenity, Data, Result}; +use crate::{serenity, structs::FrameworkContext, Result}; pub async fn guild_create( - ctx: &serenity::Context, - data: &Data, + framework_ctx: FrameworkContext<'_>, guild: &serenity::Guild, is_new: Option, ) -> Result<()> { @@ -17,11 +16,13 @@ pub async fn guild_create( return Ok(()); }; + let ctx = framework_ctx.serenity_context; let (owner_tag, owner_face) = { let owner = guild.owner_id.to_user(&ctx).await?; (owner.tag(), owner.face()) }; + let data = framework_ctx.user_data(); let dm_channel = guild.owner_id.create_dm_channel(&ctx).await?; match dm_channel.send_message(&ctx, serenity::CreateMessage::default().embed(CreateEmbed::default() .title(format!("Welcome to {}!", ctx.cache.current_user().name)) @@ -71,8 +72,7 @@ Ask questions by either responding here or asking on the support server!", } pub async fn guild_delete( - ctx: &serenity::Context, - data: &Data, + framework_ctx: FrameworkContext<'_>, incomplete: &serenity::UnavailableGuild, full: Option<&serenity::Guild>, ) -> Result<()> { @@ -80,6 +80,7 @@ pub async fn guild_delete( return Ok(()); } + let data = framework_ctx.user_data(); data.guilds_db.delete(incomplete.id.into()).await?; let Some(guild) = full else { return Ok(()) }; @@ -87,6 +88,7 @@ pub async fn guild_delete( return Ok(()); } + let ctx = framework_ctx.serenity_context; let owner_of_other_server = ctx .cache .guilds() diff --git a/src/events/member.rs b/src/events/member.rs index 2e3c6d8..90c6b4a 100644 --- a/src/events/member.rs +++ b/src/events/member.rs @@ -6,6 +6,7 @@ use reqwest::StatusCode; use crate::{ constants::PREMIUM_NEUTRAL_COLOUR, funcs::{confirm_dialog_components, confirm_dialog_wait, remove_premium}, + structs::FrameworkContext, Data, Result, }; @@ -34,12 +35,14 @@ async fn add_ofs_role(data: &Data, http: &serenity::Http, user_id: serenity::Use } pub async fn guild_member_addition( - ctx: &serenity::Context, - data: &Data, + framework_ctx: FrameworkContext<'_>, member: &serenity::Member, ) -> Result<()> { + let data = framework_ctx.user_data(); + let ctx = framework_ctx.serenity_context; + if member.guild_id == data.config.main_server && is_guild_owner(&ctx.cache, member.user.id) { - add_ofs_role(data, &ctx.http, member.user.id).await?; + add_ofs_role(&data, &ctx.http, member.user.id).await?; } Ok(()) @@ -65,11 +68,12 @@ Do you want to remove that server from your assigned slots?", } pub async fn guild_member_removal( - ctx: &serenity::Context, - data: &Data, + framework_ctx: FrameworkContext<'_>, guild_id: serenity::GuildId, user: &serenity::User, ) -> Result<()> { + let data = framework_ctx.user_data(); + let guild_row = data.guilds_db.get(guild_id.into()).await?; let Some(premium_user) = guild_row.premium_user else { return Ok(()); @@ -83,11 +87,12 @@ pub async fn guild_member_removal( return Ok(()); } + let ctx = framework_ctx.serenity_context; let msg = match user.dm(ctx, create_premium_notice()).await { Ok(msg) => msg, Err(err) => { // We cannot DM this premium user, just remove premium by default. - remove_premium(data, guild_id).await?; + remove_premium(&data, guild_id).await?; if let serenity::Error::Http(serenity::HttpError::UnsuccessfulRequest(err)) = &err && err.status_code == StatusCode::FORBIDDEN { @@ -106,11 +111,11 @@ pub async fn guild_member_removal( let response = match confirm_dialog_wait(ctx, &msg, premium_user).await? { Some(true) => format!("Okay, kept your premium assigned to {guild_name} ({guild_id})."), Some(false) => { - remove_premium(data, guild_id).await?; + remove_premium(&data, guild_id).await?; format!("Okay, removed your premium assignment from {guild_name} ({guild_id}).") } None => { - remove_premium(data, guild_id).await?; + remove_premium(&data, guild_id).await?; format!("You did not respond to whether or not to remove premium assignment from {guild_name} ({guild_id}), so it has been unassigned.") } }; diff --git a/src/events/message.rs b/src/events/message.rs index b323665..a94afe0 100644 --- a/src/events/message.rs +++ b/src/events/message.rs @@ -17,24 +17,23 @@ use crate::{ pub async fn message( framework_ctx: FrameworkContext<'_>, - ctx: &serenity::Context, new_message: &serenity::Message, ) -> Result<()> { tokio::try_join!( - process_tts_msg(ctx, new_message, &framework_ctx), - process_support_dm(ctx, new_message, framework_ctx.user_data), - process_mention_msg(ctx, new_message, framework_ctx.user_data), + process_tts_msg(framework_ctx, new_message), + process_support_dm(framework_ctx, new_message), + process_mention_msg(framework_ctx, new_message), )?; Ok(()) } async fn process_tts_msg( - ctx: &serenity::Context, + framework_ctx: FrameworkContext<'_>, message: &serenity::Message, - framework_ctx: &FrameworkContext<'_>, ) -> Result<()> { - let data = framework_ctx.user_data; + let data = framework_ctx.user_data(); + let ctx = framework_ctx.serenity_context; let guild_id = require!(message.guild_id, Ok(())); let guild_row = data.guilds_db.get(guild_id.into()).await?; @@ -43,7 +42,7 @@ async fn process_tts_msg( let (voice, mode) = { if let Some(channel_id) = to_autojoin { - let join_vc_lock = JoinVCToken::acquire(data, guild_id); + let join_vc_lock = JoinVCToken::acquire(&data, guild_id); match data .songbird .join_vc(join_vc_lock.lock().await, channel_id) @@ -136,7 +135,7 @@ async fn process_tts_msg( .try_unwrap()? }; - let join_vc_lock = JoinVCToken::acquire(data, guild_id); + let join_vc_lock = JoinVCToken::acquire(&data, guild_id); match data .songbird .join_vc(join_vc_lock.lock().await, voice_channel_id) @@ -208,14 +207,12 @@ async fn process_tts_msg( let shard_manager = framework_ctx.shard_manager.clone(); let author_name = message.author.name.clone(); let icon_url = message.author.face(); - let data = data.clone(); errors::handle_track( ctx.clone(), shard_manager, - data, extra_fields, - author_name.into_string(), + author_name, icon_url, &track_handle, ) @@ -223,10 +220,10 @@ async fn process_tts_msg( } async fn process_mention_msg( - ctx: &serenity::Context, + framework_ctx: FrameworkContext<'_>, message: &serenity::Message, - data: &Data, ) -> Result<()> { + let data = framework_ctx.user_data(); let Some(bot_mention_regex) = data.regex_cache.bot_mention.get() else { return Ok(()); }; @@ -235,6 +232,7 @@ async fn process_mention_msg( return Ok(()); }; + let ctx = framework_ctx.serenity_context; let bot_user = ctx.cache.current_user().id; let guild_id = require!(message.guild_id, Ok(())); let channel = message.channel(ctx).await?.guild().unwrap(); @@ -271,13 +269,15 @@ async fn process_mention_msg( } async fn process_support_dm( - ctx: &serenity::Context, + framework_ctx: FrameworkContext<'_>, message: &serenity::Message, - data: &Data, ) -> Result<()> { + let data = framework_ctx.user_data(); + let ctx = framework_ctx.serenity_context; + let channel = match message.channel(ctx).await? { serenity::Channel::Guild(channel) => { - return process_support_response(ctx, message, data, channel).await + return process_support_response(ctx, message, &data, channel).await } serenity::Channel::Private(channel) => channel, _ => return Ok(()), diff --git a/src/events/mod.rs b/src/events/mod.rs index 7b9600e..45ab995 100644 --- a/src/events/mod.rs +++ b/src/events/mod.rs @@ -21,35 +21,29 @@ use serenity::FullEvent as Event; use crate::structs::{FrameworkContext, Result}; -pub async fn listen( - ctx: &serenity::Context, - event: &Event, - framework_ctx: FrameworkContext<'_>, -) -> Result<()> { - let data = framework_ctx.user_data; - +pub async fn listen(framework_ctx: FrameworkContext<'_>, event: &Event) -> Result<()> { match event { - Event::Message { new_message } => message(framework_ctx, ctx, new_message).await, - Event::GuildCreate { guild, is_new } => guild_create(ctx, data, guild, *is_new).await, - Event::Ready { data_about_bot } => ready(framework_ctx, ctx, data_about_bot).await, + Event::Message { new_message } => message(framework_ctx, new_message).await, + Event::GuildCreate { guild, is_new } => guild_create(framework_ctx, guild, *is_new).await, + Event::Ready { data_about_bot } => ready(framework_ctx, data_about_bot).await, Event::GuildDelete { incomplete, full } => { - guild_delete(ctx, data, incomplete, full.as_ref()).await + guild_delete(framework_ctx, incomplete, full.as_ref()).await } Event::GuildMemberAddition { new_member } => { - guild_member_addition(ctx, data, new_member).await + guild_member_addition(framework_ctx, new_member).await } Event::GuildMemberRemoval { guild_id, user, .. } => { - guild_member_removal(ctx, data, *guild_id, user).await + guild_member_removal(framework_ctx, *guild_id, user).await } Event::VoiceStateUpdate { old, new } => { - voice_state_update(ctx, data, old.as_ref(), new).await + voice_state_update(framework_ctx, old.as_ref(), new).await } - Event::ChannelDelete { channel, .. } => channel_delete(data, channel).await, + Event::ChannelDelete { channel, .. } => channel_delete(framework_ctx, channel).await, Event::InteractionCreate { interaction } => { - interaction_create(framework_ctx, ctx, interaction).await + interaction_create(framework_ctx, interaction).await } Event::Resume { .. } => { - resume(data); + resume(&framework_ctx.user_data()); Ok(()) } _ => Ok(()), diff --git a/src/events/other.rs b/src/events/other.rs index 19ffebe..cf9a0b2 100644 --- a/src/events/other.rs +++ b/src/events/other.rs @@ -13,8 +13,7 @@ pub fn resume(data: &Data) { pub async fn interaction_create( framework_ctx: FrameworkContext<'_>, - ctx: &serenity::Context, interaction: &serenity::Interaction, ) -> Result<()> { - errors::interaction_create(ctx, interaction, framework_ctx).await + errors::interaction_create(framework_ctx, interaction).await } diff --git a/src/events/ready.rs b/src/events/ready.rs index 219d247..998ab9e 100644 --- a/src/events/ready.rs +++ b/src/events/ready.rs @@ -41,10 +41,10 @@ fn generate_status(shards: &HashMap, - ctx: &serenity::Context, data_about_bot: &serenity::Ready, ) -> Result<()> { - let data = framework_ctx.user_data; + let data = framework_ctx.user_data(); + let ctx = framework_ctx.serenity_context; let shard_count = ctx.cache.shard_count(); let user_name = &data_about_bot.user.name; diff --git a/src/events/voice_state.rs b/src/events/voice_state.rs index bb2a6d6..5194567 100644 --- a/src/events/voice_state.rs +++ b/src/events/voice_state.rs @@ -2,19 +2,20 @@ use poise::serenity_prelude as serenity; use crate::{ opt_ext::OptionTryUnwrap, - structs::{Data, Result}, + structs::{FrameworkContext, Result}, }; /// If (on leave) the bot should also leave as it is alone pub async fn voice_state_update( - ctx: &serenity::Context, - data: &Data, + framework_ctx: FrameworkContext<'_>, old: Option<&serenity::VoiceState>, new: &serenity::VoiceState, ) -> Result<()> { // User left vc let Some(old) = old else { return Ok(()) }; + let data = framework_ctx.user_data(); + // Bot is in vc on server let guild_id = new.guild_id.try_unwrap()?; if data.songbird.get(guild_id).is_none() { @@ -22,6 +23,7 @@ pub async fn voice_state_update( } // Bot is not the one leaving + let ctx = framework_ctx.serenity_context; let bot_id = ctx.cache.current_user().id; if new.member.as_ref().map_or(true, |m| m.user.id == bot_id) { return Ok(()); diff --git a/src/main.rs b/src/main.rs index 08ee09e..bcaffae 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,7 +74,7 @@ use funcs::{decode_resp, get_translation_langs, prepare_gcloud_voices}; use looper::Looper; use opt_ext::OptionTryUnwrap; use structs::{ - Config, Context, Data, DataInner, FailurePoint, PollyVoice, PostgresConfig, Result, TTSMode, + Config, Context, Data, FailurePoint, PollyVoice, PostgresConfig, Result, TTSMode, WebhookConfig, WebhookConfigRaw, }; use traits::PoiseContextExt; @@ -294,7 +294,7 @@ async fn _main(start_time: std::time::SystemTime) -> Result<()> { bot_mention: OnceLock::new(), }; - let data = Data(Arc::new(DataInner { + let data = Arc::new(Data { pool, translations, bot_list_tokens: config.bot_list_tokens, @@ -328,7 +328,7 @@ async fn _main(start_time: std::time::SystemTime) -> Result<()> { nickname_db, user_voice_db, guild_voice_db, - })); + }); let intents = serenity::GatewayIntents::GUILDS | serenity::GatewayIntents::GUILD_MESSAGES @@ -339,7 +339,7 @@ async fn _main(start_time: std::time::SystemTime) -> Result<()> { let framework_options = poise::FrameworkOptions { commands: commands::commands(), - event_handler: |ctx, event, fw_ctx, _| Box::pin(events::listen(ctx, event, fw_ctx)), + event_handler: |fw_ctx, event| Box::pin(events::listen(fw_ctx, event)), on_error: |error| { Box::pin(async move { let res = errors::handle(error).await; @@ -374,7 +374,8 @@ async fn _main(start_time: std::time::SystemTime) -> Result<()> { Box::pin(async move { Ok(Some(match ctx.guild_id { Some(guild_id) => { - let row = ctx.data.guilds_db.get(guild_id.into()).await?; + let data = ctx.framework.user_data(); + let row = data.guilds_db.get(guild_id.into()).await?; String::from(row.prefix.as_str()) } None => String::from("-"), @@ -428,16 +429,16 @@ async fn _main(start_time: std::time::SystemTime) -> Result<()> { }; let mut client = serenity::Client::builder(&token, intents) + .data(data as _) .voice_manager::(songbird) - .framework(poise::Framework::new(framework_options, |_, ready, _| { - Box::pin(async { - data.regex_cache - .bot_mention - .set(regex::Regex::new(&format!("<@!{}>", ready.user.id))?) - .unwrap(); - - Ok(data) - }) + .framework(poise::Framework::new(framework_options, |ctx, ready, _| { + let data = ctx.data::(); + data.regex_cache + .bot_mention + .set(regex::Regex::new(&format!("<@!{}>", ready.user.id)).unwrap()) + .unwrap(); + + Box::pin(std::future::ready(Ok(()))) })) .await?; diff --git a/src/structs.rs b/src/structs.rs index 4237148..a3e9750 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -113,18 +113,7 @@ pub struct RegexCache { pub emoji: regex::Regex, } -#[derive(Clone)] -pub struct Data(pub Arc); - -impl std::ops::Deref for Data { - type Target = DataInner; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -pub struct DataInner { +pub struct Data { pub analytics: Arc, pub guilds_db: database::Handler, pub userinfo_db: database::Handler, diff --git a/src/traits.rs b/src/traits.rs index cb4fa95..8af742f 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -56,7 +56,7 @@ impl<'ctx> PoiseContextExt<'ctx> for Context<'ctx> { fn current_catalog(&self) -> Option<&gettext::Catalog> { if let poise::Context::Application(ctx) = self { - ctx.data + ctx.data() .translations .get(match ctx.interaction.locale.as_str() { "ko" => "ko-KR",