From 16514b7d1a43db82954ebebea89656dd38881e08 Mon Sep 17 00:00:00 2001 From: plazmoid Date: Sun, 23 Jan 2022 15:40:40 +0500 Subject: [PATCH] i realized that arch is shitty so switch to web frontend --- bin/u_panel/src/tui/mod.rs | 29 +++++---- bin/u_panel/src/tui/retval.rs | 25 ------- bin/u_panel/src/tui/utils.rs | 20 ++---- bin/u_panel/src/tui/windows/confirm.rs | 61 +++++++---------- bin/u_panel/src/tui/windows/main_wnd.rs | 34 ++++------ bin/u_panel/src/tui/windows/mod.rs | 87 +++++++++++++------------ lib/u_lib/src/builder.rs | 13 +++- lib/u_lib/src/errors/variants.rs | 2 +- 8 files changed, 118 insertions(+), 153 deletions(-) delete mode 100644 bin/u_panel/src/tui/retval.rs diff --git a/bin/u_panel/src/tui/mod.rs b/bin/u_panel/src/tui/mod.rs index 5cd9942..80b0a08 100644 --- a/bin/u_panel/src/tui/mod.rs +++ b/bin/u_panel/src/tui/mod.rs @@ -1,5 +1,4 @@ mod impls; -mod retval; mod utils; mod windows; @@ -12,7 +11,6 @@ use crossterm::terminal::{ disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, }; use once_cell::sync::Lazy; -use retval::{RetVal, ReturnValue}; use std::{ env, io::{stdout, Stdout}, @@ -24,15 +22,14 @@ use std::{ }; use tui::{backend::CrosstermBackend, Terminal}; use utils::{AsyncChannel, Channel}; -use windows::{MainWnd, SharedWnd, WindowsHandler, WndId}; +use windows::{MainWnd, SharedWnd, WndId, WM}; pub type Backend = CrosstermBackend; pub type Frame<'f> = tui::Frame<'f, Backend>; -const EVENT_GEN_PERIOD: Duration = Duration::from_millis(120); +const EVENT_GEN_PERIOD: Duration = Duration::from_millis(70); static GENERAL_EVENT_CHANNEL: Lazy> = Lazy::new(|| Channel::new()); - static ACTIVE_LOOP: AtomicBool = AtomicBool::new(true); enum GEvent { @@ -49,10 +46,10 @@ fn get_terminal() -> AResult> { } pub async fn init_tui(args: &TUIArgs) -> AResult<()> { + let gui = !args.nogui; init_logger(); info!("Initializing u_panel"); - let gui = !args.nogui; init_signal_handlers(gui); init_panic_handler(gui); term_setup(gui)?; @@ -67,15 +64,18 @@ pub async fn init_tui(args: &TUIArgs) -> AResult<()> { async fn init_loop(args: &TUIArgs) -> AResult<()> { let gui = !args.nogui; if gui { - WindowsHandler::lock().await.clear()?; + WM::lock().await.clear()?; } - WindowsHandler::lock().await.push_new::().await; + WM::lock().await.push_new::().await; thread::spawn(move || { while is_running() { if event::poll(EVENT_GEN_PERIOD).unwrap() { match event::read().unwrap() { - Event::Key(key) => GENERAL_EVENT_CHANNEL.send(GEvent::Key(key.code)), + Event::Key(key) => { + GENERAL_EVENT_CHANNEL.send(GEvent::Key(key.code)); + GENERAL_EVENT_CHANNEL.send(GEvent::Tick); + } _ => (), } } else { @@ -87,25 +87,25 @@ async fn init_loop(args: &TUIArgs) -> AResult<()> { while is_running() { match GENERAL_EVENT_CHANNEL.recv() { GEvent::Tick => { - let mut wh = WindowsHandler::lock().await; + let mut wh = WM::lock().await; wh.update().await?; if gui { wh.draw().await?; } } GEvent::CloseWnd { wid, force } => { - WindowsHandler::lock().await.close(wid, force).await; + WM::lock().await.close(wid, force).await; } GEvent::Key(key) => { info!(?key, "pressed"); if let KeyCode::Char('q') = key { break_global(); } else { - WindowsHandler::lock().await.send_handle_kbd(key).await; + WM::lock().await.send_handle_kbd(key).await; } } GEvent::CreateWnd(wnd) => { - WindowsHandler::lock().await.push_dyn(wnd).await; + WM::lock().await.push_dyn(wnd).await; } GEvent::Exit => { break_global(); @@ -163,7 +163,8 @@ fn init_logger() { fn init_panic_handler(gui: bool) { set_hook(Box::new(move |panic_info| { term_teardown(gui).ok(); - eprintln!("{}\n{:?}", panic_info, Backtrace::new()); + eprintln!("CRITICAL PANIK ENCOUNTRD OMFG!11! go see logz lul"); + error!("{}\n{:?}", panic_info, Backtrace::new()); exit(254); })); } diff --git a/bin/u_panel/src/tui/retval.rs b/bin/u_panel/src/tui/retval.rs deleted file mode 100644 index 3874dfc..0000000 --- a/bin/u_panel/src/tui/retval.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::tui::Channel; -use once_cell::sync::Lazy; -use std::any::{type_name, Any}; - -type RV = Box; -static RETVAL: Lazy> = Lazy::new(|| Channel::new()); - -pub struct ReturnValue; - -impl ReturnValue { - pub fn set(t: RV) { - RETVAL.send(t); - } - - pub fn get() -> Box { - RETVAL - .recv() - .downcast::() - .expect(&format!("wrong type {}", type_name::())) - } -} - -pub trait RetVal { - fn retval(&self) -> RV; -} diff --git a/bin/u_panel/src/tui/utils.rs b/bin/u_panel/src/tui/utils.rs index e8e8542..6b508be 100644 --- a/bin/u_panel/src/tui/utils.rs +++ b/bin/u_panel/src/tui/utils.rs @@ -1,5 +1,6 @@ use async_channel::{ - unbounded as unbounded_async, Receiver as AsyncReceiver, Sender as AsyncSender, + unbounded as unbounded_async, Receiver as AsyncReceiver, RecvError, SendError, + Sender as AsyncSender, }; use crossbeam::channel::{unbounded, Receiver, Sender}; @@ -21,10 +22,6 @@ impl Channel { pub fn recv(&self) -> T { self.rx.recv().unwrap() } - - pub fn is_empty(&self) -> bool { - self.rx.is_empty() - } } impl Default for Channel { @@ -33,6 +30,7 @@ impl Default for Channel { } } +#[derive(Clone)] pub struct AsyncChannel { pub tx: AsyncSender, pub rx: AsyncReceiver, @@ -44,16 +42,12 @@ impl AsyncChannel { Self { tx, rx } } - pub async fn send(&self, msg: T) { - self.tx.send(msg).await.unwrap() - } - - pub async fn recv(&self) -> T { - self.rx.recv().await.unwrap() + pub async fn send(&self, msg: T) -> Result<(), SendError> { + self.tx.send(msg).await } - pub fn is_empty(&self) -> bool { - self.rx.is_empty() + pub async fn recv(&self) -> Result { + self.rx.recv().await } } diff --git a/bin/u_panel/src/tui/windows/confirm.rs b/bin/u_panel/src/tui/windows/confirm.rs index 8272ffa..319c10c 100644 --- a/bin/u_panel/src/tui/windows/confirm.rs +++ b/bin/u_panel/src/tui/windows/confirm.rs @@ -1,14 +1,10 @@ -use super::{Window, WndId}; -use crate::tui::{ - windows::WndEvent, AsyncChannel, Frame, GEvent, RetVal, ReturnValue, GENERAL_EVENT_CHANNEL, -}; +use super::{ReturnVal, Window, WndId}; +use crate::tui::Frame; use anyhow::Result as AResult; use crossterm::event::KeyCode; -use once_cell::sync::OnceCell; -use std::any::Any; use tui::layout::{Alignment, Constraint, Direction, Layout, Rect}; -use tui::style::{Modifier, Style}; -use tui::widgets::{Block, Clear, List, ListItem, ListState, Paragraph}; +use tui::style::{Color, Modifier, Style}; +use tui::widgets::{Block, Borders, Clear, List, ListItem, ListState, Paragraph}; #[derive(Default)] pub struct ConfirmWnd { @@ -19,15 +15,15 @@ pub struct ConfirmWnd { } impl ConfirmWnd { - pub fn new_yn(msg: impl Into, variants: Option>) -> Self { - let default = vec!["Yes".to_string(), "No".to_string()]; - let variants = match variants { - Some(v) if !v.is_empty() => v, - _ => default, + pub fn new(msg: impl Into, variants: &[&str]) -> Self { + let variants = if !variants.is_empty() { + variants + } else { + &["Yes", "No"] }; let mut this = Self { msg: msg.into(), - variants, + variants: variants.into_iter().map(|s| s.to_string()).collect(), ..Default::default() }; this.state.select(Some(0)); @@ -48,24 +44,14 @@ impl ConfirmWnd { } } -impl RetVal for ConfirmWnd { - fn retval(&self) -> Box { - let value = self - .variants - .get(self.state.selected().unwrap()) - .unwrap() - .to_owned(); - Box::new(value) - } -} - #[async_trait] impl Window for ConfirmWnd { async fn handle_kbd(&mut self, k: KeyCode) -> AResult<()> { match k { KeyCode::Right => self.on_right(), KeyCode::Left => self.on_left(), - KeyCode::Enter | KeyCode::Esc => self.close(false).await, + KeyCode::Enter => self.close(false, true).await, + KeyCode::Esc => self.close(false, false).await, _ => (), } Ok(()) @@ -82,10 +68,13 @@ impl Window for ConfirmWnd { fn draw(&mut self, f: &mut Frame) { let size = f.size(); let rect = centered_rect(60, 40, size); + let popup = Block::default().title("Popup").borders(Borders::ALL); + f.render_widget(Clear, rect); + f.render_widget(popup, rect); let chunks = Layout::default() .direction(Direction::Vertical) - .constraints(vec![Constraint::Percentage(70), Constraint::Percentage(30)]) + .constraints(vec![Constraint::Percentage(40), Constraint::Percentage(30)]) .split(rect); let msg = Paragraph::new(self.msg.as_ref()); f.render_widget(msg, chunks[0]); @@ -97,22 +86,20 @@ impl Window for ConfirmWnd { .map(ListItem::new) .collect::>(); let list = - List::new(options).highlight_style(Style::default().add_modifier(Modifier::BOLD)); + List::new(options).highlight_style(Style::default().bg(Color::Gray).fg(Color::Black)); f.render_stateful_widget(list, chunks[1], &mut self.state); } - fn get_chan(&self) -> &'static AsyncChannel { - static EV_CHAN: OnceCell> = OnceCell::new(); - EV_CHAN.get_or_init(|| AsyncChannel::new()) + fn retval(&self) -> ReturnVal { + let value = self + .variants + .get(self.state.selected().unwrap()) + .unwrap() + .to_owned(); + ReturnVal::String(value) } } -pub async fn confirm_wnd(msg: impl Into) -> String { - let wnd = ConfirmWnd::new_yn(msg.into(), None); - GENERAL_EVENT_CHANNEL.send(GEvent::CreateWnd(wnd.into_shared())); - *ReturnValue::get() -} - fn centered_rect(percent_x: u16, percent_y: u16, r: Rect) -> Rect { let popup_layout = Layout::default() .direction(Direction::Vertical) diff --git a/bin/u_panel/src/tui/windows/main_wnd.rs b/bin/u_panel/src/tui/windows/main_wnd.rs index 1a7c40a..d6494ee 100644 --- a/bin/u_panel/src/tui/windows/main_wnd.rs +++ b/bin/u_panel/src/tui/windows/main_wnd.rs @@ -1,13 +1,7 @@ -use super::{confirm_wnd, Window}; -use crate::tui::{ - impls::CRUD, - windows::{WndEvent, WndId}, - AsyncChannel, Frame, RetVal, -}; +use super::{ConfirmWnd, ReturnVal, Window}; +use crate::tui::{impls::CRUD, windows::WndId, Frame}; use anyhow::Result as AResult; use crossterm::event::KeyCode; -use once_cell::sync::OnceCell; -use std::any::Any; use std::{fmt::Display, str::FromStr}; use strum::VariantNames; use tokio::join; @@ -205,6 +199,7 @@ impl MainWnd { UiTabs::Agents => { self.agents.updated = false; self.jobs.updated = false; + self.map.updated = false; } UiTabs::Jobs => self.jobs.updated = false, UiTabs::Map => self.map.updated = false, @@ -255,15 +250,19 @@ impl MainWnd { impl Window for MainWnd { async fn handle_kbd(&mut self, k: KeyCode) -> AResult<()> { match k { - KeyCode::Esc => self.close(false).await, + KeyCode::Esc => self.close(false, false).await, KeyCode::Left => self.prev_tab(), KeyCode::Right => self.next_tab(), KeyCode::Up => self.on_up(), KeyCode::Down => self.on_down(), KeyCode::Delete => { - if &confirm_wnd("Delete?").await == "Yes" { - self.delete().await; - self.update_tab(); + if let ReturnVal::String(ref s) = + ConfirmWnd::new("Delete?", &["Yes", "No"]).wait_retval() + { + if s == "Yes" { + self.delete().await; + self.update_tab(); + } } } KeyCode::F(5) => self.update_tab(), @@ -316,15 +315,8 @@ impl Window for MainWnd { f.render_stateful_widget(list, chunks[1], self.tab_list_state()); } - fn get_chan(&self) -> &'static AsyncChannel { - static EV_CHAN: OnceCell> = OnceCell::new(); - EV_CHAN.get_or_init(|| AsyncChannel::new()) - } -} - -impl RetVal for MainWnd { - fn retval(&self) -> Box { - Box::new(()) + fn retval(&self) -> ReturnVal { + ReturnVal::None } } diff --git a/bin/u_panel/src/tui/windows/mod.rs b/bin/u_panel/src/tui/windows/mod.rs index c4b18a5..ec86b3f 100644 --- a/bin/u_panel/src/tui/windows/mod.rs +++ b/bin/u_panel/src/tui/windows/mod.rs @@ -1,30 +1,34 @@ mod confirm; mod main_wnd; -use async_channel::Sender; -pub use confirm::{confirm_wnd, ConfirmWnd}; +pub use confirm::ConfirmWnd; pub use main_wnd::MainWnd; use crate::tui::{ - get_terminal, impls::Id, AsyncChannel, Backend, Frame, GEvent, RetVal, ReturnValue, - GENERAL_EVENT_CHANNEL, + get_terminal, impls::Id, AsyncChannel, Backend, Channel, Frame, GEvent, GENERAL_EVENT_CHANNEL, }; use anyhow::Result as AResult; use crossterm::event::KeyCode; use once_cell::sync::{Lazy, OnceCell}; use std::collections::BTreeMap; -use std::sync::Arc; -use std::sync::{Mutex as StdMutex, MutexGuard as StdMutexGuard}; +use std::sync::{Arc, Mutex as StdMutex, MutexGuard as StdMutexGuard}; use tokio::sync::{Mutex, MutexGuard}; use tokio::task::{self, JoinHandle}; use tui::Terminal; -static WINDOWS: Lazy>> = - Lazy::new(|| Arc::new(Mutex::new(WindowsHandler::new(get_terminal().unwrap())))); +static WINDOWS: Lazy>> = + Lazy::new(|| Arc::new(Mutex::new(WM::new(get_terminal().unwrap())))); static LAST_WND_ID: OnceCell> = OnceCell::new(); +static RETVAL: Lazy> = Lazy::new(|| Channel::new()); + pub type SharedWnd = Arc>; +pub enum ReturnVal { + String(String), + None, +} + #[derive(Clone, Debug)] pub enum WndEvent { Key(KeyCode), @@ -51,7 +55,7 @@ impl Default for WndId { } #[async_trait] -pub trait Window: Id + RetVal + Send { +pub trait Window: Id + Send { async fn handle_event(&mut self, ev: WndEvent) { match ev { WndEvent::Key(k) => { @@ -60,22 +64,27 @@ pub trait Window: Id + RetVal + Send { } } - async fn close(&mut self, force: bool) { - let rv = self.retval(); - ReturnValue::set(rv); + async fn close(&mut self, force: bool, save_retval: bool) { + let rv = if save_retval { + self.retval() + } else { + ReturnVal::None + }; + RETVAL.send(rv); GENERAL_EVENT_CHANNEL.send(GEvent::CloseWnd { wid: self.id(), force, }); } - fn get_chan(&self) -> &'static AsyncChannel; + fn retval(&self) -> ReturnVal; - fn into_shared(self) -> SharedWnd + fn wait_retval(self) -> ReturnVal where Self: Sized + 'static, { - Arc::new(Mutex::new(self)) + GENERAL_EVENT_CHANNEL.send(GEvent::CreateWnd(Arc::new(Mutex::new(self)))); + RETVAL.recv() } async fn handle_update(&mut self) -> AResult<()>; @@ -88,27 +97,28 @@ pub trait Window: Id + RetVal + Send { } pub struct WndLoop { - upd_tx: Sender, - updater: JoinHandle<()>, + chan: AsyncChannel, + wnd_loop: JoinHandle<()>, window: SharedWnd, } impl WndLoop { pub async fn with_wnd(window: SharedWnd) -> Self { let wnd = window.clone(); - let AsyncChannel { tx, rx } = wnd.lock().await.get_chan(); + let chan = AsyncChannel::::new(); + let ch = chan.clone(); let wnd_loop = async move { loop { - match rx.recv().await { + match ch.recv().await { Ok(ev) => wnd.lock().await.handle_event(ev).await, Err(_) => break, } } }; WndLoop { - upd_tx: tx.clone(), + chan, window, - updater: task::spawn(wnd_loop), + wnd_loop: task::spawn(wnd_loop), } } @@ -116,17 +126,16 @@ impl WndLoop { let wnd_id = self.window.lock().await.id(); let event = ev.clone(); debug!(?event, ?wnd_id, "sending"); - self.upd_tx.send(ev).await.expect("big zhopa"); + self.chan.send(ev).await.expect("send failed"); } } -pub struct WindowsHandler { +pub struct WM { queue: BTreeMap, term: Terminal, - redraw_all: bool, } -impl WindowsHandler { +impl WM { fn get_last_wnd(&self) -> &WndLoop { let last_id = self.queue.keys().rev().next().expect("No windows found"); self.queue.get(last_id).unwrap() @@ -140,12 +149,11 @@ impl WindowsHandler { Self { term, queue: BTreeMap::new(), - redraw_all: true, } } pub async fn push(&mut self, window: W) -> SharedWnd { - self.push_dyn(window.into_shared()).await + self.push_dyn(Arc::new(Mutex::new(window))).await } pub async fn push_new(&mut self) -> SharedWnd { @@ -165,17 +173,17 @@ impl WindowsHandler { } pub async fn draw(&mut self) -> AResult<()> { - let wids_to_redraw = if self.redraw_all { - self.redraw_all = false; - self.queue.keys().collect::>() - } else { - vec![self.queue.keys().last().unwrap()] - }; - for wid in wids_to_redraw { + for wid in self.queue.keys().collect::>() { let mut wnd_locked = match self.queue.get(&wid) { - Some(w) => w.window.lock().await, + Some(w) => match w.window.try_lock() { + Ok(w) => w, + Err(_) => { + warn!("Can't lock window {:?}", wid); + continue; + } + }, None => { - eprintln!("Can't redraw window {:?}, not found", wid); + warn!("Can't redraw window {:?}, not found", wid); continue; } }; @@ -188,14 +196,13 @@ impl WindowsHandler { let wnd = match self.queue.get(&wid) { Some(w) => w.clone(), None => { - eprintln!("Can't close window {:?}, not found", wid); + warn!("Can't close window {:?}, not found", wid); return; } }; if wnd.window.lock().await.handle_close().await || force { - let WndLoop { updater, .. } = self.queue.remove(&wid).unwrap(); - updater.abort(); - self.redraw_all = true; + let WndLoop { wnd_loop, .. } = self.queue.remove(&wid).unwrap(); + wnd_loop.abort(); } if self.queue.is_empty() { diff --git a/lib/u_lib/src/builder.rs b/lib/u_lib/src/builder.rs index e6ce08f..746cc12 100644 --- a/lib/u_lib/src/builder.rs +++ b/lib/u_lib/src/builder.rs @@ -1,4 +1,13 @@ -use crate::{UError, UErrorBt, UResult, cache::JobCache, executor::{Waiter, DynFut}, messaging::Reportable, models::{Agent, AssignedJob, JobMeta, JobType}, utils::{CombinedResult, OneOrVec}}; +use crate::{ + UError, + UErrorBt, + UResult, + cache::JobCache, + executor::{Waiter, DynFut}, + messaging::Reportable, + models::{Agent, AssignedJob, JobMeta, JobType}, + utils::{CombinedResult, OneOrVec} +}; use guess_host_triple::guess_host_triple; use std::collections::HashMap; @@ -6,7 +15,7 @@ pub struct JobBuilder { waiter: Waiter, } -impl JobBuilder { +impl JobBuilder { pub fn from_request(job_requests: impl OneOrVec) -> CombinedResult { let job_requests = job_requests.into_vec(); let mut prepared: Vec = vec![]; diff --git a/lib/u_lib/src/errors/variants.rs b/lib/u_lib/src/errors/variants.rs index d84db3a..48d2fbb 100644 --- a/lib/u_lib/src/errors/variants.rs +++ b/lib/u_lib/src/errors/variants.rs @@ -66,7 +66,7 @@ pub enum UError { #[error("Panicked: {0}")] Panic(String), - #[error("UI init error: {0}")] + #[error("UI error: {0}")] TUIError(String), }