1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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())),
}
}