use chrono::{DateTime, Utc};
use trust_tasks_rs::TrustTaskCode;
use crate::transport::TransportKind;
#[derive(Debug, thiserror::Error)]
pub enum TrqlError {
#[error("configuration error: {0}")]
Config(String),
#[error("{kind} transport error: {detail}")]
Transport {
kind: TransportKind,
detail: String,
},
#[error("{kind} reply timed out after {waited_secs}s")]
Timeout {
kind: TransportKind,
waited_secs: u64,
},
#[error("registry rejected the task ({code}): {}", message.as_deref().unwrap_or("no detail"))]
Rejected {
code: TrustTaskCode,
retryable: bool,
retry_after: Option<DateTime<Utc>>,
message: Option<String>,
},
#[error("contract violation: {0}")]
Contract(String),
#[error("registry answered for a different {field}: asked `{asked}`, answered `{answered}`")]
AnswerMismatch {
field: &'static str,
asked: String,
answered: String,
},
#[error(
"referral from `{origin}` not closed: registry answered for authority `{answered}`, \
which does not confirm the referral"
)]
ReferralNotClosed {
origin: String,
answered: String,
},
#[error(
"no shared transport with the registry (we speak [{}], it advertises [{}])",
format_kinds(ours),
format_kinds(theirs)
)]
NoMatchingTransport {
ours: Vec<TransportKind>,
theirs: Vec<TransportKind>,
},
}
fn format_kinds(kinds: &[TransportKind]) -> String {
if kinds.is_empty() {
return "none".to_string();
}
kinds
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ")
}
impl TrqlError {
pub fn is_retryable(&self) -> bool {
match self {
Self::Transport { .. } | Self::Timeout { .. } => true,
Self::Rejected { retryable, .. } => *retryable,
Self::Config(_)
| Self::Contract(_)
| Self::NoMatchingTransport { .. }
| Self::AnswerMismatch { .. }
| Self::ReferralNotClosed { .. } => false,
}
}
}