wash_cli/common/
get_cmd.rsuse anyhow::Result;
use crossterm::{
cursor, execute,
terminal::{Clear, ClearType},
};
use std::{collections::HashMap, io::Write, time::Duration};
use tokio::time::sleep;
use wash_lib::cli::claims::get_claims;
use wash_lib::cli::get::{
get_host_inventories, get_hosts, GetCommand, GetHostInventoriesCommand, GetLinksCommand,
};
use wash_lib::cli::link::{LinkCommand, LinkQueryCommand};
use wash_lib::cli::{CommandOutput, OutputKind};
use crate::appearance::spinner::Spinner;
use crate::common::link_cmd::handle_command as handle_link_command;
use crate::ctl::{
get_claims_output, get_host_inventories_output, get_hosts_output, host_inventories_table,
};
pub async fn handle_command(command: GetCommand, output_kind: OutputKind) -> Result<CommandOutput> {
let sp: Spinner = Spinner::new(&output_kind)?;
let out: CommandOutput = match command {
GetCommand::Links(GetLinksCommand { opts }) => {
handle_link_command(LinkCommand::Query(LinkQueryCommand { opts }), output_kind).await?
}
GetCommand::Claims(cmd) => {
sp.update_spinner_message("Retrieving claims ... ".to_string());
let claims = get_claims(cmd).await?;
get_claims_output(claims)
}
GetCommand::Hosts(cmd) => {
sp.update_spinner_message(" Retrieving Hosts ...".to_string());
let hosts = get_hosts(cmd).await?;
get_hosts_output(hosts)
}
GetCommand::HostInventories(cmd) => {
if let Some(id) = cmd.host_id.as_ref() {
sp.update_spinner_message(format!(" Retrieving inventory for host {} ...", id));
} else {
sp.update_spinner_message(" Retrieving hosts for inventory query ...".to_string());
}
get_inventory_handler(cmd, sp).await?
}
};
Ok(out)
}
async fn get_inventory_handler(
cmd: GetHostInventoriesCommand,
sp: Spinner,
) -> Result<CommandOutput> {
if cmd.watch.is_some() {
watch_inventory(cmd, sp).await?;
Ok(CommandOutput::new(
"Completed Watching Inventory".to_string(),
HashMap::new(),
))
} else {
let invs = get_host_inventories(cmd).await?;
Ok(get_host_inventories_output(invs))
}
}
async fn watch_inventory(cmd: GetHostInventoriesCommand, sp: Spinner) -> Result<()> {
let mut stdout = std::io::stdout();
let invs = get_host_inventories(cmd.clone()).await?;
sp.finish_and_clear();
execute!(stdout, Clear(ClearType::FromCursorUp), cursor::MoveTo(0, 0))
.map_err(|e| anyhow::anyhow!("Failed to clear terminal: {}", e))?;
let output = host_inventories_table(invs);
stdout
.write_all(output.as_bytes())
.map_err(|e| anyhow::anyhow!("Failed to write inventory to stdout: {}", e))?;
let mut ctrlc = std::pin::pin!(tokio::signal::ctrl_c());
let watch_interval = cmd.watch.unwrap_or(Duration::from_millis(5000));
loop {
let invs = tokio::select! {
res = get_host_inventories(cmd.clone()) => res?,
res = &mut ctrlc => {
res?;
execute!(stdout, Clear(ClearType::Purge),Clear(ClearType::FromCursorUp), cursor::MoveTo(0, 0), cursor::Show)
.map_err(|e| anyhow::anyhow!("Failed to execute terminal commands: {}", e))?;
stdout.flush()
.map_err(|e| anyhow::anyhow!("Failed to flush stdout: {}", e))?;
return Ok(());
}
};
execute!(stdout, Clear(ClearType::Purge), cursor::MoveTo(0, 0))
.map_err(|e| anyhow::anyhow!("Failed to execute terminal commands: {}", e))?;
let output = host_inventories_table(invs);
stdout
.write_all(output.as_bytes())
.map_err(|e| anyhow::anyhow!("Failed to write inventory to stdout: {}", e))?;
stdout
.flush()
.map_err(|e| anyhow::anyhow!("Failed to flush stdout: {}", e))?;
execute!(
stdout,
Clear(ClearType::CurrentLine),
Clear(ClearType::FromCursorDown),
)
.map_err(|e| anyhow::anyhow!("Failed to clear terminal: {}", e))?;
tokio::select! {
_ = sleep(watch_interval) => continue,
res = &mut ctrlc => {
res?;
execute!(stdout, Clear(ClearType::Purge),Clear(ClearType::FromCursorUp), cursor::MoveTo(0, 0), cursor::Show)
.map_err(|e| anyhow::anyhow!("Failed to execute terminal commands: {}", e))?;
stdout.flush()
.map_err(|e| anyhow::anyhow!("Failed to flush stdout: {}", e))?;
return Ok(());
}
}
}
}