use super::BotCmdHandler;
use super::Error;
use super::Module;
use super::MsgMetadata;
use super::Reaction;
use super::Result;
use super::State;
use std;
use std::borrow::Cow;
use std::sync::Arc;
use util;
use yaml_rust::Yaml;
pub struct BotCommand {
pub name: Cow<'static, str>,
pub provider: Arc<Module>,
pub auth_lvl: BotCmdAuthLvl,
pub(super) handler: Arc<BotCmdHandler>,
pub usage_str: Cow<'static, str>,
pub(super) usage_yaml: Yaml,
pub help_msg: Cow<'static, str>,
}
#[derive(Debug)]
pub enum BotCmdAttr {}
#[derive(Debug)]
pub enum BotCmdResult {
Ok(Reaction),
Unauthorized,
SyntaxErr,
ArgMissing(Cow<'static, str>),
ArgMissing1To1(Cow<'static, str>),
LibErr(Error),
UserErrMsg(Cow<'static, str>),
BotErrMsg(Cow<'static, str>),
}
impl From<Reaction> for BotCmdResult {
fn from(r: Reaction) -> Self {
BotCmdResult::Ok(r)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum BotCmdAuthLvl {
Public,
Admin,
}
pub(super) fn run(
state: &State,
cmd_name: &str,
cmd_args: &str,
metadata: &MsgMetadata,
) -> Result<Option<BotCmdResult>> {
let &BotCommand {
ref name,
ref provider,
ref auth_lvl,
ref handler,
ref usage_yaml,
usage_str: _,
help_msg: _,
} = match state.commands.get(cmd_name) {
Some(c) => c,
None => return Ok(None),
};
let user_authorized = match auth_lvl {
&BotCmdAuthLvl::Public => Ok(true),
&BotCmdAuthLvl::Admin => state.have_admin(metadata.prefix),
};
let arg = match parse_arg(usage_yaml, cmd_args) {
Ok(arg) => arg,
Err(res) => return Ok(Some(res)),
};
let result = match user_authorized {
Ok(true) => {
debug!("Running bot command {:?} with arg: {:?}", name, arg);
match util::run_handler("command", name.clone(), || {
handler.run(state, &metadata, &arg)
}) {
Ok(r) => r,
Err(e) => BotCmdResult::LibErr(e),
}
}
Ok(false) => BotCmdResult::Unauthorized,
Err(e) => BotCmdResult::LibErr(e),
};
match result {
BotCmdResult::Ok(Reaction::Quit(ref s)) if *auth_lvl != BotCmdAuthLvl::Admin => {
Ok(Some(BotCmdResult::BotErrMsg(
format!(
"Only commands at authorization level {auth_lvl_owner:?} \
may tell the bot to quit, but the command {cmd_name:?} \
from module {provider_name:?}, at authorization level \
{cmd_auth_lvl:?}, has told the bot to quit with quit \
message {quit_msg:?}.",
auth_lvl_owner = BotCmdAuthLvl::Admin,
cmd_name = name,
provider_name = provider.name,
cmd_auth_lvl = auth_lvl,
quit_msg = s
).into(),
)))
}
r => Ok(Some(r)),
}
}
fn parse_arg<'s>(syntax: &'s Yaml, arg_str: &str) -> std::result::Result<Yaml, BotCmdResult> {
use util::yaml as uy;
match uy::parse_and_check_node(arg_str, syntax, "<argument>", || {
Yaml::Hash(Default::default())
}) {
Ok(arg) => Ok(arg),
Err(uy::Error(uy::ErrorKind::YamlScan(_), _)) => Err(BotCmdResult::SyntaxErr),
Err(err) => Err(BotCmdResult::LibErr(err.into())),
}
}