feat: Mise en place Framework Scheduler/Api with Actix
This commit is contained in:
parent
a03cb86f7a
commit
1bd8b07f47
212
Cargo.lock
generated
212
Cargo.lock
generated
@ -19,6 +19,21 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "actix-cors"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "daa239b93927be1ff123eebada5a3ff23e89f0124ccb8609234e5103d5a5ae6d"
|
||||||
|
dependencies = [
|
||||||
|
"actix-utils",
|
||||||
|
"actix-web",
|
||||||
|
"derive_more",
|
||||||
|
"futures-util",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"smallvec",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "actix-http"
|
name = "actix-http"
|
||||||
version = "3.11.0"
|
version = "3.11.0"
|
||||||
@ -31,12 +46,15 @@ dependencies = [
|
|||||||
"actix-utils",
|
"actix-utils",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
|
"brotli",
|
||||||
"bytes",
|
"bytes",
|
||||||
"bytestring",
|
"bytestring",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
|
"flate2",
|
||||||
"foldhash",
|
"foldhash",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
"h2 0.3.26",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"httparse",
|
"httparse",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
@ -52,6 +70,7 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
"zstd",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -73,6 +92,7 @@ dependencies = [
|
|||||||
"bytestring",
|
"bytestring",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
|
"regex",
|
||||||
"regex-lite",
|
"regex-lite",
|
||||||
"serde",
|
"serde",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -143,6 +163,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"bytestring",
|
"bytestring",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"cookie",
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"foldhash",
|
"foldhash",
|
||||||
@ -155,6 +176,7 @@ dependencies = [
|
|||||||
"mime",
|
"mime",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"regex",
|
||||||
"regex-lite",
|
"regex-lite",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@ -227,6 +249,21 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alloc-no-stdlib"
|
||||||
|
version = "2.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "alloc-stdlib"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece"
|
||||||
|
dependencies = [
|
||||||
|
"alloc-no-stdlib",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android-tzdata"
|
name = "android-tzdata"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@ -248,6 +285,24 @@ version = "1.0.98"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "api"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"actix-cors",
|
||||||
|
"actix-web",
|
||||||
|
"clickhouse_pool",
|
||||||
|
"config",
|
||||||
|
"database",
|
||||||
|
"poise",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"tracing-actix-web",
|
||||||
|
"utoipa",
|
||||||
|
"utoipa-actix-web",
|
||||||
|
"utoipa-scalar",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayvec"
|
name = "arrayvec"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
@ -412,6 +467,27 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "brotli"
|
||||||
|
version = "8.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d"
|
||||||
|
dependencies = [
|
||||||
|
"alloc-no-stdlib",
|
||||||
|
"alloc-stdlib",
|
||||||
|
"brotli-decompressor",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "brotli-decompressor"
|
||||||
|
version = "5.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
|
||||||
|
dependencies = [
|
||||||
|
"alloc-no-stdlib",
|
||||||
|
"alloc-stdlib",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
version = "1.12.0"
|
version = "1.12.0"
|
||||||
@ -491,6 +567,8 @@ version = "1.2.23"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
|
checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"jobserver",
|
||||||
|
"libc",
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -525,11 +603,12 @@ checksum = "93a719913643003b84bd13022b4b7e703c09342cd03b679c4641c7d2e50dc34d"
|
|||||||
name = "cli"
|
name = "cli"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"api",
|
||||||
"bot",
|
"bot",
|
||||||
"config",
|
"config",
|
||||||
|
"cron_scheduler",
|
||||||
"database",
|
"database",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-cron-scheduler",
|
|
||||||
"tool_tracing",
|
"tool_tracing",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@ -605,6 +684,17 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cookie"
|
||||||
|
version = "0.16.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb"
|
||||||
|
dependencies = [
|
||||||
|
"percent-encoding",
|
||||||
|
"time",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
@ -639,6 +729,20 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cron_scheduler"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"config",
|
||||||
|
"database",
|
||||||
|
"poise",
|
||||||
|
"tokio",
|
||||||
|
"tokio-cron-scheduler",
|
||||||
|
"tracing",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "croner"
|
name = "croner"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
@ -1478,6 +1582,7 @@ checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.3",
|
"hashbrown 0.15.3",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1501,6 +1606,16 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jobserver"
|
||||||
|
version = "0.1.33"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.3",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.77"
|
version = "0.3.77"
|
||||||
@ -1657,6 +1772,12 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mutually_exclusive_features"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e94e1e6445d314f972ff7395df2de295fe51b71821694f0b0e1e79c4f12c8577"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
@ -3212,6 +3333,21 @@ dependencies = [
|
|||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-actix-web"
|
||||||
|
version = "0.7.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2340b7722695166c7fc9b3e3cd1166e7c74fedb9075b8f0c74d3822d2e41caf5"
|
||||||
|
dependencies = [
|
||||||
|
"actix-web",
|
||||||
|
"mutually_exclusive_features",
|
||||||
|
"opentelemetry",
|
||||||
|
"pin-project",
|
||||||
|
"tracing",
|
||||||
|
"tracing-opentelemetry",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-attributes"
|
name = "tracing-attributes"
|
||||||
version = "0.1.28"
|
version = "0.1.28"
|
||||||
@ -3444,6 +3580,52 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utoipa"
|
||||||
|
version = "5.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "435c6f69ef38c9017b4b4eea965dfb91e71e53d869e896db40d1cf2441dd75c0"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap 2.9.0",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"utoipa-gen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utoipa-actix-web"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7eda9c23c05af0fb812f6a177514047331dac4851a2c8e9c4b895d6d826967f"
|
||||||
|
dependencies = [
|
||||||
|
"actix-service",
|
||||||
|
"actix-web",
|
||||||
|
"utoipa",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utoipa-gen"
|
||||||
|
version = "5.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a77d306bc75294fd52f3e99b13ece67c02c1a2789190a6f31d32f736624326f7"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.101",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utoipa-scalar"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "59559e1509172f6b26c1cdbc7247c4ddd1ac6560fe94b584f81ee489b141f719"
|
||||||
|
dependencies = [
|
||||||
|
"actix-web",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"utoipa",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
@ -4129,3 +4311,31 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.101",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd"
|
||||||
|
version = "0.13.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
|
||||||
|
dependencies = [
|
||||||
|
"zstd-safe",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd-safe"
|
||||||
|
version = "7.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
|
||||||
|
dependencies = [
|
||||||
|
"zstd-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zstd-sys"
|
||||||
|
version = "2.0.15+zstd.1.5.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
@ -8,6 +8,8 @@ members = [
|
|||||||
'libs/database',
|
'libs/database',
|
||||||
'libs/bot',
|
'libs/bot',
|
||||||
'libs/config',
|
'libs/config',
|
||||||
|
'libs/cron_scheduler',
|
||||||
|
'libs/api',
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
@ -9,11 +9,9 @@ tokio = { workspace = true }
|
|||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
database = { path = "../../libs/database" }
|
database = { path = "../../libs/database" }
|
||||||
tool_tracing = { path = "../../libs/tool_tracing" }
|
tool_tracing = { path = "../../libs/tool_tracing" }
|
||||||
tokio-cron-scheduler = { version = "0.14", features = [
|
|
||||||
"tracing-subscriber",
|
|
||||||
"signal",
|
|
||||||
] }
|
|
||||||
config = { path = "../../libs/config" }
|
config = { path = "../../libs/config" }
|
||||||
bot = { path = "../../libs/bot" }
|
bot = { path = "../../libs/bot" }
|
||||||
|
cron_scheduler = { path = "../../libs/cron_scheduler" }
|
||||||
|
api = { path = "../../libs/api" }
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use api::init_api;
|
||||||
use bot::start_bot;
|
use bot::start_bot;
|
||||||
use config::parse_local_config;
|
use config::parse_local_config;
|
||||||
|
use cron_scheduler::ScheduleJob;
|
||||||
use database::{create_manager_and_init, create_pool_manager};
|
use database::{create_manager_and_init, create_pool_manager};
|
||||||
|
use tokio::{sync::oneshot, time::sleep};
|
||||||
use tool_tracing::init::init_tracing;
|
use tool_tracing::init::init_tracing;
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() -> Result<(), ()> {
|
||||||
println!(include_str!("banner.art"));
|
println!(include_str!("banner.art"));
|
||||||
let config = parse_local_config();
|
let config = parse_local_config();
|
||||||
init_tracing(config.tracing.clone(), config.bot_name.clone());
|
init_tracing(config.tracing.clone(), config.bot_name.clone());
|
||||||
@ -19,10 +24,30 @@ async fn main() {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to create database manager: {}", e);
|
error!("Failed to create database manager: {}", e);
|
||||||
return;
|
return Err(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
info!("Database manager initialized successfully");
|
info!("Database manager initialized successfully");
|
||||||
|
let mut cron_scheduler = match ScheduleJob::start_cron_scheduler().await {
|
||||||
start_bot(config, manager).await;
|
Ok(scheduler) => {
|
||||||
|
info!("Cron scheduler started successfully");
|
||||||
|
scheduler
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
error!("Failed to start cron scheduler");
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let (tx_bot, rx_bot) = oneshot::channel();
|
||||||
|
let http = start_bot(config.clone(), manager.clone(), rx_bot).await;
|
||||||
|
|
||||||
|
let _ = init_api(config, manager, http).await;
|
||||||
|
|
||||||
|
tx_bot.send(()).unwrap_or_else(|_| {
|
||||||
|
error!("Failed to send shutdown signal to bot");
|
||||||
|
});
|
||||||
|
cron_scheduler.stop_cron_scheduler().await;
|
||||||
|
sleep(Duration::from_secs(2)).await;
|
||||||
|
//process::exit(1);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
22
libs/api/Cargo.toml
Normal file
22
libs/api/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[package]
|
||||||
|
name = "api"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { workspace = true }
|
||||||
|
tracing = { workspace = true }
|
||||||
|
poise = { workspace = true }
|
||||||
|
|
||||||
|
utoipa-actix-web = "0.1"
|
||||||
|
actix-web = "4"
|
||||||
|
actix-cors = "0.7"
|
||||||
|
utoipa-scalar = { version = "0.3", features = ["actix-web"] }
|
||||||
|
utoipa = "5"
|
||||||
|
tracing-actix-web = { version = "0.7", features = ["opentelemetry_0_29"] }
|
||||||
|
|
||||||
|
config = { path = "../../libs/config" }
|
||||||
|
database = { path = "../../libs/database" }
|
||||||
|
clickhouse_pool = { path = "../../libs/clickhouse_pool" }
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
43
libs/api/project.json
Normal file
43
libs/api/project.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "api",
|
||||||
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
|
"projectType": "library",
|
||||||
|
"sourceRoot": "libs/api/src",
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"executor": "@monodon/rust:check",
|
||||||
|
"outputs": [
|
||||||
|
"{options.target-dir}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"target-dir": "dist/target/api"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"cache": true,
|
||||||
|
"executor": "@monodon/rust:test",
|
||||||
|
"outputs": [
|
||||||
|
"{options.target-dir}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"target-dir": "dist/target/api"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"release": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"cache": true,
|
||||||
|
"executor": "@monodon/rust:lint",
|
||||||
|
"outputs": [
|
||||||
|
"{options.target-dir}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"target-dir": "dist/target/api"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": []
|
||||||
|
}
|
25
libs/api/src/apidocs.rs
Normal file
25
libs/api/src/apidocs.rs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
use utoipa::OpenApi;
|
||||||
|
|
||||||
|
#[derive(OpenApi)]
|
||||||
|
#[openapi(
|
||||||
|
info(
|
||||||
|
title = "Bot API",
|
||||||
|
description = "API documentation for the Bot application",
|
||||||
|
version = "1.0.0"
|
||||||
|
),
|
||||||
|
tags(
|
||||||
|
( name = "Bot",
|
||||||
|
description = "Bot related endpoints"
|
||||||
|
),
|
||||||
|
( name = "User",
|
||||||
|
description = "User related endpoints"
|
||||||
|
),
|
||||||
|
( name = "Admin",
|
||||||
|
description = "Admin related endpoints"
|
||||||
|
),
|
||||||
|
( name = "Cron",
|
||||||
|
description = "Cron job related endpoints"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub struct ApiDocs;
|
63
libs/api/src/lib.rs
Normal file
63
libs/api/src/lib.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use actix_cors::Cors;
|
||||||
|
use actix_web::{dev::Service, http::header, App, HttpServer};
|
||||||
|
use apidocs::ApiDocs;
|
||||||
|
use clickhouse_pool::pool_manager::PoolManager;
|
||||||
|
use config::Config;
|
||||||
|
use poise::serenity_prelude::Http;
|
||||||
|
use std::{net::Ipv4Addr, sync::Arc};
|
||||||
|
use tracing::{error, info};
|
||||||
|
use tracing_actix_web::{RequestId, TracingLogger};
|
||||||
|
use utoipa::OpenApi;
|
||||||
|
use utoipa_actix_web::AppExt;
|
||||||
|
use utoipa_scalar::{Scalar, Servable as ScalarServable};
|
||||||
|
|
||||||
|
pub mod apidocs;
|
||||||
|
|
||||||
|
pub async fn init_api(config: Config, pool: Arc<PoolManager>, http: Arc<Http>) -> Result<(), ()> {
|
||||||
|
let port = config.port.clone();
|
||||||
|
HttpServer::new(move || {
|
||||||
|
let cors = Cors::default()
|
||||||
|
.allow_any_origin()
|
||||||
|
.allow_any_method()
|
||||||
|
.allow_any_header()
|
||||||
|
.max_age(3600);
|
||||||
|
App::new()
|
||||||
|
.wrap(cors)
|
||||||
|
.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())
|
||||||
|
.into_utoipa_app()
|
||||||
|
.openapi(ApiDocs::openapi())
|
||||||
|
.app_data(actix_web::web::Data::new(pool.clone()))
|
||||||
|
.app_data(actix_web::web::Data::new(http.clone()))
|
||||||
|
.app_data(actix_web::web::Data::new(config.clone()))
|
||||||
|
.openapi_service(|api| Scalar::with_url("/api/docs", api))
|
||||||
|
.into_app()
|
||||||
|
})
|
||||||
|
.bind((Ipv4Addr::UNSPECIFIED, port))
|
||||||
|
.map_err(|e| {
|
||||||
|
error!("Failed to bind API server: {}", e);
|
||||||
|
()
|
||||||
|
})?
|
||||||
|
.run()
|
||||||
|
.await
|
||||||
|
.map_err(|e| {
|
||||||
|
eprintln!("Failed to start API server: {}", e);
|
||||||
|
()
|
||||||
|
})?;
|
||||||
|
info!("Api server stopped");
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -3,6 +3,7 @@ use std::sync::Arc;
|
|||||||
use clickhouse_pool::pool_manager::PoolManager;
|
use clickhouse_pool::pool_manager::PoolManager;
|
||||||
use event::event_handler;
|
use event::event_handler;
|
||||||
use poise::serenity_prelude::{GatewayIntents, Http};
|
use poise::serenity_prelude::{GatewayIntents, Http};
|
||||||
|
use tokio::sync::oneshot;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use trivia::trivia;
|
use trivia::trivia;
|
||||||
use utility::{age::age, help::help, server::servers};
|
use utility::{age::age, help::help, server::servers};
|
||||||
@ -23,7 +24,11 @@ pub struct Data {
|
|||||||
pub type Error = Box<dyn std::error::Error + Send + Sync>;
|
pub type Error = Box<dyn std::error::Error + Send + Sync>;
|
||||||
pub type Context<'a> = poise::Context<'a, Data, Error>;
|
pub type Context<'a> = poise::Context<'a, Data, Error>;
|
||||||
|
|
||||||
pub async fn start_bot(config: Config, datalake_config: Arc<PoolManager>) -> Arc<Http> {
|
pub async fn start_bot(
|
||||||
|
config: Config,
|
||||||
|
datalake_config: Arc<PoolManager>,
|
||||||
|
rx: oneshot::Receiver<()>,
|
||||||
|
) -> Arc<Http> {
|
||||||
let intents = GatewayIntents::GUILD_MESSAGES
|
let intents = GatewayIntents::GUILD_MESSAGES
|
||||||
| GatewayIntents::DIRECT_MESSAGES
|
| GatewayIntents::DIRECT_MESSAGES
|
||||||
| GatewayIntents::MESSAGE_CONTENT
|
| GatewayIntents::MESSAGE_CONTENT
|
||||||
@ -69,6 +74,27 @@ pub async fn start_bot(config: Config, datalake_config: Arc<PoolManager>) -> Arc
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let http = client.http.clone();
|
let http = client.http.clone();
|
||||||
client.start().await.unwrap();
|
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
|
http
|
||||||
}
|
}
|
||||||
|
19
libs/cron_scheduler/Cargo.toml
Normal file
19
libs/cron_scheduler/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[package]
|
||||||
|
name = "cron_scheduler"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { workspace = true }
|
||||||
|
poise = { workspace = true }
|
||||||
|
tracing = { workspace = true }
|
||||||
|
uuid = { workspace = true }
|
||||||
|
chrono = { workspace = true }
|
||||||
|
database = { path = "../../libs/database" }
|
||||||
|
config = { path = "../../libs/config" }
|
||||||
|
tokio-cron-scheduler = { version = "0.14", features = [
|
||||||
|
"tracing-subscriber",
|
||||||
|
"signal",
|
||||||
|
] }
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
43
libs/cron_scheduler/project.json
Normal file
43
libs/cron_scheduler/project.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "cron_scheduler",
|
||||||
|
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||||
|
"projectType": "library",
|
||||||
|
"sourceRoot": "libs/cron_scheduler/src",
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"executor": "@monodon/rust:check",
|
||||||
|
"outputs": [
|
||||||
|
"{options.target-dir}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"target-dir": "dist/target/cron_scheduler"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"cache": true,
|
||||||
|
"executor": "@monodon/rust:test",
|
||||||
|
"outputs": [
|
||||||
|
"{options.target-dir}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"target-dir": "dist/target/cron_scheduler"
|
||||||
|
},
|
||||||
|
"configurations": {
|
||||||
|
"production": {
|
||||||
|
"release": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"cache": true,
|
||||||
|
"executor": "@monodon/rust:lint",
|
||||||
|
"outputs": [
|
||||||
|
"{options.target-dir}"
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"target-dir": "dist/target/cron_scheduler"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": []
|
||||||
|
}
|
147
libs/cron_scheduler/src/lib.rs
Normal file
147
libs/cron_scheduler/src/lib.rs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
use poise::serenity_prelude::Http;
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::{self, Display},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
use tokio_cron_scheduler::JobScheduler;
|
||||||
|
use tracing::{error, info, instrument};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum StopScheduleJob {
|
||||||
|
JobNotFound,
|
||||||
|
RemoveFailed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for StopScheduleJob {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ScheduleJob {
|
||||||
|
pub job_id: Arc<RwLock<HashMap<(u64, u64), Uuid>>>,
|
||||||
|
pub scheduler: JobScheduler,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for ScheduleJob {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
ScheduleJob {
|
||||||
|
job_id: self.job_id.clone(),
|
||||||
|
scheduler: self.scheduler.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScheduleJob {
|
||||||
|
#[instrument(level = "info")]
|
||||||
|
pub async fn start_cron_scheduler() -> Result<Self, ()> {
|
||||||
|
let scheduler = JobScheduler::new().await;
|
||||||
|
let mut future_self = match scheduler {
|
||||||
|
Ok(scheduler) => ScheduleJob {
|
||||||
|
job_id: Default::default(),
|
||||||
|
scheduler,
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error starting cron scheduler: {:?}", e);
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
future_self.scheduler.set_shutdown_handler(Box::new(|| {
|
||||||
|
Box::pin(async {
|
||||||
|
info!("Cron scheduler stopped");
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
future_self.scheduler.shutdown_on_ctrl_c();
|
||||||
|
match future_self.scheduler.start().await {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Cron scheduler started");
|
||||||
|
Ok(future_self)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error starting cron scheduler: {:?}", e);
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, _http), level = "info")]
|
||||||
|
pub async fn load_all_trivial_cron_job(&mut self, _http: &Http) -> Result<(), bool> {
|
||||||
|
// Load all trivial jobs
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self), level = "info")]
|
||||||
|
pub async fn stop_cron_scheduler(&mut self) -> &mut Self {
|
||||||
|
let job_id = self.job_id.write().await;
|
||||||
|
|
||||||
|
for (server_id, channel_id) in job_id.keys() {
|
||||||
|
match self
|
||||||
|
.scheduler
|
||||||
|
.remove(job_id.get(&(*server_id, *channel_id)).unwrap())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Cron job removed");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error removing cron job: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(job_id);
|
||||||
|
match self.scheduler.shutdown().await {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Cron scheduler stopped");
|
||||||
|
self
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error stopping cron scheduler: {:?}", e);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, http), level = "info")]
|
||||||
|
pub async fn add_trivial_cron_job(
|
||||||
|
&mut self,
|
||||||
|
server_id: u64,
|
||||||
|
channel_id: u64,
|
||||||
|
cron_expression: String,
|
||||||
|
http: &Http,
|
||||||
|
) -> Result<Uuid, ()> {
|
||||||
|
let _http = Arc::new(Http::new(http.token()));
|
||||||
|
// Create a new job with the provided cron expression
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
#[instrument(skip(self), level = "info")]
|
||||||
|
pub async fn stop_scheduled_job(
|
||||||
|
&mut self,
|
||||||
|
server_id: u64,
|
||||||
|
channel_id: u64,
|
||||||
|
) -> Result<(), StopScheduleJob> {
|
||||||
|
let remove_job = {
|
||||||
|
let mut job_id = self.job_id.write().await;
|
||||||
|
job_id.remove(&(server_id, channel_id))
|
||||||
|
};
|
||||||
|
match remove_job {
|
||||||
|
Some(job_uid) => match self.scheduler.remove(&job_uid).await {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Cron job removed");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Error removing cron job: {:?}", e);
|
||||||
|
Err(StopScheduleJob::RemoveFailed)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
error!("Cron job not found");
|
||||||
|
Err(StopScheduleJob::JobNotFound)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user