1use ahash::AHashMap;
2use std::future::Future;
3use std::pin::Pin;
4
5use crate::context::Context;
6
7use crate::error::TitaniumError;
8
9type CommandHandler = Box<
10 dyn Fn(Context) -> Pin<Box<dyn Future<Output = Result<(), TitaniumError>> + Send>> + Send + Sync,
11>;
12type ErrorHandler =
13 Box<dyn Fn(TitaniumError, Context) -> Pin<Box<dyn Future<Output = ()> + Send>> + Send + Sync>;
14
15pub struct Framework {
16 pub commands: AHashMap<String, CommandHandler>,
17 pub on_error: Option<ErrorHandler>,
18}
19
20impl Default for Framework {
21 fn default() -> Self {
22 Self::new()
23 }
24}
25
26impl Framework {
27 pub fn new() -> Self {
28 Self {
29 commands: AHashMap::new(),
30 on_error: None,
31 }
32 }
33
34 pub fn command<F, Fut>(mut self, name: &str, handler: F) -> Self
35 where
36 F: Fn(Context) -> Fut + Send + Sync + 'static,
37 Fut: Future<Output = Result<(), TitaniumError>> + Send + 'static,
38 {
39 self.commands.insert(
40 name.to_string(),
41 Box::new(move |ctx| Box::pin(handler(ctx))),
42 );
43 self
44 }
45
46 pub fn on_error<F, Fut>(mut self, handler: F) -> Self
48 where
49 F: Fn(TitaniumError, Context) -> Fut + Send + Sync + 'static,
50 Fut: Future<Output = ()> + Send + 'static,
51 {
52 self.on_error = Some(Box::new(move |err, ctx| Box::pin(handler(err, ctx))));
53 self
54 }
55
56 pub async fn dispatch(&self, name: &str, ctx: Context) {
58 if let Some(handler) = self.commands.get(name) {
59 let ctx_clone = ctx.clone();
62
63 if let Err(err) = handler(ctx).await {
64 if let Some(error_handler) = &self.on_error {
65 error_handler(err, ctx_clone).await;
66 } else {
67 eprintln!("Command execution failed: {:?}", err);
69 }
70 }
71 }
72 }
73}