use std::{fmt::Debug, sync::Arc}; use futures::future::BoxFuture; use opendal::Operator; use patricia_tree::StringPatriciaMap; use songbird::{ Songbird, driver::{Channels, SampleRate}, }; use tokio_util::sync::CancellationToken; use twilight_model::{ application::{command::Command, interaction::Interaction}, id::{ Id, marker::{ApplicationMarker, CommandMarker, UserMarker}, }, }; use crate::{BotDataManager, GuildVoiceChannelToTextChannel, UserDataManager, VCsWatcher}; pub mod info; pub mod join; pub mod leave; pub mod opt_in; pub mod opt_out; #[derive(Debug, Clone)] pub struct State { pub audio_channels: Channels, pub audio_sample_rate: SampleRate, pub bot_data_manager: BotDataManager, pub cancellation_token: CancellationToken, pub discord_application_id: Id, pub discord_bot_owner_user_id: Id, pub discord_client: Arc, pub discord_info_command_id: Id, pub discord_info_command_name: Arc, pub discord_opt_in_command_id: Id, pub discord_opt_in_command_name: Arc, pub discord_opt_out_command_id: Id, pub discord_opt_out_command_name: Arc, pub discord_user_id: Id, pub discord_voice_channel_corresponding_text_channel: Arc, pub recording_data: Operator, pub songbird: Arc, pub user_data_manager: UserDataManager, pub vcs_watcher: VCsWatcher, } type Return = (); type BoxedHandler = Box BoxFuture<'static, Return>>; fn box_handler(handler: Handler) -> BoxedHandler where Fut: Future + Send + 'static, Handler: Send + Sync + Fn(State, Interaction) -> Fut + 'static, { Box::new(move |state, interaction| Box::pin(handler(state, interaction))) } pub fn all() -> Vec<(&'static Command, BoxedHandler)> { vec![ (&info::COMMAND, box_handler(info::handle)), (&join::COMMAND, box_handler(join::handle)), (&leave::COMMAND, box_handler(leave::handle)), (&opt_in::COMMAND, box_handler(opt_in::handle)), (&opt_out::COMMAND, box_handler(opt_out::handle)), ] } #[derive(Default)] pub struct Router { map: StringPatriciaMap, } impl Router { pub fn add_route(&mut self, name: &str, handler: Handler) where Fut: Future + Send + 'static, Handler: Send + Sync + Fn(State, Interaction) -> Fut + 'static, { self.add_route_already_boxed(name, box_handler(handler)); } fn add_route_already_boxed(&mut self, name: &str, boxed_handler: BoxedHandler) { self.map.insert(name, boxed_handler); } pub async fn handle( &self, state: State, command_name: &str, interaction: Interaction, ) -> Option { let handler = self.map.get(command_name)?; Some(handler(state, interaction).await) } } impl<'a> FromIterator<(&'a Command, BoxedHandler)> for Router { #[inline] fn from_iter>(iter: T) -> Self { let mut this = Self::default(); this.extend(iter); this } } impl<'a> Extend<(&'a Command, BoxedHandler)> for Router { #[inline] fn extend>(&mut self, iter: T) { for (command, boxed_handler) in iter { let name = &command.name; self.add_route_already_boxed(name, boxed_handler); } } }