use std::path::Path;
use std::time::Duration;
use crate::buffer;
use crate::event::Batch;
pub const SEND_TIMEOUT: Duration = Duration::from_secs(5);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SendOutcome {
DryRun,
Accepted,
Dropped,
}
pub fn send(root: &Path, endpoint: Option<&str>, batch: &Batch) -> SendOutcome {
send_with_transport(root, endpoint, batch, post)
}
pub(crate) fn send_with_transport(
root: &Path,
endpoint: Option<&str>,
batch: &Batch,
transport: impl FnOnce(&str, &str, String) -> SendOutcome,
) -> SendOutcome {
let Ok(body) = serde_json::to_string(batch) else {
return SendOutcome::Dropped;
};
match endpoint {
None => {
let path = buffer::dryrun_path(root);
match buffer::append_locked(root, &path, &body) {
Some(()) => SendOutcome::DryRun,
None => SendOutcome::Dropped,
}
}
Some(endpoint) => buffer::try_with_lock(root, || {
if buffer::tombstone_present(root) {
return Ok(SendOutcome::Dropped);
}
Ok(transport(endpoint, &batch.app_version, body))
})
.ok()
.flatten()
.unwrap_or(SendOutcome::Dropped),
}
}
fn post(endpoint: &str, app_version: &str, body: String) -> SendOutcome {
let client = codewhale_release::platform_blocking_http_client_builder()
.timeout(SEND_TIMEOUT)
.redirect(reqwest::redirect::Policy::none())
.user_agent(format!("codewhale-telemetry/{app_version}"))
.build();
let Ok(client) = client else {
return SendOutcome::Dropped;
};
match client
.post(endpoint)
.header(reqwest::header::CONTENT_TYPE, "application/json")
.body(body)
.send()
{
Ok(response) if response.status().is_success() => SendOutcome::Accepted,
_ => SendOutcome::Dropped,
}
}