mutant_lib/mutant/
mod.rs

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// --- Network Configuration ---
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum NetworkChoice {
21    Devnet,
22    Mainnet,
23}
24
25// --- MutAnt Configuration ---
26#[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
39// --- Internal Keys for Management Data ---
40pub 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
44/// Actual physical size of scratchpads on the network.
45pub(crate) const PHYSICAL_SCRATCHPAD_SIZE: usize = 4 * 1024 * 1024; // 4MB
46/// Usable size within a scratchpad, leaving margin for network overhead/encryption.
47/// NOTE: This should be the value persisted in MasterIndexStorage.scratchpad_size
48pub(crate) const DEFAULT_SCRATCHPAD_SIZE: usize = PHYSICAL_SCRATCHPAD_SIZE - 512; // 4MB minus 512 bytes margin
49
50/// Holds calculated storage statistics.
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub struct StorageStats {
53    /// The configured size of each individual scratchpad in bytes.
54    pub scratchpad_size: usize,
55    /// The total number of scratchpads managed (occupied + free).
56    pub total_pads: usize,
57    /// The number of scratchpads currently holding data.
58    pub occupied_pads: usize,
59    /// The number of scratchpads available for reuse.
60    pub free_pads: usize,
61    /// The total storage capacity across all managed scratchpads (total_pads * scratchpad_size).
62    pub total_space_bytes: u64,
63    /// The storage capacity currently used by occupied scratchpads (occupied_pads * scratchpad_size).
64    pub occupied_pad_space_bytes: u64,
65    /// The storage capacity currently available in free scratchpads (free_pads * scratchpad_size).
66    pub free_pad_space_bytes: u64,
67    /// The actual total size of the data stored across all occupied scratchpads.
68    pub occupied_data_bytes: u64,
69    /// The difference between the space allocated by occupied pads and the actual data stored (internal fragmentation).
70    pub wasted_space_bytes: u64,
71}
72
73/// Public struct to hold details for the `ls -l` command.
74#[derive(Debug, Clone, PartialEq, Eq)]
75pub struct KeyDetails {
76    pub key: String,
77    pub size: usize,
78    pub modified: DateTime<Utc>,
79}
80
81/// Manages raw byte data storage using the PadManager.
82#[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    /// Creates a new MutAnt instance using default configuration.
92    /// Use `init_with_progress` for detailed initialization feedback and custom config.
93    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    /// Creates a new MutAnt instance with optional progress reporting via callback and custom config.
98    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    /// Stores raw bytes under a given user key without progress reporting.
178    /// Use `store_with_progress` for detailed feedback.
179    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    /// Stores raw bytes under a given user key with optional progress reporting via callback.
184    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    /// Fetches the raw bytes associated with the given user key without progress reporting.
199    /// Use `fetch_with_progress` for detailed feedback.
200    pub async fn fetch(&self, key: &str) -> Result<Vec<u8>, Error> {
201        self.fetch_with_progress(key, None).await
202    }
203
204    /// Fetches the raw bytes associated with the given user key, with optional progress reporting.
205    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    /// Removes a user key and its associated data/metadata.
215    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    /// Updates the raw bytes associated with an existing user key without progress reporting.
234    /// Use `update_with_progress` for detailed feedback.
235    ///
236    /// Returns `Error::KeyNotFound` if the key does not exist.
237    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    /// Updates the raw bytes associated with an existing user key, with optional progress reporting.
242    ///
243    /// Returns `Error::KeyNotFound` if the key does not exist.
244    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    /// Retrieves a list of all user keys.
264    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    /// Retrieves detailed statistics about the storage usage.
277    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    /// Resets the master index to its initial empty state.
338    /// WARNING: This is a destructive operation and will orphan existing data pads.
339    pub async fn reset_master_index(&self) -> Result<(), Error> {
340        info!("Resetting master index requested.");
341
342        // 1. Lock the master index storage
343        let mut mis_guard = self.master_index_storage.lock().await;
344        info!("Acquired lock on master index storage.");
345
346        // 2. Reset the in-memory state to default, but set the correct scratchpad size
347        *mis_guard = MasterIndexStorage {
348            scratchpad_size: DEFAULT_SCRATCHPAD_SIZE,
349            ..Default::default() // Use default for all other fields
350        };
351        info!(
352            "In-memory master index reset. Size set to: {}",
353            DEFAULT_SCRATCHPAD_SIZE
354        );
355
356        // 3. Drop the guard before saving to avoid deadlock in save_master_index
357        drop(mis_guard);
358        info!("Released lock on master index storage.");
359
360        // 4. Persist the empty/default master index
361        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    /// Lists all user keys currently tracked in the master index.
375    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    /// Retrieves a list of keys along with their size and modification time.
383    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}