Geoffrey-rs/geoffrey_bot/src/bot/commands/mod.rs

136 lines
4.4 KiB
Rust

use std::fmt::Debug;
use std::future::Future;
use std::pin::Pin;
use async_trait::async_trait;
use serde::de::DeserializeOwned;
use serde::Serialize;
use serenity::builder::CreateApplicationCommand;
use serenity::model::interactions::application_command::ApplicationCommandInteraction;
use geoffrey_models::models::parameters::{CommandRequest, GeoffreyParam};
use geoffrey_models::models::player::UserID;
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
use crate::api::run_api_query;
use crate::context::GeoffreyContext;
use crate::error::BotError;
pub mod add_item;
pub mod add_location;
pub mod delete;
pub mod edit_name;
pub mod edit_pos;
pub mod find;
pub mod info;
pub mod register;
pub mod remove_item;
pub mod report_out_of_stock;
pub mod restock;
pub mod selling;
pub mod set_portal;
pub type GeoffreyCommandFn = Box<
fn(
GeoffreyContext,
UserID,
ApplicationCommandInteraction,
) -> Pin<Box<dyn Future<Output = String> + Send>>,
>;
#[async_trait]
pub trait BotCommand: Send + 'static {
type ApiParams: GeoffreyParam;
type ApiResp: Serialize + DeserializeOwned + Send + Debug;
fn command_name() -> String;
fn endpoint() -> String {
format!("command/{}/", Self::command_name())
}
fn request_type() -> reqwest::Method;
fn get_err_resp(err: BotError) -> String {
if let Some(resp) = Self::custom_err_resp(&err) {
resp
} else {
match err {
BotError::GeoffreyApi(GeoffreyAPIError::PlayerNotRegistered) => {
"You need to register before using this command!".to_string()
}
BotError::GeoffreyApi(GeoffreyAPIError::EntryNotFound) => {
"Couldn't find that, maybe look for something that exists?".to_string()
}
BotError::GeoffreyApi(GeoffreyAPIError::PermissionInsufficient) => {
"Looks like you don't have permission for that.".to_string()
}
BotError::GeoffreyApi(GeoffreyAPIError::EntryNotUnique) => {
"Slow down, I already know that thing. Try a new name.".to_string()
}
BotError::GeoffreyApi(GeoffreyAPIError::MultipleLocationsMatch) => {
"I couldn't match a single location, narrow down your search".to_string()
}
BotError::GeoffreyApi(GeoffreyAPIError::ParameterInvalid(err)) => {
format!(
"Welp, you some how messed up the {} parameter, great job",
err
)
}
_ => {
log::warn!("GeoffreyBot got an unhandled error: {}", err);
format!("OOPSIE WOOPSIE!! Uwu We made a fucky wucky!! A wittle fucko boingo! The admins at our \
headquarters are working VEWY HAWD to fix this! (Error in command {})", Self::command_name())
}
}
}
}
fn custom_err_resp(_: &BotError) -> Option<String> {
None
}
fn create_app_command(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand;
async fn process_arguments(
command_interaction: ApplicationCommandInteraction,
) -> Result<Self::ApiParams, BotError>;
async fn run_command(
ctx: GeoffreyContext,
user_id: UserID,
command_interact: ApplicationCommandInteraction,
) -> Result<String, BotError> {
let args = Self::process_arguments(command_interact).await?;
log::info!(
"Running command {}, with args {:?}",
Self::command_name(),
args
);
let request = CommandRequest {
token: ctx.cfg.api.token.clone(),
user_id: Some(user_id),
params: args.clone(),
};
let resp = run_api_query(&ctx, &request, Self::request_type(), &Self::endpoint()).await?;
Ok(Self::build_response(&ctx, resp, args))
}
async fn command(
ctx: GeoffreyContext,
user_id: UserID,
command_interact: ApplicationCommandInteraction,
) -> String {
match Self::run_command(ctx, user_id, command_interact).await {
Ok(msg) => msg,
Err(e) => Self::get_err_resp(e),
}
}
fn build_response(ctx: &GeoffreyContext, resp: Self::ApiResp, req: Self::ApiParams) -> String;
}