use crate::thread_quiet::measured_quiet;
use std::time::Duration;
use ureq::tls::{Certificate, RootCerts, TlsConfig};
pub const SCRIPT_QUIET_WINDOW: Duration = Duration::from_secs(30);
#[derive(Clone, Copy, Debug)]
pub struct Gateway<'a> {
pub url: &'a str,
pub api_key: &'a str,
pub quiet_window: Duration,
pub ceiling: Duration,
pub trusted_pem: Option<&'a [u8]>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Reply {
pub status: u16,
pub body: String,
}
pub fn post_decision(gateway: &Gateway, body: &str) -> Result<Reply, String> {
return measured_quiet("standards review gateway call", || { return post_decision_unmeasured(gateway, body); });
}
fn post_decision_unmeasured(gateway: &Gateway, body: &str) -> Result<Reply, String> {
let tls: TlsConfig = match gateway.trusted_pem {
Some(pem) => {
let authority: Certificate<'static> = Certificate::from_pem(pem).map_err(|error| return format!("the trusted authority is unreadable: {error}"))?;
TlsConfig::builder().root_certs(RootCerts::new_with_certs(&[authority])).build()
}
None => TlsConfig::default(),
};
let agent: ureq::Agent = ureq::Agent::config_builder()
.timeout_resolve(Some(gateway.quiet_window))
.timeout_connect(Some(gateway.quiet_window))
.timeout_per_read(Some(gateway.quiet_window))
.timeout_per_write(Some(gateway.quiet_window))
.timeout_global(Some(gateway.ceiling))
.http_status_as_error(false)
.max_redirects(0)
.proxy(None)
.tls_config(tls)
.build()
.into();
let mut response = agent
.post(gateway.url)
.header("content-type", "application/json")
.header("authorization", format!("Bearer {}", gateway.api_key))
.send(body.as_bytes())
.map_err(|error| { return describe(error, gateway.ceiling); })?;
let status: u16 = response.status().as_u16();
let text: String = response.body_mut().read_to_string().map_err(|error| { return describe(error, gateway.ceiling); })?;
return Ok(Reply { status, body: text });
}
fn describe(error: ureq::Error, ceiling: Duration) -> String {
return match error {
ureq::Error::Timeout(ureq::Timeout::Global) => format!(
"the standards-review gateway call ran for {} seconds, the longest cli-git lets it run, and was ended, so this commit has no \
verdict; review it again with `SHADOW_REVIEW_SHA=<commit> mise run shadow-review`",
ceiling.as_secs()
),
ureq::Error::Timeout(_) => String::from("The operation was aborted due to timeout"),
other => format!("fetch failed: {other}"),
};
}
#[cfg(test)]
#[path = "standards_review_client_tests.rs"]
mod tests;