v0.1.4-pre.015-fix.002

This commit is contained in:
2026-08-16 18:20:32 +02:00
parent 05c65a12f4
commit 9ad61b40e1
25 changed files with 776 additions and 210 deletions

View File

@@ -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 {

View File

@@ -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.

View File

@@ -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;

View File

@@ -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 {