mod.rs (4885B)
1 pub mod backend; 2 pub mod runtime; 3 4 use crate::config::MycConfig; 5 use crate::error::MycError; 6 7 pub use backend::MycSignerBackend; 8 pub use runtime::{MycRuntime, MycRuntimePaths, MycSignerContext, MycStartupSnapshot}; 9 10 #[derive(Clone)] 11 pub struct MycApp { 12 runtime: MycRuntime, 13 } 14 15 impl MycApp { 16 pub fn bootstrap(config: MycConfig) -> Result<Self, MycError> { 17 Ok(Self { 18 runtime: MycRuntime::bootstrap(config)?, 19 }) 20 } 21 22 pub fn runtime(&self) -> &MycRuntime { 23 &self.runtime 24 } 25 26 pub fn snapshot(&self) -> MycStartupSnapshot { 27 self.runtime.snapshot() 28 } 29 30 pub async fn run(self) -> Result<(), MycError> { 31 self.runtime.run().await 32 } 33 34 pub async fn run_until<F>(self, shutdown: F) -> Result<(), MycError> 35 where 36 F: std::future::Future<Output = ()>, 37 { 38 self.runtime.run_until(shutdown).await 39 } 40 } 41 42 #[cfg(test)] 43 mod tests { 44 use std::path::PathBuf; 45 46 use radroots_identity::RadrootsIdentity; 47 48 use crate::config::{MycConfig, MycSignerStateBackend}; 49 50 use super::MycApp; 51 52 fn write_test_identity(path: &std::path::Path, secret_key: &str) { 53 let identity = 54 RadrootsIdentity::from_secret_key_str(secret_key).expect("identity from secret"); 55 crate::identity_files::store_encrypted_identity(path, &identity).expect("write identity"); 56 } 57 58 #[test] 59 fn app_bootstrap_preserves_runtime_snapshot() { 60 let temp = tempfile::tempdir().expect("tempdir"); 61 let mut config = MycConfig::default(); 62 config.paths.state_dir = PathBuf::from(temp.path()).join("state"); 63 config.paths.signer_identity_path = temp.path().join("identity.json"); 64 config.paths.user_identity_path = temp.path().join("user.json"); 65 write_test_identity( 66 &config.paths.signer_identity_path, 67 "1111111111111111111111111111111111111111111111111111111111111111", 68 ); 69 write_test_identity( 70 &config.paths.user_identity_path, 71 "2222222222222222222222222222222222222222222222222222222222222222", 72 ); 73 74 let app = MycApp::bootstrap(config).expect("bootstrap"); 75 let snapshot = app.snapshot(); 76 77 assert!(snapshot.state_dir.ends_with("state")); 78 assert!(snapshot.audit_dir.ends_with("audit")); 79 assert!( 80 snapshot 81 .signer_identity_path 82 .as_ref() 83 .expect("encrypted signer path") 84 .ends_with("identity.json") 85 ); 86 assert!( 87 snapshot 88 .user_identity_path 89 .as_ref() 90 .expect("encrypted user path") 91 .ends_with("user.json") 92 ); 93 assert_eq!( 94 snapshot.signer_identity_source.backend.as_str(), 95 "encrypted_file" 96 ); 97 assert_eq!( 98 snapshot.user_identity_source.backend.as_str(), 99 "encrypted_file" 100 ); 101 assert_eq!(snapshot.signer_state_backend.as_str(), "json_file"); 102 assert!(snapshot.signer_state_path.ends_with("signer-state.json")); 103 assert_eq!(snapshot.runtime_audit_backend.as_str(), "jsonl_file"); 104 assert!(snapshot.runtime_audit_path.ends_with("operations.jsonl")); 105 assert!(!snapshot.signer_identity_id.is_empty()); 106 assert!(!snapshot.signer_public_key_hex.is_empty()); 107 assert!(!snapshot.user_identity_id.is_empty()); 108 assert!(!snapshot.user_public_key_hex.is_empty()); 109 assert!(!snapshot.transport.enabled); 110 } 111 112 #[test] 113 fn app_bootstrap_uses_backend_aware_signer_state_path() { 114 let temp = tempfile::tempdir().expect("tempdir"); 115 let mut config = MycConfig::default(); 116 config.paths.state_dir = PathBuf::from(temp.path()).join("state"); 117 config.paths.signer_identity_path = temp.path().join("identity.json"); 118 config.paths.user_identity_path = temp.path().join("user.json"); 119 config.persistence.signer_state_backend = MycSignerStateBackend::Sqlite; 120 config.persistence.runtime_audit_backend = crate::config::MycRuntimeAuditBackend::Sqlite; 121 write_test_identity( 122 &config.paths.signer_identity_path, 123 "1111111111111111111111111111111111111111111111111111111111111111", 124 ); 125 write_test_identity( 126 &config.paths.user_identity_path, 127 "2222222222222222222222222222222222222222222222222222222222222222", 128 ); 129 130 let app = MycApp::bootstrap(config).expect("bootstrap"); 131 let snapshot = app.snapshot(); 132 133 assert_eq!(snapshot.signer_state_backend.as_str(), "sqlite"); 134 assert!(snapshot.signer_state_path.ends_with("signer-state.sqlite")); 135 assert_eq!(snapshot.runtime_audit_backend.as_str(), "sqlite"); 136 assert!(snapshot.runtime_audit_path.ends_with("operations.sqlite")); 137 } 138 }