// file: crates/ksp-app-store-desk/src/store_runtime.rs // version: 1 //! Composite-selected Store readiness, status and bounded shutdown lifecycle owned by Store Desk. /// Startup result for Store, including safe diagnostics when the desktop shell remains available without an opened runtime. pub(crate) struct StoreStartup { backend_kind: std::option::Option, diagnostic: std::option::Option, network: std::option::Option, profile_id: std::option::Option, runtime: std::option::Option, } impl StoreStartup { /// Builds a fresh backend-neutral runtime/health projection for the Overview screen. pub(crate) async fn status(&self) -> crate::StoreRuntimeStatusDto { let runtime = self.runtime.as_ref(); return match runtime { std::option::Option::Some(value) => value.status().await, std::option::Option::None => crate::StoreRuntimeStatusDto { backend_kind: self.backend_kind.clone(), diagnostic: self.diagnostic.clone(), health_state: "unavailable".to_owned(), migration_version_decimal: std::option::Option::None, network: self.network.clone(), pending_migration_count: 0, pool_available: 0, pool_capacity: 0, pool_size: 0, pool_waiting: 0, profile_id: self.profile_id.clone(), store_open: false, }, }; } /// Closes the retained Store runtime if startup reached the physical Store-open phase. pub(crate) async fn close(&self) -> ksp_core_lib::Result<()> { let runtime = self.runtime.as_ref(); return match runtime { std::option::Option::Some(value) => value.close().await, std::option::Option::None => std::result::Result::Ok(()), }; } } /// Executable Store runtime retained behind an async read/write lock so read-only Desk queries may coexist while shutdown remains exclusive. pub(crate) struct StoreRuntime { profile_id: String, store: tokio::sync::RwLock>, } impl StoreRuntime { /// Builds one fresh safe Store status from the retained facade without exposing backend connection details. pub(crate) async fn status(&self) -> crate::StoreRuntimeStatusDto { let locked = self.store.read().await; let store = locked.as_ref(); let store = match store { std::option::Option::Some(value) => value, std::option::Option::None => { return crate::StoreRuntimeStatusDto { backend_kind: std::option::Option::None, diagnostic: std::option::Option::None, health_state: "closed".to_owned(), migration_version_decimal: std::option::Option::None, network: std::option::Option::None, pending_migration_count: 0, pool_available: 0, pool_capacity: 0, pool_size: 0, pool_waiting: 0, profile_id: std::option::Option::Some(self.profile_id.clone()), store_open: false, }; }, }; let runtime = store.runtime_snapshot(); let health = store.health().await; let health_state = store_health_state_code(health.state()).to_owned(); let diagnostic = non_ready_health_diagnostic(&health); return crate::StoreRuntimeStatusDto { backend_kind: std::option::Option::Some(runtime.backend_kind().code().to_owned()), diagnostic, health_state, migration_version_decimal: health.migration_version().map(|value| return value.to_string()), network: std::option::Option::Some(runtime.network().as_str().to_owned()), pending_migration_count: health.pending_migration_count(), pool_available: runtime.pool_available(), pool_capacity: runtime.pool_capacity(), pool_size: runtime.pool_size(), pool_waiting: runtime.pool_waiting(), profile_id: std::option::Option::Some(self.profile_id.clone()), store_open: true, }; } /// Explicitly closes the Store exactly once through its backend-neutral facade after all read guards have drained. pub(crate) async fn close(&self) -> ksp_core_lib::Result<()> { let mut locked = self.store.write().await; let store = locked.take(); drop(locked); let store = match store { std::option::Option::Some(value) => value, std::option::Option::None => return std::result::Result::Ok(()), }; let snapshot = store.runtime_snapshot(); let backend_kind = snapshot.backend_kind().code().to_owned(); let network = snapshot.network().as_str().to_owned(); let closed = store.close().await; return match closed { std::result::Result::Ok(()) => { ksp_logging_lib::debug!( target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_STORE, store_profile = self.profile_id.as_str(), backend = backend_kind.as_str(), network = network.as_str(), "closed Store Desk Store runtime" ); std::result::Result::Ok(()) }, std::result::Result::Err(error) => std::result::Result::Err( ksp_core_lib::Error::new(crate::ERROR_CODE_STORE_SHUTDOWN_FAILED, "Store Desk Store shutdown failed").with_source(error), ), }; } } /// Resolves the composite Store target, opens Store through the facade and captures one initial readiness probe. pub(crate) async fn initialize_store(management: &ksp_config_lib::ConfigManagement) -> StoreStartup { let environment = ksp_config_lib::ConfigEnvironment::load(); let environment = match environment { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return unavailable_startup(std::option::Option::None, std::option::Option::None, std::option::Option::None, error), }; let composite = crate::load_store_desk_composite(management); let composite = match composite { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => return unavailable_startup(std::option::Option::None, std::option::Option::None, std::option::Option::None, error), }; let profile = crate::required_composite_component_profile(&composite, crate::COMPOSITE_COMPONENT_ID_STORE, ksp_config_lib::FILE_ID_STD_STORE); let profile = match profile { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => { return unavailable_startup( std::option::Option::Some(composite.profile_id().to_owned()), std::option::Option::None, std::option::Option::None, error, ); }, }; let resolved = management.engine().resolve_store_config_profile(&profile, &environment); let resolved = match resolved { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => { return unavailable_startup( std::option::Option::Some(profile.profile_id().to_owned()), std::option::Option::None, std::option::Option::None, error, ); }, }; let profile_id = resolved.profile_id().to_owned(); let backend_kind = resolved.settings().backend_kind().code().to_owned(); let network = resolved.settings().network().as_str().to_owned(); let store = ksp_store_lib::Store::open(resolved.into_settings()).await; let store = match store { std::result::Result::Ok(value) => value, std::result::Result::Err(error) => { return unavailable_startup( std::option::Option::Some(profile_id), std::option::Option::Some(backend_kind), std::option::Option::Some(network), error, ); }, }; let health = store.health().await; ksp_logging_lib::debug!( target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_STORE, store_profile = profile_id.as_str(), backend = backend_kind.as_str(), network = network.as_str(), health_state = store_health_state_code(health.state()), pending_migration_count = health.pending_migration_count(), "initialized Store Desk Store from composite-managed configuration" ); return StoreStartup { backend_kind: std::option::Option::Some(backend_kind), diagnostic: non_ready_health_diagnostic(&health), network: std::option::Option::Some(network), profile_id: std::option::Option::Some(profile_id.clone()), runtime: std::option::Option::Some(StoreRuntime { profile_id, store: tokio::sync::RwLock::new(std::option::Option::Some(store)) }), }; } fn non_ready_health_diagnostic(health: &ksp_store_lib::StoreHealthSnapshot) -> std::option::Option { if matches!(health.state(), ksp_store_lib::StoreHealthState::Ready) { return std::option::Option::None; } let code = health.last_error_code(); return match code { std::option::Option::Some(value) => std::option::Option::Some(crate::CommandErrorDto { code: value.code().to_owned(), domain: value.domain().to_owned(), message: "Store health probe did not prove readiness".to_owned(), }), std::option::Option::None => std::option::Option::Some(crate::CommandErrorDto { code: "store_not_ready".to_owned(), domain: "store_desk".to_owned(), message: "Store health probe did not prove readiness".to_owned(), }), }; } fn store_health_state_code(state: ksp_store_lib::StoreHealthState) -> &'static str { return match state { ksp_store_lib::StoreHealthState::Ready => "ready", ksp_store_lib::StoreHealthState::NotReady => "not_ready", _ => "unknown", }; } fn unavailable_startup( profile_id: std::option::Option, backend_kind: std::option::Option, network: std::option::Option, error: ksp_core_lib::Error, ) -> StoreStartup { let diagnostic = crate::CommandErrorDto::from_error(&error); ksp_logging_lib::warn!( target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_STORE, error_domain = diagnostic.domain.as_str(), error_code = diagnostic.code.as_str(), "Store Desk Store readiness is unavailable; keeping desktop shell available" ); return StoreStartup { backend_kind, diagnostic: std::option::Option::Some(diagnostic), network, profile_id, runtime: std::option::Option::None, }; }