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"
|
||||
surrealdb = "1.1.1"
|
||||
once_cell = "1.19.0"
|
||||
poise = "0.6.1"
|
||||
poise = { version = "0.6.1", features = ["cache"] }
|
||||
tracing = "0.1"
|
||||
tracing-actix-web = "0.7.9"
|
||||
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"
|
||||
tracing-bunyan-formatter = "0.3"
|
||||
opentelemetry = "0.23"
|
||||
opentelemetry_sdk = { version = "0.23", features = ["rt-tokio"] }
|
||||
opentelemetry-otlp = { version = "0.16"}
|
||||
opentelemetry-otlp = { version = "0.16" }
|
||||
tracing-opentelemetry = "0.24"
|
||||
|
||||
|
||||
|
||||
[[bin]]
|
||||
name = "botdiscord"
|
||||
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::{
|
||||
botv2::init::{Context, Error},
|
||||
use crate::botv2::{
|
||||
domain::meme::answer::{answer_meme, AnswerResult},
|
||||
init::{Context, Error},
|
||||
};
|
||||
use poise::CreateReply;
|
||||
use tracing::instrument;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
botv2::init::{Context, Error},
|
||||
use crate::botv2::{
|
||||
domain::meme::change_auto_meme::change_auto_meme,
|
||||
init::{Context, Error},
|
||||
};
|
||||
use poise::CreateReply;
|
||||
use tracing::instrument;
|
||||
@ -16,7 +16,11 @@ pub async fn enable(
|
||||
Some(guild) => guild,
|
||||
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();
|
||||
if let Ok(embed) = embed {
|
||||
reply.embeds = embed;
|
||||
|
@ -16,33 +16,33 @@ pub async fn change_auto_meme(
|
||||
enable: Option<bool>,
|
||||
user_id: u64,
|
||||
guild_id: u64,
|
||||
bot_entity: String,
|
||||
) -> Result<Vec<CreateEmbed>, MemeChangeAutoMemeError> {
|
||||
let footer = CreateEmbedFooter::new("WeeboBot");
|
||||
let footer = CreateEmbedFooter::new(bot_entity.clone());
|
||||
let mut 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_id, &user_id).await {
|
||||
Ok(Some(user_in_db)) => user_in_db.clone(),
|
||||
Ok(None) => {
|
||||
let user_in_db = User::new(guild_id, user_id, 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);
|
||||
return Ok(vec![embed]);
|
||||
}
|
||||
let mut user_in_db: User = match User::find_by_server_id_user_id(&guild_id, &user_id).await {
|
||||
Ok(Some(user_in_db)) => user_in_db.clone(),
|
||||
Ok(None) => {
|
||||
let user_in_db = User::new(guild_id, user_id, 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);
|
||||
return Ok(vec![embed]);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
let embed = embed
|
||||
.field("Error finding user image", e.to_string(), false)
|
||||
.color(colour::Color::RED);
|
||||
return Ok(vec![embed]);
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(e) => {
|
||||
let embed = embed
|
||||
.field("Error finding user image", e.to_string(), false)
|
||||
.color(colour::Color::RED);
|
||||
return Ok(vec![embed]);
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(new_status) = enable {
|
||||
if user_in_db.enable == new_status {
|
||||
@ -66,4 +66,4 @@ pub async fn change_auto_meme(
|
||||
embed = embed.field("Auto answer", user_in_db.enable.to_string(), false);
|
||||
}
|
||||
return Ok(vec![embed]);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ use poise::serenity_prelude as serenity;
|
||||
use rand::Rng;
|
||||
use serenity::all::{CreateAttachment, CreateMessage};
|
||||
use tokio::fs::File;
|
||||
use tracing::info;
|
||||
|
||||
pub async fn event_handler(
|
||||
ctx: &serenity::Context,
|
||||
@ -13,7 +14,7 @@ pub async fn event_handler(
|
||||
) -> Result<(), Error> {
|
||||
match event {
|
||||
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 } => {
|
||||
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::config::Config;
|
||||
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 std::fs;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::task::spawn_blocking;
|
||||
use tracing::instrument;
|
||||
use tracing::{info, instrument};
|
||||
|
||||
pub struct Data {
|
||||
pub config_img: ConfigFile,
|
||||
pub config: Config,
|
||||
@ -30,96 +31,84 @@ async fn age(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 token = config.token.clone();
|
||||
let prefix = config.prefix.clone();
|
||||
let framework = poise::Framework::builder()
|
||||
.options(poise::FrameworkOptions {
|
||||
commands: vec![age(), ping(), help(), list(), enable(), answer()],
|
||||
prefix_options: poise::PrefixFrameworkOptions {
|
||||
prefix: Some(prefix.into()),
|
||||
..Default::default()
|
||||
},
|
||||
event_handler: |ctx, event, framework, data| {
|
||||
Box::pin(event_handler(ctx, event, framework, data))
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.setup(|ctx, _ready, framework| {
|
||||
Box::pin(async move {
|
||||
poise::builtins::register_globally(
|
||||
ctx,
|
||||
&framework.options().commands,
|
||||
)
|
||||
.await?;
|
||||
Ok(Data {
|
||||
config_img: config_parsed,
|
||||
config: config.clone(),
|
||||
entity_name: config.bot_name.clone(),
|
||||
})
|
||||
})
|
||||
})
|
||||
.build();
|
||||
let mut client = serenity::ClientBuilder::new(token, intents)
|
||||
.framework(framework)
|
||||
.await
|
||||
.expect("Error creating client");
|
||||
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");
|
||||
}
|
||||
}
|
||||
});
|
||||
println!("Bot is running...");
|
||||
if let Err(why) = client_start.await {
|
||||
println!("Client error: {why:?}");
|
||||
}
|
||||
println!("Bot is stopped...");
|
||||
})
|
||||
.await;
|
||||
pub async fn start_bot(config: Config, rx: oneshot::Receiver<()>) -> Arc<Http> {
|
||||
let config_img = match fs::read_to_string(format!("{}/config.yaml", config.image.path)) {
|
||||
Ok(content) => content,
|
||||
Err(err) => {
|
||||
tracing::error!("Error while opening config.yaml : {:?}", err);
|
||||
panic!("Error while opening config.yaml : {:?}", err)
|
||||
}
|
||||
};
|
||||
let config_parsed = match ConfigFile::parse_config(config_img) {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
tracing::error!("Error while parsing config.yaml : {:?}", err);
|
||||
panic!("Error while parsing config.yaml : {:?}", err)
|
||||
}
|
||||
};
|
||||
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 token = config.token.clone();
|
||||
let prefix = config.prefix.clone();
|
||||
let framework = poise::Framework::builder()
|
||||
.options(poise::FrameworkOptions {
|
||||
commands: vec![age(), ping(), help(), list(), enable(), answer()],
|
||||
prefix_options: poise::PrefixFrameworkOptions {
|
||||
prefix: Some(prefix.into()),
|
||||
..Default::default()
|
||||
},
|
||||
event_handler: |ctx, event, framework, data| {
|
||||
Box::pin(event_handler(ctx, event, framework, data))
|
||||
},
|
||||
..Default::default()
|
||||
})
|
||||
.setup(|ctx, _ready, framework| {
|
||||
Box::pin(async move {
|
||||
poise::builtins::register_globally(ctx, &framework.options().commands).await?;
|
||||
Ok(Data {
|
||||
config_img: config_parsed,
|
||||
config: config.clone(),
|
||||
entity_name: format!(
|
||||
"{}-{}",
|
||||
config.bot_name.clone(),
|
||||
env!("CARGO_PKG_VERSION").to_string()
|
||||
),
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
})
|
||||
.build();
|
||||
let mut client = serenity::ClientBuilder::new(token, intents)
|
||||
.framework(framework)
|
||||
.await
|
||||
.expect("Error creating client");
|
||||
let http = client.http.clone();
|
||||
let shard_manager = client.shard_manager.clone();
|
||||
tokio::spawn(async move {
|
||||
match rx.await {
|
||||
Ok(_) => {
|
||||
tracing::info!("Received shutdown signal");
|
||||
shard_manager.shutdown_all().await;
|
||||
tracing::info!("Shutting down bot");
|
||||
}
|
||||
Err(_) => {
|
||||
tracing::info!("Channel dropped signal");
|
||||
shard_manager.shutdown_all().await;
|
||||
tracing::info!("Shutting down bot");
|
||||
}
|
||||
}
|
||||
});
|
||||
tokio::spawn(async move {
|
||||
info!("Bot is running...");
|
||||
if let Err(why) = client.start_autosharded().await {
|
||||
tracing::error!("Client error: {why:?}");
|
||||
}
|
||||
info!("Bot is stopped...");
|
||||
});
|
||||
http
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod init;
|
||||
pub mod cmd;
|
||||
pub mod domain;
|
||||
pub mod handler;
|
||||
pub mod cmd;
|
||||
pub mod init;
|
||||
|
@ -1,10 +1,11 @@
|
||||
use crate::tracing::tracing_kind::Tracing;
|
||||
use dotenvy::dotenv;
|
||||
use serde::Deserialize;
|
||||
use poise::serenity_prelude::prelude::TypeMapKey;
|
||||
use serde::Deserialize;
|
||||
use std::env;
|
||||
use std::fs::read_to_string;
|
||||
use std::path::PathBuf;
|
||||
use crate::tracing::tracing_kind::Tracing;
|
||||
use tracing::{info, trace};
|
||||
|
||||
const DB_URL: &str = "DB_URL";
|
||||
const DB_USER: &str = "DB_USER";
|
||||
@ -60,10 +61,10 @@ pub struct PersistenceConfig {
|
||||
|
||||
pub fn parse_local_config() -> Config {
|
||||
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
println!(env!("CARGO_MANIFEST_DIR"));
|
||||
trace!(env!("CARGO_MANIFEST_DIR"));
|
||||
d.push("resources/config.toml");
|
||||
match dotenv() {
|
||||
Ok(_) => println!("Loaded .env file"),
|
||||
Ok(_) => info!("Loaded .env file"),
|
||||
Err(err) => println!("No .env file found: {:?}", err),
|
||||
}
|
||||
parse_config(d)
|
||||
|
@ -1,6 +1,6 @@
|
||||
pub mod api;
|
||||
pub mod botv2;
|
||||
pub mod config;
|
||||
pub mod db;
|
||||
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;
|
||||
use std::{process, time::Duration};
|
||||
use ::tracing::info;
|
||||
use actix_cors::Cors;
|
||||
use actix_web::{App, HttpServer};
|
||||
use botdiscord::{botv2::init::start_bot, tracing};
|
||||
use actix_web::dev::Service;
|
||||
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 tokio::{sync::oneshot, time::sleep};
|
||||
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]
|
||||
async fn main() -> std::io::Result<()> {
|
||||
@ -20,21 +28,50 @@ async fn main() -> std::io::Result<()> {
|
||||
}
|
||||
}
|
||||
let (tx, rx) = oneshot::channel();
|
||||
start_bot(config.clone(), rx);
|
||||
HttpServer::new(|| {
|
||||
let http = start_bot(config.clone(), rx).await;
|
||||
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()
|
||||
.allow_any_header()
|
||||
.allow_any_method()
|
||||
.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))?
|
||||
.run()
|
||||
.await?;
|
||||
println!("API Server stopped.");
|
||||
info!("API Server stopped.");
|
||||
tx.send(()).unwrap();
|
||||
tracing::init::stop_tracing(config.tracing.clone(), config.bot_name.clone());
|
||||
println!("Signal sent to bot.");
|
||||
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user