use std::collections::HashMap;
use std::sync::Mutex;
use std::time::{Duration, Instant};
pub const SAY_EVERY: Duration = Duration::from_secs(60);
static WINDOWS: Mutex<Option<HashMap<String, (Instant, u64)>>> = Mutex::new(None);
pub fn loud(shape: &str) -> Option<u64> {
loud_at(shape, Instant::now())
}
pub fn loud_at(shape: &str, now: Instant) -> Option<u64> {
let mut g = WINDOWS.lock().unwrap_or_else(|p| p.into_inner());
let map = g.get_or_insert_with(HashMap::new);
match map.get_mut(shape) {
Some((since, quiet)) if now.saturating_duration_since(*since) < SAY_EVERY => {
*quiet += 1;
None
}
Some(w) => {
let went = w.1;
*w = (now, 0);
Some(went)
}
None => {
map.insert(shape.to_owned(), (now, 0));
Some(0)
}
}
}
pub fn unverified(reason: &str) -> bool {
reason == "not-verified"
}
pub fn growth_hold(grpc_status: Option<i32>, grpc_message: Option<&str>) -> bool {
grpc_status == Some(14)
&& grpc_message.is_some_and(|m| m.contains("primary-growing") || m.replace("%20", " ").contains("off the stripe while the data set grows"))
}
pub fn unverified_answer(grpc_status: Option<i32>, grpc_message: Option<&str>) -> bool {
grpc_status == Some(16) && grpc_message.is_some_and(|m| m.contains("did%20not%20verify") || m.contains("did not verify"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_retried_unverified_refusal_is_said_once_a_minute_with_the_count_that_went_quietly() {
let t0 = Instant::now();
let shape = "test:a_retried_unverified_refusal";
let mut loud_ones = Vec::new();
for i in 0..14u64 {
if let Some(n) = loud_at(shape, t0 + Duration::from_secs(i * 9)) {
loud_ones.push((i, n));
}
}
assert_eq!(loud_ones, vec![(0, 0), (7, 6)], "one WARN a minute, the next one names the six that went quietly");
assert!(loud_at("test:another_shape", t0).is_some(), "shapes are counted apart");
assert!(unverified("not-verified") && !unverified("replayed") && !unverified("stale"));
assert!(unverified_answer(Some(16), Some("the%20credential%20did%20not%20verify%20against%20any%20registered%20key")));
assert!(!unverified_answer(Some(7), Some("did not verify")) && !unverified_answer(Some(16), Some("malformed credential")));
}
}