serenity/builder/
get_messages.rs

1#[cfg(feature = "http")]
2use super::Builder;
3#[cfg(feature = "http")]
4use crate::http::{CacheHttp, MessagePagination};
5#[cfg(feature = "http")]
6use crate::internal::prelude::*;
7use crate::model::prelude::*;
8
9/// Builds a request to the API to retrieve messages.
10///
11/// This accepts 2 types of parameters. The first type filters messages based on Id, and is set by
12/// one of the following:
13///
14/// - [`Self::after`]
15/// - [`Self::around`]
16/// - [`Self::before`]
17///
18/// These are mutually exclusive, and override each other if called sequentially. If one is not
19/// specified, messages are simply sorted by most recent.
20///
21/// The other parameter specifies the number of messages to retrieve. This is _optional_, and
22/// defaults to 50 if not specified.
23///
24/// See [`GuildChannel::messages`] for more examples.
25///
26/// # Examples
27///
28/// Creating a [`GetMessages`] builder to retrieve the first 25 messages after the message with an
29/// Id of `158339864557912064`:
30///
31/// ```rust,no_run
32/// # use serenity::http::Http;
33/// #
34/// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
35/// # let http: Http = unimplemented!();
36/// use serenity::builder::GetMessages;
37/// use serenity::model::id::{ChannelId, MessageId};
38///
39/// // you can then pass it into a function which retrieves messages:
40/// let channel_id = ChannelId::new(81384788765712384);
41///
42/// let builder = GetMessages::new().after(MessageId::new(158339864557912064)).limit(25);
43/// let _messages = channel_id.messages(&http, builder).await?;
44/// # Ok(())
45/// # }
46/// ```
47///
48/// [Discord docs](https://discord.com/developers/docs/resources/channel#get-channel-messages)
49#[derive(Clone, Copy, Debug, Default)]
50#[must_use]
51pub struct GetMessages {
52    search_filter: Option<SearchFilter>,
53    limit: Option<u8>,
54}
55
56impl GetMessages {
57    /// Equivalent to [`Self::default`].
58    pub fn new() -> Self {
59        Self::default()
60    }
61
62    /// Indicates to retrieve the messages after a specific message, given its Id.
63    pub fn after(mut self, message_id: impl Into<MessageId>) -> Self {
64        self.search_filter = Some(SearchFilter::After(message_id.into()));
65        self
66    }
67
68    /// Indicates to retrieve the messages _around_ a specific message, in other words in either
69    /// direction from the message in time.
70    pub fn around(mut self, message_id: impl Into<MessageId>) -> Self {
71        self.search_filter = Some(SearchFilter::Around(message_id.into()));
72        self
73    }
74
75    /// Indicates to retrieve the messages before a specific message, given its Id.
76    pub fn before(mut self, message_id: impl Into<MessageId>) -> Self {
77        self.search_filter = Some(SearchFilter::Before(message_id.into()));
78        self
79    }
80
81    /// The maximum number of messages to retrieve for the query.
82    ///
83    /// If this is not specified, a default value of 50 is used.
84    ///
85    /// **Note**: This field is capped to 100 messages due to a Discord limitation. If an amount
86    /// larger than 100 is supplied, it will be truncated.
87    pub fn limit(mut self, limit: u8) -> Self {
88        self.limit = Some(limit.min(100));
89        self
90    }
91}
92
93#[cfg(feature = "http")]
94#[async_trait::async_trait]
95impl Builder for GetMessages {
96    type Context<'ctx> = ChannelId;
97    type Built = Vec<Message>;
98
99    /// Gets messages from the channel.
100    ///
101    /// **Note**: If the user does not have the [Read Message History] permission, returns an empty
102    /// [`Vec`].
103    ///
104    /// # Errors
105    ///
106    /// Returns [`Error::Http`] if the current user lacks permission.
107    ///
108    /// [Read Message History]: Permissions::READ_MESSAGE_HISTORY
109    async fn execute(
110        self,
111        cache_http: impl CacheHttp,
112        ctx: Self::Context<'_>,
113    ) -> Result<Self::Built> {
114        cache_http.http().get_messages(ctx, self.search_filter.map(Into::into), self.limit).await
115    }
116}
117
118#[derive(Clone, Copy, Debug)]
119enum SearchFilter {
120    After(MessageId),
121    Around(MessageId),
122    Before(MessageId),
123}
124
125#[cfg(feature = "http")]
126impl From<SearchFilter> for MessagePagination {
127    fn from(filter: SearchFilter) -> Self {
128        match filter {
129            SearchFilter::After(id) => MessagePagination::After(id),
130            SearchFilter::Around(id) => MessagePagination::Around(id),
131            SearchFilter::Before(id) => MessagePagination::Before(id),
132        }
133    }
134}