use std::convert::Infallible;
use zenwave::middleware::MiddlewareError;
use zenwave::{Client, Endpoint, Middleware, Request, Response, header};
use crate::config::StowConfig;
pub const NO_ANALYTICS_ENV: &str = "STOW_NO_ANALYTICS";
const NO_ANALYTICS_HEADER: &str = "x-stow-no-analytics";
pub fn client(config: &StowConfig) -> impl Client {
zenwave::client()
.timeout(config.request_timeout)
.with(EdgeHeaders::new())
}
#[must_use]
pub fn analytics_opted_out() -> bool {
std::env::var(NO_ANALYTICS_ENV).ok().as_deref() == Some("1")
}
#[derive(Debug)]
struct EdgeHeaders {
user_agent: String,
no_analytics: bool,
}
impl EdgeHeaders {
fn new() -> Self {
Self {
user_agent: format!(
"stow-cli/{} ({})",
env!("CARGO_PKG_VERSION"),
std::env::consts::OS
),
no_analytics: analytics_opted_out(),
}
}
}
impl Middleware for EdgeHeaders {
type Error = Infallible;
async fn handle<E: Endpoint>(
&mut self,
request: &mut Request,
mut next: E,
) -> Result<Response, MiddlewareError<E::Error, Self::Error>> {
let headers = request.headers_mut();
headers.insert(
header::USER_AGENT,
self.user_agent
.parse()
.expect("the stow-cli user agent contains no invalid header bytes"),
);
if self.no_analytics {
headers.insert(
NO_ANALYTICS_HEADER,
"1".parse().expect("valid header value"),
);
}
next.respond(request)
.await
.map_err(MiddlewareError::Endpoint)
}
}
#[cfg(test)]
mod tests {
use super::analytics_opted_out;
#[test]
fn opt_out_reflects_the_environment_variable() {
let expected = std::env::var("STOW_NO_ANALYTICS").ok().as_deref() == Some("1");
assert_eq!(analytics_opted_out(), expected);
}
}