// file: kb-app-demo-desktop/src/app_state.rs // version: 10 //! Shared Tauri application state and startup initialization. /// Shared state managed by Tauri for the desktop demo application. pub(crate) struct AppState { config_path: std::string::String, app_config: kb_config::AppConfig, active_profile: kb_config::ProfileConfig, logging_guard: std::sync::Mutex, http_pool: kb_onchain_transport::HttpEndpointPool, ws_pool: std::sync::Mutex>>, demo_ws_session: tokio::sync::Mutex>>, demo_backfill_running: std::sync::atomic::AtomicBool, demo_backfill_cancel_requested: std::sync::atomic::AtomicBool, demo_core_extraction_running: std::sync::atomic::AtomicBool, demo_core_extraction_cancel_requested: std::sync::atomic::AtomicBool, demo_decode_replay_running: std::sync::atomic::AtomicBool, demo_decode_replay_cancel_requested: std::sync::atomic::AtomicBool, demo_decode_replay_campaign_id: std::sync::Mutex>, demo_execution_solana_core_running: std::sync::atomic::AtomicBool, demo_execution_solana_core_cancel_requested: std::sync::atomic::AtomicBool, startup_sequence_started: std::sync::atomic::AtomicBool, } impl crate::AppState { /// Initializes configuration, logging and shared runtime state. pub(crate) fn initialize() -> kb_core::Result { let config_path = resolve_config_path(); let workspace_root = crate::workspace_root_dir(); let app_config = match kb_config::read_config_json_file_with_environment( &config_path, &workspace_root, ) { std::result::Result::Ok(config) => config, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let active_profile = match kb_config::active_profile(&app_config) { std::result::Result::Ok(profile) => profile.clone(), std::result::Result::Err(error) => return std::result::Result::Err(error), }; let logging_config = convert_logging_config(&active_profile.logging); let logging_guard = match kb_logging::init_logging(&logging_config) { std::result::Result::Ok(guard) => guard, std::result::Result::Err(error) => return std::result::Result::Err(error), }; let http_pool = match kb_onchain_transport::HttpEndpointPool::from_profile(&active_profile) { std::result::Result::Ok(pool) => pool, std::result::Result::Err(error) => return std::result::Result::Err(error), }; return std::result::Result::Ok(crate::AppState { config_path: config_path.display().to_string(), app_config, active_profile, logging_guard: std::sync::Mutex::new(logging_guard), http_pool, ws_pool: std::sync::Mutex::new(std::option::Option::None), demo_ws_session: tokio::sync::Mutex::new(std::option::Option::None), demo_backfill_running: std::sync::atomic::AtomicBool::new(false), demo_backfill_cancel_requested: std::sync::atomic::AtomicBool::new(false), demo_core_extraction_running: std::sync::atomic::AtomicBool::new(false), demo_core_extraction_cancel_requested: std::sync::atomic::AtomicBool::new(false), demo_decode_replay_running: std::sync::atomic::AtomicBool::new(false), demo_decode_replay_cancel_requested: std::sync::atomic::AtomicBool::new(false), demo_decode_replay_campaign_id: std::sync::Mutex::new(std::option::Option::None), demo_execution_solana_core_running: std::sync::atomic::AtomicBool::new(false), demo_execution_solana_core_cancel_requested: std::sync::atomic::AtomicBool::new(false), startup_sequence_started: std::sync::atomic::AtomicBool::new(false), }); } /// Returns the path used to load the configuration file. pub(crate) fn config_path(&self) -> &str { return self.config_path.as_str(); } /// Returns the complete parsed application configuration. pub(crate) fn app_config(&self) -> &kb_config::AppConfig { return &self.app_config; } /// Returns the active profile selected from the configuration. pub(crate) fn active_profile(&self) -> &kb_config::ProfileConfig { return &self.active_profile; } /// Returns the configured HTTP endpoint pool. pub(crate) fn http_pool(&self) -> &kb_onchain_transport::HttpEndpointPool { return &self.http_pool; } /// Returns the lazily initialized WebSocket endpoint pool. pub(crate) fn demo_ws_pool( &self, ) -> kb_core::Result> { let lock_result = self.ws_pool.lock(); let mut guard = match lock_result { std::result::Result::Ok(value) => value, std::result::Result::Err(_) => { return std::result::Result::Err(kb_core::Error::invalid_state( "demo WebSocket pool lock is poisoned", )); }, }; if let std::option::Option::Some(pool) = guard.as_ref() { return std::result::Result::Ok(std::sync::Arc::clone(pool)); } let pool = match kb_onchain_transport::WsEndpointPool::from_profile(&self.active_profile) { std::result::Result::Ok(value) => std::sync::Arc::new(value), std::result::Result::Err(error) => return std::result::Result::Err(error), }; *guard = std::option::Option::Some(std::sync::Arc::clone(&pool)); return std::result::Result::Ok(pool); } /// Returns the persistent WebSocket demo session slot. pub(crate) fn demo_ws_session( &self, ) -> &tokio::sync::Mutex>> { return &self.demo_ws_session; } /// Returns the single-campaign execution flag used by the backfill window. pub(crate) fn demo_backfill_running(&self) -> &std::sync::atomic::AtomicBool { return &self.demo_backfill_running; } /// Returns the cooperative cancellation flag used by the backfill window. pub(crate) fn demo_backfill_cancel_requested(&self) -> &std::sync::atomic::AtomicBool { return &self.demo_backfill_cancel_requested; } /// Returns the core extraction running flag. pub(crate) fn demo_core_extraction_running(&self) -> &std::sync::atomic::AtomicBool { return &self.demo_core_extraction_running; } /// Returns the core extraction cancellation flag. pub(crate) fn demo_core_extraction_cancel_requested(&self) -> &std::sync::atomic::AtomicBool { return &self.demo_core_extraction_cancel_requested; } /// Returns the decode replay running flag. pub(crate) fn demo_decode_replay_running(&self) -> &std::sync::atomic::AtomicBool { return &self.demo_decode_replay_running; } /// Returns the decode replay cancellation flag. pub(crate) fn demo_decode_replay_cancel_requested(&self) -> &std::sync::atomic::AtomicBool { return &self.demo_decode_replay_cancel_requested; } /// Returns the active decode replay campaign slot. pub(crate) fn demo_decode_replay_campaign_id( &self, ) -> &std::sync::Mutex> { return &self.demo_decode_replay_campaign_id; } /// Returns the shared execution running flag used by Solana and SPL windows. pub(crate) fn demo_execution_solana_core_running(&self) -> &std::sync::atomic::AtomicBool { return &self.demo_execution_solana_core_running; } /// Returns the shared execution cancellation flag used by Solana and SPL windows. pub(crate) fn demo_execution_solana_core_cancel_requested( &self, ) -> &std::sync::atomic::AtomicBool { return &self.demo_execution_solana_core_cancel_requested; } /// Starts the splash startup sequence at most once. pub(crate) fn begin_startup_sequence(&self) -> bool { return self .startup_sequence_started .compare_exchange( false, true, std::sync::atomic::Ordering::AcqRel, std::sync::atomic::Ordering::Acquire, ) .is_ok(); } /// Returns the number of logging routes held by the logging guard. pub(crate) fn logging_route_count(&self) -> usize { let lock_result = self.logging_guard.lock(); let guard = match lock_result { std::result::Result::Ok(guard) => guard, std::result::Result::Err(_) => return 0, }; return guard.route_count(); } } fn convert_logging_config(config: &kb_config::LoggingConfig) -> kb_logging::LoggingConfig { let mut targets = std::vec::Vec::::new(); for target in &config.targets { targets.push(kb_logging::LogTargetConfig { name: target.name.clone(), enabled: target.enabled, sink: target.sink.clone(), level: target.level.clone(), path: target.path.clone(), rotation: target.rotation.clone(), format: target.format.clone(), ansi: target.ansi, targets: target.targets.clone(), }); } let mut target_filters = std::vec::Vec::::new(); for filter in &config.target_filters { target_filters.push(kb_logging::LogTargetFilterConfig { target: filter.target.clone(), level: filter.level.clone(), }); } return kb_logging::LoggingConfig { default_level: config.default_level.clone(), targets, target_filters, }; } fn resolve_config_path() -> std::path::PathBuf { let configured = std::env::var("KB_CONFIG_PATH").ok(); return resolve_config_path_from_value(configured.as_deref()); } fn resolve_config_path_from_value(value: std::option::Option<&str>) -> std::path::PathBuf { if let std::option::Option::Some(configured) = value { let trimmed = configured.trim(); if !trimmed.is_empty() { return std::path::PathBuf::from(trimmed); } } return crate::workspace_root_dir().join("config/example.config.json"); } #[cfg(test)] mod tests { #[test] fn resolve_config_path_uses_workspace_example_by_default() { let path = super::resolve_config_path_from_value(std::option::Option::None); assert_eq!( path.file_name().and_then(std::ffi::OsStr::to_str), std::option::Option::Some("example.config.json") ); } }