pub struct AppState {
pub sites: Arc<[Site]>,
pub client: Arc<Client>,
pub scans: Arc<RwLock<HashMap<ScanId, ScanHandle>>>,
pub scan_tasks: Arc<RwLock<HashMap<ScanId, JoinHandle<()>>>>,
pub scan_capacity: usize,
pub scans_dir: Option<Arc<PathBuf>>,
}Expand description
State shared across all axum handlers.
Cheap to clone — every field is an Arc or a small primitive.
axum requires State<T> to be Clone, hence this design.
Fields§
§sites: Arc<[Site]>Pre-filtered site list (registry + workspace flags applied at
startup). Held as an Arc<[Site]> to avoid re-cloning the
2.5k-entry vector on every scan dispatch.
client: Arc<Client>Shared HTTP client (connection pool, throttle, etc.).
scans: Arc<RwLock<HashMap<ScanId, ScanHandle>>>In-flight + recently-finished scans, keyed by ID.
scan_tasks: Arc<RwLock<HashMap<ScanId, JoinHandle<()>>>>Running-scan task handles, keyed by ScanId. Lets the
refilter endpoint cancel an in-flight scan via
JoinHandle::abort before spawning a successor with the new
filter. Entries are removed when their scan finishes naturally
(the task’s last act before returning) or when the eviction
policy reaps them alongside the ScanHandle.
scan_capacity: usizeMaximum number of scans retained in memory. Beyond this, the oldest finished scan is evicted on the next insertion (a tiny LRU — we never need more than ~dozens of recent scans in a human-driven web session).
scans_dir: Option<Arc<PathBuf>>Directory where finished scans are persisted as JSON. None
disables persistence (used by tests and ephemeral runs).
Implementations§
Source§impl AppState
impl AppState
Sourcepub fn new(sites: Vec<Site>, client: Client, scan_capacity: usize) -> Self
pub fn new(sites: Vec<Site>, client: Client, scan_capacity: usize) -> Self
Build initial state from a registry + a pre-built HTTP client.
The full registry is filtered with the supplied predicate; the
result is materialised into an Arc<[Site]> once so handler
dispatch is a pointer copy. Persistence is off by default —
chain Self::with_scans_dir to enable.
Sourcepub fn from_registry(
registry: &Registry,
client: Client,
scan_capacity: usize,
) -> Self
pub fn from_registry( registry: &Registry, client: Client, scan_capacity: usize, ) -> Self
Convenience: build state from a Registry using the
“no filter, NSFW excluded” default. The web UI exposes
per-scan filters anyway, so the initial site list is the full
non-NSFW set.
Sourcepub fn with_scans_dir(self, dir: PathBuf) -> Self
pub fn with_scans_dir(self, dir: PathBuf) -> Self
Enable on-disk persistence of finished scans under dir. Files
are written as <scan_id>.json after each scan completes;
startup reads them back so history survives server restarts.
Sourcepub async fn insert_scan(&self, id: ScanId, handle: ScanHandle)
pub async fn insert_scan(&self, id: ScanId, handle: ScanHandle)
Insert a fresh scan handle, evicting the oldest finished entry (or the oldest entry overall, if none has finished) when we are at capacity.
Sourcepub async fn register_scan_task(&self, id: ScanId, task: JoinHandle<()>)
pub async fn register_scan_task(&self, id: ScanId, task: JoinHandle<()>)
Register an in-flight scan task. The handle is stored so the refilter endpoint can abort it before starting a successor.
Sourcepub async fn forget_scan_task(&self, id: &ScanId)
pub async fn forget_scan_task(&self, id: &ScanId)
Remove an in-flight scan task entry. Used at the end of
crate::scan::run so the map doesn’t accumulate completed tasks.
Sourcepub async fn abort_scan(&self, id: &ScanId) -> bool
pub async fn abort_scan(&self, id: &ScanId) -> bool
Abort the running task for id (if any). Returns true when an
abort signal was actually sent; false when no live task was
recorded (already finished, or never started). Doesn’t wait for
the task to observe the abort — JoinHandle::abort is
non-blocking and the caller continues immediately.
Sourcepub async fn get_scan(&self, id: &ScanId) -> Option<ScanHandle>
pub async fn get_scan(&self, id: &ScanId) -> Option<ScanHandle>
Look up a scan by ID, cloning the handle (cheap — Arc inside).