serenity/utils/argument_convert/
message.rs

1use std::fmt;
2
3use super::ArgumentConvert;
4use crate::model::prelude::*;
5use crate::prelude::*;
6
7/// Error that can be returned from [`Message::convert`].
8#[non_exhaustive]
9#[derive(Debug)]
10pub enum MessageParseError {
11    /// When the provided string does not adhere to any known guild message format
12    Malformed,
13    /// When message data retrieval via HTTP failed
14    Http(SerenityError),
15    /// When the `gateway` feature is disabled and the required information was not in cache.
16    HttpNotAvailable,
17}
18
19impl std::error::Error for MessageParseError {
20    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
21        match self {
22            Self::Http(e) => Some(e),
23            Self::HttpNotAvailable | Self::Malformed => None,
24        }
25    }
26}
27
28impl fmt::Display for MessageParseError {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        match self {
31            Self::Malformed => {
32                f.write_str("Provided string did not adhere to any known guild message format")
33            },
34            Self::Http(_) => f.write_str("Failed to request message data via HTTP"),
35            Self::HttpNotAvailable => f.write_str(
36                "Gateway feature is disabled and the required information was not in cache",
37            ),
38        }
39    }
40}
41
42/// Look up a message by a string.
43///
44/// The lookup strategy is as follows (in order):
45/// 1. [Lookup by "{channel ID}-{message ID}"](`crate::utils::parse_message_id_pair`) (retrieved by
46///    shift-clicking on "Copy ID")
47/// 2. Lookup by message ID (the message must be in the context channel)
48/// 3. [Lookup by message URL](`crate::utils::parse_message_url`)
49#[async_trait::async_trait]
50impl ArgumentConvert for Message {
51    type Err = MessageParseError;
52
53    async fn convert(
54        ctx: impl CacheHttp,
55        _guild_id: Option<GuildId>,
56        channel_id: Option<ChannelId>,
57        s: &str,
58    ) -> Result<Self, Self::Err> {
59        let extract_from_message_id = || Some((channel_id?, s.parse().ok()?));
60
61        let extract_from_message_url = || {
62            let (_guild_id, channel_id, message_id) = crate::utils::parse_message_url(s)?;
63            Some((channel_id, message_id))
64        };
65
66        let (channel_id, message_id) = crate::utils::parse_message_id_pair(s)
67            .or_else(extract_from_message_id)
68            .or_else(extract_from_message_url)
69            .ok_or(MessageParseError::Malformed)?;
70
71        channel_id.message(ctx, message_id).await.map_err(MessageParseError::Http)
72    }
73}