use std::time::Duration;
use async_trait::async_trait;
use cratefield_core::Database;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChannelMessage {
pub category: String,
pub title: String,
pub body: String,
pub url: Option<String>,
pub notification_id: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ChannelError {
Unreachable,
Permanent(String),
Transient { retry_after: Option<Duration> },
}
impl std::fmt::Display for ChannelError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ChannelError::Unreachable => {
f.write_str("the account is not reachable on this channel")
}
ChannelError::Permanent(message) => f.write_str(message),
ChannelError::Transient { retry_after } => match retry_after {
Some(after) => write!(f, "transient; retry after {after:?}"),
None => f.write_str("transient"),
},
}
}
}
impl std::error::Error for ChannelError {}
#[async_trait]
pub trait Channel: Send + Sync + 'static {
fn name(&self) -> &'static str;
async fn reachable(&self, db: &dyn Database, account_id: &str) -> Result<bool, ChannelError>;
async fn deliver(
&self,
db: &dyn Database,
account_id: &str,
message: &ChannelMessage,
) -> Result<(), ChannelError>;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn an_error_says_what_a_dead_letter_reason_cannot() {
assert_eq!(
ChannelError::Unreachable.to_string(),
"the account is not reachable on this channel"
);
assert_eq!(
ChannelError::Permanent("telegram 400: chat not found".to_owned()).to_string(),
"telegram 400: chat not found"
);
assert_eq!(
ChannelError::Transient { retry_after: None }.to_string(),
"transient"
);
assert!(
ChannelError::Transient {
retry_after: Some(Duration::from_mins(15))
}
.to_string()
.contains("900"),
"the delay the channel named is in the text"
);
}
}