story-kit: merge 316_refactor_abstract_bot_transport_layer_for_multi_platform_support
This commit is contained in:
91
server/src/transport.rs
Normal file
91
server/src/transport.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
//! 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<dyn ChatTransport>`.
|
||||
#[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<MessageId, String>;
|
||||
|
||||
/// 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 the WhatsApp stub satisfies the ChatTransport trait and
|
||||
/// can be used as `Arc<dyn ChatTransport>`.
|
||||
#[tokio::test]
|
||||
async fn whatsapp_transport_satisfies_trait() {
|
||||
let transport: Arc<dyn ChatTransport> =
|
||||
Arc::new(crate::whatsapp::WhatsAppTransport::new());
|
||||
|
||||
let msg_id = transport
|
||||
.send_message("room-1", "hello", "<p>hello</p>")
|
||||
.await
|
||||
.unwrap();
|
||||
assert!(!msg_id.is_empty());
|
||||
|
||||
transport
|
||||
.edit_message("room-1", &msg_id, "edited", "<p>edited</p>")
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
transport.send_typing("room-1", true).await.unwrap();
|
||||
transport.send_typing("room-1", false).await.unwrap();
|
||||
}
|
||||
|
||||
/// 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<T: Send + Sync>() {}
|
||||
assert_send_sync::<crate::matrix::transport_impl::MatrixTransport>();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user