#[cfg(feature = "sqlx")]
use std::sync::Arc;
use systemprompt_identifiers::UserId;
use systemprompt_models::notifications::{
Attention, AudienceSubject, Notification, NotificationEvent, RoutePlan, StreamDecl, SubjectRef,
};
#[cfg(feature = "sqlx")]
use super::errors::NotificationSinkError;
use super::errors::{
ChannelError, NotificationAudienceError, NotificationRouterError, PublishPolicyError,
VisibilityError,
};
#[cfg(feature = "sqlx")]
#[async_trait::async_trait]
pub trait NotificationSink: Send + Sync {
fn is_available(&self) -> bool;
async fn emit(
&self,
conn: &mut sqlx::PgConnection,
event: &NotificationEvent,
) -> Result<(), NotificationSinkError>;
}
#[cfg(feature = "sqlx")]
pub type DynNotificationSink = Arc<dyn NotificationSink>;
#[async_trait::async_trait]
pub trait NotificationRouter: Send + Sync {
fn name(&self) -> &'static str;
async fn route(&self, event: &NotificationEvent) -> Result<RoutePlan, NotificationRouterError>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Membership {
Member,
NotMember,
Unknown,
}
#[async_trait::async_trait]
pub trait NotificationAudienceResolver: Send + Sync {
fn name(&self) -> &'static str;
fn handles(&self, subject: &AudienceSubject) -> bool;
async fn members(
&self,
subject: &AudienceSubject,
limit: usize,
) -> Result<Vec<UserId>, NotificationAudienceError>;
async fn is_member(
&self,
subject: &AudienceSubject,
user: &UserId,
) -> Result<Membership, NotificationAudienceError>;
}
#[async_trait::async_trait]
pub trait NotificationActorDirectory: Send + Sync {
async fn display_name(
&self,
actor: &UserId,
) -> Result<Option<String>, NotificationAudienceError>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PublishVerdict {
Admit,
Refuse { reason: String },
}
#[async_trait::async_trait]
pub trait PublishPolicy: Send + Sync {
fn name(&self) -> &'static str;
async fn may_publish(
&self,
publisher: &UserId,
stream: &StreamDecl,
) -> Result<PublishVerdict, PublishPolicyError>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Visibility {
Hidden,
Visible { excerpt_allowed: bool },
}
#[async_trait::async_trait]
pub trait ResourceVisibility: Send + Sync {
fn kinds(&self) -> &'static [&'static str];
async fn visible(
&self,
subject: &SubjectRef,
reader: &UserId,
) -> Result<Visibility, VisibilityError>;
async fn visible_many(
&self,
subject: &SubjectRef,
readers: &[UserId],
) -> Result<Vec<Visibility>, VisibilityError> {
let mut verdicts = Vec::with_capacity(readers.len());
for reader in readers {
verdicts.push(self.visible(subject, reader).await?);
}
Ok(verdicts)
}
}
#[async_trait::async_trait]
pub trait NotificationChannel: Send + Sync {
fn surface(&self) -> &'static str;
fn delivers(&self, attention: Attention) -> bool;
async fn deliver(&self, notification: &Notification, unread: i64) -> Result<(), ChannelError>;
}