mod email;
mod slack;
mod telegram;
use std::sync::Arc;
use async_trait::async_trait;
use schemars::Schema;
use tokio::{
sync::{Mutex, mpsc},
task::JoinHandle,
};
use aves::utils::uuid::SpectaUuid;
use crate::messages::ListenerType;
use crate::types::{
MessagingConfig, MessagingCredentials, MessagingError, MessagingInteraction, MessagingSendReceipt,
MessagingSenderConfig, MessagingSubscriptionError, NormalizedMessage,
};
pub(super) type MessagingPluginHandle = Arc<Mutex<Box<dyn MessagingPlugin>>>;
pub(super) const CHANNEL_MESSAGE_BUFFER_SIZE: usize = 100;
#[derive(Clone)]
pub(super) struct MessagingSubscription {
pub(super) subscribed_channels: Option<Vec<String>>,
pub(super) allowed_senders: Vec<String>,
}
#[derive(Debug, Clone)]
pub(super) struct InboundEvent {
pub(super) raw_payload: Vec<u8>,
pub(super) normalized: Option<NormalizedMessage>,
}
impl MessagingSubscription {
pub(super) fn validate(&self, listener_type: ListenerType) -> Result<(), MessagingSubscriptionError> {
if self
.subscribed_channels
.as_ref()
.is_some_and(|channels| channels.is_empty() || channels.iter().any(|channel| channel.trim().is_empty()))
{
return Err(MessagingSubscriptionError::Configuration {
listener_type,
message: "An explicit channel selection must contain non-empty channel identities".to_owned(),
});
}
Ok(())
}
}
pub(super) type MessagingTask = JoinHandle<Result<(), MessagingSubscriptionError>>;
#[async_trait]
pub(super) trait MessagingPlugin: Send + Sync {
async fn connect(
&mut self,
settings: &MessagingConfig,
credentials: &MessagingCredentials,
) -> Result<(), MessagingError>;
async fn send(
&mut self,
sender: &MessagingSenderConfig,
message: &NormalizedMessage,
) -> Result<MessagingSendReceipt, MessagingError>;
fn send_metadata_schema(&self) -> Schema;
async fn listen(
&mut self,
tx: mpsc::Sender<InboundEvent>,
interaction_tx: mpsc::Sender<MessagingInteraction>,
) -> Result<MessagingTask, MessagingSubscriptionError>;
async fn send_interactive(
&mut self,
sender: &MessagingSenderConfig,
request_id: SpectaUuid,
request_text: &str,
) -> Result<String, MessagingError>;
async fn edit_interactive(
&mut self,
sender: &MessagingSenderConfig,
provider_message_id: &str,
request_text: &str,
outcome_label: &str,
) -> Result<(), MessagingError>;
async fn subscribe(
&mut self,
subscription: MessagingSubscription,
rx: mpsc::Receiver<NormalizedMessage>,
tx: mpsc::Sender<NormalizedMessage>,
) -> Result<MessagingTask, MessagingSubscriptionError>;
}
pub(super) fn for_kind(kind: ListenerType) -> Box<dyn MessagingPlugin> {
match kind {
ListenerType::Email => Box::new(email::EmailPlugin::default()),
ListenerType::Slack => Box::new(slack::SlackPlugin::default()),
ListenerType::Telegram => Box::new(telegram::TelegramPlugin::default()),
}
}