Compare commits

...

2 commits

Author SHA1 Message Date
f4ab2a327a
fix: show req number, use localtime 2024-10-19 05:29:32 +02:00
b1ab7f433a
feat: format json if content-type json, show body 2024-10-19 05:29:26 +02:00
4 changed files with 24 additions and 12 deletions

1
Cargo.lock generated
View file

@ -813,6 +813,7 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
name = "postwoman" name = "postwoman"
version = "0.2.0" version = "0.2.0"
dependencies = [ dependencies = [
"base64",
"chrono", "chrono",
"clap", "clap",
"http", "http",

View file

@ -6,6 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
base64 = "0.22.1"
chrono = "0.4" chrono = "0.4"
clap = { version = "4.5", features = ["derive"] } clap = { version = "4.5", features = ["derive"] }
http = "1.1.0" http = "1.1.0"

View file

@ -52,11 +52,11 @@ pub enum PostWomanActions {
const TIMESTAMP_FMT: &str = "%H:%M:%S%.6f"; const TIMESTAMP_FMT: &str = "%H:%M:%S%.6f";
fn print_results(res: String, name: String, before: chrono::DateTime<chrono::Utc>) { fn print_results(res: String, name: String, before: chrono::DateTime<chrono::Local>, num: u32) {
let after = chrono::Utc::now(); let after = chrono::Local::now();
let elapsed = (after - before).num_milliseconds(); let elapsed = (after - before).num_milliseconds();
let timestamp = after.format(TIMESTAMP_FMT); let timestamp = after.format(TIMESTAMP_FMT);
eprintln!(" + [{timestamp}] {name} done in {elapsed}ms", ); eprintln!(" + [{timestamp}] {name} #{num} done in {elapsed}ms", );
print!("{}", res); print!("{}", res);
} }
@ -79,26 +79,26 @@ async fn main() -> Result<(), PostWomanError> {
let _endpoint = endpoint.clone(); let _endpoint = endpoint.clone();
let _name = name.clone(); let _name = name.clone();
let task = async move { let task = async move {
let before = chrono::Utc::now(); let before = chrono::Local::now();
eprintln!(" : [{}] sending {_name} #{}...", before.format(TIMESTAMP_FMT), i+1); eprintln!(" : [{}] sending {_name} #{}...", before.format(TIMESTAMP_FMT), i+1);
let res = _endpoint let res = _endpoint
.fill() .fill()
.execute(&_client) .execute(&_client)
.await; .await;
(res, _name, before) (res, _name, before, i)
}; };
if parallel { if parallel {
joinset.spawn(task); joinset.spawn(task);
} else { } else {
let (res, name, before) = task.await; let (res, name, before, num) = task.await;
print_results(res?, name, before); print_results(res?, name, before, num);
} }
} }
} }
} }
while let Some(j) = joinset.join_next().await { while let Some(j) = joinset.join_next().await {
match j { match j {
Ok((res, name, before)) => print_results(res?, name, before), Ok((res, name, before, num)) => print_results(res?, name, before, num),
Err(e) => eprintln!("! error joining task: {e}"), Err(e) => eprintln!("! error joining task: {e}"),
} }
} }
@ -109,7 +109,5 @@ async fn main() -> Result<(), PostWomanError> {
// }, // },
} }
eprintln!();
Ok(()) Ok(())
} }

View file

@ -1,5 +1,6 @@
use std::str::FromStr; use std::str::FromStr;
use base64::{prelude::BASE64_STANDARD, Engine};
use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use crate::APP_USER_AGENT; use crate::APP_USER_AGENT;
@ -151,8 +152,8 @@ impl Endpoint {
Ok(match self.extract.unwrap_or_default() { Ok(match self.extract.unwrap_or_default() {
StringOr::Str(_query) => todo!(), StringOr::Str(_query) => todo!(),
StringOr::T(Extractor::Discard) => "".to_string(), StringOr::T(Extractor::Discard) => "".to_string(),
StringOr::T(Extractor::Debug) => format!("{res:#?}\n"), StringOr::T(Extractor::Debug) => format!("{res:#?}\nBody: ") + &format_body(res).await? + "\n", // ughhh
StringOr::T(Extractor::Body) => res.text().await? + "\n", StringOr::T(Extractor::Body) => format_body(res).await?,
StringOr::T(Extractor::Header { key }) => res StringOr::T(Extractor::Header { key }) => res
.headers() .headers()
.get(&key) .get(&key)
@ -164,6 +165,17 @@ impl Endpoint {
} }
} }
async fn format_body(res: reqwest::Response) -> Result<String, PostWomanError> {
match res.headers().get("Content-Type") {
None => Ok(res.text().await? + "\n"),
Some(v) => match v.to_str()? {
"application/json" => Ok(serde_json::to_string_pretty(&res.json::<serde_json::Value>().await?)? + "\n"),
"text/plain" => Ok(res.text().await? + "\n"),
_ => Ok(format!("base64({})\n", BASE64_STANDARD.encode(res.bytes().await?))),
},
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(untagged)] #[serde(untagged)]
pub enum StringOr<T> { pub enum StringOr<T> {