use crate::error::{EventError, EventResult};
use crate::types::{EventKind, EventMetadata, StreamInfo};
use async_trait::async_trait;
use futures::Stream;
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::pin::Pin;
use std::time::{Duration, SystemTime};
pub trait Event: Debug + Send + Sync {
fn id(&self) -> &str;
fn kind(&self) -> &EventKind;
fn metadata(&self) -> &EventMetadata;
fn metadata_mut(&mut self) -> EventResult<&mut EventMetadata>;
fn timestamp(&self) -> SystemTime {
self.metadata().timestamp.into()
}
fn source(&self) -> &str {
&self.metadata().source
}
fn as_any(&self) -> &dyn std::any::Any;
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
fn clone_boxed(&self) -> Box<dyn Event>;
fn to_json(&self) -> EventResult<serde_json::Value>;
fn matches_filter(&self, filter: &dyn EventFilter) -> bool
where
Self: Sized,
{
filter.matches(self)
}
}
impl Clone for Box<dyn Event> {
fn clone(&self) -> Self {
self.clone_boxed()
}
}
#[async_trait]
pub trait EventParser: Send + Sync {
type Input: Send + Sync;
async fn parse(&self, input: Self::Input) -> EventResult<Vec<Box<dyn Event>>>;
fn can_parse(&self, input: &Self::Input) -> bool;
fn info(&self) -> ParserInfo;
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ParserInfo {
pub name: String,
pub version: String,
pub supported_kinds: Vec<EventKind>,
pub supported_formats: Vec<String>,
}
impl ParserInfo {
pub fn new(name: String, version: String) -> Self {
Self {
name,
version,
supported_kinds: Vec::new(),
supported_formats: Vec::new(),
}
}
pub fn with_kind(mut self, kind: EventKind) -> Self {
self.supported_kinds.push(kind);
self
}
pub fn with_format(mut self, format: String) -> Self {
self.supported_formats.push(format);
self
}
}
#[async_trait]
pub trait EventStream: Send + Sync {
async fn start(
&mut self,
) -> EventResult<Pin<Box<dyn Stream<Item = EventResult<Box<dyn Event>>> + Send>>>;
async fn stop(&mut self) -> EventResult<()>;
fn is_active(&self) -> bool;
fn info(&self) -> &StreamInfo;
fn info_mut(&mut self) -> &mut StreamInfo;
async fn restart(
&mut self,
) -> EventResult<Pin<Box<dyn Stream<Item = EventResult<Box<dyn Event>>> + Send>>> {
if self.is_active() {
self.stop().await?;
}
self.start().await
}
}
pub trait EventFilter: Send + Sync + std::fmt::Debug {
fn matches(&self, event: &dyn Event) -> bool;
fn description(&self) -> String;
}
#[async_trait]
pub trait EventHandler: Send + Sync {
async fn handle(&self, event: Box<dyn Event>) -> EventResult<()>;
fn can_handle(&self, event: &dyn Event) -> bool;
fn info(&self) -> HandlerInfo;
async fn initialize(&mut self) -> EventResult<()> {
Ok(())
}
async fn shutdown(&mut self) -> EventResult<()> {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HandlerInfo {
pub name: String,
pub version: String,
pub handled_kinds: Vec<EventKind>,
pub timeout: Option<Duration>,
}
impl HandlerInfo {
pub fn new(name: String, version: String) -> Self {
Self {
name,
version,
handled_kinds: Vec::new(),
timeout: None,
}
}
pub fn with_kind(mut self, kind: EventKind) -> Self {
self.handled_kinds.push(kind);
self
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
}
#[async_trait]
pub trait EventBatchProcessor: Send + Sync {
async fn process_batch(&self, events: Vec<Box<dyn Event>>)
-> EventResult<Vec<EventResult<()>>>;
fn optimal_batch_size(&self) -> usize {
10
}
fn batch_timeout(&self) -> Duration {
Duration::from_millis(100)
}
}
pub trait EventTransformer: Send + Sync {
fn transform(&self, event: Box<dyn Event>) -> EventResult<Box<dyn Event>>;
fn can_transform(&self, event: &dyn Event) -> bool;
}
#[async_trait]
pub trait EventRouter: Send + Sync {
async fn route(&self, event: Box<dyn Event>) -> EventResult<Vec<Box<dyn EventHandler>>>;
fn add_handler(&mut self, filter: Box<dyn EventFilter>, handler: Box<dyn EventHandler>);
fn remove_handlers(&mut self, filter: Box<dyn EventFilter>) -> usize;
}
pub trait EventMetrics: Send + Sync {
fn record_event(&self, event: &dyn Event, processing_time: Duration);
fn record_error(&self, event: &dyn Event, error: &EventError);
fn snapshot(&self) -> EventResult<serde_json::Value>;
fn reset(&self);
}
#[derive(Debug, Clone)]
pub struct KindFilter {
pub kinds: Vec<EventKind>,
}
impl KindFilter {
pub fn new(kinds: Vec<EventKind>) -> Self {
Self { kinds }
}
pub fn single(kind: EventKind) -> Self {
Self { kinds: vec![kind] }
}
}
impl EventFilter for KindFilter {
fn matches(&self, event: &dyn Event) -> bool {
self.kinds.contains(event.kind())
}
fn description(&self) -> String {
format!("Filter events by kind: {:?}", self.kinds)
}
}
#[derive(Debug, Clone)]
pub struct SourceFilter {
pub sources: Vec<String>,
}
impl SourceFilter {
pub fn new(sources: Vec<String>) -> Self {
Self { sources }
}
pub fn single(source: String) -> Self {
Self {
sources: vec![source],
}
}
}
impl EventFilter for SourceFilter {
fn matches(&self, event: &dyn Event) -> bool {
self.sources.contains(&event.source().to_string())
}
fn description(&self) -> String {
format!("Filter events by source: {:?}", self.sources)
}
}
#[derive(Debug)]
pub struct AndFilter {
pub filters: Vec<Box<dyn EventFilter>>,
}
impl AndFilter {
pub fn new(filters: Vec<Box<dyn EventFilter>>) -> Self {
Self { filters }
}
}
impl EventFilter for AndFilter {
fn matches(&self, event: &dyn Event) -> bool {
self.filters.iter().all(|f| f.matches(event))
}
fn description(&self) -> String {
let descriptions: Vec<String> = self.filters.iter().map(|f| f.description()).collect();
format!("AND({})", descriptions.join(", "))
}
}
#[derive(Debug)]
pub struct OrFilter {
pub filters: Vec<Box<dyn EventFilter>>,
}
impl OrFilter {
pub fn new(filters: Vec<Box<dyn EventFilter>>) -> Self {
Self { filters }
}
}
impl EventFilter for OrFilter {
fn matches(&self, event: &dyn Event) -> bool {
self.filters.iter().any(|f| f.matches(event))
}
fn description(&self) -> String {
let descriptions: Vec<String> = self.filters.iter().map(|f| f.description()).collect();
format!("OR({})", descriptions.join(", "))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::GenericEvent;
use serde_json::json;
#[allow(dead_code)]
struct MockHandler {
info: HandlerInfo,
}
#[async_trait]
impl EventHandler for MockHandler {
async fn handle(&self, _event: Box<dyn Event>) -> EventResult<()> {
Ok(())
}
fn can_handle(&self, event: &dyn Event) -> bool {
self.info.handled_kinds.contains(event.kind())
}
fn info(&self) -> HandlerInfo {
self.info.clone()
}
}
#[tokio::test]
async fn test_kind_filter() {
let filter = KindFilter::single(EventKind::Transaction);
let event = GenericEvent::new("test".to_string(), EventKind::Transaction, json!({}));
assert!(filter.matches(&event));
let event2 = GenericEvent::new("test2".to_string(), EventKind::Block, json!({}));
assert!(!filter.matches(&event2));
}
#[tokio::test]
async fn test_source_filter() {
let filter = SourceFilter::single("test-source".to_string());
let mut event = GenericEvent::new("test".to_string(), EventKind::Transaction, json!({}));
event.metadata.source = "test-source".to_string();
assert!(filter.matches(&event));
event.metadata.source = "other-source".to_string();
assert!(!filter.matches(&event));
}
#[tokio::test]
async fn test_and_filter() {
let kind_filter = Box::new(KindFilter::single(EventKind::Transaction));
let source_filter = Box::new(SourceFilter::single("test-source".to_string()));
let and_filter = AndFilter::new(vec![kind_filter, source_filter]);
let mut event = GenericEvent::new("test".to_string(), EventKind::Transaction, json!({}));
event.metadata.source = "test-source".to_string();
assert!(and_filter.matches(&event));
let mut event2 = event.clone();
event2.metadata.kind = EventKind::Block;
assert!(!and_filter.matches(&event2));
let mut event3 = event.clone();
event3.metadata.source = "other-source".to_string();
assert!(!and_filter.matches(&event3));
}
#[tokio::test]
async fn test_or_filter() {
let kind_filter = Box::new(KindFilter::single(EventKind::Transaction));
let source_filter = Box::new(SourceFilter::single("test-source".to_string()));
let or_filter = OrFilter::new(vec![kind_filter, source_filter]);
let event1 = GenericEvent::new("test1".to_string(), EventKind::Transaction, json!({}));
assert!(or_filter.matches(&event1));
let mut event2 = GenericEvent::new("test2".to_string(), EventKind::Block, json!({}));
event2.metadata.source = "test-source".to_string();
assert!(or_filter.matches(&event2));
let event3 = GenericEvent::new("test3".to_string(), EventKind::Block, json!({}));
assert!(!or_filter.matches(&event3));
}
#[tokio::test]
async fn test_handler_info() {
let info = HandlerInfo::new("test-handler".to_string(), "1.0.0".to_string())
.with_kind(EventKind::Transaction)
.with_kind(EventKind::Block)
.with_timeout(Duration::from_secs(30));
assert_eq!(info.name, "test-handler");
assert_eq!(info.version, "1.0.0");
assert_eq!(info.handled_kinds.len(), 2);
assert_eq!(info.timeout, Some(Duration::from_secs(30)));
}
#[tokio::test]
async fn test_parser_info() {
let info = ParserInfo::new("test-parser".to_string(), "1.0.0".to_string())
.with_kind(EventKind::Transaction)
.with_format("json".to_string())
.with_format("binary".to_string());
assert_eq!(info.name, "test-parser");
assert_eq!(info.version, "1.0.0");
assert_eq!(info.supported_kinds.len(), 1);
assert_eq!(info.supported_formats.len(), 2);
}
#[test]
fn test_generic_event_trait_implementation() {
let event = GenericEvent::new(
"test-event".to_string(),
EventKind::Swap,
json!({"amount": 100}),
);
assert_eq!(event.id(), "test-event");
assert_eq!(event.kind(), &EventKind::Swap);
assert_eq!(event.source(), "generic");
let cloned = event.clone_boxed();
assert_eq!(cloned.id(), event.id());
}
#[test]
fn test_parser_info_new() {
let info = ParserInfo::new("test-parser".to_string(), "2.0.0".to_string());
assert_eq!(info.name, "test-parser");
assert_eq!(info.version, "2.0.0");
assert!(info.supported_kinds.is_empty());
assert!(info.supported_formats.is_empty());
}
#[test]
fn test_parser_info_with_multiple_kinds() {
let info = ParserInfo::new("parser".to_string(), "1.0".to_string())
.with_kind(EventKind::Transaction)
.with_kind(EventKind::Block)
.with_kind(EventKind::Swap);
assert_eq!(info.supported_kinds.len(), 3);
assert!(info.supported_kinds.contains(&EventKind::Transaction));
assert!(info.supported_kinds.contains(&EventKind::Block));
assert!(info.supported_kinds.contains(&EventKind::Swap));
}
#[test]
fn test_parser_info_with_multiple_formats() {
let info = ParserInfo::new("parser".to_string(), "1.0".to_string())
.with_format("json".to_string())
.with_format("xml".to_string())
.with_format("protobuf".to_string());
assert_eq!(info.supported_formats.len(), 3);
assert!(info.supported_formats.contains(&"json".to_string()));
assert!(info.supported_formats.contains(&"xml".to_string()));
assert!(info.supported_formats.contains(&"protobuf".to_string()));
}
#[test]
fn test_handler_info_new() {
let info = HandlerInfo::new("test-handler".to_string(), "3.0.0".to_string());
assert_eq!(info.name, "test-handler");
assert_eq!(info.version, "3.0.0");
assert!(info.handled_kinds.is_empty());
assert_eq!(info.timeout, None);
}
#[test]
fn test_handler_info_with_multiple_kinds() {
let info = HandlerInfo::new("handler".to_string(), "1.0".to_string())
.with_kind(EventKind::Transaction)
.with_kind(EventKind::Block);
assert_eq!(info.handled_kinds.len(), 2);
assert!(info.handled_kinds.contains(&EventKind::Transaction));
assert!(info.handled_kinds.contains(&EventKind::Block));
}
#[test]
fn test_handler_info_with_timeout() {
let timeout_duration = Duration::from_secs(60);
let info = HandlerInfo::new("handler".to_string(), "1.0".to_string())
.with_timeout(timeout_duration);
assert_eq!(info.timeout, Some(timeout_duration));
}
#[test]
fn test_kind_filter_new() {
let kinds = vec![EventKind::Transaction, EventKind::Block];
let filter = KindFilter::new(kinds.clone());
assert_eq!(filter.kinds, kinds);
}
#[test]
fn test_kind_filter_multiple_kinds() {
let filter = KindFilter::new(vec![
EventKind::Transaction,
EventKind::Block,
EventKind::Swap,
]);
let tx_event = GenericEvent::new("tx".to_string(), EventKind::Transaction, json!({}));
let block_event = GenericEvent::new("block".to_string(), EventKind::Block, json!({}));
let swap_event = GenericEvent::new("swap".to_string(), EventKind::Swap, json!({}));
let other_event = GenericEvent::new(
"other".to_string(),
EventKind::Custom("test".to_string()),
json!({}),
);
assert!(filter.matches(&tx_event));
assert!(filter.matches(&block_event));
assert!(filter.matches(&swap_event));
assert!(!filter.matches(&other_event));
}
#[test]
fn test_kind_filter_description() {
let filter = KindFilter::new(vec![EventKind::Transaction, EventKind::Block]);
let description = filter.description();
assert!(description.contains("Filter events by kind"));
assert!(description.contains("Transaction"));
assert!(description.contains("Block"));
}
#[test]
fn test_source_filter_new() {
let sources = vec!["source1".to_string(), "source2".to_string()];
let filter = SourceFilter::new(sources.clone());
assert_eq!(filter.sources, sources);
}
#[test]
fn test_source_filter_multiple_sources() {
let filter = SourceFilter::new(vec!["source1".to_string(), "source2".to_string()]);
let mut event1 = GenericEvent::new("test1".to_string(), EventKind::Transaction, json!({}));
event1.metadata.source = "source1".to_string();
let mut event2 = GenericEvent::new("test2".to_string(), EventKind::Transaction, json!({}));
event2.metadata.source = "source2".to_string();
let mut event3 = GenericEvent::new("test3".to_string(), EventKind::Transaction, json!({}));
event3.metadata.source = "source3".to_string();
assert!(filter.matches(&event1));
assert!(filter.matches(&event2));
assert!(!filter.matches(&event3));
}
#[test]
fn test_source_filter_description() {
let filter = SourceFilter::new(vec!["test-source".to_string()]);
let description = filter.description();
assert!(description.contains("Filter events by source"));
assert!(description.contains("test-source"));
}
#[test]
fn test_and_filter_empty_filters() {
let and_filter = AndFilter::new(vec![]);
let event = GenericEvent::new("test".to_string(), EventKind::Transaction, json!({}));
assert!(and_filter.matches(&event));
}
#[test]
fn test_and_filter_description() {
let kind_filter = Box::new(KindFilter::single(EventKind::Transaction));
let source_filter = Box::new(SourceFilter::single("test".to_string()));
let and_filter = AndFilter::new(vec![kind_filter, source_filter]);
let description = and_filter.description();
assert!(description.contains("AND("));
assert!(description.contains("Filter events by kind"));
assert!(description.contains("Filter events by source"));
}
#[test]
fn test_or_filter_empty_filters() {
let or_filter = OrFilter::new(vec![]);
let event = GenericEvent::new("test".to_string(), EventKind::Transaction, json!({}));
assert!(!or_filter.matches(&event));
}
#[test]
fn test_or_filter_description() {
let kind_filter = Box::new(KindFilter::single(EventKind::Transaction));
let source_filter = Box::new(SourceFilter::single("test".to_string()));
let or_filter = OrFilter::new(vec![kind_filter, source_filter]);
let description = or_filter.description();
assert!(description.contains("OR("));
assert!(description.contains("Filter events by kind"));
assert!(description.contains("Filter events by source"));
}
#[test]
fn test_event_timestamp() {
let event = GenericEvent::new("test".to_string(), EventKind::Transaction, json!({}));
let timestamp = event.timestamp();
assert!(timestamp.duration_since(SystemTime::UNIX_EPOCH).is_ok());
}
#[test]
fn test_event_matches_filter() {
let event = GenericEvent::new("test".to_string(), EventKind::Transaction, json!({}));
let filter = KindFilter::single(EventKind::Transaction);
assert!(event.matches_filter(&filter));
let other_filter = KindFilter::single(EventKind::Block);
assert!(!event.matches_filter(&other_filter));
}
#[test]
fn test_box_event_clone() {
let event = GenericEvent::new("test".to_string(), EventKind::Transaction, json!({}));
let boxed: Box<dyn Event> = Box::new(event);
let cloned = boxed.clone();
assert_eq!(boxed.id(), cloned.id());
assert_eq!(boxed.kind(), cloned.kind());
}
struct MockBatchProcessor;
#[async_trait]
impl EventBatchProcessor for MockBatchProcessor {
async fn process_batch(
&self,
_events: Vec<Box<dyn Event>>,
) -> EventResult<Vec<EventResult<()>>> {
Ok(vec![])
}
}
#[test]
fn test_event_batch_processor_defaults() {
let processor = MockBatchProcessor;
assert_eq!(processor.optimal_batch_size(), 10);
assert_eq!(processor.batch_timeout(), Duration::from_millis(100));
}
struct MockHandlerForDefaults {
info: HandlerInfo,
}
#[async_trait]
impl EventHandler for MockHandlerForDefaults {
async fn handle(&self, _event: Box<dyn Event>) -> EventResult<()> {
Ok(())
}
fn can_handle(&self, _event: &dyn Event) -> bool {
true
}
fn info(&self) -> HandlerInfo {
self.info.clone()
}
}
#[tokio::test]
async fn test_event_handler_default_initialize() {
let mut handler = MockHandlerForDefaults {
info: HandlerInfo::new("test".to_string(), "1.0".to_string()),
};
let result = handler.initialize().await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_event_handler_default_shutdown() {
let mut handler = MockHandlerForDefaults {
info: HandlerInfo::new("test".to_string(), "1.0".to_string()),
};
let result = handler.shutdown().await;
assert!(result.is_ok());
}
struct MockEventStream {
active: bool,
start_called: bool,
stop_called: bool,
info: StreamInfo,
}
impl MockEventStream {
fn new() -> Self {
Self {
active: false,
start_called: false,
stop_called: false,
info: StreamInfo::new(
"mock-id".to_string(),
"mock".to_string(),
"test".to_string(),
"mock://test".to_string(),
),
}
}
}
#[async_trait]
impl EventStream for MockEventStream {
async fn start(
&mut self,
) -> EventResult<Pin<Box<dyn Stream<Item = EventResult<Box<dyn Event>>> + Send>>> {
self.active = true;
self.start_called = true;
self.info.active = true;
Err(EventError::generic("Mock stream"))
}
async fn stop(&mut self) -> EventResult<()> {
self.active = false;
self.stop_called = true;
self.info.active = false;
Ok(())
}
fn is_active(&self) -> bool {
self.active
}
fn info(&self) -> &StreamInfo {
&self.info
}
fn info_mut(&mut self) -> &mut StreamInfo {
&mut self.info
}
}
#[tokio::test]
async fn test_event_stream_restart_when_active() {
let mut stream = MockEventStream::new();
stream.active = true;
let result = stream.restart().await;
assert!(stream.stop_called);
assert!(stream.start_called);
assert!(result.is_err()); }
#[tokio::test]
async fn test_event_stream_restart_when_inactive() {
let mut stream = MockEventStream::new();
stream.active = false;
let result = stream.restart().await;
assert!(!stream.stop_called);
assert!(stream.start_called);
assert!(result.is_err()); }
}