Skip to main content

tulpje_framework/
interaction.rs

1use twilight_model::{
2    application::interaction::{
3        InteractionData,
4        application_command::{CommandDataOption, CommandOptionValue},
5    },
6    gateway::payload::incoming::InteractionCreate,
7};
8
9use crate::{Error, Metadata, context};
10
11pub fn parse<T: Clone + Send + Sync>(
12    event: &InteractionCreate,
13    meta: Metadata,
14    ctx: context::Context<T>,
15) -> Result<context::InteractionContext<T>, Error> {
16    match &event.data {
17        Some(InteractionData::ApplicationCommand(command)) => {
18            let (name, options) = extract_command(&command.name, &command.options, &mut Vec::new());
19            Ok(context::InteractionContext::<T>::Command(
20                context::CommandContext::from_context(
21                    meta,
22                    ctx,
23                    event.clone(),
24                    *command.clone(),
25                    name,
26                    options,
27                ),
28            ))
29        }
30        Some(InteractionData::MessageComponent(interaction)) => {
31            Ok(context::InteractionContext::<T>::ComponentInteraction(
32                context::ComponentInteractionContext::from_context(
33                    ctx,
34                    meta,
35                    event.clone(),
36                    *interaction.clone(),
37                ),
38            ))
39        }
40        Some(InteractionData::ModalSubmit(data)) => Ok(context::InteractionContext::<T>::Modal(
41            context::ModalContext::from_context(ctx, meta, event.clone(), *data.clone()),
42        )),
43        Some(_) => Err(format!("unknown interaction type: {:?}", event.kind).into()),
44        None => Err("no interaction data".into()),
45    }
46}
47
48fn extract_command<'a>(
49    name: &'a str,
50    options: &'a [CommandDataOption],
51    parents: &mut Vec<&'a str>,
52) -> (String, &'a [CommandDataOption]) {
53    parents.push(name);
54
55    if let Some((name, options)) = options.iter().find_map(|opt| match opt.value {
56        CommandOptionValue::SubCommand(ref sub_options)
57        | CommandOptionValue::SubCommandGroup(ref sub_options) => Some((&opt.name, sub_options)),
58        _ => None,
59    }) {
60        extract_command(name, options, parents)
61    } else {
62        (parents.join(" "), options)
63    }
64}