diff --git a/examples/e05_command_framework/src/main.rs b/examples/e05_command_framework/src/main.rs index 349a2a9ae99..0880ebfe3f3 100644 --- a/examples/e05_command_framework/src/main.rs +++ b/examples/e05_command_framework/src/main.rs @@ -29,7 +29,7 @@ use serenity::framework::standard::{ }; use serenity::gateway::ShardManager; use serenity::http::Http; -use serenity::model::channel::{Channel, Message}; +use serenity::model::channel::Message; use serenity::model::gateway::{GatewayIntents, Ready}; use serenity::model::id::UserId; use serenity::model::permissions::Permissions; @@ -557,7 +557,7 @@ async fn slow_mode(ctx: &Context, msg: &Message, mut args: Args) -> CommandResul } else { format!("Successfully set slow mode rate to `{slow_mode_rate_seconds}` seconds.") } - } else if let Some(Channel::Guild(channel)) = msg.channel_id.to_channel_cached(&ctx.cache) { + } else if let Some(channel) = msg.channel_id.to_channel_cached(&ctx.cache) { let slow_mode_rate = channel.rate_limit_per_user.unwrap_or(0); format!("Current slow mode rate is `{slow_mode_rate}` seconds.") } else { diff --git a/src/builder/create_invite.rs b/src/builder/create_invite.rs index f1cbf644c7a..6df03f68a6a 100644 --- a/src/builder/create_invite.rs +++ b/src/builder/create_invite.rs @@ -28,7 +28,7 @@ use crate::model::prelude::*; /// impl EventHandler for Handler { /// async fn message(&self, context: Context, msg: Message) { /// if msg.content == "!createinvite" { -/// let channel_opt = context.cache.guild_channel(msg.channel_id).as_deref().cloned(); +/// let channel_opt = context.cache.channel(msg.channel_id).as_deref().cloned(); /// let channel = match channel_opt { /// Some(channel) => channel, /// None => { @@ -118,7 +118,7 @@ impl<'a> CreateInvite<'a> { /// # #[cfg(all(feature = "cache", feature = "client", feature = "framework", feature = "http"))] /// # #[command] /// # async fn example(context: &Context) -> CommandResult { - /// # let channel = context.cache.guild_channel(81384788765712384).unwrap().clone(); + /// # let channel = context.cache.channel(81384788765712384).unwrap().clone(); /// let builder = CreateInvite::new().max_age(3600); /// let invite = channel.create_invite(context, builder).await?; /// # Ok(()) @@ -150,7 +150,7 @@ impl<'a> CreateInvite<'a> { /// # #[cfg(all(feature = "cache", feature = "client", feature = "framework", feature = "http"))] /// # #[command] /// # async fn example(context: &Context) -> CommandResult { - /// # let channel = context.cache.guild_channel(81384788765712384).unwrap().clone(); + /// # let channel = context.cache.channel(81384788765712384).unwrap().clone(); /// let builder = CreateInvite::new().max_uses(5); /// let invite = channel.create_invite(context, builder).await?; /// # Ok(()) @@ -180,7 +180,7 @@ impl<'a> CreateInvite<'a> { /// # #[cfg(all(feature = "cache", feature = "client", feature = "framework", feature = "http"))] /// # #[command] /// # async fn example(context: &Context) -> CommandResult { - /// # let channel = context.cache.guild_channel(81384788765712384).unwrap().clone(); + /// # let channel = context.cache.channel(81384788765712384).unwrap().clone(); /// let builder = CreateInvite::new().temporary(true); /// let invite = channel.create_invite(context, builder).await?; /// # Ok(()) @@ -210,7 +210,7 @@ impl<'a> CreateInvite<'a> { /// # #[cfg(all(feature = "cache", feature = "client", feature = "framework", feature = "http"))] /// # #[command] /// # async fn example(context: &Context) -> CommandResult { - /// # let channel = context.cache.guild_channel(81384788765712384).unwrap().clone(); + /// # let channel = context.cache.channel(81384788765712384).unwrap().clone(); /// let builder = CreateInvite::new().unique(true); /// let invite = channel.create_invite(context, builder).await?; /// # Ok(()) @@ -265,10 +265,7 @@ impl<'a> CreateInvite<'a> { #[cfg(feature = "http")] #[async_trait::async_trait] impl<'a> Builder for CreateInvite<'a> { - #[cfg(feature = "cache")] - type Context<'ctx> = (ChannelId, Option); - #[cfg(not(feature = "cache"))] - type Context<'ctx> = (ChannelId,); + type Context<'ctx> = ChannelId; type Built = RichInvite; /// Creates an invite for the given channel. @@ -289,15 +286,10 @@ impl<'a> Builder for CreateInvite<'a> { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - crate::utils::user_has_perms_cache( - cache, - ctx.0, - ctx.1, - Permissions::CREATE_INSTANT_INVITE, - )?; + crate::utils::user_has_perms_cache(cache, ctx, Permissions::CREATE_INSTANT_INVITE)?; } } - cache_http.http().create_invite(ctx.0, &self, self.audit_log_reason).await + cache_http.http().create_invite(ctx, &self, self.audit_log_reason).await } } diff --git a/src/builder/create_message.rs b/src/builder/create_message.rs index f638446203d..85dc539bd02 100644 --- a/src/builder/create_message.rs +++ b/src/builder/create_message.rs @@ -321,7 +321,7 @@ impl Builder for CreateMessage { req |= Permissions::ATTACH_FILES; } if let Some(cache) = cache_http.cache() { - crate::utils::user_has_perms_cache(cache, channel_id, guild_id, req)?; + crate::utils::user_has_perms_cache(cache, channel_id, req)?; } } @@ -344,7 +344,7 @@ impl Builder for CreateMessage { // Use either the passed in guild ID (e.g. if we were called from GuildChannel directly // we already know our guild ID), and otherwise find the guild ID in cache message.guild_id = guild_id - .or_else(|| Some(cache_http.cache()?.guild_channel(message.channel_id)?.guild_id)); + .or_else(|| Some(cache_http.cache()?.channel(message.channel_id)?.guild_id)); } Ok(message) diff --git a/src/builder/create_stage_instance.rs b/src/builder/create_stage_instance.rs index 5a0b7fe5e32..2d971c2cfc0 100644 --- a/src/builder/create_stage_instance.rs +++ b/src/builder/create_stage_instance.rs @@ -75,7 +75,7 @@ impl<'a> Builder for CreateStageInstance<'a> { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - if let Some(channel) = cache.guild_channel(ctx) { + if let Some(channel) = cache.channel(ctx) { if channel.kind != ChannelType::Stage { return Err(Error::Model(ModelError::InvalidChannelType)); } diff --git a/src/builder/create_webhook.rs b/src/builder/create_webhook.rs index fb9ce6b9150..9ddee819dc0 100644 --- a/src/builder/create_webhook.rs +++ b/src/builder/create_webhook.rs @@ -80,7 +80,7 @@ impl<'a> Builder for CreateWebhook<'a> { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - if let Some(channel) = cache.guild_channel(ctx) { + if let Some(channel) = cache.channel(ctx) { // forum channels are not text-based, but webhooks can be created in them // and used to send messages in their posts if !channel.is_text_based() && channel.kind != ChannelType::Forum { diff --git a/src/builder/edit_channel.rs b/src/builder/edit_channel.rs index defd40aa1f1..d5b6572838c 100644 --- a/src/builder/edit_channel.rs +++ b/src/builder/edit_channel.rs @@ -294,10 +294,7 @@ impl<'a> EditChannel<'a> { #[cfg(feature = "http")] #[async_trait::async_trait] impl<'a> Builder for EditChannel<'a> { - #[cfg(feature = "cache")] - type Context<'ctx> = (ChannelId, Option); - #[cfg(not(feature = "cache"))] - type Context<'ctx> = (ChannelId,); + type Context<'ctx> = ChannelId; type Built = GuildChannel; /// Edits the channel's settings. @@ -320,23 +317,13 @@ impl<'a> Builder for EditChannel<'a> { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - crate::utils::user_has_perms_cache( - cache, - ctx.0, - ctx.1, - Permissions::MANAGE_CHANNELS, - )?; + crate::utils::user_has_perms_cache(cache, ctx, Permissions::MANAGE_CHANNELS)?; if self.permission_overwrites.is_some() { - crate::utils::user_has_perms_cache( - cache, - ctx.0, - ctx.1, - Permissions::MANAGE_ROLES, - )?; + crate::utils::user_has_perms_cache(cache, ctx, Permissions::MANAGE_ROLES)?; } } } - cache_http.http().edit_channel(ctx.0, &self, self.audit_log_reason).await + cache_http.http().edit_channel(ctx, &self, self.audit_log_reason).await } } diff --git a/src/builder/edit_stage_instance.rs b/src/builder/edit_stage_instance.rs index d23d366fe7e..250a8f4bbf8 100644 --- a/src/builder/edit_stage_instance.rs +++ b/src/builder/edit_stage_instance.rs @@ -68,7 +68,7 @@ impl<'a> Builder for EditStageInstance<'a> { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - if let Some(channel) = cache.guild_channel(ctx) { + if let Some(channel) = cache.channel(ctx) { if channel.kind != ChannelType::Stage { return Err(Error::Model(ModelError::InvalidChannelType)); } diff --git a/src/builder/edit_voice_state.rs b/src/builder/edit_voice_state.rs index 2f40f9bcde1..8c3b4bea150 100644 --- a/src/builder/edit_voice_state.rs +++ b/src/builder/edit_voice_state.rs @@ -93,7 +93,7 @@ impl Builder for EditVoiceState { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - if let Some(channel) = cache.guild_channel(channel_id) { + if let Some(channel) = cache.channel(channel_id) { if channel.kind != ChannelType::Stage { return Err(Error::from(ModelError::InvalidChannelType)); } diff --git a/src/cache/event.rs b/src/cache/event.rs index 888de5492f8..8fd754d305f 100644 --- a/src/cache/event.rs +++ b/src/cache/event.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use super::{Cache, CacheUpdate}; -use crate::model::channel::{Channel, GuildChannel, Message}; +use crate::model::channel::{GuildChannel, Message}; use crate::model::event::{ ChannelCreateEvent, ChannelDeleteEvent, @@ -38,43 +38,16 @@ use crate::model::user::{CurrentUser, OnlineStatus}; use crate::model::voice::VoiceState; impl CacheUpdate for ChannelCreateEvent { - type Output = Channel; + type Output = GuildChannel; fn update(&mut self, cache: &Cache) -> Option { - match self.channel { - Channel::Guild(ref channel) => { - let (guild_id, channel_id) = (channel.guild_id, channel.id); - - let old_channel = cache - .guilds - .get_mut(&guild_id) - .and_then(|mut g| g.channels.insert(channel_id, channel.clone())); - - cache.channels.insert(channel_id, channel.guild_id); - old_channel.map(Channel::Guild) - }, - Channel::Private(ref mut channel) => { - if let Some(channel) = cache.private_channels.get(&channel.id) { - return Some(Channel::Private(channel.clone())); - } - - let id = { - let user_id = { - cache.update_user_entry(&channel.recipient); - - channel.recipient.id - }; - - if let Some(u) = cache.users.get(&user_id) { - channel.recipient = u.clone(); - } - - channel.id - }; + let old_channel = cache + .guilds + .get_mut(&self.channel.guild_id) + .and_then(|mut g| g.channels.insert(self.channel.id, self.channel.clone())); - cache.private_channels.insert(id, channel.clone()).map(Channel::Private) - }, - } + cache.channels.insert(self.channel.id, self.channel.guild_id); + old_channel } } @@ -82,52 +55,26 @@ impl CacheUpdate for ChannelDeleteEvent { type Output = Vec; fn update(&mut self, cache: &Cache) -> Option> { - match &self.channel { - Channel::Guild(channel) => { - let (guild_id, channel_id) = (channel.guild_id, channel.id); + let (channel_id, guild_id) = (self.channel.id, self.channel.guild_id); - cache.channels.remove(&channel_id); - - cache.guilds.get_mut(&guild_id).map(|mut g| g.channels.remove(&channel_id)); - }, - Channel::Private(channel) => { - let id = { channel.id }; - - cache.private_channels.remove(&id); - }, - }; + cache.channels.remove(&channel_id); + cache.guilds.get_mut(&guild_id).map(|mut g| g.channels.remove(&channel_id)); // Remove the cached messages for the channel. - cache - .messages - .remove(&self.channel.id()) - .map(|(_, messages)| messages.into_values().collect()) + cache.messages.remove(&channel_id).map(|(_, messages)| messages.into_values().collect()) } } impl CacheUpdate for ChannelUpdateEvent { - type Output = Channel; - - fn update(&mut self, cache: &Cache) -> Option { - let old_channel = cache.channel(self.channel.id()); + type Output = GuildChannel; - match &self.channel { - Channel::Guild(channel) => { - cache.channels.insert(channel.id, channel.guild_id); + fn update(&mut self, cache: &Cache) -> Option { + cache.channels.insert(self.channel.id, self.channel.guild_id); - cache - .guilds - .get_mut(&channel.guild_id) - .map(|mut g| g.channels.insert(channel.id, channel.clone())); - }, - Channel::Private(channel) => { - if let Some(mut c) = cache.private_channels.get_mut(&channel.id) { - c.clone_from(channel); - } - }, - } - - old_channel + cache + .guilds + .get_mut(&self.channel.guild_id) + .and_then(|mut g| g.channels.insert(self.channel.id, self.channel.clone())) } } @@ -135,16 +82,8 @@ impl CacheUpdate for ChannelPinsUpdateEvent { type Output = (); fn update(&mut self, cache: &Cache) -> Option<()> { - if let Some(mut channel) = cache.guild_channel_mut(self.channel_id) { - channel.last_pin_timestamp = self.last_pin_timestamp; - - return None; - } - - if let Some(mut channel) = cache.private_channels.get_mut(&self.channel_id) { + if let Some(mut channel) = cache.channel_mut(self.channel_id) { channel.last_pin_timestamp = self.last_pin_timestamp; - - return None; } None @@ -626,7 +565,7 @@ impl CacheUpdate for VoiceChannelStatusUpdateEvent { type Output = String; fn update(&mut self, cache: &Cache) -> Option { - if let Some(mut channel) = cache.guild_channel_mut(self.id) { + if let Some(mut channel) = cache.channel_mut(self.id) { let old = channel.status.clone(); channel.status = self.status.clone(); // Discord updates topic but doesn't fire ChannelUpdate. diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 03d1ea88228..f2f44530b39 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -112,7 +112,6 @@ impl std::ops::Deref for CacheRef<'_, K, V, T> { pub type UserRef<'a> = CacheRef<'a, UserId, User>; pub type GuildRef<'a> = CacheRef<'a, GuildId, Guild>; pub type CurrentUserRef<'a> = CacheRef<'a, (), CurrentUser>; -pub type PrivateChannelRef<'a> = CacheRef<'a, ChannelId, PrivateChannel>; pub type GuildChannelRef<'a> = CacheRef<'a, GuildId, GuildChannel, Guild>; pub type ChannelMessagesRef<'a> = CacheRef<'a, ChannelId, HashMap>; @@ -130,7 +129,6 @@ pub(crate) struct CachedShardData { /// /// This is the list of cached resources and the events that populate them: /// - channels: [`ChannelCreateEvent`], [`ChannelUpdateEvent`], [`GuildCreateEvent`] -/// - private_channels: [`ChannelCreateEvent`] /// - guilds: [`GuildCreateEvent`] /// - unavailable_guilds: [`ReadyEvent`], [`GuildDeleteEvent`] /// - users: [`GuildMemberAddEvent`], [`GuildMemberRemoveEvent`], [`GuildMembersChunkEvent`], @@ -151,7 +149,7 @@ pub struct Cache { /// /// The TTL for each value is configured in CacheSettings. #[cfg(feature = "temp_cache")] - pub(crate) temp_channels: MokaCache, + pub(crate) temp_channels: MokaCache, BuildHasher>, /// Cache of users who have been fetched from `to_user`. /// /// The TTL for each value is configured in CacheSettings. @@ -161,8 +159,6 @@ pub struct Cache { // Channels cache: /// A map of channel ids to the guilds in which the channel data is stored. pub(crate) channels: MaybeMap, - /// A map of direct message channels that the current user has open with other users. - pub(crate) private_channels: MaybeMap, // Guilds cache: // --- @@ -258,7 +254,6 @@ impl Cache { temp_users: temp_cache(settings.time_to_live), channels: MaybeMap(settings.cache_channels.then(DashMap::default)), - private_channels: MaybeMap(settings.cache_channels.then(DashMap::default)), guilds: MaybeMap(settings.cache_guilds.then(DashMap::default)), unavailable_guilds: MaybeMap(settings.cache_guilds.then(DashMap::default)), @@ -331,26 +326,6 @@ impl Cache { total } - /// Fetches a vector of all [`PrivateChannel`] Ids that are stored in the cache. - /// - /// # Examples - /// - /// If there are 6 private channels and 2 groups in the cache, then `8` Ids will be returned. - /// - /// Printing the count of all private channels and groups: - /// - /// ```rust,no_run - /// # use serenity::cache::Cache; - /// # - /// # let cache = Cache::default(); - /// let amount = cache.private_channels().len(); - /// - /// println!("There are {} private channels", amount); - /// ``` - pub fn private_channels(&self) -> ReadOnlyMapRef<'_, ChannelId, PrivateChannel> { - self.private_channels.as_read_only() - } - /// Fetches a vector of all [`Guild`]s' Ids that are stored in the cache. /// /// Note that if you are utilizing multiple [`Shard`]s, then the guilds retrieved over all @@ -387,39 +362,39 @@ impl Cache { self.guilds.iter().map(|i| *i.key()).chain(unavailable_guild_ids).collect() } - /// Retrieves a [`Channel`] from the cache based on the given Id. - /// - /// This will search the `channels` map, then the [`Self::private_channels`] map. - /// - /// If you know what type of channel you're looking for, you should instead manually retrieve - /// from one of the respective methods: - /// - /// - [`GuildChannel`]: [`Self::guild_channel`] or [`Self::guild_channels`] - /// - [`PrivateChannel`]: [`Self::private_channel`] or [`Self::private_channels`] + /// Retrieves a [`GuildChannel`] from the cache based on the given Id. #[inline] - pub fn channel>(&self, id: C) -> Option { + pub fn channel>(&self, id: C) -> Option> { self._channel(id.into()) } - fn _channel(&self, id: ChannelId) -> Option { - if let Some(channel) = self.guild_channel(id) { - return Some(Channel::Guild(channel.clone())); + fn _channel(&self, id: ChannelId) -> Option> { + let guild_id = *self.channels.get(&id)?; + let guild_ref = self.guilds.get(&guild_id)?; + let channel = guild_ref.try_map(|g| g.channels.get(&id)).ok(); + if let Some(channel) = channel { + return Some(CacheRef::from_mapped_ref(channel)); } #[cfg(feature = "temp_cache")] { if let Some(channel) = self.temp_channels.get(&id) { - return Some(Channel::Guild(channel)); + return Some(CacheRef::from_arc(channel)); } } - if let Some(private_channel) = self.private_channels.get(&id) { - return Some(Channel::Private(private_channel.clone())); - } - None } + pub(super) fn channel_mut( + &self, + id: ChannelId, + ) -> Option> { + let guild_id = *self.channels.get(&id)?; + let guild_ref = self.guilds.get_mut(&guild_id)?; + guild_ref.try_map(|g| g.channels.get_mut(&id)).ok() + } + /// Get a reference to the cached messages for a channel based on the given `Id`. /// /// # Examples @@ -469,75 +444,6 @@ impl Cache { self.guilds.len() } - /// Retrieves a reference to a [`Guild`]'s channel. Unlike [`Self::channel`], this will only - /// search guilds for the given channel. - /// - /// The only advantage of this method is that you can pass in anything that is indirectly a - /// [`ChannelId`]. - /// - /// # Examples - /// - /// Getting a guild's channel via the Id of the message received through a - /// [`EventHandler::message`] event dispatch: - /// - /// ```rust,no_run - /// # use serenity::model::prelude::*; - /// # use serenity::prelude::*; - /// # - /// struct Handler; - /// - /// #[serenity::async_trait] - /// impl EventHandler for Handler { - /// async fn message(&self, context: Context, message: Message) { - /// let channel_opt = context.cache.guild_channel(message.channel_id).as_deref().cloned(); - /// let channel = match channel_opt { - /// Some(channel) => channel, - /// None => { - /// let result = message - /// .channel_id - /// .say(&context, "Could not find guild's channel data") - /// .await; - /// if let Err(why) = result { - /// println!("Error sending message: {:?}", why); - /// } - /// - /// return; - /// }, - /// }; - /// } - /// } - /// - /// # #[cfg(feature = "client")] - /// # async fn run() -> Result<(), Box> { - /// let mut client = - /// Client::builder("token", GatewayIntents::default()).event_handler(Handler).await?; - /// - /// client.start().await?; - /// # Ok(()) - /// # } - /// ``` - /// - /// [`EventHandler::message`]: crate::client::EventHandler::message - #[inline] - pub fn guild_channel>(&self, id: C) -> Option> { - self._guild_channel(id.into()) - } - - fn _guild_channel(&self, id: ChannelId) -> Option> { - let guild_id = *self.channels.get(&id)?; - let guild_ref = self.guilds.get(&guild_id)?; - guild_ref.try_map(|g| g.channels.get(&id)).ok().map(CacheRef::from_mapped_ref) - } - - pub(super) fn guild_channel_mut( - &self, - id: ChannelId, - ) -> Option> { - let guild_id = *self.channels.get(&id)?; - let guild_ref = self.guilds.get_mut(&guild_id)?; - guild_ref.try_map(|g| g.channels.get_mut(&id)).ok() - } - /// Retrieves a [`Guild`]'s member from the cache based on the guild's and user's given Ids. /// /// **Note**: This will clone the entire member. Instead, retrieve the guild and retrieve from @@ -556,7 +462,7 @@ impl Cache { /// # async fn run(http: Http, cache: Cache, message: Message) { /// # /// let member = { - /// let channel = match cache.guild_channel(message.channel_id) { + /// let channel = match cache.channel(message.channel_id) { /// Some(channel) => channel, /// None => { /// if let Err(why) = message.channel_id.say(http, "Error finding channel data").await { @@ -724,38 +630,6 @@ impl Cache { self.messages.get(&channel_id).and_then(|messages| messages.get(&message_id).cloned()) } - /// Retrieves a [`PrivateChannel`] from the cache's [`Self::private_channels`] map, if it - /// exists. - /// - /// The only advantage of this method is that you can pass in anything that is indirectly a - /// [`ChannelId`]. - /// - /// # Examples - /// - /// Retrieve a private channel from the cache and print its recipient's name: - /// - /// ```rust,no_run - /// # use serenity::cache::Cache; - /// # - /// # let cache = Cache::default(); - /// // assuming the cache has been unlocked - /// - /// if let Some(channel) = cache.private_channel(7) { - /// println!("The recipient is {}", channel.recipient); - /// }; - /// ``` - #[inline] - pub fn private_channel( - &self, - channel_id: impl Into, - ) -> Option> { - self._private_channel(channel_id.into()) - } - - fn _private_channel(&self, channel_id: ChannelId) -> Option> { - self.private_channels.get(&channel_id).map(CacheRef::from_ref) - } - /// Retrieves a [`Guild`]'s role by their Ids. /// /// **Note**: This will clone the entire role. Instead, retrieve the guild and retrieve from @@ -875,7 +749,7 @@ impl Cache { /// Returns a channel category matching the given ID pub fn category(&self, channel_id: ChannelId) -> Option> { - let channel = self.guild_channel(channel_id)?; + let channel = self.channel(channel_id)?; if channel.kind == ChannelType::Category { Some(channel) } else { @@ -885,7 +759,7 @@ impl Cache { /// Returns the parent category of the given channel ID. pub fn channel_category_id(&self, channel_id: ChannelId) -> Option { - self.guild_channel(channel_id)?.parent_id + self.channel(channel_id)?.parent_id } /// Clones all channel categories in the given guild and returns them. @@ -995,10 +869,10 @@ mod test { // Add a channel delete event to the cache, the cached messages for that channel should now // be gone. let mut delete = ChannelDeleteEvent { - channel: Channel::Guild(channel.clone()), + channel: channel.clone(), }; assert!(cache.update(&mut delete).is_some()); - assert!(!cache.messages.contains_key(&delete.channel.id())); + assert!(!cache.messages.contains_key(&delete.channel.id)); // Test deletion of a guild channel's message cache when a GuildDeleteEvent is received. let mut guild_create = GuildCreateEvent { diff --git a/src/client/dispatch.rs b/src/client/dispatch.rs index e766977160f..1becccfa870 100644 --- a/src/client/dispatch.rs +++ b/src/client/dispatch.rs @@ -10,7 +10,7 @@ use crate::cache::CacheUpdate; #[cfg(feature = "framework")] use crate::framework::Framework; use crate::internal::tokio::spawn_named; -use crate::model::channel::{Channel, ChannelType}; +use crate::model::channel::ChannelType; use crate::model::event::Event; use crate::model::guild::Member; #[cfg(feature = "cache")] @@ -95,46 +95,35 @@ fn update_cache_with_event(ctx: Context, event: Event) -> Option<(FullEvent, Opt }, Event::ChannelCreate(mut event) => { update_cache(&ctx, &mut event); - match event.channel { - Channel::Guild(channel) => { - if channel.kind == ChannelType::Category { - FullEvent::CategoryCreate { - ctx, - category: channel, - } - } else { - FullEvent::ChannelCreate { - ctx, - channel, - } - } - }, - Channel::Private(_) => unreachable!( - "Private channel create events are no longer sent to bots in the v8 gateway." - ), + + let channel = event.channel; + if channel.kind == ChannelType::Category { + FullEvent::CategoryCreate { + ctx, + category: channel, + } + } else { + FullEvent::ChannelCreate { + ctx, + channel, + } } }, Event::ChannelDelete(mut event) => { let cached_messages = if_cache!(update_cache(&ctx, &mut event)); - match event.channel { - Channel::Private(_) => unreachable!( - "Private channel create events are no longer sent to bots in the v8 gateway." - ), - Channel::Guild(channel) => { - if channel.kind == ChannelType::Category { - FullEvent::CategoryDelete { - ctx, - category: channel, - } - } else { - FullEvent::ChannelDelete { - ctx, - channel, - messages: cached_messages, - } - } - }, + let channel = event.channel; + if channel.kind == ChannelType::Category { + FullEvent::CategoryDelete { + ctx, + category: channel, + } + } else { + FullEvent::ChannelDelete { + ctx, + channel, + messages: cached_messages, + } } }, Event::ChannelPinsUpdate(event) => FullEvent::ChannelPinsUpdate { diff --git a/src/client/event_handler.rs b/src/client/event_handler.rs index 1faf82cd07c..c5b7cd05060 100644 --- a/src/client/event_handler.rs +++ b/src/client/event_handler.rs @@ -138,7 +138,7 @@ event_handler! { /// Dispatched when a channel is updated. /// /// The old channel data is only provided when the cache feature is enabled. - async fn channel_update(&self, ChannelUpdate { ctx: Context, old: Option, new: Channel }); + async fn channel_update(&self, ChannelUpdate { ctx: Context, old: Option, new: GuildChannel }); /// Dispatched when a new audit log entry is created. /// diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs index 16f10dc793e..9e32265d7c1 100644 --- a/src/framework/standard/mod.rs +++ b/src/framework/standard/mod.rs @@ -30,8 +30,6 @@ use super::Framework; #[cfg(feature = "cache")] use crate::cache::Cache; use crate::client::{Context, FullEvent}; -#[cfg(feature = "cache")] -use crate::model::channel::Channel; use crate::model::channel::Message; #[cfg(feature = "cache")] use crate::model::guild::Member; @@ -250,7 +248,7 @@ impl StandardFramework { #[cfg(feature = "cache")] { - if let Some(Channel::Guild(channel)) = msg.channel_id.to_channel_cached(ctx) { + if let Some(channel) = msg.channel_id.to_channel_cached(&ctx.cache) { let guild_id = channel.guild_id; if config.blocked_guilds.contains(&guild_id) { diff --git a/src/model/channel/channel_id.rs b/src/model/channel/channel_id.rs index fd14171bd91..cf56f22b59a 100644 --- a/src/model/channel/channel_id.rs +++ b/src/model/channel/channel_id.rs @@ -21,7 +21,7 @@ use crate::builder::{ GetMessages, }; #[cfg(all(feature = "cache", feature = "model"))] -use crate::cache::Cache; +use crate::cache::{Cache, GuildChannelRef}; #[cfg(feature = "collector")] use crate::collector::{MessageCollector, ReactionCollector}; #[cfg(feature = "collector")] @@ -81,11 +81,7 @@ impl ChannelId { cache_http: impl CacheHttp, builder: CreateInvite<'_>, ) -> Result { - #[cfg(feature = "cache")] - let invite = builder.execute(cache_http, (self, None)).await; - #[cfg(not(feature = "cache"))] - let invite = builder.execute(cache_http, (self,)).await; - invite + builder.execute(cache_http, self).await } /// Creates a [permission overwrite][`PermissionOverwrite`] for either a single [`Member`] or @@ -331,11 +327,7 @@ impl ChannelId { cache_http: impl CacheHttp, builder: EditChannel<'_>, ) -> Result { - #[cfg(feature = "cache")] - let channel = builder.execute(cache_http, (self, None)).await; - #[cfg(not(feature = "cache"))] - let channel = builder.execute(cache_http, (self,)).await; - channel + builder.execute(cache_http, self).await } /// Edits a [`Message`] in the channel given its Id. @@ -380,10 +372,10 @@ impl ChannelId { http.as_ref().follow_news_channel(self, target_channel_id.into()).await } - /// Attempts to find a [`Channel`] by its Id in the cache. + /// Attempts to find a [`GuildChannel`] by its Id in the cache. #[cfg(feature = "cache")] #[inline] - pub fn to_channel_cached(self, cache: impl AsRef) -> Option { + pub fn to_channel_cached(self, cache: &Cache) -> Option> { cache.as_ref().channel(self) } @@ -404,7 +396,7 @@ impl ChannelId { { if let Some(cache) = cache_http.cache() { if let Some(channel) = cache.channel(self) { - return Ok(channel); + return Ok(Channel::Guild(channel.clone())); } } } @@ -415,7 +407,7 @@ impl ChannelId { { if let Some(cache) = cache_http.cache() { if let Channel::Guild(guild_channel) = &channel { - cache.temp_channels.insert(guild_channel.id, guild_channel.clone()); + cache.temp_channels.insert(guild_channel.id, Arc::new(guild_channel.clone())); } } } diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs index 17537d1f379..0f9d907c955 100644 --- a/src/model/channel/guild_channel.rs +++ b/src/model/channel/guild_channel.rs @@ -246,11 +246,7 @@ impl GuildChannel { cache_http: impl CacheHttp, builder: CreateInvite<'_>, ) -> Result { - #[cfg(feature = "cache")] - let invite = builder.execute(cache_http, (self.id, Some(self.guild_id))).await; - #[cfg(not(feature = "cache"))] - let invite = builder.execute(cache_http, (self.id,)).await; - invite + builder.execute(cache_http, self.id).await } /// Creates a [permission overwrite][`PermissionOverwrite`] for either a single [`Member`] or @@ -285,7 +281,7 @@ impl GuildChannel { /// kind: PermissionOverwriteType::Member(user_id), /// }; /// // assuming the cache has been unlocked - /// let channel = cache.guild_channel(channel_id).ok_or(ModelError::ItemMissing)?; + /// let channel = cache.channel(channel_id).ok_or(ModelError::ItemMissing)?; /// /// channel.create_permission(&http, overwrite).await?; /// # Ok(()) @@ -317,7 +313,7 @@ impl GuildChannel { /// kind: PermissionOverwriteType::Role(role_id), /// }; /// - /// let channel = cache.guild_channel(channel_id).ok_or(ModelError::ItemMissing)?; + /// let channel = cache.channel(channel_id).ok_or(ModelError::ItemMissing)?; /// /// channel.create_permission(&http, overwrite).await?; /// # Ok(()) @@ -354,20 +350,16 @@ impl GuildChannel { /// Otherwise returns [`Error::Http`] if the current user lacks permission. /// /// [Manage Channels]: Permissions::MANAGE_CHANNELS - pub async fn delete(&self, cache_http: impl CacheHttp) -> Result { + pub async fn delete(&self, cache_http: impl CacheHttp) -> Result { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - crate::utils::user_has_perms_cache( - cache, - self.id, - Some(self.guild_id), - Permissions::MANAGE_CHANNELS, - )?; + crate::utils::user_has_perms_cache(cache, self.id, Permissions::MANAGE_CHANNELS)?; } } - self.id.delete(cache_http.http()).await + let channel = self.id.delete(cache_http.http()).await?; + channel.guild().ok_or(Error::Model(ModelError::InvalidChannelType)) } /// Deletes all messages by Ids from the given vector in the channel. @@ -486,10 +478,7 @@ impl GuildChannel { cache_http: impl CacheHttp, builder: EditChannel<'_>, ) -> Result<()> { - #[cfg(feature = "cache")] - let channel = builder.execute(cache_http, (self.id, Some(self.guild_id))).await?; - #[cfg(not(feature = "cache"))] - let channel = builder.execute(cache_http, (self.id,)).await?; + let channel = builder.execute(cache_http, self.id).await?; *self = channel; Ok(()) } @@ -555,7 +544,7 @@ impl GuildChannel { /// use serenity::model::ModelError; /// /// // assuming the cache has been unlocked - /// let channel = cache.guild_channel(channel_id).ok_or(ModelError::ItemMissing)?; + /// let channel = cache.channel(channel_id).ok_or(ModelError::ItemMissing)?; /// /// let builder = EditVoiceState::new().suppress(false); /// channel.edit_voice_state(&http, user_id, builder).await?; @@ -603,7 +592,7 @@ impl GuildChannel { /// use serenity::model::ModelError; /// /// // assuming the cache has been unlocked - /// let channel = cache.guild_channel(channel_id).ok_or(ModelError::ItemMissing)?; + /// let channel = cache.channel(channel_id).ok_or(ModelError::ItemMissing)?; /// /// // Send a request to speak /// let builder = EditVoiceState::new().request_to_speak(true); @@ -743,7 +732,7 @@ impl GuildChannel { /// #[serenity::async_trait] /// impl EventHandler for Handler { /// async fn message(&self, context: Context, msg: Message) { - /// let channel = match context.cache.guild_channel(msg.channel_id) { + /// let channel = match context.cache.channel(msg.channel_id) { /// Some(channel) => channel, /// None => return, /// }; @@ -779,7 +768,7 @@ impl GuildChannel { /// impl EventHandler for Handler { /// async fn message(&self, context: Context, mut msg: Message) { /// let current_user_id = context.cache.current_user().id; - /// let permissions = match context.cache.guild_channel(msg.channel_id) { + /// let permissions = match context.cache.channel(msg.channel_id) { /// Some(channel) => channel.permissions_for_user(&context.cache, current_user_id), /// None => return, /// }; diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs index c6c1df8275e..0f5e21e955a 100644 --- a/src/model/channel/message.rs +++ b/src/model/channel/message.rs @@ -167,7 +167,6 @@ impl Message { utils::user_has_perms_cache( cache, self.channel_id, - self.guild_id, Permissions::MANAGE_MESSAGES, )?; } @@ -226,7 +225,6 @@ impl Message { utils::user_has_perms_cache( cache, self.channel_id, - self.guild_id, Permissions::MANAGE_MESSAGES, )?; } @@ -250,12 +248,7 @@ impl Message { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - utils::user_has_perms_cache( - cache, - self.channel_id, - self.guild_id, - Permissions::MANAGE_MESSAGES, - )?; + utils::user_has_perms_cache(cache, self.channel_id, Permissions::MANAGE_MESSAGES)?; } } @@ -301,12 +294,7 @@ impl Message { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - utils::user_has_perms_cache( - cache, - self.channel_id, - self.guild_id, - Permissions::MANAGE_MESSAGES, - )?; + utils::user_has_perms_cache(cache, self.channel_id, Permissions::MANAGE_MESSAGES)?; } } @@ -512,7 +500,6 @@ impl Message { utils::user_has_perms_cache( cache, self.channel_id, - self.guild_id, Permissions::MANAGE_MESSAGES, )?; } @@ -557,7 +544,6 @@ impl Message { utils::user_has_perms_cache( cache, self.channel_id, - self.guild_id, Permissions::ADD_REACTIONS, )?; } @@ -669,7 +655,6 @@ impl Message { utils::user_has_perms_cache( cache, self.channel_id, - self.guild_id, Permissions::SEND_MESSAGES, )?; } @@ -740,7 +725,6 @@ impl Message { utils::user_has_perms_cache( cache, self.channel_id, - self.guild_id, Permissions::MANAGE_MESSAGES, )?; } diff --git a/src/model/channel/private_channel.rs b/src/model/channel/private_channel.rs index 86700007b69..83fcf5813c4 100644 --- a/src/model/channel/private_channel.rs +++ b/src/model/channel/private_channel.rs @@ -69,8 +69,8 @@ impl PrivateChannel { /// closing a private channel on the client, which can be re-opened. #[allow(clippy::missing_errors_doc)] #[inline] - pub async fn delete(&self, http: impl AsRef) -> Result { - self.id.delete(http).await + pub async fn delete(&self, http: impl AsRef) -> Result { + self.id.delete(http).await?.private().ok_or(Error::Model(ModelError::InvalidChannelType)) } /// Deletes all messages by Ids from the given vector in the channel. diff --git a/src/model/channel/reaction.rs b/src/model/channel/reaction.rs index 5d66307d099..c4b4fd467af 100644 --- a/src/model/channel/reaction.rs +++ b/src/model/channel/reaction.rs @@ -108,7 +108,6 @@ impl Reaction { crate::utils::user_has_perms_cache( cache, self.channel_id, - self.guild_id, Permissions::MANAGE_MESSAGES, )?; } @@ -140,7 +139,6 @@ impl Reaction { crate::utils::user_has_perms_cache( cache, self.channel_id, - self.guild_id, Permissions::MANAGE_MESSAGES, )?; } diff --git a/src/model/event.rs b/src/model/event.rs index 61cbcc0f568..21b89a52b34 100644 --- a/src/model/event.rs +++ b/src/model/event.rs @@ -80,7 +80,6 @@ pub struct AutoModActionExecutionEvent { /// /// This is fired when: /// - A [`Channel`] is created in a [`Guild`] -/// - A [`PrivateChannel`] is created /// /// Requires [`GatewayIntents::GUILDS`]. /// @@ -90,7 +89,7 @@ pub struct AutoModActionExecutionEvent { #[non_exhaustive] pub struct ChannelCreateEvent { /// The channel that was created. - pub channel: Channel, + pub channel: GuildChannel, } /// Requires [`GatewayIntents::GUILDS`]. @@ -100,7 +99,7 @@ pub struct ChannelCreateEvent { #[serde(transparent)] #[non_exhaustive] pub struct ChannelDeleteEvent { - pub channel: Channel, + pub channel: GuildChannel, } /// Requires [`GatewayIntents::GUILDS`] or [`GatewayIntents::DIRECT_MESSAGES`]. @@ -121,7 +120,7 @@ pub struct ChannelPinsUpdateEvent { #[serde(transparent)] #[non_exhaustive] pub struct ChannelUpdateEvent { - pub channel: Channel, + pub channel: GuildChannel, } /// Requires [`GatewayIntents::GUILD_MODERATION`] and [`Permissions::VIEW_AUDIT_LOG`]. diff --git a/src/model/invite.rs b/src/model/invite.rs index ffaa8da1286..08ed87d1c23 100644 --- a/src/model/invite.rs +++ b/src/model/invite.rs @@ -100,11 +100,9 @@ impl Invite { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - let guild_id = self.guild.as_ref().map(|g| g.id); crate::utils::user_has_perms_cache( cache, self.channel.id, - guild_id, Permissions::MANAGE_GUILD, )?; } @@ -325,11 +323,9 @@ impl RichInvite { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { - let guild_id = self.guild.as_ref().map(|g| g.id); crate::utils::user_has_perms_cache( cache, self.channel.id, - guild_id, Permissions::MANAGE_GUILD, )?; } diff --git a/src/model/user.rs b/src/model/user.rs index 54073f679e3..883203f834a 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -705,19 +705,6 @@ impl UserId { /// /// [current user]: CurrentUser pub async fn create_dm_channel(self, cache_http: impl CacheHttp) -> Result { - #[cfg(feature = "cache")] - { - if let Some(cache) = cache_http.cache() { - for channel_entry in cache.private_channels().iter() { - let channel = channel_entry.value(); - - if channel.recipient.id == self { - return Ok(channel.clone()); - } - } - } - } - let map = json!({ "recipient_id": self, }); diff --git a/src/model/webhook.rs b/src/model/webhook.rs index 64850275d77..26e1004b022 100644 --- a/src/model/webhook.rs +++ b/src/model/webhook.rs @@ -1,5 +1,8 @@ //! Webhook model and implementations. +#[cfg(all(feature = "model", feature = "temp_cache"))] +use std::sync::Arc; + #[cfg(feature = "model")] use secrecy::ExposeSecret; use secrecy::SecretString; @@ -12,7 +15,7 @@ use super::utils::secret; #[cfg(feature = "model")] use crate::builder::{Builder, EditWebhook, EditWebhookMessage, ExecuteWebhook}; #[cfg(feature = "cache")] -use crate::cache::{Cache, GuildRef}; +use crate::cache::{Cache, GuildChannelRef, GuildRef}; #[cfg(feature = "model")] use crate::http::{CacheHttp, Http}; #[cfg(feature = "model")] @@ -172,10 +175,10 @@ pub struct WebhookChannel { #[cfg(feature = "model")] impl WebhookChannel { - /// Attempts to find a [`Channel`] by its Id in the cache. + /// Attempts to find a [`GuildChannel`] by its Id in the cache. #[cfg(feature = "cache")] #[inline] - pub fn to_channel_cached(self, cache: impl AsRef) -> Option { + pub fn to_channel_cached(self, cache: &Cache) -> Option> { cache.as_ref().channel(self.id) } @@ -191,28 +194,27 @@ impl WebhookChannel { /// /// Returns [`Error::Http`] if the channel retrieval request failed. #[inline] - pub async fn to_channel(self, cache_http: impl CacheHttp) -> Result { + pub async fn to_channel(self, cache_http: impl CacheHttp) -> Result { #[cfg(feature = "cache")] { if let Some(cache) = cache_http.cache() { if let Some(channel) = cache.channel(self.id) { - return Ok(channel); + return Ok(channel.clone()); } } } let channel = cache_http.http().get_channel(self.id).await?; + let guild_channel = channel.guild().ok_or(Error::Model(ModelError::InvalidChannelType))?; #[cfg(all(feature = "cache", feature = "temp_cache"))] { if let Some(cache) = cache_http.cache() { - if let Channel::Guild(guild_channel) = &channel { - cache.temp_channels.insert(guild_channel.id, guild_channel.clone()); - } + cache.temp_channels.insert(guild_channel.id, Arc::new(guild_channel.clone())); } } - Ok(channel) + Ok(guild_channel) } } diff --git a/src/utils/content_safe.rs b/src/utils/content_safe.rs index 1d37deb67f0..522483463cf 100644 --- a/src/utils/content_safe.rs +++ b/src/utils/content_safe.rs @@ -1,7 +1,6 @@ use std::borrow::Cow; use crate::cache::Cache; -use crate::model::channel::Channel; use crate::model::id::GuildId; use crate::model::mention::Mention; use crate::model::user::User; @@ -223,7 +222,7 @@ fn clean_mention( let cache = cache.as_ref(); match mention { Mention::Channel(id) => { - if let Some(Channel::Guild(channel)) = id.to_channel_cached(cache) { + if let Some(channel) = id.to_channel_cached(cache) { format!("#{}", channel.name).into() } else { "#deleted-channel".into() diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 1ea93720a48..6605424e522 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -441,10 +441,9 @@ pub(crate) fn user_has_guild_perms( pub(crate) fn user_has_perms_cache( cache: impl AsRef, channel_id: ChannelId, - guild_id: Option, required_permissions: Permissions, ) -> Result<()> { - match user_perms(cache, channel_id, guild_id) { + match user_perms(cache, channel_id) { Ok(perms) => { if perms.contains(required_permissions) { Ok(()) @@ -461,34 +460,14 @@ pub(crate) fn user_has_perms_cache( } #[cfg(all(feature = "cache", feature = "model"))] -pub(crate) fn user_perms( - cache: impl AsRef, - channel_id: ChannelId, - guild_id: Option, -) -> Result { +pub(crate) fn user_perms(cache: impl AsRef, channel_id: ChannelId) -> Result { let cache = cache.as_ref(); let Some(channel) = cache.channel(channel_id) else { return Err(Error::Model(ModelError::ChannelNotFound)); }; - // Both users in DMs, all users in groups, and maybe all channels in categories will have the - // same permissions. - // - // The only exception to this is when the current user is blocked by the recipient in a DM - // channel, preventing the current user from sending messages. - // - // Since serenity can't _reasonably_ check and keep track of these, just assume that all - // permissions are granted and return `true`. - let (guild_id, guild_channel) = match channel { - Channel::Guild(channel) => (channel.guild_id, channel), - Channel::Private(_) => match guild_id { - Some(_) => return Err(Error::Model(ModelError::InvalidChannelType)), - None => return Ok(Permissions::all()), - }, - }; - - let Some(guild) = cache.guild(guild_id) else { + let Some(guild) = cache.guild(channel.guild_id) else { return Err(Error::Model(ModelError::GuildNotFound)); }; @@ -496,7 +475,7 @@ pub(crate) fn user_perms( return Err(Error::Model(ModelError::MemberNotFound)); }; - Ok(guild.user_permissions_in(&guild_channel, member)) + Ok(guild.user_permissions_in(&channel, member)) } /// Calculates the Id of the shard responsible for a guild, given its Id and total number of shards