use core::BotCmdAuthLvl as Auth;
use core::*;
use regex::Captures;
use std::borrow::Cow;
use util;
use yaml_rust::Yaml;
pub fn mk() -> Module {
mk_module("default")
.command(
"join",
"<channel>",
"Have the bot join the given channel. Note that a channel name containing the \
character '#' will need to be enclosed in quotation marks, like '#channel' or \
\"#channel\".",
Auth::Admin,
Box::new(join),
&[],
)
.command(
"part",
"{chan: '[channel]', msg: '[message]'}",
"Have the bot part from the given channel (defaults to the current channel), with an \
optional part message.",
Auth::Admin,
Box::new(part),
&[],
)
.command(
"quit",
"{msg: '[message]'}",
"Have the bot quit.",
Auth::Admin,
Box::new(quit),
&[],
)
.command(
"ping",
"",
"Request a short message from the bot, typically for testing purposes.",
Auth::Public,
Box::new(ping),
&[],
)
.command(
"framework-info",
"",
"Request information about the framework with which the bot was built, such as the URL \
of a Web page about it.",
Auth::Public,
Box::new(bot_fw_info),
&[],
)
.command(
"help",
"{cmd: '[command]', list: '[list name]'}",
"Request help with the bot's features, such as commands.",
Auth::Public,
Box::new(help),
&[],
)
.trigger(
"yes?",
"^$",
"Say \"Yes?\" in response to otherwise empty messages addressed to the bot.",
TriggerPriority::Minimum,
Box::new(empty_msg_trigger),
&[],
)
.end()
}
static FW_SYNTAX_CHECK_FAIL: &str =
"The framework should have caught this syntax error before it tried to run this command \
handler!";
lazy_static! {
static ref YAML_STR_CHAN: Yaml = Yaml::String("chan".into());
static ref YAML_STR_CMD: Yaml = Yaml::String("cmd".into());
static ref YAML_STR_LIST: Yaml = Yaml::String("list".into());
static ref YAML_STR_MSG: Yaml = Yaml::String("msg".into());
}
fn join(_: &State, _: &MsgMetadata, arg: &Yaml) -> Reaction {
Reaction::RawMsg(
format!(
"JOIN {}",
util::yaml::scalar_to_str(arg, Cow::Borrowed).expect(FW_SYNTAX_CHECK_FAIL)
).into(),
)
}
fn part(
state: &State,
&MsgMetadata {
dest: MsgDest { server_id, target },
..
}: &MsgMetadata,
arg: &Yaml,
) -> BotCmdResult {
let arg = arg.as_hash().expect(FW_SYNTAX_CHECK_FAIL);
let chan = arg.get(&YAML_STR_CHAN)
.map(|y| util::yaml::scalar_to_str(y, Cow::Borrowed).expect(FW_SYNTAX_CHECK_FAIL));
let chan = match (chan, target) {
(Some(c), _) => c,
(None, t) if t == state.nick(server_id).unwrap_or("".into()) => {
return BotCmdResult::ArgMissing1To1("channel".into())
}
(None, t) => t.into(),
};
let comment = arg.get(&YAML_STR_MSG)
.map(|y| util::yaml::scalar_to_str(y, Cow::Borrowed).expect(FW_SYNTAX_CHECK_FAIL));
Reaction::RawMsg(
format!(
"PART {}{}{}",
chan,
if comment.is_some() { " :" } else { "" },
comment.unwrap_or_default()
).into(),
).into()
}
fn quit(_: &State, _: &MsgMetadata, arg: &Yaml) -> Reaction {
let comment = arg.as_hash()
.expect(FW_SYNTAX_CHECK_FAIL)
.get(&YAML_STR_MSG)
.map(|y| {
util::yaml::scalar_to_str(y, |s| Cow::Owned(s.to_owned())).expect(FW_SYNTAX_CHECK_FAIL)
});
Reaction::Quit(comment)
}
fn ping(_: &State, _: &MsgMetadata, _: &Yaml) -> BotCmdResult {
Reaction::Reply("pong".into()).into()
}
fn bot_fw_info(state: &State, _: &MsgMetadata, _: &Yaml) -> BotCmdResult {
Reaction::Reply(
format!(
"This bot was built with `{name}.rs`, version {ver}; see <{url}>.",
name = state.framework_crate_name(),
ver = state.framework_version_str(),
url = state.framework_homepage_url_str(),
).into(),
).into()
}
fn help(state: &State, _: &MsgMetadata, arg: &Yaml) -> BotCmdResult {
let arg = arg.as_hash();
let cmd = arg.and_then(|m| m.get(&YAML_STR_CMD));
let list = arg.and_then(|m| m.get(&YAML_STR_LIST));
if [cmd, list].iter().filter(|x| x.is_some()).count() > 1 {
return Reaction::Msg("Please ask for help with one thing at a time.".into()).into();
}
if let Some(&Yaml::String(ref cmd_name)) = cmd {
let &BotCommand {
ref name,
ref provider,
ref auth_lvl,
ref usage_str,
ref help_msg,
..
} = match state.command(cmd_name) {
Ok(Some(c)) => c,
Ok(None) => {
return Reaction::Msg(format!("Command {:?} not found.", cmd_name).into()).into()
}
Err(e) => return BotCmdResult::LibErr(e),
};
Reaction::Msgs(
vec![
format!("= Help for command {:?}:", name).into(),
format!("- [module {:?}, auth level {:?}]", provider.name, auth_lvl).into(),
format!("- Syntax: {} {}", name, usage_str).into(),
help_msg.clone(),
].into(),
).into()
} else if let Some(&Yaml::String(ref list_name)) = list {
let list_names = ["commands", "lists"];
if list_name == "commands" {
Reaction::Msg(format!("Available commands: {:?}", state.command_names()).into()).into()
} else if list_name == "lists" {
Reaction::Msg(format!("Available lists: {:?}", list_names).into()).into()
} else {
if list_names.contains(&list_name.as_ref()) {
error!("Help list {:?} declared but not defined.", list_name);
}
Reaction::Msg(
format!(
"List {:?} not found. Available lists: {:?}",
list_name, list_names
).into(),
).into()
}
} else {
Reaction::Msgs(
vec![
"For help with a command named 'foo', try `help cmd: foo`.".into(),
"To see a list of all available commands, try `help list: commands`.".into(),
format!(
"For this bot software's documentation, including an introduction to the \
command syntax, see <{homepage}>",
homepage = state.framework_homepage_url_str(),
).into(),
].into(),
).into()
}
}
fn empty_msg_trigger(_: &State, _: &MsgMetadata, _: Captures) -> Reaction {
Reaction::Msg("Yes?".into())
}