845b85e7a7
cargo fmt without --all fails with "Failed to find targets" in workspace repos. This was blocking every story's gates. Also ran cargo fmt --all to fix all existing formatting issues. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
120 lines
4.2 KiB
Rust
120 lines
4.2 KiB
Rust
//! 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.
|
|
|
|
pub mod commands;
|
|
pub(crate) mod lookup;
|
|
#[cfg(test)]
|
|
pub(crate) mod test_helpers;
|
|
pub mod timer;
|
|
pub mod transport;
|
|
pub mod util;
|
|
|
|
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;
|
|
|
|
/// 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 WhatsAppTransport satisfies the ChatTransport trait and
|
|
/// can be used as `Arc<dyn ChatTransport>` (compile-time check).
|
|
/// Functional tests are in `whatsapp::tests` using mockito.
|
|
#[test]
|
|
fn whatsapp_transport_satisfies_trait() {
|
|
fn assert_transport<T: ChatTransport>() {}
|
|
assert_transport::<crate::chat::transport::whatsapp::WhatsAppTransport>();
|
|
|
|
// Verify it can be wrapped in Arc<dyn ChatTransport>.
|
|
let _: Arc<dyn ChatTransport> =
|
|
Arc::new(crate::chat::transport::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<T: Send + Sync>() {}
|
|
assert_send_sync::<crate::chat::transport::matrix::transport_impl::MatrixTransport>();
|
|
}
|
|
|
|
/// Verify that SlackTransport satisfies the ChatTransport trait and
|
|
/// can be used as `Arc<dyn ChatTransport>` (compile-time check).
|
|
#[test]
|
|
fn slack_transport_satisfies_trait() {
|
|
fn assert_transport<T: ChatTransport>() {}
|
|
assert_transport::<crate::chat::transport::slack::SlackTransport>();
|
|
|
|
let _: Arc<dyn ChatTransport> = Arc::new(
|
|
crate::chat::transport::slack::SlackTransport::new("xoxb-test".to_string()),
|
|
);
|
|
}
|
|
|
|
/// Verify that TwilioWhatsAppTransport satisfies the ChatTransport trait
|
|
/// and can be used as `Arc<dyn ChatTransport>` (compile-time check).
|
|
#[test]
|
|
fn twilio_transport_satisfies_trait() {
|
|
fn assert_transport<T: ChatTransport>() {}
|
|
assert_transport::<crate::chat::transport::whatsapp::TwilioWhatsAppTransport>();
|
|
|
|
let _: Arc<dyn ChatTransport> = Arc::new(
|
|
crate::chat::transport::whatsapp::TwilioWhatsAppTransport::new(
|
|
"ACtest".to_string(),
|
|
"authtoken".to_string(),
|
|
"+14155551234".to_string(),
|
|
),
|
|
);
|
|
}
|
|
}
|