From 481b37fef3174723173e7c9c631fb0843690c21a Mon Sep 17 00:00:00 2001 From: Aras14HD Date: Fri, 5 Dec 2025 12:21:33 +0100 Subject: [PATCH 1/3] reduce the likelyhood of the token expiring while request is in transit --- factorion-bot-reddit/src/reddit_api.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/factorion-bot-reddit/src/reddit_api.rs b/factorion-bot-reddit/src/reddit_api.rs index 5f7e830..27c5214 100644 --- a/factorion-bot-reddit/src/reddit_api.rs +++ b/factorion-bot-reddit/src/reddit_api.rs @@ -11,7 +11,7 @@ use crate::{ use anyhow::{Error, anyhow}; use base64::Engine; use base64::engine::general_purpose::STANDARD_NO_PAD; -use chrono::{DateTime, NaiveDateTime, Utc}; +use chrono::{DateTime, NaiveDateTime, TimeDelta, Utc}; use factorion_lib::comment::{Commands, Comment, CommentCalculated, CommentConstructed, Status}; use futures::future::OptionFuture; use id::{DenseId, id_to_dense}; @@ -406,7 +406,7 @@ impl RedditClient { } fn is_token_expired(&self) -> bool { - let now = Utc::now(); + let now = Utc::now() + TimeDelta::seconds(1); now > self.token.expiration_time } From 117a66bd9d41eb7b4310abc2ff25c6817668c31a Mon Sep 17 00:00:00 2001 From: Aras14HD Date: Sat, 7 Mar 2026 17:31:19 +0100 Subject: [PATCH 2/3] improve panic messages (replace expects) move from expect("...") to unwrap_or_else(|| panic!("...")) including more context in the message --- factorion-bot-reddit/src/reddit_api.rs | 83 +++++++++++++----------- factorion-lib/src/calculation_results.rs | 23 ++++--- factorion-lib/src/calculation_tasks.rs | 8 ++- factorion-math/src/lib.rs | 8 +-- 4 files changed, 69 insertions(+), 53 deletions(-) diff --git a/factorion-bot-reddit/src/reddit_api.rs b/factorion-bot-reddit/src/reddit_api.rs index 27c5214..bde285e 100644 --- a/factorion-bot-reddit/src/reddit_api.rs +++ b/factorion-bot-reddit/src/reddit_api.rs @@ -126,16 +126,17 @@ impl RedditClient { subreddits.sort(); info!("Setting comments to be checked in: {subreddits:?}"); if !(subreddits.is_empty() || subreddits == [""]) { + let url = format!( + "{}/r/{}/comments", + REDDIT_OAUTH_URL, + subreddits + .into_iter() + .reduce(|a, e| format!("{a}+{e}")) + .unwrap_or_default(), + ); Some( - Url::parse(&format!( - "{}/r/{}/comments", - REDDIT_OAUTH_URL, - subreddits - .into_iter() - .reduce(|a, e| format!("{a}+{e}")) - .unwrap_or_default(), - )) - .expect("Failed to parse Url"), + Url::parse(&url) + .unwrap_or_else(|err| panic!("Failed to parse Url: {err} in {url}")), ) } else { None @@ -152,23 +153,25 @@ impl RedditClient { post_subreddits.sort(); info!("Setting posts to be checked in: {post_subreddits:?}"); if !(post_subreddits.is_empty() || post_subreddits == [""]) { + let url = format!( + "{}/r/{}/new", + REDDIT_OAUTH_URL, + post_subreddits + .into_iter() + .reduce(|a, e| format!("{a}+{e}")) + .unwrap_or_default(), + ); Some( - Url::parse(&format!( - "{}/r/{}/new", - REDDIT_OAUTH_URL, - post_subreddits - .into_iter() - .reduce(|a, e| format!("{a}+{e}")) - .unwrap_or_default(), - )) - .expect("Failed to parse Url"), + Url::parse(&url) + .unwrap_or_else(|err| panic!("Failed to parse Url: {err} in {url}")), ) } else { None } }); static MENTION_URL: LazyLock = LazyLock::new(|| { - Url::parse(&format!("{REDDIT_OAUTH_URL}/message/inbox")).expect("Failed to parse Url") + let url = format!("{REDDIT_OAUTH_URL}/message/inbox"); + Url::parse(&url).unwrap_or_else(|err| panic!("Failed to parse Url: {err} in {url}")) }); #[cfg(not(test))] if self.is_token_expired() { @@ -337,22 +340,23 @@ impl RedditClient { && !ids.is_empty() { 'get_summons: loop { + let url = format!( + "{}/api/info?id={}", + REDDIT_OAUTH_URL, + ids.iter() + .map(|(id, _)| id) + .fold(String::new(), |mut a, e| { + let _ = write!(a, "{e}"); + a + }) + ); let response = self .client - .get(format!( - "{}/api/info?id={}", - REDDIT_OAUTH_URL, - ids.iter() - .map(|(id, _)| id) - .fold(String::new(), |mut a, e| { - let _ = write!(a, "{e}"); - a - }) - )) + .get(&url) .bearer_auth(&self.token.access_token) .send() .await - .expect("Failed to get comment"); + .unwrap_or_else(|err| panic!("Failed to get comment: {err} on {url}")); if Self::check_response_status(&response).is_ok() { let (comments, _, t, _) = self .extract_comments( @@ -456,8 +460,9 @@ impl RedditClient { let response_text = &response.text().await?; let response_text = response_text.as_str(); - let response_json = - from_str::(response_text).expect("Failed to convert response to json"); + let response_json = from_str::(response_text).unwrap_or_else(|err| { + panic!("Failed to convert response to json: {err} in {response_text}") + }); let response_status_err = !RedditClient::is_success(response_text); let error_message = RedditClient::get_error_message(response_json); @@ -518,8 +523,9 @@ impl RedditClient { } fn is_success(response_text: &str) -> bool { - let response_json = - from_str::(response_text).expect("Failed to convert response to json"); + let response_json = from_str::(response_text).unwrap_or_else(|err| { + panic!("Failed to convert response to json: {err} in {response_text}") + }); response_json["success"].as_bool().unwrap_or(false) } @@ -575,17 +581,18 @@ impl RedditClient { let jwt_payload = jwt[1]; let jwt_payload = STANDARD_NO_PAD .decode(jwt_payload.as_bytes()) - .expect("Failed to decode jwt payload"); + .unwrap_or_else(|err| panic!("Failed to decode jwt payload: {err} in {jwt_payload}")); let jwt_payload = String::from_utf8(jwt_payload).expect("Failed to convert jwt payload to string"); - let jwt_payload = - from_str::(&jwt_payload).expect("Failed to convert jwt payload to json"); + let jwt_payload = from_str::(&jwt_payload).unwrap_or_else(|err| { + panic!("Failed to convert jwt payload to json: {err} in {jwt_payload}") + }); let exp = jwt_payload["exp"] .as_f64() - .expect("Failed to get exp field"); + .unwrap_or_else(|| panic!("Failed to get exp field as f64 in {jwt_payload}")); let naive = NaiveDateTime::from_timestamp(exp as i64, 0); let datetime: DateTime = DateTime::from_utc(naive, Utc); diff --git a/factorion-lib/src/calculation_results.rs b/factorion-lib/src/calculation_results.rs index 6b35044..7005eba 100644 --- a/factorion-lib/src/calculation_results.rs +++ b/factorion-lib/src/calculation_results.rs @@ -543,15 +543,18 @@ impl Calculation { /// This function may panic if less than two digits are supplied, or if it contains a non-digit of base 10, that is not a period. fn round(number: &mut String) -> bool { // Check additional digit if we need to round - if let Some(digit) = number - .pop() - .map(|n| n.to_digit(10).expect("Not a base 10 number")) - && digit >= 5 + if let Some(digit) = number.pop().map(|n| { + n.to_digit(10) + .unwrap_or_else(|| panic!("Not a base 10 number, encountered char {n}")) + }) && digit >= 5 { let mut last_digit = number .pop() - .and_then(|n| n.to_digit(10)) - .expect("Not a base 10 number"); + .map(|n| { + n.to_digit(10) + .unwrap_or_else(|| panic!("Not a base 10 number, encountered char {n}")) + }) + .expect("Number to round had less than two digits!"); // Carry over at 9s while last_digit == 9 { let Some(digit) = number.pop() else { @@ -563,7 +566,9 @@ fn round(number: &mut String) -> bool { if digit == '.' { break; } - let digit = digit.to_digit(10).expect("Not a base 10 number"); + let digit = digit + .to_digit(10) + .unwrap_or_else(|| panic!("Not a base 10 number, encountered char {digit}")); last_digit = digit; } // Round up @@ -630,7 +635,7 @@ fn format_float(acc: &mut String, number: &Float, consts: &Consts) -> std::fmt:: .clone() .log10() .to_integer_round(factorion_math::rug::float::Round::Down) - .expect("Could not round exponent") + .unwrap_or_else(|| panic!("Could not round exponent of {number}")) .0; if exponent > consts.number_decimals_scientific || exponent < -(consts.number_decimals_scientific as isize) @@ -639,7 +644,7 @@ fn format_float(acc: &mut String, number: &Float, consts: &Consts) -> std::fmt:: } let mut whole_number = number .to_integer_round(factorion_math::rug::float::Round::Down) - .expect("Could not get integer part") + .unwrap_or_else(|| panic!("Could not get integer part of {number}")) .0; let decimal_part = number - &whole_number + 1; let mut decimal_part = format!("{decimal_part}"); diff --git a/factorion-lib/src/calculation_tasks.rs b/factorion-lib/src/calculation_tasks.rs index b433a0c..9a73ea1 100644 --- a/factorion-lib/src/calculation_tasks.rs +++ b/factorion-lib/src/calculation_tasks.rs @@ -281,7 +281,9 @@ impl CalculationJob { factorial.1, ) } else { - let calc_num = calc_num.to_u64().expect("Failed to convert BigInt to u64"); + let calc_num = calc_num + .to_u64() + .unwrap_or_else(|| panic!("Failed to convert BigInt to u64: {calc_num}")); let factorial = math::factorial(calc_num, level as u32) * if negative % 2 != 0 { -1 } else { 1 }; CalculationResult::Exact(factorial) @@ -299,7 +301,9 @@ impl CalculationJob { factorial.1, ) } else { - let calc_num = calc_num.to_u64().expect("Failed to convert BigInt to u64"); + let calc_num = calc_num + .to_u64() + .unwrap_or_else(|| panic!("Failed to convert BigInt to u64: {calc_num}")); let factorial = math::subfactorial(calc_num) * if negative % 2 != 0 { -1 } else { 1 }; CalculationResult::Exact(factorial) diff --git a/factorion-math/src/lib.rs b/factorion-math/src/lib.rs index 4fc4b1c..e0cf525 100644 --- a/factorion-math/src/lib.rs +++ b/factorion-math/src/lib.rs @@ -152,7 +152,7 @@ pub fn approximate_factorial_float(n: Float) -> (Float, Integer) { let ten_in_base = Float::with_val(prec, 10).ln() / base.clone().ln(); let (extra, _) = (n.clone() / ten_in_base.clone()) .to_integer_round(rug::float::Round::Down) - .expect("Got non-finite number, n is likely non-positive"); + .unwrap_or_else(|| panic!("Got non-finite number, n was {n}")); let exponent = n.clone() - ten_in_base * Float::with_val(prec, extra.clone()); let factorial = base.pow(exponent) * (Float::with_val(prec, rug::float::Constant::Pi) * Float::with_val(prec, 2) * n.clone()) @@ -313,9 +313,9 @@ pub fn approximate_multifactorial_digits_float(k: u32, n: Float) -> Integer { let k = Float::with_val(prec, k); let ln10 = Float::with_val(prec, 10).ln(); let base = n.clone().ln() / &ln10; - ((Float::with_val(prec, 0.5) + n.clone() / k.clone()) * base - n / k / ln10) + ((Float::with_val(prec, 0.5) + n.clone() / k.clone()) * base - n.clone() / k / ln10) .to_integer_round(rug::float::Round::Down) - .expect("Got non-finite number, n is likely non-positive") + .unwrap_or_else(|| panic!("Got non-finite number, n was {n}")) .0 + Integer::ONE } @@ -341,7 +341,7 @@ pub fn adjust_approximate((x, e): (Float, Integer)) -> (Float, Integer) { let prec = x.prec(); let (extra, _) = (x.clone().ln() / Float::with_val(prec, 10).ln()) .to_integer_round(rug::float::Round::Down) - .expect("Got non-finite number, x is likely not finite"); + .unwrap_or_else(|| panic!("Got non-finite number, x was {x}")); let x = x / (Float::with_val(prec, 10).pow(extra.clone())); let total_exponent = extra + e; (x, total_exponent) From 4f04244d534450740eaed979954e051feef9d9c2 Mon Sep 17 00:00:00 2001 From: Aras14HD Date: Sat, 7 Mar 2026 17:37:27 +0100 Subject: [PATCH 3/3] bump version fix --- Cargo.lock | 8 ++++---- factorion-bot-discord/Cargo.toml | 4 ++-- factorion-bot-reddit/Cargo.toml | 4 ++-- factorion-lib/Cargo.toml | 4 ++-- factorion-math/Cargo.toml | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 97f87dd..35a0c6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -399,7 +399,7 @@ dependencies = [ [[package]] name = "factorion-bot-discord" -version = "2.4.0" +version = "2.4.1" dependencies = [ "anyhow", "dotenvy", @@ -414,7 +414,7 @@ dependencies = [ [[package]] name = "factorion-bot-reddit" -version = "5.5.0" +version = "5.5.1" dependencies = [ "anyhow", "base64 0.22.1", @@ -434,7 +434,7 @@ dependencies = [ [[package]] name = "factorion-lib" -version = "4.4.0" +version = "4.4.1" dependencies = [ "arbtest", "chrono", @@ -447,7 +447,7 @@ dependencies = [ [[package]] name = "factorion-math" -version = "1.0.1" +version = "1.0.2" dependencies = [ "gmp-mpfr-sys", "rug", diff --git a/factorion-bot-discord/Cargo.toml b/factorion-bot-discord/Cargo.toml index dc3805d..c97e0d9 100644 --- a/factorion-bot-discord/Cargo.toml +++ b/factorion-bot-discord/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factorion-bot-discord" -version = "2.4.0" +version = "2.4.1" edition = "2024" description = "factorion-bot (for factorials and related) on Discord" license = "MIT" @@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math", "discord"] categories = ["mathematics", "web-programming", "parser-implementations"] [dependencies] -factorion-lib = { path = "../factorion-lib", version = "4.4.0", features = ["serde", "influxdb"] } +factorion-lib = { path = "../factorion-lib", version = "4.4.1", features = ["serde", "influxdb"] } serenity = { version = "0.12", default-features = false, features = ["client", "gateway", "rustls_backend", "model", "cache"] } tokio = { version = "1.48.0", features = ["macros", "rt-multi-thread", "time"] } dotenvy = "^0.15.7" diff --git a/factorion-bot-reddit/Cargo.toml b/factorion-bot-reddit/Cargo.toml index e9e7f72..7eb96a4 100644 --- a/factorion-bot-reddit/Cargo.toml +++ b/factorion-bot-reddit/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factorion-bot-reddit" -version = "5.5.0" +version = "5.5.1" edition = "2024" description = "factorion-bot (for factorials and related) on Reddit" license = "MIT" @@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math"] categories = ["mathematics", "web-programming", "parser-implementations"] [dependencies] -factorion-lib = {path = "../factorion-lib", version = "4.4.0", features = ["serde", "influxdb"]} +factorion-lib = {path = "../factorion-lib", version = "4.4.1", features = ["serde", "influxdb"]} reqwest = { version = "0.12.28", features = ["json", "native-tls"], default-features = false } serde = { version = "1.0.219", default-features = false, features = ["derive"] } serde_json = "1.0.140" diff --git a/factorion-lib/Cargo.toml b/factorion-lib/Cargo.toml index f40cb22..20b9f40 100644 --- a/factorion-lib/Cargo.toml +++ b/factorion-lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factorion-lib" -version = "4.4.0" +version = "4.4.1" edition = "2024" description = "A library used to create bots to recognize and calculate factorials and related concepts" license = "MIT" @@ -10,7 +10,7 @@ keywords = ["factorial", "termial", "bot", "math"] categories = ["mathematics", "web-programming", "parser-implementations"] [dependencies] -factorion-math = {path = "../factorion-math", version = "1.0"} +factorion-math = {path = "../factorion-math", version = "1.0.2"} serde = {version = "1.0", features = ["derive"], optional = true} serde_json = {version = "1.0", optional = true} concat-idents = "1.1.4" diff --git a/factorion-math/Cargo.toml b/factorion-math/Cargo.toml index 6fe606a..ac5aee6 100644 --- a/factorion-math/Cargo.toml +++ b/factorion-math/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "factorion-math" -version = "1.0.1" +version = "1.0.2" edition = "2024" description = "The math (factorials and related functions) used by factorion" license = "MIT"