From 1cbbe36c9ecf5e9622f6db026d6e364bd0515db4 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Tue, 25 Nov 2025 22:31:49 +0000 Subject: [PATCH] GUI --- Cargo.lock | 171 ++++++------------- src/gui/log_panel.rs | 312 ++--------------------------------- src/gui/mod.rs | 3 +- src/gui/nav_bar.rs | 34 ---- src/gui/ratatui_interface.rs | 48 ------ src/gui/tui.rs | 189 +++++++++++++++++++-- src/main.rs | 9 +- src/users/user_manager.rs | 30 +++- 8 files changed, 273 insertions(+), 523 deletions(-) delete mode 100644 src/gui/nav_bar.rs delete mode 100644 src/gui/ratatui_interface.rs diff --git a/Cargo.lock b/Cargo.lock index edb67d2..b77ef42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,59 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "Iota" -version = "0.1.0" -dependencies = [ - "aes-gcm", - "async-trait", - "async-tungstenite", - "aws-lc-rs", - "axum", - "base64", - "bytes", - "cmake", - "color-eyre", - "crossterm 0.29.0", - "der", - "futures", - "futures-util", - "hex", - "hkdf", - "hmac", - "http-body-util", - "hyper", - "hyper-util", - "json", - "native-tls", - "once_cell", - "pkcs8", - "rand 0.8.5", - "rand_core 0.6.4", - "ratatui", - "reactive-rs", - "reqwest", - "rustls", - "rustls-pemfile", - "serde", - "sha1", - "sha2", - "sys-info", - "sysinfo", - "tokio", - "tokio-rustls", - "tokio-tungstenite", - "tokio-util", - "tower", - "tungstenite", - "uuid", - "walkdir", - "warp", - "x448", - "x509", - "zip", -] - [[package]] name = "addr2line" version = "0.25.1" @@ -474,15 +421,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" -[[package]] -name = "convert_case" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "cookie-factory" version = "0.3.3" @@ -582,24 +520,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "crossterm" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" -dependencies = [ - "bitflags", - "crossterm_winapi", - "derive_more", - "document-features", - "mio", - "parking_lot", - "rustix 1.1.2", - "signal-hook", - "signal-hook-mio", - "winapi", -] - [[package]] name = "crossterm_winapi" version = "0.9.1" @@ -706,27 +626,6 @@ dependencies = [ "syn", ] -[[package]] -name = "derive_more" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "digest" version = "0.10.7" @@ -749,15 +648,6 @@ dependencies = [ "syn", ] -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - [[package]] name = "dunce" version = "1.0.5" @@ -1427,6 +1317,59 @@ dependencies = [ "syn", ] +[[package]] +name = "iota" +version = "0.1.0" +dependencies = [ + "aes-gcm", + "async-trait", + "async-tungstenite", + "aws-lc-rs", + "axum", + "base64", + "bytes", + "cmake", + "color-eyre", + "crossterm", + "der", + "futures", + "futures-util", + "hex", + "hkdf", + "hmac", + "http-body-util", + "hyper", + "hyper-util", + "json", + "native-tls", + "once_cell", + "pkcs8", + "rand 0.8.5", + "rand_core 0.6.4", + "ratatui", + "reactive-rs", + "reqwest", + "rustls", + "rustls-pemfile", + "serde", + "sha1", + "sha2", + "sys-info", + "sysinfo", + "tokio", + "tokio-rustls", + "tokio-tungstenite", + "tokio-util", + "tower", + "tungstenite", + "uuid", + "walkdir", + "warp", + "x448", + "x509", + "zip", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -1539,12 +1482,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - [[package]] name = "lock_api" version = "0.4.14" @@ -2018,7 +1955,7 @@ dependencies = [ "bitflags", "cassowary", "compact_str", - "crossterm 0.28.1", + "crossterm", "indoc", "instability", "itertools", diff --git a/src/gui/log_panel.rs b/src/gui/log_panel.rs index d3fff64..ec6d9d5 100644 --- a/src/gui/log_panel.rs +++ b/src/gui/log_panel.rs @@ -1,17 +1,11 @@ use crate::APP_STATE; use crate::SHUTDOWN; -use crate::gui::ratatui_interface::TERMINAL; -use crate::gui::widgets::betterblock::draw_block_joins; +use crate::gui::tui::UNIQUE; use crate::langu::language_manager::format; use crate::langu::language_manager::from_key; use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes}; -use ratatui::widgets::canvas::{Canvas, Line}; -use ratatui::{ - layout::{Constraint, Direction, Layout}, - style::Color, - widgets::{Block, Borders, List, ListItem, Paragraph}, -}; + use std::{thread, time::Duration}; use sysinfo::{RefreshKind, System}; @@ -22,66 +16,26 @@ pub fn log_cv(cv: &CommunicationValue) { } else { log_message_trans(format!("{:?}", &cv.comm_type)); } + tokio::spawn(async move { + *UNIQUE.write().await = true; + }); } pub fn log_message_trans(key: impl Into) { APP_STATE.lock().unwrap().push_log(from_key(&key.into())); + tokio::spawn(async move { + *UNIQUE.write().await = true; + }); } pub fn log_message(msg: impl Into) { APP_STATE.lock().unwrap().push_log(msg.into()); -} -fn smooth_data(data: &[(f64, f64)], window_size: usize) -> Vec<(f64, f64)> { - if data.len() < window_size { - return data.to_vec(); - } - let mut smoothed = Vec::with_capacity(data.len()); - for i in 0..data.len() { - let start = if i + 1 >= window_size { - i + 1 - window_size - } else { - 0 - }; - let window = &data[start..=i]; - let avg = window.iter().map(|(_, y)| y).sum::() / window.len() as f64; - smoothed.push((data[i].0, avg)); - } - smoothed -} - -fn downsample_to_fit_width(data: &[(f64, f64)], width: u16) -> Vec<(f64, f64)> { - let width_usize = (width as usize) * 2; - let len = data.len(); - - if len >= width_usize { - // Trim data to fit - data[len - width_usize..].to_vec() - } else { - let mut result = Vec::with_capacity(width_usize); - - // Define X spacing (so dummy points are properly spaced across the canvas) - let dx = 1.0; - let pad_len = width_usize - len; - - // If we have real data, use its first x position to determine where to start padding - let start_x = data - .first() - .map(|(x, _)| x - (dx * pad_len as f64)) - .unwrap_or(0.0); - let _ = data.first().map(|(_, y)| *y).unwrap_or(0.0); - - // Fill padding with increasing x positions so they're visible - for i in 0..pad_len { - result.push((start_x + i as f64 * dx, -1 as f64)); - } - - // Then append the real data - result.extend_from_slice(data); - result - } + tokio::spawn(async move { + *UNIQUE.write().await = true; + }); } pub fn setup() { // Start a background thread to sample metrics - thread::spawn(async move || { + tokio::spawn(async move { let mut sys = System::new_with_specifics(RefreshKind::new()); let mut last_total_received = 0u64; let mut last_total_transmitted = 0u64; @@ -129,248 +83,8 @@ pub fn setup() { } counter += 1.0; + *UNIQUE.write().await = true; thread::sleep(Duration::from_millis(1000)); } }); } - -pub fn render() { - tokio::spawn(async move { - TERMINAL - .lock() - .await - .draw(|f| { - let sys = System::new_all(); - - let size = f.area(); - let chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(40), Constraint::Percentage(60)]) - .split(size); - - let left = chunks[0]; - let right = chunks[1]; - - { - let st = APP_STATE.lock().unwrap(); - let items: Vec = st - .logs - .iter() - .rev() - .map(|s| ListItem::new(s.clone())) - .collect(); - let list = List::new(items) - .block(Block::default().title("Logs").borders(Borders::ALL)); - f.render_widget(list, left); - } - - let right_chunks = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Length(3), Constraint::Min(0)]) - .split(right); - - { - let st = APP_STATE.lock().unwrap(); - let header = Paragraph::new(st.sys_info.clone()).block( - Block::default() - .title("System Info") - .borders(Borders::TOP.union(Borders::LEFT).union(Borders::RIGHT)), - ); - f.render_widget(header, right_chunks[0]); - } - - let grid_chunks = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(49), Constraint::Percentage(51)]) - .split(right_chunks[1]); - - let left_column = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Percentage(49), Constraint::Percentage(51)]) - .split(grid_chunks[0]); - - let right_column = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Percentage(49), Constraint::Percentage(51)]) - .split(grid_chunks[1]); - - let st = APP_STATE.lock().unwrap(); - let w = grid_chunks[0].width.saturating_sub(2); - - let ping_ds = downsample_to_fit_width(&smooth_data(&st.ping, 3), w + 4); - let cpu_ds = downsample_to_fit_width(&smooth_data(&st.cpu, 3), w); - let ram_ds = downsample_to_fit_width(&smooth_data(&st.ram, 3), w); - let down_ds = downsample_to_fit_width(&st.net_down, w + 4); - let up_ds = downsample_to_fit_width(&st.net_up, w + 4); - - // ---- Render CPU ---- - { - let min_x = cpu_ds.first().map(|(x, _)| *x).unwrap_or(0.0); - let max_x = cpu_ds.last().map(|(x, _)| *x).unwrap_or(100.0); - let block = Block::default() - .title(format!( - "CPU {}%", - &st.cpu.last().unwrap_or(&(0.0 as f64, 0.0 as f64)).1 - )) - .borders(Borders::TOP.union(Borders::RIGHT).union(Borders::LEFT)); - let canvas = Canvas::default() - .block(block) - .x_bounds([min_x, max_x]) - .y_bounds([0.0, 100.0]) - .paint(|ctx| { - for (x, y) in &cpu_ds { - ctx.draw(&Line { - x1: *x, - y1: 0.0, - x2: *x, - y2: *y, - color: Color::Cyan, - }); - } - }); - f.render_widget(canvas, left_column[0]); - draw_block_joins( - f, - left_column[0], - Borders::TOP.union(Borders::LEFT), - Borders::TOP, - ); - draw_block_joins( - f, - left_column[0], - Borders::TOP.union(Borders::RIGHT), - Borders::RIGHT, - ); - } - - // ---- Render RAM ---- - { - let min_x = ram_ds.first().map(|(x, _)| *x).unwrap_or(0.0); - let max_x = ram_ds.last().map(|(x, _)| *x).unwrap_or(100.0); - - let ram_used = sys.used_memory() as f64 / 1024.0 / 1024.0 / 1024.0; - let ram_total = sys.total_memory() as f64 / 1024.0 / 1024.0 / 1024.0; - let ram = (sys.used_memory() as f64 / sys.total_memory() as f64) * 100.0; - - let canvas = Canvas::default() - .block( - Block::default() - .title(format!( - "RAM {:.1}% ({:.1}GiB/{:.1}GiB)", - ram, ram_used, ram_total - )) - .borders(Borders::ALL), - ) - .x_bounds([min_x, max_x]) - .y_bounds([0.0, 100.0]) - .paint(|ctx| { - for (x, y) in &ram_ds { - ctx.draw(&Line { - x1: *x, - y1: 0.0, - x2: *x, - y2: *y, - color: Color::Magenta, - }); - } - }); - - f.render_widget(canvas, left_column[1]); - draw_block_joins( - f, - left_column[1], - Borders::ALL, - Borders::TOP.union(Borders::RIGHT), - ); - } - - // ---- Render Ping ---- - { - let min_x = ping_ds.first().map(|(x, _)| *x).unwrap_or(0.0); - let max_x = ping_ds.last().map(|(x, _)| *x).unwrap_or(100.0); - let max_y = ping_ds.iter().map(|(_, y)| *y).fold(1.0, f64::max); - - let canvas = Canvas::default() - .block( - Block::default() - .title(format!("Ping {:.1}(ms)", max_y)) - .borders(Borders::TOP.union(Borders::RIGHT)), - ) - .x_bounds([min_x, max_x]) - .y_bounds([0.0, max_y]) - .paint(|ctx| { - for (x, y) in &ping_ds { - ctx.draw(&Line { - x1: *x, - y1: 0.0, - x2: *x, - y2: *y, - color: Color::Yellow, - }); - } - }); - f.render_widget(canvas, right_column[0]); - draw_block_joins( - f, - right_column[0], - Borders::RIGHT.union(Borders::TOP), - Borders::TOP, - ); - } - - // ---- Render Network ---- - { - let min_x = up_ds.first().map(|(x, _)| *x).unwrap_or(0.0); - let max_x = up_ds.last().map(|(x, _)| *x).unwrap_or(100.0); - let mut max_sum: f64 = 1.0; - for ((_, up), (_, down)) in up_ds.iter().zip(down_ds.iter()) { - max_sum = max_sum.max(up + down); - } - - let canvas = Canvas::default() - .block( - Block::default() - .title("Network Up/Down") - .borders(Borders::TOP.union(Borders::RIGHT).union(Borders::BOTTOM)), - ) - .x_bounds([min_x, max_x]) - .y_bounds([0.0, max_sum]) - .paint(|ctx| { - for (x, dval) in &down_ds { - ctx.draw(&Line { - x1: *x, - y1: 0.0, - x2: *x, - y2: *dval, - color: Color::Red, - }); - } - for (x, uval) in &up_ds { - let dval = down_ds - .iter() - .find(|(xx, _)| (*xx - *x).abs() < f64::EPSILON) - .map(|(_, y)| *y) - .unwrap_or(0.0); - - ctx.draw(&Line { - x1: *x, - y1: dval, - x2: *x, - y2: dval + *uval, - color: Color::Green, - }); - } - }); - - f.render_widget(canvas, right_column[1]); - draw_block_joins( - f, - right_column[1], - Borders::TOP.union(Borders::RIGHT).union(Borders::BOTTOM), - Borders::TOP, - ); - } - }) - .unwrap(); - }); -} diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 1d6a574..52c7030 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -1,7 +1,6 @@ pub mod app_state; pub mod log_panel; -pub mod nav_bar; -pub mod ratatui_interface; pub mod widgets { pub mod betterblock; } +pub mod tui; diff --git a/src/gui/nav_bar.rs b/src/gui/nav_bar.rs deleted file mode 100644 index 0919daf..0000000 --- a/src/gui/nav_bar.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::str; - -use crate::gui::log_panel; - -pub struct Screen { - pub title: String, - pub render: Box, -} -impl Screen { - pub fn new(title: &str, render: Box) -> Self { - Screen { - title: String::from(title), - render, - } - } - pub fn renderf(&self) { - (self.render)(); - } -} -pub struct NavBar { - pub current_screen: Screen, - pub screens: Vec, -} -impl NavBar { - pub fn new() -> Self { - NavBar { - current_screen: Screen { - title: String::from("Main"), - render: Box::new(|| log_panel::render()), - }, - screens: Vec::new(), - } - } -} diff --git a/src/gui/ratatui_interface.rs b/src/gui/ratatui_interface.rs deleted file mode 100644 index b923663..0000000 --- a/src/gui/ratatui_interface.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::{ - io::Stdout, - sync::{Arc, LazyLock}, - time::Duration, -}; - -use crate::{SHUTDOWN, gui::nav_bar::NavBar}; -use color_eyre::Result; -use crossterm::{ - execute, - terminal::{EnterAlternateScreen, enable_raw_mode}, -}; -use futures_util::lock::Mutex; -use ratatui::{Terminal, prelude::CrosstermBackend}; -use std::io::stdout; -use tokio::task; - -pub static TERMINAL: LazyLock>>>> = - LazyLock::new(|| { - Arc::new(Mutex::new( - Terminal::new(CrosstermBackend::new(stdout())).unwrap(), - )) - }); -pub static NAV_BAR: LazyLock>> = - LazyLock::new(|| Arc::new(Mutex::new(NavBar::new()))); - -pub fn launch() -> Result<()> { - color_eyre::install()?; - task::spawn(run()); - ratatui::restore(); - Ok(()) -} - -fn init_terminal() { - let mut stdout = stdout(); - execute!(stdout, EnterAlternateScreen).unwrap(); - enable_raw_mode().unwrap(); -} -async fn run() -> Result<()> { - init_terminal(); - loop { - if *SHUTDOWN.read().await { - return Ok(()); - } - NAV_BAR.lock().await.current_screen.renderf(); - tokio::time::sleep(Duration::from_millis(1000)).await; - } -} diff --git a/src/gui/tui.rs b/src/gui/tui.rs index ce4331e..bc5753a 100644 --- a/src/gui/tui.rs +++ b/src/gui/tui.rs @@ -1,7 +1,32 @@ -use sha1::digest::block_buffer::Lazy; -use tokio::{self, sync::RwLock}; +use std::{ + default, + io::{Stdout, stdout}, + sync::Arc, + thread, + time::Duration, +}; -use crate::{gui::log_panel, main::SHUTDOWN}; +use crossterm::{ + execute, + terminal::{EnterAlternateScreen, enable_raw_mode}, +}; +use once_cell::sync::Lazy; +use ratatui::{ + Frame, Terminal, + layout::{Constraint, Direction, Layout, Rect}, + prelude::CrosstermBackend, + style::Color, + widgets::{ + Block, Borders, List, ListItem, + canvas::{Canvas, Line}, + }, +}; +use tokio::{ + self, + sync::{Mutex, RwLock}, +}; + +use crate::{APP_STATE, SHUTDOWN}; // ****** UTIL ****** fn init_terminal() { @@ -12,25 +37,159 @@ fn init_terminal() { // ****** MAIN ****** pub static UNIQUE: Lazy> = Lazy::new(|| RwLock::new(false)); -pub static TERMINAL: LazyLock>>>> = - LazyLock::new(|| { - Arc::new(Mutex::new( - Terminal::new(CrosstermBackend::new(stdout())).unwrap(), - )) - }); +pub static TERMINAL: Lazy>>>> = Lazy::new(|| { + Arc::new(Mutex::new( + Terminal::new(CrosstermBackend::new(stdout())).unwrap(), + )) +}); pub fn start_tui() { tokio::spawn(async move { init_terminal(); - while !SHUTDOWN.read().await { - if UNIQUE.read().await { - render_tui(); + loop { + if *SHUTDOWN.read().await { + break; + } + if *UNIQUE.read().await { + render_tui().await; } else { thread::sleep(Duration::from_millis(50)); } } - }) + }); } -pub fn render_tui() { - log_panel::render(); +pub async fn render_tui() { + TERMINAL + .lock() + .await + .draw(|f| { + let area = f.area(); + let chunks = Layout::default() + .direction(Direction::Horizontal) + .constraints([ + Constraint::Percentage(40), + Constraint::Percentage(60), + Constraint::Max(40), + ]) + .constraints([ + Constraint::Percentage(40), + Constraint::Percentage(60), + Constraint::Min(40), + ]) + .split(area); + let state; + { + state = APP_STATE.lock().unwrap().clone(); + } + // LOGS + { + let items: Vec = state + .logs + .iter() + .rev() + .map(|s| ListItem::new(s.clone())) + .collect(); + let list = List::new(items).block( + Block::default() + .title("Logs") + .borders(Borders::LEFT.union(Borders::TOP).union(Borders::BOTTOM)), + ); + f.render_widget(list, chunks[0]); + } + // SETTINGS + { + let items: Vec = state + .logs + .iter() + .rev() + .map(|s| ListItem::new(s.clone())) + .collect(); + let list = List::new(items).block( + Block::default() + .title("Settings") + .borders(Borders::LEFT.union(Borders::TOP).union(Borders::BOTTOM)), + ); + f.render_widget(list, chunks[1]); + } + // GRAPHS + { + let stack = Layout::default() + .direction(Direction::Vertical) + .constraints( + [ + Constraint::Ratio(1, 3), + Constraint::Ratio(1, 3), + Constraint::Ratio(1, 3), + ] + .as_ref(), + ) + .split(chunks[2]); + render_graphs( + f, + stack[0], + "CPU".to_string(), + state.with_width(38).cpu, + Color::Cyan, + ); + render_graphs( + f, + stack[1], + "RAM".to_string(), + state.with_width(38).ram, + Color::Green, + ); + render_graphs( + f, + stack[2], + "PING".to_string(), + state.with_width(38).ping, + Color::Magenta, + ); + } + }) + .unwrap(); + *UNIQUE.write().await = false; +} + +pub fn render_graphs( + f: &mut Frame<'_>, + area: Rect, + title: String, + graph: Vec<(f64, f64)>, + color: Color, +) { + let min_x = graph.first().map(|(x, _)| *x).unwrap_or(0.0); + let max_x = graph.last().map(|(x, _)| *x).unwrap_or(100.0); + let min_y = graph + .iter() + .map(|(_, y)| *y) + .filter(|y| *y > 0.0) + .min_by(|a, b| a.total_cmp(b)) + .unwrap_or(0.0); + let max_y = graph.iter().map(|(_, y)| *y).fold(f64::MIN, f64::max); + let block = Block::default() + .title(format!( + "{}: {}, {}/{} MIN/MAX ", + title, + graph.last().unwrap_or(&(0.0 as f64, 0.0 as f64)).1 as i64, + min_y as i64, + max_y as i64 + )) + .borders(Borders::ALL); + let canvas = Canvas::default() + .block(block) + .x_bounds([min_x, max_x]) + .y_bounds([0.0, 100.0]) + .paint(|ctx| { + for (x, y) in &graph { + ctx.draw(&Line { + x1: *x, + y1: 0.0, + x2: *x, + y2: *y, + color, + }); + } + }); + f.render_widget(canvas, area); } diff --git a/src/main.rs b/src/main.rs index 41eedee..0fee375 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,6 @@ use std::sync::LazyLock; use std::sync::Mutex; use tokio::sync::RwLock; use tokio::time::{Duration, sleep}; -use tower::make::AsService; use uuid::Uuid; mod auth; @@ -23,8 +22,9 @@ use crate::communities::community_manager; use crate::communities::interactables::registry; use crate::data::communication::{CommunicationType, CommunicationValue, DataTypes}; use crate::gui::app_state::AppState; +use crate::gui::log_panel; use crate::gui::log_panel::{log_message, log_message_trans}; -use crate::gui::{log_panel, ratatui_interface}; +use crate::gui::tui; use crate::langu::language_creator; use crate::langu::language_manager::format; use crate::omikron::omikron_connection::OMIKRON_CONNECTION; @@ -56,10 +56,7 @@ async fn main() { // UI log_panel::setup(); - if let Err(e) = ratatui_interface::launch() { - println!("Ui launch failed: {}", &e.to_string()); - return; - } + tui::start_tui(); // BASIC CONFIGURATION CONFIG.lock().await.load(); diff --git a/src/users/user_manager.rs b/src/users/user_manager.rs index fc3207f..524e511 100644 --- a/src/users/user_manager.rs +++ b/src/users/user_manager.rs @@ -1,4 +1,4 @@ -use crate::auth::auth_connector; +use crate::auth::{auth_connector, crypto_helper}; use crate::users::user_profile::UserProfile; use crate::util::config_util::CONFIG; use crate::util::file_util::{load_file, save_file}; @@ -10,7 +10,8 @@ use rand::Rng; use rand_core::OsRng; use rand_core::RngCore; use sha2::{Digest, Sha256}; -use std::io; +use std::io::{self}; +use std::str::FromStr; use std::sync::Mutex; use uuid::Uuid; use x448::{PublicKey, Secret}; @@ -18,6 +19,31 @@ use x448::{PublicKey, Secret}; static USERS: Lazy>> = Lazy::new(|| Mutex::new(Vec::new())); static UNIQUE: Lazy> = Lazy::new(|| Mutex::new(false)); +// uuid::private_key +pub async fn load_from_tu(username: &str) -> Result<(), ()> { + let file_content = load_file("", &format!("{}.tu", username)); + let segments = file_content.split("::").collect::>(); + let uuid = Uuid::from_str(segments[0]).unwrap(); + let b64_private_key = segments[1]; + + let secret: Secret = crypto_helper::load_secret_key(b64_private_key).unwrap(); + let public_key = PublicKey::from(&secret); + + let mut bytes = [0u8; 192]; + OsRng.fill(bytes.as_mut()); + let reset_token = STANDARD.encode(&bytes); + + let user_profile = UserProfile::new( + uuid, + username.to_string(), + Some(username.to_string()), + crypto_helper::public_key_to_base64(&public_key), + crypto_helper::hex_hash(b64_private_key), + reset_token, + ); + USERS.lock().unwrap().push(user_profile); + Ok(()) +} pub async fn create_user(username: &str) -> (Option, Option) { let user_id = auth_connector::get_register().await.unwrap(); let mut buf = [0u8; 56];