Prepare architecture for custom Runtime
This commit is contained in:
parent
b34da70c8b
commit
de1eb03b13
|
@ -1,3 +1,5 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use serenity::{prelude::GatewayIntents, Client as SerenityClient};
|
||||
|
||||
use crate::{database::Client as DatabaseClient, environment::get_env_variable};
|
||||
|
@ -6,18 +8,19 @@ use crate::discord::event_handler::Handler;
|
|||
|
||||
pub struct Client {
|
||||
serenity_client: SerenityClient,
|
||||
database_client: Arc<Mutex<DatabaseClient>>,
|
||||
}
|
||||
|
||||
impl Client {
|
||||
pub async fn new() -> Self {
|
||||
let mut database_client = DatabaseClient::new();
|
||||
database_client.connect().await;
|
||||
let database_client = Arc::new(Mutex::new(DatabaseClient::new()));
|
||||
database_client.clone().lock().unwrap().connect();
|
||||
|
||||
let discord_token = get_env_variable("DISCORD_TOKEN");
|
||||
let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::MESSAGE_CONTENT;
|
||||
|
||||
let event_handler = Handler {
|
||||
database: database_client,
|
||||
database: database_client.clone(),
|
||||
};
|
||||
|
||||
let serenity_client = match SerenityClient::builder(discord_token, intents)
|
||||
|
@ -28,7 +31,10 @@ impl Client {
|
|||
Err(e) => panic!("Failed to instantiate Discord Client: {e}"),
|
||||
};
|
||||
|
||||
Client { serenity_client }
|
||||
Client {
|
||||
serenity_client,
|
||||
database_client,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn start(&mut self) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pub mod bulk_create_tag;
|
||||
pub mod create_tag;
|
||||
pub mod delete_tag;
|
||||
pub mod list_tags;
|
||||
pub mod source_code;
|
||||
mod bulk_create_tag;
|
||||
pub mod commands;
|
||||
mod create_tag;
|
||||
mod delete_tag;
|
||||
mod list_tags;
|
||||
mod source_code;
|
||||
|
|
49
src/discord/commands/commands.rs
Normal file
49
src/discord/commands/commands.rs
Normal file
|
@ -0,0 +1,49 @@
|
|||
use serenity::{
|
||||
async_trait,
|
||||
builder::CreateInteractionResponseData,
|
||||
model::prelude::{
|
||||
command::{Command, CommandOptionType},
|
||||
interaction::application_command::ApplicationCommandInteraction,
|
||||
},
|
||||
prelude::Context,
|
||||
};
|
||||
|
||||
use crate::database::Client as DatabaseClient;
|
||||
|
||||
pub struct BotCommandOption {
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub kind: CommandOptionType,
|
||||
pub required: bool,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait BotCommand {
|
||||
fn new(context: ApplicationCommandInteraction) -> Self;
|
||||
fn name() -> String;
|
||||
fn description() -> String;
|
||||
fn options_list() -> Vec<BotCommandOption>;
|
||||
async fn run(&self, response: &mut CreateInteractionResponseData, database: &DatabaseClient);
|
||||
|
||||
async fn register(context: &Context) {
|
||||
match Command::create_global_application_command(context, |command| {
|
||||
let mut new_command = command.name(Self::name()).description(Self::description());
|
||||
|
||||
for opt in Self::options_list() {
|
||||
new_command = new_command.create_option(|option| {
|
||||
option
|
||||
.name(opt.name)
|
||||
.description(opt.description)
|
||||
.kind(opt.kind)
|
||||
.required(opt.required)
|
||||
});
|
||||
}
|
||||
new_command
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => println!("Successfully registered the {} command", Self::name()),
|
||||
Err(_) => panic!("Failed to register the {} command", Self::name()),
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
use mongodb::bson::doc;
|
||||
|
||||
use serenity::{
|
||||
builder::{CreateApplicationCommand, CreateInteractionResponseData},
|
||||
async_trait,
|
||||
builder::CreateInteractionResponseData,
|
||||
model::{
|
||||
application::interaction::application_command::ApplicationCommandInteraction,
|
||||
prelude::{
|
||||
|
@ -12,61 +13,74 @@ use serenity::{
|
|||
|
||||
use crate::database::{models::Tag, Client as DatabaseClient};
|
||||
|
||||
pub fn register(command: &mut CreateApplicationCommand) -> &mut CreateApplicationCommand {
|
||||
command
|
||||
.name("create_tag")
|
||||
.description("Add a new tag")
|
||||
.create_option(|option| {
|
||||
option
|
||||
.name("tag")
|
||||
.description("The tag to create")
|
||||
.kind(CommandOptionType::String)
|
||||
.required(true)
|
||||
})
|
||||
use super::commands::{BotCommand, BotCommandOption};
|
||||
|
||||
struct CreateTagCommand {
|
||||
context: ApplicationCommandInteraction,
|
||||
}
|
||||
|
||||
pub async fn run<'a, 'b>(
|
||||
response: &'a mut CreateInteractionResponseData<'b>,
|
||||
command: &ApplicationCommandInteraction,
|
||||
database: &DatabaseClient,
|
||||
) -> &'a mut CreateInteractionResponseData<'b> {
|
||||
let arg = command
|
||||
.data
|
||||
.options
|
||||
.get(0)
|
||||
.expect("Missing option")
|
||||
.resolved
|
||||
.as_ref()
|
||||
.expect("Could not deserialize option");
|
||||
|
||||
let guild_id = command
|
||||
.guild_id
|
||||
.expect("Could not fetch guild id")
|
||||
.to_string();
|
||||
|
||||
if let CommandDataOptionValue::String(tag_name) = arg {
|
||||
let matching_tags = database
|
||||
.get_all::<Tag>(Some(doc! {"name": tag_name, "guild_id": guild_id.as_str()}))
|
||||
.await;
|
||||
|
||||
if !matching_tags.is_empty() {
|
||||
response.content("This tag already exist for this server");
|
||||
} else {
|
||||
match database
|
||||
.insert_one(Tag {
|
||||
id: None,
|
||||
name: tag_name.to_string(),
|
||||
guild_id: guild_id.clone(),
|
||||
is_nsfw: false,
|
||||
subscribers: vec![],
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => response.content("Tag successfully created."),
|
||||
Err(_) => response.content("Error creating the tag"),
|
||||
};
|
||||
}
|
||||
#[async_trait]
|
||||
impl BotCommand for CreateTagCommand {
|
||||
fn name() -> String {
|
||||
String::from("create_tag")
|
||||
}
|
||||
|
||||
response
|
||||
fn description() -> String {
|
||||
String::from("Create a new tag")
|
||||
}
|
||||
|
||||
fn options_list() -> Vec<BotCommandOption> {
|
||||
vec![BotCommandOption {
|
||||
name: String::from("tag"),
|
||||
description: String::from("The tag to create"),
|
||||
kind: CommandOptionType::String,
|
||||
required: true,
|
||||
}]
|
||||
}
|
||||
|
||||
fn new(context: ApplicationCommandInteraction) -> Self {
|
||||
CreateTagCommand { context }
|
||||
}
|
||||
|
||||
async fn run(&self, response: &mut CreateInteractionResponseData, database: &DatabaseClient) {
|
||||
let arg = self
|
||||
.context
|
||||
.data
|
||||
.options
|
||||
.get(0)
|
||||
.expect("Missing option")
|
||||
.resolved
|
||||
.as_ref()
|
||||
.expect("Could not deserialize option");
|
||||
|
||||
let guild_id = self
|
||||
.context
|
||||
.guild_id
|
||||
.expect("Could not fetch guild id")
|
||||
.to_string();
|
||||
|
||||
if let CommandDataOptionValue::String(tag_name) = arg {
|
||||
let matching_tags = database
|
||||
.get_all::<Tag>(Some(doc! {"name": tag_name, "guild_id": guild_id.as_str()}))
|
||||
.await;
|
||||
|
||||
if !matching_tags.is_empty() {
|
||||
response.content("This tag already exist for this server");
|
||||
} else {
|
||||
match database
|
||||
.insert_one(Tag {
|
||||
id: None,
|
||||
name: tag_name.to_string(),
|
||||
guild_id: guild_id.clone(),
|
||||
is_nsfw: false,
|
||||
subscribers: vec![],
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => response.content("Tag successfully created."),
|
||||
Err(_) => response.content("Error creating the tag"),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,17 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::database::Client as DatabaseClient;
|
||||
use serenity::{
|
||||
async_trait,
|
||||
model::gateway::Ready,
|
||||
model::{
|
||||
application::command::Command,
|
||||
prelude::{
|
||||
interaction::{Interaction, InteractionResponseType},
|
||||
ResumedEvent,
|
||||
},
|
||||
},
|
||||
model::prelude::{interaction::Interaction, ResumedEvent},
|
||||
prelude::{Context, EventHandler},
|
||||
};
|
||||
|
||||
use super::commands::*;
|
||||
|
||||
const MAX_ARGS_NUMBER: u32 = 25;
|
||||
|
||||
pub struct Handler {
|
||||
pub database: DatabaseClient,
|
||||
pub database: Arc<Mutex<DatabaseClient>>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
@ -25,21 +19,7 @@ impl EventHandler for Handler {
|
|||
async fn ready(&self, ctx: Context, ready: Ready) {
|
||||
println!("Successfully connected as {}", ready.user.name);
|
||||
|
||||
match Command::set_global_application_commands(&ctx.http, |commands| {
|
||||
commands
|
||||
.create_application_command(|command| source_code::register(command))
|
||||
.create_application_command(|command| create_tag::register(command))
|
||||
.create_application_command(|command| {
|
||||
bulk_create_tag::register(command, MAX_ARGS_NUMBER)
|
||||
})
|
||||
.create_application_command(|command| delete_tag::register(command))
|
||||
.create_application_command(|command| list_tags::register(command))
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(_) => println!("Successfully registered application commands"),
|
||||
Err(e) => println!("Failed to register application commands: {e}"),
|
||||
};
|
||||
// TODO: Register commands
|
||||
}
|
||||
|
||||
async fn resume(&self, _: Context, _: ResumedEvent) {
|
||||
|
@ -49,21 +29,6 @@ impl EventHandler for Handler {
|
|||
async fn interaction_create(&self, ctx: Context, interaction: Interaction) {
|
||||
if let Interaction::ApplicationCommand(command) = interaction {
|
||||
println!("Received command {}", command.data.name);
|
||||
|
||||
if let Err(e) = command
|
||||
.create_interaction_response(&ctx.http, |response| {
|
||||
response
|
||||
.kind(InteractionResponseType::ChannelMessageWithSource)
|
||||
.interaction_response_data(|message| match command.data.name.as_str() {
|
||||
"source_code" => source_code::run(message),
|
||||
"create_tag" => create_tag::run(message, &command, &self.database),
|
||||
_ => message.content("Not yet implemented"),
|
||||
})
|
||||
})
|
||||
.await
|
||||
{
|
||||
println!("Failed to answer to command: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue