Skip to main content

rustyclaw_core/messengers/
mod.rs

1//! Messenger implementations for various chat platforms.
2//!
3//! Each messenger implements the `Messenger` trait and can be enabled
4//! via feature flags in Cargo.toml.
5
6use anyhow::Result;
7use async_trait::async_trait;
8use serde::{Deserialize, Serialize};
9
10// ── Core types ──────────────────────────────────────────────────────────────
11
12/// Represents a message in the messenger system
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Message {
15    pub id: String,
16    pub sender: String,
17    pub content: String,
18    pub timestamp: i64,
19    #[serde(default)]
20    pub channel: Option<String>,
21    #[serde(default)]
22    pub reply_to: Option<String>,
23    #[serde(default)]
24    pub media: Option<Vec<MediaAttachment>>,
25}
26
27/// Media attachment in a message
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct MediaAttachment {
30    pub url: Option<String>,
31    pub path: Option<String>,
32    pub mime_type: Option<String>,
33    pub filename: Option<String>,
34}
35
36/// Options for sending a message
37#[derive(Debug, Default)]
38pub struct SendOptions<'a> {
39    pub recipient: &'a str,
40    pub content: &'a str,
41    pub reply_to: Option<&'a str>,
42    pub silent: bool,
43    pub media: Option<&'a str>,
44}
45
46// ── Messenger trait ─────────────────────────────────────────────────────────
47
48/// Trait for messenger implementations (OpenClaw compatible)
49#[async_trait]
50pub trait Messenger: Send + Sync {
51    /// Get the messenger name
52    fn name(&self) -> &str;
53
54    /// Get the messenger type (telegram, discord, signal, matrix, etc.)
55    fn messenger_type(&self) -> &str;
56
57    /// Initialize the messenger (connect, authenticate, etc.)
58    async fn initialize(&mut self) -> Result<()>;
59
60    /// Send a message to a recipient/channel
61    async fn send_message(&self, recipient: &str, content: &str) -> Result<String>;
62
63    /// Send a message with additional options
64    async fn send_message_with_options(&self, opts: SendOptions<'_>) -> Result<String> {
65        // Default implementation ignores options
66        self.send_message(opts.recipient, opts.content).await
67    }
68
69    /// Receive pending messages (non-blocking poll)
70    async fn receive_messages(&self) -> Result<Vec<Message>>;
71
72    /// Check if the messenger is connected
73    fn is_connected(&self) -> bool;
74
75    /// Disconnect the messenger
76    async fn disconnect(&mut self) -> Result<()>;
77}
78
79// ── Messenger manager ───────────────────────────────────────────────────────
80
81/// Manager for multiple messengers
82pub struct MessengerManager {
83    messengers: Vec<Box<dyn Messenger>>,
84}
85
86impl MessengerManager {
87    pub fn new() -> Self {
88        Self {
89            messengers: Vec::new(),
90        }
91    }
92
93    /// Add a messenger to the manager
94    pub fn add_messenger(&mut self, messenger: Box<dyn Messenger>) {
95        self.messengers.push(messenger);
96    }
97
98    /// Initialize all messengers
99    pub async fn initialize_all(&mut self) -> Result<()> {
100        for messenger in &mut self.messengers {
101            messenger.initialize().await?;
102        }
103        Ok(())
104    }
105
106    /// Get all messengers
107    pub fn get_messengers(&self) -> &[Box<dyn Messenger>] {
108        &self.messengers
109    }
110
111    /// Get a messenger by name
112    pub fn get_messenger(&self, name: &str) -> Option<&dyn Messenger> {
113        self.messengers
114            .iter()
115            .find(|m| m.name() == name)
116            .map(|b| &**b)
117    }
118
119    /// Get a messenger by type
120    pub fn get_messenger_by_type(&self, msg_type: &str) -> Option<&dyn Messenger> {
121        self.messengers
122            .iter()
123            .find(|m| m.messenger_type() == msg_type)
124            .map(|b| &**b)
125    }
126
127    /// Disconnect all messengers
128    pub async fn disconnect_all(&mut self) -> Result<()> {
129        for messenger in &mut self.messengers {
130            messenger.disconnect().await?;
131        }
132        Ok(())
133    }
134}
135
136impl Default for MessengerManager {
137    fn default() -> Self {
138        Self::new()
139    }
140}
141
142// ── Built-in messengers ─────────────────────────────────────────────────────
143
144mod webhook;
145mod console;
146mod discord;
147mod telegram;
148
149pub use webhook::WebhookMessenger;
150pub use console::ConsoleMessenger;
151pub use discord::DiscordMessenger;
152pub use telegram::TelegramMessenger;
153
154// ── Optional messengers (feature-gated) ─────────────────────────────────────
155
156#[cfg(feature = "matrix")]
157mod matrix;
158#[cfg(feature = "matrix")]
159pub use matrix::MatrixMessenger;
160
161#[cfg(feature = "signal")]
162mod signal;
163#[cfg(feature = "signal")]
164pub use signal::SignalMessenger;