feat,fix: add `get` cli command, cli commands don't panic

feat/type-attributes
Tomáš Mládek 2023-06-06 19:01:38 +02:00
parent d3c5d182af
commit 04d54f6e43
2 changed files with 86 additions and 16 deletions

View File

@ -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();
}

View File

@ -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<String>,
/// 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<Url>,
/// 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::<HashMap<String, serde_json::Value>>()?
.json::<HashMap<String, serde_json::Value>>().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::<HashMap<String, serde_json::Value>>()
.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<String> = response.json()?;
let data: Vec<String> = 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"))