aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAustin Hellyer <[email protected]>2016-11-12 11:21:12 -0800
committerAustin Hellyer <[email protected]>2016-11-12 11:21:12 -0800
commite9cdc50f68ad36d78b5fcc1c0dd6463274828eca (patch)
treec6b0bd54bae9f18906a47fd85402faea5345a1cd /src
parentAdd delete_message_reactions + register event (diff)
downloadserenity-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.rs38
-rw-r--r--src/client/mod.rs7
-rw-r--r--src/constants.rs2
-rw-r--r--src/model/channel.rs89
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)) {