use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DispatchAck {
pub msg_id: Option<String>,
}
#[non_exhaustive]
#[derive(Debug, Error, Clone, PartialEq, Eq)]
pub enum DispatchError {
#[error("unauthorized binding `{channel}:{account_id}`")]
UnauthorizedBinding {
channel: String,
account_id: String,
},
#[error("channel `{0}` adapter not registered")]
ChannelUnavailable(String),
#[error("rate limit exceeded")]
RateLimitExceeded,
#[error("validation error: {0}")]
ValidationError(String),
#[error("transport: {0}")]
Transport(String),
}
#[derive(Debug, Clone)]
pub struct OutboundDispatcher {
stub: bool,
}
impl OutboundDispatcher {
pub fn new_stub() -> Self {
Self { stub: true }
}
pub async fn send_text(
&self,
channel: &str,
account_id: &str,
to: &str,
text: &str,
) -> Result<DispatchAck, DispatchError> {
let _ = (channel, account_id, to, text);
if self.stub {
return Err(DispatchError::Transport(
"82.3.b runtime not ready".to_string(),
));
}
Ok(DispatchAck { msg_id: None })
}
pub async fn send_media(
&self,
channel: &str,
account_id: &str,
to: &str,
media_url: &str,
caption: Option<&str>,
) -> Result<DispatchAck, DispatchError> {
let _ = (channel, account_id, to, media_url, caption);
if self.stub {
return Err(DispatchError::Transport(
"82.3.b runtime not ready".to_string(),
));
}
Ok(DispatchAck { msg_id: None })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn send_text_stub_returns_transport_error() {
let d = OutboundDispatcher::new_stub();
let r = d
.send_text("whatsapp", "personal", "+5491100", "hi")
.await;
assert!(matches!(r, Err(DispatchError::Transport(_))));
}
#[tokio::test]
async fn send_media_stub_returns_transport_error() {
let d = OutboundDispatcher::new_stub();
let r = d
.send_media("whatsapp", "personal", "+5491100", "http://x", None)
.await;
assert!(matches!(r, Err(DispatchError::Transport(_))));
}
#[test]
fn dispatch_error_unauthorized_binding_renders_message() {
let e = DispatchError::UnauthorizedBinding {
channel: "whatsapp".into(),
account_id: "x".into(),
};
assert!(format!("{e}").contains("unauthorized binding"));
}
}