166 lines
4.7 KiB
Rust
166 lines
4.7 KiB
Rust
mod bot;
|
|
mod configs;
|
|
mod context;
|
|
mod logging;
|
|
|
|
use crate::bot::{build_commands, CommandRunner};
|
|
use crate::configs::GeoffreyBotConfig;
|
|
use crate::context::GeoffreyContext;
|
|
use crate::logging::init_logging;
|
|
use geoffrey_models::logging::LogLevel;
|
|
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;
|
|
|
|
#[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 mut data = ctx.data.write().await;
|
|
|
|
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) => msg,
|
|
Err(e) => {
|
|
log::warn!("Error running command '{}': {:?}", command_name, e);
|
|
return;
|
|
}
|
|
};
|
|
|
|
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,
|
|
});
|
|
|
|
data.insert::<CommandRunner>(CommandRunner::default());
|
|
}
|
|
|
|
if let Err(e) = client.start().await {
|
|
log::warn!("Client error: {:?}", e);
|
|
}
|
|
}
|