use std::fmt;
use super::ArgumentConvert;
use crate::model::prelude::*;
use crate::prelude::*;
#[non_exhaustive]
#[derive(Debug)]
pub enum ChannelParseError {
Http(SerenityError),
NotFoundOrMalformed,
}
impl std::error::Error for ChannelParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Http(e) => Some(e),
Self::NotFoundOrMalformed => None,
}
}
}
impl fmt::Display for ChannelParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Http(_) => f.write_str("Failed to request channel via HTTP"),
Self::NotFoundOrMalformed => f.write_str("Channel not found or unknown format"),
}
}
}
fn channel_belongs_to_guild(channel: &Channel, guild: GuildId) -> bool {
match channel {
Channel::Guild(channel) => channel.guild_id == guild,
Channel::Private(_channel) => false,
}
}
async fn lookup_channel_global(
ctx: impl CacheHttp,
guild_id: Option<GuildId>,
s: &str,
) -> Result<Channel, ChannelParseError> {
if let Some(channel_id) = s.parse().ok().or_else(|| crate::utils::parse_channel_mention(s)) {
return channel_id.to_channel(&ctx).await.map_err(ChannelParseError::Http);
}
let guild_id = guild_id.ok_or(ChannelParseError::NotFoundOrMalformed)?;
#[cfg(feature = "cache")]
if let Some(cache) = ctx.cache() {
if let Some(guild) = cache.guild(guild_id) {
let channel = guild.channels.values().find(|c| c.name.eq_ignore_ascii_case(s));
if let Some(channel) = channel {
return Ok(Channel::Guild(channel.clone()));
}
}
return Err(ChannelParseError::NotFoundOrMalformed);
}
let channels = ctx.http().get_channels(guild_id).await.map_err(ChannelParseError::Http)?;
if let Some(channel) = channels.into_iter().find(|c| c.name.eq_ignore_ascii_case(s)) {
Ok(Channel::Guild(channel))
} else {
Err(ChannelParseError::NotFoundOrMalformed)
}
}
#[async_trait::async_trait]
impl ArgumentConvert for Channel {
type Err = ChannelParseError;
async fn convert(
ctx: impl CacheHttp,
guild_id: Option<GuildId>,
_channel_id: Option<ChannelId>,
s: &str,
) -> Result<Self, Self::Err> {
let channel = lookup_channel_global(&ctx, guild_id, s).await?;
if let Some(guild_id) = guild_id {
if !channel_belongs_to_guild(&channel, guild_id) {
return Err(ChannelParseError::NotFoundOrMalformed);
}
}
Ok(channel)
}
}
#[non_exhaustive]
#[derive(Debug)]
pub enum GuildChannelParseError {
Http(SerenityError),
NotFoundOrMalformed,
NotAGuildChannel,
}
impl std::error::Error for GuildChannelParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Http(e) => Some(e),
Self::NotFoundOrMalformed | Self::NotAGuildChannel => None,
}
}
}
impl fmt::Display for GuildChannelParseError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Http(_) => f.write_str("Failed to request channel via HTTP"),
Self::NotFoundOrMalformed => f.write_str("Channel not found or unknown format"),
Self::NotAGuildChannel => f.write_str("Channel is not a guild channel"),
}
}
}
#[async_trait::async_trait]
impl ArgumentConvert for GuildChannel {
type Err = GuildChannelParseError;
async fn convert(
ctx: impl CacheHttp,
guild_id: Option<GuildId>,
channel_id: Option<ChannelId>,
s: &str,
) -> Result<Self, Self::Err> {
match Channel::convert(&ctx, guild_id, channel_id, s).await {
Ok(Channel::Guild(channel)) => Ok(channel),
Ok(_) => Err(GuildChannelParseError::NotAGuildChannel),
Err(ChannelParseError::Http(e)) => Err(GuildChannelParseError::Http(e)),
Err(ChannelParseError::NotFoundOrMalformed) => {
Err(GuildChannelParseError::NotFoundOrMalformed)
},
}
}
}