172 lines
7.0 KiB
Rust
172 lines
7.0 KiB
Rust
// file: crates/ksp-app-config-desk/src/splash.rs
|
|
// version: 3
|
|
|
|
//! Common splash settings and frontend event contracts for Config Desk.
|
|
|
|
use ts_rs::TS; // rust-rules: derive-import
|
|
|
|
const ENV_SPLASH_MINIMUM_MS: &str = "KSP_DESK_SPLASH_MINIMUM_MS";
|
|
const ENV_SPLASH_FADE_MS: &str = "KSP_DESK_SPLASH_FADE_MS";
|
|
const DEFAULT_SPLASH_MINIMUM_MS: u64 = 1200;
|
|
const DEFAULT_SPLASH_FADE_MS: u32 = 300;
|
|
const MAX_SPLASH_MINIMUM_MS: u64 = 60_000;
|
|
const MAX_SPLASH_FADE_MS: u32 = 10_000;
|
|
|
|
/// Runtime timings used by the common desk splash lifecycle.
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
pub(crate) struct SplashSettings {
|
|
minimum_ms: u64,
|
|
fade_ms: u32,
|
|
minimum_source: ksp_config_lib::ConfigEnvironmentSource,
|
|
fade_source: ksp_config_lib::ConfigEnvironmentSource,
|
|
}
|
|
|
|
impl SplashSettings {
|
|
/// Resolves splash timings through the Config-owned environment snapshot.
|
|
pub(crate) fn load() -> ksp_core_lib::Result<Self> {
|
|
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 minimum = environment.resolve_variable(ENV_SPLASH_MINIMUM_MS, std::option::Option::Some("1200"));
|
|
let minimum = match minimum {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let fade = environment.resolve_variable(ENV_SPLASH_FADE_MS, std::option::Option::Some("300"));
|
|
let fade = match fade {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let minimum_ms = parse_u64_setting(ENV_SPLASH_MINIMUM_MS, minimum.value(), MAX_SPLASH_MINIMUM_MS);
|
|
let minimum_ms = match minimum_ms {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
let fade_ms = parse_u32_setting(ENV_SPLASH_FADE_MS, fade.value(), MAX_SPLASH_FADE_MS);
|
|
let fade_ms = match fade_ms {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
|
};
|
|
return std::result::Result::Ok(Self { minimum_ms, fade_ms, minimum_source: minimum.source(), fade_source: fade.source() });
|
|
}
|
|
|
|
/// Returns safe in-memory timings used when the managed environment cannot be resolved.
|
|
#[must_use]
|
|
pub(crate) const fn fallback() -> Self {
|
|
return Self {
|
|
minimum_ms: DEFAULT_SPLASH_MINIMUM_MS,
|
|
fade_ms: DEFAULT_SPLASH_FADE_MS,
|
|
minimum_source: ksp_config_lib::ConfigEnvironmentSource::Fallback,
|
|
fade_source: ksp_config_lib::ConfigEnvironmentSource::Fallback,
|
|
};
|
|
}
|
|
|
|
/// Returns the minimum visible duration after splash frontend readiness.
|
|
#[must_use]
|
|
pub(crate) const fn minimum_ms(self) -> u64 {
|
|
return self.minimum_ms;
|
|
}
|
|
|
|
/// Returns the fade duration used for both fade-in and fade-out.
|
|
#[must_use]
|
|
pub(crate) const fn fade_ms(self) -> u32 {
|
|
return self.fade_ms;
|
|
}
|
|
|
|
/// Returns the safe provenance code for the minimum duration.
|
|
#[must_use]
|
|
pub(crate) const fn minimum_source(self) -> &'static str {
|
|
return environment_source_code(self.minimum_source);
|
|
}
|
|
|
|
/// Returns the safe provenance code for the fade duration.
|
|
#[must_use]
|
|
pub(crate) const fn fade_source(self) -> &'static str {
|
|
return environment_source_code(self.fade_source);
|
|
}
|
|
|
|
/// Returns the minimum backend lifecycle duration from readiness until main activation.
|
|
#[must_use]
|
|
pub(crate) fn expected_backend_lifecycle_ms(self) -> u64 {
|
|
return self.minimum_ms + u64::from(self.fade_ms);
|
|
}
|
|
}
|
|
|
|
const fn environment_source_code(source: ksp_config_lib::ConfigEnvironmentSource) -> &'static str {
|
|
return match source {
|
|
ksp_config_lib::ConfigEnvironmentSource::Process => "process",
|
|
ksp_config_lib::ConfigEnvironmentSource::DotEnv => "dotenv",
|
|
ksp_config_lib::ConfigEnvironmentSource::Fallback => "fallback",
|
|
};
|
|
}
|
|
|
|
/// Command emitted by Rust to the splash frontend.
|
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_config_desk/splash/SplashOrderDto.ts")]
|
|
pub(crate) struct SplashOrderDto {
|
|
/// Splash action name.
|
|
pub(crate) action: String,
|
|
/// Optional status text.
|
|
pub(crate) message: std::option::Option<String>,
|
|
/// Optional animation duration in milliseconds.
|
|
pub(crate) duration_ms: std::option::Option<u32>,
|
|
}
|
|
|
|
impl SplashOrderDto {
|
|
#[must_use]
|
|
pub(crate) fn new(action: &str, message: std::option::Option<&str>, duration_ms: std::option::Option<u32>) -> Self {
|
|
return Self { action: action.to_owned(), message: message.map(std::string::ToString::to_string), duration_ms };
|
|
}
|
|
}
|
|
|
|
fn parse_u64_setting(variable_name: &str, value: &str, maximum: u64) -> ksp_core_lib::Result<u64> {
|
|
let parsed = value.parse::<u64>();
|
|
let parsed = match parsed {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_SPLASH_SETTING_INVALID, "KSP desk splash duration is not a valid unsigned integer")
|
|
.with_context("variable_name", variable_name)
|
|
.with_source(error),
|
|
);
|
|
},
|
|
};
|
|
if parsed > maximum {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_SPLASH_SETTING_INVALID, "KSP desk splash duration exceeds the allowed bound")
|
|
.with_context("variable_name", variable_name)
|
|
.with_context("maximum_ms", maximum.to_string()),
|
|
);
|
|
}
|
|
return std::result::Result::Ok(parsed);
|
|
}
|
|
|
|
fn parse_u32_setting(variable_name: &str, value: &str, maximum: u32) -> ksp_core_lib::Result<u32> {
|
|
let parsed = value.parse::<u32>();
|
|
let parsed = match parsed {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(error) => {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_SPLASH_SETTING_INVALID, "KSP desk splash duration is not a valid unsigned integer")
|
|
.with_context("variable_name", variable_name)
|
|
.with_source(error),
|
|
);
|
|
},
|
|
};
|
|
if parsed > maximum {
|
|
return std::result::Result::Err(
|
|
ksp_core_lib::Error::new(crate::ERROR_CODE_SPLASH_SETTING_INVALID, "KSP desk splash duration exceeds the allowed bound")
|
|
.with_context("variable_name", variable_name)
|
|
.with_context("maximum_ms", maximum.to_string()),
|
|
);
|
|
}
|
|
return std::result::Result::Ok(parsed);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "../unit_tests/splash.rs"]
|
|
mod tests;
|