diff --git a/Cargo.lock b/Cargo.lock index 02d0c0d..80d74c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -404,9 +404,11 @@ dependencies = [ "chrono", "clickhouse", "clickhouse_pool", + "database", "poise", "serde", "tokio", + "tokio-cron-scheduler", "toml", "tool_tracing", "tracing", @@ -615,6 +617,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "croner" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38fd53511eaf0b00a185613875fee58b208dfce016577d0ad4bb548e1c4fb3ee" +dependencies = [ + "chrono", +] + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -695,6 +706,19 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +[[package]] +name = "database" +version = "0.1.0" +dependencies = [ + "chrono", + "clickhouse", + "clickhouse_pool", + "serde", + "tokio", + "tracing", + "uuid", +] + [[package]] name = "deadpool" version = "0.12.2" @@ -1641,6 +1665,17 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2906,6 +2941,22 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "tokio-cron-scheduler" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71ce8f810abc9fabebccc30302a952f9e89c6cf246fafaf170fef164063141" +dependencies = [ + "chrono", + "croner", + "num-derive", + "num-traits", + "tokio", + "tracing", + "tracing-subscriber", + "uuid", +] + [[package]] name = "tokio-macros" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 66ab975..1211eab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,12 @@ [workspace] resolver = '2' -members = ['apps/bot', 'libs/tool_tracing', 'libs/clickhouse_pool'] +members = [ + 'apps/bot', + 'libs/tool_tracing', + 'libs/clickhouse_pool', + 'libs/database', +] [workspace.dependencies] poise = '0.6.1' @@ -13,7 +18,9 @@ tokio = { version = '1.45.0', features = [ serde = '1.0' tracing = '0.1' serde_json = '1.0' -clickhouse = { version = "0.13", features = ["native-tls", "uuid", "chrono"] } +clickhouse = { version = '0.13', features = ['native-tls', 'uuid', 'chrono'] } +uuid = { version = "1.16", features = ["serde", "v4"] } +chrono = { version = "0.4.41", features = ["serde"] } [profile.release] lto = true diff --git a/apps/bot/Cargo.toml b/apps/bot/Cargo.toml index eba956d..5f5ae23 100644 --- a/apps/bot/Cargo.toml +++ b/apps/bot/Cargo.toml @@ -9,12 +9,16 @@ poise = { workspace = true } tokio = { workspace = true } serde = { workspace = true } tracing = { workspace = true } +database = { path = "../../libs/database" } tool_tracing = { path = "../../libs/tool_tracing" } toml = "0.8" clickhouse_pool = { path = "../../libs/clickhouse_pool" } clickhouse = { workspace = true } -uuid = { version = "1.16", features = ["serde", "v4"] } -chrono = { version = "0.4.41", features = ["serde"] } - +uuid = { workspace = true } +chrono = { workspace = true } +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 diff --git a/apps/bot/src/bot/mod.rs b/apps/bot/src/bot/mod.rs new file mode 100644 index 0000000..0f2bb0b --- /dev/null +++ b/apps/bot/src/bot/mod.rs @@ -0,0 +1,69 @@ +use std::sync::Arc; + +use clickhouse_pool::pool_manager::PoolManager; +use poise::serenity_prelude as serenity; +use poise::serenity_prelude::GatewayIntents; +use tracing::{info, instrument}; + +use crate::config::Config; + +/// Displays your or another user's account creation date +#[instrument(skip(ctx), level = "info", fields(channel_id = ctx.channel_id().get() , guild_id = ?ctx.guild_id(), user_id = ?ctx.author().id.get(), user_name = ctx.author().name))] +#[poise::command(slash_command, prefix_command)] +async fn age( + ctx: Context<'_>, + #[description = "Selected user"] user: Option, +) -> Result<(), Error> { + let u = user.as_ref().unwrap_or_else(|| ctx.author()); + let response = format!("{}'s account was created at {}", u.name, u.created_at()); + ctx.say(response).await?; + Ok(()) +} + +pub struct Data { + pub config: Config, + pub datalake_config: Arc, + pub entity_name: String, +} + +pub type Error = Box; +pub type Context<'a> = poise::Context<'a, Data, Error>; + +pub async fn start_bot(config: Config, datalake_config: Arc) { + 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(); + info!("Starting bot {}", config.bot_name.clone()); + + let framework = poise::Framework::builder() + .options(poise::FrameworkOptions { + commands: vec![age()], + prefix_options: poise::PrefixFrameworkOptions { + prefix: Some(prefix), + ..Default::default() + }, + ..Default::default() + }) + .setup(|ctx, _ready, framework| { + Box::pin(async move { + poise::builtins::register_globally(ctx, &framework.options().commands).await?; + Ok(Data { + config: config.clone(), + datalake_config: datalake_config, + entity_name: format!("{}-{}", config.bot_name, env!("CARGO_PKG_VERSION")), + }) + }) + }) + .build(); + let client = poise::serenity_prelude::ClientBuilder::new(token, intents) + .framework(framework) + .await; + client.unwrap().start().await.unwrap(); +} diff --git a/apps/bot/src/config.rs b/apps/bot/src/config.rs index 7164365..5e37d2c 100644 --- a/apps/bot/src/config.rs +++ b/apps/bot/src/config.rs @@ -1,3 +1,4 @@ +use database::config::PersistenceConfig; use poise::serenity_prelude::prelude::TypeMapKey; use serde::Deserialize; use std::{env, fs::read_to_string, path::PathBuf}; @@ -34,16 +35,6 @@ pub struct Config { pub persistence: PersistenceConfig, } -// Clickhouse https://github.com/ranger-finance/clickhouse-pool/blob/master/examples/simple-clickhouse/src/main.rs -#[derive(Deserialize, Clone)] -pub struct PersistenceConfig { - pub host: String, - pub port: u16, - pub user: String, - pub password: String, - pub database: String, -} - pub fn parse_local_config() -> Config { let mut d = PathBuf::from(env::current_dir().unwrap()); d.push("resources/config.toml"); diff --git a/apps/bot/src/main.rs b/apps/bot/src/main.rs index b3b7787..f9004e8 100644 --- a/apps/bot/src/main.rs +++ b/apps/bot/src/main.rs @@ -1,27 +1,10 @@ +use bot::start_bot; use config::parse_local_config; -use poise::serenity_prelude as serenity; -use tracing::{error, info, instrument}; +use tracing::{error, info}; +pub mod bot; pub mod config; pub mod dotenv; -pub mod model; - -struct Data {} // User data, which is stored and accessible in all command invocations -type Error = Box; -type Context<'a> = poise::Context<'a, Data, Error>; - -/// Displays your or another user's account creation date -#[instrument(skip(ctx), level = "info", fields(channel_id = ctx.channel_id().get() , guild_id = ?ctx.guild_id(), user_id = ?ctx.author().id.get(), user_name = ctx.author().name))] -#[poise::command(slash_command, prefix_command)] -async fn age( - ctx: Context<'_>, - #[description = "Selected user"] user: Option, -) -> Result<(), Error> { - let u = user.as_ref().unwrap_or_else(|| ctx.author()); - let response = format!("{}'s account was created at {}", u.name, u.created_at()); - ctx.say(response).await?; - Ok(()) -} #[tokio::main] async fn main() { @@ -29,8 +12,8 @@ async fn main() { tool_tracing::init::init_tracing(config.tracing.clone(), config.bot_name.clone()); info!("Init Database"); - let datalake_config = model::create_pool_manager(config.persistence.clone()).unwrap(); - let _manager = match model::create_manager_and_init(datalake_config).await { + let datalake_config = database::create_pool_manager(config.persistence.clone()).unwrap(); + let manager = match database::create_manager_and_init(datalake_config).await { Ok(manager) => { info!("Database manager created successfully"); manager @@ -42,24 +25,5 @@ async fn main() { }; info!("Database manager initialized successfully"); - info!("Starting bot {}", config.bot_name); - let intents = serenity::GatewayIntents::non_privileged(); - - let framework = poise::Framework::builder() - .options(poise::FrameworkOptions { - commands: vec![age()], - ..Default::default() - }) - .setup(|ctx, _ready, framework| { - Box::pin(async move { - poise::builtins::register_globally(ctx, &framework.options().commands).await?; - Ok(Data {}) - }) - }) - .build(); - - let client = serenity::ClientBuilder::new(config.token.clone(), intents) - .framework(framework) - .await; - client.unwrap().start().await.unwrap(); + start_bot(config, manager).await; } diff --git a/libs/database/Cargo.toml b/libs/database/Cargo.toml new file mode 100644 index 0000000..c93fad9 --- /dev/null +++ b/libs/database/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "database" +version = "0.1.0" +edition = "2021" + +[dependencies] +tokio = { workspace = true } +serde = { workspace = true } +tracing = { workspace = true } +clickhouse_pool = { path = "../clickhouse_pool" } +clickhouse = { workspace = true } +uuid = { workspace = true } +chrono = { workspace = true } + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/libs/database/project.json b/libs/database/project.json new file mode 100644 index 0000000..20e8225 --- /dev/null +++ b/libs/database/project.json @@ -0,0 +1,43 @@ +{ + "name": "database", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "projectType": "library", + "sourceRoot": "libs/database/src", + "targets": { + "build": { + "executor": "@monodon/rust:check", + "outputs": [ + "{options.target-dir}" + ], + "options": { + "target-dir": "dist/target/database" + } + }, + "test": { + "cache": true, + "executor": "@monodon/rust:test", + "outputs": [ + "{options.target-dir}" + ], + "options": { + "target-dir": "dist/target/database" + }, + "configurations": { + "production": { + "release": true + } + } + }, + "lint": { + "cache": true, + "executor": "@monodon/rust:lint", + "outputs": [ + "{options.target-dir}" + ], + "options": { + "target-dir": "dist/target/database" + } + } + }, + "tags": [] +} diff --git a/libs/database/src/config.rs b/libs/database/src/config.rs new file mode 100644 index 0000000..1dcf3d1 --- /dev/null +++ b/libs/database/src/config.rs @@ -0,0 +1,11 @@ +use serde::Deserialize; + +// Clickhouse https://github.com/ranger-finance/clickhouse-pool/blob/master/examples/simple-clickhouse/src/main.rs +#[derive(Deserialize, Clone)] +pub struct PersistenceConfig { + pub host: String, + pub port: u16, + pub user: String, + pub password: String, + pub database: String, +} diff --git a/apps/bot/src/model/mod.rs b/libs/database/src/lib.rs similarity index 99% rename from apps/bot/src/model/mod.rs rename to libs/database/src/lib.rs index bb6098d..045e4f0 100644 --- a/apps/bot/src/model/mod.rs +++ b/libs/database/src/lib.rs @@ -1,3 +1,5 @@ +pub mod config; + use std::{error::Error, sync::Arc}; pub mod trivial; diff --git a/apps/bot/src/model/trivial.rs b/libs/database/src/trivial.rs similarity index 100% rename from apps/bot/src/model/trivial.rs rename to libs/database/src/trivial.rs diff --git a/apps/bot/src/model/trivial_point.rs b/libs/database/src/trivial_point.rs similarity index 100% rename from apps/bot/src/model/trivial_point.rs rename to libs/database/src/trivial_point.rs diff --git a/apps/bot/src/model/trivial_question.rs b/libs/database/src/trivial_question.rs similarity index 100% rename from apps/bot/src/model/trivial_question.rs rename to libs/database/src/trivial_question.rs diff --git a/apps/bot/src/model/trivial_round.rs b/libs/database/src/trivial_round.rs similarity index 96% rename from apps/bot/src/model/trivial_round.rs rename to libs/database/src/trivial_round.rs index a30cd24..b499071 100644 --- a/apps/bot/src/model/trivial_round.rs +++ b/libs/database/src/trivial_round.rs @@ -14,6 +14,8 @@ pub struct TrivialRound { pub question_id: Uuid, pub answer: Vec<(u64, String, DateTime)>, + pub finished: bool, + #[serde(with = "clickhouse::serde::chrono::datetime64::millis")] pub created_at: DateTime, #[serde(with = "clickhouse::serde::chrono::datetime64::millis")] @@ -34,6 +36,7 @@ impl Model for TrivialRound { trivial_id UUID, question_id UUID, answer Array(Tuple(UInt64, String, DateTime64(3))), + finished Bool, created_at DateTime64(3), updated_at DateTime64(3) ) ENGINE = MergeTree() @@ -48,6 +51,7 @@ impl Model for TrivialRound { "trivial_id", "question_id", "answer", + "finished", "created_at", "updated_at", ] @@ -61,6 +65,7 @@ impl Model for TrivialRound { self.trivial_id.to_string(), self.question_id.to_string(), format!("{:?}", self.answer), + self.finished.to_string(), self.created_at.to_string(), self.updated_at.to_string(), ], diff --git a/resources/config.toml b/resources/config.toml index af02f88..c4089ae 100644 --- a/resources/config.toml +++ b/resources/config.toml @@ -1,4 +1,4 @@ -bot_name = "WeeKit" +bot_name = "Mioneolas" env = "dev-che" port = 5437 token = ""