use std::fmt::Debug;
use std::time::{SystemTime, UNIX_EPOCH};
use tokio::sync::mpsc;
use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum EventType {
Created,
Updated,
Deleted,
Custom(u32),
}
impl EventType {
pub fn is_created(&self) -> bool {
matches!(self, EventType::Created)
}
pub fn is_updated(&self) -> bool {
matches!(self, EventType::Updated)
}
pub fn is_deleted(&self) -> bool {
matches!(self, EventType::Deleted)
}
pub fn is_custom(&self) -> bool {
matches!(self, EventType::Custom(_))
}
pub fn custom_code(&self) -> Option<u32> {
match self {
EventType::Custom(code) => Some(*code),
_ => None,
}
}
}
impl std::fmt::Display for EventType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EventType::Created => write!(f, "Created"),
EventType::Updated => write!(f, "Updated"),
EventType::Deleted => write!(f, "Deleted"),
EventType::Custom(code) => write!(f, "Custom({})", code),
}
}
}
#[derive(Debug, Clone)]
pub struct Event<T>
where
T: Clone + Send + Sync,
{
pub id: String,
pub event_type: EventType,
pub data: T,
pub timestamp: u64,
pub source: Option<String>,
pub correlation_id: Option<String>,
}
impl<T> Event<T>
where
T: Clone + Send + Sync,
{
pub fn new(event_type: EventType, data: T) -> Self {
Self {
id: Uuid::new_v4().to_string(),
event_type,
data,
timestamp: current_timestamp_millis(),
source: None,
correlation_id: None,
}
}
pub fn created(data: T) -> Self {
Self::new(EventType::Created, data)
}
pub fn updated(data: T) -> Self {
Self::new(EventType::Updated, data)
}
pub fn deleted(data: T) -> Self {
Self::new(EventType::Deleted, data)
}
pub fn custom(code: u32, data: T) -> Self {
Self::new(EventType::Custom(code), data)
}
pub fn with_source(mut self, source: impl Into<String>) -> Self {
self.source = Some(source.into());
self
}
pub fn with_correlation_id(mut self, correlation_id: impl Into<String>) -> Self {
self.correlation_id = Some(correlation_id.into());
self
}
pub fn is_type(&self, event_type: EventType) -> bool {
self.event_type == event_type
}
}
#[async_trait::async_trait]
pub trait Subscriber<T>: Send + Sync
where
T: Clone + Send + Sync + 'static,
{
async fn on_event(&self, event: Event<T>);
fn should_receive(&self, event: &Event<T>) -> bool {
let _ = event;
true
}
}
#[derive(Debug)]
pub struct SubscriptionHandle {
pub id: String,
active: std::sync::atomic::AtomicBool,
}
impl SubscriptionHandle {
pub fn new() -> Self {
Self {
id: Uuid::new_v4().to_string(),
active: std::sync::atomic::AtomicBool::new(true),
}
}
pub fn is_active(&self) -> bool {
self.active.load(std::sync::atomic::Ordering::Relaxed)
}
pub fn cancel(&self) {
self.active
.store(false, std::sync::atomic::Ordering::Relaxed);
}
}
impl Default for SubscriptionHandle {
fn default() -> Self {
Self::new()
}
}
pub type EventReceiver<T> = mpsc::Receiver<Event<T>>;
pub type EventSender<T> = mpsc::Sender<Event<T>>;
fn current_timestamp_millis() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64
}