1use crate::error::Error;
2use crate::events::{GetCallback, InitCallback, PutCallback};
3use crate::mutant::data_structures::MasterIndexStorage;
4use crate::pad_manager::PadManager;
5use crate::storage::Storage;
6use autonomi::{Network, ScratchpadAddress, Wallet};
7use chrono::{DateTime, Utc};
8use log::{debug, error, info};
9use std::sync::Arc;
10use tokio::sync::Mutex;
11use tokio::task::JoinHandle;
12
13pub mod data_structures;
14pub mod remove_logic;
15pub mod store_logic;
16pub mod update_logic;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum NetworkChoice {
21 Devnet,
22 Mainnet,
23}
24
25#[derive(Debug, Clone)]
27pub struct MutAntConfig {
28 pub network: NetworkChoice,
29}
30
31impl Default for MutAntConfig {
32 fn default() -> Self {
33 Self {
34 network: NetworkChoice::Mainnet,
35 }
36 }
37}
38
39pub const MASTER_INDEX_KEY: &str = "__MUTANT_MASTER_INDEX__";
41pub const FREE_DIRECT_LIST_KEY: &str = "__mutant_free_direct_v1__";
42pub const FREE_CHUNK_LIST_KEY: &str = "__mutant_free_chunk_v1__";
43
44pub(crate) const PHYSICAL_SCRATCHPAD_SIZE: usize = 4 * 1024 * 1024; pub(crate) const DEFAULT_SCRATCHPAD_SIZE: usize = PHYSICAL_SCRATCHPAD_SIZE - 512; #[derive(Debug, Clone, PartialEq, Eq)]
52pub struct StorageStats {
53 pub scratchpad_size: usize,
55 pub total_pads: usize,
57 pub occupied_pads: usize,
59 pub free_pads: usize,
61 pub total_space_bytes: u64,
63 pub occupied_pad_space_bytes: u64,
65 pub free_pad_space_bytes: u64,
67 pub occupied_data_bytes: u64,
69 pub wasted_space_bytes: u64,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct KeyDetails {
76 pub key: String,
77 pub size: usize,
78 pub modified: DateTime<Utc>,
79}
80
81#[derive(Clone)]
83pub struct MutAnt {
84 pub(crate) storage: Arc<Storage>,
85 master_index_addr: ScratchpadAddress,
86 master_index_storage: Arc<Mutex<MasterIndexStorage>>,
87 pub(crate) pad_manager: PadManager,
88}
89
90impl MutAnt {
91 pub async fn init(private_key_hex: String) -> Result<(Self, Option<JoinHandle<()>>), Error> {
94 Self::init_with_progress(private_key_hex, MutAntConfig::default(), None).await
95 }
96
97 pub async fn init_with_progress(
99 private_key_hex: String,
100 config: MutAntConfig,
101 mut init_callback: Option<InitCallback>,
102 ) -> Result<(Self, Option<JoinHandle<()>>), Error> {
103 info!("Initializing MutAnt with config: {:?}...", config);
104
105 let use_local = match config.network {
106 NetworkChoice::Devnet => true,
107 NetworkChoice::Mainnet => false,
108 };
109
110 let network = match Network::new(use_local) {
111 Ok(n) => n,
112 Err(e) => {
113 error!("Failed to initialize Autonomi network: {}", e);
114 return Err(Error::NetworkInitError(format!(
115 "Failed to initialize Autonomi network: {}",
116 e
117 )));
118 }
119 };
120
121 info!("Autonomi network initialized.");
122
123 let wallet = match Wallet::new_from_private_key(network.clone(), &private_key_hex) {
124 Ok(w) => w,
125 Err(e) => {
126 error!("Failed to create wallet from private key: {}", e);
127 return Err(Error::WalletError(format!(
128 "Failed to create wallet from private key: {}",
129 e
130 )));
131 }
132 };
133
134 info!("Autonomi wallet created.");
135
136 {
137 info!("Initializing Storage layer...");
138
139 let (storage_instance, storage_init_handle, mis_mutex): (
140 Storage,
141 Option<JoinHandle<()>>,
142 Arc<Mutex<MasterIndexStorage>>,
143 ) = match crate::storage::new(
144 wallet,
145 private_key_hex.clone(),
146 config.network,
147 &mut init_callback,
148 )
149 .await
150 {
151 Ok(result) => result,
152 Err(e) => {
153 return Err(e);
154 }
155 };
156 let storage_arc = Arc::new(storage_instance);
157 info!("Storage layer initialized.");
158
159 info!("Initializing PadManager...");
160 let pad_manager = PadManager::new(storage_arc.clone(), mis_mutex.clone());
161 info!("PadManager initialized.");
162
163 let mis_addr_from_storage = storage_arc.get_master_index_info().0;
164
165 let mutant = Self {
166 storage: storage_arc,
167 pad_manager,
168 master_index_storage: mis_mutex,
169 master_index_addr: mis_addr_from_storage,
170 };
171
172 info!("MutAnt initialization complete.");
173 Ok((mutant, storage_init_handle))
174 }
175 }
176
177 pub async fn store(&self, user_key: &str, data_bytes: &[u8]) -> Result<(), Error> {
180 self.store_with_progress(user_key, data_bytes, None).await
181 }
182
183 pub async fn store_with_progress(
185 &self,
186 user_key: &str,
187 data_bytes: &[u8],
188 callback: Option<PutCallback>,
189 ) -> Result<(), Error> {
190 if user_key == MASTER_INDEX_KEY {
191 return Err(Error::InvalidInput(
192 "User key conflicts with internal master index key".to_string(),
193 ));
194 }
195 store_logic::store_item(self, user_key, data_bytes, callback).await
196 }
197
198 pub async fn fetch(&self, key: &str) -> Result<Vec<u8>, Error> {
201 self.fetch_with_progress(key, None).await
202 }
203
204 pub async fn fetch_with_progress(
206 &self,
207 key: &str,
208 mut callback: Option<GetCallback>,
209 ) -> Result<Vec<u8>, Error> {
210 info!("MutAnt: fetch called for key '{}'", key);
211 self.pad_manager.retrieve_data(key, &mut callback).await
212 }
213
214 pub async fn remove(&self, user_key: &str) -> Result<(), Error> {
216 debug!("MutAnt::remove: Entered for key '{}'", user_key);
217 if user_key == MASTER_INDEX_KEY {
218 error!("Attempted to remove the master index key directly. Ignoring.");
219 return Ok(());
220 }
221 debug!(
222 "MutAnt::remove: Calling remove_logic::delete_item for key '{}'",
223 user_key
224 );
225 let result = remove_logic::delete_item(self, user_key).await;
226 debug!(
227 "MutAnt::remove: Returned from remove_logic::delete_item for key '{}'",
228 user_key
229 );
230 result
231 }
232
233 pub async fn update(&self, user_key: &str, data_bytes: &[u8]) -> Result<(), Error> {
238 self.update_with_progress(user_key, data_bytes, None).await
239 }
240
241 pub async fn update_with_progress(
245 &self,
246 user_key: &str,
247 data_bytes: &[u8],
248 callback: Option<PutCallback>,
249 ) -> Result<(), Error> {
250 debug!("MutAnt::update: Entered for key '{}'", user_key);
251 if user_key == MASTER_INDEX_KEY {
252 error!("Attempted to update the master index key directly. Denying access.");
253 return Err(Error::OperationNotSupported);
254 }
255 let result = update_logic::update_item(self, user_key, data_bytes, callback).await;
256 debug!(
257 "MutAnt::update: Returned from update_logic::update_item for key '{}'",
258 user_key
259 );
260 result
261 }
262
263 pub async fn get_user_keys(&self) -> Vec<String> {
265 let mis_guard = self.master_index_storage.lock().await;
266 let all_user_keys: Vec<String> = mis_guard
267 .index
268 .keys()
269 .filter(|k| *k != MASTER_INDEX_KEY)
270 .cloned()
271 .collect();
272 drop(mis_guard);
273 all_user_keys
274 }
275
276 pub async fn get_storage_stats(&self) -> Result<StorageStats, Error> {
278 debug!("Getting storage stats...");
279 let mis_guard = self.master_index_storage.lock().await;
280 debug!("Master index lock acquired for stats.");
281
282 let scratchpad_size = mis_guard.scratchpad_size;
283 if scratchpad_size == 0 {
284 error!("Cannot calculate stats: Scratchpad size is zero.");
285 return Err(Error::InternalError(
286 "Cannot calculate stats with zero scratchpad size".to_string(),
287 ));
288 }
289
290 let free_pads_count = mis_guard.free_pads.len();
291 let mut occupied_pads_count = 0;
292 let mut occupied_data_size_total: u64 = 0;
293
294 for key_info in mis_guard.index.values() {
295 occupied_pads_count += key_info.pads.len();
296 occupied_data_size_total += key_info.data_size as u64;
297 }
298
299 let total_pads_count = occupied_pads_count + free_pads_count;
300
301 let scratchpad_size_u64 = scratchpad_size as u64;
302 let occupied_pad_space_bytes = occupied_pads_count as u64 * scratchpad_size_u64;
303 let free_pad_space_bytes = free_pads_count as u64 * scratchpad_size_u64;
304 let total_space_bytes = total_pads_count as u64 * scratchpad_size_u64;
305
306 let wasted_space_bytes = occupied_pad_space_bytes.saturating_sub(occupied_data_size_total);
307
308 debug!(
309 "Stats calculated: total_pads={}, occupied_pads={}, free_pads={}, total_space={}, data_size={}",
310 total_pads_count, occupied_pads_count, free_pads_count, total_space_bytes, occupied_data_size_total
311 );
312 debug!("Master index lock released after stats.");
313
314 Ok(StorageStats {
315 scratchpad_size,
316 total_pads: total_pads_count,
317 occupied_pads: occupied_pads_count,
318 free_pads: free_pads_count,
319 total_space_bytes,
320 occupied_pad_space_bytes,
321 free_pad_space_bytes,
322 occupied_data_bytes: occupied_data_size_total,
323 wasted_space_bytes,
324 })
325 }
326
327 async fn save_master_index(&self) -> Result<(), Error> {
328 crate::storage::storage_save_mis_from_arc_static(
329 &self.storage.client(),
330 &self.master_index_addr,
331 &self.storage.get_master_index_info().1,
332 &self.master_index_storage,
333 )
334 .await
335 }
336
337 pub async fn reset_master_index(&self) -> Result<(), Error> {
340 info!("Resetting master index requested.");
341
342 let mut mis_guard = self.master_index_storage.lock().await;
344 info!("Acquired lock on master index storage.");
345
346 *mis_guard = MasterIndexStorage {
348 scratchpad_size: DEFAULT_SCRATCHPAD_SIZE,
349 ..Default::default() };
351 info!(
352 "In-memory master index reset. Size set to: {}",
353 DEFAULT_SCRATCHPAD_SIZE
354 );
355
356 drop(mis_guard);
358 info!("Released lock on master index storage.");
359
360 info!("Attempting to save the reset master index...");
362 match self.save_master_index().await {
363 Ok(_) => {
364 info!("Successfully saved the reset master index.");
365 Ok(())
366 }
367 Err(e) => {
368 error!("Failed to save the reset master index: {}", e);
369 Err(e)
370 }
371 }
372 }
373
374 pub async fn list_keys(&self) -> Result<Vec<String>, Error> {
376 debug!("MutAnt: list_keys called");
377 let guard = self.master_index_storage.lock().await;
378 let keys = guard.index.keys().cloned().collect();
379 Ok(keys)
380 }
381
382 pub async fn list_key_details(&self) -> Result<Vec<KeyDetails>, Error> {
384 debug!("MutAnt: list_key_details called");
385 let guard = self.master_index_storage.lock().await;
386 let details: Vec<KeyDetails> = guard
387 .index
388 .iter()
389 .map(|(key, info)| KeyDetails {
390 key: key.clone(),
391 size: info.data_size,
392 modified: info.modified,
393 })
394 .collect();
395 Ok(details)
396 }
397}