Add error type parameter to commands
This commit is contained in:
parent
4dcc021f73
commit
ec9c4c9dd4
3 changed files with 41 additions and 33 deletions
|
|
@ -76,10 +76,10 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait Command<B> {
|
pub trait Command<B, E> {
|
||||||
fn description(&self) -> Option<String> {
|
fn description(&self) -> Option<String> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B);
|
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,21 @@ use async_trait::async_trait;
|
||||||
use clap::{CommandFactory, Parser};
|
use clap::{CommandFactory, Parser};
|
||||||
|
|
||||||
use crate::api::Message;
|
use crate::api::Message;
|
||||||
|
use crate::conn;
|
||||||
|
|
||||||
use super::{Command, Context};
|
use super::{Command, Context};
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait ClapCommand<B> {
|
pub trait ClapCommand<B, E> {
|
||||||
type Args;
|
type Args;
|
||||||
|
|
||||||
async fn execute(&self, args: Self::Args, msg: &Message, ctx: &Context, bot: &mut B);
|
async fn execute(
|
||||||
|
&self,
|
||||||
|
args: Self::Args,
|
||||||
|
msg: &Message,
|
||||||
|
ctx: &Context,
|
||||||
|
bot: &mut B,
|
||||||
|
) -> Result<(), E>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse bash-like quoted arguments separated by whitespace.
|
/// Parse bash-like quoted arguments separated by whitespace.
|
||||||
|
|
@ -92,22 +99,23 @@ fn parse_quoted_args(text: &str) -> Result<Vec<String>, &'static str> {
|
||||||
pub struct Clap<C>(pub C);
|
pub struct Clap<C>(pub C);
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<B, C> Command<B> for Clap<C>
|
impl<B, E, C> Command<B, E> for Clap<C>
|
||||||
where
|
where
|
||||||
B: Send,
|
B: Send,
|
||||||
C: ClapCommand<B> + Send + Sync,
|
E: From<conn::Error>,
|
||||||
|
C: ClapCommand<B, E> + Send + Sync,
|
||||||
C::Args: Parser + Send,
|
C::Args: Parser + Send,
|
||||||
{
|
{
|
||||||
fn description(&self) -> Option<String> {
|
fn description(&self) -> Option<String> {
|
||||||
C::Args::command().get_about().map(|s| format!("{s}"))
|
C::Args::command().get_about().map(|s| format!("{s}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) {
|
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E> {
|
||||||
let mut args = match parse_quoted_args(arg) {
|
let mut args = match parse_quoted_args(arg) {
|
||||||
Ok(args) => args,
|
Ok(args) => args,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let _ = ctx.reply(msg.id, err);
|
ctx.reply(msg.id, err).await?;
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -116,8 +124,8 @@ where
|
||||||
let args = match C::Args::try_parse_from(args) {
|
let args = match C::Args::try_parse_from(args) {
|
||||||
Ok(args) => args,
|
Ok(args) => args,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
let _ = ctx.reply(msg.id, format!("{}", err.render()));
|
ctx.reply(msg.id, format!("{}", err.render())).await?;
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,18 +46,18 @@ pub struct CommandInfo {
|
||||||
pub visible: bool,
|
pub visible: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CommandWrapper<B> {
|
struct CommandWrapper<B, E> {
|
||||||
command: Box<dyn Command<B>>,
|
command: Box<dyn Command<B, E>>,
|
||||||
visible: bool,
|
visible: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Commands<B> {
|
pub struct Commands<B, E> {
|
||||||
global: HashMap<String, CommandWrapper<B>>,
|
global: HashMap<String, CommandWrapper<B, E>>,
|
||||||
general: HashMap<String, CommandWrapper<B>>,
|
general: HashMap<String, CommandWrapper<B, E>>,
|
||||||
specific: HashMap<String, CommandWrapper<B>>,
|
specific: HashMap<String, CommandWrapper<B, E>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> Commands<B> {
|
impl<B, E> Commands<B, E> {
|
||||||
/// Global commands always respond. They override any specific or general
|
/// Global commands always respond. They override any specific or general
|
||||||
/// commands of the same name.
|
/// commands of the same name.
|
||||||
///
|
///
|
||||||
|
|
@ -65,7 +65,7 @@ impl<B> Commands<B> {
|
||||||
pub fn global<S, C>(mut self, name: S, command: C, visible: bool) -> Self
|
pub fn global<S, C>(mut self, name: S, command: C, visible: bool) -> Self
|
||||||
where
|
where
|
||||||
S: ToString,
|
S: ToString,
|
||||||
C: Command<B> + 'static,
|
C: Command<B, E> + 'static,
|
||||||
{
|
{
|
||||||
let command = Box::new(command);
|
let command = Box::new(command);
|
||||||
let info = CommandWrapper { command, visible };
|
let info = CommandWrapper { command, visible };
|
||||||
|
|
@ -80,7 +80,7 @@ impl<B> Commands<B> {
|
||||||
pub fn general<S, C>(mut self, name: S, command: C, visible: bool) -> Self
|
pub fn general<S, C>(mut self, name: S, command: C, visible: bool) -> Self
|
||||||
where
|
where
|
||||||
S: ToString,
|
S: ToString,
|
||||||
C: Command<B> + 'static,
|
C: Command<B, E> + 'static,
|
||||||
{
|
{
|
||||||
let command = Box::new(command);
|
let command = Box::new(command);
|
||||||
let info = CommandWrapper { command, visible };
|
let info = CommandWrapper { command, visible };
|
||||||
|
|
@ -92,7 +92,7 @@ impl<B> Commands<B> {
|
||||||
pub fn specific<S, C>(mut self, name: S, command: C, visible: bool) -> Self
|
pub fn specific<S, C>(mut self, name: S, command: C, visible: bool) -> Self
|
||||||
where
|
where
|
||||||
S: ToString,
|
S: ToString,
|
||||||
C: Command<B> + 'static,
|
C: Command<B, E> + 'static,
|
||||||
{
|
{
|
||||||
let command = Box::new(command);
|
let command = Box::new(command);
|
||||||
let info = CommandWrapper { command, visible };
|
let info = CommandWrapper { command, visible };
|
||||||
|
|
@ -149,20 +149,20 @@ impl<B> Commands<B> {
|
||||||
packet: &ParsedPacket,
|
packet: &ParsedPacket,
|
||||||
snapshot: &Snapshot,
|
snapshot: &Snapshot,
|
||||||
bot: &mut B,
|
bot: &mut B,
|
||||||
) -> bool {
|
) -> Result<bool, E> {
|
||||||
let msg = match &packet.content {
|
let msg = match &packet.content {
|
||||||
Ok(Data::SendEvent(SendEvent(msg))) => msg,
|
Ok(Data::SendEvent(SendEvent(msg))) => msg,
|
||||||
_ => return false,
|
_ => return Ok(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
let joined = match &snapshot.state {
|
let joined = match &snapshot.state {
|
||||||
conn::State::Joining(_) => return false,
|
conn::State::Joining(_) => return Ok(false),
|
||||||
conn::State::Joined(joined) => joined.clone(),
|
conn::State::Joined(joined) => joined.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (cmd_name, rest) = match parse_command(&msg.content) {
|
let (cmd_name, rest) = match parse_command(&msg.content) {
|
||||||
Some(parsed) => parsed,
|
Some(parsed) => parsed,
|
||||||
None => return false,
|
None => return Ok(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut ctx = Context {
|
let mut ctx = Context {
|
||||||
|
|
@ -175,8 +175,8 @@ impl<B> Commands<B> {
|
||||||
|
|
||||||
if let Some(wrapper) = self.global.get(cmd_name) {
|
if let Some(wrapper) = self.global.get(cmd_name) {
|
||||||
ctx.kind = Kind::Global;
|
ctx.kind = Kind::Global;
|
||||||
wrapper.command.execute(rest, msg, &ctx, bot).await;
|
wrapper.command.execute(rest, msg, &ctx, bot).await?;
|
||||||
return true;
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((cmd_nick, rest)) = parse_specific(rest) {
|
if let Some((cmd_nick, rest)) = parse_specific(rest) {
|
||||||
|
|
@ -185,8 +185,8 @@ impl<B> Commands<B> {
|
||||||
let cmd_nick_norm = normalize_specific_nick(cmd_nick);
|
let cmd_nick_norm = normalize_specific_nick(cmd_nick);
|
||||||
if nick_norm == cmd_nick_norm {
|
if nick_norm == cmd_nick_norm {
|
||||||
ctx.kind = Kind::Specific;
|
ctx.kind = Kind::Specific;
|
||||||
wrapper.command.execute(rest, msg, &ctx, bot).await;
|
wrapper.command.execute(rest, msg, &ctx, bot).await?;
|
||||||
return true;
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,16 +196,16 @@ impl<B> Commands<B> {
|
||||||
//
|
//
|
||||||
// To call a specific command with a mention as its first positional
|
// To call a specific command with a mention as its first positional
|
||||||
// argument, -- can be used.
|
// argument, -- can be used.
|
||||||
return false;
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(wrapper) = self.general.get(cmd_name) {
|
if let Some(wrapper) = self.general.get(cmd_name) {
|
||||||
ctx.kind = Kind::General;
|
ctx.kind = Kind::General;
|
||||||
wrapper.command.execute(rest, msg, &ctx, bot).await;
|
wrapper.command.execute(rest, msg, &ctx, bot).await?;
|
||||||
return true;
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue