From a1d8bcbeff46361b9ffb996a8aaa03702f7afb2d Mon Sep 17 00:00:00 2001 From: Alex Emmet Date: Sun, 7 Sep 2025 15:56:48 +0200 Subject: [PATCH] Omikron Connects Data Sends Identified Users loaded --- src/auth/auth_connector.rs | 4 +- src/data/communication.rs | 22 +-- src/eula/eula_checker.rs | 27 ++++ src/eula/mod.rs | 1 + src/main.rs | 47 ++++-- src/omikron/omikron_connection.rs | 61 ++++---- src/users/contact.rs | 1 - src/users/user_manager.rs | 14 +- src/util/config_util.rs | 34 +--- src/util/file_util.rs | 250 +++++++++++++++--------------- 10 files changed, 240 insertions(+), 221 deletions(-) create mode 100644 src/eula/eula_checker.rs create mode 100644 src/eula/mod.rs diff --git a/src/auth/auth_connector.rs b/src/auth/auth_connector.rs index 01f2fd4..e3acc9f 100644 --- a/src/auth/auth_connector.rs +++ b/src/auth/auth_connector.rs @@ -56,7 +56,7 @@ impl AuthConnector { if !cv.is_type(CommunicationType::Success) { return None; } - Uuid::parse_str(cv.get_data(DataTypes::UserId).unwrap()).ok() + Uuid::parse_str(&*cv.get_data(DataTypes::UserId).unwrap().to_string()).ok() } pub async fn get_user(user_id: Uuid) -> Option { @@ -90,7 +90,7 @@ impl AuthConnector { let json = res.text().await.ok()?; let mut cv = CommunicationValue::from_json(&json); - Uuid::parse_str(cv.get_data(DataTypes::UserId).unwrap()).ok() + Uuid::parse_str(&*cv.get_data(DataTypes::UserId).unwrap().to_string()).ok() } pub async fn complete_register(user_profile: &UserProfile, iota_id: &str) -> bool { diff --git a/src/data/communication.rs b/src/data/communication.rs index 4a47fb8..79cf97d 100644 --- a/src/data/communication.rs +++ b/src/data/communication.rs @@ -286,7 +286,7 @@ pub struct CommunicationValue { pub log_value: Option, pub sender: Option, pub receiver: Option, - pub data: HashMap, + pub data: HashMap, } impl CommunicationValue { @@ -328,11 +328,15 @@ impl CommunicationValue { pub fn get_receiver(&self) -> Option { self.receiver.clone() } - pub fn add_data(mut self, key: DataTypes, value: String) -> Self { + pub fn add_data_str(mut self, key: DataTypes, value: String) -> Self { + self.data.insert(key, JsonValue::String(value)); + self + } + pub fn add_data(mut self, key: DataTypes, value: JsonValue) -> Self { self.data.insert(key, value); self } - pub fn get_data(&mut self, key: DataTypes) -> Option<&String> { + pub fn get_data(&mut self, key: DataTypes) -> Option<&JsonValue> { self.data.get(&key) } @@ -376,7 +380,7 @@ impl CommunicationValue { if parsed["data"].is_object() { for (k, v) in parsed["data"].entries() { if let Some(val) = v.as_str() { - data.insert(DataTypes::parse(k.to_string()), val.to_string()); + data.insert(DataTypes::parse(k.to_string()), v.clone()); } } } @@ -394,12 +398,12 @@ impl CommunicationValue { .with_id(message_id); if let Some(s) = sender { - cv = cv.add_data(DataTypes::SenderId, s.to_string()); + cv = cv.add_data(DataTypes::SenderId, JsonValue::String(s.to_string())); } cv } pub fn forward_to_other_iota(original: &mut CommunicationValue) -> CommunicationValue { - let receiver = Uuid::from_str(original.get_data(DataTypes::ReceiverId).unwrap()).ok() + let receiver = Uuid::from_str(&*original.get_data(DataTypes::ReceiverId).unwrap().to_string()).ok() .or(Option::from(Uuid::nil())); let now_ms = SystemTime::now() @@ -410,12 +414,12 @@ impl CommunicationValue { let mut cv = CommunicationValue::new(CommunicationType::MessageOtherIota) .with_id(original.get_id()) .with_receiver(receiver.unwrap()) - .add_data(DataTypes::SendTime, now_ms.to_string()) - .add_data(DataTypes::MessageContent, original.get_data(DataTypes::MessageContent).unwrap().to_string()); + .add_data(DataTypes::SendTime, JsonValue::String(now_ms.to_string())) + .add_data(DataTypes::MessageContent, JsonValue::String(original.get_data(DataTypes::MessageContent).unwrap().to_string())); // include sender_id if the original had one if let Some(sender) = original.get_sender() { - cv = cv.add_data(DataTypes::SenderId, sender.to_string()); + cv = cv.add_data(DataTypes::SenderId, JsonValue::String(sender.to_string())); } cv } diff --git a/src/eula/eula_checker.rs b/src/eula/eula_checker.rs new file mode 100644 index 0000000..18b3244 --- /dev/null +++ b/src/eula/eula_checker.rs @@ -0,0 +1,27 @@ + +use crate::util::file_util::{load_file, save_file}; + +pub fn check_eula() -> bool{ + let eula = "By changing the value to \"true\" you agree to our end user license agreement and our terms of service!\ + \nYou can find our Terms of service on https://docs.tensamin.methanium.net/legal/terms-of-service/.\ + \neula=false"; + let file = load_file("", "eula.txt"); + if(file.is_empty()){ + save_file("", "eula.txt", eula); + return false; + } + + if (file.contains("eula=false")) { + false + } else if (file.contains("eula=true")) { + true + } else { + false + } +} +pub fn accept_eula(){ + let eula = "By changing the value to \"true\" you agree to some shit we say on our website IDK this shouldn't be public yet!\ + \nYou also give us all rights to your soul, and we own your dog now.\ + \neula=true"; + save_file("", "eula.txt", eula); +} \ No newline at end of file diff --git a/src/eula/mod.rs b/src/eula/mod.rs new file mode 100644 index 0000000..a3ee485 --- /dev/null +++ b/src/eula/mod.rs @@ -0,0 +1 @@ +pub mod eula_checker; \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 3754627..bc2b0d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,42 +1,59 @@ -use tokio::runtime::Runtime; -use std::process::{Command, ExitStatus}; use futures_util::SinkExt; -use json::{self}; +use json::{self, JsonValue}; +use json::JsonValue::String; use uuid::Uuid; mod data; mod omikron; mod util; mod users; +mod eula; mod gui { pub mod ratatui_interface; } -mod auth; +mod auth; +use crate::eula::*; use crate::omikron::omikron_connection::{OmikronConnection}; use crate::data::communication::{CommunicationValue, CommunicationType, DataTypes}; -use gui::{ratatui_interface}; +use crate::users::user_manager::UserManager; +use crate::util::config_util::ConfigUtil; #[tokio::main] async fn main() { - let mut omikron: OmikronConnection = OmikronConnection::new(); + if(!eula_checker::check_eula()){ + println!("Please accept the end user license agreement before launching!"); + return; + } + + let mut c_util = ConfigUtil::new(); + c_util.load(); + if !c_util.config.has_key("iota_id") { + c_util.change("iota_id", Uuid::new_v4()); + c_util.save(); + } + + UserManager::load_users().await; + let mut sb = "".to_string(); + for up in UserManager::get_users() { + sb = sb + "," + &*up.user_id.to_string(); + } + + UserManager::save_users(); + let omikron: OmikronConnection = OmikronConnection::new(); omikron.connect().await; - omikron.send_message( CommunicationValue::new( CommunicationType::Identification ) - .add_data(DataTypes::UserIds, Uuid::new_v4().to_string()) - .add_data(DataTypes::IotaId, Uuid::new_v4().to_string()) + .add_data(DataTypes::UserIds, String(sb.to_string())) + .add_data(DataTypes::IotaId, String(c_util.config["iota_id"].to_string())) .to_json() .to_string() .as_mut() .to_string() - ); - - let mut child = Command::new("sleep").arg("5").spawn().unwrap(); - let _result = child.wait().unwrap(); - omikron.close().await; - println!("reached end of main"); + ).await; + + loop {} } diff --git a/src/omikron/omikron_connection.rs b/src/omikron/omikron_connection.rs index dca53ee..375f85f 100644 --- a/src/omikron/omikron_connection.rs +++ b/src/omikron/omikron_connection.rs @@ -1,9 +1,9 @@ use futures_util::{SinkExt, StreamExt}; use std::collections::HashMap; -use std::ptr::write; use std::str::FromStr; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; +use json::JsonValue; use tokio::sync::Mutex; use tokio::net::TcpStream; use tokio::time::{sleep, Duration}; @@ -37,7 +37,7 @@ impl OmikronConnection { } /// Connect loop with retry - pub async fn connect(&self) { + pub async fn connect<'a>(&'a self) { loop { match connect_async("wss://tensamin.methanium.net/ws/iota/").await { Ok((ws_stream, _)) => { @@ -85,14 +85,6 @@ impl OmikronConnection { println!("[Omikron] Pong received"); // handle pingpong reset here } - - if waiting.lock().await.contains_key(&cv.get_id()) { - if let Some(callback) = waiting.lock().await.remove(&cv.get_id()) { - callback(cv); - } - continue; - } - // ************************************************ // // Direct messages // // ************************************************ // @@ -100,19 +92,20 @@ impl OmikronConnection { let sender_id = &cv.get_sender(); let receiver_id = &cv.get_receiver(); ChatFiles::add_message( - cv.get_data(DataTypes::SendTime).unwrap().parse::().unwrap_or(-1), + + cv.get_data(DataTypes::SendTime).unwrap().as_i64().unwrap_or(-1), false, receiver_id.unwrap(), sender_id.unwrap(), - cv.get_data(DataTypes::MessageContent).unwrap().as_str(), + cv.get_data(DataTypes::MessageContent).unwrap().as_str().unwrap(), ); let response = CommunicationValue::new(CommunicationType::MessageLive) .with_id(cv.get_id()) .with_receiver(cv.get_receiver().unwrap()) - .add_data(DataTypes::SendTime, cv.get_data(DataTypes::SendTime).unwrap().to_string()) - .add_data(DataTypes::Message, cv.get_data(DataTypes::MessageContent).unwrap().to_string()) - .add_data(DataTypes::SenderId, cv.get_sender().unwrap().to_string()); - Self::send_message_static(&writer, response.to_json().to_string()).await; + .add_data(DataTypes::SendTime, cv.get_data(DataTypes::SendTime).unwrap().clone()) + .add_data(DataTypes::Message, cv.get_data(DataTypes::MessageContent).unwrap().clone()) + .add_data(DataTypes::SenderId, JsonValue::String(cv.get_sender().unwrap().clone().to_string())); + Self::send_message_static(&writer.clone(), response.to_json().to_string()).await; continue; } @@ -129,10 +122,10 @@ impl OmikronConnection { ); // ack let ack = CommunicationValue::ack_message(cv.get_id(), my_id); - Self::send_message_static(&writer, ack.to_json().to_string()).await; + Self::send_message_static(&writer.clone(), ack.to_json().to_string()).await; // forward let forward = CommunicationValue::forward_to_other_iota(&mut cv); - Self::send_message_static(&writer, forward.to_json().to_string()).await; + Self::send_message_static(&writer.clone(), forward.to_json().to_string()).await; continue; } @@ -147,9 +140,9 @@ impl OmikronConnection { .with_id(cv.get_id()) .with_receiver(my_id); if !messages.is_empty() { - resp = resp.add_data(DataTypes::MessageChunk, messages.to_string()); + resp = resp.add_data(DataTypes::MessageChunk, messages); } - Self::send_message_static(&writer, resp.to_json().to_string()).await; + Self::send_message_static(&writer.clone(), resp.to_json().to_string()).await; continue; } @@ -159,14 +152,14 @@ impl OmikronConnection { let resp = CommunicationValue::new(CommunicationType::GetChats) .with_id(cv.get_id()) .with_receiver(user_id.unwrap()) - .add_data(DataTypes::UserIds, users.to_string()); - Self::send_message_static(&writer, resp.to_json().to_string()).await; + .add_data(DataTypes::UserIds, users); + Self::send_message_static(&writer.clone(), resp.to_json().to_string()).await; continue; } if cv.is_type(CommunicationType::AddChat) { let user_id = cv.get_sender(); - let other_id = Uuid::from_str(&*cv.get_data(DataTypes::ReceiverId).unwrap().to_string()).unwrap(); + let other_id = Uuid::from_str(&*cv.get_data(DataTypes::UserId).unwrap().to_string()).unwrap(); let mut contact = ChatsUtil::get_user(user_id.unwrap(), other_id).unwrap_or(Contact::new(other_id)); // needs ChatsUtil + Contact contact.set_last_message_at(SystemTime::now() .duration_since(UNIX_EPOCH) @@ -176,7 +169,7 @@ impl OmikronConnection { let resp = CommunicationValue::new(CommunicationType::AddChat) .with_id(cv.get_id()) .with_receiver(user_id.unwrap()); - Self::send_message_static(&writer, resp.to_json().to_string()).await; + Self::send_message_static(&writer.clone(), resp.to_json().to_string()).await; continue; } @@ -189,7 +182,7 @@ impl OmikronConnection { let resp = CommunicationValue::new(CommunicationType::AddCommunity) .with_id(cv.get_id()) .with_receiver(cv.get_sender().unwrap()); - Self::send_message_static(&writer, resp.to_json().to_string()).await; + Self::send_message_static(&writer.clone(), resp.to_json().to_string()).await; continue; } @@ -197,8 +190,8 @@ impl OmikronConnection { let resp = CommunicationValue::new(CommunicationType::GetCommunities) .with_id(cv.get_id()) .with_receiver(cv.get_sender().unwrap()) - .add_data(DataTypes::Communities, UserCommunityUtil::get_communities(cv.get_sender().unwrap()).to_string()); // needs UserCommunityUtil - Self::send_message_static(&writer, resp.to_json().to_string()).await; + .add_data(DataTypes::Communities, UserCommunityUtil::get_communities(cv.get_sender().unwrap())); // needs UserCommunityUtil + Self::send_message_static(&writer.clone(), resp.to_json().to_string()).await; continue; } @@ -207,7 +200,7 @@ impl OmikronConnection { let resp = CommunicationValue::new(CommunicationType::RemoveCommunity) .with_id(cv.get_id()) .with_receiver(cv.get_sender().unwrap()); - Self::send_message_static(&writer, resp.to_json().to_string()).await; + Self::send_message_static(&writer.clone(), resp.to_json().to_string()).await; continue; } } @@ -220,16 +213,20 @@ impl OmikronConnection { } }); } - pub fn send_message(&self, msg: String){ - OmikronConnection::send_message_static(&self.writer, msg); + pub async fn send_message(&self, msg: String) { + Self::send_message_static(&self.writer, msg).await; } pub async fn send_message_static( writer: &Arc>, Message>>>>, msg: String, - ) { + ) -> Result<(), tokio_tungstenite::tungstenite::Error> { let mut guard = writer.lock().await; if let Some(writer) = guard.as_mut() { - let _ = writer.send(Message::Text(msg)).await; + writer.send(Message::Text(msg)).await?; + writer.flush().await?; + Ok(()) + } else { + Err(tokio_tungstenite::tungstenite::Error::ConnectionClosed) } } diff --git a/src/users/contact.rs b/src/users/contact.rs index b7a3d4d..dced7f8 100644 --- a/src/users/contact.rs +++ b/src/users/contact.rs @@ -1,6 +1,5 @@ use json::{self, JsonValue}; use std::time::{SystemTime, UNIX_EPOCH}; -use axum::Json; use uuid::Uuid; #[derive(Debug, Clone)] diff --git a/src/users/user_manager.rs b/src/users/user_manager.rs index 51c334e..e8b7ae1 100644 --- a/src/users/user_manager.rs +++ b/src/users/user_manager.rs @@ -10,6 +10,7 @@ use json::{JsonValue}; use once_cell::sync::Lazy; use crate::users::user_profile::UserProfile; use crate::users::user_profile_full::UserProfileFull; +use crate::util::file_util::{load_file, save_file}; pub struct UserManager; @@ -72,20 +73,19 @@ impl UserManager { let users = USERS.lock().unwrap(); let arr: Vec = users.iter().map(|u| u.to_json()).collect(); let json_str = JsonValue::Array(arr).dump(); - fs::write("users.json", json_str)?; + + save_file("", "users.json", &json_str); Ok(()) } pub async fn load_users() -> io::Result<()> { - let path = Path::new("users.json"); - if !path.exists() { - return Ok(()); - } - let content = fs::read_to_string(path)?; + let content = load_file("", "users.json"); if content.trim().is_empty() { return Ok(()); } - let parsed = json::parse(&content).map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; + + let parsed = json::parse(&content) + .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; if let JsonValue::Array(arr) = parsed { let mut users = USERS.lock().unwrap(); for j in arr.iter() { diff --git a/src/util/config_util.rs b/src/util/config_util.rs index cebf038..1a92a7b 100644 --- a/src/util/config_util.rs +++ b/src/util/config_util.rs @@ -2,6 +2,8 @@ use json::JsonValue; use std::fs::{self, File}; use std::io::{Read, Write}; use std::path::Path; +use uuid::Uuid; +use crate::util::file_util::{load_file, save_file}; pub struct ConfigUtil { pub config: JsonValue, @@ -16,37 +18,15 @@ impl ConfigUtil { } } - fn load_file(path: &str) -> String { - if let Ok(mut f) = File::open(path) { - let mut content = String::new(); - let _ = f.read_to_string(&mut content); - content - } else { - String::new() - } - } - - fn save_file(path: &str, content: &str) -> std::io::Result<()> { - if let Some(parent) = Path::new(path).parent() { - fs::create_dir_all(parent)?; - } - let mut file = File::create(path)?; - file.write_all(content.as_bytes()) - } - pub fn load(&mut self) { - let s = Self::load_file("config.json"); + let s = load_file("", "config.json"); if !s.is_empty() { self.config = json::parse(&s).unwrap_or(JsonValue::new_object()); } - if self.config.has_key("ssl_port") { - if let Some(port) = self.config["ssl_port"].as_i32() { - } - } } - pub fn change(&mut self, key: &str, value: JsonValue) { - self.config[key] = value; + pub fn change(&mut self, key: &str, value: Uuid) { + self.config[key] = JsonValue::String(value.to_string()); self.unique = true; } @@ -56,7 +36,7 @@ impl ConfigUtil { } } - pub fn save(&self) -> std::io::Result<()> { - Self::save_file("config.json", &self.config.dump()) + pub fn save(&self) { + save_file("","config.json", &self.config.to_string()); } } diff --git a/src/util/file_util.rs b/src/util/file_util.rs index db19780..1045925 100644 --- a/src/util/file_util.rs +++ b/src/util/file_util.rs @@ -8,149 +8,143 @@ use std::process; use walkdir::WalkDir; use std::fmt::Write as FmtWrite; use uuid::Uuid; - -pub struct FileUtil; - -impl FileUtil { - pub fn delete_file(path: &str, name: &str) -> bool { - let dir = Path::new(&Self::get_jar_directory()).join(path); - let file = dir.join(name); - if !file.exists() { - return false; - } - fs::remove_file(file).is_ok() +pub fn delete_file(path: &str, name: &str) -> bool { + let dir = Path::new(&get_directory()).join(path); + let file = dir.join(name); + if !file.exists() { + return false; } + fs::remove_file(file).is_ok() +} - pub fn delete_directory(path: &str) -> bool { - let dir = Path::new(&Self::get_jar_directory()).join(path); - Self::delete_dir_recursive(&dir) +pub fn delete_directory(path: &str) -> bool { + let dir = Path::new(&get_directory()).join(path); + delete_dir_recursive(&dir) +} + +fn delete_dir_recursive(directory: &Path) -> bool { + if !directory.exists() { + return false; } - - fn delete_dir_recursive(directory: &Path) -> bool { - if !directory.exists() { - return false; - } - if let Err(e) = fs::remove_dir_all(directory) { - println!("[IMPORTANT] Couldn't delete directory {}: {}", directory.display(), e); - return false; - } - true + if let Err(e) = fs::remove_dir_all(directory) { + println!("[IMPORTANT] Couldn't delete directory {}: {}", directory.display(), e); + return false; } + true +} - pub fn delete_user_directory(user_id: Uuid) { - let user_dir = Path::new(&Self::get_jar_directory()) - .join("users") - .join(user_id.to_string()); - let _ = Self::delete_dir_recursive(&user_dir); - } +pub fn delete_user_directory(user_id: Uuid) { + let user_dir = Path::new(&get_directory()) + .join("users") + .join(user_id.to_string()); + let _ = delete_dir_recursive(&user_dir); +} - pub fn load_file(path: &str, name: &str) -> String { - let dir = Path::new(&Self::get_jar_directory()).join(path); - let file_path = dir.join(name); +pub fn load_file(path: &str, name: &str) -> String { + let dir = Path::new(&get_directory()).join(path); + let file_path = dir.join(name); - if !dir.exists() { - if let Err(e) = fs::create_dir_all(&dir) { - println!("[IMPORTANT] Couldn't create directories: {}", e); - return String::new(); - } + if !dir.exists() { + if let Err(e) = fs::create_dir_all(&dir) { + println!("[IMPORTANT] Couldn't create directories: {}", e); return String::new(); } - - if !file_path.exists() { - if let Err(e) = File::create(&file_path) { - println!("[IMPORTANT] Couldn't create file: {}", e); - } - return String::new(); - } - - let mut content = String::new(); - if let Ok(mut f) = File::open(&file_path) { - let _ = f.read_to_string(&mut content); - } - content + return String::new(); } - pub fn save_file(path: &str, name: &str, value: &str) { - let dir = Path::new(&Self::get_jar_directory()).join(path); - let file_path = dir.join(name); - - if !dir.exists() { - if let Err(e) = fs::create_dir_all(&dir) { - println!("[IMPORTANT] Couldn't create directories: {}", e); - return; - } + if !file_path.exists() { + if let Err(e) = File::create(&file_path) { + println!("[IMPORTANT] Couldn't create file: {}", e); } + return String::new(); + } - if let Err(e) = fs::write(&file_path, value) { - println!("[IMPORTANT] Couldn't write file {}: {}", file_path.display(), e); + let mut content = String::new(); + if let Ok(mut f) = File::open(&file_path) { + let _ = f.read_to_string(&mut content); + } + content +} + +pub fn save_file(path: &str, name: &str, value: &str) { + let dir = Path::new(&get_directory()).join(path); + let file_path = dir.join(name); + + if !dir.exists() { + if let Err(e) = fs::create_dir_all(&dir) { + println!("[IMPORTANT] Couldn't create directories: {}", e); + return; } } - pub fn get_jar_directory() -> String { - // In Rust, use current_exe as a proxy for JAR directory - let exe = std::env::current_exe().unwrap_or_else(|_| PathBuf::from(".")); - exe.parent() - .unwrap_or(Path::new(".")) - .to_string_lossy() - .to_string() - } - - pub fn used_space() -> u64 { - Self::get_directory_size(&PathBuf::from(Self::get_jar_directory())) - } - - pub fn get_directory_size(directory: &Path) -> u64 { - let mut size = 0; - for entry in WalkDir::new(directory).into_iter().filter_map(|e| e.ok()) { - let path = entry.path(); - if path.is_file() { - if let Ok(metadata) = path.metadata() { - size += path - .file_name() - .unwrap_or(OsStr::new("")) - .len() as u64; - size += metadata.len(); - } - } - } - size - } - - pub fn get_designed_storage(user_id: Uuid) -> String { - let user_dir = Path::new(&Self::get_jar_directory()) - .join("users") - .join(user_id.to_string()); - Self::design_byte(Self::get_directory_size(&user_dir)) - } - - pub fn design_byte(bytes: u64) -> String { - let mut hr_size = format!("{:.2}B", bytes as f64); - let k = bytes as f64 / 1024.0; - let m = k / 1024.0; - let g = m / 1024.0; - let t = g / 1024.0; - - if t >= 1.0 { - hr_size = format!("{:.2}TB", t); - } else if g >= 1.0 { - hr_size = format!("{:.2}GB", g); - } else if m >= 1.0 { - hr_size = format!("{:.2}MB", m); - } else if k >= 1.0 { - hr_size = format!("{:.2}KB", k); - } - hr_size - } - - pub fn get_used_ram() -> String { - let mut sys = System::new_all(); - sys.refresh_all(); - let used = sys.used_memory() * 1024; // kB to bytes - let total = sys.total_memory() * 1024; - format!( - "{}/{}", - Self::design_byte(used), - Self::design_byte(total) - ) + if let Err(e) = fs::write(&file_path, value) { + println!("[IMPORTANT] Couldn't write file {}: {}", file_path.display(), e); } } + +pub fn get_directory() -> String { + let exe = std::env::current_exe().unwrap_or_else(|_| PathBuf::from(".")); + exe.parent() + .unwrap_or(Path::new(".")) + .to_string_lossy() + .to_string() +} + +pub fn used_space() -> u64 { + get_directory_size(&PathBuf::from(get_directory())) +} + +pub fn get_directory_size(directory: &Path) -> u64 { + let mut size = 0; + for entry in WalkDir::new(directory).into_iter().filter_map(|e| e.ok()) { + let path = entry.path(); + if path.is_file() { + if let Ok(metadata) = path.metadata() { + size += path + .file_name() + .unwrap_or(OsStr::new("")) + .len() as u64; + size += metadata.len(); + } + } + } + size +} + +pub fn get_designed_storage(user_id: Uuid) -> String { + let user_dir = Path::new(&get_directory()) + .join("users") + .join(user_id.to_string()); + design_byte(get_directory_size(&user_dir)) +} + +pub fn design_byte(bytes: u64) -> String { + let mut hr_size = format!("{:.2}B", bytes as f64); + let k = bytes as f64 / 1024.0; + let m = k / 1024.0; + let g = m / 1024.0; + let t = g / 1024.0; + + if t >= 1.0 { + hr_size = format!("{:.2}TB", t); + } else if g >= 1.0 { + hr_size = format!("{:.2}GB", g); + } else if m >= 1.0 { + hr_size = format!("{:.2}MB", m); + } else if k >= 1.0 { + hr_size = format!("{:.2}KB", k); + } + hr_size +} + +pub fn get_used_ram() -> String { + let mut sys = System::new_all(); + sys.refresh_all(); + let used = sys.used_memory() * 1024; // kB to bytes + let total = sys.total_memory() * 1024; + format!( + "{}/{}", + design_byte(used), + design_byte(total) + ) +}