keylight 0.1.3

Keylight licensing SDK — activate/validate licenses with offline Ed25519 lease verification.
Documentation
use super::{HttpResponse, Transport, TransportOutcome};

pub struct UreqTransport {
    agent: ureq::Agent,
}

impl Default for UreqTransport {
    fn default() -> Self {
        Self {
            agent: ureq::AgentBuilder::new()
                .timeout(std::time::Duration::from_secs(15))
                .build(),
        }
    }
}

/// Collapse a `ureq::Response` (whether it arrived as `Ok` or a non-2xx `Status`) into
/// our uniform `HttpResponse` so the retry layer sees the status code consistently.
fn parse_response(resp: ureq::Response) -> TransportOutcome {
    let status = resp.status();
    let retry_after = resp
        .header("Retry-After")
        .and_then(|h| h.parse::<u64>().ok());
    let body = resp.into_string().unwrap_or_default();
    TransportOutcome::Response(HttpResponse {
        status,
        body,
        retry_after,
    })
}

fn handle(res: Result<ureq::Response, ureq::Error>) -> TransportOutcome {
    match res {
        Ok(resp) => parse_response(resp),
        Err(ureq::Error::Status(_, resp)) => parse_response(resp),
        Err(ureq::Error::Transport(t)) => {
            use ureq::ErrorKind::*;
            match t.kind() {
                Io | Dns | ConnectionFailed => TransportOutcome::Transient(t.to_string()),
                _ => TransportOutcome::Terminal(t.to_string()),
            }
        }
    }
}

impl Transport for UreqTransport {
    fn post_json(&self, url: &str, headers: &[(String, String)], body: &str) -> TransportOutcome {
        let mut req = self.agent.post(url);
        for (k, v) in headers {
            req = req.set(k, v);
        }
        handle(req.send_string(body))
    }

    fn get(&self, url: &str, headers: &[(String, String)]) -> TransportOutcome {
        let mut req = self.agent.get(url);
        for (k, v) in headers {
            req = req.set(k, v);
        }
        handle(req.call())
    }
}