use dusa_collection_utils::{
core::errors::{ErrorArrayItem, Errors, UnifiedResult as uf},
core::logger::LogLevel,
core::types::{pathtype::PathType, rwarc::LockWithTimeout},
log,
platform::functions::{del_file, make_dir, path_present},
};
use glob::glob;
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use sysinfo::{System, SystemExt};
use tempfile::TempDir;
use crate::{
array::{generate_system_array, index_system_array},
auth::generate_user_key,
config::STREAMING_BUFFER_SIZE,
PROGNAME,
};
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
lazy_static! {
static ref SYSTEM_PATH_LOCK: LockWithTimeout<SystemPaths> =
LockWithTimeout::new(SystemPaths::new());
}
#[allow(non_snake_case)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SystemPaths {
pub SYSTEM_PATH: PathType,
pub DATA: PathType,
pub MAPS: PathType,
pub META: PathType,
pub SYSTEM_ARRAY_LOCATION: PathType,
pub USER_KEY_LOCATION: PathType,
}
impl SystemPaths {
pub fn new() -> Self {
let system_path = PathType::Content(format!("/var/{}", unsafe { PROGNAME }));
SystemPaths {
SYSTEM_PATH: system_path.clone(),
DATA: PathType::Content(format!("{}/secrets", system_path.clone())),
MAPS: PathType::Content(format!("{}/maps", system_path.clone())),
META: PathType::Content(format!("{}/meta", system_path.clone())),
SYSTEM_ARRAY_LOCATION: PathType::Content(format!("{}/array.recs", system_path.clone())),
USER_KEY_LOCATION: PathType::Content(format!("{}/userdata.recs", system_path.clone())),
}
}
pub async fn read_current() -> Self {
let system_path_lock: LockWithTimeout<SystemPaths> = SYSTEM_PATH_LOCK.clone();
let system_path_async = system_path_lock.try_read().await;
match system_path_async {
Ok(path) => path.clone(),
Err(err) => {
log!(LogLevel::Error, "Failed to read the system path: {}", err);
Self::new() }
}
}
pub async fn set_current(temporary: bool) {
let system_path_lock = SYSTEM_PATH_LOCK.clone();
let mut write_guard = system_path_lock.try_write().await.unwrap();
let system_path = if temporary {
log!(LogLevel::Trace, "Setting temporary file system space");
let temp_dir = TempDir::new()
.map_err(|err| ErrorArrayItem::from(err))
.unwrap();
PathType::Path(temp_dir.into_path().into())
} else {
PathType::Content(format!("/var/{}", unsafe { PROGNAME }))
};
let system_path = SystemPaths {
SYSTEM_PATH: system_path.clone(),
DATA: PathType::Content(format!("{}/secrets", system_path.clone())),
MAPS: PathType::Content(format!("{}/maps", system_path.clone())),
META: PathType::Content(format!("{}/meta", system_path.clone())),
SYSTEM_ARRAY_LOCATION: PathType::Content(format!("{}/array.recs", system_path.clone())),
USER_KEY_LOCATION: PathType::Content(format!("{}/userdata.recs", system_path.clone())),
};
*write_guard = system_path;
log!(LogLevel::Debug, "System paths updated successfully");
}
}
pub async fn set_system(debug: bool) -> uf<()> {
if let Err(err) = make_folders(debug).await.uf_unwrap() {
return uf::new(Err(err));
}
if let Err(e) = generate_system_array().await {
return uf::new(Err(e));
}
if let Err(e) = index_system_array().await.uf_unwrap() {
return uf::new(Err(e));
}
if let Err(e) = generate_user_key(debug).await.uf_unwrap() {
return uf::new(Err(e));
}
log!(LogLevel::Trace, "System array has been created and indexed");
uf::new(Ok(()))
}
async fn make_folders(debug: bool) -> uf<()> {
let system_paths: SystemPaths = SystemPaths::read_current().await;
match path_present(&system_paths.SYSTEM_PATH).uf_unwrap() {
Ok(b) => match b {
true => {
let mut paths: Vec<PathType> = vec![];
paths.insert(0, system_paths.DATA.clone());
paths.insert(1, system_paths.MAPS.clone());
paths.insert(2, system_paths.META.clone());
for path in paths.iter() {
let _ = match make_dir(&path).uf_unwrap() {
Ok(_) => match debug {
true => log!(LogLevel::Debug, "Path : {} created", &path),
false => (),
},
Err(e) => return uf::new(Err(e)),
};
}
}
false => {
return uf::new(Err(ErrorArrayItem::new(
Errors::GeneralError,
String::from("System Path missing"),
)));
}
},
Err(e) => return uf::new(Err(e)),
}
uf::new(Ok(()))
}
pub async fn clean_temps() -> Result<(), ErrorArrayItem> {
let paths: SystemPaths = SystemPaths::read_current().await;
let pattern: String = format!("{}/*.rand", paths.DATA);
for file in glob(&pattern)
.map_err(|err| ErrorArrayItem::new(Errors::GeneralError, err.msg.to_string()))?
{
match file {
Ok(path) => {
if path.is_file() {
log!(LogLevel::Debug, "RECS: Deleting: {}", path.display());
del_file(&PathType::PathBuf(path)).uf_unwrap()?;
}
}
Err(err) => return Err(ErrorArrayItem::new(Errors::GeneralError, err.to_string())),
}
}
Ok(())
}
pub fn calc_buffer() -> usize {
let mut system = System::new_all();
system.refresh_memory();
let used_ram = system.used_memory();
let total_ram = system.total_memory();
let free_ram = total_ram - used_ram;
let available_ram = free_ram as f64;
let buffer_size = if available_ram <= STREAMING_BUFFER_SIZE as f64 {
STREAMING_BUFFER_SIZE as f64 * 0.8 } else {
STREAMING_BUFFER_SIZE as f64 + (available_ram * 0.1) };
let max_buffer_size = 1_073_741_824; let final_buffer_size = buffer_size.min(max_buffer_size as f64);
final_buffer_size as usize }