use serde::de::DeserializeOwned; use serde_json::{from_slice, Value}; use std::fmt::{Debug, Display}; use std::process::{Command, Output}; use u_lib::{conv::bytes_to_string, proc_output::ProcOutput, types::PanelResult}; const PANEL_BINARY: &str = "/u_panel"; pub struct Panel; impl Panel { fn run(args: &[&str]) -> Output { Command::new(PANEL_BINARY) .env("RUST_LOG", "u_lib=debug") .args(args) .output() .unwrap() } pub fn output_argv(argv: &[&str]) -> PanelResult { let result = Self::run(argv); let output = ProcOutput::from_output(&result); let stderr = output.get_stderr(); if !stderr.is_empty() { println!( "\n*** PANEL DEBUG OUTPUT START***\n{}\n*** PANEL DEBUG OUTPUT END ***\n", String::from_utf8_lossy(stderr) ); } match from_slice(output.get_stdout()) { Ok(r) => r, Err(e) => { eprintln!( "Failed to decode panel response: ###'{}'###", bytes_to_string(output.get_stdout()) ); panic!("{e}") } } } pub fn output(args: impl IntoArgs) -> PanelResult { eprintln!(">>> {PANEL_BINARY} {}", args.display()); let splitted = args.into_args(); let result = Self::output_argv( splitted .iter() .map(|s| s.as_ref()) .collect::>() .as_ref(), ); match &result { PanelResult::Ok(r) => eprintln!("+<< {r:#?}"), PanelResult::Err(e) => eprintln!("!<< {e:#?}"), } result } fn status_is_ok(data: PanelResult) -> T { match data { PanelResult::Ok(r) => r, PanelResult::Err(e) => panic!("Panel failed: {e}"), } } pub fn check_status(args: impl IntoArgs) { let result: PanelResult = Self::output(args); Self::status_is_ok(result); } pub fn check_output(args: impl IntoArgs) -> T { let result = Self::output(args); Self::status_is_ok(result) } } pub trait IntoArgs { fn into_args(self) -> Vec; fn display(&self) -> String; } impl IntoArgs for String { fn into_args(self) -> Vec { >::as_ref(&self).into_args() } fn display(&self) -> String { self.clone() } } impl IntoArgs for &str { fn into_args(self) -> Vec { shlex::split(self.as_ref()).unwrap() } fn display(&self) -> String { self.to_string() } } impl IntoArgs for [S; N] where S: Display, { fn into_args(self) -> Vec { self.into_iter().map(|s| s.to_string()).collect() } fn display(&self) -> String { self.iter() .map(|s| format!(r#""{s}""#)) .collect::>() .join(" ") } }