Geoffrey-rs/geoffrey_bot/src/main.rs

203 lines
5.7 KiB
Rust

use std::path::PathBuf;
use reqwest::Method;
use serenity::{
async_trait,
model::{
gateway::Ready,
interactions::{Interaction, InteractionResponseType},
},
prelude::*,
};
use structopt::StructOpt;
use geoffrey_models::logging::LogLevel;
use geoffrey_models::models::parameters::{CommandRequest, EmptyRequest};
use geoffrey_models::models::player::UserID;
use geoffrey_models::models::settings::GeoffreySettings;
use crate::api::run_api_query;
use crate::bot::formatters::clean_message;
use crate::bot::{build_commands, CommandRunner};
use crate::configs::GeoffreyBotConfig;
use crate::context::GeoffreyContext;
use crate::logging::init_logging;
mod api;
mod bot;
mod configs;
mod context;
mod error;
mod logging;
#[derive(Debug, StructOpt, Clone)]
#[structopt(name = "GeoffreyBot", about = "Geoffrey Discord Bot")]
struct Args {
#[structopt(env = "GEOFFREY_BOT_CONFIG", parse(from_os_str))]
config: PathBuf,
#[structopt(
short,
long,
env = "GEOFFREY_LOG_LEVEL",
parse(from_str),
default_value = "Info"
)]
log_level: LogLevel,
}
struct HttpClient;
impl TypeMapKey for HttpClient {
type Value = serenity::client::Client;
}
struct Settings;
impl TypeMapKey for Settings {
type Value = GeoffreySettings;
}
struct Handler;
#[async_trait]
impl EventHandler for Handler {
async fn ready(&self, ctx: Context, ready: Ready) {
log::info!("{} is connected!", ready.user.name);
let mut data = ctx.data.write().await;
let mut geoffrey_ctx = data.get_mut::<GeoffreyContext>().expect("Unable");
match run_api_query::<EmptyRequest, GeoffreySettings>(
geoffrey_ctx,
&CommandRequest {
token: geoffrey_ctx.cfg.api.token.clone(),
user_id: None,
params: EmptyRequest {},
},
Method::GET,
"model/settings/",
)
.await
{
Ok(settings) => geoffrey_ctx.settings = settings,
Err(err) => {
log::warn!(
"Unable to retrieve Geoffrey global settings, using defaults. Error: {}",
err
)
}
}
let command_runner = data
.get_mut::<CommandRunner>()
.expect("Unable to open command runner!");
match build_commands(&ctx, command_runner).await {
Ok(_) => {
log::debug!("Registered the following commands:");
for command in &command_runner.app_commands {
log::debug!("{:?}", command)
}
}
Err(e) => {
log::warn!("Error registering commands: {:?}", e)
}
}
log::info!("Init completed.");
}
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
let data = ctx.data.read().await;
let geoffrey_ctx = data.get::<GeoffreyContext>().unwrap();
let command_runner = data.get::<CommandRunner>().unwrap();
if let Interaction::ApplicationCommand(command) = interaction {
let user_id = UserID::DiscordUUID {
discord_uuid: command.user.id.0,
};
let command_name = command.data.name.clone();
let msg = match command_runner
.run_command(
&command_name,
geoffrey_ctx.clone(),
user_id,
command.clone(),
)
.await
{
Ok(msg) => clean_message(ctx.cache, &msg).await,
Err(e) => {
log::warn!("Error running command '{}': {:?}", command_name, e);
return;
}
};
command
.create_interaction_response(&ctx.http, |resp| {
resp.kind(InteractionResponseType::ChannelMessageWithSource)
.interaction_response_data(|message| message.content(msg))
})
.await
.unwrap()
} else if let Interaction::Autocomplete(auto_complete) = interaction {
auto_complete
.create_autocomplete_response(&ctx.http, |resp| resp)
.await
.unwrap()
} else if let Interaction::MessageComponent(msg) = interaction {
msg.create_interaction_response(&ctx.http, |resp| resp)
.await
.unwrap()
} else if let Interaction::Ping(_) = interaction {
// do nothing
}
}
}
#[tokio::main]
async fn main() {
let args: Args = Args::from_args();
init_logging(args.log_level).expect("Unable to init logging");
let cfg = match GeoffreyBotConfig::new(args.config.as_path()) {
Ok(cfg) => cfg,
Err(e) => {
log::warn!("Error opening config: {}", e);
return;
}
};
let client = Client::builder(cfg.discord.token.clone())
.event_handler(Handler)
.application_id(cfg.discord.app_id)
.await;
let mut client = match client {
Ok(client) => client,
Err(e) => {
log::warn!("Unable to init serenity client: {}", e);
return;
}
};
// Block for initializing global data
{
let mut data = client.data.write().await;
data.insert::<GeoffreyContext>(GeoffreyContext {
http_client: reqwest::Client::new(),
cfg,
settings: GeoffreySettings::default(),
});
data.insert::<CommandRunner>(CommandRunner::default());
}
if let Err(e) = client.start().await {
log::warn!("Client error: {:?}", e);
}
}