diff options
| author | Austin Hellyer <[email protected]> | 2016-11-12 11:21:12 -0800 |
|---|---|---|
| committer | Austin Hellyer <[email protected]> | 2016-11-12 11:21:12 -0800 |
| commit | e9cdc50f68ad36d78b5fcc1c0dd6463274828eca (patch) | |
| tree | c6b0bd54bae9f18906a47fd85402faea5345a1cd /src | |
| parent | Add delete_message_reactions + register event (diff) | |
| download | serenity-e9cdc50f68ad36d78b5fcc1c0dd6463274828eca.tar.xz serenity-e9cdc50f68ad36d78b5fcc1c0dd6463274828eca.zip | |
Add a check for message content length
Before sending a request to Discord, ensure that a message's content on
non-HTTP functions and methods meets the required length. If it exceeds
the limit, then return a
`Error::Client(ClientError::MessageTooLong(u64))`, containing the number
of unicode code points exceeding the limit.
Note that directly using the HTTP methods does not impose this limit.
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/context.rs | 38 | ||||
| -rw-r--r-- | src/client/mod.rs | 7 | ||||
| -rw-r--r-- | src/constants.rs | 2 | ||||
| -rw-r--r-- | src/model/channel.rs | 89 |
4 files changed, 129 insertions, 7 deletions
diff --git a/src/client/context.rs b/src/client/context.rs index faa23f6..9e584b3 100644 --- a/src/client/context.rs +++ b/src/client/context.rs @@ -813,10 +813,15 @@ impl Context { /// /// # Errors /// + /// Returns a [`ClientError::MessageTooLong`] if the content of the message + /// is over the above limit, containing the number of unicode code points + /// over the limit. + /// /// Returns a [`ClientError::NoChannelId`] when there is no [`ChannelId`] /// directly available. /// - /// [`ChannelId`]: ../../models/struct.ChannelId.html + /// [`ChannelId`]: ../../model/struct.ChannelId.html + /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong /// [`ClientError::NoChannelId`]: ../enum.ClientError.html#NoChannelId /// [`Message`]: ../model/struct.Message.html pub fn say(&self, text: &str) -> Result<Message> { @@ -827,6 +832,20 @@ impl Context { } } + /// Sends a file along with optional message contents. The filename _must_ + /// be specified. + /// + /// Pass an empty string to send no message contents. + /// + /// **Note**: Message contents must be under 2000 unicode code points. + /// + /// # Errors + /// + /// If the content of the message is over the above limit, then a + /// [`ClientError::MessageTooLong`] will be returned, containing the number + /// of unicode code points over the limit. + /// + /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong pub fn send_file<C, R>(&self, channel_id: C, content: &str, @@ -834,6 +853,10 @@ impl Context { filename: &str) -> Result<Message> where C: Into<ChannelId>, R: Read { + if let Some(length_over) = Message::overflow_length(content) { + return Err(Error::Client(ClientError::MessageTooLong(length_over))); + } + http::send_file(channel_id.into().0, content, file, filename) } @@ -842,6 +865,8 @@ impl Context { /// Note that often a nonce is not required and can be omitted in most /// situations. /// + /// **Note**: Message contents must be under 2000 unicode code points. + /// /// # Example /// /// ```rust,ignore @@ -849,9 +874,20 @@ impl Context { /// let _ = context.send_message(message.channel_id, "Hello!", "", false); /// ``` /// + /// # Errors + /// + /// Returns a [`ClientError::MessageTooLong`] if the content of the message + /// is over the above limit, containing the number of unicode code points + /// over the limit. + /// /// [`Channel`]: ../model/enum.Channel.html + /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong pub fn send_message<C>(&self, channel_id: C, content: &str, nonce: &str, tts: bool) -> Result<Message> where C: Into<ChannelId> { + if let Some(length_over) = Message::overflow_length(content) { + return Err(Error::Client(ClientError::MessageTooLong(length_over))); + } + let map = ObjectBuilder::new() .insert("content", content) .insert("nonce", nonce) diff --git a/src/client/mod.rs b/src/client/mod.rs index 4db7a4e..0f0fa7a 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -175,6 +175,13 @@ pub enum ClientError { /// /// [`State`]: ../ext/state/struct.State.html ItemMissing, + /// Indicates that a [`Message`]s content was too long and will not + /// successfully send, as the length is over 2000 codepoints, or 4000 bytes. + /// + /// The number of bytes larger than the limit is provided. + /// + /// [`Message`]: ../model/struct.Message.html + MessageTooLong(u64), /// When attempting to use a [`Context`] helper method which requires a /// contextual [`ChannelId`], but the current context is not appropriate for /// the action. diff --git a/src/constants.rs b/src/constants.rs index 7f71f5b..262dffd 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -3,6 +3,8 @@ use ::prelude_internal::*; /// The gateway version used by the library. The gateway URI is retrieved via /// the REST API. pub const GATEWAY_VERSION: u8 = 6; +/// The maximum unicode code points allowed within a message by Discord. +pub const MESSAGE_CODE_LIMIT: u16 = 2000; /// The [UserAgent] sent along with every request. /// /// [UserAgent]: ../hyper/header/struct.UserAgent.html diff --git a/src/model/channel.rs b/src/model/channel.rs index 989bda8..cd2c099 100644 --- a/src/model/channel.rs +++ b/src/model/channel.rs @@ -18,6 +18,7 @@ use super::*; use super::utils; use ::builder::{CreateEmbed, CreateInvite, EditChannel}; use ::client::{STATE, http}; +use ::constants; use ::prelude_internal::*; use ::utils::decode_array; @@ -448,13 +449,24 @@ impl Message { /// /// **Note**: You must be the author of the message to be able to do this. /// + /// **Note**: Messages must be under 2000 unicode code points. + /// /// # Errors /// - /// Returns a - /// [`ClientError::InvalidUser`] if the current user is not the author. + /// Returns a [`ClientError::InvalidUser`] if the current user is not the + /// author. + /// + /// Returns a [`ClientError::MessageTooLong`] if the content of the message + /// is over the above limit, containing the number of unicode code points + /// over the limit. /// /// [`ClientError::InvalidUser`]: ../client/enum.ClientError.html#variant.InvalidUser + /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong pub fn edit(&mut self, new_content: &str) -> Result<()> { + if let Some(length_over) = Message::overflow_length(new_content) { + return Err(Error::Client(ClientError::MessageTooLong(length_over))); + } + if self.author.id != STATE.lock().unwrap().user.id { return Err(Error::Client(ClientError::InvalidUser)); } @@ -473,6 +485,25 @@ impl Message { } } + /// Checks the length of a string to ensure that it is within Discord's + /// maximum message length limit. + /// + /// Returns `None` if the message is within the limit, otherwise returns + /// `Some` with an inner value of how many unicode code points the message + /// is over. + pub fn overflow_length(content: &str) -> Option<u64> { + // Check if the content is over the maximum number of unicode code + // points. + let count = content.chars().count() as u64; + let diff = count - constants::MESSAGE_CODE_LIMIT as u64; + + if diff > 0 { + Some(diff) + } else { + None + } + } + /// Pins this message to its channel. /// /// **Note**: Requires the [Manage Messages] permission. @@ -527,15 +558,25 @@ impl Message { /// /// **Note**: Requires the [Send Messages] permission. /// + /// **Note**: Message contents must be under 2000 unicode code points. + /// /// # Errors /// - /// Returns a - /// [`ClientError::InvalidPermissions`] if the current user does not have - /// the required permissions. + /// Returns a [`ClientError::InvalidPermissions`] if the current user does + /// not have the required permissions. + /// + /// Returns a [`ClientError::MessageTooLong`] if the content of the message + /// is over the above limit, containing the number of unicode code points + /// over the limit. /// /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions + /// [`ClientError::MessageTooLong`]: enum.ClientError.html#variant.MessageTooLong /// [Send Messages]: permissions/constant.SEND_MESSAGES.html pub fn reply(&self, content: &str) -> Result<Message> { + if let Some(length_over) = Message::overflow_length(content) { + return Err(Error::Client(ClientError::MessageTooLong(length_over))); + } + let req = permissions::SEND_MESSAGES; if !try!(utils::user_has_perms(self.channel_id, req)) { @@ -660,8 +701,22 @@ impl PrivateChannel { http::get_pins(self.id.0) } - /// Sends a message to the recipient with the given content. + /// Sends a message to the channel with the given content. + /// + /// **Note**: This will only work when a [`Message`] is received. + /// + /// # Errors + /// + /// Returns a [`ClientError::MessageTooLong`] if the content of the message + /// is over the above limit, containing the number of unicode code points + /// over the limit. + /// + /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong pub fn send_message(&self, content: &str) -> Result<Message> { + if let Some(length_over) = Message::overflow_length(content) { + return Err(Error::Client(ClientError::MessageTooLong(length_over))); + } + let map = ObjectBuilder::new() .insert("content", content) .insert("nonce", "") @@ -783,7 +838,29 @@ impl PublicChannel { http::get_pins(self.id.0) } + /// Sends a message to the channel with the given content. + /// + /// **Note**: This will only work when a [`Message`] is received. + /// + /// **Note**: Requires the [Send Messages] permission. + /// + /// # Errors + /// + /// Returns a [`ClientError::MessageTooLong`] if the content of the message + /// is over the above limit, containing the number of unicode code points + /// over the limit. + /// + /// Returns a [`ClientError::InvalidPermissions`] if the current user does + /// not have the required permissions. + /// + /// [`ClientError::InvalidPermissions`]: ../client/enum.ClientError.html#variant.InvalidPermissions + /// [`ClientError::MessageTooLong`]: ../client/enum.ClientError.html#variant.MessageTooLong + /// [Send Messages]: permissions/constant.SEND_MESSAGES.html pub fn send_message(&self, content: &str) -> Result<Message> { + if let Some(length_over) = Message::overflow_length(content) { + return Err(Error::Client(ClientError::MessageTooLong(length_over))); + } + let req = permissions::SEND_MESSAGES; if !try!(utils::user_has_perms(self.id, req)) { |