diff --git a/examples/e05_command_framework/src/main.rs b/examples/e05_command_framework/src/main.rs index 37b8160fe5b..d9dfae22b96 100644 --- a/examples/e05_command_framework/src/main.rs +++ b/examples/e05_command_framework/src/main.rs @@ -343,23 +343,18 @@ async fn commands(ctx: &Context, msg: &Message) -> CommandResult { #[command] async fn say(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult { match args.single_quoted::() { - Ok(x) => { - let settings = if let Some(guild_id) = msg.guild_id { + Ok(mut x) => { + // We only need to wipe mentions in guilds, as DM mentions do not matter. + if let Some(guild) = msg.guild(&ctx.cache) { // By default roles, users, and channel mentions are cleaned. - ContentSafeOptions::default() + let settings = ContentSafeOptions::default() // We do not want to clean channal mentions as they do not ping users. - .clean_channel(false) - // If it's a guild channel, we want mentioned users to be displayed as their - // display name. - .display_as_member_from(guild_id) - } else { - ContentSafeOptions::default().clean_channel(false).clean_role(false) - }; + .clean_channel(false); - let content = content_safe(&ctx.cache, x, &settings, &msg.mentions); - - msg.channel_id.say(&ctx.http, &content).await?; + x = content_safe(&guild, x, &settings, &msg.mentions); + } + msg.channel_id.say(&ctx.http, x).await?; return Ok(()); }, Err(_) => { diff --git a/src/cache/event.rs b/src/cache/event.rs index 9c315360d5e..e49f855ff6f 100644 --- a/src/cache/event.rs +++ b/src/cache/event.rs @@ -97,14 +97,7 @@ impl CacheUpdate for GuildCreateEvent { fn update(&mut self, cache: &Cache) -> Option<()> { cache.unavailable_guilds.remove(&self.guild.id); - let mut guild = self.guild.clone(); - - for (user_id, member) in &mut guild.members { - cache.update_user_entry(&member.user); - if let Some(u) = cache.user(user_id) { - member.user = u.clone(); - } - } + let guild = self.guild.clone(); cache.guilds.insert(self.guild.id, guild); for channel_id in self.guild.channels.keys() { @@ -159,15 +152,9 @@ impl CacheUpdate for GuildMemberAddEvent { type Output = (); fn update(&mut self, cache: &Cache) -> Option<()> { - let user_id = self.member.user.id; - cache.update_user_entry(&self.member.user); - if let Some(u) = cache.user(user_id) { - self.member.user = u.clone(); - } - if let Some(mut guild) = cache.guilds.get_mut(&self.member.guild_id) { guild.member_count += 1; - guild.members.insert(user_id, self.member.clone()); + guild.members.insert(self.member.user.id, self.member.clone()); } None @@ -191,8 +178,6 @@ impl CacheUpdate for GuildMemberUpdateEvent { type Output = Member; fn update(&mut self, cache: &Cache) -> Option { - cache.update_user_entry(&self.user); - if let Some(mut guild) = cache.guilds.get_mut(&self.guild_id) { let item = if let Some(member) = guild.members.get_mut(&self.user.id) { let item = Some(member.clone()); @@ -242,10 +227,6 @@ impl CacheUpdate for GuildMembersChunkEvent { type Output = (); fn update(&mut self, cache: &Cache) -> Option<()> { - for member in self.members.values() { - cache.update_user_entry(&member.user); - } - if let Some(mut g) = cache.guilds.get_mut(&self.guild_id) { g.members.extend(self.members.clone()); } @@ -385,14 +366,6 @@ impl CacheUpdate for PresenceUpdateEvent { type Output = (); fn update(&mut self, cache: &Cache) -> Option<()> { - if let Some(user) = self.presence.user.to_user() { - cache.update_user_entry(&user); - } - - if let Some(user) = cache.user(self.presence.user.id) { - self.presence.user.update_with_user(&user); - } - if let Some(guild_id) = self.presence.guild_id { if let Some(mut guild) = cache.guilds.get_mut(&guild_id) { // If the member went offline, remove them from the presence list. diff --git a/src/cache/mod.rs b/src/cache/mod.rs index c569666dd8f..36ca9ec3ebe 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -31,7 +31,6 @@ use std::sync::Arc; #[cfg(feature = "temp_cache")] use std::time::Duration; -use dashmap::mapref::entry::Entry; use dashmap::mapref::one::{MappedRef, MappedRefMut, Ref}; use dashmap::DashMap; #[cfg(feature = "temp_cache")] @@ -186,22 +185,6 @@ pub struct Cache { /// are "sent in" over time through the receiving of [`Event::GuildCreate`]s. pub(crate) unavailable_guilds: MaybeMap, - // Users cache: - // --- - /// A map of users that the current user sees. - /// - /// Users are added to - and updated from - this map via the following received events: - /// - /// - [`GuildMemberAdd`][`GuildMemberAddEvent`] - /// - [`GuildMemberRemove`][`GuildMemberRemoveEvent`] - /// - [`GuildMembersChunk`][`GuildMembersChunkEvent`] - /// - [`PresenceUpdate`][`PresenceUpdateEvent`] - /// - [`Ready`][`ReadyEvent`] - /// - /// Note, however, that users are _not_ removed from the map on removal events such as - /// [`GuildMemberRemove`][`GuildMemberRemoveEvent`], as other structs such as members or - /// recipients may still exist. - pub(crate) users: MaybeMap, /// A map of users' presences. This is updated in real-time. Note that status updates are often /// "eaten" by the gateway, and this should not be treated as being entirely 100% accurate. pub(crate) presences: MaybeMap, @@ -275,7 +258,6 @@ impl Cache { guilds: MaybeMap(settings.cache_guilds.then(DashMap::default)), unavailable_guilds: MaybeMap(settings.cache_guilds.then(DashMap::default)), - users: MaybeMap(settings.cache_users.then(DashMap::default)), presences: MaybeMap(settings.cache_users.then(DashMap::default)), messages: DashMap::default(), @@ -647,56 +629,6 @@ impl Cache { self.settings.write().max_messages = max; } - /// Retrieves a [`User`] from the cache's [`Self::users`] map, if it exists. - /// - /// The only advantage of this method is that you can pass in anything that is indirectly a - /// [`UserId`]. - /// - /// # Examples - /// - /// Retrieve a user from the cache and print their name: - /// - /// ```rust,no_run - /// # use serenity::client::Context; - /// # - /// # async fn test(context: &Context) -> Result<(), Box> { - /// if let Some(user) = context.cache.user(7) { - /// println!("User with Id 7 is currently named {}", user.name); - /// } - /// # Ok(()) - /// # } - /// ``` - #[inline] - pub fn user>(&self, user_id: U) -> Option> { - self._user(user_id.into()) - } - - #[cfg(feature = "temp_cache")] - fn _user(&self, user_id: UserId) -> Option> { - if let Some(user) = self.users.get(&user_id) { - Some(CacheRef::from_ref(user)) - } else { - self.temp_users.get(&user_id).map(CacheRef::from_arc) - } - } - - #[cfg(not(feature = "temp_cache"))] - fn _user(&self, user_id: UserId) -> Option> { - self.users.get(&user_id).map(CacheRef::from_ref) - } - - /// Clones all users and returns them. - #[inline] - pub fn users(&self) -> ReadOnlyMapRef<'_, UserId, User> { - self.users.as_read_only() - } - - /// Returns the amount of cached users. - #[inline] - pub fn user_count(&self) -> usize { - self.users.len() - } - /// This method provides a reference to the user used by the bot. #[inline] pub fn current_user(&self) -> CurrentUserRef<'_> { @@ -745,19 +677,6 @@ impl Cache { pub fn update(&self, e: &mut E) -> Option { e.update(self) } - - pub(crate) fn update_user_entry(&self, user: &User) { - if let Some(users) = &self.users.0 { - match users.entry(user.id) { - Entry::Vacant(e) => { - e.insert(user.clone()); - }, - Entry::Occupied(mut e) => { - e.get_mut().clone_from(user); - }, - } - } - } } impl Default for Cache { diff --git a/src/model/gateway.rs b/src/model/gateway.rs index 567fc4d1897..3c27ccdd3e5 100644 --- a/src/model/gateway.rs +++ b/src/model/gateway.rs @@ -291,20 +291,6 @@ impl PresenceUser { pub fn to_user(&self) -> Option { self.clone().into_user() } - - #[cfg(feature = "cache")] // method is only used with the cache feature enabled - pub(crate) fn update_with_user(&mut self, user: &User) { - self.id = user.id; - if let Some(avatar) = user.avatar { - self.avatar = Some(avatar); - } - self.bot = Some(user.bot); - self.discriminator = user.discriminator; - self.name = Some(user.name.clone()); - if let Some(public_flags) = user.public_flags { - self.public_flags = Some(public_flags); - } - } } /// Information detailing the current online status of a [`User`]. diff --git a/src/model/user.rs b/src/model/user.rs index c0f3bc5c3dc..0da40a2874d 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -11,8 +11,6 @@ use serde::{Deserialize, Serialize}; use super::prelude::*; #[cfg(feature = "model")] use crate::builder::{Builder, CreateMessage, EditProfile}; -#[cfg(all(feature = "cache", feature = "model"))] -use crate::cache::{Cache, UserRef}; #[cfg(feature = "collector")] use crate::collector::{MessageCollector, ReactionCollector}; #[cfg(feature = "collector")] @@ -671,13 +669,6 @@ impl UserId { cache_http.http().create_private_channel(&map).await } - /// Attempts to find a [`User`] by its Id in the cache. - #[cfg(feature = "cache")] - #[inline] - pub fn to_user_cached(self, cache: &impl AsRef) -> Option> { - cache.as_ref().user(self) - } - /// First attempts to find a [`User`] by its Id in the cache, upon failure requests it via the /// REST API. /// @@ -694,18 +685,18 @@ impl UserId { /// May also return an [`Error::Json`] if there is an error in deserializing the user. #[inline] pub async fn to_user(self, cache_http: impl CacheHttp) -> Result { - #[cfg(feature = "cache")] + #[cfg(feature = "temp_cache")] { if let Some(cache) = cache_http.cache() { - if let Some(user) = cache.user(self) { - return Ok(user.clone()); + if let Some(user) = cache.temp_users.get(&self) { + return Ok(User::clone(&user)); } } } let user = cache_http.http().get_user(self).await?; - #[cfg(all(feature = "cache", feature = "temp_cache"))] + #[cfg(feature = "temp_cache")] { if let Some(cache) = cache_http.cache() { use crate::cache::MaybeOwnedArc; diff --git a/src/utils/argument_convert/user.rs b/src/utils/argument_convert/user.rs index 24fb459fb86..c49db78a360 100644 --- a/src/utils/argument_convert/user.rs +++ b/src/utils/argument_convert/user.rs @@ -23,36 +23,6 @@ impl fmt::Display for UserParseError { } } -#[cfg(feature = "cache")] -fn lookup_by_global_cache(ctx: impl CacheHttp, s: &str) -> Option { - let users = &ctx.cache()?.users; - - let lookup_by_id = || users.get(&s.parse().ok()?).map(|u| u.clone()); - - let lookup_by_mention = || users.get(&crate::utils::parse_user_mention(s)?).map(|u| u.clone()); - - let lookup_by_name_and_discrim = || { - let (name, discrim) = crate::utils::parse_user_tag(s)?; - users.iter().find_map(|m| { - let user = m.value(); - (user.discriminator == discrim && user.name.eq_ignore_ascii_case(name)) - .then(|| user.clone()) - }) - }; - - let lookup_by_name = || { - users.iter().find_map(|m| { - let user = m.value(); - (&*user.name == s).then(|| user.clone()) - }) - }; - - lookup_by_id() - .or_else(lookup_by_mention) - .or_else(lookup_by_name_and_discrim) - .or_else(lookup_by_name) -} - /// Look up a user by a string case-insensitively. /// /// Requires the cache feature to be enabled. If a user is not in cache, they will not be found! @@ -72,13 +42,7 @@ impl ArgumentConvert for User { channel_id: Option, s: &str, ) -> Result { - // Try to look up in global user cache via a variety of methods - #[cfg(feature = "cache")] - if let Some(user) = lookup_by_global_cache(&ctx, s) { - return Ok(user); - } - - // If not successful, convert as a Member which uses HTTP endpoints instead of cache + // Convert as a Member which uses HTTP endpoints instead of cache if let Ok(member) = Member::convert(&ctx, guild_id, channel_id, s).await { return Ok(member.user); } diff --git a/src/utils/content_safe.rs b/src/utils/content_safe.rs index 3ed64a46523..c87da4140f0 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::id::GuildId; +use crate::model::guild::Guild; use crate::model::mention::Mention; use crate::model::user::User; @@ -14,7 +13,6 @@ pub struct ContentSafeOptions { clean_here: bool, clean_everyone: bool, show_discriminator: bool, - guild_reference: Option, } impl ContentSafeOptions { @@ -64,15 +62,6 @@ impl ContentSafeOptions { self } - /// If set, [`content_safe`] will replace a user mention with the user's display name in passed - /// `guild`. - #[must_use] - pub fn display_as_member_from>(mut self, guild: G) -> Self { - self.guild_reference = Some(guild.into()); - - self - } - /// If set, [`content_safe`] will replace `@here` with a non-pinging alternative. #[must_use] pub fn clean_here(mut self, b: bool) -> Self { @@ -100,13 +89,12 @@ impl Default for ContentSafeOptions { clean_here: true, clean_everyone: true, show_discriminator: true, - guild_reference: None, } } } /// Transforms role, channel, user, `@everyone` and `@here` mentions into raw text by using the -/// [`Cache`] and the users passed in with `users`. +/// Guild and the users passed in with `users`. /// /// [`ContentSafeOptions`] decides what kind of mentions should be filtered and how the raw-text /// will be displayed. @@ -116,15 +104,14 @@ impl Default for ContentSafeOptions { /// Sanitise an `@everyone` mention. /// /// ```rust -/// # use serenity::client::Cache; -/// # -/// # let cache = Cache::default(); +/// # let cache = serenity::client::Cache::default(); +/// # let guild = serenity::model::guild::Guild::default(); /// use serenity::utils::{content_safe, ContentSafeOptions}; /// /// let with_mention = "@everyone"; -/// let without_mention = content_safe(&cache, &with_mention, &ContentSafeOptions::default(), &[]); +/// let without_mention = content_safe(&guild, &with_mention, &ContentSafeOptions::default(), &[]); /// -/// assert_eq!("@\u{200B}everyone".to_string(), without_mention); +/// assert_eq!("@\u{200B}everyone", without_mention); /// ``` /// /// Filtering out mentions from a message. @@ -135,16 +122,26 @@ impl Default for ContentSafeOptions { /// use serenity::utils::{content_safe, ContentSafeOptions}; /// /// fn filter_message(cache: &Cache, message: &Message) -> String { -/// content_safe(cache, &message.content, &ContentSafeOptions::default(), &message.mentions) +/// if let Some(guild) = message.guild(cache) { +/// content_safe( +/// &guild, +/// &message.content, +/// &ContentSafeOptions::default(), +/// &message.mentions, +/// ) +/// } else { +/// // We don't need to clean messages in DMs +/// message.content.to_string() +/// } /// } /// ``` pub fn content_safe( - cache: impl AsRef, + guild: &Guild, s: impl AsRef, options: &ContentSafeOptions, users: &[User], ) -> String { - let mut content = clean_mentions(&cache, s, options, users); + let mut content = clean_mentions(guild, s, options, users); if options.clean_here { content = content.replace("@here", "@\u{200B}here"); @@ -158,7 +155,7 @@ pub fn content_safe( } fn clean_mentions( - cache: impl AsRef, + guild: &Guild, s: impl AsRef, options: &ContentSafeOptions, users: &[User], @@ -197,7 +194,7 @@ fn clean_mentions( // NOTE: numeric strings that are too large to fit into u64 will not parse // correctly and will be left unchanged. if let Ok(mention) = mention_str.parse() { - content.push_str(&clean_mention(&cache, mention, options, users)); + content.push_str(&clean_mention(guild, mention, options, users)); cleaned = true; } } @@ -214,53 +211,39 @@ fn clean_mentions( } fn clean_mention( - cache: impl AsRef, + guild: &Guild, mention: Mention, options: &ContentSafeOptions, users: &[User], ) -> Cow<'static, str> { - let cache = cache.as_ref(); match mention { Mention::Channel(id) => { - if let Some(channel) = id.to_channel_cached(cache) { + if let Some(channel) = guild.channels.get(&id) { format!("#{}", channel.name).into() } else { "#deleted-channel".into() } }, - Mention::Role(id) => options - .guild_reference - .and_then(|id| cache.guild(id)) - .and_then(|g| g.roles.get(&id).map(|role| format!("@{}", role.name).into())) - .unwrap_or(Cow::Borrowed("@deleted-role")), + Mention::Role(id) => guild + .roles + .get(&id) + .map_or(Cow::Borrowed("@deleted-role"), |role| format!("@{}", role.name).into()), Mention::User(id) => { - if let Some(guild_id) = options.guild_reference { - if let Some(guild) = cache.guild(guild_id) { - if let Some(member) = guild.members.get(&id) { - return if options.show_discriminator { - format!("@{}", member.distinct()) - } else { - format!("@{}", member.display_name()) - } - .into(); - } + if let Some(member) = guild.members.get(&id) { + if options.show_discriminator { + format!("@{}", member.distinct()).into() + } else { + format!("@{}", member.display_name()).into() } - } - - let get_username = |user: &User| { + } else if let Some(user) = users.iter().find(|u| u.id == id) { if options.show_discriminator { - format!("@{}", user.tag()) + format!("@{}", user.tag()).into() } else { - format!("@{}", user.name) + format!("@{}", user.name).into() } - .into() - }; - - cache - .user(id) - .map(|u| get_username(&u)) - .or_else(|| users.iter().find(|u| u.id == id).map(get_username)) - .unwrap_or(Cow::Borrowed("@invalid-user")) + } else { + "@invalid-user".into() + } }, } } @@ -268,12 +251,10 @@ fn clean_mention( #[allow(clippy::non_ascii_literal)] #[cfg(test)] mod tests { - use std::sync::Arc; - use super::*; use crate::model::channel::*; use crate::model::guild::*; - use crate::model::id::{ChannelId, RoleId, UserId}; + use crate::model::id::{ChannelId, GuildId, RoleId, UserId}; use crate::model::user::User; #[test] @@ -284,17 +265,13 @@ mod tests { ..Default::default() }; - let outside_cache_user = User { - id: UserId::new(100000000000000001), - name: "Boat".to_string().into(), - ..Default::default() - }; - - let mut guild = Guild { + let no_member_guild = Guild { id: GuildId::new(381880193251409931), ..Default::default() }; + let mut guild = no_member_guild.clone(); + let member = Member { nick: Some("Ferris".to_string().into()), ..Default::default() @@ -312,14 +289,9 @@ mod tests { ..Default::default() }; - let cache = Arc::new(Cache::default()); - guild.channels.insert(channel.id, channel.clone()); guild.members.insert(user.id, member.clone()); guild.roles.insert(role.id, role); - cache.users.insert(user.id, user.clone()); - cache.guilds.insert(guild.id, guild.clone()); - cache.channels.insert(channel.id, guild.id); let with_user_mentions = "<@!100000000000000000> <@!000000000000000000> <@123> <@!123> \ <@!123123123123123123123> <@123> <@123123123123123123> <@!invalid> \ @@ -327,7 +299,7 @@ mod tests { <@!i)/==(<<>z/9080)> <@!1231invalid> <@invalid123> \ <@123invalid> <@> <@ "; - let without_user_mentions = "@Crab <@!000000000000000000> @invalid-user @invalid-user \ + let without_user_mentions = "@Ferris <@!000000000000000000> @invalid-user @invalid-user \ <@!123123123123123123123> @invalid-user @invalid-user <@!invalid> \ <@invalid> <@日本語 한국어$§)[/__#\\(/&2032$§#> \ <@!i)/==(<<>z/9080)> <@!1231invalid> <@invalid123> \ @@ -335,49 +307,31 @@ mod tests { // User mentions let options = ContentSafeOptions::default(); - assert_eq!(without_user_mentions, content_safe(&cache, with_user_mentions, &options, &[])); - - let options = ContentSafeOptions::default(); - assert_eq!( - format!("@{}", user.name), - content_safe(&cache, "<@!100000000000000000>", &options, &[]) - ); - - let options = ContentSafeOptions::default(); - assert_eq!( - format!("@{}", user.name), - content_safe(&cache, "<@100000000000000000>", &options, &[]) - ); - - let options = ContentSafeOptions::default(); - assert_eq!("@invalid-user", content_safe(&cache, "<@100000000000000001>", &options, &[])); + assert_eq!(without_user_mentions, content_safe(&guild, with_user_mentions, &options, &[])); - let options = ContentSafeOptions::default(); assert_eq!( - format!("@{}", outside_cache_user.name), - content_safe(&cache, "<@100000000000000001>", &options, &[outside_cache_user]) + "@invalid-user", + content_safe(&no_member_guild, "<@100000000000000001>", &options, &[]) ); - let options = options.show_discriminator(false); + let options = ContentSafeOptions::default().show_discriminator(false); assert_eq!( format!("@{}", user.name), - content_safe(&cache, "<@!100000000000000000>", &options, &[]) + content_safe(&no_member_guild, "<@!100000000000000000>", &options, &[user.clone()]) ); - let options = options.show_discriminator(false); assert_eq!( - format!("@{}", user.name), - content_safe(&cache, "<@100000000000000000>", &options, &[]) + "@invalid-user", + content_safe(&no_member_guild, "<@!100000000000000000>", &options, &[]) ); - let options = options.display_as_member_from(guild.id); assert_eq!( - format!("@{}", member.nick.unwrap()), - content_safe(&cache, "<@!100000000000000000>", &options, &[]) + format!("@{}", member.nick.as_ref().unwrap()), + content_safe(&guild, "<@100000000000000000>", &options, &[]) ); let options = options.clean_user(false); - assert_eq!(with_user_mentions, content_safe(&cache, with_user_mentions, &options, &[])); + assert_eq!(with_user_mentions, content_safe(&guild, with_user_mentions, &options, &[])); // Channel mentions let with_channel_mentions = "<#> <#deleted-channel> #deleted-channel <#1> \ @@ -390,13 +344,13 @@ mod tests { assert_eq!( without_channel_mentions, - content_safe(&cache, with_channel_mentions, &options, &[]) + content_safe(&guild, with_channel_mentions, &options, &[]) ); let options = options.clean_channel(false); assert_eq!( with_channel_mentions, - content_safe(&cache, with_channel_mentions, &options, &[]) + content_safe(&guild, with_channel_mentions, &options, &[]) ); // Role mentions @@ -408,10 +362,10 @@ mod tests { @ferris-club-member @deleted-role \ <@&111111111111111111111111111111> <@&@deleted-role"; - assert_eq!(without_role_mentions, content_safe(&cache, with_role_mentions, &options, &[])); + assert_eq!(without_role_mentions, content_safe(&guild, with_role_mentions, &options, &[])); let options = options.clean_role(false); - assert_eq!(with_role_mentions, content_safe(&cache, with_role_mentions, &options, &[])); + assert_eq!(with_role_mentions, content_safe(&guild, with_role_mentions, &options, &[])); // Everyone mentions let with_everyone_mention = "@everyone"; @@ -420,13 +374,13 @@ mod tests { assert_eq!( without_everyone_mention, - content_safe(&cache, with_everyone_mention, &options, &[]) + content_safe(&guild, with_everyone_mention, &options, &[]) ); let options = options.clean_everyone(false); assert_eq!( with_everyone_mention, - content_safe(&cache, with_everyone_mention, &options, &[]) + content_safe(&guild, with_everyone_mention, &options, &[]) ); // Here mentions @@ -434,9 +388,9 @@ mod tests { let without_here_mention = "@\u{200B}here"; - assert_eq!(without_here_mention, content_safe(&cache, with_here_mention, &options, &[])); + assert_eq!(without_here_mention, content_safe(&guild, with_here_mention, &options, &[])); let options = options.clean_here(false); - assert_eq!(with_here_mention, content_safe(&cache, with_here_mention, &options, &[])); + assert_eq!(with_here_mention, content_safe(&guild, with_here_mention, &options, &[])); } }