forked from projectmoon/tenebrous-dicebot
Make command execution async.
This commit is contained in:
parent
97d91704a1
commit
3c2a37c0f7
|
@ -1,17 +1,18 @@
|
|||
use chronicle_dicebot::commands::Command;
|
||||
use chronicle_dicebot::commands;
|
||||
use chronicle_dicebot::context::Context;
|
||||
use chronicle_dicebot::db::Database;
|
||||
use chronicle_dicebot::error::BotError;
|
||||
|
||||
fn main() -> Result<(), BotError> {
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), BotError> {
|
||||
let db = Database::new(&sled::open("test-db")?);
|
||||
let input = std::env::args().skip(1).collect::<Vec<String>>().join(" ");
|
||||
let command = match Command::parse(&input) {
|
||||
let command = match commands::parse(&input) {
|
||||
Ok(command) => command,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
let context = Context::new(&db, "roomid", "localuser", &input);
|
||||
println!("{}", command.execute(&context).plain());
|
||||
println!("{}", command.execute(&context).await.plain());
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ use chronicle_dicebot::state::DiceBotState;
|
|||
use env_logger::Env;
|
||||
use log::error;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use tokio::prelude::*;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
|
|
@ -227,7 +227,7 @@ impl EventEmitter for DiceBot {
|
|||
|
||||
let ctx = Context::new(&self.db, &room_id.as_str(), &sender_username, &msg_body);
|
||||
|
||||
if let Some(cmd_result) = execute_command(&ctx) {
|
||||
if let Some(cmd_result) = execute_command(&ctx).await {
|
||||
let response = AnyMessageEventContent::RoomMessage(MessageEventContent::Notice(
|
||||
NoticeMessageEventContent::html(cmd_result.plain, cmd_result.html),
|
||||
));
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::dice::ElementExpression;
|
|||
use crate::error::BotError;
|
||||
use crate::help::HelpTopic;
|
||||
use crate::roll::Roll;
|
||||
use async_trait::async_trait;
|
||||
use thiserror::Error;
|
||||
|
||||
pub mod parser;
|
||||
|
@ -33,19 +34,21 @@ impl Execution {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait Command {
|
||||
fn execute(&self, ctx: &Context) -> Execution;
|
||||
#[async_trait]
|
||||
pub trait Command: Send + Sync {
|
||||
async fn execute(&self, ctx: &Context) -> Execution;
|
||||
fn name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
pub struct RollCommand(ElementExpression);
|
||||
|
||||
#[async_trait]
|
||||
impl Command for RollCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"roll regular dice"
|
||||
}
|
||||
|
||||
fn execute(&self, _ctx: &Context) -> Execution {
|
||||
async fn execute(&self, _ctx: &Context) -> Execution {
|
||||
let roll = self.0.roll();
|
||||
let plain = format!("Dice: {}\nResult: {}", self.0, roll);
|
||||
let html = format!(
|
||||
|
@ -58,12 +61,13 @@ impl Command for RollCommand {
|
|||
|
||||
pub struct PoolRollCommand(DicePool);
|
||||
|
||||
#[async_trait]
|
||||
impl Command for PoolRollCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"roll dice pool"
|
||||
}
|
||||
|
||||
fn execute(&self, ctx: &Context) -> Execution {
|
||||
async fn execute(&self, ctx: &Context) -> Execution {
|
||||
let pool_with_ctx = DicePoolWithContext(&self.0, ctx);
|
||||
let roll_result = pool_with_ctx.roll();
|
||||
|
||||
|
@ -89,12 +93,13 @@ impl Command for PoolRollCommand {
|
|||
|
||||
pub struct HelpCommand(Option<HelpTopic>);
|
||||
|
||||
#[async_trait]
|
||||
impl Command for HelpCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"help information"
|
||||
}
|
||||
|
||||
fn execute(&self, _ctx: &Context) -> Execution {
|
||||
async fn execute(&self, _ctx: &Context) -> Execution {
|
||||
let help = match &self.0 {
|
||||
Some(topic) => topic.message(),
|
||||
_ => "There is no help for this topic",
|
||||
|
@ -108,12 +113,13 @@ impl Command for HelpCommand {
|
|||
|
||||
pub struct GetVariableCommand(String);
|
||||
|
||||
#[async_trait]
|
||||
impl Command for GetVariableCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"retrieve variable value"
|
||||
}
|
||||
|
||||
fn execute(&self, ctx: &Context) -> Execution {
|
||||
async fn execute(&self, ctx: &Context) -> Execution {
|
||||
let name = &self.0;
|
||||
let value = match ctx.db.get_user_variable(&ctx.room_id, &ctx.username, name) {
|
||||
Ok(num) => format!("{} = {}", name, num),
|
||||
|
@ -129,12 +135,13 @@ impl Command for GetVariableCommand {
|
|||
|
||||
pub struct SetVariableCommand(String, i32);
|
||||
|
||||
#[async_trait]
|
||||
impl Command for SetVariableCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"set variable value"
|
||||
}
|
||||
|
||||
fn execute(&self, ctx: &Context) -> Execution {
|
||||
async fn execute(&self, ctx: &Context) -> Execution {
|
||||
let name = &self.0;
|
||||
let value = self.1;
|
||||
let result = ctx
|
||||
|
@ -154,12 +161,13 @@ impl Command for SetVariableCommand {
|
|||
|
||||
pub struct DeleteVariableCommand(String);
|
||||
|
||||
#[async_trait]
|
||||
impl Command for DeleteVariableCommand {
|
||||
fn name(&self) -> &'static str {
|
||||
"delete variable"
|
||||
}
|
||||
|
||||
fn execute(&self, ctx: &Context) -> Execution {
|
||||
async fn execute(&self, ctx: &Context) -> Execution {
|
||||
let name = &self.0;
|
||||
let value = match ctx
|
||||
.db
|
||||
|
@ -176,16 +184,14 @@ impl Command for DeleteVariableCommand {
|
|||
}
|
||||
}
|
||||
|
||||
impl dyn Command {
|
||||
/// Parse a command string into a dynamic command execution trait
|
||||
/// object. Returns an error if a command was recognized but not
|
||||
/// parsed correctly. Returns Ok(None) if no command was recognized.
|
||||
pub fn parse(s: &str) -> Result<Box<dyn Command>, BotError> {
|
||||
match parser::parse_command(s) {
|
||||
Ok(Some(command)) => Ok(command),
|
||||
Ok(None) => Err(BotError::CommandError(CommandError::IgnoredCommand)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
/// Parse a command string into a dynamic command execution trait
|
||||
/// object. Returns an error if a command was recognized but not
|
||||
/// parsed correctly. Returns Ok(None) if no command was recognized.
|
||||
pub fn parse(s: &str) -> Result<Box<dyn Command>, BotError> {
|
||||
match parser::parse_command(s) {
|
||||
Ok(Some(command)) => Ok(command),
|
||||
Ok(None) => Err(BotError::CommandError(CommandError::IgnoredCommand)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,14 +204,14 @@ pub struct CommandResult {
|
|||
/// go back to Matrix, if the command was executed (successfully or
|
||||
/// not). If a command is determined to be ignored, this function will
|
||||
/// return None, signifying that we should not send a response.
|
||||
pub fn execute_command(ctx: &Context) -> Option<CommandResult> {
|
||||
let res = Command::parse(&ctx.message_body).map(|cmd| {
|
||||
let execution = cmd.execute(ctx);
|
||||
(execution.plain().into(), execution.html().into())
|
||||
});
|
||||
pub async fn execute_command(ctx: &Context) -> Option<CommandResult> {
|
||||
let res = parse(&ctx.message_body);
|
||||
|
||||
let (plain, html) = match res {
|
||||
Ok(plain_and_html) => plain_and_html,
|
||||
Ok(cmd) => {
|
||||
let execution = cmd.execute(ctx).await;
|
||||
(execution.plain().into(), execution.html().into())
|
||||
}
|
||||
Err(BotError::CommandError(CommandError::IgnoredCommand)) => return None,
|
||||
Err(e) => {
|
||||
let message = format!("Error parsing command: {}", e);
|
||||
|
|
Loading…
Reference in New Issue