use std::sync::Arc; use parking_lot::RwLock; use rustc_hash::FxHashMap; use crate::auth::TokenCache; use crate::data::{ OutcodeData, POICategoryGroup, POIData, PlaceData, PostcodeData, PropertyData, TravelTimeStore, }; use crate::licensing::ShareBoundsCache; use crate::pocketbase::SuperuserTokenCache; use crate::routes::FeaturesResponse; use crate::utils::GridIndex; pub struct AppState { pub data: PropertyData, pub grid: GridIndex, /// h3_cells[row_idx] = precomputed H3 cell ID at max resolution (12). /// Parent cells for lower resolutions derived via CellIndex::parent(). pub h3_cells: Vec, /// O(1) lookup: feature name → index in feature_names/feature_data pub feature_name_to_index: FxHashMap, /// Precomputed JSON key names: "min_{feature_name}" for each feature pub min_keys: Vec, /// Precomputed JSON key names: "max_{feature_name}" for each feature pub max_keys: Vec, /// Precomputed JSON key names: "avg_{feature_name}" for each feature pub avg_keys: Vec, /// Precomputed features response for /api/features endpoint pub features_response: FeaturesResponse, /// Complete system prompt for AI filters (features + examples + instructions) pub ai_filters_system_prompt: String, pub poi_data: Arc, pub poi_grid: Arc, pub place_data: Arc, /// Postcode boundary data for high-zoom rendering pub postcode_data: Arc, /// Precomputed outcode centroids for search pub outcode_data: Arc, /// Precomputed POI category groups (sorted) pub poi_category_groups: Arc>, /// Precomputed travel time data store pub travel_time_store: Arc, /// Token validation cache (60s TTL) pub token_cache: Arc, /// Cached PocketBase superuser token (10min TTL) to avoid rate-limiting pub superuser_token_cache: Arc, /// Cached share-link bbox lookups (5min TTL); used to grant unlicensed /// users access to the area their share link references. pub share_cache: Arc, // --- Config (cheap to clone) --- /// URL of the screenshot service (e.g. http://screenshot:8002) pub screenshot_url: String, /// Public-facing URL for absolute og:image URLs (e.g. https://perfectpostcodes.dev) pub public_url: String, /// True when --dist is not provided (no static serving, relaxed auth checks) pub is_dev: bool, /// Shared HTTP client for proxying to the screenshot service and PocketBase pub http_client: reqwest::Client, /// PocketBase server URL for authentication (e.g. http://localhost:8090) pub pocketbase_url: String, /// PocketBase superuser email (needed for admin-only operations like subscription updates) pub pocketbase_admin_email: String, /// PocketBase superuser password pub pocketbase_admin_password: String, /// Gemini API key for AI filters pub gemini_api_key: String, /// Gemini model name (e.g. gemini-2.0-flash) pub gemini_model: String, /// Google Maps API key for Street View metadata lookups pub google_maps_api_key: String, /// Stripe secret key for creating checkout sessions pub stripe_secret_key: String, /// Stripe webhook signing secret pub stripe_webhook_secret: String, /// Stripe Coupon ID for referral discounts pub stripe_referral_coupon_id: String, } /// Wraps AppState for shared access across route handlers. /// Route handlers call `load_state()` to get the current snapshot. pub struct SharedState { current: RwLock>, } impl SharedState { pub fn new(state: AppState) -> Self { Self { current: RwLock::new(Arc::new(state)), } } /// Get the current AppState snapshot. Cheap (Arc clone under a brief read lock). pub fn load_state(&self) -> Arc { self.current.read().clone() } }