use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum AsxProtocol {
As2,
As4,
}
impl AsxProtocol {
pub fn as_str(self) -> &'static str {
match self {
Self::As2 => "as2",
Self::As4 => "as4",
}
}
}
impl std::fmt::Display for AsxProtocol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum AsxIngressStage {
As2ReceiveWithMdn,
As4ReceivePush,
As4ReceivePull,
}
impl AsxIngressStage {
pub fn as_str(self) -> &'static str {
match self {
Self::As2ReceiveWithMdn => "as2_receive_with_mdn",
Self::As4ReceivePush => "as4_receive_push",
Self::As4ReceivePull => "as4_receive_pull",
}
}
}
impl std::fmt::Display for AsxIngressStage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum AsxEvent {
OutboundPrepared {
message_id: Arc<str>,
protocol: AsxProtocol,
},
MicComputed {
message_id: Arc<str>,
digest_alg: &'static str,
mic_base64: String,
},
MessageSigned {
message_id: Arc<str>,
},
MessageEncrypted {
message_id: Arc<str>,
},
MdnReceived {
message_id: Arc<str>,
disposition: String,
},
ReceiptReceived {
message_id: Arc<str>,
signal: &'static str,
},
ReceiptTaxonomyOutcome {
message_id: Arc<str>,
signal: &'static str,
outcome: &'static str,
detail: &'static str,
},
ReceiptTaxonomyAlertRaised {
signal: &'static str,
severity: &'static str,
category: &'static str,
observed_rate_ppm: u64,
sample_size: u64,
},
RetryScheduled {
message_id: Arc<str>,
attempt: u32,
reason: &'static str,
},
ReconciliationQueued {
message_id: Arc<str>,
reason: &'static str,
},
DuplicateDetected {
message_id: Arc<str>,
key: String,
ingress: AsxIngressStage,
},
InteropRelaxationApplied {
message_id: Arc<str>,
rule: &'static str,
detail: &'static str,
},
InteropGuardrailEvaluated {
message_id: Arc<str>,
code: &'static str,
outcome: &'static str,
detail: &'static str,
},
MaterializationApplied {
message_id: Arc<str>,
stage: &'static str,
reason: &'static str,
bytes: usize,
source: &'static str,
},
SpoolKeyProviderHealthChecked {
provider: &'static str,
backend: &'static str,
auth_mode: &'static str,
auth_fingerprint_label: Arc<str>,
auth_rotation_hint: &'static str,
health_state: &'static str,
startup_self_test_ms: u64,
resolve_key_ms: u64,
},
SpoolKeyProviderHealthCheckFailed {
provider: &'static str,
backend: &'static str,
auth_mode: &'static str,
auth_fingerprint_label: Arc<str>,
auth_rotation_hint: &'static str,
health_state: &'static str,
phase: &'static str,
error_code: &'static str,
},
SpoolKeyProviderHealthStateChanged {
provider: &'static str,
backend: &'static str,
previous_state: &'static str,
current_state: &'static str,
reason: &'static str,
},
SpoolProviderHealthAlertRaised {
severity: &'static str,
category: &'static str,
observed_rate_ppm: u64,
sample_size: u64,
},
SpoolHeadroomChecked {
stage: &'static str,
free_bytes: u64,
min_required_bytes: u64,
},
PullQueueOverflow {
message_id: Arc<str>,
action: &'static str,
policy: &'static str,
},
CertOcspRevoked {
message_id: Arc<str>,
subject_cn: Arc<str>,
serial_hex: Arc<str>,
},
CertOcspUnknown {
message_id: Arc<str>,
subject_cn: Arc<str>,
},
CertNearExpiry {
message_id: Arc<str>,
subject_cn: Arc<str>,
days_remaining: i64,
},
As2AsyncMdnRequested {
message_id: Arc<str>,
mailto_address: Arc<str>,
},
}
impl AsxEvent {
pub fn kind(&self) -> &'static str {
match self {
Self::OutboundPrepared { .. } => "outbound_prepared",
Self::MicComputed { .. } => "mic_computed",
Self::MessageSigned { .. } => "message_signed",
Self::MessageEncrypted { .. } => "message_encrypted",
Self::MdnReceived { .. } => "mdn_received",
Self::ReceiptReceived { .. } => "receipt_received",
Self::ReceiptTaxonomyOutcome { .. } => "receipt_taxonomy_outcome",
Self::ReceiptTaxonomyAlertRaised { .. } => "receipt_taxonomy_alert_raised",
Self::RetryScheduled { .. } => "retry_scheduled",
Self::ReconciliationQueued { .. } => "reconciliation_queued",
Self::DuplicateDetected { .. } => "duplicate_detected",
Self::InteropRelaxationApplied { .. } => "interop_relaxation_applied",
Self::InteropGuardrailEvaluated { .. } => "interop_guardrail_evaluated",
Self::MaterializationApplied { .. } => "materialization_applied",
Self::SpoolKeyProviderHealthChecked { .. } => "spool_key_provider_health_checked",
Self::SpoolKeyProviderHealthCheckFailed { .. } => {
"spool_key_provider_health_check_failed"
}
Self::SpoolKeyProviderHealthStateChanged { .. } => {
"spool_key_provider_health_state_changed"
}
Self::SpoolProviderHealthAlertRaised { .. } => "spool_provider_health_alert_raised",
Self::SpoolHeadroomChecked { .. } => "spool_headroom_checked",
Self::PullQueueOverflow { .. } => "pull_queue_overflow",
Self::CertOcspRevoked { .. } => "cert_ocsp_revoked",
Self::CertOcspUnknown { .. } => "cert_ocsp_unknown",
Self::CertNearExpiry { .. } => "cert_near_expiry",
Self::As2AsyncMdnRequested { .. } => "as2_async_mdn_requested",
}
}
}
pub type SharedAsxEvent = Arc<AsxEvent>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopedAsxEvent {
pub session_id: String,
pub partner_id: String,
pub timestamp_ms: u64,
pub traceparent: Option<Arc<str>>,
pub event: SharedAsxEvent,
}