detee-cli/src/utils.rs

110 lines
3.4 KiB
Rust

// SPDX-License-Identifier: Apache-2.0
use crate::config::Config;
use tonic::{
metadata::{errors::InvalidMetadataValue, AsciiMetadataValue},
Request,
};
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
ConfigError(#[from] crate::config::Error),
#[error(transparent)]
InternalError(#[from] InvalidMetadataValue),
}
pub fn block_on<F>(future: F) -> F::Output
where
F: std::future::Future,
{
tokio::runtime::Runtime::new().unwrap().block_on(future)
}
pub fn sign_request<T: std::fmt::Debug>(req: T) -> Result<Request<T>, Error> {
let pubkey = Config::get_detee_wallet()?;
let timestamp = chrono::Utc::now().to_rfc3339();
let signature = Config::try_sign_message(&format!("{timestamp}{req:?}"))?;
let timestamp: AsciiMetadataValue = timestamp.parse()?;
let pubkey: AsciiMetadataValue = pubkey.parse()?;
let signature: AsciiMetadataValue = signature.parse()?;
let mut req = Request::new(req);
req.metadata_mut().insert("timestamp", timestamp);
req.metadata_mut().insert("pubkey", pubkey);
req.metadata_mut().insert("request-signature", signature);
Ok(req)
}
pub fn shorten_string(my_string: &String) -> String {
if my_string.len() <= 8 {
my_string.to_string()
} else {
let first_part = &my_string[..8];
// let last_part = &my_string[my_string.len() - 4..];
format!("{}", first_part)
}
}
pub fn display_mib_or_gib(value: &u64) -> String {
if *value >= 1024 {
if *value < 102400 {
let value = (value / 102) as f64;
format!("{}G", value / 10_f64)
} else {
format!("{}G", value / 1024)
}
} else {
format!("{}M", value)
}
}
#[macro_export]
macro_rules! call_with_follow_redirect {
(
$client:expr,
$req_data:expr,
$method:ident
) => {
async {
let mut client = $client;
for attempt in 0..crate::constants::MAX_REDIRECTS {
log::debug!(
"Attempt #{}: Calling method '{}'...",
attempt + 1,
stringify!($method)
);
let req_data_clone = $req_data.clone();
let signed_req = crate::utils::sign_request(req_data_clone)?;
match client.$method(signed_req).await {
Ok(resp) => return Ok(resp),
Err(status)
if status.code() == tonic::Code::Unavailable
&& status.message() == "moved" =>
{
let redirect_url = status
.metadata()
.get("location")
.and_then(|v| v.to_str().ok())
.ok_or_else(|| {
Error::RedirectError(
"Server indicated a move but provided no location".into(),
)
})?;
log::info!("Server moved. Redirecting to {}...", redirect_url);
client = client_from_endpoint(format!("https://{}", redirect_url)).await?;
continue;
}
Err(e) => return Err(Error::ResponseStatus(e)),
}
}
Err(Error::MaxRedirectsExceeded(crate::constants::MAX_REDIRECTS.to_string()))
}
};
}