blastmud/blastmud_game/src/message_handler/user_commands.rs

142 lines
4.0 KiB
Rust
Raw Normal View History

2022-12-24 21:16:23 +11:00
use super::ListenerSession;
2022-12-24 13:43:28 +11:00
use crate::DResult;
2022-12-25 00:25:52 +11:00
use crate::db::{DBTrans, DBPool};
use ansi::ansi;
2022-12-24 21:16:23 +11:00
use phf::phf_map;
use async_trait::async_trait;
2022-12-26 01:30:59 +11:00
use crate::models::{session::Session, user::User};
use log::warn;
2022-12-24 13:43:28 +11:00
mod agree;
2022-12-24 21:16:23 +11:00
mod help;
mod ignore;
2022-12-26 01:30:59 +11:00
mod less_explicit_mode;
2022-12-27 16:08:27 +11:00
mod login;
mod look;
mod parsing;
mod quit;
mod register;
2022-12-24 21:16:23 +11:00
pub struct VerbContext<'l> {
session: &'l ListenerSession,
session_dat: &'l mut Session,
2022-12-26 01:30:59 +11:00
user_dat: &'l mut Option<User>,
2022-12-25 00:25:52 +11:00
trans: &'l DBTrans
2022-12-24 21:16:23 +11:00
}
pub enum CommandHandlingError {
UserError(String),
SystemError(Box<dyn std::error::Error + Send + Sync>)
}
use CommandHandlingError::*;
#[async_trait]
pub trait UserVerb {
2022-12-26 01:30:59 +11:00
async fn handle(self: &Self, ctx: &mut VerbContext, verb: &str, remaining: &str) -> UResult<()>;
2022-12-24 21:16:23 +11:00
}
pub type UResult<A> = Result<A, CommandHandlingError>;
2022-12-27 16:08:27 +11:00
impl<T> From<T> for CommandHandlingError where T: Into<Box<dyn std::error::Error + Send + Sync>> {
fn from(input: T) -> CommandHandlingError {
SystemError(input.into())
2022-12-24 21:16:23 +11:00
}
}
pub fn user_error<A>(msg: String) -> UResult<A> {
Err(UserError(msg))
}
2022-12-26 01:30:59 +11:00
/* Verb registries list types of commands available in different circumstances. */
pub type UserVerbRef = &'static (dyn UserVerb + Sync + Send);
2022-12-24 21:16:23 +11:00
type UserVerbRegistry = phf::Map<&'static str, UserVerbRef>;
static ALWAYS_AVAILABLE_COMMANDS: UserVerbRegistry = phf_map! {
"" => ignore::VERB,
"help" => help::VERB,
"quit" => quit::VERB,
2022-12-24 21:16:23 +11:00
};
2022-12-26 01:30:59 +11:00
static UNREGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
"agree" => agree::VERB,
"connect" => login::VERB,
2022-12-26 01:30:59 +11:00
"less_explicit_mode" => less_explicit_mode::VERB,
2022-12-27 16:08:27 +11:00
"login" => login::VERB,
"register" => register::VERB,
};
static REGISTERED_COMMANDS: UserVerbRegistry = phf_map! {
"l" => look::VERB,
"look" => look::VERB,
2022-12-26 01:30:59 +11:00
};
pub fn explicit_if_allowed<'l>(ctx: &VerbContext, explicit: &'l str, non_explicit: Option<&'l str>) -> &'l str {
if ctx.session_dat.less_explicit_mode {
non_explicit.unwrap_or(explicit)
} else {
explicit
}
}
2022-12-26 01:30:59 +11:00
fn resolve_handler(ctx: &VerbContext, cmd: &str) -> Option<&'static UserVerbRef> {
let mut result = ALWAYS_AVAILABLE_COMMANDS.get(cmd);
match &ctx.user_dat {
None => {
result = result.or_else(|| UNREGISTERED_COMMANDS.get(cmd));
}
Some(user_dat) => {
if user_dat.terms.terms_complete {
result = result.or_else(|| REGISTERED_COMMANDS.get(cmd));
} else if cmd == "agree" {
result = Some(&agree::VERB);
}
}
2022-12-26 01:30:59 +11:00
}
result
}
2022-12-24 21:16:23 +11:00
pub async fn handle(session: &ListenerSession, msg: &str, pool: &DBPool) -> DResult<()> {
let (cmd, params) = parsing::parse_command_name(msg);
2022-12-25 00:25:52 +11:00
let trans = pool.start_transaction().await?;
2022-12-26 01:30:59 +11:00
let (mut session_dat, mut user_dat) = match trans.get_session_user_model(session).await? {
None => {
// If the session has been cleaned up from the database, there is
// nowhere to go from here, so just ignore it.
warn!("Got command from session not in database: {}", session.session);
return Ok(());
}
Some(v) => v
};
2022-12-26 01:30:59 +11:00
let mut ctx = VerbContext { session, trans: &trans, session_dat: &mut session_dat,
user_dat: &mut user_dat };
let handler_opt = resolve_handler(&ctx, cmd);
2022-12-24 21:16:23 +11:00
match handler_opt {
None => {
2022-12-25 00:25:52 +11:00
trans.queue_for_session(session,
Some(ansi!(
2022-12-25 00:25:52 +11:00
"That's not a command I know. Try <bold>help<reset>\r\n"
))
2022-12-24 21:16:23 +11:00
).await?;
trans.commit().await?;
2022-12-24 21:16:23 +11:00
}
Some(handler) => {
2022-12-26 01:30:59 +11:00
match handler.handle(&mut ctx, cmd, params).await {
Ok(()) => {
trans.commit().await?;
}
2022-12-24 21:16:23 +11:00
Err(UserError(err_msg)) => {
pool.queue_for_session(session, Some(&(err_msg + "\r\n"))).await?;
2022-12-24 21:16:23 +11:00
}
Err(SystemError(e)) => Err(e)?
}
}
}
2022-12-24 13:43:28 +11:00
Ok(())
}