From 04d54f6e434e4ec2f3b63c007147c64f556b19bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Ml=C3=A1dek?= Date: Tue, 6 Jun 2023 19:01:38 +0200 Subject: [PATCH] feat,fix: add `get` cli command, cli commands don't panic --- cli/src/common.rs | 6 ++- cli/src/main.rs | 96 +++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 86 insertions(+), 16 deletions(-) diff --git a/cli/src/common.rs b/cli/src/common.rs index b79eb25..ecd822e 100644 --- a/cli/src/common.rs +++ b/cli/src/common.rs @@ -23,9 +23,13 @@ lazy_static! { upend::common::build::PROJECT_NAME, upend::common::build::PKG_VERSION ); - pub static ref REQWEST_CLIENT: reqwest::blocking::Client = reqwest::blocking::Client::builder() .user_agent(APP_USER_AGENT.as_str()) .build() .unwrap(); + + pub static ref REQWEST_ASYNC_CLIENT: reqwest::Client = reqwest::Client::builder() + .user_agent(APP_USER_AGENT.as_str()) + .build() + .unwrap(); } diff --git a/cli/src/main.rs b/cli/src/main.rs index de67f9c..f237d71 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,6 +1,6 @@ #[macro_use] extern crate upend; -use crate::common::{get_static_dir, REQWEST_CLIENT}; +use crate::common::{get_static_dir, REQWEST_ASYNC_CLIENT}; use actix_cors::Cors; use actix_web::web::Data; use actix_web::{middleware, App, HttpServer}; @@ -63,12 +63,24 @@ enum Commands { #[arg(short, long, default_value = "tsv")] format: OutputFormat, }, + Get { + /// URL of the UpEnd instance to query. + #[arg(short, long, default_value = "http://localhost:8093")] + url: Url, + /// The address of the entity; prefix a filepath by `=` to insert its hash. + entity: String, + /// The attribute to get the value(s) of. Optional. + attribute: Option, + /// Output format + #[arg(short, long, default_value = "tsv")] + format: OutputFormat, + }, /// Insert an entry into an UpEnd server instance. Insert { /// URL of the UpEnd instance to query. - #[arg(short, long)] - url: Option, - /// The address of the entity; prefix a filepath by `@` to insert its hash. + #[arg(short, long, default_value = "http://localhost:8093")] + url: Url, + /// The address of the entity; prefix a filepath by `=` to insert its hash. entity: String, /// The attribute of the entry. attribute: String, @@ -196,21 +208,73 @@ async fn main() -> Result<()> { }) .to_string(); - debug!("Final query: {}", query); - let api_url = url.join("/api/query")?; - debug!("Querying \"{}\"", api_url); - let response = REQWEST_CLIENT.post(api_url).body(query).send()?; + debug!("Querying \"{}\": {}", api_url, query); + let response = REQWEST_ASYNC_CLIENT.post(api_url).body(query).send().await?; response.error_for_status_ref()?; match format { - OutputFormat::Json | OutputFormat::Raw => println!("{}", response.text()?), + OutputFormat::Json | OutputFormat::Raw => println!("{}", response.text().await?), OutputFormat::Tsv => { eprintln!("entity\tattribute\tvalue\ttimestamp\tprovenance"); response - .json::>()? + .json::>().await? + .iter() + .for_each(|(_, entry)| { + println!( + "{}\t{}\t{}\t{}\t{}", + entry.get("entity").and_then(|e| e.as_str()).unwrap(), + entry.get("attribute").and_then(|a| a.as_str()).unwrap(), + entry.get("value").and_then(|v| v.get("c")).unwrap(), + entry.get("timestamp").and_then(|t| t.as_str()).unwrap(), + entry.get("provenance").and_then(|p| p.as_str()).unwrap(), + ) + }) + } + } + + Ok(()) + } + Commands::Get { + url, + entity, + attribute, + format, + } => { + let api_url = url.join("/api/obj")?; + + let entity = match entity { + entity if entity.starts_with('=') => hash_path(&entity[1..])?.to_string(), + entity if entity.starts_with("http") => Address::Url(entity.parse()?).to_string(), + _ => entity, + }; + + let query = format!( + "(matches @{} {} ?)", + entity, + attribute + .map(|a| format!("\"{a}\"")) + .unwrap_or("?".to_string()) + ); + + debug!("Querying \"{}\": {}", api_url, query); + let response = REQWEST_ASYNC_CLIENT + .get(api_url) + .body(query) + .send() + .await?; + + response.error_for_status_ref()?; + + match format { + OutputFormat::Json | OutputFormat::Raw => println!("{}", response.text().await?), + OutputFormat::Tsv => { + eprintln!("entity\tattribute\tvalue\ttimestamp\tprovenance"); + response + .json::>() + .await? .iter() .for_each(|(_, entry)| { println!( @@ -234,7 +298,6 @@ async fn main() -> Result<()> { value, format: _, } => { - let url = url.unwrap_or("http://localhost:8093".parse().unwrap()); let api_url = url.join("/api/obj")?; let entity = match entity { @@ -252,15 +315,15 @@ async fn main() -> Result<()> { }); debug!("Inserting {:?} at \"{}\"", body, api_url); - let response = REQWEST_CLIENT.put(api_url).json(&body).send()?; + let response = REQWEST_ASYNC_CLIENT.put(api_url).json(&body).send().await?; match response.error_for_status_ref() { Ok(_) => { - let data: Vec = response.json()?; + let data: Vec = response.json().await?; Ok(println!("{}", data[0])) } Err(err) => { - error!("{}", response.text()?); + error!("{}", response.text().await?); Err(err.into()) } } @@ -402,7 +465,10 @@ async fn main() -> Result<()> { let app = App::new() .wrap(cors) - .wrap(middleware::DefaultHeaders::new().add(("UPEND-VERSION", upend::common::build::PKG_VERSION))) + .wrap( + middleware::DefaultHeaders::new() + .add(("UPEND-VERSION", upend::common::build::PKG_VERSION)), + ) .app_data(actix_web::web::PayloadConfig::new(4_294_967_296)) .app_data(Data::new(state.clone())) .wrap(middleware::Logger::default().exclude("/api/jobs"))