167 lines
5.6 KiB
Rust
167 lines
5.6 KiB
Rust
use crate::context::GeoffreyContext;
|
|
use async_trait::async_trait;
|
|
use geoffrey_models::models::parameters::CommandRequest;
|
|
use geoffrey_models::models::player::UserID;
|
|
use geoffrey_models::models::response::api_error::GeoffreyAPIError;
|
|
use geoffrey_models::models::response::APIResponse;
|
|
use reqwest::Error;
|
|
use serde::de::DeserializeOwned;
|
|
use serde::Serialize;
|
|
use serenity::model::prelude::application_command::{
|
|
ApplicationCommand, ApplicationCommandInteraction,
|
|
};
|
|
use serenity::prelude::{Context, SerenityError};
|
|
use std::fmt::{Display, Formatter};
|
|
|
|
#[derive(Debug)]
|
|
pub enum CommandError {
|
|
ArgumentParse(String),
|
|
GeoffreyApi(GeoffreyAPIError),
|
|
Serenity(serenity::Error),
|
|
Reqwest(reqwest::Error),
|
|
}
|
|
|
|
impl Display for CommandError {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
let s = match self {
|
|
CommandError::ArgumentParse(s) => format!("Unable to parse argument '{}'", s),
|
|
CommandError::GeoffreyApi(err) => format!("Got error from GeoffreyAPI: {}", err),
|
|
CommandError::Serenity(err) => format!("Serenity Error: {}", err),
|
|
CommandError::Reqwest(err) => format!("Reqwest Error: {}", err),
|
|
};
|
|
|
|
write!(f, "{}", s)
|
|
}
|
|
}
|
|
|
|
impl From<GeoffreyAPIError> for CommandError {
|
|
fn from(err: GeoffreyAPIError) -> Self {
|
|
Self::GeoffreyApi(err)
|
|
}
|
|
}
|
|
|
|
impl From<SerenityError> for CommandError {
|
|
fn from(err: SerenityError) -> Self {
|
|
Self::Serenity(err)
|
|
}
|
|
}
|
|
|
|
impl From<reqwest::Error> for CommandError {
|
|
fn from(err: Error) -> Self {
|
|
Self::Reqwest(err)
|
|
}
|
|
}
|
|
|
|
#[async_trait]
|
|
pub trait BotCommand {
|
|
type ApiParams: CommandRequest;
|
|
type ApiResp: Serialize + DeserializeOwned + Send;
|
|
|
|
fn command_name() -> String;
|
|
|
|
fn request_type() -> reqwest::Method;
|
|
|
|
fn command_url(base_string: &str) -> String {
|
|
let slash = if !base_string.ends_with('/') { "/" } else { "" };
|
|
|
|
format!("{}{}command/{}/", base_string, slash, Self::command_name())
|
|
}
|
|
|
|
async fn run_api_query(
|
|
ctx: &GeoffreyContext,
|
|
params: Self::ApiParams,
|
|
) -> Result<APIResponse<Self::ApiResp>, CommandError> {
|
|
let command_url = Self::command_url(&ctx.cfg.api.base_url);
|
|
let resp: APIResponse<Self::ApiResp> = ctx
|
|
.http_client
|
|
.request(Self::request_type(), command_url)
|
|
.json(¶ms)
|
|
.send()
|
|
.await?
|
|
.json()
|
|
.await?;
|
|
|
|
Ok(resp)
|
|
}
|
|
|
|
fn get_err_resp(err: CommandError) -> String {
|
|
if let Some(resp) = Self::custom_err_resp(&err) {
|
|
resp
|
|
} else {
|
|
match err {
|
|
CommandError::GeoffreyApi(err) => match err {
|
|
GeoffreyAPIError::PlayerNotRegistered => {
|
|
"You need to register before using this command!".to_string()
|
|
}
|
|
GeoffreyAPIError::EntryNotFound => {
|
|
"Couldn't find that, maybe look for something that exists?".to_string()
|
|
}
|
|
GeoffreyAPIError::PermissionInsufficient => {
|
|
"Looks like you don't have permission for that.".to_string()
|
|
}
|
|
GeoffreyAPIError::EntryNotUnique => {
|
|
"Slow down, I already know that thing. Try a new name.".to_string()
|
|
}
|
|
GeoffreyAPIError::DatabaseError(_) => "How the heck u mess that up".to_string(),
|
|
GeoffreyAPIError::TokenNotAuthorized => "WHO ARE YOU????".to_string(),
|
|
GeoffreyAPIError::MultipleLocationsMatch => {
|
|
"I couldn't match a single location, narrow down your search".to_string()
|
|
}
|
|
GeoffreyAPIError::ParameterInvalid(err) => {
|
|
format!(
|
|
"Welp, you some how messed up the {} parameter, great job",
|
|
err
|
|
)
|
|
}
|
|
},
|
|
_ => {
|
|
println!("GeoffreyBot 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(_: &CommandError) -> Option<String> {
|
|
None
|
|
}
|
|
|
|
async fn create_app_command(ctx: &Context) -> Result<ApplicationCommand, CommandError>;
|
|
|
|
async fn process_arguments(
|
|
command_interaction: ApplicationCommandInteraction,
|
|
) -> Result<Self::ApiParams, CommandError>;
|
|
|
|
async fn run_command(
|
|
ctx: &GeoffreyContext,
|
|
user_id: UserID,
|
|
command_interact: ApplicationCommandInteraction,
|
|
) -> Result<String, CommandError> {
|
|
let mut args = Self::process_arguments(command_interact).await?;
|
|
|
|
args.set_token(ctx.cfg.api.token.clone());
|
|
args.set_user_id(user_id);
|
|
|
|
let resp = Self::run_api_query(ctx, args).await?;
|
|
|
|
match resp {
|
|
APIResponse::Response(resp) => Ok(Self::build_response(resp)),
|
|
APIResponse::Error { error: err, .. } => Err(CommandError::GeoffreyApi(err)),
|
|
}
|
|
}
|
|
|
|
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(resp: Self::ApiResp) -> String;
|
|
}
|