1pub mod log_entry;
11pub mod chain;
12pub mod merkle_service;
13pub mod publication;
14pub mod error;
15
16use serde::{Deserialize, Serialize};
17use std::sync::Arc;
18use tokio::sync::RwLock;
19
20pub struct ImmutableLog {
22 chain: Arc<RwLock<chain::LogChain>>,
23 merkle: Arc<RwLock<merkle_service::MerkleService>>,
24}
25
26impl ImmutableLog {
27 pub fn new() -> Self {
29 ImmutableLog {
30 chain: Arc::new(RwLock::new(chain::LogChain::new())),
31 merkle: Arc::new(RwLock::new(merkle_service::MerkleService::new())),
32 }
33 }
34
35 pub async fn append(&self, entry: log_entry::LogEntry) -> Result<log_entry::LogEntry, error::LogError> {
37 let mut chain = self.chain.write().await;
39 let entry = chain.append(entry).await?;
40
41 let mut merkle = self.merkle.write().await;
43 merkle.add_entry(entry.clone()).await;
44
45 Ok(entry)
46 }
47
48 pub async fn verify(&self) -> Result<bool, error::LogError> {
50 let chain = self.chain.read().await;
51 Ok(chain.verify())
52 }
53
54 pub async fn get_hourly_root(&self) -> Option<merkle_service::HourlyRoot> {
56 let merkle = self.merkle.read().await;
57 merkle.get_current_root()
58 }
59
60 pub async fn get_chain_proof(&self, entry_id: &str) -> Option<chain::ChainProof> {
62 let chain = self.chain.read().await;
63 chain.generate_proof(entry_id)
64 }
65}
66
67impl Default for ImmutableLog {
68 fn default() -> Self {
69 Self::new()
70 }
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct LogConfig {
76 pub hash_algorithm: String,
78 pub hourly_publication: bool,
80 pub daily_publication: bool,
82 pub tsa_url: Option<String>,
84 pub blockchain_enabled: bool,
86}
87
88impl Default for LogConfig {
89 fn default() -> Self {
90 LogConfig {
91 hash_algorithm: "SHA256".to_string(),
92 hourly_publication: true,
93 daily_publication: true,
94 tsa_url: None,
95 blockchain_enabled: true,
96 }
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn test_default_config() {
106 let config = LogConfig::default();
107 assert_eq!(config.hash_algorithm, "SHA256");
108 assert!(config.hourly_publication);
109 }
110
111 #[tokio::test]
112 async fn test_append_entry() {
113 let log = ImmutableLog::new();
114
115 let entry = log_entry::LogEntry::new(
116 log_entry::EventType::AccountQuery,
117 "agent-001".to_string(),
118 "org-001".to_string(),
119 );
120
121 let result = log.append(entry).await;
122 assert!(result.is_ok());
123 }
124}