From 4cb6d5b1996fa0fadf3edbe071b08d98781109da Mon Sep 17 00:00:00 2001 From: Pavel Perestoronin Date: Sun, 11 Jun 2023 22:50:23 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Implement=20the=20giveaway=20CLI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 11 +++++++++-- Cargo.toml | 1 + src/cli.rs | 22 ++++++++++++++++++++-- src/cli/export.rs | 4 ++-- src/cli/giveaway.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/main.rs | 3 ++- 6 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 src/cli/giveaway.rs diff --git a/Cargo.lock b/Cargo.lock index a126db7..8e3e93f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -255,6 +255,7 @@ dependencies = [ "clap", "cookie", "derive_more", + "fastrand 2.0.0", "indexmap", "itertools", "maud", @@ -656,6 +657,12 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrand" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" + [[package]] name = "findshlibs" version = "0.10.2" @@ -736,7 +743,7 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" dependencies = [ - "fastrand", + "fastrand 1.9.0", "futures-core", "futures-io", "memchr", @@ -2328,7 +2335,7 @@ checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ "autocfg", "cfg-if 1.0.0", - "fastrand", + "fastrand 1.9.0", "redox_syscall 0.3.5", "rustix", "windows-sys", diff --git a/Cargo.toml b/Cargo.toml index 7c0996b..0be5553 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ chrono-humanize = "0.2.2" clap = { version = "4.3.0", features = ["derive", "env", "cargo"] } cookie = "0.17.0" derive_more = { version = "0.99.17", default-features = false, features = ["from"] } +fastrand = "2.0.0" indexmap = "1.9.3" itertools = "0.10.5" maud = { version = "0.25.0", features = ["axum"] } diff --git a/src/cli.rs b/src/cli.rs index 7b68996..745551a 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,5 @@ pub mod export; +pub mod giveaway; use std::{net::SocketAddr, path::PathBuf}; @@ -23,7 +24,10 @@ pub enum Command { Web(WebArgs), /// Export all the votes in JSONL format. - ExportVotes(ExportVotes), + ExportVotes(ExportVotesArgs), + + /// Pick an account for a giveaway. + Giveaway(GiveawayArgs), } #[derive(Args)] @@ -80,7 +84,21 @@ impl DbArgs { } #[derive(Args)] -pub struct ExportVotes { +pub struct ExportVotesArgs { + #[clap(flatten)] + pub db: DbArgs, +} + +#[derive(Args)] +pub struct GiveawayArgs { #[clap(flatten)] pub db: DbArgs, + + /// Account IDs to exclude, comma-separated. + #[clap(long, value_parser, num_args = 0.., value_delimiter = ',')] + pub exclude_ids: Vec, + + /// Trace all candidate IDs. + #[clap(long)] + pub trace_candidates: bool, } diff --git a/src/cli/export.rs b/src/cli/export.rs index 4ddf51f..ee32c02 100644 --- a/src/cli/export.rs +++ b/src/cli/export.rs @@ -1,8 +1,8 @@ use serde_json::json; -use crate::{cli::ExportVotes, prelude::*}; +use crate::{cli::ExportVotesArgs, prelude::*}; -pub async fn export_votes(args: ExportVotes) -> Result { +pub fn export_votes(args: &ExportVotesArgs) -> Result { let manager = args.db.open()?.vote_manager()?; for result in manager.iter_all() { let (account_id, tank_id, vote) = result?; diff --git a/src/cli/giveaway.rs b/src/cli/giveaway.rs new file mode 100644 index 0000000..c639c9c --- /dev/null +++ b/src/cli/giveaway.rs @@ -0,0 +1,38 @@ +use std::collections::HashSet; + +use tracing::info; + +use crate::{cli::GiveawayArgs, prelude::*}; + +pub fn run(args: GiveawayArgs) -> Result { + let manager = args.db.open()?; + + info!("⏳ Reading votes…"); + let mut account_ids = manager + .vote_manager()? + .iter_all() + .map(|result| { + let (account_id, ..) = result?; + Ok(account_id) + }) + .collect::>>()?; + + info!(n_accounts = account_ids.len(), "βœ… Votes processed"); + + for account_id in args.exclude_ids { + info!(account_id, "πŸ—‘οΈ Removing excluded account"); + account_ids.remove(&account_id); + } + info!(n_accounts = account_ids.len(), "βœ… Ready to pick"); + + if args.trace_candidates { + for account_id in &account_ids { + info!(account_id, "🀞 Candidate"); + } + } + + let winner_id = fastrand::choice(&account_ids); + info!(?winner_id, "πŸŽ‰ Picked a winner!"); + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 6dfcba6..ff0e1f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,6 +32,7 @@ async fn main() -> Result { match args.command { Command::Web(args) => trace(web::run(args).await), - Command::ExportVotes(args) => trace(cli::export::export_votes(args).await), + Command::ExportVotes(args) => trace(cli::export::export_votes(&args)), + Command::Giveaway(args) => trace(cli::giveaway::run(args)), } }