From 997c567c807ce52b41431882ce38c8b156fc0c28 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Fri, 20 Feb 2026 20:24:11 +0100 Subject: [PATCH] [Add] UI optimizations, Graphs, More console commands --- src/gui/elements/console_card.rs | 126 ++++++++++--------- src/gui/elements/graph_card.rs | 208 +++++++++++++++++++++++++++++++ src/gui/elements/log_card.rs | 25 +++- src/gui/input_handler.rs | 3 +- src/gui/mod.rs | 1 + src/gui/screens/main_screen.rs | 78 +++++++++--- src/gui/screens/screens.rs | 6 +- src/gui/screens/terms_checker.rs | 4 - src/gui/screens/terms_updater.rs | 4 - src/gui/tui.rs | 0 src/gui/ui.rs | 72 +++++++++-- src/main.rs | 6 +- src/util/logger.rs | 10 +- 13 files changed, 426 insertions(+), 117 deletions(-) create mode 100644 src/gui/elements/graph_card.rs mode change 100644 => 100755 src/gui/elements/log_card.rs create mode 100644 src/gui/tui.rs diff --git a/src/gui/elements/console_card.rs b/src/gui/elements/console_card.rs index c425dd3..7ab1d6c 100644 --- a/src/gui/elements/console_card.rs +++ b/src/gui/elements/console_card.rs @@ -1,5 +1,4 @@ use crossterm::event::{KeyCode, KeyEvent}; -use json::JsonValue; use ratatui::{ Frame, layout::Rect, @@ -7,14 +6,15 @@ use ratatui::{ text::{Line, Span}, widgets::{Block, Borders, Paragraph}, }; +use uuid::Uuid; use crate::{ - ACTIVE_TASKS, - data::communication::{CommunicationType, CommunicationValue, DataTypes}, + ACTIVE_TASKS, RELOAD, SHUTDOWN, + data::communication::{CommunicationType, CommunicationValue}, gui::{ elements::elements::{Element, InteractableElement, JoinableElement}, interaction_result::InteractionResult, - ui::{FPS, UI}, + ui::FPS, util::borders::draw_block_joins, }, log, log_cv, @@ -22,11 +22,7 @@ use crate::{ users::{user_manager, user_profile::UserProfile}, util::file_util, }; -use std::{ - any::Any, - sync::Arc, - time::{Duration, SystemTime}, -}; +use std::{any::Any, time::Duration}; pub struct ConsoleCard { focused: bool, @@ -129,8 +125,12 @@ impl InteractableElement for ConsoleCard { match key.code { KeyCode::Enter => { let command = self.content.clone(); + let id = Uuid::new_v4(); + let task_id = format!("command_{}_{}", command, id); + ACTIVE_TASKS.insert(task_id.clone()); tokio::spawn(async move { run_command(&command).await; + ACTIVE_TASKS.remove(&task_id); }); self.content = "".to_string(); InteractionResult::Handled @@ -171,66 +171,43 @@ pub async fn run_command(command: &str) { ["tasks"] => { let active_tasks: Vec = ACTIVE_TASKS.clone().iter().map(|v| v.to_string()).collect(); - log!("Active tasks: {:?}", active_tasks); + let info = if *SHUTDOWN.read().await && *RELOAD.read().await { + "Rebooting, " + } else if *SHUTDOWN.read().await { + "Shutting , " + } else { + "" + }; + log!("{}Active tasks: {:?}", info, active_tasks); } ["fps"] => { - log!("FPS: {}", *FPS.read().await); + let (fps, skips) = *FPS.read().await; + log!("{:.1} FPS with {:.1}% of attempts skipped", fps, skips); } + + ["help"] => { + log!("Available commands: tasks, fps, ping, user"); + } + + ["help", "tasks"] => { + log!("Tasks command usage: tasks"); + } + ["help", "fps"] => { + log!("FPS command usage: fps"); + } + ["help", "ping"] => { + log!("Ping command usage: ping [time]"); + } + ["help", "user"] => { + log!("User command usage: user add | user remove | user list"); + } + ["ping"] => { - let time = 20; - - let now = SystemTime::now(); - - let conn = { - let guard = OMIKRON_CONNECTION.read().await; - guard.as_ref().cloned() - }; - - let conn = match conn { - Some(c) => c, - None => return, - }; - - let response_cv = conn - .await_response( - &CommunicationValue::new(CommunicationType::ping), - Some(Duration::from_secs(time)), - ) - .await; - - let elapsed = now.elapsed().unwrap_or(Duration::ZERO); - - match response_cv { - Ok(response) => log_cv!(response.add_data( - DataTypes::get_time, - JsonValue::from(elapsed.as_millis() as i64) - )), - Err(err) => log!("Ping error: {:?}", err), - } + ping(20).await; } ["ping", time] => { let time = time.parse::().unwrap_or(20); - - let conn = { - let guard = OMIKRON_CONNECTION.read().await; - guard.as_ref().cloned() - }; - - let conn = match conn { - Some(c) => c, - None => return, - }; - - let response_cv = conn - .await_response( - &CommunicationValue::new(CommunicationType::ping), - Some(Duration::from_secs(time)), - ) - .await; - match response_cv { - Ok(response) => log_cv!(response), - Err(err) => log!("Ping error: {:?}", err), - } + ping(time).await; } ["user", "add", username] => { if let (Some(user), Some(_)) = user_manager::create_user(username).await { @@ -273,3 +250,28 @@ pub async fn run_command(command: &str) { } } } + +pub async fn ping(time: u64) { + let time = time; + + let conn = { + let guard = OMIKRON_CONNECTION.read().await; + guard.as_ref().cloned() + }; + + let conn = match conn { + Some(c) => c, + None => return, + }; + + let response_cv = conn + .await_response( + &CommunicationValue::new(CommunicationType::ping), + Some(Duration::from_secs(time)), + ) + .await; + match response_cv { + Ok(response) => log_cv!(response), + Err(err) => log!("Ping error: {:?}", err), + } +} diff --git a/src/gui/elements/graph_card.rs b/src/gui/elements/graph_card.rs new file mode 100644 index 0000000..a0a7562 --- /dev/null +++ b/src/gui/elements/graph_card.rs @@ -0,0 +1,208 @@ +use std::{any::Any, sync::Arc}; + +use crossterm::event::KeyEvent; +use ratatui::{ + Frame, + layout::Rect, + style::{Color, Style}, + widgets::{ + Block, Borders, + canvas::{Canvas, Line}, + }, +}; + +use crate::{ + APP_STATE, + gui::{ + elements::elements::{Element, InteractableElement, JoinableElement}, + interaction_result::InteractionResult, + ui::UI, + util::borders::draw_block_joins, + }, +}; + +pub enum GRAPHS { + Ram, + Cpu, + Ping, +} + +impl GRAPHS { + pub fn get_graph(&self) -> Vec<(f64, f64)> { + match self { + GRAPHS::Ram => APP_STATE.lock().unwrap().ram.clone(), + GRAPHS::Cpu => APP_STATE.lock().unwrap().cpu.clone(), + GRAPHS::Ping => APP_STATE.lock().unwrap().ping.clone(), + } + } + + pub fn get_unit(&self) -> String { + match self { + GRAPHS::Ram => "MB".to_string(), + GRAPHS::Cpu => "%".to_string(), + GRAPHS::Ping => "ms".to_string(), + } + } +} + +pub struct GraphCard { + ui: Arc, + graph_type: GRAPHS, + + focused: bool, + pub title: String, + color: Color, + + borders: Borders, + joins: Borders, + + open: bool, +} + +impl GraphCard { + pub fn new(ui: Arc, graph_type: GRAPHS, title: String) -> Self { + Self { + ui, + graph_type, + focused: false, + title, + color: Color::White, + borders: Borders::ALL, + joins: Borders::NONE, + open: false, + } + } + + pub fn set_open(&mut self, open: bool) { + self.open = open; + } +} +impl Element for GraphCard { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn render(&self, f: &mut Frame, r: Rect) { + if self.open { + let graph = self.graph_type.get_graph(); + let unit = self.graph_type.get_unit(); + 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", + self.title, + graph.last().unwrap_or(&(0.0, 0.0)).1 as i64, + unit, + min_y as i64, + max_y as i64, + )) + .borders(self.borders) + .border_style(if self.focused { + Style::default().fg(Color::Yellow) + } else { + Style::default() + }); + + 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: self.color, + }); + } + }); + f.render_widget(canvas, r); + } else { + let block = Block::default() + .title("") + .borders(self.borders) + .border_style(if self.focused { + Style::default().fg(Color::Yellow) + } else { + Style::default() + }); + f.render_widget(block, r); + } + draw_block_joins(f, r, self.borders, self.joins); + } +} + +impl JoinableElement for GraphCard { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn as_element(&self) -> &dyn Element { + self + } + + fn as_element_mut(&mut self) -> &mut dyn Element { + self + } + + fn set_borders(&mut self, borders: Borders) { + self.borders = borders; + } + + fn set_joins(&mut self, joins: Borders) { + self.joins = joins; + } +} + +impl InteractableElement for GraphCard { + fn as_any(&self) -> &dyn Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + self + } + + fn as_element(&self) -> &dyn Element { + self + } + + fn as_element_mut(&mut self) -> &mut dyn Element { + self + } + + fn interact(&mut self, _key: KeyEvent) -> InteractionResult { + InteractionResult::Handled + } + + fn can_focus(&self) -> bool { + true + } + + fn is_focused(&self) -> bool { + self.focused + } + + fn focus(&mut self, f: bool) { + self.focused = f; + } +} diff --git a/src/gui/elements/log_card.rs b/src/gui/elements/log_card.rs old mode 100644 new mode 100755 index 27f6a44..fe125c8 --- a/src/gui/elements/log_card.rs +++ b/src/gui/elements/log_card.rs @@ -30,7 +30,7 @@ impl LogCard { pub fn new() -> Self { Self { focused: false, - scroll: 0, + scroll: 1, borders: Borders::ALL, joins: Borders::NONE, } @@ -51,7 +51,9 @@ impl Element for LogCard { let lines: Vec = logs .iter() - .map(|log| Line::from(Span::raw(log.line.clone())).style(log.color)) + .map(|log| { + Line::from(Span::raw(log.line.clone())).style(Style::default().fg(log.color)) + }) .collect(); let block = Block::default() @@ -67,10 +69,17 @@ impl Element for LogCard { Style::default() }); + let inner_height = area.height.saturating_sub(2) as usize; + + let total_lines = lines.len(); + let base_scroll = total_lines.saturating_sub(inner_height) as u16; + + let scroll = base_scroll.saturating_sub(self.scroll); + let paragraph = Paragraph::new(lines) .block(block) .wrap(Wrap { trim: false }) - .scroll((self.scroll, 0)); + .scroll((scroll, 0)); f.render_widget(paragraph, area); draw_block_joins(f, area, self.borders, self.joins); @@ -121,13 +130,17 @@ impl InteractableElement for LogCard { fn interact(&mut self, key: KeyEvent) -> InteractionResult { match key.code { KeyCode::Char('J') | KeyCode::Char('j') => { - if self.scroll > 0 { - self.scroll -= 1; + let state = APP_STATE.lock().unwrap(); + let logs = state.get_logs(); + if self.scroll < logs.len() as u16 { + self.scroll += 1; } InteractionResult::Handled } KeyCode::Char('K') | KeyCode::Char('k') => { - self.scroll += 1; + if self.scroll > 1 { + self.scroll -= 1; + } InteractionResult::Handled } _ => InteractionResult::Unhandled, diff --git a/src/gui/input_handler.rs b/src/gui/input_handler.rs index d499f56..d4e0d45 100644 --- a/src/gui/input_handler.rs +++ b/src/gui/input_handler.rs @@ -3,6 +3,7 @@ use crate::gui::ui::{UI, UNIQUE}; use crate::{RELOAD, SHUTDOWN}; use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind, KeyModifiers, poll, read}; use std::sync::Arc; +use std::sync::atomic::Ordering; use std::time::Duration; pub fn setup_input_handler(ui: Arc) { @@ -30,7 +31,7 @@ pub fn setup_input_handler(ui: Arc) { if key_event.kind == KeyEventKind::Press { let uic = ui.clone(); handle_input(key_event, uic).await; - *UNIQUE.write().await = true; + UNIQUE.store(true, Ordering::Relaxed); } } } diff --git a/src/gui/mod.rs b/src/gui/mod.rs index 87c8eec..0dadd8f 100644 --- a/src/gui/mod.rs +++ b/src/gui/mod.rs @@ -1,6 +1,7 @@ pub mod elements { pub mod console_card; pub mod elements; + pub mod graph_card; pub mod log_card; } pub mod screens { diff --git a/src/gui/screens/main_screen.rs b/src/gui/screens/main_screen.rs index 8543451..f0ffe41 100644 --- a/src/gui/screens/main_screen.rs +++ b/src/gui/screens/main_screen.rs @@ -2,6 +2,7 @@ use crate::gui::{ elements::{ console_card::ConsoleCard, elements::{InteractableElement, JoinableElement}, + graph_card::{GRAPHS, GraphCard}, log_card::LogCard, }, interaction_result::InteractionResult, @@ -19,34 +20,49 @@ use ratatui::{ use std::{any::Any, sync::Arc}; pub struct MainScreen { - ui: Arc, elements: Vec>, nav_grid: Vec>>, selected_coords: (usize, usize), + graphs_open: bool, } impl MainScreen { pub async fn new(ui: Arc) -> Self { let mut elements: Vec> = Vec::new(); - let mut nav_grid: Vec>> = Vec::new(); + + let nav_grid = vec![ + vec![Some(0), Some(2)], + vec![Some(1), Some(3)], + vec![None, Some(4)], + ]; let mut log_card = LogCard::new(); log_card.set_borders(Borders::TOP.union(Borders::RIGHT).union(Borders::LEFT)); let mut console_card = ConsoleCard::new("Console", ""); console_card.set_joins(Borders::TOP); + elements.push(Box::new(log_card)); elements.push(Box::new(console_card)); - nav_grid.push(vec![Some(0)]); - nav_grid.push(vec![Some(1)]); + let mut ram_graph = GraphCard::new(ui.clone(), GRAPHS::Ram, "RAM Usage".into()); + ram_graph.set_borders(Borders::TOP.union(Borders::LEFT).union(Borders::RIGHT)); + elements.push(Box::new(ram_graph)); + let mut cpu_graph = GraphCard::new(ui.clone(), GRAPHS::Cpu, "CPU Usage".into()); + cpu_graph.set_borders(Borders::TOP.union(Borders::LEFT).union(Borders::RIGHT)); + cpu_graph.set_joins(Borders::TOP); + elements.push(Box::new(cpu_graph)); + let mut ping_graph = GraphCard::new(ui.clone(), GRAPHS::Ping, "Ping".into()); + ping_graph.set_joins(Borders::TOP); + elements.push(Box::new(ping_graph)); + + let graphs_open = true; let mut screen = MainScreen { - ui, elements, nav_grid, selected_coords: (1, 0), + graphs_open, }; - screen.focus_current(); screen } @@ -101,7 +117,6 @@ impl MainScreen { _ => {} } - // Clamp X to row length if let Some(row) = self.nav_grid.get(y) { if x >= row.len() { x = row.len() - 1; @@ -129,10 +144,6 @@ impl Screen for MainScreen { self } - fn get_ui(&self) -> &Arc { - &self.ui - } - fn render(&self, f: &mut Frame, rect: Rect) { let main_block = Block::default().title("Main").borders(Borders::ALL); f.render_widget(main_block, rect); @@ -142,14 +153,42 @@ impl Screen for MainScreen { horizontal: 1, }); - let chunks = Layout::vertical([Constraint::Min(0), Constraint::Length(3)]).split(inner); + let graphs_width = if self.graphs_open { 30 } else { 2 }; + let main_width = inner.width.saturating_sub(graphs_width); + + let chunks = Layout::default() + .direction(ratatui::layout::Direction::Horizontal) + .constraints([ + Constraint::Length(main_width), + Constraint::Length(graphs_width), + ]) + .split(inner); + let left_chunks = + Layout::vertical([Constraint::Min(0), Constraint::Length(3)]).split(chunks[0]); if let Some(Some(index)) = self.nav_grid.get(0).and_then(|r| r.get(0)) { - self.elements[*index].as_element().render(f, chunks[0]); + self.elements[*index].as_element().render(f, left_chunks[0]); + } + if let Some(Some(index)) = self.nav_grid.get(1).and_then(|r| r.get(0)) { + self.elements[*index].as_element().render(f, left_chunks[1]); } - if let Some(Some(index)) = self.nav_grid.get(1).and_then(|r| r.get(0)) { - self.elements[*index].as_element().render(f, chunks[1]); + let graph_elements: Vec<_> = self + .elements + .iter() + .filter(|el| el.as_any().is::()) + .collect(); + + let graph_chunks = Layout::vertical( + graph_elements + .iter() + .map(|_| Constraint::Length(chunks[1].height / graph_elements.len() as u16)) + .collect::>(), + ) + .split(chunks[1]); + + for (el, area) in graph_elements.iter().zip(graph_chunks.iter()) { + el.as_element().render(f, *area); } } @@ -159,6 +198,15 @@ impl Screen for MainScreen { KeyCode::Down => self.navigate(NavDirection::Down), KeyCode::Left => self.navigate(NavDirection::Left), KeyCode::Right => self.navigate(NavDirection::Right), + KeyCode::Enter | KeyCode::Char(' ') if self.selected_coords.1 == 1 => { + self.graphs_open = !self.graphs_open; + for element in self.elements.iter_mut() { + if let Some(graph) = element.as_any_mut().downcast_mut::() { + graph.set_open(self.graphs_open); + } + } + return InteractionResult::Handled; + } _ => { let (y, x) = self.selected_coords; if let Some(Some(index)) = self.nav_grid.get(y).and_then(|r| r.get(x)) { diff --git a/src/gui/screens/screens.rs b/src/gui/screens/screens.rs index 78f3bee..9676fbb 100644 --- a/src/gui/screens/screens.rs +++ b/src/gui/screens/screens.rs @@ -1,9 +1,9 @@ -use std::{any::Any, sync::Arc}; +use std::any::Any; use crossterm::event::KeyEvent; use ratatui::{Frame, layout::Rect}; -use crate::gui::{interaction_result::InteractionResult, ui::UI}; +use crate::gui::interaction_result::InteractionResult; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum NavDirection { @@ -20,8 +20,6 @@ pub trait Screen: Send + Sync + Any { fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; - fn get_ui(&self) -> &Arc; - fn render(&self, f: &mut Frame, rect: Rect); fn handle_input(&mut self, event: KeyEvent) -> InteractionResult; } diff --git a/src/gui/screens/terms_checker.rs b/src/gui/screens/terms_checker.rs index 804b6bc..7aaa1c0 100644 --- a/src/gui/screens/terms_checker.rs +++ b/src/gui/screens/terms_checker.rs @@ -51,10 +51,6 @@ impl Screen for TermsCheckerScreen { self } - fn get_ui(&self) -> &Arc { - &self.ui - } - fn render(&self, f: &mut Frame, size: Rect) { let mut needed_height = 5; diff --git a/src/gui/screens/terms_updater.rs b/src/gui/screens/terms_updater.rs index 4e553af..7fa95ed 100644 --- a/src/gui/screens/terms_updater.rs +++ b/src/gui/screens/terms_updater.rs @@ -121,10 +121,6 @@ impl Screen for TermsUpdaterScreen { self } - fn get_ui(&self) -> &Arc { - &self.ui - } - fn render(&self, f: &mut Frame, size: Rect) { let mut needed_height = 5; diff --git a/src/gui/tui.rs b/src/gui/tui.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/gui/ui.rs b/src/gui/ui.rs index 50c1d6b..9052ea7 100644 --- a/src/gui/ui.rs +++ b/src/gui/ui.rs @@ -9,16 +9,21 @@ use crossterm::event::KeyEvent; use once_cell::sync::Lazy; use ratatui::{Terminal, backend::CrosstermBackend, init}; use std::{ + collections::VecDeque, io::Stdout, - sync::{Arc, Mutex}, + sync::{ + Arc, Mutex, + atomic::{AtomicBool, Ordering}, + }, time::Duration, }; use tokio::{sync::RwLock, time::Instant}; /// UI state and rendering -pub static UNIQUE: Lazy> = Lazy::new(|| RwLock::new(true)); +pub static UNIQUE: AtomicBool = AtomicBool::new(true); + +pub static FPS: Lazy> = Lazy::new(|| RwLock::new((0.0, 0.0))); -pub static FPS: Lazy> = Lazy::new(|| RwLock::new(0.0)); pub struct UI { pub terminal: Arc>>>, screen: Arc>>>, @@ -27,26 +32,71 @@ pub struct UI { pub fn start_tui() -> Arc { let ui = Arc::new(UI::new()); let uic = ui.clone(); + ACTIVE_TASKS.insert("UI Renderer".to_string()); tokio::spawn(async move { - ACTIVE_TASKS.insert("UI Renderer".to_string()); let mut last_render = Instant::now(); - let mut last: Vec = Vec::new(); + + let mut fps_samples: VecDeque = VecDeque::with_capacity(20); + let mut skip_samples: VecDeque = VecDeque::with_capacity(20); + + let mut fps_sum = 0.0; + let mut skip_sum: u32 = 0; + + let mut skipped = 0; + loop { if *SHUTDOWN.read().await { break; } - if *UNIQUE.read().await { + if skipped > 5 || UNIQUE.load(Ordering::Relaxed) { uic.render().await; + + skip_samples.push_back(skipped); + skip_sum += skipped as u32; + + if skip_samples.len() > 20 { + if let Some(old) = skip_samples.pop_front() { + skip_sum -= old as u32; + } + } + + skipped = 0; + let elapsed = last_render.elapsed().as_secs_f64(); if elapsed > 0.0 { - last.push(1.0 / elapsed); + let fps = 1.0 / elapsed; + + fps_samples.push_back(fps); + fps_sum += fps; + + if fps_samples.len() > 20 { + if let Some(old) = fps_samples.pop_front() { + fps_sum -= old; + } + } } - if last.len() > 10 { - last.remove(0); - } - *FPS.write().await = last.iter().sum::() / last.len() as f64; + + let avg_fps = if !fps_samples.is_empty() { + fps_sum / fps_samples.len() as f64 + } else { + 0.0 + }; + + let avg_skips_percentage = if !skip_samples.is_empty() { + let avg_skipped = skip_sum as f64 / skip_samples.len() as f64; + let total_iterations = avg_skipped + 1.0; + (avg_skipped / total_iterations) * 100.0 + } else { + 0.0 + }; + + *FPS.write().await = (avg_fps, avg_skips_percentage); + last_render = Instant::now(); + UNIQUE.store(false, Ordering::Relaxed); + } else { + skipped += 1; } tokio::time::sleep(Duration::from_millis(16)).await; } diff --git a/src/main.rs b/src/main.rs index 082f7db..800414e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,7 +40,7 @@ pub static SHUTDOWN: Lazy> = Lazy::new(|| RwLock::new(false)); pub static RELOAD: Lazy> = Lazy::new(|| RwLock::new(true)); pub static ACTIVE_TASKS: Lazy> = Lazy::new(|| DashSet::new()); -#[tokio::main(flavor = "multi_thread", worker_threads = 8)] +#[tokio::main(flavor = "multi_thread", worker_threads = 16)] #[allow(unused_must_use, dead_code)] async fn main() { while *RELOAD.read().await { @@ -57,7 +57,7 @@ async fn main() { if ACTIVE_TASKS.is_empty() { break; } - sleep(Duration::from_secs(1)).await; + sleep(Duration::from_millis(100)).await; } println!("You need to accept our End User Licence Agreement before launching!"); println!("You can find this at 'agreements'!"); @@ -176,7 +176,7 @@ async fn main() { if !omikron.is_connected().await { break; } - sleep(Duration::from_secs(1)).await; + sleep(Duration::from_millis(100)).await; } } if *RELOAD.read().await { diff --git a/src/util/logger.rs b/src/util/logger.rs index 700f4d2..c6a57c2 100644 --- a/src/util/logger.rs +++ b/src/util/logger.rs @@ -2,7 +2,7 @@ use std::{ fs::{self, OpenOptions}, io::Write, path::Path, - sync::{OnceLock, mpsc}, + sync::{OnceLock, atomic::Ordering, mpsc}, thread, time::{SystemTime, UNIX_EPOCH}, }; @@ -122,9 +122,7 @@ pub fn log_internal_translated( args: Vec, ) { if let Some(tx) = LOGGER.get() { - tokio::spawn(async move { - *UNIQUE.write().await = true; - }); + UNIQUE.store(true, Ordering::Relaxed); let _ = tx.send(LogMessage { timestamp_ms: SystemTime::now() .duration_since(UNIX_EPOCH) @@ -142,9 +140,7 @@ pub fn log_internal_translated( pub fn log_internal(kind: PrintType, prefix: String, is_error: bool, message: String) { if let Some(tx) = LOGGER.get() { - tokio::spawn(async move { - *UNIQUE.write().await = true; - }); + UNIQUE.store(true, Ordering::Relaxed); let _ = tx.send(LogMessage { timestamp_ms: SystemTime::now() .duration_since(UNIX_EPOCH)