From e8ea862a97a937a1de3f6ec19f6654ea1cacc5c8 Mon Sep 17 00:00:00 2001 From: veeso Date: Wed, 31 Aug 2022 10:43:31 +0200 Subject: [PATCH] random aphorism sequence --- CHANGELOG.md | 1 + src/big_luca/aphorism.rs | 62 ++++++++++++++++++++++++++++---------- src/big_luca/automatize.rs | 18 +++++++++-- src/big_luca/mod.rs | 15 ++++++--- 4 files changed, 73 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34feb07..0623989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Released on 31/08/2022 - From now on courses and aphorisms are read from `parameters.json`. RELOAD REQUIRES A BOT RESTART. - Added `PARAMETERS_PATH` to environment parameters +- Repeating random aphorisms are now PREVENTED creating a shuffled sequence ## 0.3.4 diff --git a/src/big_luca/aphorism.rs b/src/big_luca/aphorism.rs index 2317628..f843df3 100644 --- a/src/big_luca/aphorism.rs +++ b/src/big_luca/aphorism.rs @@ -2,18 +2,39 @@ //! //! This module contains the papi's aphorisms -use super::PARAMETERS; +use rand::seq::SliceRandom; +use std::sync::atomic::{AtomicUsize, Ordering}; -use rand::Rng; - -pub struct Aphorism; +pub struct AphorismJar { + aphorisms: Vec, + index: AtomicUsize, +} -impl Aphorism { +impl AphorismJar { /// Get a random aphorism of the papi - pub fn get_random() -> String { + pub fn get_random(&self) -> &str { + if self.index.load(Ordering::Relaxed) >= self.aphorisms.len() { + self.index.store(0, Ordering::SeqCst); + } + let aphorism = self + .aphorisms + .get(self.index.load(Ordering::Relaxed)) + .map(|x| x.as_str()) + .unwrap_or_default(); + self.index.fetch_add(1, Ordering::SeqCst); + aphorism + } +} + +impl From<&[String]> for AphorismJar { + fn from(aphorisms: &[String]) -> Self { + let mut aphorisms: Vec = aphorisms.iter().map(|x| x.to_string()).collect(); let mut rng = rand::thread_rng(); - let aphorisms = PARAMETERS.get().unwrap().aphorisms.as_slice(); - aphorisms[rng.gen_range(0..aphorisms.len())].clone() + aphorisms.shuffle(&mut rng); + Self { + aphorisms, + index: AtomicUsize::new(0), + } } } @@ -22,18 +43,27 @@ mod test { use super::*; use crate::big_luca::Parameters; + + use pretty_assertions::assert_eq; use std::path::Path; #[test] fn should_get_random_aphorism() { - assert!(PARAMETERS - .set(Parameters::try_from_path(Path::new("config/parameters.json")).unwrap()) - .is_ok()); - assert!(!Aphorism::get_random().is_empty()); - assert!(PARAMETERS - .get() - .unwrap() + let parameters = Parameters::try_from_path(Path::new("config/parameters.json")).unwrap(); + let aphorism = AphorismJar::from(parameters.aphorisms.as_slice()); + assert!(!aphorism.get_random().is_empty()); + assert!(parameters .aphorisms - .contains(&Aphorism::get_random())) + .contains(&aphorism.get_random().to_string())); + } + + #[test] + fn should_wrap_and_increment_index() { + let parameters = Parameters::try_from_path(Path::new("config/parameters.json")).unwrap(); + let aphorism = AphorismJar::from(¶meters.aphorisms[0..2]); + assert_eq!(aphorism.aphorisms.len(), 2); + assert_eq!(aphorism.aphorisms[0], aphorism.get_random()); + assert_eq!(aphorism.aphorisms[1], aphorism.get_random()); + assert_eq!(aphorism.aphorisms[0], aphorism.get_random()); } } diff --git a/src/big_luca/automatize.rs b/src/big_luca/automatize.rs index 4e99f9f..ce70359 100644 --- a/src/big_luca/automatize.rs +++ b/src/big_luca/automatize.rs @@ -7,14 +7,18 @@ use crate::big_luca::redis::RedisRepository; use super::repository::Repository; use super::rsshub::RssHubClient; use super::youtube::Youtube; -use super::{AnswerBuilder, Aphorism, Stickers}; +use super::{AnswerBuilder, AphorismJar, Parameters, Stickers}; use chrono::Utc; +use once_cell::sync::OnceCell; use teloxide::prelude::*; use teloxide::types::ChatId; use thiserror::Error; use tokio_cron_scheduler::{Job, JobScheduler, JobSchedulerError}; +/// Aphorism jAR RESERVED TO THE AUTOMATIZER +static APHORISMS_JAR: OnceCell = OnceCell::new(); + type AutomatizerResult = Result; /// Automatizer error @@ -22,6 +26,8 @@ type AutomatizerResult = Result; pub enum AutomatizerError { #[error("scheduler error: {0}")] Scheduler(JobSchedulerError), + #[error("failed to setup aphorism jar")] + BadAphorisms, } impl From for AutomatizerError { @@ -37,8 +43,14 @@ pub struct Automatizer { impl Automatizer { /// Start automatizer - pub async fn start() -> AutomatizerResult { + pub async fn start(params: &Parameters) -> AutomatizerResult { debug!("starting automatizer"); + if APHORISMS_JAR + .set(AphorismJar::from(params.aphorisms.as_slice())) + .is_err() + { + return Err(AutomatizerError::BadAphorisms); + } Ok(Self { scheduler: Self::setup_cron_scheduler().await?, }) @@ -124,7 +136,7 @@ impl Automatizer { async fn send_perla() -> anyhow::Result<()> { let bot = Bot::from_env().auto_send(); let message = AnswerBuilder::default() - .text(Aphorism::get_random()) + .text(APHORISMS_JAR.get().unwrap().get_random()) .sticker(Stickers::random()) .finalize(); for chat in Self::subscribed_chats().await?.iter() { diff --git a/src/big_luca/mod.rs b/src/big_luca/mod.rs index 0b1db3b..6d7585f 100644 --- a/src/big_luca/mod.rs +++ b/src/big_luca/mod.rs @@ -18,7 +18,7 @@ use teloxide::{dispatching::update_listeners::webhooks, prelude::*, utils::comma use url::Url; use answer::{Answer, AnswerBuilder}; -use aphorism::Aphorism; +use aphorism::AphorismJar; use automatize::Automatizer; use commands::Command; pub use config::Config; @@ -26,6 +26,7 @@ use once_cell::sync::OnceCell; pub use parameters::Parameters; use stickers::Stickers; +static APHORISMS_JAR: OnceCell = OnceCell::new(); pub static AUTOMATIZER: OnceCell = OnceCell::new(); pub static PARAMETERS: OnceCell = OnceCell::new(); @@ -42,14 +43,20 @@ impl BigLuca { if let Err(err) = Config::try_from_env() { return Err(err); } - let automatizer = Automatizer::start() + let parameters = Parameters::try_from_path(&config.parameters_path)?; + let automatizer = Automatizer::start(¶meters) .await .map_err(|e| anyhow::anyhow!("failed to start automatizer: {}", e))?; // read parameters if AUTOMATIZER.set(automatizer).is_err() { anyhow::bail!("failed to set automatizer"); }; - let parameters = Parameters::try_from_path(&config.parameters_path)?; + if APHORISMS_JAR + .set(AphorismJar::from(parameters.aphorisms.as_slice())) + .is_err() + { + anyhow::bail!("failed to set aphorisms"); + } if PARAMETERS.set(parameters).is_err() { anyhow::bail!("failed to set parameters"); } @@ -138,7 +145,7 @@ La lista di attesa può durare mesi e solo in pochi dopo una rigida selezione ri /// Send a random aphorism fn aphorism() -> Answer { AnswerBuilder::default() - .text(Aphorism::get_random()) + .text(APHORISMS_JAR.get().unwrap().get_random()) .sticker(Stickers::random()) .finalize() }