use std::io;
use std::sync::Arc;
#[derive(Debug, thiserror::Error)]
pub enum RuntimeError {
#[error("io error: {0}")]
Io(#[from] io::Error),
#[error("channel closed")]
ChannelClosed,
#[error("channel full")]
ChannelFull,
#[error("blocking operation is unavailable in a current-thread async context")]
BlockingInAsyncContext,
#[error("operation timed out")]
Timeout,
#[error("operation cancelled")]
Cancelled,
#[error("task panicked: {0}")]
TaskPanicked(Box<str>),
#[error("no runtime context is established")]
NoRuntime,
#[error("task scope is closed to admission")]
ScopeClosed,
#[error("scope drain timed out; children outstanding: {0}")]
ScopeDrainTimeout(usize),
#[error("http error: {0}")]
Http(Arc<str>),
#[error("bad request: {0}")]
BadRequest(Box<str>),
#[error("malformed request body: {0}")]
MalformedBody(Box<str>),
#[error("invalid multipart body: {0}")]
Multipart(Box<str>),
#[error("database error: {0}")]
Database(Box<str>),
#[error("tls error: {0}")]
Tls(Box<str>),
#[error("invalid argument: {0}")]
InvalidArgument(Box<str>),
#[error("schedule error: {0}")]
Schedule(Box<str>),
#[error("message queue error: {0}")]
MessageQueue(Box<str>),
#[error("config error: {0}")]
Config(Box<str>),
#[error("secret error: {0}")]
Secret(Box<str>),
#[error("dns error: {0}")]
Dns(Box<str>),
#[error("acme error: {0}")]
Acme(Box<str>),
}
fn io_kind(err: &RuntimeError) -> Option<io::ErrorKind> {
match err {
RuntimeError::Io(e) => Some(e.kind()),
_ => None,
}
}
fn is_benign_kind(kind: io::ErrorKind) -> bool {
matches!(
kind,
io::ErrorKind::ConnectionReset
| io::ErrorKind::ConnectionAborted
| io::ErrorKind::BrokenPipe
| io::ErrorKind::NotConnected
)
}
pub(crate) fn is_benign_io(err: &io::Error) -> bool {
is_benign_kind(err.kind())
}
pub(crate) fn is_benign_io_error(err: &RuntimeError) -> bool {
matches!(io_kind(err), Some(kind) if is_benign_kind(kind))
}
pub(crate) fn is_transient_datagram_error(err: &RuntimeError) -> bool {
matches!(
io_kind(err),
Some(
io::ErrorKind::ConnectionRefused
| io::ErrorKind::ConnectionReset
| io::ErrorKind::Interrupted
)
)
}
const EMFILE: i32 = 24; const ENFILE: i32 = 23;
pub(crate) fn is_transient_accept_error(err: &io::Error) -> bool {
matches!(err.raw_os_error(), Some(EMFILE | ENFILE))
}