223 lines
12 KiB
Rust
223 lines
12 KiB
Rust
// file: crates/ksp-app-raw-transaction-ingest-desk/src/app_state.rs
|
|
// version: 9
|
|
|
|
//! Shared backend state owned by the Raw Transaction Ingest Desk Tauri application.
|
|
|
|
/// Shared Raw Transaction Ingest Desk application state managed by Tauri.
|
|
pub(crate) struct AppState {
|
|
active_composite_profile: std::option::Option<String>,
|
|
config_management: ksp_config_lib::ConfigManagement,
|
|
inventory_generation: std::sync::Mutex<u32>,
|
|
logging_runtime: std::sync::Mutex<LoggingRuntimeState>,
|
|
route_runtime: std::sync::Arc<crate::RouteRuntimeState>,
|
|
splash_settings: crate::SplashSettings,
|
|
splash_sequence_started: std::sync::atomic::AtomicBool,
|
|
}
|
|
|
|
impl crate::AppState {
|
|
/// Initializes Config ownership and composite-managed Logging without constructing Transport, Store or Worker resources.
|
|
pub(crate) fn initialize(arguments: &[std::ffi::OsString]) -> ksp_core_lib::Result<Self> {
|
|
let config_management = crate::config_management(arguments);
|
|
let config_management = match config_management {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let runtime_identity = crate::launch_identity();
|
|
let runtime_identity = match runtime_identity {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let logging_startup = crate::initialize_logging(&config_management, &runtime_identity);
|
|
let logging_startup = match logging_startup {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let composite = crate::load_raw_transaction_ingest_desk_composite(&config_management);
|
|
let active_composite_profile = match composite {
|
|
std::result::Result::Ok(value) => std::option::Option::Some(value.profile_id().to_owned()),
|
|
std::result::Result::Err(_) => std::option::Option::None,
|
|
};
|
|
let splash_settings = crate::SplashSettings::load();
|
|
let splash_settings = match splash_settings {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => {
|
|
ksp_logging_lib::warn!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WINDOWS, error_domain = error.code().domain(), error_code = error.code().code(), "managed splash timings are invalid; using transient in-memory defaults");
|
|
crate::SplashSettings::fallback()
|
|
},
|
|
};
|
|
ksp_logging_lib::debug!(target: crate::TRACING_TARGET, domain = crate::TRACING_DOMAIN_WINDOWS, minimum_ms = splash_settings.minimum_ms(), minimum_source = splash_settings.minimum_source(), fade_in_ms = splash_settings.fade_in_ms(), fade_in_source = splash_settings.fade_in_source(), fade_out_ms = splash_settings.fade_out_ms(), fade_out_source = splash_settings.fade_out_source(), expected_backend_lifecycle_ms = splash_settings.expected_backend_lifecycle_ms(), "resolved Raw Transaction Ingest Desk splash timings");
|
|
return std::result::Result::Ok(Self {
|
|
active_composite_profile,
|
|
config_management,
|
|
inventory_generation: std::sync::Mutex::new(0),
|
|
logging_runtime: std::sync::Mutex::new(LoggingRuntimeState {
|
|
guard: logging_startup.guard,
|
|
active_profile_id: logging_startup.active_profile_id,
|
|
fallback_active: logging_startup.fallback_active,
|
|
startup_diagnostic: logging_startup.startup_diagnostic,
|
|
}),
|
|
route_runtime: std::sync::Arc::new(crate::RouteRuntimeState::new()),
|
|
splash_settings,
|
|
splash_sequence_started: std::sync::atomic::AtomicBool::new(false),
|
|
});
|
|
}
|
|
|
|
/// Returns the static V1 route/state vocabulary without making any Config composability claim.
|
|
#[must_use]
|
|
pub(crate) fn route_foundation(&self) -> crate::RawIngestRouteFoundationDto {
|
|
let _keep_config_owner_alive = &self.config_management;
|
|
return crate::RawIngestRouteFoundationDto::scaffold();
|
|
}
|
|
|
|
/// Rebuilds the complete Config-only route inventory and publishes a fresh monotonic generation.
|
|
pub(crate) fn route_inventory(&self) -> ksp_core_lib::Result<crate::RawIngestRouteInventoryDto> {
|
|
let generation = self.inventory_generation.lock();
|
|
let mut generation = match generation {
|
|
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,
|
|
"Raw Transaction Ingest Desk route inventory generation lock is poisoned",
|
|
));
|
|
},
|
|
};
|
|
let next_generation = generation.checked_add(1);
|
|
let next_generation = match next_generation {
|
|
std::option::Option::Some(value) => value,
|
|
std::option::Option::None => {
|
|
return std::result::Result::Err(ksp_core_lib::Error::new(
|
|
crate::ERROR_CODE_ROUTE_INVENTORY_INVALID,
|
|
"Raw Transaction Ingest Desk route inventory generation is exhausted",
|
|
));
|
|
},
|
|
};
|
|
let inventory = crate::build_route_inventory(&self.config_management, next_generation);
|
|
let inventory = match inventory {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
*generation = next_generation;
|
|
return std::result::Result::Ok(inventory);
|
|
}
|
|
|
|
/// Revalidates one future Start request and reconstructs its exact Transport/Worker source contract without launching a Worker.
|
|
pub(crate) fn validate_route_start(&self, request: &crate::RawIngestRouteStartRequestDto) -> ksp_core_lib::Result<crate::RawIngestRouteStartValidationDto> {
|
|
let generation = self.inventory_generation.lock();
|
|
let generation = match generation {
|
|
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,
|
|
"Raw Transaction Ingest Desk route inventory generation lock is poisoned",
|
|
));
|
|
},
|
|
};
|
|
return crate::validate_route_start(&self.config_management, generation, request);
|
|
}
|
|
|
|
/// Starts one independent route Worker after repeating complete Start-time revalidation, sharing Store only on an exact network match.
|
|
pub(crate) async fn start_route(&self, request: &crate::RawIngestRouteStartRequestDto) -> ksp_core_lib::Result<crate::RouteRuntimeLaunch> {
|
|
let admission = self.route_runtime.ensure_start_admission_open();
|
|
if let std::result::Result::Err(error) = admission {
|
|
return std::result::Result::Err(error);
|
|
}
|
|
let prepared = {
|
|
let generation = self.inventory_generation.lock();
|
|
let generation = match generation {
|
|
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,
|
|
"Raw Transaction Ingest Desk route inventory generation lock is poisoned",
|
|
));
|
|
},
|
|
};
|
|
let prepared = crate::prepare_route_start(&self.config_management, *generation, request);
|
|
match prepared {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
}
|
|
};
|
|
return crate::start_route_runtime(std::sync::Arc::clone(&self.route_runtime), prepared).await;
|
|
}
|
|
|
|
/// Returns complete latest-value monitoring projections for active and recent terminal routes in the current same-network runtime session.
|
|
pub(crate) fn route_monitoring(&self) -> ksp_core_lib::Result<std::vec::Vec<crate::RawIngestRouteMonitoringDto>> {
|
|
return self.route_runtime.monitoring_statuses();
|
|
}
|
|
|
|
/// Requests cooperative Stop for one exact logical route and waits until its Worker cleanup is complete.
|
|
pub(crate) async fn stop_route(&self, request: &crate::RawIngestRouteStopRequestDto) -> ksp_core_lib::Result<crate::RawIngestRouteRuntimeDto> {
|
|
return self.route_runtime.stop_and_wait(request).await;
|
|
}
|
|
|
|
/// Closes route Start admission once and requests cooperative Stop for all routes during application shutdown.
|
|
pub(crate) fn begin_shutdown(&self) -> ksp_core_lib::Result<bool> {
|
|
return self.route_runtime.begin_shutdown();
|
|
}
|
|
|
|
/// Waits for bounded cleanup of all route Workers and the shared Store during application shutdown.
|
|
pub(crate) async fn shutdown_routes(&self) -> ksp_core_lib::Result<()> {
|
|
return self.route_runtime.shutdown_and_wait().await;
|
|
}
|
|
|
|
/// Builds the safe scaffold status exposed by the shell.
|
|
pub(crate) fn shell_status(&self) -> ksp_core_lib::Result<crate::ShellStatusDto> {
|
|
let document_count = self.config_management.engine().registry().descriptors().count();
|
|
let document_count = u32::try_from(document_count);
|
|
let document_count = match document_count {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(
|
|
crate::ERROR_CODE_APP_STATE_INVALID,
|
|
"Config registry contains too many descriptors for the Raw Transaction Ingest Desk runtime DTO",
|
|
)
|
|
.with_source(error),
|
|
);
|
|
},
|
|
};
|
|
let runtime = self.logging_runtime.lock();
|
|
let 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,
|
|
"Raw Transaction Ingest Desk Logging runtime state lock is poisoned",
|
|
));
|
|
},
|
|
};
|
|
let _keep_guard_alive = &runtime.guard;
|
|
return std::result::Result::Ok(crate::ShellStatusDto {
|
|
active_composite_profile: self.active_composite_profile.clone(),
|
|
active_logging_profile: runtime.active_profile_id.clone(),
|
|
application_version: env!("CARGO_PKG_VERSION").to_owned(),
|
|
config_document_count: document_count,
|
|
fallback_logging_active: runtime.fallback_active,
|
|
shell_phase: "pre.010-runtime-monitoring".to_owned(),
|
|
startup_diagnostic: runtime.startup_diagnostic.clone(),
|
|
});
|
|
}
|
|
|
|
/// Returns the resolved splash timings captured during application bootstrap.
|
|
#[must_use]
|
|
pub(crate) const fn splash_settings(&self) -> crate::SplashSettings {
|
|
return self.splash_settings;
|
|
}
|
|
|
|
/// Marks the one-shot splash lifecycle as started and reports whether this caller won the transition.
|
|
pub(crate) fn begin_splash_sequence(&self) -> bool {
|
|
return self
|
|
.splash_sequence_started
|
|
.compare_exchange(false, true, std::sync::atomic::Ordering::AcqRel, std::sync::atomic::Ordering::Acquire)
|
|
.is_ok();
|
|
}
|
|
}
|
|
|
|
struct LoggingRuntimeState {
|
|
guard: ksp_logging_lib::LoggingGuard,
|
|
active_profile_id: std::option::Option<String>,
|
|
fallback_active: bool,
|
|
startup_diagnostic: std::option::Option<crate::CommandErrorDto>,
|
|
}
|