Return whether command handled message
This commit is contained in:
parent
a6331d50b8
commit
4479126500
12 changed files with 142 additions and 47 deletions
|
|
@ -15,6 +15,13 @@ Procedure when bumping the version number:
|
|||
|
||||
### Added
|
||||
- `bot::botrulez::Uptime` now implements `bot::command::Command`
|
||||
- `bot::commands::Commands::fallthrough`
|
||||
- `bot::commands::Commands::set_fallthrough`
|
||||
|
||||
### Changed
|
||||
- `bot::command::ClapCommand::execute` now returns a `Result<bool, E>` instead of a `Result<(), E>`
|
||||
- `bot::command::Command::execute` now returns a `Result<bool, E>` instead of a `Result<(), E>`
|
||||
- `bot::commands::Commands::handle_packet` now returns a `Result<bool, E>` instead of a `Result<(), E>`
|
||||
|
||||
## v0.3.1 - 2023-02-26
|
||||
|
||||
|
|
|
|||
|
|
@ -34,10 +34,10 @@ impl ClapCommand<Bot, conn::Error> for Kill {
|
|||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut Bot,
|
||||
) -> Result<(), conn::Error> {
|
||||
) -> Result<bool, conn::Error> {
|
||||
bot.stop = true;
|
||||
ctx.reply(msg.id, "/me dies").await?;
|
||||
Ok(())
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,14 +61,14 @@ impl ClapCommand<Bot, conn::Error> for Test {
|
|||
msg: &Message,
|
||||
ctx: &Context,
|
||||
_bot: &mut Bot,
|
||||
) -> Result<(), conn::Error> {
|
||||
) -> Result<bool, conn::Error> {
|
||||
let content = if args.amount == 1 {
|
||||
format!("/me did {} test", args.amount)
|
||||
} else {
|
||||
format!("/me did {} tests", args.amount)
|
||||
};
|
||||
ctx.reply(msg.id, content).await?;
|
||||
Ok(())
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,12 +50,20 @@ where
|
|||
B: HasDescriptions + Send,
|
||||
E: From<conn::Error>,
|
||||
{
|
||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E> {
|
||||
async fn execute(
|
||||
&self,
|
||||
arg: &str,
|
||||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<bool, E> {
|
||||
if arg.trim().is_empty() {
|
||||
let reply = self.formulate_reply(ctx, bot);
|
||||
ctx.reply(msg.id, reply).await?;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,9 +85,9 @@ where
|
|||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<(), E> {
|
||||
) -> Result<bool, E> {
|
||||
let reply = self.formulate_reply(ctx, bot);
|
||||
ctx.reply(msg.id, reply).await?;
|
||||
Ok(())
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,11 +30,13 @@ where
|
|||
msg: &Message,
|
||||
ctx: &Context,
|
||||
_bot: &mut B,
|
||||
) -> Result<(), E> {
|
||||
) -> Result<bool, E> {
|
||||
if arg.trim().is_empty() {
|
||||
ctx.reply(msg.id, &self.0).await?;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -55,8 +57,8 @@ where
|
|||
msg: &Message,
|
||||
ctx: &Context,
|
||||
_bot: &mut B,
|
||||
) -> Result<(), E> {
|
||||
) -> Result<bool, E> {
|
||||
ctx.reply(msg.id, &self.0).await?;
|
||||
Ok(())
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@ where
|
|||
msg: &Message,
|
||||
ctx: &Context,
|
||||
_bot: &mut B,
|
||||
) -> Result<(), E> {
|
||||
) -> Result<bool, E> {
|
||||
if arg.trim().is_empty() {
|
||||
ctx.reply(msg.id, &self.0).await?;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -49,8 +51,8 @@ where
|
|||
msg: &Message,
|
||||
ctx: &Context,
|
||||
_bot: &mut B,
|
||||
) -> Result<(), E> {
|
||||
) -> Result<bool, E> {
|
||||
ctx.reply(msg.id, &self.0).await?;
|
||||
Ok(())
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,12 +81,20 @@ where
|
|||
B: HasStartTime + Send,
|
||||
E: From<conn::Error>,
|
||||
{
|
||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E> {
|
||||
async fn execute(
|
||||
&self,
|
||||
arg: &str,
|
||||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<bool, E> {
|
||||
if arg.trim().is_empty() {
|
||||
let reply = self.formulate_reply(ctx, bot, false);
|
||||
ctx.reply(msg.id, reply).await?;
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -112,9 +120,9 @@ where
|
|||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<(), E> {
|
||||
) -> Result<bool, E> {
|
||||
let reply = self.formulate_reply(ctx, bot, args.connected);
|
||||
ctx.reply(msg.id, reply).await?;
|
||||
Ok(())
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,11 @@ pub trait Command<B, E> {
|
|||
None
|
||||
}
|
||||
|
||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E>;
|
||||
async fn execute(
|
||||
&self,
|
||||
arg: &str,
|
||||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<bool, E>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,15 +65,21 @@ where
|
|||
Some(format!("{}{} - {inner}", self.prefix, self.name))
|
||||
}
|
||||
|
||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E> {
|
||||
async fn execute(
|
||||
&self,
|
||||
arg: &str,
|
||||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<bool, E> {
|
||||
// TODO Replace with let-else
|
||||
let (name, rest) = match parse_command(arg, &self.prefix) {
|
||||
Some(parsed) => parsed,
|
||||
None => return Ok(()),
|
||||
None => return Ok(false),
|
||||
};
|
||||
|
||||
if name != self.name {
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
self.inner.execute(rest, msg, ctx, bot).await
|
||||
|
|
@ -112,22 +118,28 @@ where
|
|||
Some(format!("{}{} - {inner}", self.prefix, self.name))
|
||||
}
|
||||
|
||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E> {
|
||||
async fn execute(
|
||||
&self,
|
||||
arg: &str,
|
||||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<bool, E> {
|
||||
// TODO Replace with let-else
|
||||
let (name, rest) = match parse_command(arg, &self.prefix) {
|
||||
Some(parsed) => parsed,
|
||||
None => return Ok(()),
|
||||
None => return Ok(false),
|
||||
};
|
||||
|
||||
if name != self.name {
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if parse_specific(rest).is_some() {
|
||||
// The command looks like a specific command. If we treated it like
|
||||
// a general command match, we would interpret other bots' specific
|
||||
// commands as general commands.
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
self.inner.execute(rest, msg, ctx, bot).await
|
||||
|
|
@ -167,25 +179,31 @@ where
|
|||
Some(format!("{}{} @{nick} - {inner}", self.prefix, self.name))
|
||||
}
|
||||
|
||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E> {
|
||||
async fn execute(
|
||||
&self,
|
||||
arg: &str,
|
||||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<bool, E> {
|
||||
// TODO Replace with let-else
|
||||
let (name, rest) = match parse_command(arg, &self.prefix) {
|
||||
Some(parsed) => parsed,
|
||||
None => return Ok(()),
|
||||
None => return Ok(false),
|
||||
};
|
||||
|
||||
if name != self.name {
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// TODO Replace with let-else
|
||||
let (nick, rest) = match parse_specific(rest) {
|
||||
Some(parsed) => parsed,
|
||||
None => return Ok(()),
|
||||
None => return Ok(false),
|
||||
};
|
||||
|
||||
if nick::normalize(nick) != nick::normalize(&ctx.joined.session.name) {
|
||||
return Ok(());
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
self.inner.execute(rest, msg, ctx, bot).await
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ pub trait ClapCommand<B, E> {
|
|||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<(), E>;
|
||||
) -> Result<bool, E>;
|
||||
}
|
||||
|
||||
/// Parse bash-like quoted arguments separated by whitespace.
|
||||
|
|
@ -110,12 +110,18 @@ where
|
|||
C::Args::command().get_about().map(|s| format!("{s}"))
|
||||
}
|
||||
|
||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E> {
|
||||
async fn execute(
|
||||
&self,
|
||||
arg: &str,
|
||||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<bool, E> {
|
||||
let mut args = match parse_quoted_args(arg) {
|
||||
Ok(args) => args,
|
||||
Err(err) => {
|
||||
ctx.reply(msg.id, err).await?;
|
||||
return Ok(());
|
||||
return Ok(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -127,7 +133,7 @@ where
|
|||
Ok(args) => args,
|
||||
Err(err) => {
|
||||
ctx.reply(msg.id, format!("{}", err.render())).await?;
|
||||
return Ok(());
|
||||
return Ok(true);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,13 @@ where
|
|||
None
|
||||
}
|
||||
|
||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E> {
|
||||
async fn execute(
|
||||
&self,
|
||||
arg: &str,
|
||||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<bool, E> {
|
||||
self.0.execute(arg, msg, ctx, bot).await
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,11 +29,17 @@ where
|
|||
Some(format!("{} - {inner}", self.prefix))
|
||||
}
|
||||
|
||||
async fn execute(&self, arg: &str, msg: &Message, ctx: &Context, bot: &mut B) -> Result<(), E> {
|
||||
async fn execute(
|
||||
&self,
|
||||
arg: &str,
|
||||
msg: &Message,
|
||||
ctx: &Context,
|
||||
bot: &mut B,
|
||||
) -> Result<bool, E> {
|
||||
if let Some(rest) = arg.trim_start().strip_prefix(&self.prefix) {
|
||||
self.inner.execute(rest, msg, ctx, bot).await
|
||||
} else {
|
||||
Ok(())
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,32 @@ use super::instance::{InstanceConfig, Snapshot};
|
|||
|
||||
pub struct Commands<B, E> {
|
||||
commands: Vec<Box<dyn Command<B, E> + Send + Sync>>,
|
||||
fallthrough: bool,
|
||||
}
|
||||
|
||||
impl<B, E> Commands<B, E> {
|
||||
pub fn new() -> Self {
|
||||
Self { commands: vec![] }
|
||||
Self {
|
||||
commands: vec![],
|
||||
fallthrough: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether further commands should be executed after a command returns
|
||||
/// `true`.
|
||||
///
|
||||
/// If disabled, commands are run until the first command that returns
|
||||
/// `true`. If enabled, all commands are run irrespective of their return
|
||||
/// values.
|
||||
pub fn fallthrough(&self) -> bool {
|
||||
self.fallthrough
|
||||
}
|
||||
|
||||
/// Set whether fallthrough is active.
|
||||
///
|
||||
/// See [`Self::fallthrough`] for more details.
|
||||
pub fn set_fallthrough(&mut self, active: bool) {
|
||||
self.fallthrough = active;
|
||||
}
|
||||
|
||||
pub fn add<C>(&mut self, command: C)
|
||||
|
|
@ -28,21 +49,22 @@ impl<B, E> Commands<B, E> {
|
|||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
/// Returns `true` if a command was found and executed, `false` otherwise.
|
||||
/// Returns `true` if one or more commands returned `true`, `false`
|
||||
/// otherwise.
|
||||
pub async fn handle_packet(
|
||||
&self,
|
||||
config: &InstanceConfig,
|
||||
packet: &ParsedPacket,
|
||||
snapshot: &Snapshot,
|
||||
bot: &mut B,
|
||||
) -> Result<(), E> {
|
||||
) -> Result<bool, E> {
|
||||
let msg = match &packet.content {
|
||||
Ok(Data::SendEvent(SendEvent(msg))) => msg,
|
||||
_ => return Ok(()),
|
||||
_ => return Ok(false),
|
||||
};
|
||||
|
||||
let joined = match &snapshot.state {
|
||||
conn::State::Joining(_) => return Ok(()),
|
||||
conn::State::Joining(_) => return Ok(false),
|
||||
conn::State::Joined(joined) => joined.clone(),
|
||||
};
|
||||
|
||||
|
|
@ -52,11 +74,15 @@ impl<B, E> Commands<B, E> {
|
|||
joined,
|
||||
};
|
||||
|
||||
let mut handled = false;
|
||||
for command in &self.commands {
|
||||
command.execute(&msg.content, msg, &ctx, bot).await?;
|
||||
handled = handled || command.execute(&msg.content, msg, &ctx, bot).await?;
|
||||
if !self.fallthrough && handled {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(handled)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue