Skip to main content

tulpje_framework/handler/
command_handler.rs

1use std::{future::Future, pin::Pin};
2
3use twilight_model::channel::message::MessageFlags;
4use twilight_util::builder::message::{ContainerBuilder, TextDisplayBuilder};
5
6use super::super::context::CommandContext;
7
8use crate::{Error, color};
9
10pub(crate) type CommandFunc<T> =
11    fn(CommandContext<T>) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send>>;
12
13#[derive(Clone)]
14pub struct CommandHandler<T: Clone + Send + Sync> {
15    pub module: String,
16    pub name: String,
17    pub func: CommandFunc<T>,
18}
19
20impl<T: Clone + Send + Sync> CommandHandler<T> {
21    #[tracing::instrument(name="command-handler", skip_all, fields(
22        module=self.module,
23        name=self.name
24    ))]
25    pub async fn run(&self, ctx: CommandContext<T>) -> Result<(), Error> {
26        // TODO: More elegant way of handling command errors
27        // TODO: Test if errors work in DMs
28        if let Err(err) = (self.func)(ctx.clone()).await {
29            tracing::error!(
30                "error during command {}, sending reference to client: {}",
31                self.name,
32                err
33            );
34
35            if let Some(chan) = &ctx.event.channel {
36                ctx.client
37                    .create_message(chan.id)
38                    .flags(MessageFlags::IS_COMPONENTS_V2)
39                    .components(&[ContainerBuilder::new()
40                        .accent_color(Some(*color::roles::RED))
41                        .component(
42                            // TODO: Better way to handle extra error info than, whatever this is
43                            TextDisplayBuilder::new(format!(
44                                "### Internal Error\n{}\n**Error Code**\n```{}```",
45                                std::env::var("TULPJE_EXTRA_ERROR_MESSAGE").unwrap_or_default(),
46                                ctx.meta.uuid
47                            ))
48                            .build(),
49                        )
50                        .build()
51                        .into()])
52                    .await?;
53            } else {
54                tracing::warn!(event = ?ctx.event, "channel on event was empty, can't send error");
55            }
56        }
57
58        Ok(())
59    }
60}