Geoffrey-rs/geoffrey_bot/src/main.rs

151 lines
4.5 KiB
Rust

mod bot;
mod configs;
mod context;
mod logging;
use crate::bot::create_commands;
use crate::configs::GeoffreyBotConfig;
use crate::context::GeoffreyContext;
use bot::commands::add_item::AddItemCommand;
use bot::commands::add_location::AddLocationCommand;
use bot::commands::find::FindCommand;
use bot::commands::selling::SellingCommand;
use bot::commands::BotCommand;
use geoffrey_models::models::player::UserID;
use serenity::utils::{content_safe, ContentSafeOptions};
use serenity::{
async_trait,
model::{
gateway::Ready,
interactions::{Interaction, InteractionResponseType},
},
prelude::*,
};
use std::path::PathBuf;
use structopt::StructOpt;
use geoffrey_models::logging::LogLevel;
use crate::logging::init_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 Handler;
#[async_trait]
impl EventHandler for Handler {
async fn ready(&self, ctx: Context, ready: Ready) {
log::info!("{} is connected!", ready.user.name);
let commands = create_commands(&ctx).await.unwrap();
log::debug!("The following bot have been registered:");
for command in commands {
log::debug!(
"{}: {} - {:?}",
command.name, command.description, command.options
);
}
}
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
let data = ctx.data.read().await;
let geoffrey_ctx = data.get::<GeoffreyContext>().unwrap();
if let Interaction::ApplicationCommand(command) = interaction {
let user_id = UserID::DiscordUUID {
discord_uuid: command.user.id.0,
};
let msg = match command.data.name.as_str() {
"find" => FindCommand::command(geoffrey_ctx, user_id, command.clone()).await,
"selling" => SellingCommand::command(geoffrey_ctx, user_id, command.clone()).await,
"add_location" => {
AddLocationCommand::command(geoffrey_ctx, user_id, command.clone()).await
}
"add_item" => AddItemCommand::command(geoffrey_ctx, user_id, command.clone()).await,
_ => "not implemented :(".to_string(),
};
let msg = content_safe(&ctx.cache, &msg, &ContentSafeOptions::default()).await;
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,
})
}
if let Err(e) = client.start().await {
log::warn!("Client error: {:?}", e);
}
}