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}