diff options
| author | Lakelezz <[email protected]> | 2018-12-18 20:55:32 +0100 |
|---|---|---|
| committer | Alex M. M <[email protected]> | 2018-12-18 20:55:32 +0100 |
| commit | 8cb1bdc6cf992cc55810f5af753666d54f2237d5 (patch) | |
| tree | 052e2f425a6117e45323886bb2b2b683b6d5a1e8 /src/model | |
| parent | Mutably borrow on `ChannelId`'s `edit`-method. (#447) (diff) | |
| download | serenity-8cb1bdc6cf992cc55810f5af753666d54f2237d5.tar.xz serenity-8cb1bdc6cf992cc55810f5af753666d54f2237d5.zip | |
Remove global Cache (#448)
* Update to use Rust 2018.
* Update examples and use Rust 2018.
* Pass cache via `Context` around instead of being global.
* Remove `lazy_static` from `cache`-feature.
* Update examples to use `Context`'s cache.
* Replace cache's update-timeout-setting with `update_cache_timeout`.
* Update documentation to stop using global cache.
* Move `HttpAndCache` to `lib.rs`.
* Add `__nonexhaustive`-field to `CacheAndHttp`.
* Add `__nonexhaustive` in `CacheAndHttp`-initialisers.
* Avoid `__nonexhaustive`-usage in doctest.
* Remove unnecessary comma in `cfg`-attribute.
Diffstat (limited to 'src/model')
| -rw-r--r-- | src/model/channel/channel_category.rs | 18 | ||||
| -rw-r--r-- | src/model/channel/channel_id.rs | 25 | ||||
| -rw-r--r-- | src/model/channel/guild_channel.rs | 94 | ||||
| -rw-r--r-- | src/model/channel/message.rs | 78 | ||||
| -rw-r--r-- | src/model/channel/mod.rs | 60 | ||||
| -rw-r--r-- | src/model/channel/reaction.rs | 37 | ||||
| -rw-r--r-- | src/model/guild/emoji.rs | 55 | ||||
| -rw-r--r-- | src/model/guild/guild_id.rs | 20 | ||||
| -rw-r--r-- | src/model/guild/member.rs | 36 | ||||
| -rw-r--r-- | src/model/guild/mod.rs | 91 | ||||
| -rw-r--r-- | src/model/guild/partial_guild.rs | 12 | ||||
| -rw-r--r-- | src/model/guild/role.rs | 32 | ||||
| -rw-r--r-- | src/model/invite.rs | 26 | ||||
| -rw-r--r-- | src/model/misc.rs | 14 | ||||
| -rw-r--r-- | src/model/user.rs | 140 | ||||
| -rw-r--r-- | src/model/utils.rs | 6 |
16 files changed, 425 insertions, 319 deletions
diff --git a/src/model/channel/channel_category.rs b/src/model/channel/channel_category.rs index f38b0f6..50720f9 100644 --- a/src/model/channel/channel_category.rs +++ b/src/model/channel/channel_category.rs @@ -1,5 +1,7 @@ -use crate::model::prelude::*; +use crate::{model::prelude::*}; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(all(feature = "builder", feature = "model"))] use crate::builder::EditChannel; #[cfg(all(feature = "builder", feature = "model"))] @@ -55,14 +57,18 @@ impl ChannelCategory { self.id.delete_permission(permission_type) } - /// Deletes this category. + + /// Deletes this category if required permissions are met. + /// + /// **Note**: If the `cache`-feature is enabled permissions will be checked and upon + /// owning the required permissions the HTTP-request will be issued. #[inline] - pub fn delete(&self) -> Result<()> { + pub fn delete(&self, context: &Context) -> Result<()> { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_CHANNELS; - if !utils::user_has_perms(self.id, req)? { + if !utils::user_has_perms(&context.cache, self.id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -82,13 +88,13 @@ impl ChannelCategory { /// category.edit(|c| c.name("test").bitrate(86400)); /// ``` #[cfg(all(feature = "builder", feature = "model", feature = "utils"))] - pub fn edit<F>(&mut self, f: F) -> Result<()> + pub fn edit<F>(&mut self, context: &Context, f: F) -> Result<()> where F: FnOnce(EditChannel) -> EditChannel { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_CHANNELS; - if !utils::user_has_perms(self.id, req)? { + if !utils::user_has_perms(&context.cache, self.id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } diff --git a/src/model/channel/channel_id.rs b/src/model/channel/channel_id.rs index 782ea5b..3f452fa 100644 --- a/src/model/channel/channel_id.rs +++ b/src/model/channel/channel_id.rs @@ -1,6 +1,7 @@ -use crate::internal::RwLockExt; -use crate::model::prelude::*; +use crate::{internal::RwLockExt, model::prelude::*}; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(feature = "model")] use std::borrow::Cow; #[cfg(feature = "model")] @@ -13,9 +14,9 @@ use crate::builder::{ GetMessages }; #[cfg(all(feature = "cache", feature = "model"))] -use crate::CACHE; +use crate::cache::Cache; #[cfg(all(feature = "cache", feature = "model"))] -use crate::Cache; +use parking_lot::RwLock; #[cfg(feature = "model")] use crate::http::{self, AttachmentType}; #[cfg(feature = "model")] @@ -293,8 +294,8 @@ impl ChannelId { /// [`Channel`]: ../channel/enum.Channel.html #[cfg(feature = "cache")] #[inline] - pub fn to_channel_cached(self) -> Option<Channel> { - self._to_channel_cached(&CACHE) + pub fn to_channel_cached(self, cache: &Arc<RwLock<Cache>>) -> Option<Channel> { + self._to_channel_cached(&cache) } /// To allow testing pass their own cache instead of using the globale one. @@ -307,15 +308,15 @@ impl ChannelId { /// First attempts to find a [`Channel`] by its Id in the cache, /// upon failure requests it via the REST API. /// - /// **Note**: If the cache is not enabled, - /// REST API will be used only. + /// **Note**: If the `cache`-feature is enabled permissions will be checked and upon + /// owning the required permissions the HTTP-request will be issued. /// /// [`Channel`]: ../channel/enum.Channel.html #[inline] - pub fn to_channel(self) -> Result<Channel> { + pub fn to_channel(self, context: &Context) -> Result<Channel> { #[cfg(feature = "cache")] { - if let Some(channel) = CACHE.read().channel(self) { + if let Some(channel) = context.cache.read().channel(self) { return Ok(channel); } } @@ -385,11 +386,11 @@ impl ChannelId { /// Returns the name of whatever channel this id holds. #[cfg(feature = "model")] - pub fn name(&self) -> Option<String> { + pub fn name(&self, context: &Context) -> Option<String> { use self::Channel::*; let finding = feature_cache! {{ - Some(self.to_channel_cached()) + Some(self.to_channel_cached(&context.cache)) } else { None }}; diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs index b976b0b..0c476e6 100644 --- a/src/model/channel/guild_channel.rs +++ b/src/model/channel/guild_channel.rs @@ -1,8 +1,14 @@ use chrono::{DateTime, FixedOffset}; -use crate::model::prelude::*; +use crate::{model::prelude::*}; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(all(feature = "cache", feature = "model"))] -use crate::CACHE; +use crate::cache::Cache; +#[cfg(feature = "cache")] +use parking_lot::RwLock; +#[cfg(feature = "cache")] +use std::sync::Arc; #[cfg(feature = "model")] use crate::builder::{ CreateInvite, @@ -119,16 +125,17 @@ impl GuildChannel { /// let invite = channel.create_invite(|i| i.max_uses(5)); /// ``` #[cfg(feature = "utils")] - pub fn create_invite<F>(&self, f: F) -> Result<RichInvite> + pub fn create_invite<F>(&self, context: &Context, f: F) -> Result<RichInvite> where F: FnOnce(&mut CreateInvite) -> &mut CreateInvite { #[cfg(feature = "cache")] { let req = Permissions::CREATE_INVITE; - if !utils::user_has_perms(self.id, req)? { + if !utils::user_has_perms(&context.cache, self.id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } + let mut invite = CreateInvite::default(); f(&mut invite); @@ -153,10 +160,15 @@ impl GuildChannel { /// permissions: /// /// ```rust,no_run - /// # use serenity::model::id::{ChannelId, UserId}; - /// # use std::error::Error; + /// # extern crate parking_lot; + /// # extern crate serenity; /// # - /// # fn try_main() -> Result<(), Box<Error>> { + /// # use serenity::{cache::Cache, model::id::{ChannelId, UserId}}; + /// # use parking_lot::RwLock; + /// # use std::{error::Error, sync::Arc}; + /// # + /// # fn main() -> Result<(), Box<Error>> { + /// # let cache = Arc::new(RwLock::new(Cache::default())); /// # let (channel_id, user_id) = (ChannelId(0), UserId(0)); /// # /// use serenity::model::channel::{ @@ -164,8 +176,6 @@ impl GuildChannel { /// PermissionOverwriteType, /// }; /// use serenity::model::{ModelError, Permissions}; - /// use serenity::CACHE; - /// /// let allow = Permissions::SEND_MESSAGES; /// let deny = Permissions::SEND_TTS_MESSAGES | Permissions::ATTACH_FILES; /// let overwrite = PermissionOverwrite { @@ -173,18 +183,14 @@ impl GuildChannel { /// deny: deny, /// kind: PermissionOverwriteType::Member(user_id), /// }; - /// - /// let cache = CACHE.read(); + /// # let cache = cache.read(); + /// // assuming the cache has been unlocked /// let channel = cache /// .guild_channel(channel_id) /// .ok_or(ModelError::ItemMissing)?; /// /// channel.read().create_permission(&overwrite)?; - /// # Ok(()) - /// # } - /// # - /// # fn main() { - /// # try_main().unwrap(); + /// # Ok(()) /// # } /// ``` /// @@ -194,18 +200,22 @@ impl GuildChannel { /// permissions: /// /// ```rust,no_run - /// # use serenity::model::id::{ChannelId, UserId}; - /// # use std::error::Error; + /// # extern crate parking_lot; + /// # extern crate serenity; + /// + /// # use serenity::{cache::Cache, model::id::{ChannelId, UserId}}; + /// # use parking_lot::RwLock; + /// # use std::{error::Error, sync::Arc}; /// # /// # fn try_main() -> Result<(), Box<Error>> { - /// # let (channel_id, user_id) = (ChannelId(0), UserId(0)); + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let (channel_id, user_id) = (ChannelId(0), UserId(0)); /// # /// use serenity::model::channel::{ /// PermissionOverwrite, /// PermissionOverwriteType, /// }; /// use serenity::model::{ModelError, Permissions}; - /// use serenity::CACHE; /// /// let allow = Permissions::SEND_MESSAGES; /// let deny = Permissions::SEND_TTS_MESSAGES | Permissions::ATTACH_FILES; @@ -215,7 +225,7 @@ impl GuildChannel { /// kind: PermissionOverwriteType::Member(user_id), /// }; /// - /// let cache = CACHE.read(); + /// let cache = cache.read(); /// let channel = cache /// .guild_channel(channel_id) /// .ok_or(ModelError::ItemMissing)?; @@ -247,12 +257,15 @@ impl GuildChannel { } /// Deletes this channel, returning the channel on a successful deletion. - pub fn delete(&self) -> Result<Channel> { + /// + /// **Note**: If the `cache`-feature is enabled permissions will be checked and upon + /// owning the required permissions the HTTP-request will be issued. + pub fn delete(&self, context: &Context) -> Result<Channel> { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_CHANNELS; - if !utils::user_has_perms(self.id, req)? { + if !utils::user_has_perms(&context.cache, self.id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -322,13 +335,13 @@ impl GuildChannel { /// channel.edit(|c| c.name("test").bitrate(86400)); /// ``` #[cfg(feature = "utils")] - pub fn edit<F>(&mut self, f: F) -> Result<()> + pub fn edit<F>(&mut self, context: &Context, f: F) -> Result<()> where F: FnOnce(EditChannel) -> EditChannel { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_CHANNELS; - if !utils::user_has_perms(self.id, req)? { + if !utils::user_has_perms(&context.cache, self.id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -380,7 +393,7 @@ impl GuildChannel { /// **Note**: Right now this performs a clone of the guild. This will be /// optimized in the future. #[cfg(feature = "cache")] - pub fn guild(&self) -> Option<Arc<RwLock<Guild>>> { CACHE.read().guild(self.guild_id) } + pub fn guild(&self, cache: &Arc<RwLock<Cache>>) -> Option<Arc<RwLock<Guild>>> { cache.read().guild(self.guild_id) } /// Gets all of the channel's invites. /// @@ -443,16 +456,14 @@ impl GuildChannel { /// use serenity::model::prelude::*; /// struct Handler; /// - /// use serenity::CACHE; - /// /// impl EventHandler for Handler { - /// fn message(&self, _: Context, msg: Message) { - /// let channel = match CACHE.read().guild_channel(msg.channel_id) { + /// fn message(&self, context: Context, msg: Message) { + /// let channel = match context.cache.read().guild_channel(msg.channel_id) { /// Some(channel) => channel, /// None => return, /// }; /// - /// let permissions = channel.read().permissions_for(&msg.author).unwrap(); + /// let permissions = channel.read().permissions_for(&context.cache, &msg.author).unwrap(); /// /// println!("The user's permissions: {:?}", permissions); /// } @@ -467,7 +478,6 @@ impl GuildChannel { /// for demonstrative purposes): /// /// ```rust,no_run - /// use serenity::CACHE; /// use serenity::prelude::*; /// use serenity::model::prelude::*; /// use std::fs::File; @@ -475,15 +485,15 @@ impl GuildChannel { /// struct Handler; /// /// impl EventHandler for Handler { - /// fn message(&self, _: Context, mut msg: Message) { - /// let channel = match CACHE.read().guild_channel(msg.channel_id) { + /// fn message(&self, context: Context, mut msg: Message) { + /// let channel = match context.cache.read().guild_channel(msg.channel_id) { /// Some(channel) => channel, /// None => return, /// }; /// - /// let current_user_id = CACHE.read().user.id; + /// let current_user_id = context.cache.read().user.id; /// let permissions = - /// channel.read().permissions_for(current_user_id).unwrap(); + /// channel.read().permissions_for(&context.cache, current_user_id).unwrap(); /// /// if !permissions.contains(Permissions::ATTACH_FILES | Permissions::SEND_MESSAGES) { /// return; @@ -526,13 +536,13 @@ impl GuildChannel { /// [Send Messages]: ../permissions/struct.Permissions.html#associatedconstant.SEND_MESSAGES #[cfg(feature = "cache")] #[inline] - pub fn permissions_for<U: Into<UserId>>(&self, user_id: U) -> Result<Permissions> { - self._permissions_for(user_id.into()) + pub fn permissions_for<U: Into<UserId>>(&self, cache: &Arc<RwLock<Cache>>, user_id: U) -> Result<Permissions> { + self._permissions_for(&cache, user_id.into()) } #[cfg(feature = "cache")] - fn _permissions_for(&self, user_id: UserId) -> Result<Permissions> { - self.guild() + fn _permissions_for(&self, cache: &Arc<RwLock<Cache>>, user_id: UserId) -> Result<Permissions> { + self.guild(&cache) .ok_or_else(|| Error::Model(ModelError::GuildNotFound)) .map(|g| g.read().permissions_in(self.id, user_id)) } @@ -628,13 +638,13 @@ impl GuildChannel { /// [`ModelError::MessageTooLong`]: ../error/enum.Error.html#variant.MessageTooLong /// [`Message`]: struct.Message.html /// [Send Messages]: ../permissions/struct.Permissions.html#associatedconstant.SEND_MESSAGES - pub fn send_message<F>(&self, f: F) -> Result<Message> + pub fn send_message<F>(&self, context: &Context, f: F) -> Result<Message> where for <'b> F: FnOnce(&'b mut CreateMessage<'b>) -> &'b mut CreateMessage<'b> { #[cfg(feature = "cache")] { let req = Permissions::SEND_MESSAGES; - if !utils::user_has_perms(self.id, req)? { + if !utils::user_has_perms(&context.cache, self.id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } diff --git a/src/model/channel/message.rs b/src/model/channel/message.rs index 28c00fe..60ee3df 100644 --- a/src/model/channel/message.rs +++ b/src/model/channel/message.rs @@ -1,13 +1,19 @@ //! Models relating to Discord channels. use chrono::{DateTime, FixedOffset}; -use crate::model::prelude::*; +use crate::{model::prelude::*}; use serde_json::Value; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(feature = "model")] use crate::builder::{CreateEmbed, EditMessage}; #[cfg(all(feature = "cache", feature = "model"))] -use crate::CACHE; +use crate::cache::Cache; +#[cfg(all(feature = "cache", feature = "model"))] +use parking_lot::RwLock; +#[cfg(all(feature = "cache", feature = "model"))] +use std::sync::Arc; #[cfg(all(feature = "cache", feature = "model"))] use std::fmt::Write; #[cfg(feature = "model")] @@ -102,30 +108,30 @@ impl Message { /// .configure(|c| c.prefix("~")) /// .cmd("channelname", channel_name)); /// - /// command!(channel_name(_ctx, msg) { - /// let _ = match msg.channel() { - /// Some(Channel::Category(c)) => msg.reply(&c.read().name), - /// Some(Channel::Group(c)) => msg.reply(&c.read().name()), - /// Some(Channel::Guild(c)) => msg.reply(&c.read().name), + /// command!(channel_name(ctx, msg) { + /// let _ = match msg.channel(&ctx.cache) { + /// Some(Channel::Category(c)) => msg.reply(&ctx, &c.read().name), + /// Some(Channel::Group(c)) => msg.reply(&ctx, &c.read().name()), + /// Some(Channel::Guild(c)) => msg.reply(&ctx, &c.read().name), /// Some(Channel::Private(c)) => { /// let channel = c.read(); /// let user = channel.recipient.read(); /// - /// msg.reply(&format!("DM with {}", user.name.clone())) + /// msg.reply(&ctx, &format!("DM with {}", user.name.clone())) /// }, - /// None => msg.reply("Unknown"), + /// None => msg.reply(&ctx, "Unknown"), /// }; /// }); /// # } /// ``` #[cfg(feature = "cache")] #[inline] - pub fn channel(&self) -> Option<Channel> { CACHE.read().channel(self.channel_id) } + pub fn channel(&self, cache: &Arc<RwLock<Cache>>) -> Option<Channel> { cache.read().channel(self.channel_id) } /// A util function for determining whether this message was sent by someone else, or the /// bot. #[cfg(all(feature = "cache", feature = "utils"))] - pub fn is_own(&self) -> bool { self.author.id == CACHE.read().user.id } + pub fn is_own(&self, cache: &Arc<RwLock<Cache>>) -> bool { self.author.id == cache.read().user.id } /// Deletes the message. /// @@ -141,12 +147,12 @@ impl Message { /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [`ModelError::InvalidUser`]: ../error/enum.Error.html#variant.InvalidUser /// [Manage Messages]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_MESSAGES - pub fn delete(&self) -> Result<()> { + pub fn delete(&self, context: &Context) -> Result<()> { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_MESSAGES; - let is_author = self.author.id == CACHE.read().user.id; - let has_perms = utils::user_has_perms(self.channel_id, req)?; + let is_author = self.author.id == context.cache.read().user.id; + let has_perms = utils::user_has_perms(&context.cache, self.channel_id, req)?; if !is_author && !has_perms { return Err(Error::Model(ModelError::InvalidPermissions(req))); @@ -169,12 +175,12 @@ impl Message { /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [`Reaction`]: struct.Reaction.html /// [Manage Messages]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_MESSAGES - pub fn delete_reactions(&self) -> Result<()> { + pub fn delete_reactions(&self, context: &Context) -> Result<()> { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_MESSAGES; - if !utils::user_has_perms(self.channel_id, req)? { + if !utils::user_has_perms(&context.cache, self.channel_id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -214,11 +220,11 @@ impl Message { /// [`ModelError::MessageTooLong`]: ../error/enum.Error.html#variant.MessageTooLong /// [`EditMessage`]: ../../builder/struct.EditMessage.html /// [`the limit`]: ../../builder/struct.EditMessage.html#method.content - pub fn edit<F>(&mut self, f: F) -> Result<()> + pub fn edit<F>(&mut self, context: &Context, f: F) -> Result<()> where F: FnOnce(&mut EditMessage) -> &mut EditMessage { #[cfg(feature = "cache")] { - if self.author.id != CACHE.read().user.id { + if self.author.id != context.cache.read().user.id { return Err(Error::Model(ModelError::InvalidUser)); } } @@ -276,7 +282,7 @@ impl Message { /// Returns message content, but with user and role mentions replaced with /// names and everyone/here mentions cancelled. #[cfg(feature = "cache")] - pub fn content_safe(&self) -> String { + pub fn content_safe(&self, cache: &Arc<RwLock<Cache>>) -> String { let mut result = self.content.clone(); // First replace all user mentions. @@ -293,7 +299,7 @@ impl Message { for id in &self.mention_roles { let mention = id.mention(); - if let Some(role) = id.to_role_cached() { + if let Some(role) = id.to_role_cached(&cache) { result = result.replace(&mention, &format!("@{}", role.name)); } else { result = result.replace(&mention, "@deleted-role"); @@ -342,8 +348,8 @@ impl Message { /// /// [`guild_id`]: #method.guild_id #[cfg(feature = "cache")] - pub fn guild(&self) -> Option<Arc<RwLock<Guild>>> { - CACHE.read().guild(self.guild_id?) + pub fn guild(&self, cache: &Arc<RwLock<Cache>>) -> Option<Arc<RwLock<Guild>>> { + cache.read().guild(self.guild_id?) } /// True if message was sent using direct messages. @@ -360,8 +366,8 @@ impl Message { /// /// [`Guild::members`]: ../guild/struct.Guild.html#structfield.members #[cfg(feature = "cache")] - pub fn member(&self) -> Option<Member> { - self.guild().and_then(|g| g.read().members.get(&self.author.id).cloned()) + pub fn member(&self, cache: &Arc<RwLock<Cache>>) -> Option<Member> { + self.guild(&cache).and_then(|g| g.read().members.get(&self.author.id).cloned()) } /// Checks the length of a string to ensure that it is within Discord's @@ -395,13 +401,13 @@ impl Message { /// /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [Manage Messages]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_MESSAGES.html - pub fn pin(&self) -> Result<()> { + pub fn pin(&self, context: &Context) -> Result<()> { #[cfg(feature = "cache")] { if self.guild_id.is_some() { let req = Permissions::MANAGE_MESSAGES; - if !utils::user_has_perms(self.channel_id, req)? { + if !utils::user_has_perms(&context.cache, self.channel_id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -426,17 +432,17 @@ impl Message { /// ../permissions/struct.Permissions.html#associatedconstant.ADD_REACTIONS /// [permissions]: ../permissions/index.html #[inline] - pub fn react<R: Into<ReactionType>>(&self, reaction_type: R) -> Result<()> { - self._react(&reaction_type.into()) + pub fn react<R: Into<ReactionType>>(&self, context: &Context, reaction_type: R) -> Result<()> { + self._react(&context, &reaction_type.into()) } - fn _react(&self, reaction_type: &ReactionType) -> Result<()> { + fn _react(&self, context: &Context, reaction_type: &ReactionType) -> Result<()> { #[cfg(feature = "cache")] { if self.guild_id.is_some() { let req = Permissions::ADD_REACTIONS; - if !utils::user_has_perms(self.channel_id, req)? { + if !utils::user_has_perms(&context.cache, self.channel_id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -467,7 +473,7 @@ impl Message { /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [`ModelError::MessageTooLong`]: ../error/enum.Error.html#variant.MessageTooLong /// [Send Messages]: ../permissions/struct.Permissions.html#associatedconstant.SEND_MESSAGES - pub fn reply(&self, content: &str) -> Result<Message> { + pub fn reply(&self, context: &Context, content: &str) -> Result<Message> { if let Some(length_over) = Message::overflow_length(content) { return Err(Error::Model(ModelError::MessageTooLong(length_over))); } @@ -477,7 +483,7 @@ impl Message { if self.guild_id.is_some() { let req = Permissions::SEND_MESSAGES; - if !utils::user_has_perms(self.channel_id, req)? { + if !utils::user_has_perms(&context.cache, self.channel_id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -526,13 +532,13 @@ impl Message { /// /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [Manage Messages]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_MESSAGES - pub fn unpin(&self) -> Result<()> { + pub fn unpin(&self, context: &Context) -> Result<()> { #[cfg(feature = "cache")] { if self.guild_id.is_some() { let req = Permissions::MANAGE_MESSAGES; - if !utils::user_has_perms(self.channel_id, req)? { + if !utils::user_has_perms(&context.cache, self.channel_id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -546,8 +552,8 @@ impl Message { /// **Note**: /// If message was sent in a private channel, then the function will return /// `None`. - pub fn author_nick(&self) -> Option<String> { - self.guild_id.as_ref().and_then(|guild_id| self.author.nick_in(*guild_id)) + pub fn author_nick(&self, context: &Context) -> Option<String> { + self.guild_id.as_ref().and_then(|guild_id| self.author.nick_in(&context, *guild_id)) } pub(crate) fn check_content_length(map: &JsonMap) -> Result<()> { diff --git a/src/model/channel/mod.rs b/src/model/channel/mod.rs index 9c913cb..d21acb2 100644 --- a/src/model/channel/mod.rs +++ b/src/model/channel/mod.rs @@ -20,22 +20,29 @@ pub use self::private_channel::*; pub use self::reaction::*; pub use self::channel_category::*; -use crate::internal::RwLockExt; -use crate::model::prelude::*; +use crate::{internal::RwLockExt, model::prelude::*}; use serde::de::Error as DeError; use serde::ser::{SerializeStruct, Serialize, Serializer}; use serde_json; use super::utils::deserialize_u64; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(feature = "model")] use std::fmt::{Display, Formatter, Result as FmtResult}; #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] -use std::str::FromStr; +use crate::cache::FromStrAndCache; #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] use crate::model::misc::ChannelParseError; #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] use crate::utils::parse_channel; +#[cfg(feature = "cache")] +use crate::cache::Cache; +#[cfg(feature = "cache")] +use std::sync::Arc; +#[cfg(feature = "cache")] +use parking_lot::RwLock; /// A container for any channel. #[derive(Clone, Debug)] @@ -71,13 +78,17 @@ impl Channel { /// Basic usage: /// /// ```rust,no_run + /// # extern crate parking_lot; /// # extern crate serenity; /// # - /// # use self::serenity::model::id::ChannelId; + /// # use serenity::{cache::Cache, model::id::ChannelId}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; /// # /// # #[cfg(feature = "model")] /// # fn main() { - /// # let channel = ChannelId(0).to_channel().unwrap(); + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let channel = ChannelId(0).to_channel_cached(&cache).unwrap(); /// # /// match channel.group() { /// Some(group_lock) => { @@ -113,13 +124,17 @@ impl Channel { /// Basic usage: /// /// ```rust,no_run + /// # extern crate parking_lot; /// # extern crate serenity; /// # - /// # use self::serenity::model::id::ChannelId; + /// # use serenity::{cache::Cache, model::id::ChannelId}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; /// # /// # #[cfg(feature = "model")] /// # fn main() { - /// # let channel = ChannelId(0).to_channel().unwrap(); + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let channel = ChannelId(0).to_channel_cached(&cache).unwrap(); /// # /// match channel.guild() { /// Some(guild_lock) => { @@ -151,13 +166,17 @@ impl Channel { /// Basic usage: /// /// ```rust,no_run + /// # extern crate parking_lot; /// # extern crate serenity; /// # - /// # use self::serenity::model::id::ChannelId; + /// # use serenity::{cache::Cache, model::id::ChannelId}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; /// # /// # #[cfg(feature = "model")] /// # fn main() { - /// # let channel = ChannelId(0).to_channel().unwrap(); + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let channel = ChannelId(0).to_channel_cached(&cache).unwrap(); /// # /// match channel.private() { /// Some(private_lock) => { @@ -192,13 +211,17 @@ impl Channel { /// Basic usage: /// /// ```rust,no_run + /// # extern crate parking_lot; /// # extern crate serenity; /// # - /// # use self::serenity::model::id::ChannelId; + /// # use serenity::{cache::Cache, model::id::ChannelId}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; /// # /// # #[cfg(feature = "model")] /// # fn main() { - /// # let channel = ChannelId(0).to_channel().unwrap(); + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let channel = ChannelId(0).to_channel_cached(&cache).unwrap(); /// # /// match channel.category() { /// Some(category_lock) => { @@ -221,24 +244,27 @@ impl Channel { /// Deletes the inner channel. /// + /// **Note**: If the `cache`-feature is enabled permissions will be checked and upon + /// owning the required permissions the HTTP-request will be issued. + /// /// **Note**: There is no real function as _deleting_ a [`Group`]. The /// closest functionality is leaving it. /// /// [`Group`]: struct.Group.html #[cfg(feature = "model")] - pub fn delete(&self) -> Result<()> { + pub fn delete(&self, context: &Context) -> Result<()> { match *self { Channel::Group(ref group) => { let _ = group.read().leave()?; }, Channel::Guild(ref public_channel) => { - let _ = public_channel.read().delete()?; + let _ = public_channel.read().delete(&context)?; }, Channel::Private(ref private_channel) => { let _ = private_channel.read().delete()?; }, Channel::Category(ref category) => { - category.read().delete()?; + category.read().delete(&context)?; }, } @@ -564,12 +590,12 @@ mod test { } #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] -impl FromStr for Channel { +impl FromStrAndCache for Channel { type Err = ChannelParseError; - fn from_str(s: &str) -> StdResult<Self, Self::Err> { + fn from_str(cache: &Arc<RwLock<Cache>>, s: &str) -> StdResult<Self, Self::Err> { match parse_channel(s) { - Some(x) => match ChannelId(x).to_channel_cached() { + Some(x) => match ChannelId(x).to_channel_cached(&cache) { Some(channel) => Ok(channel), _ => Err(ChannelParseError::NotPresentInCache), }, diff --git a/src/model/channel/reaction.rs b/src/model/channel/reaction.rs index a1df12a..6c5bdeb 100644 --- a/src/model/channel/reaction.rs +++ b/src/model/channel/reaction.rs @@ -1,4 +1,4 @@ -use crate::model::prelude::*; +use crate::{model::prelude::*}; use serde::de::{Deserialize, Error as DeError, MapAccess, Visitor}; use serde::ser::{SerializeMap, Serialize, Serializer}; use std::{ @@ -11,10 +11,11 @@ use std::{ }, str::FromStr }; + use crate::internal::prelude::*; -#[cfg(all(feature = "cache", feature = "model"))] -use crate::CACHE; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(feature = "model")] use crate::http; @@ -50,8 +51,8 @@ impl Reaction { /// /// [Read Message History]: ../permissions/struct.Permissions.html#associatedconstant.READ_MESSAGE_HISTORY #[inline] - pub fn channel(&self) -> Result<Channel> { - self.channel_id.to_channel() + pub fn channel(&self, context: &Context) -> Result<Channel> { + self.channel_id.to_channel(&context) } /// Deletes the reaction, but only if the current user is the user who made @@ -69,10 +70,10 @@ impl Reaction { /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [Manage Messages]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_MESSAGES /// [permissions]: ../permissions/index.html - pub fn delete(&self) -> Result<()> { + pub fn delete(&self, context: &Context) -> Result<()> { let user_id = feature_cache! { { - let user = if self.user_id == CACHE.read().user.id { + let user = if self.user_id == context.cache.read().user.id { None } else { Some(self.user_id.0) @@ -87,7 +88,7 @@ impl Reaction { if user.is_some() { let req = Permissions::MANAGE_MESSAGES; - if !utils::user_has_perms(self.channel_id, req).unwrap_or(true) { + if !utils::user_has_perms(&context.cache, self.channel_id, req).unwrap_or(true) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -122,8 +123,8 @@ impl Reaction { /// If not - or the user was not found - this will perform a request over /// the REST API for the user. #[inline] - pub fn user(&self) -> Result<User> { - self.user_id.to_user() + pub fn user(&self, context: &Context) -> Result<User> { + self.user_id.to_user(&context) } /// Retrieves the list of [`User`]s who have reacted to a [`Message`] with a @@ -326,19 +327,13 @@ impl From<char> for ReactionType { /// Reacting to a message with an apple: /// /// ```rust,no_run - /// # use serenity::model::id::ChannelId; - /// # use std::error::Error; - /// # - /// # fn try_main() -> Result<(), Box<Error>> { - /// # let message = ChannelId(0).message(0)?; + /// # use serenity::{command, model::id::ChannelId}; /// # - /// message.react('🍎')?; - /// # Ok(()) - /// # } + /// # command!(example(context) { + /// # let message = ChannelId(0).message(0)?; /// # - /// # fn main() { - /// # try_main().unwrap(); - /// # } + /// message.react(&context, '🍎')?; + /// # }); /// ``` fn from(ch: char) -> ReactionType { ReactionType::Unicode(ch.to_string()) } } diff --git a/src/model/guild/emoji.rs b/src/model/guild/emoji.rs index 03c7a7e..dde379e 100644 --- a/src/model/guild/emoji.rs +++ b/src/model/guild/emoji.rs @@ -15,7 +15,11 @@ use super::super::ModelError; #[cfg(all(feature = "cache", feature = "model"))] use super::super::id::GuildId; #[cfg(all(feature = "cache", feature = "model"))] -use crate::{CACHE, http}; +use crate::{cache::Cache, http}; +#[cfg(all(feature = "cache", feature = "model"))] +use parking_lot::RwLock; +#[cfg(all(feature = "cache", feature = "model"))] +use std::sync::Arc; /// Represents a custom guild emoji, which can either be created using the API, /// or via an integration. Emojis created using the API only work within the @@ -52,7 +56,7 @@ impl Emoji { /// /// **Note**: Only user accounts may use this method. /// - /// [Manage Emojis]: + /// [Manage Emojis]: /// ../permissions/struct.Permissions.html#associatedconstant.MANAGE_EMOJIS /// /// # Examples @@ -60,8 +64,14 @@ impl Emoji { /// Delete a given emoji: /// /// ```rust,no_run - /// # use serenity::model::guild::Emoji; - /// # use serenity::model::id::EmojiId; + /// # extern crate parking_lot; + /// # extern crate serenity; + /// # + /// # use serenity::{cache::Cache, model::{guild::Emoji, id::EmojiId}}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; + /// # + /// # let cache = Arc::new(RwLock::new(Cache::default())); /// # /// # let mut emoji = Emoji { /// # animated: false, @@ -73,14 +83,14 @@ impl Emoji { /// # }; /// # /// // assuming emoji has been set already - /// match emoji.delete() { + /// match emoji.delete(&cache) { /// Ok(()) => println!("Emoji deleted."), /// Err(_) => println!("Could not delete emoji.") /// } /// ``` #[cfg(feature = "cache")] - pub fn delete(&self) -> Result<()> { - match self.find_guild_id() { + pub fn delete(&self, cache: &Arc<RwLock<Cache>>) -> Result<()> { + match self.find_guild_id(&cache) { Some(guild_id) => http::delete_emoji(guild_id.0, self.id.0), None => Err(Error::Model(ModelError::ItemMissing)), } @@ -99,9 +109,9 @@ impl Emoji { /// Change the name of an emoji: /// /// ```rust,no_run - /// # use serenity::model::guild::Emoji; - /// # use serenity::model::id::EmojiId; + /// # use serenity::{command, model::{guild::Emoji, id::EmojiId}}; /// # + /// # command!(example(context) { /// # let mut emoji = Emoji { /// # animated: false, /// # id: EmojiId(7), @@ -110,14 +120,14 @@ impl Emoji { /// # require_colons: false, /// # roles: vec![], /// # }; - /// # /// // assuming emoji has been set already - /// let _ = emoji.edit("blobuwu"); + /// let _ = emoji.edit(&context.cache, "blobuwu"); /// assert_eq!(emoji.name, "blobuwu"); + /// # }); /// ``` #[cfg(feature = "cache")] - pub fn edit(&mut self, name: &str) -> Result<()> { - match self.find_guild_id() { + pub fn edit(&mut self, cache: &Arc<RwLock<Cache>>, name: &str) -> Result<()> { + match self.find_guild_id(&cache) { Some(guild_id) => { let map = json!({ "name": name, @@ -145,8 +155,14 @@ impl Emoji { /// Print the guild id that owns this emoji: /// /// ```rust,no_run - /// # use serenity::model::guild::Emoji; - /// # use serenity::model::id::EmojiId; + /// # extern crate parking_lot; + /// # extern crate serenity; + /// # + /// # use serenity::{cache::Cache, model::{guild::Emoji, id::EmojiId}}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; + /// # + /// # let cache = Arc::new(RwLock::new(Cache::default())); /// # /// # let mut emoji = Emoji { /// # animated: false, @@ -158,13 +174,13 @@ impl Emoji { /// # }; /// # /// // assuming emoji has been set already - /// if let Some(guild_id) = emoji.find_guild_id() { + /// if let Some(guild_id) = emoji.find_guild_id(&cache) { /// println!("{} is owned by {}", emoji.name, guild_id); /// } /// ``` #[cfg(feature = "cache")] - pub fn find_guild_id(&self) -> Option<GuildId> { - for guild in CACHE.read().guilds.values() { + pub fn find_guild_id(&self, cache: &Arc<RwLock<Cache>>) -> Option<GuildId> { + for guild in cache.read().guilds.values() { let guild = guild.read(); if guild.emojis.contains_key(&self.id) { @@ -182,8 +198,7 @@ impl Emoji { /// Print the direct link to the given emoji: /// /// ```rust,no_run - /// # use serenity::model::guild::Emoji; - /// # use serenity::model::id::EmojiId; + /// # use serenity::model::{guild::Emoji, id::EmojiId}; /// # /// # let mut emoji = Emoji { /// # animated: false, diff --git a/src/model/guild/guild_id.rs b/src/model/guild/guild_id.rs index c488b52..3146c78 100644 --- a/src/model/guild/guild_id.rs +++ b/src/model/guild/guild_id.rs @@ -1,7 +1,9 @@ -use crate::model::prelude::*; +use crate::{model::prelude::*}; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(all(feature = "cache", feature = "model"))] -use crate::CACHE; +use crate::cache::Cache; #[cfg(feature = "model")] use crate::builder::{EditGuild, EditMember, EditRole}; #[cfg(feature = "model")] @@ -407,7 +409,7 @@ impl GuildId { /// [`Guild`]: ../guild/struct.Guild.html #[cfg(feature = "cache")] #[inline] - pub fn to_guild_cached(self) -> Option<Arc<RwLock<Guild>>> { CACHE.read().guild(self) } + pub fn to_guild_cached(self, cache: &Arc<RwLock<Cache>>) -> Option<Arc<RwLock<Guild>>> { cache.read().guild(self) } /// Requests [`PartialGuild`] over REST API. /// @@ -456,14 +458,14 @@ impl GuildId { /// [`Guild`]: ../guild/struct.Guild.html /// [`Member`]: ../guild/struct.Member.html #[inline] - pub fn member<U: Into<UserId>>(&self, user_id: U) -> Result<Member> { - self._member(user_id.into()) + pub fn member<U: Into<UserId>>(&self, context: &Context, user_id: U) -> Result<Member> { + self._member(&context, user_id.into()) } - fn _member(&self, user_id: UserId) -> Result<Member> { + fn _member(&self, context: &Context, user_id: UserId) -> Result<Member> { #[cfg(feature = "cache")] { - if let Some(member) = CACHE.read().member(self.0, user_id) { + if let Some(member) = context.cache.read().member(self.0, user_id) { return Ok(member); } } @@ -563,7 +565,9 @@ impl GuildId { /// [`utils::shard_id`]: ../../utils/fn.shard_id.html #[cfg(all(feature = "cache", feature = "utils"))] #[inline] - pub fn shard_id(&self) -> u64 { crate::utils::shard_id(self.0, CACHE.read().shard_count) } + pub fn shard_id(&self, cache: &Arc<RwLock<Cache>>) -> u64 { + crate::utils::shard_id(self.0, cache.read().shard_count) + } /// Returns the Id of the shard associated with the guild. /// diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index cbda4c3..d969bd0 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -1,4 +1,4 @@ -use crate::model::prelude::*; +use crate::{model::prelude::*}; use chrono::{DateTime, FixedOffset}; use std::fmt::{ Display, @@ -7,6 +7,8 @@ use std::fmt::{ }; use super::deserialize_sync_user; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(all(feature = "builder", feature = "cache", feature = "model"))] use crate::builder::EditMember; #[cfg(all(feature = "cache", feature = "model"))] @@ -16,7 +18,7 @@ use std::borrow::Cow; #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] use crate::utils::Colour; #[cfg(all(feature = "cache", feature = "model"))] -use crate::{CACHE, http, utils}; +use crate::{cache::Cache, http, utils}; /// A trait for allowing both u8 or &str or (u8, &str) to be passed into the `ban` methods in `Guild` and `Member`. pub trait BanOptions { @@ -169,8 +171,8 @@ impl Member { /// Determines the member's colour. #[cfg(all(feature = "cache", feature = "utils"))] - pub fn colour(&self) -> Option<Colour> { - let cache = CACHE.read(); + pub fn colour(&self, cache: &Arc<RwLock<Cache>>) -> Option<Colour> { + let cache = cache.read(); let guild = cache.guilds.get(&self.guild_id)?.read(); let mut roles = self.roles @@ -191,8 +193,8 @@ impl Member { /// (This returns the first channel that can be read by the member, if there isn't /// one returns `None`) #[cfg(feature = "cache")] - pub fn default_channel(&self) -> Option<Arc<RwLock<GuildChannel>>> { - let guild = match self.guild_id.to_guild_cached() { + pub fn default_channel(&self, cache: &Arc<RwLock<Cache>>) -> Option<Arc<RwLock<GuildChannel>>> { + let guild = match self.guild_id.to_guild_cached(&cache) { Some(guild) => guild, None => return None, }; @@ -257,8 +259,8 @@ impl Member { /// position. If two or more roles have the same highest position, then the /// role with the lowest ID is the highest. #[cfg(feature = "cache")] - pub fn highest_role_info(&self) -> Option<(RoleId, i64)> { - let guild = self.guild_id.to_guild_cached()?; + pub fn highest_role_info(&self, cache: &Arc<RwLock<Cache>>) -> Option<(RoleId, i64)> { + let guild = self.guild_id.to_guild_cached(&cache)?; let reader = guild.try_read()?; let mut highest = None; @@ -315,20 +317,20 @@ impl Member { /// [`ModelError::GuildNotFound`]: ../error/enum.Error.html#variant.GuildNotFound /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [Kick Members]: ../permissions/struct.Permissions.html#associatedconstant.KICK_MEMBERS - pub fn kick(&self) -> Result<()> { + pub fn kick(&self, context: &Context) -> Result<()> { #[cfg(feature = "cache")] { - let cache = CACHE.read(); + let locked_cache = context.cache.read(); - if let Some(guild) = cache.guilds.get(&self.guild_id) { + if let Some(guild) = locked_cache.guilds.get(&self.guild_id) { let req = Permissions::KICK_MEMBERS; let reader = guild.read(); - if !reader.has_perms(req) { + if !reader.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } - reader.check_hierarchy(self.user.read().id)?; + reader.check_hierarchy(&context.cache, self.user.read().id)?; } } @@ -356,8 +358,8 @@ impl Member { /// [`ModelError::GuildNotFound`]: ../error/enum.Error.html#variant.GuildNotFound /// [`ModelError::ItemMissing`]: ../error/enum.Error.html#variant.ItemMissing #[cfg(feature = "cache")] - pub fn permissions(&self) -> Result<Permissions> { - let guild = match self.guild_id.to_guild_cached() { + pub fn permissions(&self, cache: &Arc<RwLock<Cache>>) -> Result<Permissions> { + let guild = match self.guild_id.to_guild_cached(&cache) { Some(guild) => guild, None => return Err(From::from(ModelError::GuildNotFound)), }; @@ -426,10 +428,10 @@ impl Member { /// /// If role data can not be found for the member, then `None` is returned. #[cfg(feature = "cache")] - pub fn roles(&self) -> Option<Vec<Role>> { + pub fn roles(&self, cache: &Arc<RwLock<Cache>>) -> Option<Vec<Role>> { self .guild_id - .to_guild_cached() + .to_guild_cached(&cache) .map(|g| g .read() .roles diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index 86cba3d..3ea8d06 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -17,13 +17,19 @@ pub use self::role::*; pub use self::audit_log::*; use chrono::{DateTime, FixedOffset}; -use crate::model::prelude::*; +use crate::{model::prelude::*}; use serde::de::Error as DeError; use serde_json; use super::utils::*; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(all(feature = "cache", feature = "model"))] -use crate::CACHE; +use crate::cache::Cache; +#[cfg(all(feature = "cache", feature = "model"))] +use parking_lot::RwLock; +#[cfg(all(feature = "cache", feature = "model"))] +use std::sync::Arc; #[cfg(feature = "model")] use crate::http; #[cfg(feature = "model")] @@ -146,10 +152,10 @@ pub struct Guild { #[cfg(feature = "model")] impl Guild { #[cfg(feature = "cache")] - fn check_hierarchy(&self, other_user: UserId) -> Result<()> { - let current_id = CACHE.read().user.id; + fn check_hierarchy(&self, cache: &Arc<RwLock<Cache>>, other_user: UserId) -> Result<()> { + let current_id = cache.read().user.id; - if let Some(higher) = self.greater_member_hierarchy(other_user, current_id) { + if let Some(higher) = self.greater_member_hierarchy(&cache, other_user, current_id) { if higher != current_id { return Err(Error::Model(ModelError::Hierarchy)); } @@ -189,8 +195,8 @@ impl Guild { } #[cfg(feature = "cache")] - fn has_perms(&self, mut permissions: Permissions) -> bool { - let user_id = CACHE.read().user.id; + fn has_perms(&self, cache: &Arc<RwLock<Cache>>, mut permissions: Permissions) -> bool { + let user_id = cache.read().user.id; let perms = self.member_permissions(user_id); permissions.remove(perms); @@ -228,20 +234,20 @@ impl Guild { /// [`User`]: ../user/struct.User.html /// [Ban Members]: ../permissions/struct.Permissions.html#associatedconstant.BAN_MEMBERS #[inline] - pub fn ban<U: Into<UserId>, BO: BanOptions>(&self, user: U, options: &BO) -> Result<()> { - self._ban(user.into(), options) + pub fn ban<U: Into<UserId>, BO: BanOptions>(&self, context: &Context, user: U, options: &BO) -> Result<()> { + self._ban(&context, user.into(), options) } - fn _ban<BO: BanOptions>(&self, user: UserId, options: &BO) -> Result<()> { + fn _ban<BO: BanOptions>(&self, context: &Context, user: UserId, options: &BO) -> Result<()> { #[cfg(feature = "cache")] { let req = Permissions::BAN_MEMBERS; - if !self.has_perms(req) { + if !self.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } - self.check_hierarchy(user)?; + self.check_hierarchy(&context.cache, user)?; } self.id.ban(user, options) @@ -259,12 +265,12 @@ impl Guild { /// [`Ban`]: struct.Ban.html /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [Ban Members]: ../permissions/struct.Permissions.html#associatedconstant.BAN_MEMBERS - pub fn bans(&self) -> Result<Vec<Ban>> { + pub fn bans(&self, context: &Context) -> Result<Vec<Ban>> { #[cfg(feature = "cache")] { let req = Permissions::BAN_MEMBERS; - if !self.has_perms(req) { + if !self.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -346,13 +352,13 @@ impl Guild { /// [`Channel`]: ../channel/enum.Channel.html /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [Manage Channels]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_CHANNELS - pub fn create_channel<C>(&self, name: &str, kind: ChannelType, category: C) -> Result<GuildChannel> + pub fn create_channel<C>(&self, context: &Context, name: &str, kind: ChannelType, category: C) -> Result<GuildChannel> where C: Into<Option<ChannelId>> { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_CHANNELS; - if !self.has_perms(req) { + if !self.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -417,13 +423,13 @@ impl Guild { /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [`Role`]: struct.Role.html /// [Manage Roles]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_ROLES - pub fn create_role<F>(&self, f: F) -> Result<Role> + pub fn create_role<F>(&self, context: &Context, f: F) -> Result<Role> where F: FnOnce(&mut EditRole) -> &mut EditRole { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_ROLES; - if !self.has_perms(req) { + if !self.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -442,10 +448,10 @@ impl Guild { /// if the current user is not the guild owner. /// /// [`ModelError::InvalidUser`]: ../error/enum.Error.html#variant.InvalidUser - pub fn delete(&self) -> Result<PartialGuild> { + pub fn delete(&self, context: &Context) -> Result<PartialGuild> { #[cfg(feature = "cache")] { - if self.owner_id != CACHE.read().user.id { + if self.owner_id != context.cache.read().user.id { let req = Permissions::MANAGE_GUILD; return Err(Error::Model(ModelError::InvalidPermissions(req))); @@ -519,13 +525,13 @@ impl Guild { /// /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [Manage Guild]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_GUILD - pub fn edit<F>(&mut self, f: F) -> Result<()> + pub fn edit<F>(&mut self, context: &Context, f: F) -> Result<()> where F: FnOnce(&mut EditGuild) -> &mut EditGuild { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_GUILD; - if !self.has_perms(req) { + if !self.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -600,12 +606,12 @@ impl Guild { /// /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [Change Nickname]: ../permissions/struct.Permissions.html#associatedconstant.CHANGE_NICKNAME - pub fn edit_nickname(&self, new_nickname: Option<&str>) -> Result<()> { + pub fn edit_nickname(&self, context: &Context, new_nickname: Option<&str>) -> Result<()> { #[cfg(feature = "cache")] { let req = Permissions::CHANGE_NICKNAME; - if !self.has_perms(req) { + if !self.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -673,14 +679,15 @@ impl Guild { /// [`position`]: struct.Role.html#structfield.position #[cfg(feature = "cache")] #[inline] - pub fn greater_member_hierarchy<T, U>(&self, lhs_id: T, rhs_id: U) + pub fn greater_member_hierarchy<T, U>(&self, cache: &Arc<RwLock<Cache>>, lhs_id: T, rhs_id: U) -> Option<UserId> where T: Into<UserId>, U: Into<UserId> { - self._greater_member_hierarchy(lhs_id.into(), rhs_id.into()) + self._greater_member_hierarchy(&cache, lhs_id.into(), rhs_id.into()) } #[cfg(feature = "cache")] fn _greater_member_hierarchy( &self, + cache: &Arc<RwLock<Cache>>, lhs_id: UserId, rhs_id: UserId, ) -> Option<UserId> { @@ -697,10 +704,10 @@ impl Guild { } let lhs = self.members.get(&lhs_id)? - .highest_role_info() + .highest_role_info(&cache) .unwrap_or((RoleId(0), 0)); let rhs = self.members.get(&rhs_id)? - .highest_role_info() + .highest_role_info(&cache) .unwrap_or((RoleId(0), 0)); // If LHS and RHS both have no top position or have the same role ID, @@ -754,12 +761,12 @@ impl Guild { /// /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [Manage Guild]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_GUILD - pub fn invites(&self) -> Result<Vec<RichInvite>> { + pub fn invites(&self, context: &Context) -> Result<Vec<RichInvite>> { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_GUILD; - if !self.has_perms(req) { + if !self.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -790,7 +797,9 @@ impl Guild { /// [`Guild`]: ../guild/struct.Guild.html /// [`Member`]: struct.Member.html #[inline] - pub fn member<U: Into<UserId>>(&self, user_id: U) -> Result<Member> { self.id.member(user_id) } + pub fn member<U: Into<UserId>>(&self, context: &Context, user_id: U) -> Result<Member> { + self.id.member(&context, user_id) + } /// Gets a list of the guild's members. /// @@ -1339,12 +1348,12 @@ impl Guild { /// [`GuildPrune`]: struct.GuildPrune.html /// [`Member`]: struct.Member.html /// [Kick Members]: ../permissions/struct.Permissions.html#associatedconstant.KICK_MEMBERS - pub fn prune_count(&self, days: u16) -> Result<GuildPrune> { + pub fn prune_count(&self, context: &Context, days: u16) -> Result<GuildPrune> { #[cfg(feature = "cache")] { let req = Permissions::KICK_MEMBERS; - if !self.has_perms(req) { + if !self.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -1374,7 +1383,7 @@ impl Guild { /// [`utils::shard_id`]: ../../utils/fn.shard_id.html #[cfg(all(feature = "cache", feature = "utils"))] #[inline] - pub fn shard_id(&self) -> u64 { self.id.shard_id() } + pub fn shard_id(&self, cache: &Arc<RwLock<Cache>>) -> u64 { self.id.shard_id(&cache) } /// Returns the Id of the shard associated with the guild. /// @@ -1432,12 +1441,12 @@ impl Guild { /// [`GuildPrune`]: struct.GuildPrune.html /// [`Member`]: struct.Member.html /// [Kick Members]: ../permissions/struct.Permissions.html#associatedconstant.KICK_MEMBERS - pub fn start_prune(&self, days: u16) -> Result<GuildPrune> { + pub fn start_prune(&self, context: &Context, days: u16) -> Result<GuildPrune> { #[cfg(feature = "cache")] { let req = Permissions::KICK_MEMBERS; - if !self.has_perms(req) { + if !self.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -1457,12 +1466,12 @@ impl Guild { /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [`User`]: ../user/struct.User.html /// [Ban Members]: ../permissions/struct.Permissions.html#associatedconstant.BAN_MEMBERS - pub fn unban<U: Into<UserId>>(&self, user_id: U) -> Result<()> { + pub fn unban<U: Into<UserId>>(&self, context: &Context, user_id: U) -> Result<()> { #[cfg(feature = "cache")] { let req = Permissions::BAN_MEMBERS; - if !self.has_perms(req) { + if !self.has_perms(&context.cache, req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -1503,11 +1512,9 @@ impl Guild { /// /// struct Handler; /// - /// use serenity::CACHE; - /// /// impl EventHandler for Handler { - /// fn message(&self, _: Context, msg: Message) { - /// if let Some(arc) = msg.guild_id.unwrap().to_guild_cached() { + /// fn message(&self, ctx: Context, msg: Message) { + /// if let Some(arc) = msg.guild_id.unwrap().to_guild_cached(&ctx.cache) { /// if let Some(role) = arc.read().role_by_name("role_name") { /// println!("{:?}", role); /// } diff --git a/src/model/guild/partial_guild.rs b/src/model/guild/partial_guild.rs index 6276db2..8b1be58 100644 --- a/src/model/guild/partial_guild.rs +++ b/src/model/guild/partial_guild.rs @@ -1,6 +1,8 @@ -use crate::model::prelude::*; +use crate::{model::prelude::*}; use super::super::utils::{deserialize_emojis, deserialize_roles}; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(feature = "model")] use crate::builder::{EditGuild, EditMember, EditRole}; @@ -333,7 +335,9 @@ impl PartialGuild { /// /// [`Guild`]: struct.Guild.html /// [`Member`]: struct.Member.html - pub fn member<U: Into<UserId>>(&self, user_id: U) -> Result<Member> { self.id.member(user_id) } + pub fn member<U: Into<UserId>>(&self, context: &Context, user_id: U) -> Result<Member> { + self.id.member(&context, user_id) + } /// Gets a list of the guild's members. /// @@ -380,7 +384,7 @@ impl PartialGuild { /// [`utils::shard_id`]: ../../utils/fn.shard_id.html #[cfg(all(feature = "cache", feature = "utils"))] #[inline] - pub fn shard_id(&self) -> u64 { self.id.shard_id() } + pub fn shard_id(&self, context: &Context) -> u64 { self.id.shard_id(&context.cache) } /// Returns the Id of the shard associated with the guild. /// @@ -465,8 +469,6 @@ impl PartialGuild { /// /// struct Handler; /// - /// use serenity::CACHE; - /// /// impl EventHandler for Handler { /// fn message(&self, _: Context, msg: Message) { /// let guild = msg.guild_id.unwrap().to_partial_guild().unwrap(); diff --git a/src/model/guild/role.rs b/src/model/guild/role.rs index b68803b..404cfcf 100644 --- a/src/model/guild/role.rs +++ b/src/model/guild/role.rs @@ -6,10 +6,10 @@ use crate::builder::EditRole; #[cfg(all(feature = "cache", feature = "model"))] use crate::internal::prelude::*; #[cfg(all(feature = "cache", feature = "model"))] -use crate::{CACHE, Cache, http}; +use crate::{cache::Cache, http}; #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] -use std::str::FromStr; +use crate::cache::FromStrAndCache; #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] use crate::model::misc::RoleParseError; #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] @@ -75,7 +75,9 @@ impl Role { /// [Manage Roles]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_ROLES #[cfg(feature = "cache")] #[inline] - pub fn delete(&self) -> Result<()> { http::delete_role(self.find_guild()?.0, self.id.0) } + pub fn delete(&self, cache: &Arc<RwLock<Cache>>) -> Result<()> { + http::delete_role(self.find_guild(&cache)?.0, self.id.0) + } /// Edits a [`Role`], optionally setting its new fields. /// @@ -85,9 +87,9 @@ impl Role { /// /// Make a role hoisted: /// - /// ```rust,no_run + /// ```rust,ignore /// # use serenity::model::id::RoleId; - /// # let role = RoleId(7).to_role_cached().unwrap(); + /// # let role = RoleId(7).to_role_cached(&cache).unwrap(); /// // assuming a `role` has already been bound // /// role.edit(|mut r| { @@ -100,8 +102,8 @@ impl Role { /// [`Role`]: struct.Role.html /// [Manage Roles]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_ROLES #[cfg(all(feature = "builder", feature = "cache"))] - pub fn edit<F: FnOnce(EditRole) -> EditRole>(&self, f: F) -> Result<Role> { - self.find_guild() + pub fn edit<F: FnOnce(EditRole) -> EditRole>(&self, cache: &Arc<RwLock<Cache>>, f: F) -> Result<Role> { + self.find_guild(&cache) .and_then(|guild_id| guild_id.edit_role(self.id, f)) } @@ -114,8 +116,8 @@ impl Role { /// /// [`ModelError::GuildNotFound`]: ../error/enum.Error.html#variant.GuildNotFound #[cfg(feature = "cache")] - pub fn find_guild(&self) -> Result<GuildId> { - for guild in CACHE.read().guilds.values() { + pub fn find_guild(&self, cache: &Arc<RwLock<Cache>>) -> Result<GuildId> { + for guild in cache.read().guilds.values() { let guild = guild.read(); if guild.roles.contains_key(&RoleId(self.id.0)) { @@ -178,12 +180,12 @@ impl RoleId { /// /// [`Role`]: ../guild/struct.Role.html #[cfg(feature = "cache")] - pub fn to_role_cached(self) -> Option<Role> { - self._to_role_cached(&CACHE) + pub fn to_role_cached(self, cache: &Arc<RwLock<Cache>>) -> Option<Role> { + self._to_role_cached(&cache) } #[cfg(feature = "cache")] - pub(crate) fn _to_role_cached(self, cache: &RwLock<Cache>) -> Option<Role> { + pub(crate) fn _to_role_cached(self, cache: &Arc<RwLock<Cache>>) -> Option<Role> { for guild in cache.read().guilds.values() { let guild = guild.read(); @@ -211,12 +213,12 @@ impl<'a> From<&'a Role> for RoleId { } #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] -impl FromStr for Role { +impl FromStrAndCache for Role { type Err = RoleParseError; - fn from_str(s: &str) -> StdResult<Self, Self::Err> { + fn from_str(cache: &Arc<RwLock<Cache>>, s: &str) -> StdResult<Self, Self::Err> { match parse_role(s) { - Some(x) => match RoleId(x).to_role_cached() { + Some(x) => match RoleId(x).to_role_cached(&cache) { Some(role) => Ok(role), _ => Err(RoleParseError::NotPresentInCache), }, diff --git a/src/model/invite.rs b/src/model/invite.rs index 74a46dc..a6f0479 100644 --- a/src/model/invite.rs +++ b/src/model/invite.rs @@ -3,6 +3,8 @@ use chrono::{DateTime, FixedOffset}; use super::prelude::*; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(feature = "model")] use crate::builder::CreateInvite; #[cfg(feature = "model")] @@ -11,6 +13,12 @@ use crate::internal::prelude::*; use super::{Permissions, utils as model_utils}; #[cfg(feature = "model")] use crate::{http, utils}; +#[cfg(feature = "cache")] +use crate::cache::Cache; +#[cfg(feature = "cache")] +use parking_lot::RwLock; +#[cfg(feature = "cache")] +use std::sync::Arc; /// Information about an invite code. /// @@ -70,18 +78,18 @@ impl Invite { /// [`GuildChannel`]: ../channel/struct.GuildChannel.html /// [Create Invite]: ../permissions/struct.Permissions.html#associatedconstant.CREATE_INVITE /// [permission]: ../permissions/index.html - pub fn create<C, F>(channel_id: C, f: F) -> Result<RichInvite> + pub fn create<C, F>(context: &Context, channel_id: C, f: F) -> Result<RichInvite> where C: Into<ChannelId>, F: FnOnce(CreateInvite) -> CreateInvite { - Self::_create(channel_id.into(), f) + Self::_create(&context, channel_id.into(), f) } - fn _create<F>(channel_id: ChannelId, f: F) -> Result<RichInvite> + fn _create<F>(context: &Context, channel_id: ChannelId, f: F) -> Result<RichInvite> where F: FnOnce(CreateInvite) -> CreateInvite { #[cfg(feature = "cache")] { let req = Permissions::CREATE_INVITE; - if !model_utils::user_has_perms(channel_id, req)? { + if !model_utils::user_has_perms(&context.cache, channel_id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -103,12 +111,12 @@ impl Invite { /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions /// [Manage Guild]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_GUILD /// [permission]: ../permissions/index.html - pub fn delete(&self) -> Result<Invite> { + pub fn delete(&self, context: &Context) -> Result<Invite> { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_GUILD; - if !model_utils::user_has_perms(self.channel.id, req)? { + if !model_utils::user_has_perms(&context.cache, self.channel.id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -195,7 +203,7 @@ impl InviteGuild { /// [`utils::shard_id`]: ../../utils/fn.shard_id.html #[cfg(all(feature = "cache", feature = "utils"))] #[inline] - pub fn shard_id(&self) -> u64 { self.id.shard_id() } + pub fn shard_id(&self, cache: &Arc<RwLock<Cache>>) -> u64 { self.id.shard_id(&cache) } /// Returns the Id of the shard associated with the guild. /// @@ -288,12 +296,12 @@ impl RichInvite { /// [`http::delete_invite`]: ../../http/fn.delete_invite.html /// [Manage Guild]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_GUILD.html /// [permission]: ../permissions/index.html - pub fn delete(&self) -> Result<Invite> { + pub fn delete(&self, context: &Context) -> Result<Invite> { #[cfg(feature = "cache")] { let req = Permissions::MANAGE_GUILD; - if !model_utils::user_has_perms(self.channel.id, req)? { + if !model_utils::user_has_perms(&context.cache, self.channel.id, req)? { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } diff --git a/src/model/misc.rs b/src/model/misc.rs index e2adbcc..5726af6 100644 --- a/src/model/misc.rs +++ b/src/model/misc.rs @@ -112,20 +112,6 @@ impl StdError for UserParseError { } } -#[cfg(all(feature = "model", feature = "utils"))] -impl FromStr for User { - type Err = UserParseError; - - fn from_str(s: &str) -> StdResult<Self, Self::Err> { - match utils::parse_username(s) { - Some(x) => UserId(x as u64) - .to_user() - .map_err(|e| UserParseError::Rest(Box::new(e))), - _ => Err(UserParseError::InvalidUsername), - } - } -} - macro_rules! impl_from_str { (id: $($id:tt, $err:ident;)*) => { $( diff --git a/src/model/user.rs b/src/model/user.rs index 80bf40e..923d4d1 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -4,11 +4,10 @@ use serde_json; use std::fmt; use super::utils::deserialize_u16; use super::prelude::*; -use crate::internal::prelude::*; -use crate::model::misc::Mentionable; +use crate::{internal::prelude::*, model::misc::Mentionable}; -#[cfg(all(feature = "cache", feature = "model"))] -use crate::CACHE; +#[cfg(feature = "client")] +use crate::client::Context; #[cfg(feature = "model")] use crate::builder::{CreateMessage, EditProfile}; #[cfg(feature = "model")] @@ -22,6 +21,8 @@ use std::fmt::Write; #[cfg(feature = "model")] use std::mem; #[cfg(all(feature = "cache", feature = "model"))] +use crate::cache::Cache; +#[cfg(all(feature = "cache", feature = "model"))] use std::sync::Arc; #[cfg(feature = "model")] use crate::utils::{self, VecMap}; @@ -50,10 +51,15 @@ impl CurrentUser { /// Print out the current user's avatar url if one is set: /// /// ```rust,no_run - /// # use serenity::CACHE; + /// # extern crate parking_lot; + /// # extern crate serenity; /// # - /// # let cache = CACHE.read(); + /// # use serenity::{cache::Cache, model::prelude::*, prelude::*}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; /// # + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let cache = cache.read(); /// // assuming the cache has been unlocked /// let user = &cache.user; /// @@ -82,11 +88,9 @@ impl CurrentUser { /// Change the avatar: /// /// ```rust,ignore - /// use serenity::CACHE; - /// /// let avatar = serenity::utils::read_image("./avatar.png").unwrap(); /// - /// CACHE.write().user.edit(|p| p.avatar(Some(&avatar))); + /// context.cache.write().user.edit(|p| p.avatar(Some(&avatar))); /// ``` /// /// [`EditProfile`]: ../../builder/struct.EditProfile.html @@ -131,10 +135,15 @@ impl CurrentUser { /// Print out the names of all guilds the current user is in: /// /// ```rust,no_run - /// # use serenity::CACHE; + /// # extern crate parking_lot; + /// # extern crate serenity; /// # - /// # let cache = CACHE.read(); + /// # use serenity::{cache::Cache, model::prelude::*, prelude::*}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; /// # + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let cache = cache.read(); /// // assuming the cache has been unlocked /// let user = &cache.user; /// @@ -159,9 +168,15 @@ impl CurrentUser { /// Get the invite url with no permissions set: /// /// ```rust,no_run - /// # use serenity::CACHE; + /// # extern crate parking_lot; + /// # extern crate serenity; + /// # + /// # use serenity::{cache::Cache, model::prelude::*, prelude::*}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; /// # - /// # let mut cache = CACHE.write(); + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let mut cache = cache.write(); /// /// use serenity::model::Permissions; /// @@ -182,10 +197,15 @@ impl CurrentUser { /// Get the invite url with some basic permissions set: /// /// ```rust,no_run - /// # use serenity::CACHE; + /// # extern crate parking_lot; + /// # extern crate serenity; /// # - /// # let mut cache = CACHE.write(); - /// + /// # use serenity::{cache::Cache, model::prelude::*, prelude::*}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; + /// # + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let mut cache = cache.write(); /// use serenity::model::Permissions; /// /// // assuming the cache has been unlocked @@ -238,10 +258,15 @@ impl CurrentUser { /// Print out the current user's static avatar url if one is set: /// /// ```rust,no_run - /// # use serenity::CACHE; + /// # extern crate parking_lot; + /// # extern crate serenity; /// # - /// # let cache = CACHE.read(); + /// # use serenity::{cache::Cache, model::prelude::*, prelude::*}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; /// # + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let cache = cache.read(); /// // assuming the cache has been unlocked /// let user = &cache.user; /// @@ -262,10 +287,15 @@ impl CurrentUser { /// Print out the current user's distinct identifier (e.g., Username#1234): /// /// ```rust,no_run - /// # use serenity::CACHE; + /// # extern crate parking_lot; + /// # extern crate serenity; /// # - /// # let cache = CACHE.read(); + /// # use serenity::{cache::Cache, model::prelude::*, prelude::*}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; /// # + /// # let cache = Arc::new(RwLock::new(Cache::default())); + /// # let cache = cache.read(); /// // assuming the cache has been unlocked /// println!("The current user's distinct identifier is {}", cache.user.tag()); /// ``` @@ -415,14 +445,13 @@ impl User { /// # use serenity::model::prelude::*; /// # /// use serenity::model::Permissions; - /// use serenity::CACHE; /// /// struct Handler; /// /// impl EventHandler for Handler { - /// fn message(&self, _: Context, msg: Message) { + /// fn message(&self, ctx: Context, msg: Message) { /// if msg.content == "~help" { - /// let cache = CACHE.read(); + /// let cache = ctx.cache.read(); /// /// let url = match cache.user.invite_url(Permissions::empty()) { /// Ok(v) => v, @@ -438,18 +467,18 @@ impl User { /// url, /// ); /// - /// let dm = msg.author.direct_message(|m| { + /// let dm = msg.author.direct_message(&ctx, |m| { /// m.content(&help) /// }); /// /// match dm { /// Ok(_) => { - /// let _ = msg.react('👌'); + /// let _ = msg.react(&ctx, '👌'); /// }, /// Err(why) => { /// println!("Err sending help: {:?}", why); /// - /// let _ = msg.reply("There was an error DMing you help."); + /// let _ = msg.reply(&ctx, "There was an error DMing you help."); /// }, /// }; /// } @@ -483,7 +512,7 @@ impl User { // (AKA: Clippy is wrong and so we have to mark as allowing this lint.) #[allow(clippy::let_and_return)] #[cfg(feature = "builder")] - pub fn direct_message<F>(&self, f: F) -> Result<Message> + pub fn direct_message<F>(&self, context: &Context, f: F) -> Result<Message> where for <'b> F: FnOnce(&'b mut CreateMessage<'b>) -> &'b mut CreateMessage<'b> { if self.bot { return Err(Error::Model(ModelError::MessagingBot)); @@ -492,7 +521,7 @@ impl User { let private_channel_id = feature_cache! { { let finding = { - let cache = CACHE.read(); + let cache = context.cache.read(); let finding = cache.private_channels .values() @@ -545,9 +574,9 @@ impl User { /// [direct_message]: #method.direct_message #[cfg(feature = "builder")] #[inline] - pub fn dm<F>(&self, f: F) -> Result<Message> + pub fn dm<F>(&self, context: &Context, f: F) -> Result<Message> where for <'b> F: FnOnce(&'b mut CreateMessage<'b>) -> &'b mut CreateMessage<'b> { - self.direct_message(f) + self.direct_message(&context, f) } /// Retrieves the URL to the user's avatar, falling back to the default @@ -585,17 +614,17 @@ impl User { /// [`Role`]: ../guild/struct.Role.html /// [`Cache`]: ../../cache/struct.Cache.html // no-cache would warn on guild_id. - pub fn has_role<G, R>(&self, guild: G, role: R) -> bool + pub fn has_role<G, R>(&self, context: &Context, guild: G, role: R) -> bool where G: Into<GuildContainer>, R: Into<RoleId> { - self._has_role(guild.into(), role.into()) + self._has_role(&context, guild.into(), role.into()) } - fn _has_role(&self, guild: GuildContainer, role: RoleId) -> bool { + fn _has_role(&self, context: &Context, guild: GuildContainer, role: RoleId) -> bool { match guild { GuildContainer::Guild(guild) => guild.roles.contains_key(&role), GuildContainer::Id(_guild_id) => { feature_cache! {{ - CACHE.read() + context.cache.read() .guilds .get(&_guild_id) .map(|g| { @@ -622,9 +651,12 @@ impl User { /// out-of-sync: /// /// ```rust,no_run - /// # use serenity::prelude::*; - /// # use serenity::model::prelude::*; + /// # extern crate parking_lot; + /// # extern crate serenity; /// # + /// # use serenity::{cache::Cache, model::prelude::*, prelude::*}; + /// # use parking_lot::RwLock; + /// # use std::sync::Arc; /// struct Handler; /// /// impl EventHandler for Handler { @@ -635,38 +667,42 @@ impl User { /// /// let mut client = Client::new("token", Handler).unwrap(); /// # - /// use serenity::model::id::UserId; - /// use serenity::CACHE; + /// use serenity::{command, model::id::UserId}; /// use std::thread; /// use std::time::Duration; /// - /// let special_users = vec![UserId(114941315417899012), UserId(87600987040120832)]; - /// /// // start a new thread to periodically refresh the special users' data /// // every 12 hours + /// # command!(example(context) { + /// # let context = context.clone(); + /// /// let handle = thread::spawn(move || { + /// let special_users = vec![UserId(114941315417899012), UserId(87600987040120832)]; + /// # let cache = Arc::new(RwLock::new(Cache::default())); /// // 12 hours in seconds /// let duration = Duration::from_secs(43200); /// /// loop { /// thread::sleep(duration); /// - /// let cache = CACHE.read(); + /// let cache = cache.read(); /// /// for id in &special_users { + /// /// if let Some(user) = cache.user(*id) { - /// if let Err(why) = user.write().refresh() { + /// + /// if let Err(why) = user.write().refresh(&context) { /// println!("Error refreshing {}: {:?}", id, why); /// } /// } /// } /// } /// }); - /// + /// # }); /// println!("{:?}", client.start()); /// ``` - pub fn refresh(&mut self) -> Result<()> { - self.id.to_user().map(|replacement| { + pub fn refresh(&mut self, context: &Context) -> Result<()> { + self.id.to_user(&context).map(|replacement| { mem::replace(self, replacement); () @@ -722,15 +758,15 @@ impl User { /// /// If none is used, it returns `None`. #[inline] - pub fn nick_in<G>(&self, guild_id: G) -> Option<String> + pub fn nick_in<G>(&self, context: &Context, guild_id: G) -> Option<String> where G: Into<GuildId> { - self._nick_in(guild_id.into()) + self._nick_in(&context, guild_id.into()) } - fn _nick_in(&self, guild_id: GuildId) -> Option<String> { + fn _nick_in(&self, context: &Context, guild_id: GuildId) -> Option<String> { #[cfg(feature = "cache")] { - guild_id.to_guild_cached().and_then(|guild| { + guild_id.to_guild_cached(&context.cache).and_then(|guild| { guild.read().members.get(&self.id).and_then(|member| member.nick.clone()) }) } @@ -769,7 +805,7 @@ impl UserId { /// [`User`]: ../user/struct.User.html #[cfg(feature = "cache")] #[inline] - pub fn to_user_cached(self) -> Option<Arc<RwLock<User>>> { CACHE.read().user(self) } + pub fn to_user_cached(self, cache: &Arc<RwLock<Cache>>) -> Option<Arc<RwLock<User>>> { cache.read().user(self) } /// First attempts to find a [`User`] by its Id in the cache, /// upon failure requests it via the REST API. @@ -779,10 +815,10 @@ impl UserId { /// /// [`User`]: ../user/struct.User.html #[inline] - pub fn to_user(self) -> Result<User> { + pub fn to_user(self, context: &Context) -> Result<User> { #[cfg(feature = "cache")] { - if let Some(user) = CACHE.read().user(self) { + if let Some(user) = context.cache.read().user(self) { return Ok(user.read().clone()); } } diff --git a/src/model/utils.rs b/src/model/utils.rs index 2399db3..9cb9571 100644 --- a/src/model/utils.rs +++ b/src/model/utils.rs @@ -14,7 +14,7 @@ use crate::internal::prelude::*; #[cfg(all(feature = "cache", feature = "model"))] use super::permissions::Permissions; #[cfg(all(feature = "cache", feature = "model"))] -use crate::CACHE; +use crate::cache::Cache; pub fn default_true() -> bool { true @@ -206,8 +206,8 @@ pub fn serialize_gen_locked_map<K: Eq + Hash, S: Serializer, V: Serialize>( } #[cfg(all(feature = "cache", feature = "model"))] -pub fn user_has_perms(channel_id: ChannelId, mut permissions: Permissions) -> Result<bool> { - let cache = CACHE.read(); +pub fn user_has_perms(cache: &Arc<RwLock<Cache>>, channel_id: ChannelId, mut permissions: Permissions) -> Result<bool> { + let cache = cache.read(); let current_user = &cache.user; let channel = match cache.channel(channel_id) { |