innernet/client/src/util.rs

111 lines
3.3 KiB
Rust

use crate::{ClientError, Error};
use colored::*;
use serde::{de::DeserializeOwned, Serialize};
use shared::{interface_config::ServerInfo, INNERNET_PUBKEY_HEADER};
use std::time::Duration;
use ureq::{Agent, AgentBuilder};
pub fn human_duration(duration: Duration) -> String {
match duration.as_secs() {
n if n < 1 => "just now".cyan().to_string(),
n if n < 60 => format!("{} {} ago", n, "seconds".cyan()),
n if n < 60 * 60 => {
let mins = n / 60;
let secs = n % 60;
format!(
"{} {}, {} {} ago",
mins,
if mins == 1 { "minute" } else { "minutes" }.cyan(),
secs,
if secs == 1 { "second" } else { "seconds" }.cyan(),
)
},
n => {
let hours = n / (60 * 60);
let mins = (n / 60) % 60;
format!(
"{} {}, {} {} ago",
hours,
if hours == 1 { "hour" } else { "hours" }.cyan(),
mins,
if mins == 1 { "minute" } else { "minutes" }.cyan(),
)
},
}
}
pub fn human_size(bytes: u64) -> String {
const KB: u64 = 1024;
const MB: u64 = 1024 * KB;
const GB: u64 = 1024 * MB;
const TB: u64 = 1024 * GB;
match bytes {
n if n < 2 * KB => format!("{} {}", n, "B".cyan()),
n if n < 2 * MB => format!("{:.2} {}", n as f64 / KB as f64, "KiB".cyan()),
n if n < 2 * GB => format!("{:.2} {}", n as f64 / MB as f64, "MiB".cyan()),
n if n < 2 * TB => format!("{:.2} {}", n as f64 / GB as f64, "GiB".cyan()),
n => format!("{:.2} {}", n as f64 / TB as f64, "TiB".cyan()),
}
}
pub struct Api<'a> {
agent: Agent,
server: &'a ServerInfo,
}
impl<'a> Api<'a> {
pub fn new(server: &'a ServerInfo) -> Self {
let agent = AgentBuilder::new()
.timeout(Duration::from_secs(5))
.redirects(0)
.build();
Self { agent, server }
}
pub fn http<T: DeserializeOwned>(&self, verb: &str, endpoint: &str) -> Result<T, Error> {
self.request::<(), _>(verb, endpoint, None)
}
pub fn http_form<S: Serialize, T: DeserializeOwned>(
&self,
verb: &str,
endpoint: &str,
form: S,
) -> Result<T, Error> {
self.request(verb, endpoint, Some(form))
}
fn request<S: Serialize, T: DeserializeOwned>(
&self,
verb: &str,
endpoint: &str,
form: Option<S>,
) -> Result<T, Error> {
let request = self
.agent
.request(
verb,
&format!("http://{}/v1{}", self.server.internal_endpoint, endpoint),
)
.set(INNERNET_PUBKEY_HEADER, &self.server.public_key);
let response = if let Some(form) = form {
request.send_json(serde_json::to_value(form)?)?
} else {
request.call()?
};
let mut response = response.into_string()?;
// A little trick for serde to parse an empty response as `()`.
if response.is_empty() {
response = "null".into();
}
Ok(serde_json::from_str(&response).map_err(|e| {
ClientError(format!(
"failed to deserialize JSON response from the server: {}, response={}",
e, &response
))
})?)
}
}