feat: init setup api avec access au minimal au bot discord
This commit is contained in:
parent
070153be8a
commit
458e239b35
11
Cargo.toml
11
Cargo.toml
@ -28,20 +28,23 @@ rand = "0.8.5"
|
|||||||
walkdir = "2.4.0"
|
walkdir = "2.4.0"
|
||||||
surrealdb = "1.1.1"
|
surrealdb = "1.1.1"
|
||||||
once_cell = "1.19.0"
|
once_cell = "1.19.0"
|
||||||
poise = "0.6.1"
|
poise = { version = "0.6.1", features = ["cache"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-actix-web = "0.7.9"
|
tracing-actix-web = "0.7.9"
|
||||||
serde_repr = "0.1"
|
serde_repr = "0.1"
|
||||||
tracing-subscriber = { version = "0.3", features = ["registry", "env-filter","time"] }
|
tracing-subscriber = { version = "0.3", features = [
|
||||||
|
"registry",
|
||||||
|
"env-filter",
|
||||||
|
"time",
|
||||||
|
] }
|
||||||
time = "0.3.36"
|
time = "0.3.36"
|
||||||
tracing-bunyan-formatter = "0.3"
|
tracing-bunyan-formatter = "0.3"
|
||||||
opentelemetry = "0.23"
|
opentelemetry = "0.23"
|
||||||
opentelemetry_sdk = { version = "0.23", features = ["rt-tokio"] }
|
opentelemetry_sdk = { version = "0.23", features = ["rt-tokio"] }
|
||||||
opentelemetry-otlp = { version = "0.16"}
|
opentelemetry-otlp = { version = "0.16" }
|
||||||
tracing-opentelemetry = "0.24"
|
tracing-opentelemetry = "0.24"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "botdiscord"
|
name = "botdiscord"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
24
cog.toml
24
cog.toml
@ -1,24 +0,0 @@
|
|||||||
from_latest_tag = false
|
|
||||||
ignore_merge_commits = false
|
|
||||||
disable_changelog = false
|
|
||||||
disable_bump_commit = false
|
|
||||||
generate_mono_repository_global_tag = true
|
|
||||||
branch_whitelist = []
|
|
||||||
skip_ci = "[skip ci]"
|
|
||||||
skip_untracked = false
|
|
||||||
pre_bump_hooks = []
|
|
||||||
post_bump_hooks = []
|
|
||||||
pre_package_bump_hooks = []
|
|
||||||
post_package_bump_hooks = []
|
|
||||||
|
|
||||||
[git_hooks]
|
|
||||||
|
|
||||||
[commit_types]
|
|
||||||
|
|
||||||
[changelog]
|
|
||||||
path = "CHANGELOG.md"
|
|
||||||
authors = []
|
|
||||||
|
|
||||||
[bump_profiles]
|
|
||||||
|
|
||||||
[packages]
|
|
26
src/api/apidocs.rs
Normal file
26
src/api/apidocs.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use utoipa::OpenApi;
|
||||||
|
|
||||||
|
use crate::api::bot::info;
|
||||||
|
|
||||||
|
#[derive(OpenApi)]
|
||||||
|
#[openapi(
|
||||||
|
info(
|
||||||
|
title = "BotDiscordApi",
|
||||||
|
version = "0.1.0",
|
||||||
|
description = "Api for discord bot",
|
||||||
|
),
|
||||||
|
tags(
|
||||||
|
(name= "Auth", description = "Authentication"),
|
||||||
|
(name= "User", description = "User operations"),
|
||||||
|
(name= "Bot", description = "Bot operations")
|
||||||
|
),
|
||||||
|
components(
|
||||||
|
schemas(
|
||||||
|
info::Info,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
paths(
|
||||||
|
info::get_info,
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub struct ApiDocs;
|
40
src/api/bot/info.rs
Normal file
40
src/api/bot/info.rs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use actix_web::{get, web, HttpResponse, Responder};
|
||||||
|
use poise::serenity_prelude::Http;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, ToSchema)]
|
||||||
|
pub struct Info {
|
||||||
|
pub name: String,
|
||||||
|
pub version: String,
|
||||||
|
pub description: String,
|
||||||
|
pub available_guids: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[utoipa::path(
|
||||||
|
tag= "Bot",
|
||||||
|
operation_id = "getInfo",
|
||||||
|
path = "/api/bot/info",
|
||||||
|
responses(
|
||||||
|
(status = 200, description = "Information about the bot", body = Info),
|
||||||
|
(status = 500, description = "Internal server error")
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
#[get("/info")]
|
||||||
|
#[tracing::instrument(name = "get_info", skip(config, http))]
|
||||||
|
pub async fn get_info(config: web::Data<Config>, http: web::Data<Arc<Http>>) -> impl Responder {
|
||||||
|
let list_guilds = http.get_guilds(None, None).await;
|
||||||
|
match list_guilds {
|
||||||
|
Ok(guilds) => HttpResponse::Ok().json(Info {
|
||||||
|
name: "BotDiscord".to_string(),
|
||||||
|
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||||
|
description: config.bot_name.clone(),
|
||||||
|
available_guids: guilds.iter().map(|g| g.name.clone()).collect(),
|
||||||
|
}),
|
||||||
|
Err(e) => HttpResponse::InternalServerError().body(format!("Error getting guilds: {}", e)),
|
||||||
|
}
|
||||||
|
}
|
6
src/api/bot/mod.rs
Normal file
6
src/api/bot/mod.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
use actix_web::Scope;
|
||||||
|
pub mod info;
|
||||||
|
|
||||||
|
pub fn init_bot() -> Scope {
|
||||||
|
Scope::new("/bot").service(info::get_info)
|
||||||
|
}
|
9
src/api/init.rs
Normal file
9
src/api/init.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use actix_web::Scope;
|
||||||
|
|
||||||
|
use super::{bot, meme};
|
||||||
|
|
||||||
|
pub fn init_api() -> Scope {
|
||||||
|
Scope::new("/api")
|
||||||
|
.service(meme::init_meme())
|
||||||
|
.service(bot::init_bot())
|
||||||
|
}
|
5
src/api/meme/mod.rs
Normal file
5
src/api/meme/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
use actix_web::Scope;
|
||||||
|
|
||||||
|
pub fn init_meme() -> Scope {
|
||||||
|
Scope::new("/meme")
|
||||||
|
}
|
4
src/api/mod.rs
Normal file
4
src/api/mod.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
pub mod apidocs;
|
||||||
|
pub mod bot;
|
||||||
|
pub mod init;
|
||||||
|
pub mod meme;
|
@ -1,28 +0,0 @@
|
|||||||
use serenity::client::Context;
|
|
||||||
use serenity::framework::standard::macros::help;
|
|
||||||
use serenity::framework::standard::{
|
|
||||||
help_commands, Args, CommandGroup, CommandResult, HelpOptions,
|
|
||||||
};
|
|
||||||
use serenity::model::prelude::{Message, UserId};
|
|
||||||
use std::collections::HashSet;
|
|
||||||
|
|
||||||
#[help]
|
|
||||||
#[individual_command_tip = "Hello! Pour plus d'information sur une commande, passe la en argument."]
|
|
||||||
#[command_not_found_text = "La commande `{}` n'a pas été trouver."]
|
|
||||||
#[max_levenshtein_distance(3)]
|
|
||||||
#[wrong_channel = "Strike"]
|
|
||||||
#[lacking_role = "Hide"]
|
|
||||||
#[lacking_permissions = "Hide"]
|
|
||||||
#[strikethrough_commands_tip_in_guild("")]
|
|
||||||
#[embed_success_colour = "#5F021F"]
|
|
||||||
async fn help(
|
|
||||||
context: &Context,
|
|
||||||
msg: &Message,
|
|
||||||
args: Args,
|
|
||||||
help_options: &'static HelpOptions,
|
|
||||||
groups: &[&'static CommandGroup],
|
|
||||||
owners: HashSet<UserId>,
|
|
||||||
) -> CommandResult {
|
|
||||||
let _ = help_commands::with_embeds(context, msg, args, help_options, groups, owners).await;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,151 +0,0 @@
|
|||||||
use rand::Rng;
|
|
||||||
use serenity::{
|
|
||||||
all::Message,
|
|
||||||
builder::{CreateAttachment, CreateEmbed, CreateEmbedFooter, CreateMessage},
|
|
||||||
client::Context,
|
|
||||||
framework::standard::{macros::command, Args, CommandResult},
|
|
||||||
};
|
|
||||||
use tokio::fs::File;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
config::ConfigGlobal,
|
|
||||||
img::config_file::{ConfigImgGlobal, KeyWordItem},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[command]
|
|
||||||
#[description = "Answer your message with a meme, the keyword need to be put under quote"]
|
|
||||||
pub async fn answer(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
|
||||||
if let Ok(keyword) = args.single_quoted::<String>() {
|
|
||||||
println!("Keyword: {}", keyword);
|
|
||||||
|
|
||||||
let (config_img, config) = {
|
|
||||||
let data_read = ctx.data.read().await;
|
|
||||||
let config_img = data_read
|
|
||||||
.get::<ConfigImgGlobal>()
|
|
||||||
.expect("Config img not found")
|
|
||||||
.clone();
|
|
||||||
let config = data_read
|
|
||||||
.get::<ConfigGlobal>()
|
|
||||||
.expect("Main config not found")
|
|
||||||
.clone();
|
|
||||||
(config_img, config)
|
|
||||||
};
|
|
||||||
let folder_container = match config_img
|
|
||||||
.keyword
|
|
||||||
.iter()
|
|
||||||
.find(|keyword_under_search| keyword_under_search.does_value_match(keyword.clone()))
|
|
||||||
{
|
|
||||||
Some(keyword_matching) => {
|
|
||||||
println!("{} match {:?}", keyword, keyword_matching);
|
|
||||||
let keyword_path = match keyword_matching.path.len() {
|
|
||||||
0 => keyword_matching.path[0].clone(),
|
|
||||||
_ => {
|
|
||||||
let id: usize = {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
rng.gen_range(0..keyword_matching.path.len())
|
|
||||||
};
|
|
||||||
keyword_matching.path[id].clone()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
keyword_path.clone()
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
if let Err(why) = msg
|
|
||||||
.channel_id
|
|
||||||
.say(&ctx.http, format!("No match for {}", keyword))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let path = format!("{}/{}", config.image.path.clone(), folder_container);
|
|
||||||
let file_folder = KeyWordItem::output_folder_content(path.clone());
|
|
||||||
let id_rand: usize = {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
rng.gen_range(0..file_folder.len())
|
|
||||||
};
|
|
||||||
let filename = match file_folder.get(id_rand) {
|
|
||||||
Some(file) => file.file_name().to_str().unwrap(),
|
|
||||||
None => {
|
|
||||||
if let Err(why) = msg
|
|
||||||
.channel_id
|
|
||||||
.say(
|
|
||||||
&ctx.http,
|
|
||||||
format!("Couldn't find file in folder for {}", keyword),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let file_path = format!("{}/{}", path, filename);
|
|
||||||
let file = match File::open(file_path).await {
|
|
||||||
Ok(file) => file,
|
|
||||||
Err(why) => {
|
|
||||||
if let Err(why) = msg
|
|
||||||
.channel_id
|
|
||||||
.say(
|
|
||||||
&ctx.http,
|
|
||||||
format!("Error opening file {} => {:?}", filename, why),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let attachment = match CreateAttachment::file(&file, filename).await {
|
|
||||||
Ok(attachment) => attachment,
|
|
||||||
Err(why) => {
|
|
||||||
if let Err(why) = msg
|
|
||||||
.channel_id
|
|
||||||
.say(&ctx.http, format!("Error creating attachment: {:?}", why))
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if filename.ends_with(".mp3") || filename.ends_with(".mp4") {
|
|
||||||
let builder = CreateMessage::new()
|
|
||||||
.add_file(attachment)
|
|
||||||
.reference_message(msg);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why);
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let footer = CreateEmbedFooter::new("WeeboBot");
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title(keyword)
|
|
||||||
.footer(footer)
|
|
||||||
.image(format!("attachment://{}", filename));
|
|
||||||
let builder = CreateMessage::new()
|
|
||||||
.embed(embed)
|
|
||||||
.add_file(attachment)
|
|
||||||
.reference_message(msg);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why);
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
if let Err(why) = msg
|
|
||||||
.channel_id
|
|
||||||
.say(
|
|
||||||
&ctx.http,
|
|
||||||
"Please add keyword if you want to use this command. Example: `!meme answer \"keyword\"`",
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
use serenity::builder::{CreateEmbed, CreateEmbedFooter, CreateMessage};
|
|
||||||
use serenity::{
|
|
||||||
all::Message,
|
|
||||||
client::Context,
|
|
||||||
framework::standard::{macros::command, CommandResult},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[command]
|
|
||||||
#[description = "Info to ask for new meme"]
|
|
||||||
pub async fn ask(ctx: &Context, msg: &Message) -> CommandResult {
|
|
||||||
let footer = CreateEmbedFooter::new("WeeboBot");
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title("New meme ?")
|
|
||||||
.field("Hello, si tu souhaites ajouter un nouveau meme au bot, tu dois demander à batleforc d'en ajouter un nouveau. Tu peux le faire en lui envoyant un message.".to_string(), String::new(), true)
|
|
||||||
.footer(footer);
|
|
||||||
let builder = CreateMessage::new().embed(embed);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,96 +0,0 @@
|
|||||||
use serenity::{
|
|
||||||
all::Message,
|
|
||||||
builder::{CreateEmbed, CreateEmbedFooter, CreateMessage},
|
|
||||||
client::Context,
|
|
||||||
framework::standard::{macros::command, Args, CommandResult},
|
|
||||||
model::colour,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::db::user_image::User;
|
|
||||||
|
|
||||||
#[command]
|
|
||||||
#[description = "Enable/Disable the auto meme answer"]
|
|
||||||
pub async fn enable(ctx: &Context, msg: &Message, mut args: Args) -> CommandResult {
|
|
||||||
let guild = match msg.guild_id {
|
|
||||||
Some(guild) => guild,
|
|
||||||
None => return Ok(()),
|
|
||||||
};
|
|
||||||
let footer = CreateEmbedFooter::new("WeeboBot");
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title("Enable/Disable auto meme answer")
|
|
||||||
.footer(footer);
|
|
||||||
let mut user_in_db: User =
|
|
||||||
match User::find_by_server_id_user_id(&guild.get(), &msg.author.id.get()).await {
|
|
||||||
Ok(Some(user_in_db)) => user_in_db.clone(),
|
|
||||||
Ok(None) => {
|
|
||||||
let user_in_db = User::new(guild.get(), msg.author.id.get(), false).unwrap();
|
|
||||||
match user_in_db.create().await {
|
|
||||||
Ok(_) => user_in_db,
|
|
||||||
Err(e) => {
|
|
||||||
let embed = embed
|
|
||||||
.field("Could't create user in db", e.to_string(), false)
|
|
||||||
.color(colour::Color::RED);
|
|
||||||
let builder = CreateMessage::new().embed(embed).reference_message(msg);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
println!("Error saving user image: {:?}", e);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
let embed = embed
|
|
||||||
.field("Error finding user image", e.to_string(), false)
|
|
||||||
.color(colour::Color::RED);
|
|
||||||
let builder = CreateMessage::new().embed(embed).reference_message(msg);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
println!("Error finding user image: {:?}", e);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if let Ok(new_status) = args.single::<bool>() {
|
|
||||||
if user_in_db.enable == new_status {
|
|
||||||
let embed = embed.field(
|
|
||||||
format!("Auto answer the same : {}", new_status),
|
|
||||||
String::new(),
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
let builder = CreateMessage::new().embed(embed).reference_message(msg);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
user_in_db.enable = new_status;
|
|
||||||
match user_in_db.update().await {
|
|
||||||
Ok(_) => {
|
|
||||||
let embed = embed.field("Auto answer", new_status.to_string(), false);
|
|
||||||
let builder = CreateMessage::new().embed(embed).reference_message(msg);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
let embed = embed.field("Couldn't update user in db", e.to_string(), false);
|
|
||||||
let builder = CreateMessage::new().embed(embed).reference_message(msg);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
println!("Error saving user image: {:?}", e);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
} else {
|
|
||||||
let embed = embed.field("Auto answer", user_in_db.enable.to_string(), false);
|
|
||||||
let builder = CreateMessage::new().embed(embed).reference_message(msg);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
use super::{answer::ANSWER_COMMAND, ask::ASK_COMMAND, enable::ENABLE_COMMAND, list::LIST_COMMAND};
|
|
||||||
use serenity::all::standard::macros::group;
|
|
||||||
|
|
||||||
// Include the meme commands
|
|
||||||
// - enable/disable the meme answer
|
|
||||||
// - trigger a one time meme answer (default command)
|
|
||||||
// - make a request to add a new meme
|
|
||||||
// - list meme categories
|
|
||||||
#[group]
|
|
||||||
#[prefixes("meme", "m")]
|
|
||||||
#[summary = "Meme related commands"]
|
|
||||||
#[description = "Commands to handle the meme related stuffs, it allow you to enable/disable the meme answer or to trigger a one time meme answer."]
|
|
||||||
#[commands(enable, answer, ask, list)]
|
|
||||||
#[default_command(answer)]
|
|
||||||
pub struct Meme;
|
|
@ -1,44 +0,0 @@
|
|||||||
use serenity::builder::{CreateEmbed, CreateEmbedFooter, CreateMessage};
|
|
||||||
use serenity::{
|
|
||||||
all::Message,
|
|
||||||
client::Context,
|
|
||||||
framework::standard::{macros::command, CommandResult},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::img::config_file::ConfigImgGlobal;
|
|
||||||
|
|
||||||
#[command]
|
|
||||||
#[description = "List supported meme keywords"]
|
|
||||||
pub async fn list(ctx: &Context, msg: &Message) -> CommandResult {
|
|
||||||
let config_img = {
|
|
||||||
let data_read = ctx.data.read().await;
|
|
||||||
data_read
|
|
||||||
.get::<ConfigImgGlobal>()
|
|
||||||
.expect("Config img not found")
|
|
||||||
.clone()
|
|
||||||
};
|
|
||||||
let list_value: Vec<(String, String, bool)> = config_img
|
|
||||||
.keyword
|
|
||||||
.iter()
|
|
||||||
.map(|x| (x.value.clone().join(", "), String::new(), true))
|
|
||||||
.collect();
|
|
||||||
if list_value.is_empty() {
|
|
||||||
let builder = CreateMessage::new().content("No meme keyword found");
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
for chunks in list_value.chunks(25) {
|
|
||||||
let footer = CreateEmbedFooter::new("WeeboBot");
|
|
||||||
let embed = CreateEmbed::new()
|
|
||||||
.title("Meme List")
|
|
||||||
.fields(chunks.to_vec())
|
|
||||||
.footer(footer);
|
|
||||||
let builder = CreateMessage::new().embed(embed);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
pub mod answer;
|
|
||||||
pub mod ask;
|
|
||||||
pub mod enable;
|
|
||||||
pub mod init;
|
|
||||||
pub mod list;
|
|
@ -1,3 +0,0 @@
|
|||||||
pub mod help;
|
|
||||||
pub mod meme;
|
|
||||||
pub mod ping;
|
|
@ -1,14 +0,0 @@
|
|||||||
use serenity::{
|
|
||||||
all::Message,
|
|
||||||
client::Context,
|
|
||||||
framework::standard::{macros::command, CommandResult},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[command]
|
|
||||||
#[description = "Pong!"]
|
|
||||||
pub async fn ping(ctx: &Context, msg: &Message) -> CommandResult {
|
|
||||||
if let Err(why) = msg.channel_id.say(&ctx.http, "Pong from framework!").await {
|
|
||||||
println!("Error sending message: {:?}", why)
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
use rand::Rng;
|
|
||||||
use serenity::prelude::*;
|
|
||||||
use serenity::{
|
|
||||||
all::{Message, Ready},
|
|
||||||
async_trait,
|
|
||||||
builder::{CreateAttachment, CreateMessage},
|
|
||||||
client::Context,
|
|
||||||
};
|
|
||||||
use tokio::fs::File;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
config::ConfigGlobal,
|
|
||||||
db::user_image::User,
|
|
||||||
img::config_file::{ConfigImgGlobal, KeyWordItem},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
pub struct Handler;
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl EventHandler for Handler {
|
|
||||||
async fn message(&self, ctx: Context, msg: Message) {
|
|
||||||
if msg.author.bot || msg.content.starts_with("!") || msg.content.len() == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let guild = match msg.guild_id {
|
|
||||||
Some(guild) => guild,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
let user_in_db: User =
|
|
||||||
match User::find_by_server_id_user_id(&guild.get(), &msg.author.id.get()).await {
|
|
||||||
Ok(Some(user_in_db)) => user_in_db.clone(),
|
|
||||||
Ok(None) => {
|
|
||||||
let user_in_db =
|
|
||||||
User::new(guild.get(), msg.author.id.get(), false).unwrap();
|
|
||||||
match user_in_db.create().await {
|
|
||||||
Ok(_) => user_in_db,
|
|
||||||
Err(e) => {
|
|
||||||
println!("Error saving user image: {:?}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
println!("Error finding user image: {:?}", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if !user_in_db.enable {
|
|
||||||
println!("User image is not enable");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let (config_img, config) = {
|
|
||||||
let data_read = ctx.data.read().await;
|
|
||||||
let config_img = data_read
|
|
||||||
.get::<ConfigImgGlobal>()
|
|
||||||
.expect("Config img not found")
|
|
||||||
.clone();
|
|
||||||
let config = data_read
|
|
||||||
.get::<ConfigGlobal>()
|
|
||||||
.expect("Main config not found")
|
|
||||||
.clone();
|
|
||||||
(config_img, config)
|
|
||||||
};
|
|
||||||
|
|
||||||
if config_img.keyword.len() == 0 || msg.content.len() > 50 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let folder_container = match config_img
|
|
||||||
.keyword
|
|
||||||
.iter()
|
|
||||||
.find(|keyword| keyword.does_value_match(msg.content.clone()))
|
|
||||||
{
|
|
||||||
Some(keyword_matching) => {
|
|
||||||
println!("{} match {:?}", msg.content, keyword_matching);
|
|
||||||
let keyword_path = match keyword_matching.path.len() {
|
|
||||||
0 => keyword_matching.path[0].clone(),
|
|
||||||
_ => {
|
|
||||||
let id: usize = {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
rng.gen_range(0..keyword_matching.path.len())
|
|
||||||
};
|
|
||||||
keyword_matching.path[id].clone()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
keyword_path.clone()
|
|
||||||
}
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
let path = format!("{}/{}", config.image.path.clone(), folder_container);
|
|
||||||
let file_folder = KeyWordItem::output_folder_content(path.clone());
|
|
||||||
let id_rand: usize = {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
rng.gen_range(0..file_folder.len())
|
|
||||||
};
|
|
||||||
let filename = match file_folder.get(id_rand) {
|
|
||||||
Some(file) => file.file_name().to_str().unwrap(),
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
let file_path = format!("{}/{}", path, filename);
|
|
||||||
let file = match File::open(file_path).await {
|
|
||||||
Ok(file) => file,
|
|
||||||
Err(why) => {
|
|
||||||
println!("Error opening file: {:?}", why);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let attachment = match CreateAttachment::file(&file, filename).await {
|
|
||||||
Ok(attachment) => attachment,
|
|
||||||
Err(why) => {
|
|
||||||
println!("Error creating attachment: {:?}", why);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let builder = CreateMessage::new().add_file(attachment);
|
|
||||||
if let Err(why) = msg.channel_id.send_message(&ctx.http, builder).await {
|
|
||||||
println!("Error sending message: {:?}", why);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn ready(&self, _: Context, ready: Ready) {
|
|
||||||
println!("{} is connected!", ready.user.name);
|
|
||||||
}
|
|
||||||
}
|
|
124
src/bot/init.rs
124
src/bot/init.rs
@ -1,124 +0,0 @@
|
|||||||
use super::cmd::meme::init::MEME_GROUP;
|
|
||||||
use super::cmd::{help::HELP, ping::PING_COMMAND};
|
|
||||||
use super::handler::Handler;
|
|
||||||
use crate::config::{Config, ConfigGlobal};
|
|
||||||
use crate::img::config_file::{ConfigFile, ConfigImgGlobal};
|
|
||||||
use serenity::framework::standard::Configuration;
|
|
||||||
use serenity::{
|
|
||||||
all::GatewayIntents,
|
|
||||||
framework::{standard::macros::group, StandardFramework},
|
|
||||||
http::Http,
|
|
||||||
Client,
|
|
||||||
};
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::fs;
|
|
||||||
use tokio::sync::oneshot;
|
|
||||||
use tokio::task::spawn_blocking;
|
|
||||||
|
|
||||||
#[group]
|
|
||||||
#[commands(ping)]
|
|
||||||
struct General;
|
|
||||||
|
|
||||||
pub fn start_bot(config: Config, rx: oneshot::Receiver<()>) {
|
|
||||||
if config.token != "" {
|
|
||||||
spawn_blocking(move || {
|
|
||||||
let rt = tokio::runtime::Handle::current();
|
|
||||||
rt.block_on(async move {
|
|
||||||
let local = tokio::task::LocalSet::new();
|
|
||||||
let _ = local
|
|
||||||
.run_until(async move {
|
|
||||||
let config_img = match fs::read_to_string(format!(
|
|
||||||
"{}/config.yaml",
|
|
||||||
config.image.path
|
|
||||||
)) {
|
|
||||||
Ok(content) => content,
|
|
||||||
Err(err) => {
|
|
||||||
println!("Error while opening config.yaml : {:?}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let config_parsed = match ConfigFile::parse_config(config_img) {
|
|
||||||
Ok(config) => config,
|
|
||||||
Err(err) => {
|
|
||||||
println!("Error while parsing config.yaml : {:?}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let intents = GatewayIntents::GUILD_MESSAGES
|
|
||||||
| GatewayIntents::DIRECT_MESSAGES
|
|
||||||
| GatewayIntents::MESSAGE_CONTENT
|
|
||||||
| GatewayIntents::GUILD_VOICE_STATES
|
|
||||||
| GatewayIntents::GUILDS
|
|
||||||
| GatewayIntents::GUILD_MEMBERS
|
|
||||||
| GatewayIntents::GUILD_PRESENCES
|
|
||||||
| GatewayIntents::GUILD_MESSAGE_REACTIONS;
|
|
||||||
let http = Http::new(&config.token);
|
|
||||||
let (owners, _bot_id) = match http.get_current_application_info().await {
|
|
||||||
Ok(info) => {
|
|
||||||
let mut owners = HashSet::new();
|
|
||||||
match info.owner {
|
|
||||||
Some(user) => {
|
|
||||||
owners.insert(user.id);
|
|
||||||
println!("{}", user.global_name.unwrap())
|
|
||||||
}
|
|
||||||
None => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
(owners, info.id)
|
|
||||||
}
|
|
||||||
Err(why) => panic!("Could not access application info: {:?}", why),
|
|
||||||
};
|
|
||||||
|
|
||||||
let framework = StandardFramework::new()
|
|
||||||
.help(&HELP)
|
|
||||||
.group(&GENERAL_GROUP)
|
|
||||||
.group(&MEME_GROUP);
|
|
||||||
|
|
||||||
framework.configure(
|
|
||||||
Configuration::new()
|
|
||||||
.with_whitespace(true)
|
|
||||||
.prefix(config.prefix.clone())
|
|
||||||
.owners(owners),
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut client = Client::builder(&config.token, intents)
|
|
||||||
.event_handler(Handler)
|
|
||||||
.framework(framework)
|
|
||||||
.await
|
|
||||||
.expect("Err creating client");
|
|
||||||
|
|
||||||
{
|
|
||||||
// Open the data lock in write mode, so keys can be inserted to it.
|
|
||||||
let mut data = client.data.write().await;
|
|
||||||
|
|
||||||
data.insert::<ConfigImgGlobal>(config_parsed.clone());
|
|
||||||
data.insert::<ConfigGlobal>(config.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
let shard_manager = client.shard_manager.clone();
|
|
||||||
let client_start = client.start_autosharded();
|
|
||||||
tokio::spawn(async move {
|
|
||||||
match rx.await {
|
|
||||||
Ok(_) => {
|
|
||||||
println!("Received shutdown signal");
|
|
||||||
shard_manager.shutdown_all().await;
|
|
||||||
println!("Shutting down bot");
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
println!("Channel dropped signal");
|
|
||||||
shard_manager.shutdown_all().await;
|
|
||||||
println!("Shutting down bot");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Err(why) = client_start.await {
|
|
||||||
println!("Client error: {why:?}");
|
|
||||||
}
|
|
||||||
println!("Bot stopped.");
|
|
||||||
})
|
|
||||||
.await;
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
pub mod cmd;
|
|
||||||
pub mod handler;
|
|
||||||
pub mod init;
|
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::botv2::{
|
||||||
botv2::init::{Context, Error},
|
|
||||||
domain::meme::answer::{answer_meme, AnswerResult},
|
domain::meme::answer::{answer_meme, AnswerResult},
|
||||||
|
init::{Context, Error},
|
||||||
};
|
};
|
||||||
use poise::CreateReply;
|
use poise::CreateReply;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::botv2::{
|
||||||
botv2::init::{Context, Error},
|
|
||||||
domain::meme::change_auto_meme::change_auto_meme,
|
domain::meme::change_auto_meme::change_auto_meme,
|
||||||
|
init::{Context, Error},
|
||||||
};
|
};
|
||||||
use poise::CreateReply;
|
use poise::CreateReply;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
@ -16,7 +16,11 @@ pub async fn enable(
|
|||||||
Some(guild) => guild,
|
Some(guild) => guild,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
let embed = change_auto_meme(enable, ctx.author().id.get(), guild.get()).await;
|
let entity_name = ctx.data().entity_name.clone();
|
||||||
|
let embed: Result<
|
||||||
|
Vec<poise::serenity_prelude::CreateEmbed>,
|
||||||
|
crate::botv2::domain::meme::change_auto_meme::MemeChangeAutoMemeError,
|
||||||
|
> = change_auto_meme(enable, ctx.author().id.get(), guild.get(), entity_name).await;
|
||||||
let mut reply = CreateReply::default();
|
let mut reply = CreateReply::default();
|
||||||
if let Ok(embed) = embed {
|
if let Ok(embed) = embed {
|
||||||
reply.embeds = embed;
|
reply.embeds = embed;
|
||||||
|
@ -16,13 +16,13 @@ pub async fn change_auto_meme(
|
|||||||
enable: Option<bool>,
|
enable: Option<bool>,
|
||||||
user_id: u64,
|
user_id: u64,
|
||||||
guild_id: u64,
|
guild_id: u64,
|
||||||
|
bot_entity: String,
|
||||||
) -> Result<Vec<CreateEmbed>, MemeChangeAutoMemeError> {
|
) -> Result<Vec<CreateEmbed>, MemeChangeAutoMemeError> {
|
||||||
let footer = CreateEmbedFooter::new("WeeboBot");
|
let footer = CreateEmbedFooter::new(bot_entity.clone());
|
||||||
let mut embed = CreateEmbed::new()
|
let mut embed = CreateEmbed::new()
|
||||||
.title("Enable/Disable auto meme answer")
|
.title("Enable/Disable auto meme answer")
|
||||||
.footer(footer);
|
.footer(footer);
|
||||||
let mut user_in_db: User =
|
let mut user_in_db: User = match User::find_by_server_id_user_id(&guild_id, &user_id).await {
|
||||||
match User::find_by_server_id_user_id(&guild_id, &user_id).await {
|
|
||||||
Ok(Some(user_in_db)) => user_in_db.clone(),
|
Ok(Some(user_in_db)) => user_in_db.clone(),
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
let user_in_db = User::new(guild_id, user_id, false).unwrap();
|
let user_in_db = User::new(guild_id, user_id, false).unwrap();
|
@ -4,6 +4,7 @@ use poise::serenity_prelude as serenity;
|
|||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use serenity::all::{CreateAttachment, CreateMessage};
|
use serenity::all::{CreateAttachment, CreateMessage};
|
||||||
use tokio::fs::File;
|
use tokio::fs::File;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
pub async fn event_handler(
|
pub async fn event_handler(
|
||||||
ctx: &serenity::Context,
|
ctx: &serenity::Context,
|
||||||
@ -13,7 +14,7 @@ pub async fn event_handler(
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
match event {
|
match event {
|
||||||
serenity::FullEvent::Ready { data_about_bot, .. } => {
|
serenity::FullEvent::Ready { data_about_bot, .. } => {
|
||||||
println!("{} is connected !", data_about_bot.user.name);
|
info!("{} is connected !", data_about_bot.user.name);
|
||||||
}
|
}
|
||||||
serenity::FullEvent::Message { new_message } => {
|
serenity::FullEvent::Message { new_message } => {
|
||||||
if new_message.author.bot
|
if new_message.author.bot
|
||||||
|
@ -2,12 +2,13 @@ use crate::botv2::cmd::meme::{answer::answer, enable::enable, list::list};
|
|||||||
use crate::botv2::cmd::{help::help, ping::ping};
|
use crate::botv2::cmd::{help::help, ping::ping};
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::{botv2::handler::event_handler, img::config_file::ConfigFile};
|
use crate::{botv2::handler::event_handler, img::config_file::ConfigFile};
|
||||||
use poise::serenity_prelude as serenity;
|
use poise::serenity_prelude::{self as serenity, Http};
|
||||||
use serenity::GatewayIntents;
|
use serenity::GatewayIntents;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use std::sync::Arc;
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use tokio::task::spawn_blocking;
|
use tracing::{info, instrument};
|
||||||
use tracing::instrument;
|
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
pub config_img: ConfigFile,
|
pub config_img: ConfigFile,
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
@ -30,29 +31,19 @@ async fn age(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_bot(config: Config, rx: oneshot::Receiver<()>) {
|
pub async fn start_bot(config: Config, rx: oneshot::Receiver<()>) -> Arc<Http> {
|
||||||
if config.token != "" {
|
let config_img = match fs::read_to_string(format!("{}/config.yaml", config.image.path)) {
|
||||||
spawn_blocking(move || {
|
|
||||||
let rt = tokio::runtime::Handle::current();
|
|
||||||
rt.block_on(async move {
|
|
||||||
let local = tokio::task::LocalSet::new();
|
|
||||||
let _ = local
|
|
||||||
.run_until(async move {
|
|
||||||
let config_img = match fs::read_to_string(format!(
|
|
||||||
"{}/config.yaml",
|
|
||||||
config.image.path
|
|
||||||
)) {
|
|
||||||
Ok(content) => content,
|
Ok(content) => content,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Error while opening config.yaml : {:?}", err);
|
tracing::error!("Error while opening config.yaml : {:?}", err);
|
||||||
return;
|
panic!("Error while opening config.yaml : {:?}", err)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let config_parsed = match ConfigFile::parse_config(config_img) {
|
let config_parsed = match ConfigFile::parse_config(config_img) {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Error while parsing config.yaml : {:?}", err);
|
tracing::error!("Error while parsing config.yaml : {:?}", err);
|
||||||
return;
|
panic!("Error while parsing config.yaml : {:?}", err)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let intents = GatewayIntents::GUILD_MESSAGES
|
let intents = GatewayIntents::GUILD_MESSAGES
|
||||||
@ -79,15 +70,15 @@ pub fn start_bot(config: Config, rx: oneshot::Receiver<()>) {
|
|||||||
})
|
})
|
||||||
.setup(|ctx, _ready, framework| {
|
.setup(|ctx, _ready, framework| {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
poise::builtins::register_globally(
|
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
||||||
ctx,
|
|
||||||
&framework.options().commands,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
Ok(Data {
|
Ok(Data {
|
||||||
config_img: config_parsed,
|
config_img: config_parsed,
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
entity_name: config.bot_name.clone(),
|
entity_name: format!(
|
||||||
|
"{}-{}",
|
||||||
|
config.bot_name.clone(),
|
||||||
|
env!("CARGO_PKG_VERSION").to_string()
|
||||||
|
),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -96,30 +87,28 @@ pub fn start_bot(config: Config, rx: oneshot::Receiver<()>) {
|
|||||||
.framework(framework)
|
.framework(framework)
|
||||||
.await
|
.await
|
||||||
.expect("Error creating client");
|
.expect("Error creating client");
|
||||||
|
let http = client.http.clone();
|
||||||
let shard_manager = client.shard_manager.clone();
|
let shard_manager = client.shard_manager.clone();
|
||||||
let client_start = client.start_autosharded();
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
match rx.await {
|
match rx.await {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
println!("Received shutdown signal");
|
tracing::info!("Received shutdown signal");
|
||||||
shard_manager.shutdown_all().await;
|
shard_manager.shutdown_all().await;
|
||||||
println!("Shutting down bot");
|
tracing::info!("Shutting down bot");
|
||||||
}
|
}
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
println!("Channel dropped signal");
|
tracing::info!("Channel dropped signal");
|
||||||
shard_manager.shutdown_all().await;
|
shard_manager.shutdown_all().await;
|
||||||
println!("Shutting down bot");
|
tracing::info!("Shutting down bot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
println!("Bot is running...");
|
tokio::spawn(async move {
|
||||||
if let Err(why) = client_start.await {
|
info!("Bot is running...");
|
||||||
println!("Client error: {why:?}");
|
if let Err(why) = client.start_autosharded().await {
|
||||||
|
tracing::error!("Client error: {why:?}");
|
||||||
}
|
}
|
||||||
println!("Bot is stopped...");
|
info!("Bot is stopped...");
|
||||||
})
|
|
||||||
.await;
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
http
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
pub mod init;
|
|
||||||
pub mod handler;
|
|
||||||
pub mod cmd;
|
pub mod cmd;
|
||||||
|
pub mod domain;
|
||||||
|
pub mod handler;
|
||||||
|
pub mod init;
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
use crate::tracing::tracing_kind::Tracing;
|
||||||
use dotenvy::dotenv;
|
use dotenvy::dotenv;
|
||||||
use serde::Deserialize;
|
|
||||||
use poise::serenity_prelude::prelude::TypeMapKey;
|
use poise::serenity_prelude::prelude::TypeMapKey;
|
||||||
|
use serde::Deserialize;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use crate::tracing::tracing_kind::Tracing;
|
use tracing::{info, trace};
|
||||||
|
|
||||||
const DB_URL: &str = "DB_URL";
|
const DB_URL: &str = "DB_URL";
|
||||||
const DB_USER: &str = "DB_USER";
|
const DB_USER: &str = "DB_USER";
|
||||||
@ -60,10 +61,10 @@ pub struct PersistenceConfig {
|
|||||||
|
|
||||||
pub fn parse_local_config() -> Config {
|
pub fn parse_local_config() -> Config {
|
||||||
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
println!(env!("CARGO_MANIFEST_DIR"));
|
trace!(env!("CARGO_MANIFEST_DIR"));
|
||||||
d.push("resources/config.toml");
|
d.push("resources/config.toml");
|
||||||
match dotenv() {
|
match dotenv() {
|
||||||
Ok(_) => println!("Loaded .env file"),
|
Ok(_) => info!("Loaded .env file"),
|
||||||
Err(err) => println!("No .env file found: {:?}", err),
|
Err(err) => println!("No .env file found: {:?}", err),
|
||||||
}
|
}
|
||||||
parse_config(d)
|
parse_config(d)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
pub mod api;
|
||||||
|
pub mod botv2;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod img;
|
pub mod img;
|
||||||
pub mod botv2;
|
|
||||||
pub mod domain;
|
|
||||||
pub mod tracing;
|
pub mod tracing;
|
55
src/main.rs
55
src/main.rs
@ -1,11 +1,19 @@
|
|||||||
extern crate botdiscord;
|
extern crate botdiscord;
|
||||||
use std::{process, time::Duration};
|
use ::tracing::info;
|
||||||
use actix_cors::Cors;
|
use actix_cors::Cors;
|
||||||
use actix_web::{App, HttpServer};
|
use actix_web::dev::Service;
|
||||||
use botdiscord::{botv2::init::start_bot, tracing};
|
use actix_web::http::header;
|
||||||
|
use actix_web::{web, App, HttpServer};
|
||||||
|
use botdiscord::api::apidocs::ApiDocs;
|
||||||
|
use botdiscord::api::init::init_api;
|
||||||
use botdiscord::config::parse_local_config;
|
use botdiscord::config::parse_local_config;
|
||||||
use tokio::{sync::oneshot, time::sleep};
|
|
||||||
use botdiscord::db;
|
use botdiscord::db;
|
||||||
|
use botdiscord::{botv2::init::start_bot, tracing};
|
||||||
|
use std::{process, time::Duration};
|
||||||
|
use tokio::{sync::oneshot, time::sleep};
|
||||||
|
use tracing_actix_web::{RequestId, TracingLogger};
|
||||||
|
use utoipa::OpenApi;
|
||||||
|
use utoipa_swagger_ui::SwaggerUi;
|
||||||
|
|
||||||
#[tokio::main] // or #[actix_web::main]
|
#[tokio::main] // or #[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
@ -20,21 +28,50 @@ async fn main() -> std::io::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
start_bot(config.clone(), rx);
|
let http = start_bot(config.clone(), rx).await;
|
||||||
HttpServer::new(|| {
|
info!("API Server started on port {}", port);
|
||||||
|
let mut openapi = ApiDocs::openapi();
|
||||||
|
openapi.info.title = format!("{} Api", config.bot_name.clone());
|
||||||
|
openapi.info.version = env!("CARGO_PKG_VERSION").to_string();
|
||||||
|
let api_config = config.clone();
|
||||||
|
HttpServer::new(move || {
|
||||||
let cors = Cors::default()
|
let cors = Cors::default()
|
||||||
.allow_any_header()
|
.allow_any_header()
|
||||||
.allow_any_method()
|
.allow_any_method()
|
||||||
.allow_any_origin();
|
.allow_any_origin();
|
||||||
App::new().wrap(cors)
|
let swagger_ui =
|
||||||
|
SwaggerUi::new("/api/docs/{_:.*}").url("/api/docs/docs.json", openapi.clone());
|
||||||
|
App::new()
|
||||||
|
.app_data(web::Data::new(api_config.clone()))
|
||||||
|
.app_data(web::Data::new(http.clone()))
|
||||||
|
.wrap(cors)
|
||||||
|
.service(swagger_ui)
|
||||||
|
.service(
|
||||||
|
init_api()
|
||||||
|
.wrap_fn(|mut req, srv| {
|
||||||
|
let request_id_asc = req.extract::<RequestId>();
|
||||||
|
let fut = srv.call(req);
|
||||||
|
async move {
|
||||||
|
let mut res = fut.await?;
|
||||||
|
let request_id: RequestId = request_id_asc.await.unwrap();
|
||||||
|
let request_id_str = format!("{}", request_id);
|
||||||
|
let headers = res.headers_mut();
|
||||||
|
headers.insert(
|
||||||
|
header::HeaderName::from_static("x-request-id"),
|
||||||
|
header::HeaderValue::from_str(request_id_str.as_str()).unwrap(),
|
||||||
|
);
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.wrap(TracingLogger::default()),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.bind(("0.0.0.0", port))?
|
.bind(("0.0.0.0", port))?
|
||||||
.run()
|
.run()
|
||||||
.await?;
|
.await?;
|
||||||
println!("API Server stopped.");
|
info!("API Server stopped.");
|
||||||
tx.send(()).unwrap();
|
tx.send(()).unwrap();
|
||||||
tracing::init::stop_tracing(config.tracing.clone(), config.bot_name.clone());
|
tracing::init::stop_tracing(config.tracing.clone(), config.bot_name.clone());
|
||||||
println!("Signal sent to bot.");
|
|
||||||
sleep(Duration::from_secs(2)).await;
|
sleep(Duration::from_secs(2)).await;
|
||||||
process::exit(1); // This is a workaround to stop the bot, it should be replaced by a better solution
|
process::exit(1); // This is a workaround to stop the bot, it should be replaced by a better solution
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user