use crate::types::BlackoutWindow;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum RedFolderEvent {
BlackoutWarning {
window: BlackoutWindow,
minutes_until_start: i64,
worker_id: Option<String>,
},
BlackoutStarted {
window: BlackoutWindow,
worker_id: Option<String>,
},
BlackoutEnded {
window: BlackoutWindow,
worker_id: Option<String>,
},
CalendarUpdated {
total_events: usize,
total_windows: usize,
},
CalendarSyncFailed { error: String },
}
impl RedFolderEvent {
#[must_use]
pub fn is_blackout_started(&self) -> bool {
matches!(self, RedFolderEvent::BlackoutStarted { .. })
}
#[must_use]
pub fn is_blackout_ended(&self) -> bool {
matches!(self, RedFolderEvent::BlackoutEnded { .. })
}
#[must_use]
pub fn is_warning(&self) -> bool {
matches!(self, RedFolderEvent::BlackoutWarning { .. })
}
#[must_use]
pub fn is_sync_failed(&self) -> bool {
matches!(self, RedFolderEvent::CalendarSyncFailed { .. })
}
#[must_use]
pub fn window(&self) -> Option<&BlackoutWindow> {
match self {
RedFolderEvent::BlackoutWarning { window, .. } => Some(window),
RedFolderEvent::BlackoutStarted { window, .. } => Some(window),
RedFolderEvent::BlackoutEnded { window, .. } => Some(window),
RedFolderEvent::CalendarUpdated { .. } | RedFolderEvent::CalendarSyncFailed { .. } => {
None
}
}
}
#[must_use]
pub fn worker_id(&self) -> Option<&str> {
match self {
RedFolderEvent::BlackoutWarning { worker_id, .. } => worker_id.as_deref(),
RedFolderEvent::BlackoutStarted { worker_id, .. } => worker_id.as_deref(),
RedFolderEvent::BlackoutEnded { worker_id, .. } => worker_id.as_deref(),
RedFolderEvent::CalendarUpdated { .. } | RedFolderEvent::CalendarSyncFailed { .. } => {
None
}
}
}
}
#[async_trait::async_trait]
pub trait EventListener: Send + Sync {
async fn on_event(&self, event: &RedFolderEvent);
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::{Duration, Utc};
#[test]
fn test_event_methods() {
let now = Utc::now();
let window = BlackoutWindow {
start: now,
end: now + Duration::minutes(30),
events: vec![],
};
let started = RedFolderEvent::BlackoutStarted {
window: window.clone(),
worker_id: Some("eurusd".into()),
};
assert!(started.is_blackout_started());
assert!(!started.is_blackout_ended());
assert_eq!(started.worker_id(), Some("eurusd"));
assert!(started.window().is_some());
let ended = RedFolderEvent::BlackoutEnded {
window: window.clone(),
worker_id: None,
};
assert!(ended.is_blackout_ended());
let warning = RedFolderEvent::BlackoutWarning {
window,
minutes_until_start: 5,
worker_id: None,
};
assert!(warning.is_warning());
let sync_failed = RedFolderEvent::CalendarSyncFailed {
error: "connection timeout".into(),
};
assert!(sync_failed.is_sync_failed());
assert!(!sync_failed.is_warning());
assert_eq!(sync_failed.worker_id(), None);
assert_eq!(sync_failed.window(), None);
}
}