use async_trait::async_trait;
use std::time::Duration;
use thiserror::Error;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Member {
pub id: String,
}
impl Member {
#[must_use]
pub fn new(id: impl Into<String>) -> Self {
Self { id: id.into() }
}
}
#[derive(Debug, Clone, Error)]
pub enum RealtimeError {
#[error("realtime is not configured")]
NotConfigured,
#[error("sender is not a member of this room")]
NotAMember,
#[error("no such room: {0}")]
NoSuchRoom(String),
#[error("realtime operation failed: {0}")]
Operation(String),
}
#[async_trait]
pub trait RoomContext: Send + Sync {
fn room_id(&self) -> &str;
async fn members(&self) -> Vec<Member>;
async fn broadcast(&self, message: &[u8]) -> Result<(), RealtimeError>;
async fn send(&self, member_id: &str, message: &[u8]) -> Result<(), RealtimeError>;
async fn set_alarm(&self, delay: Duration) -> Result<(), RealtimeError>;
}
#[async_trait]
pub trait RoomHandler: Send + Sync {
fn route(&self) -> &'static str {
"/rooms"
}
async fn on_join(&self, ctx: &dyn RoomContext, member: &Member) -> Result<(), RealtimeError> {
let _ = (ctx, member);
Ok(())
}
async fn on_message(
&self,
ctx: &dyn RoomContext,
member: &Member,
message: &[u8],
) -> Result<(), RealtimeError>;
async fn on_leave(&self, ctx: &dyn RoomContext, member: &Member) -> Result<(), RealtimeError> {
let _ = (ctx, member);
Ok(())
}
async fn on_alarm(&self, ctx: &dyn RoomContext) -> Result<(), RealtimeError> {
let _ = ctx;
Ok(())
}
}
#[async_trait]
pub trait Realtime: Send + Sync {
async fn broadcast(&self, room_id: &str, message: &[u8]) -> Result<(), RealtimeError>;
async fn members(&self, room_id: &str) -> Result<Vec<Member>, RealtimeError>;
}