leptos_sync_core/reliability/data_integrity/
checksum.rs1use super::super::IntegrityError;
4use serde::{Deserialize, Serialize};
5use sha2::{Digest, Sha256};
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10pub enum ChecksumAlgorithm {
11 Sha256,
13 Md5,
15 Crc32,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
21pub struct ChecksumConfig {
22 pub algorithm: ChecksumAlgorithm,
24 pub verify_on_read: bool,
26 pub compute_on_write: bool,
28}
29
30impl Default for ChecksumConfig {
31 fn default() -> Self {
32 Self {
33 algorithm: ChecksumAlgorithm::Sha256,
34 verify_on_read: true,
35 compute_on_write: true,
36 }
37 }
38}
39
40#[derive(Debug, Clone)]
42pub struct ChecksumVerifier {
43 config: ChecksumConfig,
45 checksum_cache: HashMap<String, String>,
47}
48
49impl ChecksumVerifier {
50 pub fn new() -> Self {
52 Self {
53 config: ChecksumConfig::default(),
54 checksum_cache: HashMap::new(),
55 }
56 }
57
58 pub fn with_config(config: ChecksumConfig) -> Self {
60 Self {
61 config,
62 checksum_cache: HashMap::new(),
63 }
64 }
65
66 pub fn compute_checksum(&mut self, data: &[u8], key: &str) -> Result<String, IntegrityError> {
68 let checksum = match self.config.algorithm {
69 ChecksumAlgorithm::Sha256 => {
70 let mut hasher = Sha256::new();
71 hasher.update(data);
72 format!("{:x}", hasher.finalize())
73 }
74 ChecksumAlgorithm::Md5 => {
75 "md5_placeholder".to_string()
77 }
78 ChecksumAlgorithm::Crc32 => {
79 "crc32_placeholder".to_string()
81 }
82 };
83
84 self.checksum_cache
86 .insert(key.to_string(), checksum.clone());
87
88 Ok(checksum)
89 }
90
91 pub fn verify_checksum(
93 &self,
94 data: &[u8],
95 expected_checksum: &str,
96 ) -> Result<bool, IntegrityError> {
97 let computed_checksum = match self.config.algorithm {
98 ChecksumAlgorithm::Sha256 => {
99 let mut hasher = Sha256::new();
100 hasher.update(data);
101 format!("{:x}", hasher.finalize())
102 }
103 ChecksumAlgorithm::Md5 => "md5_placeholder".to_string(),
104 ChecksumAlgorithm::Crc32 => "crc32_placeholder".to_string(),
105 };
106
107 Ok(computed_checksum == expected_checksum)
108 }
109
110 pub fn get_cached_checksum(&self, key: &str) -> Option<&String> {
112 self.checksum_cache.get(key)
113 }
114
115 pub fn clear_cache(&mut self) {
117 self.checksum_cache.clear();
118 }
119
120 pub fn config(&self) -> &ChecksumConfig {
122 &self.config
123 }
124}
125
126impl Default for ChecksumVerifier {
127 fn default() -> Self {
128 Self::new()
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn test_checksum_verifier_creation() {
138 let verifier = ChecksumVerifier::new();
139 assert_eq!(verifier.config().algorithm, ChecksumAlgorithm::Sha256);
140 assert!(verifier.config().verify_on_read);
141 assert!(verifier.config().compute_on_write);
142 }
143
144 #[test]
145 fn test_checksum_verifier_with_config() {
146 let config = ChecksumConfig {
147 algorithm: ChecksumAlgorithm::Md5,
148 verify_on_read: false,
149 compute_on_write: true,
150 };
151 let verifier = ChecksumVerifier::with_config(config.clone());
152 assert_eq!(verifier.config().algorithm, ChecksumAlgorithm::Md5);
153 assert!(!verifier.config().verify_on_read);
154 assert!(verifier.config().compute_on_write);
155 }
156
157 #[test]
158 fn test_compute_checksum() {
159 let mut verifier = ChecksumVerifier::new();
160 let data = b"test data";
161 let key = "test_key";
162
163 let checksum = verifier.compute_checksum(data, key).unwrap();
164 assert!(!checksum.is_empty());
165
166 assert!(verifier.get_cached_checksum(key).is_some());
168 }
169
170 #[test]
171 fn test_verify_checksum() {
172 let mut verifier = ChecksumVerifier::new();
173 let data = b"test data";
174 let key = "test_key";
175
176 let checksum = verifier.compute_checksum(data, key).unwrap();
177 let is_valid = verifier.verify_checksum(data, &checksum).unwrap();
178 assert!(is_valid);
179
180 let is_invalid = verifier.verify_checksum(data, "wrong_checksum").unwrap();
182 assert!(!is_invalid);
183 }
184
185 #[test]
186 fn test_clear_cache() {
187 let mut verifier = ChecksumVerifier::new();
188 let data = b"test data";
189 let key = "test_key";
190
191 verifier.compute_checksum(data, key).unwrap();
192 assert!(verifier.get_cached_checksum(key).is_some());
193
194 verifier.clear_cache();
195 assert!(verifier.get_cached_checksum(key).is_none());
196 }
197}