sl_map_web/state.rs
1//! Shared application state passed to every handler.
2
3use std::sync::Arc;
4use std::sync::atomic::AtomicBool;
5
6use axum::extract::FromRef;
7use axum_extra::extract::cookie::Key;
8use sl_glw::GlwEventCache;
9use sl_map_apis::map_tiles::MapTileCache;
10use sl_map_apis::region::RegionNameToGridCoordinatesCache;
11use tokio::sync::Mutex;
12
13use crate::config::Config;
14use crate::fonts::FontDirectory;
15use crate::jobs::JobStore;
16
17/// State shared between all axum handlers.
18///
19/// The two cache types both require `&mut self` to drive lookups, so they
20/// are wrapped in async [`Mutex`]es. As a side effect this serialises
21/// renders to one at a time; that is acceptable for v1 because each render
22/// is also bounded by the upstream rate limiter.
23#[derive(Clone, Debug)]
24#[expect(
25 clippy::module_name_repetitions,
26 reason = "`AppState` is the conventional name for axum shared state and would be ambiguous as just `State`"
27)]
28pub struct AppState {
29 /// the on-disk + in-memory cache of map tiles, shared with the CLI.
30 pub map_tile_cache: Arc<Mutex<MapTileCache>>,
31 /// the region name <-> grid coordinates cache.
32 pub region_cache: Arc<Mutex<RegionNameToGridCoordinatesCache>>,
33 /// the in-memory store of running and recently completed render jobs.
34 pub jobs: Arc<JobStore>,
35 /// the runtime configuration.
36 pub config: Arc<Config>,
37 /// SQLite pool used by the auth subsystem (users, sessions, set-password
38 /// tokens). Cheap to clone.
39 pub db: sqlx::SqlitePool,
40 /// signing key for the session cookie, derived from the configured
41 /// `session_signing_key` at startup. `Key` is internally a buffer of
42 /// bytes; cloning is cheap.
43 pub cookie_key: Key,
44 /// in-process flag raised whenever a code path may have produced stale
45 /// files under `<storage_dir>/renders/` without unlinking them inline
46 /// (e.g. a cascade delete from removing a group). The orphan sweeper
47 /// only scans the filesystem when this flag is set so an idle server
48 /// does no filesystem work.
49 pub library_cleanup_dirty: Arc<AtomicBool>,
50 /// three-tier cache (memory LRU + redb + http-cache-semantics) for
51 /// GLW events. Created at startup from `config.cache_dir` like the
52 /// CLI does. Used by render workers when a render requests a GLW
53 /// overlay via event id or event key.
54 pub glw_event_cache: Arc<Mutex<GlwEventCache>>,
55 /// fonts discovered under `config.fonts_directory` at startup.
56 /// Surfaced through `GET /api/fonts` and used by render workers to
57 /// resolve a client-supplied `font_id` to the font file path.
58 pub fonts: Arc<FontDirectory>,
59}
60
61// `axum_extra::extract::cookie::SignedCookieJar` extracts itself via
62// `FromRef<S, Key>`, so we expose the `cookie_key` through `FromRef`.
63impl FromRef<AppState> for Key {
64 fn from_ref(input: &AppState) -> Self {
65 input.cookie_key.clone()
66 }
67}