use std::sync::Arc;
use super::super::audit::GatewayAudit;
use super::super::stream_tap::log_terminal;
pub const ABANDONED_REASON: &str = "client disconnected before upstream responded";
const CLIENT_CLOSED_REQUEST: u16 = 499;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Arming {
armed: bool,
}
impl Arming {
pub const fn armed() -> Self {
Self { armed: true }
}
pub const fn disarm(&mut self) {
self.armed = false;
}
pub const fn take(&mut self) -> bool {
let fires = self.armed;
self.armed = false;
fires
}
}
pub(super) struct AbandonGuard {
audit: Arc<GatewayAudit>,
arming: Arming,
}
impl AbandonGuard {
pub(super) const fn arm(audit: Arc<GatewayAudit>) -> Self {
Self {
audit,
arming: Arming::armed(),
}
}
pub(super) const fn disarm(&mut self) {
self.arming.disarm();
}
}
impl Drop for AbandonGuard {
fn drop(&mut self) {
if !self.arming.take() {
return;
}
let audit = Arc::clone(&self.audit);
audit.mark_upstream_end();
log_terminal(&audit, CLIENT_CLOSED_REQUEST, Some(ABANDONED_REASON));
tokio::spawn(async move {
if let Err(e) = audit.fail(ABANDONED_REASON).await {
tracing::warn!(error = %e, "abandoned dispatch audit fail failed");
}
});
}
}