v0.1.4-pre.015-fix.002
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/src/app_state.rs
|
||||
// version: 4
|
||||
// version: 5
|
||||
|
||||
//! Shared backend state owned by the Tauri application.
|
||||
|
||||
@@ -110,6 +110,29 @@ impl AppState {
|
||||
return &self.config_management;
|
||||
}
|
||||
|
||||
/// Replaces the active Logging runtime with freshly resolved settings and advances the runtime generation only after success.
|
||||
pub(crate) fn reinitialize_logging_runtime(&self, profile_id: &str, settings: &ksp_logging_lib::LoggingSettings) -> ksp_core_lib::Result<u32> {
|
||||
let runtime = self.logging_runtime.lock();
|
||||
let mut runtime = match runtime {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => {
|
||||
return std::result::Result::Err(ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_APP_STATE_LOCK_FAILED,
|
||||
"Config Desk Logging runtime state lock is poisoned",
|
||||
));
|
||||
},
|
||||
};
|
||||
let reinitialized = ksp_logging_lib::reinitialize(&mut runtime.guard, settings);
|
||||
if let std::result::Result::Err(error) = reinitialized {
|
||||
return std::result::Result::Err(error);
|
||||
}
|
||||
runtime.active_profile_id = std::option::Option::Some(profile_id.to_owned());
|
||||
runtime.generation = runtime.generation.saturating_add(1);
|
||||
runtime.fallback_active = false;
|
||||
runtime.startup_diagnostic = std::option::Option::None;
|
||||
return std::result::Result::Ok(runtime.generation);
|
||||
}
|
||||
|
||||
/// Returns the resolved splash timings captured during application bootstrap.
|
||||
#[must_use]
|
||||
pub(crate) const fn splash_settings(&self) -> crate::SplashSettings {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/src/errors.rs
|
||||
// version: 7
|
||||
// version: 8
|
||||
|
||||
//! Application-local error codes for the configuration desktop shell.
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
pub(crate) const ERROR_CODE_TAURI_RUNTIME_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("config_desk", "tauri_runtime_failed");
|
||||
/// Config Desk could not install the managed Logging runtime or its safe fallback.
|
||||
pub(crate) const ERROR_CODE_LOGGING_BOOTSTRAP_FAILED: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("config_desk", "logging_bootstrap_failed");
|
||||
/// Config Desk persisted a Logging candidate but could not restore the previous source after runtime application failed.
|
||||
pub(crate) const ERROR_CODE_LOGGING_SOURCE_ROLLBACK_FAILED: ksp_core_lib::ErrorCode =
|
||||
ksp_core_lib::ErrorCode::new("config_desk", "logging_source_rollback_failed");
|
||||
/// Shared Config Desk application state is internally inconsistent.
|
||||
pub(crate) const ERROR_CODE_APP_STATE_INVALID: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("config_desk", "app_state_invalid");
|
||||
/// Shared Config Desk runtime state cannot be locked safely.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/src/lib.rs
|
||||
// version: 11
|
||||
// version: 12
|
||||
|
||||
//! Tauri desktop application for managing and validating KSP configuration.
|
||||
|
||||
@@ -55,6 +55,7 @@ pub(crate) use self::errors::ERROR_CODE_DOCUMENT_KIND_INVALID;
|
||||
pub(crate) use self::errors::ERROR_CODE_FRONTEND_LOG_LEVEL_INVALID;
|
||||
pub(crate) use self::errors::ERROR_CODE_FRONTEND_LOG_TARGET_INVALID;
|
||||
pub(crate) use self::errors::ERROR_CODE_LOGGING_BOOTSTRAP_FAILED;
|
||||
pub(crate) use self::errors::ERROR_CODE_LOGGING_SOURCE_ROLLBACK_FAILED;
|
||||
pub(crate) use self::errors::ERROR_CODE_PROFILE_CONTRACT_MISSING;
|
||||
pub(crate) use self::errors::ERROR_CODE_PROFILE_PROJECTION_FAILED;
|
||||
pub(crate) use self::errors::ERROR_CODE_SECRET_REVEAL_REQUIRES_SECRET;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-app-config-desk/src/logging_editor.rs
|
||||
// version: 2
|
||||
// version: 3
|
||||
|
||||
//! Typed Logging document projection and validated persistence for the Config Desk Logging editor.
|
||||
|
||||
@@ -127,7 +127,13 @@ pub(crate) struct LoggingDocumentSaveResultDto {
|
||||
pub(crate) source_changed: bool,
|
||||
/// Whether Config consumers must reload the document.
|
||||
pub(crate) reload_required: bool,
|
||||
/// Fresh typed document loaded after successful persistence.
|
||||
/// Whether the active KSP Logging runtime was hot-reloaded from the persisted candidate.
|
||||
pub(crate) runtime_applied: bool,
|
||||
/// Runtime generation after the successful hot reload.
|
||||
pub(crate) logging_generation: u32,
|
||||
/// Profile selected and applied to the runtime.
|
||||
pub(crate) active_profile: String,
|
||||
/// Fresh typed document loaded after successful persistence and runtime application.
|
||||
pub(crate) document: LoggingDocumentDto,
|
||||
}
|
||||
|
||||
@@ -136,14 +142,31 @@ pub(crate) fn document(state: &crate::AppState) -> ksp_core_lib::Result<LoggingD
|
||||
return document_from_management(state.config_management());
|
||||
}
|
||||
|
||||
/// Validates and atomically persists one typed Logging candidate through ConfigManagement.
|
||||
/// Validates, atomically persists and hot-reloads one typed Logging candidate through ConfigManagement and `ksp-logging-lib`.
|
||||
pub(crate) fn save(state: &crate::AppState, candidate: LoggingDocumentCandidateDto) -> ksp_core_lib::Result<LoggingDocumentSaveResultDto> {
|
||||
let file_id = ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_STD_LOGGING);
|
||||
let file_id = match file_id {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let previous = state.config_management().read_source(&file_id);
|
||||
let previous = match previous {
|
||||
std::result::Result::Ok(value) => value.content().to_owned(),
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let source = config_candidate(candidate);
|
||||
let report = state.config_management().save_logging_document(&source);
|
||||
let report = match report {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let applied = apply_persisted_runtime(state);
|
||||
let (active_profile, logging_generation) = match applied {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
return rollback_after_runtime_failure(state.config_management(), &file_id, previous.as_str(), report.source_changed(), error);
|
||||
},
|
||||
};
|
||||
let document = document_from_management(state.config_management());
|
||||
let document = match document {
|
||||
std::result::Result::Ok(value) => value,
|
||||
@@ -154,17 +177,68 @@ pub(crate) fn save(state: &crate::AppState, candidate: LoggingDocumentCandidateD
|
||||
domain = crate::TRACING_DOMAIN_LOGGING_EDITOR,
|
||||
source_changed = report.source_changed(),
|
||||
reload_required = report.reload_required(),
|
||||
runtime_applied = true,
|
||||
logging_generation,
|
||||
active_profile = active_profile.as_str(),
|
||||
profile_count = document.profiles.len(),
|
||||
default_profile = document.default_profile.as_str(),
|
||||
"typed Logging document persistence completed; runtime was not reinitialized"
|
||||
"typed Logging document persistence and runtime hot reload completed"
|
||||
);
|
||||
return std::result::Result::Ok(LoggingDocumentSaveResultDto {
|
||||
source_changed: report.source_changed(),
|
||||
reload_required: report.reload_required(),
|
||||
runtime_applied: true,
|
||||
logging_generation,
|
||||
active_profile,
|
||||
document,
|
||||
});
|
||||
}
|
||||
|
||||
fn apply_persisted_runtime(state: &crate::AppState) -> ksp_core_lib::Result<(String, u32)> {
|
||||
let environment = ksp_config_lib::ConfigEnvironment::load();
|
||||
let environment = match environment {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let resolved = state.config_management().engine().load_resolved_logging_config(std::option::Option::None, &environment);
|
||||
let resolved = match resolved {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let profile_id = resolved.profile_id().to_owned();
|
||||
let settings = resolved.into_settings();
|
||||
let generation = state.reinitialize_logging_runtime(profile_id.as_str(), &settings);
|
||||
return match generation {
|
||||
std::result::Result::Ok(value) => std::result::Result::Ok((profile_id, value)),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||
};
|
||||
}
|
||||
|
||||
fn rollback_after_runtime_failure(
|
||||
management: &ksp_config_lib::ConfigManagement,
|
||||
file_id: &ksp_config_lib::ConfigFileId,
|
||||
previous_source: &str,
|
||||
source_changed: bool,
|
||||
runtime_error: ksp_core_lib::Error,
|
||||
) -> ksp_core_lib::Result<LoggingDocumentSaveResultDto> {
|
||||
if !source_changed {
|
||||
return std::result::Result::Err(runtime_error);
|
||||
}
|
||||
let rollback = management.save_source_candidate(file_id, previous_source);
|
||||
return match rollback {
|
||||
std::result::Result::Ok(_) => std::result::Result::Err(runtime_error),
|
||||
std::result::Result::Err(rollback_error) => std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_LOGGING_SOURCE_ROLLBACK_FAILED,
|
||||
"Logging runtime hot reload failed and the previous persisted source could not be restored",
|
||||
)
|
||||
.with_context("runtime_error_domain", runtime_error.code().domain())
|
||||
.with_context("runtime_error_code", runtime_error.code().code())
|
||||
.with_source(rollback_error),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
fn document_from_management(management: &ksp_config_lib::ConfigManagement) -> ksp_core_lib::Result<LoggingDocumentDto> {
|
||||
let source = management.load_logging_document();
|
||||
let source = match source {
|
||||
|
||||
Reference in New Issue
Block a user