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::Category(channel) => channel.guild_id == guild,
Channel::Private(_channel) => false,
}
}
async fn lookup_channel_global(
ctx: &Context,
guild_id: Option<GuildId>,
s: &str,
) -> Result<Channel, ChannelParseError> {
if let Some(channel_id) = s.parse::<u64>().ok().or_else(|| crate::utils::parse_channel(s)) {
return ChannelId(channel_id).to_channel(ctx).await.map_err(ChannelParseError::Http);
}
#[cfg(feature = "cache")]
if let Some(channel) = ctx.cache.channels.iter().find_map(|m| {
let channel = m.value();
if channel.name.eq_ignore_ascii_case(s) {
Some(channel.clone())
} else {
None
}
}) {
return Ok(Channel::Guild(channel));
}
if let Some(guild_id) = guild_id {
let channels = ctx.http.get_channels(guild_id.0).await.map_err(ChannelParseError::Http)?;
if let Some(channel) =
channels.into_iter().find(|channel| channel.name.eq_ignore_ascii_case(s))
{
return Ok(Channel::Guild(channel));
}
}
Err(ChannelParseError::NotFoundOrMalformed)
}
#[async_trait::async_trait]
impl ArgumentConvert for Channel {
type Err = ChannelParseError;
async fn convert(
ctx: &Context,
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: &Context,
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)
},
}
}
}
#[non_exhaustive]
#[derive(Debug)]
pub enum ChannelCategoryParseError {
Http(SerenityError),
NotFoundOrMalformed,
NotAChannelCategory,
}
impl std::error::Error for ChannelCategoryParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Http(e) => Some(e),
Self::NotFoundOrMalformed | Self::NotAChannelCategory => None,
}
}
}
impl fmt::Display for ChannelCategoryParseError {
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::NotAChannelCategory => f.write_str("Channel is not a channel category"),
}
}
}
#[async_trait::async_trait]
impl ArgumentConvert for ChannelCategory {
type Err = ChannelCategoryParseError;
async fn convert(
ctx: &Context,
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::Category(channel)) => Ok(channel),
Ok(_) => Err(ChannelCategoryParseError::NotAChannelCategory),
Err(ChannelParseError::Http(e)) => Err(ChannelCategoryParseError::Http(e)),
Err(ChannelParseError::NotFoundOrMalformed) => {
Err(ChannelCategoryParseError::NotFoundOrMalformed)
},
}
}
}