recs/
lib.rs

1#[path = "system/array.rs"]
2mod array;
3#[path = "system/array_retrive.rs"]
4mod array_tools;
5#[path = "auth.rs"]
6mod auth;
7#[path = "system/config.rs"]
8mod config;
9#[path = "system/encrypt.rs"]
10mod encrypt;
11// pub mod errors;
12#[path = "enviornment.rs"]
13mod local_env;
14#[path = "system/secrets.rs"]
15mod secret;
16use dusa_collection_utils::log;
17use dusa_collection_utils::core::logger::LogLevel;
18use dusa_collection_utils::core::types::pathtype::PathType;
19use dusa_collection_utils::core::types::stringy::Stringy;
20use dusa_collection_utils::{
21    core::errors::{ErrorArrayItem, OkWarning, UnifiedResult as uf},
22    platform::functions::{create_hash, path_present},
23};
24use local_env::{clean_temps, VERSION};
25use secret::{read_raw, write_raw};
26
27use std::{
28    fs::{File, OpenOptions},
29    io::{Read, Write},
30};
31
32use crate::{
33    array::{index_system_array, ChunkMap},
34    array_tools::fetch_chunk,
35    config::{ARRAY_LEN, CHUNK_SIZE},
36    local_env::{set_system, SystemPaths},
37    secret::{forget, read, write},
38};
39
40/// Debugging should be set while initializing the lib. If not defined, the default is disabled.
41pub static mut DEBUGGING: Option<bool> = None;
42
43/// This value is set by set_prog. It is used for logging, creating paths, and other functions.
44/// To handle its creation or modification, use set_prog() to avoid wrapping.
45pub static mut PROGNAME: &str = "";
46
47/// Changes some mandatory logging functions and enables longer outputs in logs
48///
49/// # Arguments
50///
51/// * `option` - A boolean value to enable or disable debugging.
52pub fn set_debug(option: bool) {
53    // Enables longer backtraces and enables more verbose logging
54    match option {
55        true => unsafe { DEBUGGING = Some(true) },
56        false => unsafe { DEBUGGING = Some(false) },
57    }
58}
59
60/// This function handles setting the PROGNAME variable.
61///
62/// # Arguments
63///
64/// * `data` - A static string slice representing the program name.
65pub fn set_prog(data: &'static str) {
66    unsafe { PROGNAME = data };
67}
68
69/// Initialize checks the progname and debugging values and ensures the lib is ready to function
70///
71/// # Arguments
72///
73/// * `errors` - An ErrorArray to capture errors.
74/// * `warnings` - A WarningArray to capture warnings.
75///
76/// # Returns
77///
78/// * `uf<()>` - A unified result indicating success or failure.
79pub async fn initialize(temporary_path: bool) -> uf<()> {
80    let debugging: bool = match unsafe { DEBUGGING } {
81        Some(d) => match d {
82            true => true,
83            false => false,
84        },
85        None => false,
86    };
87
88    let debug: bool = match &debugging {
89        true => {
90            use std::env;
91            env::set_var("RUST_BACKTRACE", "1");
92            true
93        }
94        false => false,
95    };
96
97    log!(LogLevel::Trace, "RECS started");
98
99    SystemPaths::set_current(temporary_path).await;
100
101    if let Err(e) = ensure_system_path(debug).await.uf_unwrap() {
102        return uf::new(Err(e));
103    }
104
105    if let Err(e) = ensure_max_map_exists().await.uf_unwrap() {
106        return uf::new(Err(e));
107    }
108
109    uf::new(Ok(()))
110}
111
112/// Ensures that the system path exists, if not reinitializes it.
113///
114/// # Arguments
115///
116/// * `debug` - A boolean indicating if debugging is enabled.
117/// * `errors` - An ErrorArray to capture errors.
118/// * `warnings` - A WarningArray to capture warnings.
119///
120/// # Returns
121///
122/// * `uf<()>` - A unified result indicating success or failure.
123async fn ensure_system_path(debug: bool) -> uf<()> {
124    let system_paths = SystemPaths::read_current().await;
125
126    match path_present(&system_paths.SYSTEM_ARRAY_LOCATION).uf_unwrap() {
127        Ok(true) => (),
128        Ok(false) => {
129            log!(
130                LogLevel::Trace,
131                "System array file does not exist, reinitialize recs"
132            );
133            if let Err(e) = set_system(debug).await.uf_unwrap() {
134                return uf::new(Err(e));
135            }
136        }
137        Err(e) => return uf::new(Err(e)),
138    }
139
140    uf::new(Ok(()))
141}
142
143/// Ensures that the maximum map exists, if not indexes the system array.
144///
145/// # Arguments
146///
147/// * `errors` - An ErrorArray to capture errors.
148/// * `warnings` - A WarningArray to capture warnings.
149///
150/// # Returns
151///
152/// * `uf<()>` - A unified result indicating success or failure.
153async fn ensure_max_map_exists() -> uf<()> {
154    let system_paths = SystemPaths::read_current().await;
155    let max_map = ARRAY_LEN / CHUNK_SIZE;
156    let max_map_path = PathType::Content(format!("{}/{}.map", system_paths.MAPS, max_map - 1));
157
158    match path_present(&max_map_path).uf_unwrap() {
159        Ok(true) => uf::new(Ok(())),
160        Ok(false) => match index_system_array().await.uf_unwrap() {
161            Ok(_d) => uf::new(Ok(())),
162            Err(e) => return uf::new(Err(e)),
163        },
164        Err(e) => uf::new(Err(e)),
165    }
166}
167
168/// Inserts a file by encrypting and storing it.
169///
170/// # Arguments
171///
172/// * `filename` - The relative path of the file to be stored.
173/// * `owner` - The owner of the file.
174/// * `name` - The name of the file.
175/// * `errors` - An ErrorArray to capture errors.
176/// * `warnings` - A WarningArray to capture warnings.
177///
178/// # Returns
179///
180/// * `uf<()>` - A unified result indicating success or failure.
181pub async fn store(filename: PathType, owner: String, name: String) -> uf<()> {
182    match write(filename, owner, name, false).await.uf_unwrap() {
183        Ok(d) => {
184            log!(LogLevel::Info, "Stored: value:{}, count: {} ", d.0, d.1);
185            return uf::new(Ok(()));
186        }
187        Err(e) => return uf::new(Err(e)),
188    }
189}
190
191/// Retrieves a file by decrypting it.
192///
193/// # Arguments
194///
195/// * `owner` - The owner of the file.
196/// * `name` - The name of the file.
197/// * `uid` - The unique identifier for the file.
198/// * `errors` - An ErrorArray to capture errors.
199/// * `warnings` - A WarningArray to capture warnings.
200///
201/// # Returns
202///
203/// * `uf<OkWarning<(PathType, PathType)>>` - A unified result containing the decrypted file paths or an error.
204pub async fn retrieve(
205    owner: String,
206    name: String,
207    uid: u32,
208) -> uf<OkWarning<(PathType, PathType)>> {
209    read(owner, name, uid, false).await
210}
211
212/// Removes a file.
213///
214/// # Arguments
215///
216/// * `owner` - The owner of the file.
217/// * `name` - The name of the file.
218/// * `errors` - An ErrorArray to capture errors.
219/// * `warnings` - A WarningArray to capture warnings.
220///
221/// # Returns
222///
223/// * `uf<()>` - A unified result indicating success or failure.
224pub async fn remove(owner: String, name: String) -> uf<()> {
225    match forget(owner, name).await {
226        Ok(_) => uf::new(Ok(())),
227        Err(err) => uf::new(Err(err)),
228    }
229}
230
231/// Checks if a file exists.
232///
233/// # Arguments
234///
235/// * `owner` - The owner of the file.
236/// * `name` - The name of the file.
237/// * `errors` - An ErrorArray to capture errors.
238///
239/// # Returns
240///
241/// * `uf<bool>` - A unified result indicating if the file exists or not.
242pub async fn ping(owner: String, name: String) -> uf<bool> {
243    let system_paths: SystemPaths = SystemPaths::read_current().await;
244    let secret_map_path = PathType::Content(format!(
245        "{}/{owner}-{name}.meta",
246        system_paths.META,
247        owner = owner,
248        name = name
249    ));
250    path_present(&secret_map_path)
251}
252
253/// Encrypts raw data.
254///
255/// # Arguments
256///
257/// * `data` - The data to be encrypted.
258/// * `errors` - An ErrorArray to capture errors.
259/// * `warnings` - A WarningArray to capture warnings.
260///
261/// # Returns
262///
263/// * `uf<(String, String, usize)>` - A unified result containing the encrypted data, key, and chunk size.
264pub async fn encrypt_raw(data: String) -> uf<(String, String, usize)> {
265    write_raw(data.into()).await
266}
267
268/// Decrypts raw data.
269///
270/// # Arguments
271///
272/// * `recs_data` - The encrypted data.
273/// * `recs_key` - The key for decryption.
274/// * `recs_chunks` - The number of chunks.
275/// * `errors` - An ErrorArray to capture errors.
276/// * `warnings` - A WarningArray to capture warnings.
277///
278/// # Returns
279///
280/// * `uf<OkWarning<Vec<u8>>>` - A unified result containing the decrypted data or an error.
281pub fn decrypt_raw(recs_data: String, recs_key: String, recs_chunks: usize) -> uf<Vec<u8>> {
282    read_raw(recs_data, recs_key, recs_chunks)
283}
284
285/// Performs house keeping tasks
286/// cleans the .rand files from raw encrypt requests
287/// re-indexs the system array to ensure valid versions
288/// and signatures.
289/// * Will eventually run tests to ensure chunck count
290/// * logic functions as intended periodically as well
291pub async fn house_keeping() -> Result<(), ErrorArrayItem> {
292    let handle: tokio::task::JoinHandle<Result<(), ErrorArrayItem>> = tokio::spawn(async {
293        clean_temps().await?;
294        ensure_max_map_exists().await.uf_unwrap()?;
295        Ok(())
296    });
297
298    match handle.await {
299        Ok(result) => {
300            match result {
301                Ok(_) => Ok(()),
302                Err(err) => Err(err),
303            }
304        },
305        Err(err) => Err(ErrorArrayItem::new(
306            dusa_collection_utils::core::errors::Errors::GeneralError,
307            err.to_string(),
308        )),
309    }
310}
311
312/// Updates the map with new data.
313///
314/// # Arguments
315///
316/// * `map_num` - The map number to be updated.
317/// * `errors` - An ErrorArray to capture errors.
318/// * `warnings` - A WarningArray to capture warnings.
319///
320/// # Returns
321///
322/// * `bool` - A boolean indicating if the update was successful.
323pub async fn update_map(map_num: u32) -> bool {
324    let system_paths: SystemPaths = SystemPaths::read_current().await;
325    // Add a result to return errors from this
326    // ? Getting the current map data
327    let map_path: PathType =
328        PathType::Content(format!("{}/chunk_{}.map", system_paths.MAPS, map_num));
329
330    // ? Reading the map
331    let mut map_file = File::open(&map_path).expect("File could not be opened");
332    let mut map_data: String = String::new();
333
334    map_file
335        .read_to_string(&mut map_data)
336        .expect("Could not read the map file !");
337
338    // ? unpacking to the chunk map struct
339    let pretty_map_data: ChunkMap = serde_json::from_str(&map_data).unwrap();
340
341    // ? calculating new hash
342    let chunk_data: (bool, Option<String>) = match fetch_chunk(map_num).await.uf_unwrap() {
343        Ok(data) => (true, Some(data)),
344        Err(_) => (false, None),
345    };
346
347    let new_hash: Option<Stringy> = match chunk_data {
348        (true, None) => None,
349        (true, Some(chunk)) => Some(create_hash(chunk)),
350        (false, None) => None,
351        (false, Some(_)) => None,
352    };
353
354    if new_hash == None {
355        log!(
356            LogLevel::Error,
357            "Failed to fetch chunk data for number {}",
358            &map_num
359        );
360    }
361
362    //  making new map
363    let new_map: ChunkMap = ChunkMap {
364        location: pretty_map_data.location,
365        version: VERSION.to_string(),
366        chunk_num: pretty_map_data.chunk_num,
367        chunk_hsh: new_hash.unwrap(),
368        chunk_beg: pretty_map_data.chunk_beg,
369        chunk_end: pretty_map_data.chunk_end,
370    };
371
372    // write the new map file
373    let _ = map_path.delete();
374    let updated_map = serde_json::to_string_pretty(&new_map).unwrap();
375
376    let mut map_file = OpenOptions::new()
377        .create_new(true)
378        .write(true)
379        .append(true)
380        .open(map_path)
381        .expect("File could not written to");
382
383    if let Err(_e) = writeln!(map_file, "{}", updated_map) {
384        log!(LogLevel::Error, "Could save map data to file");
385    };
386
387    return true;
388}