use thiserror::Error;
use crate::pdu::AkkaPdu;
use crate::transport::TransportError;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum RemoteErrorKind {
Handshake,
Quarantined,
Tombstoned,
UnknownPdu,
Codec,
Transport,
Closed,
Timeout,
BackPressure,
Other,
}
impl RemoteErrorKind {
pub fn as_str(self) -> &'static str {
match self {
Self::Handshake => "handshake",
Self::Quarantined => "quarantined",
Self::Tombstoned => "tombstoned",
Self::UnknownPdu => "unknown_pdu",
Self::Codec => "codec",
Self::Transport => "transport",
Self::Closed => "closed",
Self::Timeout => "timeout",
Self::BackPressure => "back_pressure",
Self::Other => "other",
}
}
}
#[derive(Debug, Error)]
#[error("{kind:?}: {message}")]
#[non_exhaustive]
pub struct RemoteError {
pub kind: RemoteErrorKind,
pub message: String,
}
impl RemoteError {
pub fn new(kind: RemoteErrorKind, message: impl Into<String>) -> Self {
Self { kind, message: message.into() }
}
pub fn unknown_pdu(pdu: &AkkaPdu) -> Self {
Self::new(RemoteErrorKind::UnknownPdu, format!("unexpected PDU: {pdu:?}"))
}
pub fn quarantined(target: impl std::fmt::Display) -> Self {
Self::new(RemoteErrorKind::Quarantined, format!("{target} is quarantined"))
}
pub fn tombstoned(target: impl std::fmt::Display) -> Self {
Self::new(RemoteErrorKind::Tombstoned, format!("{target} is tombstoned"))
}
}
impl From<TransportError> for RemoteError {
fn from(e: TransportError) -> Self {
let (kind, msg) = match &e {
TransportError::HandshakeRejected(s) => (RemoteErrorKind::Handshake, s.clone()),
TransportError::Closed => (RemoteErrorKind::Closed, "transport closed".into()),
other => (RemoteErrorKind::Transport, other.to_string()),
};
Self::new(kind, msg)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_transport_handshake_rejected() {
let t = TransportError::HandshakeRejected("bad cookie".into());
let r: RemoteError = t.into();
assert_eq!(r.kind, RemoteErrorKind::Handshake);
assert!(r.message.contains("bad cookie"));
}
#[test]
fn quarantined_constructs() {
let r = RemoteError::quarantined("akka.tcp://Sys@host:7355");
assert_eq!(r.kind, RemoteErrorKind::Quarantined);
assert!(r.message.contains("host:7355"));
}
#[test]
fn kind_strings_stable() {
assert_eq!(RemoteErrorKind::Handshake.as_str(), "handshake");
assert_eq!(RemoteErrorKind::UnknownPdu.as_str(), "unknown_pdu");
}
}