feat: partitionning

This commit is contained in:
Max batleforc 2025-05-23 23:54:42 +02:00
parent 6c30d6efc5
commit 34501bc413
No known key found for this signature in database
GPG Key ID: 25D243AB4B6AC9E7
15 changed files with 220 additions and 58 deletions

51
Cargo.lock generated
View File

@ -404,9 +404,11 @@ dependencies = [
"chrono", "chrono",
"clickhouse", "clickhouse",
"clickhouse_pool", "clickhouse_pool",
"database",
"poise", "poise",
"serde", "serde",
"tokio", "tokio",
"tokio-cron-scheduler",
"toml", "toml",
"tool_tracing", "tool_tracing",
"tracing", "tracing",
@ -615,6 +617,15 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "croner"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38fd53511eaf0b00a185613875fee58b208dfce016577d0ad4bb548e1c4fb3ee"
dependencies = [
"chrono",
]
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.15" version = "0.5.15"
@ -695,6 +706,19 @@ version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
[[package]]
name = "database"
version = "0.1.0"
dependencies = [
"chrono",
"clickhouse",
"clickhouse_pool",
"serde",
"tokio",
"tracing",
"uuid",
]
[[package]] [[package]]
name = "deadpool" name = "deadpool"
version = "0.12.2" version = "0.12.2"
@ -1641,6 +1665,17 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 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]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.19" version = "0.2.19"
@ -2906,6 +2941,22 @@ dependencies = [
"windows-sys 0.52.0", "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]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "2.5.0" version = "2.5.0"

View File

@ -1,7 +1,12 @@
[workspace] [workspace]
resolver = '2' resolver = '2'
members = ['apps/bot', 'libs/tool_tracing', 'libs/clickhouse_pool'] members = [
'apps/bot',
'libs/tool_tracing',
'libs/clickhouse_pool',
'libs/database',
]
[workspace.dependencies] [workspace.dependencies]
poise = '0.6.1' poise = '0.6.1'
@ -13,7 +18,9 @@ tokio = { version = '1.45.0', features = [
serde = '1.0' serde = '1.0'
tracing = '0.1' tracing = '0.1'
serde_json = '1.0' 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] [profile.release]
lto = true lto = true

View File

@ -9,12 +9,16 @@ poise = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
database = { path = "../../libs/database" }
tool_tracing = { path = "../../libs/tool_tracing" } tool_tracing = { path = "../../libs/tool_tracing" }
toml = "0.8" toml = "0.8"
clickhouse_pool = { path = "../../libs/clickhouse_pool" } clickhouse_pool = { path = "../../libs/clickhouse_pool" }
clickhouse = { workspace = true } clickhouse = { workspace = true }
uuid = { version = "1.16", features = ["serde", "v4"] } uuid = { workspace = true }
chrono = { version = "0.4.41", features = ["serde"] } 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 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

69
apps/bot/src/bot/mod.rs Normal file
View File

@ -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<serenity::User>,
) -> 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<PoolManager>,
pub entity_name: String,
}
pub type Error = Box<dyn std::error::Error + Send + Sync>;
pub type Context<'a> = poise::Context<'a, Data, Error>;
pub async fn start_bot(config: Config, datalake_config: Arc<PoolManager>) {
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();
}

View File

@ -1,3 +1,4 @@
use database::config::PersistenceConfig;
use poise::serenity_prelude::prelude::TypeMapKey; use poise::serenity_prelude::prelude::TypeMapKey;
use serde::Deserialize; use serde::Deserialize;
use std::{env, fs::read_to_string, path::PathBuf}; use std::{env, fs::read_to_string, path::PathBuf};
@ -34,16 +35,6 @@ pub struct Config {
pub persistence: PersistenceConfig, 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 { pub fn parse_local_config() -> Config {
let mut d = PathBuf::from(env::current_dir().unwrap()); let mut d = PathBuf::from(env::current_dir().unwrap());
d.push("resources/config.toml"); d.push("resources/config.toml");

View File

@ -1,27 +1,10 @@
use bot::start_bot;
use config::parse_local_config; use config::parse_local_config;
use poise::serenity_prelude as serenity; use tracing::{error, info};
use tracing::{error, info, instrument};
pub mod bot;
pub mod config; pub mod config;
pub mod dotenv; pub mod dotenv;
pub mod model;
struct Data {} // User data, which is stored and accessible in all command invocations
type Error = Box<dyn std::error::Error + Send + Sync>;
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<serenity::User>,
) -> 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] #[tokio::main]
async fn main() { async fn main() {
@ -29,8 +12,8 @@ async fn main() {
tool_tracing::init::init_tracing(config.tracing.clone(), config.bot_name.clone()); tool_tracing::init::init_tracing(config.tracing.clone(), config.bot_name.clone());
info!("Init Database"); info!("Init Database");
let datalake_config = model::create_pool_manager(config.persistence.clone()).unwrap(); let datalake_config = database::create_pool_manager(config.persistence.clone()).unwrap();
let _manager = match model::create_manager_and_init(datalake_config).await { let manager = match database::create_manager_and_init(datalake_config).await {
Ok(manager) => { Ok(manager) => {
info!("Database manager created successfully"); info!("Database manager created successfully");
manager manager
@ -42,24 +25,5 @@ async fn main() {
}; };
info!("Database manager initialized successfully"); info!("Database manager initialized successfully");
info!("Starting bot {}", config.bot_name); start_bot(config, manager).await;
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();
} }

15
libs/database/Cargo.toml Normal file
View File

@ -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

View File

@ -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": []
}

View File

@ -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,
}

View File

@ -1,3 +1,5 @@
pub mod config;
use std::{error::Error, sync::Arc}; use std::{error::Error, sync::Arc};
pub mod trivial; pub mod trivial;

View File

@ -14,6 +14,8 @@ pub struct TrivialRound {
pub question_id: Uuid, pub question_id: Uuid,
pub answer: Vec<(u64, String, DateTime<Utc>)>, pub answer: Vec<(u64, String, DateTime<Utc>)>,
pub finished: bool,
#[serde(with = "clickhouse::serde::chrono::datetime64::millis")] #[serde(with = "clickhouse::serde::chrono::datetime64::millis")]
pub created_at: DateTime<Utc>, pub created_at: DateTime<Utc>,
#[serde(with = "clickhouse::serde::chrono::datetime64::millis")] #[serde(with = "clickhouse::serde::chrono::datetime64::millis")]
@ -34,6 +36,7 @@ impl Model for TrivialRound {
trivial_id UUID, trivial_id UUID,
question_id UUID, question_id UUID,
answer Array(Tuple(UInt64, String, DateTime64(3))), answer Array(Tuple(UInt64, String, DateTime64(3))),
finished Bool,
created_at DateTime64(3), created_at DateTime64(3),
updated_at DateTime64(3) updated_at DateTime64(3)
) ENGINE = MergeTree() ) ENGINE = MergeTree()
@ -48,6 +51,7 @@ impl Model for TrivialRound {
"trivial_id", "trivial_id",
"question_id", "question_id",
"answer", "answer",
"finished",
"created_at", "created_at",
"updated_at", "updated_at",
] ]
@ -61,6 +65,7 @@ impl Model for TrivialRound {
self.trivial_id.to_string(), self.trivial_id.to_string(),
self.question_id.to_string(), self.question_id.to_string(),
format!("{:?}", self.answer), format!("{:?}", self.answer),
self.finished.to_string(),
self.created_at.to_string(), self.created_at.to_string(),
self.updated_at.to_string(), self.updated_at.to_string(),
], ],

View File

@ -1,4 +1,4 @@
bot_name = "WeeKit" bot_name = "Mioneolas"
env = "dev-che" env = "dev-che"
port = 5437 port = 5437
token = "" token = ""