From 292cedaa3462f7532efda98722354afa8e213b6a Mon Sep 17 00:00:00 2001 From: acdenisSK Date: Tue, 24 Oct 2017 18:05:25 +0200 Subject: Fall back to `str::parse` if `parse_username` fails --- src/model/misc.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/model/misc.rs b/src/model/misc.rs index af49a76..625e202 100644 --- a/src/model/misc.rs +++ b/src/model/misc.rs @@ -125,9 +125,10 @@ impl FromStr for UserId { type Err = UserIdParseError; fn from_str(s: &str) -> StdResult { - utils::parse_username(s) - .ok_or_else(|| UserIdParseError::InvalidFormat) - .map(UserId) + Ok(match utils::parse_username(s) { + Some(id) => UserId(id), + None => s.parse::().map(UserId).map_err(|_| UserIdParseError::InvalidFormat)?, + }) } } -- cgit v1.2.3 From e694766bb6c93d5f6a75ad9871cfdefbd0309a17 Mon Sep 17 00:00:00 2001 From: Uninteresting Account Date: Sun, 29 Oct 2017 18:27:38 +1000 Subject: Fix #206 (#207) --- src/framework/standard/command.rs | 37 +++++++++++++++++++++++++++---------- src/framework/standard/mod.rs | 2 +- 2 files changed, 28 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/framework/standard/command.rs b/src/framework/standard/command.rs index 6330810..b53ed90 100644 --- a/src/framework/standard/command.rs +++ b/src/framework/standard/command.rs @@ -131,6 +131,7 @@ pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Opti if let Some(mention_end) = find_mention_end(&msg.content, conf) { positions.push(mention_end); + return Some(positions); } else if let Some(ref func) = conf.dynamic_prefix { if let Some(x) = func(ctx, msg) { if msg.content.starts_with(&x) { @@ -155,22 +156,18 @@ pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Opti return None; } - if conf.allow_whitespace { - let pos = *unsafe { positions.get_unchecked(0) }; + let pos = *unsafe { positions.get_unchecked(0) }; - positions.insert(0, pos + 1); + if conf.allow_whitespace { + positions.insert(0, find_end_of_prefix_with_whitespace(&msg.content, pos).unwrap_or(pos)); + } else if find_end_of_prefix_with_whitespace(&msg.content, pos).is_some() { + return None; } Some(positions) } else if conf.on_mention.is_some() { find_mention_end(&msg.content, conf).map(|mention_end| { - let mut positions = vec![mention_end]; - - if conf.allow_whitespace { - positions.insert(0, mention_end + 1); - } - - positions + vec![mention_end] // This can simply be returned without trying to find the end whitespaces as trim will remove it later }) } else { None @@ -185,3 +182,23 @@ fn find_mention_end(content: &str, conf: &Configuration) -> Option { .map(|m| m.len()) }) } + +// Finds the end of the first continuous block of whitespace after the prefix +fn find_end_of_prefix_with_whitespace(content: &str, position: usize) -> Option { + let mut ws_split = content.split_whitespace(); + if let Some(cmd) = ws_split.nth(1) { + if let Some(index_of_cmd) = content.find(cmd) { + if index_of_cmd > position && index_of_cmd <= content.len() { + let slice = unsafe { content.slice_unchecked(position, index_of_cmd) }.as_bytes(); + for byte in slice.iter() { + // 0x20 is ASCII for space + if *byte != 0x20u8 { + return None; + } + } + return Some(index_of_cmd); + } + } + } + None +} diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs index 1a7a5ee..f4c98e8 100644 --- a/src/framework/standard/mod.rs +++ b/src/framework/standard/mod.rs @@ -860,7 +860,7 @@ impl Framework for StandardFramework { 'outer: for position in positions { let mut built = String::new(); let round = message.content.chars().skip(position).collect::(); - let round = round.trim().split_whitespace().collect::>(); + let round = round.trim().split_whitespace().collect::>(); // Call to `trim` causes the related bug under the main bug #206 - where the whitespace settings are ignored. The fix is implemented as an additional check inside command::positions for i in 0..self.configuration.depth { if i != 0 { -- cgit v1.2.3 From 361658510f3e2eb9aefbe66232b9b1f1a1ebb80f Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Sun, 29 Oct 2017 11:52:54 -0700 Subject: Fix shard shutdown via Context This fixes the shard shutdown via the Context. This works by setting a "shutdown" field on the Shard struct as being true, indicating that the Shard has shutdown. The Shard Runner detects this and requests a shutdown from the Shard Manager. The ideal solution here would be to add a "Shutdown" variant to serenity::gateway::ConnectionStage, but that would be a breaking change, so we instead need to opt for adding a new struct to gateway::Shard. The Shard Manager has also been updated to only attempt the shutdown of a shard if it doesn't already know for certain that it shut itself down, which avoids an error logged saying that there was an error sending a shutdown message to its Shard Runner. When all shards have been shutdown (for most bots, this will only be one), the Shard Manager will end and the Client will stop its operations, returning thread control to the user. --- src/client/bridge/gateway/shard_manager.rs | 14 +++++++++----- src/client/bridge/gateway/shard_runner.rs | 19 +++++++++++++++++-- src/gateway/mod.rs | 2 +- src/gateway/shard.rs | 19 +++++++++++++++++++ 4 files changed, 46 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/bridge/gateway/shard_manager.rs b/src/client/bridge/gateway/shard_manager.rs index 98ada1e..dfd4a16 100644 --- a/src/client/bridge/gateway/shard_manager.rs +++ b/src/client/bridge/gateway/shard_manager.rs @@ -174,13 +174,17 @@ impl ShardManager { } fn shutdown(&mut self, shard_id: ShardId) { - info!("Shutting down shard {}", shard_id); - if let Some(runner) = self.runners.lock().get(&shard_id) { - let msg = ShardManagerMessage::Shutdown(shard_id); + let is_shutdown = runner.shard.lock().is_shutdown(); + + if !is_shutdown { + info!("Shutting down shard {}", shard_id); + + let msg = ShardManagerMessage::Shutdown(shard_id); - if let Err(why) = runner.runner_tx.send(msg) { - warn!("Failed to cleanly shutdown shard {}: {:?}", shard_id, why); + if let Err(why) = runner.runner_tx.send(msg) { + warn!("Failed to cleanly shutdown shard {}: {:?}", shard_id, why); + } } } diff --git a/src/client/bridge/gateway/shard_runner.rs b/src/client/bridge/gateway/shard_runner.rs index 7ee18c3..aa0e064 100644 --- a/src/client/bridge/gateway/shard_runner.rs +++ b/src/client/bridge/gateway/shard_runner.rs @@ -140,8 +140,16 @@ impl ShardRunner { }} } - if !successful && !self.shard.lock().stage().is_connecting() { - return self.request_restart(); + { + let shard = self.shard.lock(); + + if !successful && !shard.stage().is_connecting() { + return self.request_restart(); + } + + if shard.is_shutdown() { + return self.request_shutdown(); + } } } } @@ -219,4 +227,11 @@ impl ShardRunner { Ok(()) } + + fn request_shutdown(&self) -> Result<()> { + debug!("[ShardRunner {:?}] Requesting shutdown", self.shard_info); + let _ = self.manager_tx.send(ShardManagerMessage::ShutdownAll); + + Ok(()) + } } diff --git a/src/gateway/mod.rs b/src/gateway/mod.rs index b593f5c..ed54bca 100644 --- a/src/gateway/mod.rs +++ b/src/gateway/mod.rs @@ -132,7 +132,7 @@ impl ConnectionStage { match *self { Connecting | Handshake | Identifying | Resuming => true, - _ => false, + Connected | Disconnected => false, } } } diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs index 3a8209d..e5fe65d 100644 --- a/src/gateway/shard.rs +++ b/src/gateway/shard.rs @@ -89,6 +89,8 @@ pub struct Shard { seq: u64, session_id: Option, shard_info: [u64; 2], + /// Whether the shard has permanently shutdown. + shutdown: bool, stage: ConnectionStage, token: Arc>, ws_url: Arc>, @@ -144,6 +146,7 @@ impl Shard { let user = http::get_current_user()?; Shard { + shutdown: false, client, current_presence, heartbeat_instants, @@ -160,6 +163,7 @@ impl Shard { } } else { Shard { + shutdown: false, client, current_presence, heartbeat_instants, @@ -176,6 +180,18 @@ impl Shard { }) } + /// Whether the shard has permanently shutdown. + /// + /// This should normally happen due to manual calling of [`shutdown`] or + /// [`shutdown_clean`]. + /// + /// [`shutdown`]: #method.shutdown + /// [`shutdown_clean`]: #method.shutdown_clean + #[inline] + pub fn is_shutdown(&self) -> bool { + self.shutdown + } + /// Retrieves a copy of the current shard information. /// /// The first element is the _current_ shard - 0-indexed - while the second @@ -604,6 +620,7 @@ impl Shard { stream.flush()?; stream.shutdown(Shutdown::Both)?; + self.shutdown = true; debug!("[Shard {:?}] Cleanly shutdown shard", self.shard_info); Ok(()) @@ -616,6 +633,8 @@ impl Shard { stream.flush()?; stream.shutdown(Shutdown::Both)?; + self.shutdown = true; + Ok(()) } -- cgit v1.2.3 From c99091d241f240c6b76ac969655a8ec4423aaf80 Mon Sep 17 00:00:00 2001 From: acdenisSK Date: Mon, 30 Oct 2017 12:05:31 +0100 Subject: Add some docs to `BanOptions` --- src/model/guild/member.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index 83cb863..6e04b98 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -16,6 +16,7 @@ use builder::EditMember; #[cfg(all(feature = "cache", feature = "model", feature = "utils"))] use utils::Colour; +/// 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 { fn dmd(&self) -> u8 { 0 } fn reason(&self) -> &str { "" } -- cgit v1.2.3 From 2ba4d03f15d57d9f0fb1cc4d4f4355ebbc483d0a Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Mon, 30 Oct 2017 10:12:22 -0700 Subject: Add Guild::member_permissions Add a method on the Guild for calculating only a member's guild-only permissions, not including the permissions for either the default channel or any specific channel. --- src/model/guild/mod.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'src') diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index aa9fd1d..0a8fe16 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -1004,6 +1004,57 @@ impl Guild { } } + /// Calculate a [`Member`]'s permissions in the guild. + /// + /// [`Member`]: struct.Member.html + pub fn member_permissions(&self, user_id: U) -> Permissions + where U: Into { + let user_id = user_id.into(); + + if user_id == self.owner_id { + return Permissions::all(); + } + + let everyone = match self.roles.get(&RoleId(self.id.0)) { + Some(everyone) => everyone, + None => { + error!( + "(╯°□°)╯︵ ┻━┻ @everyone role ({}) missing in '{}'", + self.id, + self.name, + ); + + return Permissions::empty(); + }, + }; + + let member = match self.members.get(&user_id) { + Some(member) => member, + None => return everyone.permissions, + }; + + let mut permissions = everyone.permissions; + + for role in &member.roles { + if let Some(role) = self.roles.get(&role) { + if role.permissions.contains(Permissions::ADMINISTRATOR) { + return Permissions::all(); + } + + permissions |= role.permissions; + } else { + warn!( + "(╯°□°)╯︵ ┻━┻ {} on {} has non-existent role {:?}", + member.user.read().unwrap().id, + self.id, + role, + ); + } + } + + permissions + } + /// Moves a member to a specific voice channel. /// /// Requires the [Move Members] permission. -- cgit v1.2.3 From 1b7101fe71335c0e18bf855c0703acc23d87e427 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Mon, 30 Oct 2017 10:14:16 -0700 Subject: Guild::has_perms: use Guild::member_permissions Make `Guild`'s internal method `has_perms` go through `Guild::member_permissions` to check permissions, since all method that use it don't need channel-specific permissions. --- src/model/guild/mod.rs | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index 0a8fe16..1ad2b36 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -158,21 +158,13 @@ impl Guild { } #[cfg(feature = "cache")] - fn has_perms(&self, mut permissions: Permissions) -> Result { - let member = match self.members.get(&CACHE.read().unwrap().user.id) { - Some(member) => member, - None => return Err(Error::Model(ModelError::ItemMissing)), - }; - - let default_channel = match self.default_channel() { - Some(dc) => dc, - None => return Err(Error::Model(ModelError::ItemMissing)), - }; + fn has_perms(&self, mut permissions: Permissions) -> bool { + let user_id = CACHE.read().unwrap().user.id; - let perms = self.permissions_for(default_channel.id, member.user.read().unwrap().id); + let perms = self.member_permissions(user_id); permissions.remove(perms); - Ok(permissions.is_empty()) + permissions.is_empty() } /// Ban a [`User`] from the guild. All messages by the @@ -210,7 +202,7 @@ impl Guild { { let req = Permissions::BAN_MEMBERS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -235,7 +227,7 @@ impl Guild { { let req = Permissions::BAN_MEMBERS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -317,7 +309,7 @@ impl Guild { { let req = Permissions::MANAGE_CHANNELS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -388,7 +380,7 @@ impl Guild { { let req = Permissions::MANAGE_ROLES; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -490,7 +482,7 @@ impl Guild { { let req = Permissions::MANAGE_GUILD; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -570,7 +562,7 @@ impl Guild { { let req = Permissions::CHANGE_NICKNAME; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -652,7 +644,7 @@ impl Guild { { let req = Permissions::MANAGE_GUILD; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -1217,7 +1209,7 @@ impl Guild { { let req = Permissions::KICK_MEMBERS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -1300,7 +1292,7 @@ impl Guild { { let req = Permissions::KICK_MEMBERS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -1325,7 +1317,7 @@ impl Guild { { let req = Permissions::BAN_MEMBERS; - if !self.has_perms(req)? { + if !self.has_perms(req) { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } -- cgit v1.2.3 From dcac27168915b4f22745950ec0ef0c0af696774e Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Mon, 30 Oct 2017 10:17:15 -0700 Subject: Rename `Guild::permissions_for`->`permissions_in` Rename `Guild::permissions_for` to `Guild::permissions_in`, deprecating `Guild::permissions_for` which is only an inline method to `permissions_in`. --- src/framework/standard/mod.rs | 2 +- src/model/channel/guild_channel.rs | 2 +- src/model/guild/member.rs | 4 ++-- src/model/guild/mod.rs | 17 ++++++++++++++--- src/model/utils.rs | 2 +- 5 files changed, 19 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs index f4c98e8..9ad68da 100644 --- a/src/framework/standard/mod.rs +++ b/src/framework/standard/mod.rs @@ -972,7 +972,7 @@ pub fn has_correct_permissions(command: &Command, message: &Message) -> bool { if !command.required_permissions.is_empty() { if let Some(guild) = message.guild() { let perms = guild - .with(|g| g.permissions_for(message.channel_id, message.author.id)); + .with(|g| g.permissions_in(message.channel_id, message.author.id)); return perms.contains(command.required_permissions); } diff --git a/src/model/channel/guild_channel.rs b/src/model/channel/guild_channel.rs index d6649b4..b7295fc 100644 --- a/src/model/channel/guild_channel.rs +++ b/src/model/channel/guild_channel.rs @@ -512,7 +512,7 @@ impl GuildChannel { pub fn permissions_for>(&self, user_id: U) -> Result { self.guild() .ok_or_else(|| Error::Model(ModelError::GuildNotFound)) - .map(|g| g.read().unwrap().permissions_for(self.id, user_id)) + .map(|g| g.read().unwrap().permissions_in(self.id, user_id)) } /// Pins a [`Message`] to the channel. diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index 6e04b98..a9de969 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -257,7 +257,7 @@ impl Member { .get(&self.guild_id) .map(|guild| guild.read().unwrap().has_perms(req)); - if let Some(Ok(false)) = has_perms { + if let Some(false) = has_perms { return Err(Error::Model(ModelError::InvalidPermissions(req))); } } @@ -301,7 +301,7 @@ impl Member { Ok( guild - .permissions_for(default_channel.id, self.user.read().unwrap().id), + .permissions_in(default_channel.id, self.user.read().unwrap().id), ) } diff --git a/src/model/guild/mod.rs b/src/model/guild/mod.rs index 1ad2b36..fe9bc6a 100644 --- a/src/model/guild/mod.rs +++ b/src/model/guild/mod.rs @@ -132,7 +132,7 @@ impl Guild { let uid = CACHE.read().unwrap().user.id; for (cid, channel) in &self.channels { - if self.permissions_for(*cid, uid).read_messages() { + if self.permissions_in(*cid, uid).read_messages() { return Some(channel.read().unwrap().clone()); } } @@ -148,7 +148,7 @@ impl Guild { pub fn default_channel_guaranteed(&self) -> Option { for (cid, channel) in &self.channels { for memid in self.members.keys() { - if self.permissions_for(*cid, *memid).read_messages() { + if self.permissions_in(*cid, *memid).read_messages() { return Some(channel.read().unwrap().clone()); } } @@ -1058,10 +1058,21 @@ impl Guild { self.id.move_member(user_id, channel_id) } + /// Alias for [`permissions_in`]. + /// + /// [`permissions_in`]: #method.permissions_in + #[deprecated(since = "0.4.3", + note = "This will serve a different purpose in 0.5")] + #[inline] + pub fn permissions_for(&self, channel_id: C, user_id: U) + -> Permissions where C: Into, U: Into { + self.permissions_in(channel_id, user_id) + } + /// Calculate a [`User`]'s permissions in a given channel in the guild. /// /// [`User`]: struct.User.html - pub fn permissions_for(&self, channel_id: C, user_id: U) -> Permissions + pub fn permissions_in(&self, channel_id: C, user_id: U) -> Permissions where C: Into, U: Into { let user_id = user_id.into(); diff --git a/src/model/utils.rs b/src/model/utils.rs index 719a472..a64156b 100644 --- a/src/model/utils.rs +++ b/src/model/utils.rs @@ -180,7 +180,7 @@ pub fn user_has_perms(channel_id: ChannelId, mut permissions: Permissions) -> Re let perms = guild .read() .unwrap() - .permissions_for(channel_id, current_user.id); + .permissions_in(channel_id, current_user.id); permissions.remove(perms); -- cgit v1.2.3 From bb205d28ea28fd8ac005ce66c90aa6cf2ca85e45 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Mon, 30 Oct 2017 10:17:34 -0700 Subject: Fix extraneous whitespace --- src/framework/standard/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/framework/standard/mod.rs b/src/framework/standard/mod.rs index 9ad68da..a806817 100644 --- a/src/framework/standard/mod.rs +++ b/src/framework/standard/mod.rs @@ -143,7 +143,7 @@ use std::fmt; impl fmt::Debug for DispatchError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::DispatchError::*; - + match *self { CheckFailed(..) => write!(f, "DispatchError::CheckFailed"), CommandDisabled(ref s) => f.debug_tuple("DispatchError::CommandDisabled").field(&s).finish(), -- cgit v1.2.3 From 3be6e2e28b0c3e9baaef19f405c463e3a41fed25 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Mon, 30 Oct 2017 21:07:08 -0700 Subject: Slightly clarify ratelimiting documentation --- src/http/ratelimiting.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/http/ratelimiting.rs b/src/http/ratelimiting.rs index dbaca6b..8008616 100644 --- a/src/http/ratelimiting.rs +++ b/src/http/ratelimiting.rs @@ -339,8 +339,8 @@ pub enum Route { VoiceRegions, /// Route for the `/webhooks/:webhook_id` path. WebhooksId, - /// Route where no ratelimit headers are in place (i.e. user account-only - /// routes). + /// Route where no ratelimit headers are in place (e.g. current application + /// info retrieval). /// /// This is a special case, in that if the route is `None` then pre- and /// post-hooks are not executed. -- cgit v1.2.3 From d3eddc68e07bbc31e2043577cbf48741f0547ed3 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Tue, 31 Oct 2017 08:51:43 -0700 Subject: Make Member::permissions return guild permissions Fixes what is realistically a bug where `Member::permissions` would retrieve the permissions for the Member in the default channel of the guild. This now only returns the guild-level permissions of the member. --- src/model/guild/member.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/model/guild/member.rs b/src/model/guild/member.rs index a9de969..c81e2a3 100644 --- a/src/model/guild/member.rs +++ b/src/model/guild/member.rs @@ -265,7 +265,7 @@ impl Member { self.guild_id.kick(self.user.read().unwrap().id) } - /// Returns the permissions for the member. + /// Returns the guild-level permissions for the member. /// /// # Examples /// @@ -292,17 +292,9 @@ impl Member { None => return Err(From::from(ModelError::GuildNotFound)), }; - let guild = guild.read().unwrap(); + let reader = guild.read().unwrap(); - let default_channel = match guild.default_channel() { - Some(dc) => dc, - None => return Err(From::from(ModelError::ItemMissing)), - }; - - Ok( - guild - .permissions_in(default_channel.id, self.user.read().unwrap().id), - ) + Ok(reader.member_permissions(self.user.read().unwrap().id)) } /// Removes a [`Role`] from the member, editing its roles in-place if the -- cgit v1.2.3 From 800e58f4603ce99ab69569b30cbec756301a6a63 Mon Sep 17 00:00:00 2001 From: Ben Date: Tue, 31 Oct 2017 16:27:53 -0600 Subject: Fix ping bot example (#211) --- src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 471d41b..7e5609a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,12 +33,17 @@ //! #[macro_use] extern crate serenity; //! //! use serenity::client::Client; +//! use serenity::prelude::EventHandler; //! use serenity::framework::standard::StandardFramework; //! use std::env; //! +//! struct Handler; +//! +//! impl EventHandler for Handler {} +//! //! fn main() { //! // Login with a bot token from the environment -//! let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("token")); +//! let mut client = Client::new(&env::var("DISCORD_TOKEN").expect("token"), Handler); //! client.with_framework(StandardFramework::new() //! .configure(|c| c.prefix("~")) // set the bot's prefix to "~" //! .on("ping", ping)); -- cgit v1.2.3 From e219a6a9d6a890b008fc390a909ae504a0c1a329 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Wed, 1 Nov 2017 07:48:24 -0700 Subject: Use consistent token names in examples The names of environment variable tokens in the examples differed, so this makes them all use the same name. --- src/client/mod.rs | 2 +- src/framework/mod.rs | 2 +- src/framework/standard/configuration.rs | 2 +- src/gateway/shard.rs | 2 +- src/model/error.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/mod.rs b/src/client/mod.rs index 0a3c49f..6711287 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -685,7 +685,7 @@ impl Client { /// use serenity::Client; /// use std::env; /// - /// let token = env::var("DISCORD_BOT_TOKEN").unwrap(); + /// let token = env::var("DISCORD_TOKEN").unwrap(); /// let mut client = Client::new(&token, Handler); /// /// let _ = client.start_shard_range([4, 7], 10); diff --git a/src/framework/mod.rs b/src/framework/mod.rs index a5f458d..85ae6f4 100644 --- a/src/framework/mod.rs +++ b/src/framework/mod.rs @@ -36,7 +36,7 @@ //! use serenity::model::Message; //! use std::env; //! -//! let mut client = Client::new(&env::var("DISCORD_BOT_TOKEN").unwrap()); +//! let mut client = Client::new(&env::var("DISCORD_TOKEN").unwrap()); //! //! client.with_framework(|f| f //! .configure(|c| c.prefix("~")) diff --git a/src/framework/standard/configuration.rs b/src/framework/standard/configuration.rs index 8cc25fa..c731d31 100644 --- a/src/framework/standard/configuration.rs +++ b/src/framework/standard/configuration.rs @@ -24,7 +24,7 @@ use model::{GuildId, Message, UserId}; /// use std::env; /// use serenity::framework::StandardFramework; /// -/// let mut client = Client::new(&env::var("DISCORD_BOT_TOKEN").unwrap(), Handler); +/// let mut client = Client::new(&env::var("DISCORD_TOKEN").unwrap(), Handler); /// /// client.with_framework(StandardFramework::new() /// .configure(|c| c.on_mention(true).prefix("~"))); diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs index e5fe65d..f5888af 100644 --- a/src/gateway/shard.rs +++ b/src/gateway/shard.rs @@ -116,7 +116,7 @@ impl Shard { /// use serenity::http; /// use std::env; /// - /// let token = env::var("DISCORD_BOT_TOKEN").expect("Token in environment"); + /// let token = env::var("DISCORD_TOKEN").expect("Token in environment"); /// // retrieve the gateway response, which contains the URL to connect to /// let gateway = http::get_gateway().expect("Valid gateway response").url; /// let shard = Shard::new(&gateway, &token, None) diff --git a/src/model/error.rs b/src/model/error.rs index fa24272..57801da 100644 --- a/src/model/error.rs +++ b/src/model/error.rs @@ -46,7 +46,7 @@ use super::Permissions; /// } /// } /// } -/// let token = env::var("DISCORD_BOT_TOKEN")?; +/// let token = env::var("DISCORD_TOKEN")?; /// let mut client = Client::new(&token, Handler); client.start()?; /// # Ok(()) /// # } -- cgit v1.2.3 From 1d632f72824e7c4d070169ae0b450f1d3594f434 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Wed, 1 Nov 2017 11:12:10 -0700 Subject: Fix no-parking_lot compilation Fixes compilation without the `parking_lot` crate compiled. The prelude re-exposed `parking_lot`'s `Mutex` and `RwLock`, but didn't do so conditionally. --- src/prelude.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/prelude.rs b/src/prelude.rs index 435fb8a..8a361e9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -16,7 +16,6 @@ pub use error::Error as SerenityError; pub use model::Mentionable; -pub use parking_lot::{Mutex, RwLock}; #[cfg(feature = "client")] pub use client::{Client, ClientError as ClientError, Context, EventHandler}; @@ -26,5 +25,7 @@ pub use gateway::GatewayError; pub use http::HttpError; #[cfg(feature = "model")] pub use model::ModelError; +#[cfg(feature = "parking_lot")] +pub use parking_lot::{Mutex, RwLock}; #[cfg(feature = "voice")] pub use voice::VoiceError; -- cgit v1.2.3 From ccbc3b348fe41aaad74c7676f1334be246008cae Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Wed, 1 Nov 2017 12:45:21 -0700 Subject: Fix no-client cache tests There were a few doctests in the cache module that relied on the client module, so instead feature-gate the doctests. --- src/builder/create_embed.rs | 2 +- src/builder/create_invite.rs | 10 +++++----- src/cache/mod.rs | 44 +++++++++++++++++++++++++++++++++----------- src/model/user.rs | 12 ++++++------ 4 files changed, 45 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/builder/create_embed.rs b/src/builder/create_embed.rs index cc5e642..b38984c 100644 --- a/src/builder/create_embed.rs +++ b/src/builder/create_embed.rs @@ -248,7 +248,7 @@ impl CreateEmbed { /// struct Handler; /// impl EventHandler for Handler { /// fn on_guild_member_addition(&self, _: Context, guild_id: GuildId, member: Member) { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// let cache = CACHE.read().unwrap(); /// /// if let Some(guild) = cache.guild(guild_id) { diff --git a/src/builder/create_invite.rs b/src/builder/create_invite.rs index 5f4f0bf..645d401 100644 --- a/src/builder/create_invite.rs +++ b/src/builder/create_invite.rs @@ -19,7 +19,7 @@ use internal::prelude::*; /// /// impl EventHandler for Handler { /// fn on_message(&self, _: Context, msg: Message) { -/// use serenity::client::CACHE; +/// use serenity::CACHE; /// if msg.content == "!createinvite" { /// let channel = match CACHE.read().unwrap().guild_channel(msg.channel_id) { /// Some(channel) => channel, @@ -72,7 +72,7 @@ impl CreateInvite { /// Create an invite with a max age of `3600` seconds, or 1 hour: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # use serenity::model::ChannelId; /// # use std::error::Error; /// # @@ -106,7 +106,7 @@ impl CreateInvite { /// Create an invite with a max use limit of `5`: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # use serenity::model::ChannelId; /// # use std::error::Error; /// # @@ -138,7 +138,7 @@ impl CreateInvite { /// Create an invite which is temporary: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # use serenity::model::ChannelId; /// # use std::error::Error; /// # @@ -170,7 +170,7 @@ impl CreateInvite { /// Create an invite which is unique: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # use serenity::model::ChannelId; /// # use std::error::Error; /// # diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 921e77b..357092f 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -169,7 +169,9 @@ impl Cache { /// # use serenity::prelude::*; /// # use serenity::model::*; /// # - /// use serenity::client::CACHE; + /// # #[cfg(feature = "client")] + /// # fn main() { + /// use serenity::CACHE; /// use std::thread; /// use std::time::Duration; /// @@ -193,6 +195,10 @@ impl Cache { /// } /// /// let mut client = Client::new("token", Handler); client.start().unwrap(); + /// # } + /// # + /// # #[cfg(not(feature = "client"))] + /// # fn main() { } /// ``` /// /// [`Member`]: ../model/struct.Member.html @@ -225,7 +231,7 @@ impl Cache { /// Printing the count of all private channels and groups: /// /// ```rust,no_run - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let amount = CACHE.read().unwrap().all_private_channels().len(); /// @@ -252,10 +258,12 @@ impl Cache { /// Print all of the Ids of guilds in the Cache: /// /// ```rust,no_run + /// # #[cfg(feature = "client")] + /// # fn main() { /// # use serenity::prelude::*; /// # use serenity::model::*; /// # - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// struct Handler; /// impl EventHandler for Handler { @@ -264,6 +272,10 @@ impl Cache { /// } /// } /// let mut client = Client::new("token", Handler); + /// # } + /// # + /// # #[cfg(not(feature = "client"))] + /// # fn main() { } /// ``` /// /// [`Context`]: ../client/struct.Context.html @@ -330,7 +342,7 @@ impl Cache { /// # use std::error::Error; /// # /// # fn try_main() -> Result<(), Box> { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let cache = CACHE.read()?; /// @@ -361,10 +373,12 @@ impl Cache { /// [`Client::on_message`] event dispatch: /// /// ```rust,no_run + /// # #[cfg(feature = "client")] + /// # fn main() { /// # use serenity::prelude::*; /// # use serenity::model::*; /// # - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// struct Handler; /// @@ -387,6 +401,10 @@ impl Cache { /// } /// /// let mut client = Client::new("token", Handler); client.start().unwrap(); + /// # } + /// # + /// # #[cfg(not(feature = "client"))] + /// # fn main() { } /// ``` /// /// [`ChannelId`]: ../model/struct.ChannelId.html @@ -415,7 +433,7 @@ impl Cache { /// # use std::error::Error; /// # /// # fn try_main() -> Result<(), Box> { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let cache = CACHE.read()?; /// @@ -494,18 +512,22 @@ impl Cache { /// /// # Examples /// - /// Retrieve a private channel from the cache and send a message: + /// Retrieve a private channel from the cache and print its recipient's + /// name: /// /// ```rust,no_run /// # use std::error::Error; /// # /// # fn try_main() -> Result<(), Box> { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let cache = CACHE.read()?; /// /// if let Some(channel) = cache.private_channel(7) { - /// channel.read().unwrap().say("Hello there!"); + /// let channel_reader = channel.read().unwrap(); + /// let user_reader = channel_reader.recipient.read().unwrap(); + /// + /// println!("The recipient is {}", user_reader.name); /// } /// # Ok(()) /// # } @@ -537,7 +559,7 @@ impl Cache { /// # use std::error::Error; /// # /// # fn try_main() -> Result<(), Box> { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let cache = CACHE.read()?; /// @@ -574,7 +596,7 @@ impl Cache { /// # use std::error::Error; /// # /// # fn try_main() -> Result<(), Box> { - /// use serenity::client::CACHE; + /// use serenity::CACHE; /// /// let cache = CACHE.read()?; /// diff --git a/src/model/user.rs b/src/model/user.rs index 3d39759..bf725cc 100644 --- a/src/model/user.rs +++ b/src/model/user.rs @@ -44,7 +44,7 @@ impl CurrentUser { /// Print out the current user's avatar url if one is set: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let cache = CACHE.read().unwrap(); /// # @@ -121,7 +121,7 @@ impl CurrentUser { /// Print out the names of all guilds the current user is in: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let cache = CACHE.read().unwrap(); /// # @@ -149,7 +149,7 @@ impl CurrentUser { /// Get the invite url with no permissions set: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let mut cache = CACHE.write().unwrap(); /// @@ -172,7 +172,7 @@ impl CurrentUser { /// Get the invite url with some basic permissions set: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let mut cache = CACHE.write().unwrap(); /// @@ -228,7 +228,7 @@ impl CurrentUser { /// Print out the current user's static avatar url if one is set: /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let cache = CACHE.read().unwrap(); /// # @@ -252,7 +252,7 @@ impl CurrentUser { /// Print out the current user's distinct identifier (e.g., Username#1234): /// /// ```rust,no_run - /// # use serenity::client::CACHE; + /// # use serenity::CACHE; /// # /// # let cache = CACHE.read().unwrap(); /// # -- cgit v1.2.3 From 2c59f87c1408ef633b8749f6688dc42129054a36 Mon Sep 17 00:00:00 2001 From: Zeyla Hellyer Date: Wed, 1 Nov 2017 13:10:16 -0700 Subject: Fix doctests for a variety of feature targets --- src/cache/mod.rs | 6 ++++-- src/client/context.rs | 6 ++++++ src/gateway/shard.rs | 21 +++++++++++++++++++-- src/model/error.rs | 8 ++++---- 4 files changed, 33 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 357092f..a663a79 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -266,12 +266,14 @@ impl Cache { /// use serenity::CACHE; /// /// struct Handler; + /// /// impl EventHandler for Handler { /// fn on_ready(&self, _: Context, _: Ready) { - /// println!("Guilds in the Cache: {:?}", CACHE.read().unwrap().all_guilds()); + /// let guilds = CACHE.read().unwrap().guilds.len(); + /// + /// println!("Guilds in the Cache: {}", guilds); /// } /// } - /// let mut client = Client::new("token", Handler); /// # } /// # /// # #[cfg(not(feature = "client"))] diff --git a/src/client/context.rs b/src/client/context.rs index 2288f28..d0a6fc7 100644 --- a/src/client/context.rs +++ b/src/client/context.rs @@ -263,6 +263,8 @@ impl Context { /// playing: /// /// ```rust,no_run + /// # #[cfg(feature = "model")] + /// # fn main() { /// # use serenity::prelude::*; /// # use serenity::model::*; /// # @@ -282,6 +284,10 @@ impl Context { /// } /// /// let mut client = Client::new("token", Handler); client.start().unwrap(); + /// # } + /// # + /// # #[cfg(not(feature = "model"))] + /// # fn main() { } /// ``` /// /// [`Online`]: ../model/enum.OnlineStatus.html#variant.Online diff --git a/src/gateway/shard.rs b/src/gateway/shard.rs index f5888af..bd60b57 100644 --- a/src/gateway/shard.rs +++ b/src/gateway/shard.rs @@ -235,6 +235,8 @@ impl Shard { /// Setting the current game to playing `"Heroes of the Storm"`: /// /// ```rust,no_run + /// # #[cfg(feature = "model")] + /// # fn main() { /// # use serenity::client::gateway::Shard; /// # use std::sync::{Arc, Mutex}; /// # @@ -245,6 +247,10 @@ impl Shard { /// use serenity::model::Game; /// /// shard.set_game(Some(Game::playing("Heroes of the Storm"))); + /// # } + /// # + /// # #[cfg(not(feature = "model"))] + /// # fn main() { } /// ``` pub fn set_game(&mut self, game: Option) { self.current_presence.0 = game; @@ -299,6 +305,8 @@ impl Shard { /// and not being afk: /// /// ```rust,no_run + /// # #[cfg(feature = "model")] + /// # fn main() { /// # use serenity::client::gateway::Shard; /// # use std::sync::{Arc, Mutex}; /// # @@ -308,8 +316,11 @@ impl Shard { /// # /// use serenity::model::{Game, OnlineStatus}; /// - /// shard.set_presence(Some(Game::playing("Heroes of the Storm")), OnlineStatus::Online, - /// false); + /// shard.set_presence(Some(Game::playing("Heroes of the Storm")), OnlineStatus::Online, false); + /// # } + /// # + /// # #[cfg(not(feature = "model"))] + /// # fn main() { } /// ``` pub fn set_presence(&mut self, game: Option, mut status: OnlineStatus, afk: bool) { if status == OnlineStatus::Offline { @@ -569,6 +580,8 @@ impl Shard { /// message handled through [`Client::on_message`]. /// /// ```rust,no_run + /// # #[cfg(feature = "model")] + /// # fn main() { /// # use serenity::prelude::*; /// # use serenity::model::*; /// struct Handler; @@ -587,6 +600,10 @@ impl Shard { /// } /// } /// let mut client = Client::new("token", Handler); client.start().unwrap(); + /// # } + /// # + /// # #[cfg(not(feature = "model"))] + /// # fn main() { } /// ``` /// /// [`Client`]: ../struct.Client.html diff --git a/src/model/error.rs b/src/model/error.rs index 57801da..454b94b 100644 --- a/src/model/error.rs +++ b/src/model/error.rs @@ -13,10 +13,10 @@ use super::Permissions; /// re-ban all members with an odd discriminator: /// /// ```rust,no_run -/// # #[cfg(feature="client")] +/// # #[cfg(all(feature = "client", feature = "model"))] /// # use std::error::Error; /// # -/// # #[cfg(feature="client")] +/// # #[cfg(all(feature = "client", feature = "model"))] /// # fn try_main() -> Result<(), Box> { /// use serenity::prelude::*; /// use serenity::model::*; @@ -51,12 +51,12 @@ use super::Permissions; /// # Ok(()) /// # } /// # -/// # #[cfg(feature="client")] +/// # #[cfg(all(feature = "client", feature = "model"))] /// # fn main() { /// # try_main().unwrap(); /// # } /// # -/// # #[cfg(not(feature="client"))] +/// # #[cfg(not(all(feature="client", feature = "model")))] /// # fn main() { } /// ``` /// -- cgit v1.2.3