//! WhatsApp stub implementation of [`ChatTransport`]. //! //! This is a placeholder transport that logs operations and returns stub //! values. It exists to prove the transport abstraction works with a //! second platform and will be replaced with a real WhatsApp Business API //! integration in the future. use async_trait::async_trait; use crate::slog; use crate::transport::{ChatTransport, MessageId}; /// Stub WhatsApp transport. /// /// All methods log the operation and return success with placeholder values. /// Message editing is not supported by WhatsApp — `edit_message` sends a /// new message instead (TODO: implement via WhatsApp Business API). pub struct WhatsAppTransport { /// Counter for generating unique stub message IDs. next_id: std::sync::atomic::AtomicU64, } impl WhatsAppTransport { pub fn new() -> Self { Self { next_id: std::sync::atomic::AtomicU64::new(1), } } fn next_message_id(&self) -> String { let id = self .next_id .fetch_add(1, std::sync::atomic::Ordering::Relaxed); format!("whatsapp-stub-{id}") } } impl Default for WhatsAppTransport { fn default() -> Self { Self::new() } } #[async_trait] impl ChatTransport for WhatsAppTransport { async fn send_message( &self, room_id: &str, plain: &str, _html: &str, ) -> Result { // TODO: Send via WhatsApp Business API let msg_id = self.next_message_id(); slog!( "[whatsapp-stub] send_message to {room_id}: {plain:.80} (id={msg_id})" ); Ok(msg_id) } async fn edit_message( &self, room_id: &str, original_message_id: &str, plain: &str, html: &str, ) -> Result<(), String> { // WhatsApp does not support message editing. // Send a new message instead. slog!( "[whatsapp-stub] edit_message (original={original_message_id}) — \ WhatsApp does not support edits, sending new message" ); self.send_message(room_id, plain, html).await.map(|_| ()) } async fn send_typing(&self, room_id: &str, typing: bool) -> Result<(), String> { // TODO: Send typing indicator via WhatsApp Business API slog!("[whatsapp-stub] send_typing to {room_id}: typing={typing}"); Ok(()) } } #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn send_message_returns_unique_ids() { let transport = WhatsAppTransport::new(); let id1 = transport .send_message("room1", "hello", "

hello

") .await .unwrap(); let id2 = transport .send_message("room1", "world", "

world

") .await .unwrap(); assert_ne!(id1, id2, "each message should get a unique ID"); assert!(id1.starts_with("whatsapp-stub-")); } #[tokio::test] async fn edit_message_succeeds() { let transport = WhatsAppTransport::new(); let result = transport .edit_message("room1", "msg-1", "updated", "

updated

") .await; assert!(result.is_ok(), "edit should succeed (sends new message)"); } #[tokio::test] async fn send_typing_succeeds() { let transport = WhatsAppTransport::new(); assert!(transport.send_typing("room1", true).await.is_ok()); assert!(transport.send_typing("room1", false).await.is_ok()); } }