Mountain/ApplicationState/Internal/Persistence/
MementoLoader.rs1use std::{collections::HashMap, fs, path::Path};
33
34use CommonLibrary::Error::CommonError::CommonError;
35use serde_json::Value;
36use log::{debug, error, warn};
37
38pub fn LoadInitialMementoFromDisk(StorageFilePath:&Path) -> HashMap<String, Value> {
55 if !StorageFilePath.exists() {
56 debug!("[MementoLoader] Memento file does not exist: {}", StorageFilePath.display());
57 return HashMap::new();
58 }
59
60 match fs::read_to_string(StorageFilePath) {
61 Ok(Content) => {
62 serde_json::from_str(&Content).unwrap_or_else(|Error| {
63 error!(
64 "[MementoLoader] Failed to parse JSON from '{}': {}. Attempting recovery.",
65 StorageFilePath.display(),
66 Error
67 );
68
69 attempt_memento_recovery(StorageFilePath, &Content);
71 HashMap::new()
72 })
73 },
74
75 Err(Error) => {
76 error!(
77 "[MementoLoader] Failed to read '{}': {}. Attempting recovery.",
78 StorageFilePath.display(),
79 Error
80 );
81
82 if let Some(parent) = StorageFilePath.parent() {
84 if !parent.exists() {
85 if let Err(dir_error) = fs::create_dir_all(parent) {
86 warn!(
87 "[MementoLoader] Failed to create directory '{}': {}",
88 parent.display(),
89 dir_error
90 );
91 }
92 }
93 }
94
95 HashMap::new()
96 },
97 }
98}
99
100pub fn LoadMementoWithRecovery(StorageFilePath:&Path) -> Result<HashMap<String, Value>, CommonError> {
111 if !StorageFilePath.exists() {
112 debug!("[MementoLoader] Memento file does not exist: {}", StorageFilePath.display());
113 return Ok(HashMap::new());
114 }
115
116 let content = fs::read_to_string(StorageFilePath).map_err(|e| {
117 CommonError::FileSystemIO {
118 Path:StorageFilePath.to_path_buf(),
119 Description:format!("Failed to read memento file: {}", e),
120 }
121 })?;
122
123 serde_json::from_str(&content).map_err(|e| {
124 create_corrupted_backup(StorageFilePath, &content);
126 CommonError::SerializationError {
127 Description:format!("Failed to parse memento JSON from '{}': {}", StorageFilePath.display(), e),
128 }
129 })
130}
131
132fn attempt_memento_recovery(file_path:&Path, corrupted_content:&str) {
138 let backup_path = file_path.with_extension("json.backup");
139
140 match fs::write(&backup_path, corrupted_content) {
141 Ok(()) => {
142 warn!(
143 "[MementoLoader] Created backup of corrupted memento at: {}",
144 backup_path.display()
145 );
146 },
147 Err(e) => {
148 error!(
149 "[MementoLoader] Failed to create backup of corrupted memento at '{}': {}",
150 backup_path.display(),
151 e
152 );
153 },
154 }
155}
156
157fn create_corrupted_backup(file_path:&Path, content:&str) {
163 let timestamp = chrono::Utc::now().format("%Y%m%d_%H%M%S");
164 let backup_path = file_path.with_extension(format!("json.corrupted.{}", timestamp));
165
166 if let Err(e) = fs::write(&backup_path, content) {
167 error!(
168 "[MementoLoader] Failed to create corrupted backup at '{}': {}",
169 backup_path.display(),
170 e
171 );
172 } else {
173 debug!("[MementoLoader] Created corrupted backup at: {}", backup_path.display());
174 }
175}