pub struct ChallengeMemory { /* private fields */ }Expand description
Short-horizon, capacity-bounded LRU memory of challenge outcomes
keyed by (domain, target_class).
The store reuses the same LruTtlStore
primitive that backs the investigation report cache. That keeps
eviction + expiry semantics consistent across both caches and
satisfies the “no new cache store” requirement.
§Example
use stygian_charon::challenge_feedback::{ChallengeMemory, ChallengeOutcome};
use stygian_charon::types::TargetClass;
use std::num::NonZeroUsize;
use std::time::Duration;
let memory =
ChallengeMemory::new(NonZeroUsize::new(8).expect("non-zero"), Duration::from_mins(5));
memory.record("example.com", TargetClass::ContentSite, ChallengeOutcome::Captcha);
let entry = memory.lookup("example.com", TargetClass::ContentSite).expect("entry");
assert_eq!(entry.last_outcome, ChallengeOutcome::Captcha);
assert_eq!(entry.observation_count, 1);Implementations§
Source§impl ChallengeMemory
impl ChallengeMemory
Sourcepub fn new(capacity: NonZeroUsize, ttl: Duration) -> Self
pub fn new(capacity: NonZeroUsize, ttl: Duration) -> Self
Create a new challenge memory with explicit capacity and TTL.
Sourcepub fn with_default_ttl(capacity: NonZeroUsize) -> Self
pub fn with_default_ttl(capacity: NonZeroUsize) -> Self
Create a new challenge memory with
DEFAULT_CHALLENGE_CAPACITY and
DEFAULT_CHALLENGE_TTL.
Sourcepub fn with_defaults() -> Self
pub fn with_defaults() -> Self
Capacity-bounded ChallengeMemory with the default
capacity and TTL.
Sourcepub fn record(
&self,
domain: &str,
target_class: TargetClass,
outcome: ChallengeOutcome,
)
pub fn record( &self, domain: &str, target_class: TargetClass, outcome: ChallengeOutcome, )
Record a challenge outcome for a (domain, target_class)
key. Replaces the existing entry (if any) and increments the
observation counter atomically with the read-modify-write
sequence. Lower-cases the domain for stable keying.
§Example
use stygian_charon::challenge_feedback::{ChallengeMemory, ChallengeOutcome};
use stygian_charon::types::TargetClass;
let memory = ChallengeMemory::with_defaults();
memory.record("Example.COM", TargetClass::Api, ChallengeOutcome::Pass);
let entry = memory.lookup("example.com", TargetClass::Api).unwrap();
assert_eq!(entry.last_outcome, ChallengeOutcome::Pass);
assert_eq!(entry.observation_count, 1);Sourcepub fn lookup(
&self,
domain: &str,
target_class: TargetClass,
) -> Option<ChallengeMemoryEntry>
pub fn lookup( &self, domain: &str, target_class: TargetClass, ) -> Option<ChallengeMemoryEntry>
Look up the current entry for a (domain, target_class) key.
Returns None if the key is absent or has expired.
§Example
use stygian_charon::challenge_feedback::ChallengeMemory;
use stygian_charon::types::TargetClass;
let memory = ChallengeMemory::with_defaults();
assert!(memory.lookup("nope.example", TargetClass::Api).is_none());Sourcepub fn invalidate(&self, domain: &str, target_class: TargetClass)
pub fn invalidate(&self, domain: &str, target_class: TargetClass)
Invalidate a single (domain, target_class) key.