#[cfg(not(target_arch = "wasm32"))]
pub mod jsonl;
pub mod stdout;
pub mod webhook;
use std::sync::Arc;
use crate::error::EventSinkError;
use crate::event::EventSink;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct EventSinkConfig {
#[serde(rename = "type")]
pub sink_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<String>,
}
pub async fn create_sink(config: &EventSinkConfig) -> Result<Arc<dyn EventSink>, EventSinkError> {
match config.sink_type.as_str() {
"stdout" => Ok(Arc::new(stdout::StdoutSink::new())),
#[cfg(not(target_arch = "wasm32"))]
"jsonl" => {
let path = config
.path
.as_deref()
.ok_or_else(|| EventSinkError::SinkError("jsonl sink requires 'path'".into()))?;
let sink = jsonl::JsonlSink::open(path).await?;
Ok(Arc::new(sink))
}
"webhook" => {
let url = config
.url
.as_deref()
.ok_or_else(|| EventSinkError::SinkError("webhook sink requires 'url'".into()))?;
Ok(Arc::new(webhook::WebhookSink::new(url)))
}
other => Err(EventSinkError::SinkError(format!("unknown sink type: {other}"))),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn create_stdout_sink_from_config() {
let config = EventSinkConfig { sink_type: "stdout".into(), path: None, url: None };
let sink = create_sink(&config).await.unwrap();
assert_eq!(sink.name(), "stdout");
}
#[tokio::test]
async fn create_jsonl_sink_from_config() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("test.jsonl");
let config = EventSinkConfig {
sink_type: "jsonl".into(),
path: Some(path.to_string_lossy().into()),
url: None,
};
let sink = create_sink(&config).await.unwrap();
assert_eq!(sink.name(), "jsonl");
}
#[tokio::test]
async fn create_webhook_sink_from_config() {
let config = EventSinkConfig {
sink_type: "webhook".into(),
path: None,
url: Some("https://example.com/events".into()),
};
let sink = create_sink(&config).await.unwrap();
assert_eq!(sink.name(), "webhook");
}
#[tokio::test]
async fn create_jsonl_sink_missing_path_returns_error() {
let config = EventSinkConfig { sink_type: "jsonl".into(), path: None, url: None };
let result = create_sink(&config).await;
assert!(result.is_err());
}
#[tokio::test]
async fn create_webhook_sink_missing_url_returns_error() {
let config = EventSinkConfig { sink_type: "webhook".into(), path: None, url: None };
let result = create_sink(&config).await;
assert!(result.is_err());
}
#[tokio::test]
async fn create_unknown_sink_returns_error() {
let config = EventSinkConfig { sink_type: "kafka".into(), path: None, url: None };
let result = create_sink(&config).await;
assert!(result.is_err());
}
}