#[path = "system/array.rs"]
mod array;
#[path = "system/array_retrive.rs"]
mod array_tools;
#[path = "auth.rs"]
mod auth;
#[path = "system/config.rs"]
mod config;
#[path = "system/encrypt.rs"]
mod encrypt;
#[path = "enviornment.rs"]
mod local_env;
#[path = "system/secrets.rs"]
mod secret;
use dusa_collection_utils::log;
use dusa_collection_utils::core::logger::LogLevel;
use dusa_collection_utils::core::types::pathtype::PathType;
use dusa_collection_utils::core::types::stringy::Stringy;
use dusa_collection_utils::{
core::errors::{ErrorArrayItem, OkWarning, UnifiedResult as uf},
platform::functions::{create_hash, path_present},
};
use local_env::{clean_temps, VERSION};
use secret::{read_raw, write_raw};
use std::{
fs::{File, OpenOptions},
io::{Read, Write},
};
use crate::{
array::{index_system_array, ChunkMap},
array_tools::fetch_chunk,
config::{ARRAY_LEN, CHUNK_SIZE},
local_env::{set_system, SystemPaths},
secret::{forget, read, write},
};
pub static mut DEBUGGING: Option<bool> = None;
pub static mut PROGNAME: &str = "";
pub fn set_debug(option: bool) {
match option {
true => unsafe { DEBUGGING = Some(true) },
false => unsafe { DEBUGGING = Some(false) },
}
}
pub fn set_prog(data: &'static str) {
unsafe { PROGNAME = data };
}
pub async fn initialize(temporary_path: bool) -> uf<()> {
let debugging: bool = match unsafe { DEBUGGING } {
Some(d) => match d {
true => true,
false => false,
},
None => false,
};
let debug: bool = match &debugging {
true => {
use std::env;
env::set_var("RUST_BACKTRACE", "1");
true
}
false => false,
};
log!(LogLevel::Trace, "RECS started");
SystemPaths::set_current(temporary_path).await;
if let Err(e) = ensure_system_path(debug).await.uf_unwrap() {
return uf::new(Err(e));
}
if let Err(e) = ensure_max_map_exists().await.uf_unwrap() {
return uf::new(Err(e));
}
uf::new(Ok(()))
}
async fn ensure_system_path(debug: bool) -> uf<()> {
let system_paths = SystemPaths::read_current().await;
match path_present(&system_paths.SYSTEM_ARRAY_LOCATION).uf_unwrap() {
Ok(true) => (),
Ok(false) => {
log!(
LogLevel::Trace,
"System array file does not exist, reinitialize recs"
);
if let Err(e) = set_system(debug).await.uf_unwrap() {
return uf::new(Err(e));
}
}
Err(e) => return uf::new(Err(e)),
}
uf::new(Ok(()))
}
async fn ensure_max_map_exists() -> uf<()> {
let system_paths = SystemPaths::read_current().await;
let max_map = ARRAY_LEN / CHUNK_SIZE;
let max_map_path = PathType::Content(format!("{}/{}.map", system_paths.MAPS, max_map - 1));
match path_present(&max_map_path).uf_unwrap() {
Ok(true) => uf::new(Ok(())),
Ok(false) => match index_system_array().await.uf_unwrap() {
Ok(_d) => uf::new(Ok(())),
Err(e) => return uf::new(Err(e)),
},
Err(e) => uf::new(Err(e)),
}
}
pub async fn store(filename: PathType, owner: String, name: String) -> uf<()> {
match write(filename, owner, name, false).await.uf_unwrap() {
Ok(d) => {
log!(LogLevel::Info, "Stored: value:{}, count: {} ", d.0, d.1);
return uf::new(Ok(()));
}
Err(e) => return uf::new(Err(e)),
}
}
pub async fn retrieve(
owner: String,
name: String,
uid: u32,
) -> uf<OkWarning<(PathType, PathType)>> {
read(owner, name, uid, false).await
}
pub async fn remove(owner: String, name: String) -> uf<()> {
match forget(owner, name).await {
Ok(_) => uf::new(Ok(())),
Err(err) => uf::new(Err(err)),
}
}
pub async fn ping(owner: String, name: String) -> uf<bool> {
let system_paths: SystemPaths = SystemPaths::read_current().await;
let secret_map_path = PathType::Content(format!(
"{}/{owner}-{name}.meta",
system_paths.META,
owner = owner,
name = name
));
path_present(&secret_map_path)
}
pub async fn encrypt_raw(data: String) -> uf<(String, String, usize)> {
write_raw(data.into()).await
}
pub fn decrypt_raw(recs_data: String, recs_key: String, recs_chunks: usize) -> uf<Vec<u8>> {
read_raw(recs_data, recs_key, recs_chunks)
}
pub async fn house_keeping() -> Result<(), ErrorArrayItem> {
let handle: tokio::task::JoinHandle<Result<(), ErrorArrayItem>> = tokio::spawn(async {
clean_temps().await?;
ensure_max_map_exists().await.uf_unwrap()?;
Ok(())
});
match handle.await {
Ok(result) => {
match result {
Ok(_) => Ok(()),
Err(err) => Err(err),
}
},
Err(err) => Err(ErrorArrayItem::new(
dusa_collection_utils::core::errors::Errors::GeneralError,
err.to_string(),
)),
}
}
pub async fn update_map(map_num: u32) -> bool {
let system_paths: SystemPaths = SystemPaths::read_current().await;
let map_path: PathType =
PathType::Content(format!("{}/chunk_{}.map", system_paths.MAPS, map_num));
let mut map_file = File::open(&map_path).expect("File could not be opened");
let mut map_data: String = String::new();
map_file
.read_to_string(&mut map_data)
.expect("Could not read the map file !");
let pretty_map_data: ChunkMap = serde_json::from_str(&map_data).unwrap();
let chunk_data: (bool, Option<String>) = match fetch_chunk(map_num).await.uf_unwrap() {
Ok(data) => (true, Some(data)),
Err(_) => (false, None),
};
let new_hash: Option<Stringy> = match chunk_data {
(true, None) => None,
(true, Some(chunk)) => Some(create_hash(chunk)),
(false, None) => None,
(false, Some(_)) => None,
};
if new_hash == None {
log!(
LogLevel::Error,
"Failed to fetch chunk data for number {}",
&map_num
);
}
let new_map: ChunkMap = ChunkMap {
location: pretty_map_data.location,
version: VERSION.to_string(),
chunk_num: pretty_map_data.chunk_num,
chunk_hsh: new_hash.unwrap(),
chunk_beg: pretty_map_data.chunk_beg,
chunk_end: pretty_map_data.chunk_end,
};
let _ = map_path.delete();
let updated_map = serde_json::to_string_pretty(&new_map).unwrap();
let mut map_file = OpenOptions::new()
.create_new(true)
.write(true)
.append(true)
.open(map_path)
.expect("File could not written to");
if let Err(_e) = writeln!(map_file, "{}", updated_map) {
log!(LogLevel::Error, "Could save map data to file");
};
return true;
}