Add support for extras, conditionally displaying commands in the help command, and start working on moderation commands
This commit is contained in:
+55
-40
@@ -9,7 +9,7 @@ use twilight_model::gateway::payload::outgoing::update_presence::UpdatePresenceP
|
||||
|
||||
use crate::{
|
||||
framework::{
|
||||
commands::{Command, runner::CommandRunner},
|
||||
commands::{Command, extras::ExtrasGetter, runner::CommandRunner},
|
||||
events::traits::{
|
||||
OnInteractionHandler, OnMessageDeleteHandler, OnMessageEditHandler, OnMessageHandler,
|
||||
OnReadyHandler, OnReconnectHandler, OnServerCreateHandler, OnServerDeleteHandler,
|
||||
@@ -32,7 +32,7 @@ pub enum RuntimeError {
|
||||
|
||||
/// Getter trait for command prefixes.
|
||||
#[async_trait]
|
||||
pub trait PrefixGetter<T> {
|
||||
pub trait PrefixGetter<T, E> {
|
||||
/// Get the command prefixes for the given server and user IDs.
|
||||
///
|
||||
/// The getter must never fail. In case an internal process does, it must fall back to default
|
||||
@@ -49,75 +49,87 @@ pub trait PrefixGetter<T> {
|
||||
/// first one will always be the safest choice.
|
||||
async fn get(
|
||||
&self,
|
||||
runtime: &Runtime<T>,
|
||||
runtime: &Runtime<T, E>,
|
||||
server_id: Option<u64>,
|
||||
user_id: Option<u64>,
|
||||
) -> Vec<String>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PrefixGetter<T> for String {
|
||||
async fn get(&self, _: &Runtime<T>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
|
||||
impl<T, E> PrefixGetter<T, E> for String {
|
||||
async fn get(&self, _: &Runtime<T, E>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
|
||||
vec![self.to_string()]
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> PrefixGetter<T> for &str {
|
||||
async fn get(&self, _: &Runtime<T>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
|
||||
impl<T, E> PrefixGetter<T, E> for &str {
|
||||
async fn get(&self, _: &Runtime<T, E>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
|
||||
vec![self.to_string()]
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Send + Sync + 'static, const N: usize, S: Send + Sync + 'static> PrefixGetter<S> for [T; N]
|
||||
impl<T, const N: usize, S, E> PrefixGetter<S, E> for [T; N]
|
||||
where
|
||||
T: ToString,
|
||||
T: ToString + Send + Sync + 'static,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
async fn get(&self, _: &Runtime<S>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
|
||||
async fn get(&self, _: &Runtime<S, E>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
|
||||
self.iter().map(|s| s.to_string()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<F, Fut, T> PrefixGetter<T> for F
|
||||
impl<F, Fut, T, E> PrefixGetter<T, E> for F
|
||||
where
|
||||
F: Fn() -> Fut + Send + Sync + 'static,
|
||||
Fut: Future<Output = Vec<String>> + Send,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
async fn get(&self, _: &Runtime<T>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
|
||||
async fn get(&self, _: &Runtime<T, E>, _: Option<u64>, _: Option<u64>) -> Vec<String> {
|
||||
(self)().await
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bot<T: Send + Sync> {
|
||||
pub struct Bot<T: Send + Sync, E: Send + Sync = ()> {
|
||||
shard: ShardId,
|
||||
state: Arc<T>,
|
||||
presence: Option<UpdatePresencePayload>,
|
||||
prefixes: Arc<dyn PrefixGetter<T> + Send + Sync>,
|
||||
prefixes: Arc<dyn PrefixGetter<T, E> + Send + Sync>,
|
||||
intents: Intents,
|
||||
extras: Arc<dyn ExtrasGetter<T, Extras = E>>,
|
||||
cached_resource_types: Vec<ResourceType>,
|
||||
commands: Vec<Arc<dyn Command<T>>>,
|
||||
components: Vec<Arc<dyn Component<T>>>,
|
||||
on_ready_handlers: Vec<Arc<dyn OnReadyHandler<T>>>,
|
||||
on_reconnect_handlers: Vec<Arc<dyn OnReconnectHandler<T>>>,
|
||||
on_interaction_handlers: Vec<Arc<dyn OnInteractionHandler<T>>>,
|
||||
on_message_handlers: Vec<Arc<dyn OnMessageHandler<T>>>,
|
||||
on_message_edit_handlers: Vec<Arc<dyn OnMessageEditHandler<T>>>,
|
||||
on_message_delete_handlers: Vec<Arc<dyn OnMessageDeleteHandler<T>>>,
|
||||
on_server_create_handlers: Vec<Arc<dyn OnServerCreateHandler<T>>>,
|
||||
on_server_update_handlers: Vec<Arc<dyn OnServerUpdateHandler<T>>>,
|
||||
on_server_delete_handlers: Vec<Arc<dyn OnServerDeleteHandler<T>>>,
|
||||
commands: Vec<Arc<dyn Command<T, E>>>,
|
||||
components: Vec<Arc<dyn Component<T, E>>>,
|
||||
on_ready_handlers: Vec<Arc<dyn OnReadyHandler<T, E>>>,
|
||||
on_reconnect_handlers: Vec<Arc<dyn OnReconnectHandler<T, E>>>,
|
||||
on_interaction_handlers: Vec<Arc<dyn OnInteractionHandler<T, E>>>,
|
||||
on_message_handlers: Vec<Arc<dyn OnMessageHandler<T, E>>>,
|
||||
on_message_edit_handlers: Vec<Arc<dyn OnMessageEditHandler<T, E>>>,
|
||||
on_message_delete_handlers: Vec<Arc<dyn OnMessageDeleteHandler<T, E>>>,
|
||||
on_server_create_handlers: Vec<Arc<dyn OnServerCreateHandler<T, E>>>,
|
||||
on_server_update_handlers: Vec<Arc<dyn OnServerUpdateHandler<T, E>>>,
|
||||
on_server_delete_handlers: Vec<Arc<dyn OnServerDeleteHandler<T, E>>>,
|
||||
}
|
||||
|
||||
impl<T: 'static + Send + Sync> Bot<T> {
|
||||
pub fn new(state: T, prefixes: impl PrefixGetter<T> + Send + Sync + 'static) -> Self {
|
||||
impl<T, E> Bot<T, E>
|
||||
where
|
||||
T: 'static + Send + Sync,
|
||||
E: 'static + Send + Sync,
|
||||
{
|
||||
pub fn new(
|
||||
state: T,
|
||||
prefixes: impl PrefixGetter<T, E> + Send + Sync + 'static,
|
||||
extras: impl ExtrasGetter<T, Extras = E> + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
shard: ShardId::new(0, 1),
|
||||
state: Arc::new(state),
|
||||
presence: None,
|
||||
prefixes: Arc::new(prefixes),
|
||||
intents: Intents::empty(),
|
||||
extras: Arc::new(extras),
|
||||
cached_resource_types: Vec::new(),
|
||||
commands: Vec::new(),
|
||||
components: Vec::new(),
|
||||
@@ -148,12 +160,12 @@ impl<T: 'static + Send + Sync> Bot<T> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn command(mut self, command: impl Command<T> + 'static) -> Self {
|
||||
pub fn command(mut self, command: impl Command<T, E> + 'static) -> Self {
|
||||
self.commands.push(Arc::new(command));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn component(mut self, component: impl Component<T> + 'static) -> Self {
|
||||
pub fn component(mut self, component: impl Component<T, E> + 'static) -> Self {
|
||||
self.components.push(Arc::new(component));
|
||||
self
|
||||
}
|
||||
@@ -166,50 +178,53 @@ impl<T: 'static + Send + Sync> Bot<T> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_ready(mut self, handler: impl OnReadyHandler<T> + 'static) -> Self {
|
||||
pub fn on_ready(mut self, handler: impl OnReadyHandler<T, E> + 'static) -> Self {
|
||||
self.on_ready_handlers.push(Arc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_reconnect(mut self, handler: impl OnReconnectHandler<T> + 'static) -> Self {
|
||||
pub fn on_reconnect(mut self, handler: impl OnReconnectHandler<T, E> + 'static) -> Self {
|
||||
self.on_reconnect_handlers.push(Arc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn on_interaction(mut self, handler: impl OnInteractionHandler<T> + 'static) -> Self {
|
||||
pub fn on_interaction(mut self, handler: impl OnInteractionHandler<T, E> + 'static) -> Self {
|
||||
self.on_interaction_handlers.push(Arc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_message(mut self, handler: impl OnMessageHandler<T> + 'static) -> Self {
|
||||
pub fn on_message(mut self, handler: impl OnMessageHandler<T, E> + 'static) -> Self {
|
||||
self.on_message_handlers.push(Arc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn on_message_edit(mut self, handler: impl OnMessageEditHandler<T> + 'static) -> Self {
|
||||
pub fn on_message_edit(mut self, handler: impl OnMessageEditHandler<T, E> + 'static) -> Self {
|
||||
self.on_message_edit_handlers.push(Arc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn on_message_delete(mut self, handler: impl OnMessageDeleteHandler<T> + 'static) -> Self {
|
||||
pub fn on_message_delete(
|
||||
mut self,
|
||||
handler: impl OnMessageDeleteHandler<T, E> + 'static,
|
||||
) -> Self {
|
||||
self.on_message_delete_handlers.push(Arc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_server_create(mut self, handler: impl OnServerCreateHandler<T> + 'static) -> Self {
|
||||
pub fn on_server_create(mut self, handler: impl OnServerCreateHandler<T, E> + 'static) -> Self {
|
||||
self.on_server_create_handlers.push(Arc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_server_update(mut self, handler: impl OnServerUpdateHandler<T> + 'static) -> Self {
|
||||
pub fn on_server_update(mut self, handler: impl OnServerUpdateHandler<T, E> + 'static) -> Self {
|
||||
self.on_server_update_handlers.push(Arc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_server_delete(mut self, handler: impl OnServerDeleteHandler<T> + 'static) -> Self {
|
||||
pub fn on_server_delete(mut self, handler: impl OnServerDeleteHandler<T, E> + 'static) -> Self {
|
||||
self.on_server_delete_handlers.push(Arc::new(handler));
|
||||
self
|
||||
}
|
||||
@@ -302,7 +317,7 @@ impl<T: 'static + Send + Sync> Bot<T> {
|
||||
Event::InteractionCreate(interaction) => {
|
||||
for handler in &task_bot.on_interaction_handlers {
|
||||
handler
|
||||
.on_interaction(&interaction, task_rt.clone())
|
||||
.on_interaction(&interaction, task_rt.clone(), task_bot.extras.clone())
|
||||
.await
|
||||
.inspect_err(
|
||||
|e| log::error!("An error occurred while handling on interaction for {handler:?}! {e:?}")
|
||||
@@ -315,7 +330,7 @@ impl<T: 'static + Send + Sync> Bot<T> {
|
||||
log::trace!("Running {handler:?}");
|
||||
|
||||
handler
|
||||
.on_message(&message, task_rt.clone())
|
||||
.on_message(&message, task_rt.clone(), task_bot.extras.clone())
|
||||
.await
|
||||
.inspect_err(
|
||||
|e| log::error!("An error occurred while handling on message for {handler:?}! {e:?}")
|
||||
|
||||
@@ -5,6 +5,8 @@ use std::{
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::framework::commands::context::CommandContext;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ArgumentParsingError {
|
||||
#[error("This argument was missing in the arguments array")]
|
||||
@@ -12,14 +14,23 @@ pub enum ArgumentParsingError {
|
||||
|
||||
#[error("An argument was there but it could not be parsed into the specified value")]
|
||||
InvalidArgument,
|
||||
|
||||
#[error("A database operation failed")]
|
||||
DatabaseFailed,
|
||||
}
|
||||
|
||||
pub trait FromArguments: Sized {
|
||||
fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError>;
|
||||
pub trait FromArguments<S, E>: Sized {
|
||||
async fn from_args<'a>(
|
||||
args: &'a str,
|
||||
ctx: &'a CommandContext<'_, S, E>,
|
||||
) -> Result<(Self, &'a str), ArgumentParsingError>;
|
||||
}
|
||||
|
||||
impl FromArguments for String {
|
||||
fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError> {
|
||||
impl<S, E> FromArguments<S, E> for String {
|
||||
async fn from_args<'a>(
|
||||
args: &'a str,
|
||||
_ctx: &'a CommandContext<'_, S, E>,
|
||||
) -> Result<(Self, &'a str), ArgumentParsingError> {
|
||||
if !args.is_empty() {
|
||||
match args.split_once(" ") {
|
||||
Some((arg, rest)) => Ok((arg.to_string(), rest)),
|
||||
@@ -37,8 +48,11 @@ impl FromArguments for String {
|
||||
/// Parsing this argument type never fails.
|
||||
pub struct GreedyString(pub String);
|
||||
|
||||
impl FromArguments for GreedyString {
|
||||
fn from_args<'a>(args: &str) -> Result<(Self, &str), ArgumentParsingError> {
|
||||
impl<S, E> FromArguments<S, E> for GreedyString {
|
||||
async fn from_args<'a>(
|
||||
args: &'a str,
|
||||
_ctx: &'a CommandContext<'_, S, E>,
|
||||
) -> Result<(Self, &'a str), ArgumentParsingError> {
|
||||
let value = GreedyString(args.to_string());
|
||||
|
||||
Ok((value, ""))
|
||||
@@ -87,8 +101,11 @@ impl fmt::Display for NeedyString {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArguments for NeedyString {
|
||||
fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError> {
|
||||
impl<S, E> FromArguments<S, E> for NeedyString {
|
||||
async fn from_args<'a>(
|
||||
args: &'a str,
|
||||
_ctx: &'a CommandContext<'_, S, E>,
|
||||
) -> Result<(Self, &'a str), ArgumentParsingError> {
|
||||
if !args.is_empty() {
|
||||
match args.split_once(" ") {
|
||||
Some((arg, rest)) => Ok((Self(arg.to_string()), rest)),
|
||||
@@ -122,8 +139,11 @@ impl fmt::Display for NeedyGreedyString {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArguments for NeedyGreedyString {
|
||||
fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError> {
|
||||
impl<S, E> FromArguments<S, E> for NeedyGreedyString {
|
||||
async fn from_args<'a>(
|
||||
args: &'a str,
|
||||
_ctx: &'a CommandContext<'_, S, E>,
|
||||
) -> Result<(Self, &'a str), ArgumentParsingError> {
|
||||
if !args.is_empty() {
|
||||
Ok((Self(args.to_string()), ""))
|
||||
} else {
|
||||
@@ -132,8 +152,11 @@ impl FromArguments for NeedyGreedyString {
|
||||
}
|
||||
}
|
||||
|
||||
impl FromArguments for bool {
|
||||
fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError> {
|
||||
impl<S, E> FromArguments<S, E> for bool {
|
||||
async fn from_args<'a>(
|
||||
args: &'a str,
|
||||
_ctx: &'a CommandContext<'_, S, E>,
|
||||
) -> Result<(Self, &'a str), ArgumentParsingError> {
|
||||
let arg: &str;
|
||||
let rest: &str;
|
||||
|
||||
@@ -156,73 +179,86 @@ impl FromArguments for bool {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromArguments for Option<T>
|
||||
impl<T, S, E> FromArguments<S, E> for Option<T>
|
||||
where
|
||||
T: FromArguments,
|
||||
T: FromArguments<S, E>,
|
||||
{
|
||||
fn from_args(args: &str) -> Result<(Self, &str), ArgumentParsingError> {
|
||||
match T::from_args(args) {
|
||||
async fn from_args<'a>(
|
||||
args: &'a str,
|
||||
_ctx: &'a CommandContext<'_, S, E>,
|
||||
) -> Result<(Self, &'a str), ArgumentParsingError> {
|
||||
match T::from_args(args, _ctx).await {
|
||||
Ok((result, rest)) => Ok((Some(result), rest)),
|
||||
Err(_) => Ok((None, args)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ParseArguments: Sized {
|
||||
fn parse(args: &str) -> Result<Self, ArgumentParsingError>;
|
||||
}
|
||||
pub struct Arg<T>(pub T);
|
||||
|
||||
impl ParseArguments for () {
|
||||
fn parse(_: &str) -> Result<Self, ArgumentParsingError> {
|
||||
Ok(())
|
||||
impl<T> Deref for Arg<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> ParseArguments for A
|
||||
where
|
||||
A: FromArguments,
|
||||
{
|
||||
fn parse(args: &str) -> Result<Self, ArgumentParsingError> {
|
||||
let (a, _) = A::from_args(args)?;
|
||||
|
||||
Ok(a)
|
||||
impl<T> DerefMut for Arg<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<A> ParseArguments for (A,)
|
||||
pub trait ParseArguments<S, E>: Sized {
|
||||
async fn parse(args: &str, ctx: &CommandContext<S, E>) -> Result<Self, ArgumentParsingError>;
|
||||
}
|
||||
|
||||
impl<T, S, E> ParseArguments<S, E> for Arg<T>
|
||||
where
|
||||
A: FromArguments,
|
||||
T: FromArguments<S, E>,
|
||||
{
|
||||
fn parse(args: &str) -> Result<Self, ArgumentParsingError> {
|
||||
let (a, _) = A::from_args(args)?;
|
||||
async fn parse(args: &str, ctx: &CommandContext<'_, S, E>) -> Result<Self, ArgumentParsingError> {
|
||||
let (value, _) = T::from_args(args, ctx).await?;
|
||||
|
||||
Ok(Arg(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, S, E> ParseArguments<S, E> for (A,)
|
||||
where
|
||||
A: FromArguments<S, E>,
|
||||
{
|
||||
async fn parse(args: &str, ctx: &CommandContext<'_, S, E>) -> Result<Self, ArgumentParsingError> {
|
||||
let (a, _) = A::from_args(args, ctx).await?;
|
||||
|
||||
Ok((a,))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> ParseArguments for (A, B)
|
||||
impl<A, B, S, E> ParseArguments<S, E> for (A, B)
|
||||
where
|
||||
A: FromArguments,
|
||||
B: FromArguments,
|
||||
A: FromArguments<S, E>,
|
||||
B: FromArguments<S, E>,
|
||||
{
|
||||
fn parse(args: &str) -> Result<Self, ArgumentParsingError> {
|
||||
let (a, args) = A::from_args(args)?;
|
||||
let (b, _) = B::from_args(args)?;
|
||||
async fn parse(args: &str, ctx: &CommandContext<'_, S, E>) -> Result<Self, ArgumentParsingError> {
|
||||
let (a, args) = A::from_args(args, ctx).await?;
|
||||
let (b, _) = B::from_args(args, ctx).await?;
|
||||
|
||||
Ok((a, b))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B, C> ParseArguments for (A, B, C)
|
||||
impl<A, B, C, S, E> ParseArguments<S, E> for (A, B, C)
|
||||
where
|
||||
A: FromArguments,
|
||||
B: FromArguments,
|
||||
C: FromArguments,
|
||||
A: FromArguments<S, E>,
|
||||
B: FromArguments<S, E>,
|
||||
C: FromArguments<S, E>,
|
||||
{
|
||||
fn parse(args: &str) -> Result<Self, ArgumentParsingError> {
|
||||
let (a, args) = A::from_args(args)?;
|
||||
let (b, args) = B::from_args(args)?;
|
||||
let (c, _) = C::from_args(args)?;
|
||||
async fn parse(args: &str, ctx: &CommandContext<'_, S, E>) -> Result<Self, ArgumentParsingError> {
|
||||
let (a, args) = A::from_args(args, ctx).await?;
|
||||
let (b, args) = B::from_args(args, ctx).await?;
|
||||
let (c, _) = C::from_args(args, ctx).await?;
|
||||
|
||||
Ok((a, b, c))
|
||||
}
|
||||
|
||||
@@ -4,21 +4,33 @@ use twilight_model::gateway::payload::incoming::MessageCreate;
|
||||
|
||||
use crate::framework::{commands::messages::MessageSender, runtime::Runtime};
|
||||
|
||||
pub struct CommandContext<'a, T> {
|
||||
pub struct CommandContext<'a, T, E> {
|
||||
pub event: &'a MessageCreate,
|
||||
pub rt: Arc<Runtime<T>>,
|
||||
pub rt: Arc<Runtime<T, E>>,
|
||||
pub prefix: &'a str,
|
||||
pub extras: E,
|
||||
}
|
||||
|
||||
impl<'a, T> CommandContext<'a, T>
|
||||
impl<'a, T, E> CommandContext<'a, T, E>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
pub fn new(event: &'a MessageCreate, rt: Arc<Runtime<T>>, prefix: &'a str) -> Self {
|
||||
Self { event, rt, prefix }
|
||||
pub fn new(
|
||||
event: &'a MessageCreate,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
prefix: &'a str,
|
||||
extras: E,
|
||||
) -> Self {
|
||||
Self {
|
||||
event,
|
||||
rt,
|
||||
prefix,
|
||||
extras,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send(&self) -> MessageSender<T> {
|
||||
pub fn send(&self) -> MessageSender<T, E> {
|
||||
MessageSender::new(self.event.channel_id, self.rt.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
use std::error::Error;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use twilight_model::user::User;
|
||||
|
||||
use crate::framework::runtime::Runtime;
|
||||
|
||||
#[async_trait]
|
||||
pub trait ExtrasGetter<S>: Send + Sync {
|
||||
type Extras;
|
||||
|
||||
async fn get_extra(
|
||||
&self,
|
||||
user: &User,
|
||||
rt: &Runtime<S, Self::Extras>,
|
||||
) -> Result<Self::Extras, Box<dyn Error>>;
|
||||
}
|
||||
|
||||
pub struct DefaultExtraGetter;
|
||||
|
||||
#[async_trait]
|
||||
impl<S> ExtrasGetter<S> for DefaultExtraGetter {
|
||||
type Extras = ();
|
||||
|
||||
async fn get_extra(
|
||||
&self,
|
||||
_user: &User,
|
||||
_rt: &Runtime<S, Self::Extras>,
|
||||
) -> Result<Self::Extras, Box<dyn Error>> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -23,23 +23,24 @@ use crate::framework::{
|
||||
runtime::Runtime,
|
||||
};
|
||||
|
||||
pub struct MessageSender<T> {
|
||||
pub struct MessageSender<T, E> {
|
||||
channel_id: Id<ChannelMarker>,
|
||||
|
||||
rt: Arc<Runtime<T>>,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
|
||||
content: Option<String>,
|
||||
embeds: Vec<Embed>,
|
||||
|
||||
// Row index, component
|
||||
components: Vec<(u8, Arc<dyn Component<T>>)>,
|
||||
components: Vec<(u8, Arc<dyn Component<T, E>>)>,
|
||||
}
|
||||
|
||||
impl<T> MessageSender<T>
|
||||
impl<T, E> MessageSender<T, E>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
pub fn new(channel_id: Id<ChannelMarker>, rt: Arc<Runtime<T>>) -> Self {
|
||||
pub fn new(channel_id: Id<ChannelMarker>, rt: Arc<Runtime<T, E>>) -> Self {
|
||||
Self {
|
||||
channel_id,
|
||||
rt,
|
||||
@@ -61,7 +62,7 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn component(mut self, component: impl Component<T> + 'static, row: u8) -> Self {
|
||||
pub fn component(mut self, component: impl Component<T, E> + 'static, row: u8) -> Self {
|
||||
self.components.push((row, Arc::new(component)));
|
||||
|
||||
self
|
||||
@@ -120,7 +121,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> IntoFuture for MessageSender<T> {
|
||||
impl<T: Send + Sync + 'static, E: Send + Sync + 'static> IntoFuture for MessageSender<T, E> {
|
||||
type Output = Result<Response<Message>, Error>;
|
||||
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
|
||||
|
||||
@@ -129,27 +130,28 @@ impl<T: Send + Sync + 'static> IntoFuture for MessageSender<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OriginalMessageUpdater<T> {
|
||||
pub struct OriginalMessageUpdater<T, E> {
|
||||
interaction_id: Id<InteractionMarker>,
|
||||
interaction_token: String,
|
||||
|
||||
rt: Arc<Runtime<T>>,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
|
||||
content: Option<String>,
|
||||
embeds: Vec<Embed>,
|
||||
|
||||
// Row index, component
|
||||
components: Vec<(u8, Arc<dyn Component<T>>)>,
|
||||
components: Vec<(u8, Arc<dyn Component<T, E>>)>,
|
||||
}
|
||||
|
||||
impl<T> OriginalMessageUpdater<T>
|
||||
impl<T, E> OriginalMessageUpdater<T, E>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
pub fn new(
|
||||
interaction_id: Id<InteractionMarker>,
|
||||
interaction_token: String,
|
||||
rt: Arc<Runtime<T>>,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
interaction_id,
|
||||
@@ -174,7 +176,7 @@ where
|
||||
self
|
||||
}
|
||||
|
||||
pub fn component(mut self, component: impl Component<T> + 'static, row: u8) -> Self {
|
||||
pub fn component(mut self, component: impl Component<T, E> + 'static, row: u8) -> Self {
|
||||
self.components.push((row, Arc::new(component)));
|
||||
|
||||
self
|
||||
@@ -245,7 +247,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> IntoFuture for OriginalMessageUpdater<T> {
|
||||
impl<T: Send + Sync + 'static, E: Send + Sync + 'static> IntoFuture
|
||||
for OriginalMessageUpdater<T, E>
|
||||
{
|
||||
type Output = Result<Response<EmptyBody>, Error>;
|
||||
type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send>>;
|
||||
|
||||
|
||||
@@ -5,12 +5,13 @@ use deadpool_redis::{cluster::PoolError, redis::RedisError};
|
||||
use thiserror::Error;
|
||||
use twilight_http::response::DeserializeBodyError;
|
||||
|
||||
use crate::framework::commands::{
|
||||
use crate::framework::{commands::{
|
||||
arguments::Argument, context::CommandContext, permissions::Permission,
|
||||
};
|
||||
}, runtime::Runtime};
|
||||
|
||||
pub mod arguments;
|
||||
pub mod context;
|
||||
pub mod extras;
|
||||
pub mod messages;
|
||||
pub mod permissions;
|
||||
pub mod runner;
|
||||
@@ -21,7 +22,7 @@ pub enum CommandError {
|
||||
MessageSendingFailed,
|
||||
|
||||
#[error("A database query failed")]
|
||||
DatabaseQueryFailed,
|
||||
DatabaseFailed,
|
||||
|
||||
#[error("A database operation failed due to an inconsistent state")]
|
||||
DatabaseInconsistentState,
|
||||
@@ -35,9 +36,6 @@ pub enum CommandError {
|
||||
#[error(transparent)]
|
||||
DiscordDeserializationFailed(#[from] DeserializeBodyError),
|
||||
|
||||
#[error("The cache's state was inconsistent.")]
|
||||
CacheStateInconsistent,
|
||||
|
||||
#[error(transparent)]
|
||||
RedisPoolFailed(#[from] PoolError),
|
||||
|
||||
@@ -46,21 +44,29 @@ pub enum CommandError {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Command<T>: Send + Sync + Debug {
|
||||
pub trait Command<T, E>: Send + Sync + Debug {
|
||||
fn name(&self) -> &'static str;
|
||||
|
||||
fn aliases(&self) -> &'static [&'static str] {
|
||||
&[]
|
||||
}
|
||||
|
||||
fn description(&self) -> &'static str {
|
||||
"A Payphone command."
|
||||
}
|
||||
|
||||
fn arguments(&self) -> &'static [Argument] {
|
||||
&[]
|
||||
}
|
||||
fn permissions(&self) -> Vec<Box<dyn Permission<T> + Send + Sync + 'static>> {
|
||||
|
||||
fn permissions(&self) -> Vec<Box<dyn Permission<T, E> + Send + Sync + 'static>> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn show_in_help(&self, rt: &Runtime<T, E>, extras: &E) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Returns the command name + all its aliases.
|
||||
///
|
||||
/// Returns:
|
||||
@@ -71,7 +77,7 @@ pub trait Command<T>: Send + Sync + Debug {
|
||||
all
|
||||
}
|
||||
|
||||
async fn execute(&self, ctx: CommandContext<'_, T>, args: &str) -> Result<(), CommandError>;
|
||||
async fn execute(&self, ctx: CommandContext<'_, T, E>, args: &str) -> Result<(), CommandError>;
|
||||
}
|
||||
|
||||
pub struct CommandParts<'a> {
|
||||
|
||||
@@ -5,10 +5,10 @@ use async_trait::async_trait;
|
||||
use crate::framework::commands::{CommandError, context::CommandContext};
|
||||
|
||||
#[async_trait]
|
||||
pub trait Permission<S: Send + Sync + 'static>: Debug {
|
||||
async fn check(&self, ctx: &CommandContext<S>) -> Result<bool, CommandError>;
|
||||
pub trait Permission<S: Send + Sync + 'static, E>: Debug {
|
||||
async fn check(&self, ctx: &CommandContext<S, E>) -> Result<bool, CommandError>;
|
||||
|
||||
async fn on_handle_denied(&self, _ctx: &CommandContext<S>) -> Result<(), CommandError> {
|
||||
async fn on_handle_denied(&self, _ctx: &CommandContext<S, E>) -> Result<(), CommandError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use async_trait::async_trait;
|
||||
use twilight_model::gateway::payload::incoming::MessageCreate;
|
||||
|
||||
use crate::framework::{
|
||||
commands::{context::CommandContext, get_command_parts},
|
||||
commands::{context::CommandContext, extras::ExtrasGetter, get_command_parts},
|
||||
events::traits::{EventResult, OnMessageHandler},
|
||||
runtime::Runtime,
|
||||
};
|
||||
@@ -13,8 +13,17 @@ use crate::framework::{
|
||||
pub struct CommandRunner;
|
||||
|
||||
#[async_trait]
|
||||
impl<T: Send + Sync + 'static> OnMessageHandler<T> for CommandRunner {
|
||||
async fn on_message(&self, event: &MessageCreate, rt: Arc<Runtime<T>>) -> EventResult {
|
||||
impl<T, E> OnMessageHandler<T, E> for CommandRunner
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
async fn on_message(
|
||||
&self,
|
||||
event: &MessageCreate,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
extras: Arc<dyn ExtrasGetter<T, Extras = E>>,
|
||||
) -> EventResult {
|
||||
if event.author.bot || event.author.system.unwrap_or(false) {
|
||||
return Ok(());
|
||||
}
|
||||
@@ -31,7 +40,12 @@ impl<T: Send + Sync + 'static> OnMessageHandler<T> for CommandRunner {
|
||||
});
|
||||
|
||||
if let Some(command) = command {
|
||||
let ctx = CommandContext::new(event, rt.clone(), &prefixes[0]);
|
||||
let extras = extras
|
||||
.get_extra(&event.author, &rt)
|
||||
.await
|
||||
.inspect_err(|e| log::error!("Failed to get extras: {e}"))?;
|
||||
|
||||
let ctx = CommandContext::new(event, rt.clone(), &prefixes[0], extras);
|
||||
|
||||
for permission in command.permissions() {
|
||||
if !permission
|
||||
|
||||
@@ -6,78 +6,98 @@ use twilight_model::gateway::payload::incoming::{
|
||||
MessageUpdate, Ready,
|
||||
};
|
||||
|
||||
use crate::framework::runtime::Runtime;
|
||||
use crate::framework::{commands::extras::ExtrasGetter, runtime::Runtime};
|
||||
|
||||
pub type EventResult = Result<(), Box<dyn Error>>;
|
||||
|
||||
#[async_trait]
|
||||
pub trait OnReadyHandler<T>: Send + Sync + Debug
|
||||
pub trait OnReadyHandler<T, E>: Send + Sync + Debug
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
async fn on_ready(&self, event: &Ready, rt: Arc<Runtime<T>>) -> EventResult;
|
||||
async fn on_ready(&self, event: &Ready, rt: Arc<Runtime<T, E>>) -> EventResult;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait OnReconnectHandler<T>: Send + Sync + Debug
|
||||
pub trait OnReconnectHandler<T, E>: Send + Sync + Debug
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
async fn on_reconnect(&self, rt: Arc<Runtime<T>>) -> EventResult;
|
||||
async fn on_reconnect(&self, rt: Arc<Runtime<T, E>>) -> EventResult;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait OnInteractionHandler<T>: Send + Sync + Debug
|
||||
pub trait OnInteractionHandler<T, E>: Send + Sync + Debug
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
async fn on_interaction(&self, event: &InteractionCreate, rt: Arc<Runtime<T>>) -> EventResult;
|
||||
async fn on_interaction(
|
||||
&self,
|
||||
event: &InteractionCreate,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
extras: Arc<dyn ExtrasGetter<T, Extras = E>>,
|
||||
) -> EventResult;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait OnMessageHandler<T>: Send + Sync + Debug
|
||||
pub trait OnMessageHandler<T, E>: Send + Sync + Debug
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
async fn on_message(&self, event: &MessageCreate, rt: Arc<Runtime<T>>) -> EventResult;
|
||||
async fn on_message(
|
||||
&self,
|
||||
event: &MessageCreate,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
extras: Arc<dyn ExtrasGetter<T, Extras = E>>,
|
||||
) -> EventResult;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait OnMessageEditHandler<T>: Send + Sync + Debug
|
||||
pub trait OnMessageEditHandler<T, E>: Send + Sync + Debug
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
async fn on_message_edit(&self, event: &MessageUpdate, rt: Arc<Runtime<T>>) -> EventResult;
|
||||
async fn on_message_edit(&self, event: &MessageUpdate, rt: Arc<Runtime<T, E>>) -> EventResult;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait OnMessageDeleteHandler<T>: Send + Sync + Debug
|
||||
pub trait OnMessageDeleteHandler<T, E>: Send + Sync + Debug
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
async fn on_message_delete(&self, event: &MessageDelete, rt: Arc<Runtime<T>>) -> EventResult;
|
||||
async fn on_message_delete(&self, event: &MessageDelete, rt: Arc<Runtime<T, E>>)
|
||||
-> EventResult;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait OnServerCreateHandler<T>: Send + Sync + Debug
|
||||
pub trait OnServerCreateHandler<T, E>: Send + Sync + Debug
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
async fn on_server_create(&self, event: &GuildCreate, rt: Arc<Runtime<T>>) -> EventResult;
|
||||
async fn on_server_create(&self, event: &GuildCreate, rt: Arc<Runtime<T, E>>) -> EventResult;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait OnServerUpdateHandler<T>: Send + Sync + Debug
|
||||
pub trait OnServerUpdateHandler<T, E>: Send + Sync + Debug
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
async fn on_server_update(&self, event: &GuildUpdate, rt: Arc<Runtime<T>>) -> EventResult;
|
||||
async fn on_server_update(&self, event: &GuildUpdate, rt: Arc<Runtime<T, E>>) -> EventResult;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait OnServerDeleteHandler<T>: Send + Sync + Debug
|
||||
pub trait OnServerDeleteHandler<T, E>: Send + Sync + Debug
|
||||
where
|
||||
T: Send + Sync,
|
||||
E: Send + Sync,
|
||||
{
|
||||
async fn on_server_delete(&self, event: &GuildDelete, rt: Arc<Runtime<T>>) -> EventResult;
|
||||
async fn on_server_delete(&self, event: &GuildDelete, rt: Arc<Runtime<T, E>>) -> EventResult;
|
||||
}
|
||||
|
||||
@@ -8,20 +8,20 @@ use twilight_model::channel::message::{
|
||||
|
||||
use crate::framework::interactions::{InteractionError, context::InteractionContext};
|
||||
|
||||
type ComponentWithID<T> = (Option<String>, Arc<dyn Component<T>>);
|
||||
type ComponentWithID<T, E> = (Option<String>, Arc<dyn Component<T, E>>);
|
||||
|
||||
pub struct ActionRow<T> {
|
||||
components: Vec<ComponentWithID<T>>,
|
||||
pub struct ActionRow<T, E> {
|
||||
components: Vec<ComponentWithID<T, E>>,
|
||||
}
|
||||
|
||||
impl<T> ActionRow<T> {
|
||||
pub fn new(components: &[ComponentWithID<T>]) -> Self {
|
||||
impl<T, E> ActionRow<T, E> {
|
||||
pub fn new(components: &[ComponentWithID<T, E>]) -> Self {
|
||||
Self {
|
||||
components: components.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, id: Option<String>, component: Arc<dyn Component<T>>) {
|
||||
pub fn add(&mut self, id: Option<String>, component: Arc<dyn Component<T, E>>) {
|
||||
self.components.push((id, component));
|
||||
}
|
||||
|
||||
@@ -41,19 +41,21 @@ impl<T> ActionRow<T> {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Component<T>: Send + Sync + Debug {
|
||||
pub trait Component<T, E>: Send + Sync + Debug {
|
||||
fn custom_id(&self) -> Option<String> {
|
||||
Some(String::from("component"))
|
||||
}
|
||||
fn build(&self, id: Option<String>) -> TwilightComponent;
|
||||
|
||||
async fn execute(&self, ctx: InteractionContext<T>) -> Result<(), InteractionError>;
|
||||
async fn execute(&self, ctx: InteractionContext<T, E>) -> Result<(), InteractionError>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T, S: Send + Sync + 'static> Component<S> for T
|
||||
impl<T, S, E> Component<S, E> for T
|
||||
where
|
||||
T: Button<S>,
|
||||
T: Button<S, E>,
|
||||
S: Send + Sync + 'static,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
fn custom_id(&self) -> Option<String> {
|
||||
Button::id(self)
|
||||
@@ -75,13 +77,17 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
async fn execute(&self, ctx: InteractionContext<S>) -> Result<(), InteractionError> {
|
||||
async fn execute(&self, ctx: InteractionContext<S, E>) -> Result<(), InteractionError> {
|
||||
self.on_press(ctx).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait Button<S: Send + Sync + 'static>: Send + Sync + Debug {
|
||||
pub trait Button<S, E>: Send + Sync + Debug
|
||||
where
|
||||
S: Send + Sync + 'static,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
fn id(&self) -> Option<String> {
|
||||
if self.url().is_none() {
|
||||
Some(String::from("Button"))
|
||||
@@ -99,7 +105,7 @@ pub trait Button<S: Send + Sync + 'static>: Send + Sync + Debug {
|
||||
None
|
||||
}
|
||||
|
||||
async fn on_press(&self, ctx: InteractionContext<S>) -> Result<(), InteractionError> {
|
||||
async fn on_press(&self, ctx: InteractionContext<S, E>) -> Result<(), InteractionError> {
|
||||
ctx.defer().await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,15 +10,26 @@ use crate::framework::{
|
||||
commands::messages::OriginalMessageUpdater, interactions::InteractionError, runtime::Runtime,
|
||||
};
|
||||
|
||||
pub struct InteractionContext<T> {
|
||||
pub struct InteractionContext<T, E> {
|
||||
pub event: InteractionCreate,
|
||||
pub rt: Arc<Runtime<T>>,
|
||||
pub rt: Arc<Runtime<T, E>>,
|
||||
pub prefix: String,
|
||||
pub extras: E,
|
||||
}
|
||||
|
||||
impl<T> InteractionContext<T> {
|
||||
pub fn new(event: InteractionCreate, rt: Arc<Runtime<T>>, prefix: String) -> Self {
|
||||
Self { event, rt, prefix }
|
||||
impl<T, E> InteractionContext<T, E> {
|
||||
pub fn new(
|
||||
event: InteractionCreate,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
prefix: String,
|
||||
extras: E,
|
||||
) -> Self {
|
||||
Self {
|
||||
event,
|
||||
rt,
|
||||
prefix,
|
||||
extras,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn defer(&self) -> Result<(), InteractionError> {
|
||||
@@ -39,7 +50,7 @@ impl<T> InteractionContext<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn original_message(&self) -> Option<OriginalMessage<T>> {
|
||||
pub fn original_message(&self) -> Option<OriginalMessage<T, E>> {
|
||||
self.event.message.as_ref().map(|_| OriginalMessage {
|
||||
interaction_id: self.event.id,
|
||||
interaction_token: self.event.token.clone(),
|
||||
@@ -48,17 +59,18 @@ impl<T> InteractionContext<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OriginalMessage<T> {
|
||||
pub struct OriginalMessage<T, E> {
|
||||
interaction_id: Id<InteractionMarker>,
|
||||
interaction_token: String,
|
||||
rt: Arc<Runtime<T>>,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
}
|
||||
|
||||
impl<T> OriginalMessage<T>
|
||||
impl<T, E> OriginalMessage<T, E>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
pub fn edit(&self) -> OriginalMessageUpdater<T> {
|
||||
pub fn edit(&self) -> OriginalMessageUpdater<T, E> {
|
||||
OriginalMessageUpdater::new(
|
||||
self.interaction_id,
|
||||
self.interaction_token.clone(),
|
||||
|
||||
@@ -23,4 +23,7 @@ pub enum InteractionError {
|
||||
|
||||
#[error("No prefixes were returned for the event")]
|
||||
PrefixesVectorEmpty,
|
||||
|
||||
#[error("The extras getter failed to retrieve extras")]
|
||||
ExtrasGetterFailed,
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use twilight_model::{
|
||||
};
|
||||
|
||||
use crate::framework::{
|
||||
commands::extras::ExtrasGetter,
|
||||
interactions::{InteractionError, context::InteractionContext},
|
||||
runtime::Runtime,
|
||||
};
|
||||
@@ -14,13 +15,14 @@ use crate::framework::{
|
||||
use super::components::Component;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ComponentRegistry<T> {
|
||||
inner: HashMap<String, Arc<dyn Component<T>>>,
|
||||
pub struct ComponentRegistry<T, E> {
|
||||
inner: HashMap<String, Arc<dyn Component<T, E>>>,
|
||||
}
|
||||
|
||||
impl<T> ComponentRegistry<T>
|
||||
impl<T, E> ComponentRegistry<T, E>
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
@@ -28,7 +30,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register(&self, id: impl ToString, component: Arc<dyn Component<T>>) {
|
||||
pub fn register(&self, id: impl ToString, component: Arc<dyn Component<T, E>>) {
|
||||
self.inner.upsert(id.to_string(), component);
|
||||
}
|
||||
|
||||
@@ -39,7 +41,8 @@ where
|
||||
pub async fn execute(
|
||||
&self,
|
||||
event: &InteractionCreate,
|
||||
rt: Arc<Runtime<T>>,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
extras: Arc<dyn ExtrasGetter<T, Extras = E>>,
|
||||
) -> Result<(), InteractionError> {
|
||||
if let Some(data) = &event.data {
|
||||
match data {
|
||||
@@ -55,11 +58,23 @@ where
|
||||
.first()
|
||||
.ok_or(InteractionError::PrefixesVectorEmpty)?;
|
||||
|
||||
let extras = extras
|
||||
.get_extra(
|
||||
&event.author().expect("Component interaction had no author"),
|
||||
&rt,
|
||||
)
|
||||
.await
|
||||
.inspect_err(|e| {
|
||||
log::error!("Failed to get extras for component interaction: {e:?}")
|
||||
})
|
||||
.map_err(|_| InteractionError::ExtrasGetterFailed)?;
|
||||
|
||||
component
|
||||
.execute(InteractionContext::new(
|
||||
event.clone(),
|
||||
rt.clone(),
|
||||
prefix.to_string(),
|
||||
extras,
|
||||
))
|
||||
.await
|
||||
} else {
|
||||
|
||||
@@ -4,6 +4,7 @@ use async_trait::async_trait;
|
||||
use twilight_model::gateway::payload::incoming::InteractionCreate;
|
||||
|
||||
use crate::framework::{
|
||||
commands::extras::ExtrasGetter,
|
||||
events::traits::{EventResult, OnInteractionHandler},
|
||||
runtime::Runtime,
|
||||
};
|
||||
@@ -12,11 +13,17 @@ use crate::framework::{
|
||||
pub struct InteractionRunner;
|
||||
|
||||
#[async_trait]
|
||||
impl<T> OnInteractionHandler<T> for InteractionRunner
|
||||
impl<T, E> OnInteractionHandler<T, E> for InteractionRunner
|
||||
where
|
||||
T: Send + Sync + 'static,
|
||||
E: Send + Sync + 'static,
|
||||
{
|
||||
async fn on_interaction(&self, event: &InteractionCreate, rt: Arc<Runtime<T>>) -> EventResult {
|
||||
Ok(rt.registry.execute(event, rt.clone()).await?)
|
||||
async fn on_interaction(
|
||||
&self,
|
||||
event: &InteractionCreate,
|
||||
rt: Arc<Runtime<T, E>>,
|
||||
extras: Arc<dyn ExtrasGetter<T, Extras = E>>,
|
||||
) -> EventResult {
|
||||
Ok(rt.registry.execute(event, rt.clone(), extras).await?)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::framework::{
|
||||
};
|
||||
|
||||
/// The application's runtime tools.
|
||||
pub struct Runtime<T> {
|
||||
pub struct Runtime<T, E> {
|
||||
/// The HTTP client used for making requests to the HTTP API.
|
||||
pub http: Client,
|
||||
|
||||
@@ -36,13 +36,13 @@ pub struct Runtime<T> {
|
||||
pub app: Application,
|
||||
|
||||
/// The component registry.
|
||||
pub registry: ComponentRegistry<T>,
|
||||
pub registry: ComponentRegistry<T, E>,
|
||||
|
||||
/// The command prefixes getter.
|
||||
pub prefixes: Arc<dyn PrefixGetter<T> + Send + Sync + 'static>,
|
||||
pub prefixes: Arc<dyn PrefixGetter<T, E> + Send + Sync + 'static>,
|
||||
|
||||
/// The commands available in the application.
|
||||
pub commands: Vec<Arc<dyn Command<T>>>,
|
||||
pub commands: Vec<Arc<dyn Command<T, E>>>,
|
||||
|
||||
/// The application state.
|
||||
pub state: Arc<T>,
|
||||
@@ -50,7 +50,7 @@ pub struct Runtime<T> {
|
||||
pub cache: InMemoryCache,
|
||||
}
|
||||
|
||||
impl<T> Runtime<T> {
|
||||
impl<T, E> Runtime<T, E> {
|
||||
/// Get the command prefixes set for the server and user ID.
|
||||
///
|
||||
/// Arguments:
|
||||
@@ -74,7 +74,7 @@ impl<T> Runtime<T> {
|
||||
///
|
||||
/// Returns:
|
||||
/// [`Option<Arc<dyn Command<T>>>`] - The command if found, otherwise `None`.
|
||||
pub fn get_command(&self, name: &str) -> Option<Arc<dyn Command<T>>> {
|
||||
pub fn get_command(&self, name: &str) -> Option<Arc<dyn Command<T, E>>> {
|
||||
self.commands
|
||||
.iter()
|
||||
.find(|cmd| {
|
||||
|
||||
Reference in New Issue
Block a user