This commit is contained in:
nora 2021-12-17 23:21:11 +01:00
parent 072deb19c1
commit 4a9990a9cd
4 changed files with 56 additions and 68 deletions

View file

@ -4,10 +4,9 @@ use crate::{view, App};
use crossterm::event; use crossterm::event;
use crossterm::event::{Event, KeyCode}; use crossterm::event::{Event, KeyCode};
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::{OsStr, OsString}; use std::ffi::OsString;
use std::io; use std::io;
use std::io::{ErrorKind, Read}; use std::io::{ErrorKind, Read, Write};
use std::os::unix::ffi::OsStrExt;
use std::process::{Child, Command, Stdio}; use std::process::{Child, Command, Stdio};
use std::sync::mpsc::TryRecvError; use std::sync::mpsc::TryRecvError;
use std::sync::{mpsc, Mutex}; use std::sync::{mpsc, Mutex};
@ -15,6 +14,10 @@ use tui::backend::Backend;
use tui::widgets::TableState; use tui::widgets::TableState;
use tui::Terminal; use tui::Terminal;
const STDOUT_SEND_BUF_SIZE: usize = 512;
pub type StdoutSendBuf = ([u8; STDOUT_SEND_BUF_SIZE], usize);
pub fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> { pub fn run_app<B: Backend>(terminal: &mut Terminal<B>, mut app: App) -> io::Result<()> {
loop { loop {
terminal.draw(|f| view::render_ui(f, &mut app))?; terminal.draw(|f| view::render_ui(f, &mut app))?;
@ -64,7 +67,7 @@ impl App {
.or_else(|_| std::env::current_dir())?, .or_else(|_| std::env::current_dir())?,
env: service.env.unwrap_or_else(HashMap::new), env: service.env.unwrap_or_else(HashMap::new),
status: Mutex::new(ServiceStatus::NotStarted), status: Mutex::new(ServiceStatus::NotStarted),
stdout_buf: OsString::new(), stdout_buf: Vec::new(),
stdout_recv, stdout_recv,
stdout_send: Mutex::new(Some(stdout_send)), stdout_send: Mutex::new(Some(stdout_send)),
}) })
@ -82,19 +85,19 @@ impl App {
fn recv_stdouts(&mut self) { fn recv_stdouts(&mut self) {
for service in self.table.services.iter_mut() { for service in self.table.services.iter_mut() {
while let Ok(vec) = service.stdout_recv.try_recv() { while let Ok((buf, n)) = service.stdout_recv.try_recv() {
service.stdout_buf.push(OsStr::from_bytes(&vec)); service.stdout_buf.extend_from_slice(&buf[0..n]);
std::fs::write( std::fs::write(
format!( format!(
"debug/received_something_{}_{}.txt", "debug/received_something_{}_{}.txt",
service.name, &service.name,
std::time::SystemTime::now() std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
.unwrap() .unwrap()
.as_millis() .as_millis()
), ),
service.stdout_buf.as_bytes(), &service.stdout_buf,
) )
.expect("debug failed fuck"); .expect("debug failed fuck");
} }
@ -172,8 +175,13 @@ impl App {
let child = match cmd.spawn() { let child = match cmd.spawn() {
Err(err) => { Err(err) => {
let mut buf = [0; STDOUT_SEND_BUF_SIZE];
let bytes = err.to_string();
(&mut buf[..]).write_all(bytes.as_bytes()).expect("dont");
stdout_send stdout_send
.send(err.to_string().into_bytes()) .send((buf, bytes.len()))
.expect("failed to send stdout"); .expect("failed to send stdout");
return; return;
} }
@ -192,7 +200,7 @@ impl App {
} }
fn child_process_thread( fn child_process_thread(
child: Child, child: Child,
stdout_send: mpsc::Sender<Vec<u8>>, stdout_send: mpsc::Sender<StdoutSendBuf>,
terminate_channel: mpsc::Receiver<()>, terminate_channel: mpsc::Receiver<()>,
) -> io::Result<()> { ) -> io::Result<()> {
let mut child = child; let mut child = child;
@ -204,29 +212,30 @@ fn child_process_thread(
Err(TryRecvError::Empty) => {} Err(TryRecvError::Empty) => {}
} }
let mut stdout_buf = Vec::new(); let mut stdout_buf = [0; STDOUT_SEND_BUF_SIZE];
match stdout.read(&mut stdout_buf) { match stdout.read(&mut stdout_buf) {
Ok(0) => continue, Ok(0) => continue,
Ok(_) => { Ok(n) => {
std::fs::write( // std::fs::write(
format!( // format!(
"debug/read_something_{}.txt", // "debug/read_something_{}.txt",
std::time::SystemTime::now() // std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) // .duration_since(std::time::UNIX_EPOCH)
.unwrap() // .unwrap()
.as_millis() // .as_millis()
), // ),
&stdout_buf, // &stdout_buf,
) // )
.ok(); // .ok();
stdout_send
.send((stdout_buf, n))
.map_err(|_| io::Error::from(io::ErrorKind::Other))?;
} }
Err(e) if e.kind() == io::ErrorKind::Interrupted => {} Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
stdout_send
.send(stdout_buf)
.map_err(|_| io::Error::from(io::ErrorKind::Other))?;
} }
match child.kill() { match child.kill() {

View file

@ -18,43 +18,6 @@ use crate::model::config::Config;
use crate::model::App; use crate::model::App;
fn main() { fn main() {
///// ------------------------ TEST START ------------------------
let mut cmd = std::process::Command::new("sh");
let mut child = cmd
.stdout(Stdio::piped())
.args(&["-c", "echo hello"])
.spawn()
.unwrap();
let mut stdout = child.stdout.take().unwrap(); // std::fs::File::open("config.toml").unwrap();
std::thread::spawn(move || {
let mut buf = [0; 1024];
println!("{}", buf.len());
// stdout.read_to_end(&mut buf);
// println!("{}", String::from_utf8_lossy(&buf).as_ref());
// return;
loop {
match stdout.read(&mut buf) {
Ok(0) => break,
Ok(_) => println!("READ: now `{}`", String::from_utf8(buf.to_vec()).unwrap()),
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => eprintln!("error: {}", e),
}
}
println!("done!");
});
std::thread::sleep(Duration::from_secs(3454233));
///// ------------------------ TEST END ------------------------
let file_path = env::args() let file_path = env::args()
.nth(1) .nth(1)
.or_else(|| env::var("SERVICE_MANAGER_CONFIG_PATH").ok()) .or_else(|| env::var("SERVICE_MANAGER_CONFIG_PATH").ok())

View file

@ -1,5 +1,8 @@
use crate::controller::StdoutSendBuf;
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::OsString; use std::ffi::OsString;
use std::io;
use std::io::Error;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::{mpsc, Mutex}; use std::sync::{mpsc, Mutex};
use tui::widgets::TableState; use tui::widgets::TableState;
@ -24,9 +27,9 @@ pub struct Service {
pub workdir: PathBuf, pub workdir: PathBuf,
pub env: HashMap<String, String>, pub env: HashMap<String, String>,
pub status: Mutex<ServiceStatus>, pub status: Mutex<ServiceStatus>,
pub stdout_buf: OsString, pub stdout_buf: Vec<u8>,
pub stdout_recv: mpsc::Receiver<Vec<u8>>, pub stdout_recv: mpsc::Receiver<StdoutSendBuf>,
pub stdout_send: Mutex<Option<mpsc::Sender<Vec<u8>>>>, pub stdout_send: Mutex<Option<mpsc::Sender<StdoutSendBuf>>>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -52,3 +55,16 @@ pub mod config {
pub env: Option<HashMap<String, String>>, pub env: Option<HashMap<String, String>>,
} }
} }
pub type SmResult = Result<(), SmError>;
pub enum SmError {
Io(io::Error),
MutexPoisoned,
}
impl From<io::Error> for SmError {
fn from(e: Error) -> Self {
Self::Io(e)
}
}

View file

@ -41,7 +41,7 @@ fn render_full_view<B: Backend>(f: &mut Frame<B>, state: &mut AppState, index: u
.borders(Borders::ALL) .borders(Borders::ALL)
.title("service".as_ref()); .title("service".as_ref());
let stdout = service.stdout_buf.to_string_lossy(); let stdout = String::from_utf8_lossy(&service.stdout_buf);
let paragraph = Paragraph::new(stdout.as_ref()).block(block); let paragraph = Paragraph::new(stdout.as_ref()).block(block);