diff --git a/src/controller.rs b/src/controller.rs index cea687c..d5b6e0c 100644 --- a/src/controller.rs +++ b/src/controller.rs @@ -1,10 +1,9 @@ use crate::model::config::Config; -use crate::model::{AppState, Service, ServiceStatus}; +use crate::model::{AppState, Service, ServiceStatus, SmError, SmResult}; use crate::{view, App}; use crossterm::event; use crossterm::event::{Event, KeyCode}; use std::collections::HashMap; -use std::ffi::OsString; use std::io; use std::io::{ErrorKind, Read, Write}; use std::process::{Child, Command, Stdio}; @@ -18,7 +17,7 @@ const STDOUT_SEND_BUF_SIZE: usize = 512; pub type StdoutSendBuf = ([u8; STDOUT_SEND_BUF_SIZE], usize); -pub fn run_app(terminal: &mut Terminal, mut app: App) -> io::Result<()> { +pub fn run_app(terminal: &mut Terminal, mut app: App) -> SmResult { loop { terminal.draw(|f| view::render_ui(f, &mut app))?; @@ -30,7 +29,7 @@ pub fn run_app(terminal: &mut Terminal, mut app: App) -> io::Resu Some(_) => app.leave_service(), None => break, }, - KeyCode::Char('r') => app.run_service(), + KeyCode::Char('r') => app.run_service()?, KeyCode::Down => app.next(), KeyCode::Up => app.previous(), KeyCode::Enter => app.select_service(), @@ -87,19 +86,6 @@ impl App { for service in self.table.services.iter_mut() { while let Ok((buf, n)) = service.stdout_recv.try_recv() { service.stdout_buf.extend_from_slice(&buf[0..n]); - - std::fs::write( - format!( - "debug/received_something_{}_{}.txt", - &service.name, - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_millis() - ), - &service.stdout_buf, - ) - .expect("debug failed fuck"); } } } @@ -144,25 +130,26 @@ impl App { self.table.table_state.select(Some(i)); } - fn run_service(&mut self) { + fn run_service(&mut self) -> SmResult { if let Some(selected) = self.selected { self.start_service(selected) } else if let Some(selected) = self.table.table_state.selected() { self.start_service(selected) + } else { + Ok(()) } } - fn start_service(&mut self, service: usize) { + fn start_service(&mut self, service: usize) -> SmResult { let service = &mut self.table.services[service]; - *service.status.lock().expect("service.status lock poisoned") = ServiceStatus::Running; + *service.status.lock()? = ServiceStatus::Running; let stdout_send = service .stdout_send - .lock() - .expect("stdout_send lock poisoned") + .lock()? .take() - .expect("stdout_send has been stolen"); + .ok_or(SmError::StdioStolen)?; let mut cmd = Command::new("sh"); @@ -178,12 +165,14 @@ impl App { let mut buf = [0; STDOUT_SEND_BUF_SIZE]; let bytes = err.to_string(); - (&mut buf[..]).write_all(bytes.as_bytes()).expect("dont"); + + (&mut buf[..]).write_all(bytes.as_bytes())?; stdout_send .send((buf, bytes.len())) - .expect("failed to send stdout"); - return; + .map_err(|_| SmError::FailedToSendStdio)?; + + return Err(SmError::FailedToStartChild(err)); } Ok(child) => child, }; @@ -196,6 +185,8 @@ impl App { Ok(_) => {} Err(e) => std::fs::write("error.txt", e.to_string()).unwrap(), }); + + Ok(()) } } fn child_process_thread( @@ -217,18 +208,6 @@ fn child_process_thread( match stdout.read(&mut stdout_buf) { Ok(0) => continue, Ok(n) => { - // std::fs::write( - // format!( - // "debug/read_something_{}.txt", - // std::time::SystemTime::now() - // .duration_since(std::time::UNIX_EPOCH) - // .unwrap() - // .as_millis() - // ), - // &stdout_buf, - // ) - // .ok(); - stdout_send .send((stdout_buf, n)) .map_err(|_| io::Error::from(io::ErrorKind::Other))?; diff --git a/src/main.rs b/src/main.rs index 432b5df..cd9e03a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,7 @@ use crossterm::execute; use crossterm::terminal::{ disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, }; -use std::io::{ErrorKind, Read, StdoutLock}; -use std::process::Stdio; -use std::time::Duration; +use std::io::StdoutLock; use std::{env, fs, io}; use tui::backend::CrosstermBackend; use tui::Terminal; @@ -44,7 +42,10 @@ or use the environment variable SERVICE_MANAGER_CONFIG_PATH" let stdout = io::stdout(); let stdout = stdout.lock(); - let mut terminal = setup_terminal(stdout).expect("failed to setup terminal"); + let mut terminal = setup_terminal(stdout).unwrap_or_else(|e| { + eprintln!("error: failed to setup terminal: {}", e); + std::process::exit(1); + }); // create app and run it let app = App::new(config); @@ -53,7 +54,7 @@ or use the environment variable SERVICE_MANAGER_CONFIG_PATH" let res = controller::run_app(&mut terminal, app); if let Err(err) = res { - println!("{:?}", err) + println!("error: {}", err) } } diff --git a/src/model.rs b/src/model.rs index d484db3..aef3baa 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,12 +1,11 @@ use crate::controller::StdoutSendBuf; use std::collections::HashMap; -use std::ffi::OsString; -use std::io; -use std::io::Error; use std::path::PathBuf; use std::sync::{mpsc, Mutex}; use tui::widgets::TableState; +pub use error::{SmError, SmResult}; + #[derive(Debug)] pub struct App { pub table: AppState, @@ -55,16 +54,44 @@ pub mod config { pub env: Option>, } } +mod error { + use std::fmt::{Display, Formatter}; + use std::io; + use std::sync::PoisonError; -pub type SmResult = Result<(), SmError>; + pub type SmResult = Result<(), SmError>; -pub enum SmError { - Io(io::Error), - MutexPoisoned, -} + pub enum SmError { + Io(io::Error), + FailedToStartChild(io::Error), + MutexPoisoned, + StdioStolen, + FailedToSendStdio, + } -impl From for SmError { - fn from(e: Error) -> Self { - Self::Io(e) + impl From for SmError { + fn from(e: io::Error) -> Self { + Self::Io(e) + } + } + + impl From> for SmError { + fn from(_: PoisonError) -> Self { + Self::MutexPoisoned + } + } + + impl Display for SmError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Io(e) => Display::fmt(e, f), + SmError::MutexPoisoned => f.write_str("Mutex was poisoned. This is a bug."), + SmError::StdioStolen => f.write_str("Stdio was stolen. This is a bug."), + SmError::FailedToStartChild(e) => write!(f, "Failed to start child process: {}", e), + SmError::FailedToSendStdio => { + f.write_str("Failed to send stdio to display thread. This is a bug.") + } + } + } } } diff --git a/src/view.rs b/src/view.rs index aadf44c..5b1a302 100644 --- a/src/view.rs +++ b/src/view.rs @@ -69,7 +69,7 @@ fn render_table(f: &mut Frame, state: &mut AppState, area: Rect) service .status .lock() - .expect("service.status lock poisoned") + .expect("service.status lock poisoned") // returning result here is too much effort .to_string(), ), ];