use std::fmt;
use crate::{ConnectionError, VarInt};
pub const ANT_QUIC_CLOSE_CODE_BASE: u32 = 0x4E5B00;
const CLOSE_CODE_SUPERSEDED: u32 = ANT_QUIC_CLOSE_CODE_BASE;
const CLOSE_CODE_READER_EXIT: u32 = ANT_QUIC_CLOSE_CODE_BASE + 0x01;
const CLOSE_CODE_PEER_SHUTDOWN: u32 = ANT_QUIC_CLOSE_CODE_BASE + 0x02;
const CLOSE_CODE_BANNED: u32 = ANT_QUIC_CLOSE_CODE_BASE + 0x03;
const CLOSE_CODE_LIFECYCLE_CLEANUP: u32 = ANT_QUIC_CLOSE_CODE_BASE + 0x04;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConnectionCloseReason {
Superseded,
ReaderExit,
PeerShutdown,
Banned,
LifecycleCleanup,
ApplicationClosed,
ConnectionClosed,
TimedOut,
Reset,
TransportError,
LocallyClosed,
VersionMismatch,
CidsExhausted,
Unknown,
}
impl ConnectionCloseReason {
pub fn app_error_code(self) -> Option<VarInt> {
let code = match self {
Self::Superseded => CLOSE_CODE_SUPERSEDED,
Self::ReaderExit => CLOSE_CODE_READER_EXIT,
Self::PeerShutdown => CLOSE_CODE_PEER_SHUTDOWN,
Self::Banned => CLOSE_CODE_BANNED,
Self::LifecycleCleanup => CLOSE_CODE_LIFECYCLE_CLEANUP,
Self::ApplicationClosed
| Self::ConnectionClosed
| Self::TimedOut
| Self::Reset
| Self::TransportError
| Self::LocallyClosed
| Self::VersionMismatch
| Self::CidsExhausted
| Self::Unknown => return None,
};
Some(VarInt::from_u32(code))
}
pub fn as_str(self) -> &'static str {
match self {
Self::Superseded => "Superseded",
Self::ReaderExit => "ReaderExit",
Self::PeerShutdown => "PeerShutdown",
Self::Banned => "Banned",
Self::LifecycleCleanup => "LifecycleCleanup",
Self::ApplicationClosed => "ApplicationClosed",
Self::ConnectionClosed => "ConnectionClosed",
Self::TimedOut => "TimedOut",
Self::Reset => "Reset",
Self::TransportError => "TransportError",
Self::LocallyClosed => "LocallyClosed",
Self::VersionMismatch => "VersionMismatch",
Self::CidsExhausted => "CidsExhausted",
Self::Unknown => "Unknown",
}
}
pub fn reason_bytes(self) -> &'static [u8] {
self.as_str().as_bytes()
}
pub fn from_app_error_code(code: VarInt) -> Option<Self> {
match code.into_inner() as u32 {
CLOSE_CODE_SUPERSEDED => Some(Self::Superseded),
CLOSE_CODE_READER_EXIT => Some(Self::ReaderExit),
CLOSE_CODE_PEER_SHUTDOWN => Some(Self::PeerShutdown),
CLOSE_CODE_BANNED => Some(Self::Banned),
CLOSE_CODE_LIFECYCLE_CLEANUP => Some(Self::LifecycleCleanup),
_ => None,
}
}
pub fn from_connection_error(error: &ConnectionError) -> Self {
match error {
ConnectionError::ApplicationClosed(frame) => {
Self::from_app_error_code(frame.error_code).unwrap_or(Self::ApplicationClosed)
}
ConnectionError::ConnectionClosed(_) => Self::ConnectionClosed,
ConnectionError::TransportError(_) => Self::TransportError,
ConnectionError::VersionMismatch => Self::VersionMismatch,
ConnectionError::Reset => Self::Reset,
ConnectionError::TimedOut => Self::TimedOut,
ConnectionError::LocallyClosed => Self::LocallyClosed,
ConnectionError::CidsExhausted => Self::CidsExhausted,
}
}
}
impl fmt::Display for ConnectionCloseReason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ConnectionLifecycleState {
Live,
Superseded {
replaced_by_generation: u64,
},
Closing {
reason: ConnectionCloseReason,
},
Closed {
reason: ConnectionCloseReason,
closed_at_unix_ms: u64,
},
}
impl ConnectionLifecycleState {
pub(crate) fn name(self) -> &'static str {
match self {
Self::Live => "Live",
Self::Superseded { .. } => "Superseded",
Self::Closing { .. } => "Closing",
Self::Closed { .. } => "Closed",
}
}
}