//! Transport abstraction for chat platforms. //! //! The [`ChatTransport`] trait defines a platform-agnostic interface for //! sending and editing messages, allowing the bot logic (commands, htop, //! notifications) to work against any chat platform — Matrix, WhatsApp, etc. use async_trait::async_trait; /// A platform-agnostic identifier for a sent message. /// /// On Matrix this is the event ID; on other platforms it may be a message ID /// or similar opaque string. The transport implementation is responsible for /// producing and consuming these identifiers. pub type MessageId = String; /// A platform-agnostic identifier for a chat room / channel / conversation. pub type RoomId = String; /// Abstraction over a chat platform's message-sending capabilities. /// /// Implementations must be `Send + Sync` so they can be shared across /// async tasks via `Arc`. #[async_trait] pub trait ChatTransport: Send + Sync { /// Send a plain-text + HTML message to a room. /// /// Returns the platform-specific message ID on success so it can be /// referenced later (e.g. for edits or reply detection). async fn send_message( &self, room_id: &str, plain: &str, html: &str, ) -> Result; /// Edit a previously sent message. /// /// `original_message_id` is the [`MessageId`] returned by a prior /// [`send_message`](ChatTransport::send_message) call. /// /// Platforms that do not support editing (e.g. WhatsApp) should send a /// new message instead. async fn edit_message( &self, room_id: &str, original_message_id: &str, plain: &str, html: &str, ) -> Result<(), String>; /// Signal that the bot is typing (or has stopped typing) in a room. /// /// Platforms that do not support typing indicators should no-op. async fn send_typing(&self, room_id: &str, typing: bool) -> Result<(), String>; } #[cfg(test)] mod tests { use super::*; use std::sync::Arc; /// Verify that WhatsAppTransport satisfies the ChatTransport trait and /// can be used as `Arc` (compile-time check). /// Functional tests are in `whatsapp::tests` using mockito. #[test] fn whatsapp_transport_satisfies_trait() { fn assert_transport() {} assert_transport::(); // Verify it can be wrapped in Arc. let _: Arc = Arc::new(crate::whatsapp::WhatsAppTransport::new( "test-phone".to_string(), "test-token".to_string(), "pipeline_notification".to_string(), )); } /// MatrixTransport cannot be tested without a live homeserver, but we /// can verify the type implements the trait at compile time. #[test] fn matrix_transport_is_send_sync() { fn assert_send_sync() {} assert_send_sync::(); } }