diff --git a/src/app.rs b/src/app.rs index d45c97c..978f944 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,25 +1,54 @@ +use std::sync::mpsc::{channel, Receiver, Sender}; +use std::sync::Arc; + use anyhow::Result; use threadpool::ThreadPool; -use crate::pipeline::Server; +use crate::pipeline::{Message, Server}; use crate::tui::Tui; pub struct App { tpool: ThreadPool, - server: Server, - ui: Tui, + server: Arc, } impl App { pub fn new() -> Self { Self { tpool: ThreadPool::new(8), - server: Server::new().expect("server init failed"), - ui: Tui {}, + server: Arc::new(Server::new().expect("server init failed")), } } - pub fn start() -> Result<()> { + pub fn start(&self) -> Result<()> { + let (server_tx, server_rx) = channel::(); + let (app_tx, app_rx) = channel::(); + + let server_ptr = self.server.clone(); + let ui = Tui::new(app_tx); + + self.tpool.execute(move || { + server_ptr.start(server_rx).expect("server init failed"); + }); + + self.tpool.execute(move || { + ui.start().expect("ui init failed"); + }); + + self.tpool.execute(move || loop { + match app_rx.try_recv() { + Ok(Message::Exit) => { + server_tx + .send(Message::Exit) + .expect("message passing to app from ui failed"); + break; + } + _ => continue, + } + }); + + self.tpool.join(); + Ok(()) } } diff --git a/src/main.rs b/src/main.rs index b750b72..3235fab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,10 @@ +mod app; mod fileinfo; mod formatter; mod interactive; mod params; mod processor; mod scanner; -mod app; /* version 2.0 modules*/ mod cli; @@ -12,15 +12,15 @@ mod pipeline; mod tui; use anyhow::Result; + +use self::app::App; // use clap::Parser; // use formatter::Formatter; // use params::Params; // use processor::Processor; // use scanner::Scanner; -use pipeline::Server; fn main() -> Result<()> { - let server = Server::new(); // let app_args = Params::parse(); // let scan_results = Scanner::build(&app_args)?.scan()?; // let processor = Processor::new(scan_results); @@ -31,5 +31,7 @@ fn main() -> Result<()> { // true => interactive::init(results.files, &app_args)?, // } + App::new().start().expect("app init failed."); + Ok(()) } diff --git a/src/pipeline/mod.rs b/src/pipeline/mod.rs index 45aa53f..0bee002 100644 --- a/src/pipeline/mod.rs +++ b/src/pipeline/mod.rs @@ -1,8 +1,8 @@ mod file; +mod flags; mod processor; mod scanner; mod store; -mod flags; use anyhow::{anyhow, Result}; use std::collections::HashMap; @@ -22,6 +22,7 @@ pub type FileQueue = Arc>>>; pub enum Message { AddScanDirectory(Box), Exit, + None, } pub struct Server { @@ -62,6 +63,7 @@ impl Server { .send(Message::AddScanDirectory(path)) .unwrap_or_default(); } + Ok(Message::None) => {} Ok(Message::Exit) | Err(_) => { scanner_tx.send(Message::Exit).unwrap_or_default(); processor_tx.send(Message::Exit).unwrap_or_default(); diff --git a/src/pipeline/scanner.rs b/src/pipeline/scanner.rs index 64c6001..a2ba53d 100644 --- a/src/pipeline/scanner.rs +++ b/src/pipeline/scanner.rs @@ -31,7 +31,7 @@ impl Scanner { let mut mfq = self.proc_queue.lock().unwrap(); mfq.push(path); } - Err(mpsc::TryRecvError::Empty) => {} + Err(mpsc::TryRecvError::Empty) | Ok(Message::None) => {} Ok(Message::Exit) | Err(_) => break, } diff --git a/src/tui/mod.rs b/src/tui/mod.rs index a7ca828..24bd42a 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -1,7 +1,70 @@ -pub struct Tui { +use std::sync::mpsc::Sender; +use std::time::Duration; -}; +use anyhow::{Context, Result}; +use ratatui::crossterm::event::{self, Event, KeyCode}; +use ratatui::widgets::Paragraph; +use ratatui::{DefaultTerminal, Frame}; + +use crate::pipeline::Message; + +pub struct Tui { + app_tx: Sender, +} impl Tui { - pub fn init(&self) { } + pub fn new(app_tx: Sender) -> Self { + Self { app_tx } + } + + pub fn start(&self) -> Result<()> { + let terminal = ratatui::init(); + self.run(terminal).expect("ui loop failed."); + ratatui::restore(); + + Ok(()) + } + + fn poll_events() -> Result { + match event::poll(Duration::from_millis(250)).context("event polling failed.")? { + true => match event::read().context("event read failed.")? { + Event::Key(key) => match key.code { + KeyCode::Char('q') => Ok(Message::Exit), + _ => Ok(Message::None), + }, + _ => Ok(Message::None), + }, + false => Ok(Message::None), + } + } + + fn handle_events(&self) -> Result { + let handleable_event = Self::poll_events(); + + match Self::poll_events() { + Ok(Message::Exit) => { + self.app_tx + .send(Message::Exit) + .expect("app event send failed."); + Ok(Message::Exit) + } + _ => Ok(Message::None), + } + } + + fn draw(frame: &mut Frame) { + frame.render_widget(Paragraph::new("Hello, World"), frame.area()); + } + + fn run(&self, mut terminal: DefaultTerminal) -> Result<()> { + loop { + terminal.draw(Self::draw)?; + match self.handle_events() { + Ok(Message::Exit) => break, + _ => {} + } + } + + Ok(()) + } }