use async_trait::async_trait;
pub use echo_core::error::ChannelError;
pub use echo_core::error::ReactError;
use echo_core::error::Result;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChatType {
Direct,
Group,
}
impl std::fmt::Display for ChatType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ChatType::Direct => write!(f, "direct"),
ChatType::Group => write!(f, "group"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AttachmentKind {
Image,
File,
Audio,
Video,
}
#[derive(Debug, Clone)]
pub struct MessageAttachment {
pub kind: AttachmentKind,
pub data: Vec<u8>,
pub filename: Option<String>,
}
impl MessageAttachment {
pub fn new(kind: AttachmentKind, data: Vec<u8>) -> Self {
Self {
kind,
data,
filename: None,
}
}
pub fn with_filename(mut self, filename: impl Into<String>) -> Self {
self.filename = Some(filename.into());
self
}
}
#[derive(Debug, Clone)]
pub struct InboundMessage {
pub channel_id: String,
pub sender_id: String,
pub chat_id: String,
pub chat_type: ChatType,
pub text: String,
pub message_id: String,
pub timestamp: u64,
pub attachments: Vec<MessageAttachment>,
}
impl InboundMessage {
pub fn new(
channel_id: impl Into<String>,
sender_id: impl Into<String>,
chat_id: impl Into<String>,
chat_type: ChatType,
text: impl Into<String>,
message_id: impl Into<String>,
) -> Self {
Self {
channel_id: channel_id.into(),
sender_id: sender_id.into(),
chat_id: chat_id.into(),
chat_type,
text: text.into(),
message_id: message_id.into(),
timestamp: chrono::Utc::now().timestamp() as u64,
attachments: Vec::new(),
}
}
pub fn with_attachments(mut self, attachments: Vec<MessageAttachment>) -> Self {
self.attachments = attachments;
self
}
}
#[derive(Debug, Clone)]
pub struct OutboundMessage {
pub channel_id: String,
pub to: String,
pub chat_type: ChatType,
pub text: String,
pub reply_to: Option<String>,
pub attachments: Vec<MessageAttachment>,
}
impl OutboundMessage {
pub fn new(
channel_id: impl Into<String>,
to: impl Into<String>,
chat_type: ChatType,
text: impl Into<String>,
) -> Self {
Self {
channel_id: channel_id.into(),
to: to.into(),
chat_type,
text: text.into(),
reply_to: None,
attachments: Vec::new(),
}
}
pub fn with_reply_to(mut self, reply_to: impl Into<String>) -> Self {
self.reply_to = Some(reply_to.into());
self
}
pub fn with_attachments(mut self, attachments: Vec<MessageAttachment>) -> Self {
self.attachments = attachments;
self
}
}
use std::sync::Arc;
#[async_trait]
pub trait MessageHandler: Send + Sync {
async fn handle(&self, msg: InboundMessage) -> Result<OutboundMessage>;
async fn reply(&self, msg: OutboundMessage) -> Result<()>;
}
#[derive(Debug)]
pub struct ChannelCapabilities {
pub chat_types: &'static [ChatType],
pub supports_media: bool,
pub supports_threads: bool,
}
#[async_trait]
pub trait ChannelPlugin: Send + Sync {
fn id(&self) -> &str;
fn label(&self) -> &str {
self.id()
}
fn capabilities(&self) -> &ChannelCapabilities;
async fn start(&mut self, handler: Arc<dyn MessageHandler>) -> Result<()>;
async fn stop(&mut self) -> Result<()>;
async fn send(&self, msg: OutboundMessage) -> Result<()>;
async fn health_check(&self) -> Result<()> {
Ok(())
}
}
pub struct ChannelContext {
pub handler: Arc<dyn MessageHandler>,
}
impl ChannelContext {
pub fn new(handler: Arc<dyn MessageHandler>) -> Self {
Self { handler }
}
}