1use crate::{
2 Context as MessageContext, Error,
3 commands::{
4 Check, Command, CommandEventHandler, Context, DefaultHelpCommand, HelpCommand, Words,
5 help_command,
6 },
7};
8use state::TypeMap;
9use std::{
10 collections::HashMap,
11 fmt::Debug,
12 sync::{Arc, RwLock},
13};
14use stoat_models::v0::Message;
15
16#[derive(Clone)]
17pub struct CommandHandler<H: CommandEventHandler + Clone + Send + Sync + 'static> {
18 commands: Commands<H::Error, H::State>,
19 checks: Vec<Arc<dyn Check<H::Error, H::State>>>,
20 event_handler: H,
21 state: H::State,
22 help_command: Arc<dyn HelpCommand<H::Error, H::State>>,
23}
24
25impl<
26 H: CommandEventHandler<State = S, Error = E> + Clone + Send + Sync,
27 E: From<Error> + Clone + Debug + Send + Sync + 'static,
28 S: Debug + Clone + Send + Sync + 'static,
29> CommandHandler<H>
30{
31 pub fn new(event_handler: H, state: S) -> Self {
32 let commands = Commands::new();
33 commands.register(help_command());
34
35 Self {
36 commands,
37 checks: Vec::new(),
38 event_handler,
39 state,
40 help_command: Arc::new(DefaultHelpCommand),
41 }
42 }
43
44 pub fn register(self, commands: Vec<Command<E, S>>) -> Self {
45 for command in commands {
46 self.commands.register(command)
47 }
48
49 self
50 }
51
52 pub fn help_command<HC: HelpCommand<E, S> + 'static>(
53 mut self,
54 help_command: Option<HC>,
55 ) -> Self {
56 if let Some(help_command) = help_command {
57 self.help_command = Arc::new(help_command);
58 } else if let Some(help_command) = self.commands.get_command("help") {
59 self.commands.unregister(help_command);
60 }
61
62 self
63 }
64
65 pub fn check<C: Check<E, S>>(mut self, check: C) -> Self {
66 self.checks.push(Arc::new(check));
67
68 self
69 }
70
71 pub async fn can_run(&self, context: Context<E, S>) -> Result<bool, E> {
72 for check in &self.checks {
73 if check.run(context.clone()).await? == false {
74 return Err(Error::CheckFailure.into());
75 }
76 }
77
78 if let Some(command) = &context.command {
79 return command.can_run(context.clone()).await;
80 }
81
82 Ok(true)
83 }
84
85 pub async fn process_commands(
86 &self,
87 context: MessageContext,
88 message: Message,
89 ) -> Result<(), E> {
90 let Some(message_content) = message.content.as_deref() else {
91 return Ok(());
93 };
94
95 if message.user.as_ref().unwrap().bot.is_some() {
96 return Ok(());
97 };
98
99 let mut cmd_context = Context {
100 inner: context,
101 prefix: None,
102 command: None,
103 message: message.clone(),
104 state: self.state.clone(),
105 words: Words::new(message_content),
106 commands: self.commands.clone(),
107 help_command: self.help_command.clone(),
108 local_state: Arc::new(<TypeMap![Send + Sync]>::new()),
109 };
110
111 let prefixes = match self.event_handler.get_prefix(cmd_context.clone()).await {
112 Ok(prefixes) => prefixes,
113 Err(e) => {
114 self.event_handler.error(cmd_context.clone(), e).await?;
115 return Ok(());
116 }
117 };
118
119 let Some(prefix) = prefixes
120 .into_iter()
121 .filter(|prefix| message_content.starts_with(prefix))
122 .next()
123 else {
124 return Ok(());
126 };
127
128 let rest = &message_content[prefix.len()..];
129
130 cmd_context.words = Words::new(rest);
131 cmd_context.command = self
132 .commands
133 .find_command_from_words(None, &cmd_context.words);
134 cmd_context.prefix = Some(prefix);
135
136 if cmd_context.command.is_none() {
137 if let Err(e) = self.event_handler.no_command(cmd_context.clone()).await {
138 self.event_handler.error(cmd_context.clone(), e).await?;
139 };
140
141 return Ok(());
142 }
143
144 if let Err(e) = self.event_handler.command(cmd_context.clone()).await {
145 self.event_handler.error(cmd_context.clone(), e).await?;
146 };
147
148 if let Some(command) = cmd_context.command.as_ref() {
149 if let Err(e) = self.can_run(cmd_context.clone()).await {
150 self.event_handler.error(cmd_context.clone(), e).await?;
151 } else {
152 if let Err(e) = command.handle.handle(cmd_context.clone()).await {
153 if let Some(error) = &command.error {
154 error.handle(cmd_context.clone(), e.clone()).await?;
155 };
156
157 self.event_handler.error(cmd_context.clone(), e).await?;
158 };
159
160 if let Err(e) = self.event_handler.after_command(cmd_context.clone()).await {
161 self.event_handler.error(cmd_context.clone(), e).await?;
162 };
163 }
164 }
165
166 Ok(())
167 }
168}
169
170#[derive(Debug, Clone)]
171pub struct Commands<
172 E: From<Error> + Clone + Debug + Send + Sync + 'static,
173 S: Debug + Clone + Send + Sync + 'static,
174> {
175 mapping: Arc<RwLock<HashMap<String, Command<E, S>>>>,
176}
177
178impl<
179 E: From<Error> + Clone + Debug + Send + Sync + 'static,
180 S: Debug + Clone + Send + Sync + 'static,
181> Commands<E, S>
182{
183 pub fn new() -> Self {
184 Self {
185 mapping: Arc::new(RwLock::new(HashMap::new())),
186 }
187 }
188
189 pub fn register(&self, command: Command<E, S>) {
190 let mut mapping = self.mapping.write().unwrap();
191
192 mapping.insert(command.name.clone(), command.clone());
193
194 for alias in command.aliases.clone() {
195 mapping.insert(alias, command.clone());
196 }
197 }
198
199 pub fn unregister(&self, command: Command<E, S>) {
200 let mut mapping = self.mapping.write().unwrap();
201
202 mapping.remove(&command.name);
203
204 for alias in command.aliases.clone() {
205 mapping.remove(&alias);
206 }
207 }
208
209 pub fn find_command_from_words(
210 &self,
211 current_command: Option<&Command<E, S>>,
212 words: &Words,
213 ) -> Option<Command<E, S>> {
214 let next_word = words.current()?;
215
216 let commands = self.mapping.read().unwrap();
217
218 if let Some(command) = current_command
219 .and_then(|command| command.children.get(&next_word))
220 .or_else(|| commands.get(&next_word))
221 {
222 words.advance();
223
224 if !command.children.is_empty() {
225 let subcommand = self.find_command_from_words(Some(command), words);
226
227 match subcommand {
228 Some(sub) => Some(sub),
229 None => {
230 Some(command.clone())
233 }
234 }
235 } else {
236 Some(command.clone())
237 }
238 } else {
239 None
240 }
241 }
242
243 pub fn get_command_from_slice(&self, words: &[String]) -> Option<Command<E, S>> {
244 let mapping = self.mapping.read().unwrap();
245
246 let mut current_command: Option<Command<E, S>> = None;
247
248 for word in words {
249 if let Some(command) = current_command
250 .as_ref()
251 .and_then(|command| command.get_command(word))
252 .or_else(|| mapping.get(word).cloned())
253 {
254 current_command = Some(command)
255 } else {
256 break;
257 }
258 }
259
260 return current_command;
261 }
262
263 pub fn get_command(&self, name: &str) -> Option<Command<E, S>> {
264 self.mapping.read().unwrap().get(name).cloned()
265 }
266
267 pub fn get_commands(&self) -> Vec<Command<E, S>> {
268 self.mapping
269 .read()
270 .unwrap()
271 .clone()
272 .into_iter()
273 .filter(|(name, command)| name == &command.name)
274 .map(|(_, command)| command)
275 .collect()
276 }
277
278 pub fn get_command_parents(&self, command: &Command<E, S>) -> Vec<Command<E, S>> {
279 let mut parents: Vec<Command<E, S>> = Vec::new();
280
281 for parent in &command.parents {
282 if let Some(last_parent) = parents.last() {
283 let child = last_parent.get_command(parent).unwrap();
284 parents.push(child);
285 } else {
286 parents.push(self.get_command(parent).unwrap());
287 }
288 }
289
290 parents
291 }
292}