// file: crates/ksp-logging-lib/src/identity.rs // version: 2 //! Stable runtime identity used to separate persistent file outputs between application launches. /// Identity attached to one installed KSP Logging runtime for the lifetime of an application launch. #[derive(Clone, Debug, Eq, PartialEq)] pub struct LoggingRuntimeIdentity { application_id: std::string::String, launch_timestamp: std::string::String, } impl LoggingRuntimeIdentity { /// Creates a validated runtime identity from an application identifier and launch timestamp token. pub fn new( application_id: impl std::convert::Into, launch_timestamp: impl std::convert::Into, ) -> ksp_core_lib::Result { let application_id = application_id.into(); let launch_timestamp = launch_timestamp.into(); let application_validation = validate_identity_component(application_id.as_str(), "application_id"); if let std::result::Result::Err(error) = application_validation { return std::result::Result::Err(error); } let timestamp_validation = validate_identity_component(launch_timestamp.as_str(), "launch_timestamp"); if let std::result::Result::Err(error) = timestamp_validation { return std::result::Result::Err(error); } return std::result::Result::Ok(Self { application_id, launch_timestamp }); } /// Returns the application identifier embedded in persistent runtime file names. #[must_use] pub fn application_id(&self) -> &str { return self.application_id.as_str(); } /// Returns the stable launch timestamp token embedded in persistent runtime file names. #[must_use] pub fn launch_timestamp(&self) -> &str { return self.launch_timestamp.as_str(); } /// Executes the crate-internal file name prefix operation for `LoggingRuntimeIdentity`. pub(crate) fn file_name_prefix(&self, configured_prefix: &str) -> std::string::String { return format!("{}.{}.{}", self.application_id, self.launch_timestamp, configured_prefix); } } fn validate_identity_component(value: &str, field: &'static str) -> ksp_core_lib::Result<()> { if value.is_empty() || value.len() > 160 { return invalid_identity(field); } for byte in value.bytes() { let accepted = byte.is_ascii_alphanumeric() || matches!(byte, b'.' | b'_' | b'-'); if !accepted { return invalid_identity(field); } } return std::result::Result::Ok(()); } fn invalid_identity(field: &'static str) -> ksp_core_lib::Result<()> { return std::result::Result::Err( ksp_core_lib::Error::new(crate::ERROR_CODE_INVALID_RUNTIME_IDENTITY, "KSP Logging runtime identity contains an invalid component") .with_context("field", field), ); } #[cfg(test)] #[path = "../unit_tests/identity.rs"] mod tests;