use std::fmt;
use axum::http::StatusCode;
use super::channel::ChannelError;
#[derive(Debug)]
pub enum RealtimeError {
Origin,
Unauthorized,
ConnectionLimit,
Protocol { hint: ProtocolHint },
Channel(ChannelError),
Shutdown { remaining: usize },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProtocolHint {
Oversize,
Malformed,
Utf8,
Stream,
}
impl fmt::Display for ProtocolHint {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Oversize => f.write_str("oversize"),
Self::Malformed => f.write_str("malformed"),
Self::Utf8 => f.write_str("utf8"),
Self::Stream => f.write_str("stream"),
}
}
}
impl fmt::Display for RealtimeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Origin => f.write_str("origin not allowed"),
Self::Unauthorized => f.write_str("unauthorized"),
Self::ConnectionLimit => f.write_str("connection limit reached"),
Self::Protocol { hint } => write!(f, "protocol error: {hint}"),
Self::Channel(e) => write!(f, "channel error: {e}"),
Self::Shutdown { remaining } => {
write!(f, "drain timed out with {remaining} connections remaining")
}
}
}
}
impl std::error::Error for RealtimeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Channel(e) => Some(e),
_ => None,
}
}
}
impl From<ChannelError> for RealtimeError {
fn from(e: ChannelError) -> Self {
Self::Channel(e)
}
}
#[must_use]
pub fn admission_status(e: &RealtimeError) -> StatusCode {
match e {
RealtimeError::Origin | RealtimeError::Unauthorized => StatusCode::FORBIDDEN,
RealtimeError::ConnectionLimit => StatusCode::SERVICE_UNAVAILABLE,
RealtimeError::Protocol { .. }
| RealtimeError::Channel(_)
| RealtimeError::Shutdown { .. } => StatusCode::INTERNAL_SERVER_ERROR,
}
}