Files
khadhroony-solana-project/crates/ksp-app-store-desk/src/store_runtime.rs
2026-09-03 16:26:18 +02:00

250 lines
11 KiB
Rust

// 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<String>,
diagnostic: std::option::Option<crate::CommandErrorDto>,
network: std::option::Option<String>,
profile_id: std::option::Option<String>,
runtime: std::option::Option<StoreRuntime>,
}
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<std::option::Option<ksp_store_lib::Store>>,
}
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<crate::CommandErrorDto> {
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<String>,
backend_kind: std::option::Option<String>,
network: std::option::Option<String>,
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,
};
}