serenity/utils/argument_convert/
channel.rs1use std::fmt;
2
3use super::ArgumentConvert;
4use crate::model::prelude::*;
5use crate::prelude::*;
6
7#[non_exhaustive]
9#[derive(Debug)]
10pub enum ChannelParseError {
11 Http(SerenityError),
13 NotFoundOrMalformed,
16}
17
18impl std::error::Error for ChannelParseError {
19 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
20 match self {
21 Self::Http(e) => Some(e),
22 Self::NotFoundOrMalformed => None,
23 }
24 }
25}
26
27impl fmt::Display for ChannelParseError {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 Self::Http(_) => f.write_str("Failed to request channel via HTTP"),
31 Self::NotFoundOrMalformed => f.write_str("Channel not found or unknown format"),
32 }
33 }
34}
35
36fn channel_belongs_to_guild(channel: &Channel, guild: GuildId) -> bool {
37 match channel {
38 Channel::Guild(channel) => channel.guild_id == guild,
39 Channel::Private(_channel) => false,
40 }
41}
42
43async fn lookup_channel_global(
44 ctx: impl CacheHttp,
45 guild_id: Option<GuildId>,
46 s: &str,
47) -> Result<Channel, ChannelParseError> {
48 if let Some(channel_id) = s.parse().ok().or_else(|| crate::utils::parse_channel_mention(s)) {
49 return channel_id.to_channel(&ctx).await.map_err(ChannelParseError::Http);
50 }
51
52 let guild_id = guild_id.ok_or(ChannelParseError::NotFoundOrMalformed)?;
53
54 #[cfg(feature = "cache")]
55 if let Some(cache) = ctx.cache() {
56 if let Some(guild) = cache.guild(guild_id) {
57 let channel = guild.channels.values().find(|c| c.name.eq_ignore_ascii_case(s));
58 if let Some(channel) = channel {
59 return Ok(Channel::Guild(channel.clone()));
60 }
61 }
62
63 return Err(ChannelParseError::NotFoundOrMalformed);
64 }
65
66 let channels = ctx.http().get_channels(guild_id).await.map_err(ChannelParseError::Http)?;
67 if let Some(channel) = channels.into_iter().find(|c| c.name.eq_ignore_ascii_case(s)) {
68 Ok(Channel::Guild(channel))
69 } else {
70 Err(ChannelParseError::NotFoundOrMalformed)
71 }
72}
73
74#[async_trait::async_trait]
85impl ArgumentConvert for Channel {
86 type Err = ChannelParseError;
87
88 async fn convert(
89 ctx: impl CacheHttp,
90 guild_id: Option<GuildId>,
91 _channel_id: Option<ChannelId>,
92 s: &str,
93 ) -> Result<Self, Self::Err> {
94 let channel = lookup_channel_global(&ctx, guild_id, s).await?;
95
96 if let Some(guild_id) = guild_id {
98 if !channel_belongs_to_guild(&channel, guild_id) {
99 return Err(ChannelParseError::NotFoundOrMalformed);
100 }
101 };
102
103 Ok(channel)
104 }
105}
106
107#[non_exhaustive]
109#[derive(Debug)]
110pub enum GuildChannelParseError {
111 Http(SerenityError),
113 NotFoundOrMalformed,
116 NotAGuildChannel,
118}
119
120impl std::error::Error for GuildChannelParseError {
121 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
122 match self {
123 Self::Http(e) => Some(e),
124 Self::NotFoundOrMalformed | Self::NotAGuildChannel => None,
125 }
126 }
127}
128
129impl fmt::Display for GuildChannelParseError {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 match self {
132 Self::Http(_) => f.write_str("Failed to request channel via HTTP"),
133 Self::NotFoundOrMalformed => f.write_str("Channel not found or unknown format"),
134 Self::NotAGuildChannel => f.write_str("Channel is not a guild channel"),
135 }
136 }
137}
138
139#[async_trait::async_trait]
145impl ArgumentConvert for GuildChannel {
146 type Err = GuildChannelParseError;
147
148 async fn convert(
149 ctx: impl CacheHttp,
150 guild_id: Option<GuildId>,
151 channel_id: Option<ChannelId>,
152 s: &str,
153 ) -> Result<Self, Self::Err> {
154 match Channel::convert(&ctx, guild_id, channel_id, s).await {
155 Ok(Channel::Guild(channel)) => Ok(channel),
156 Ok(_) => Err(GuildChannelParseError::NotAGuildChannel),
157 Err(ChannelParseError::Http(e)) => Err(GuildChannelParseError::Http(e)),
158 Err(ChannelParseError::NotFoundOrMalformed) => {
159 Err(GuildChannelParseError::NotFoundOrMalformed)
160 },
161 }
162 }
163}