razeri_plugin_api/sinks/
webhook.rs1use std::sync::Arc;
4
5use async_trait::async_trait;
6
7use crate::builder::EventSinkRegistration;
8use crate::error::EventSinkError;
9use crate::event::{EventSink, RazeriEvent};
10
11pub struct WebhookSink {
20 url: String,
21}
22
23impl WebhookSink {
24 pub fn new(url: impl Into<String>) -> Self {
26 Self { url: url.into() }
27 }
28
29 #[must_use]
31 pub fn url(&self) -> &str {
32 &self.url
33 }
34}
35
36#[async_trait]
37impl EventSink for WebhookSink {
38 fn name(&self) -> &'static str {
39 "webhook"
40 }
41
42 async fn on_event(&self, event: &RazeriEvent) -> Result<(), EventSinkError> {
43 let _payload = serde_json::to_string(event)
46 .map_err(|e| EventSinkError::SinkError(format!("serialization failed: {e}")))?;
47
48 tracing::debug!(url = %self.url, "Webhook event queued");
49 Ok(())
50 }
51
52 async fn flush(&self) -> Result<(), EventSinkError> {
53 Ok(())
54 }
55}
56
57inventory::submit! {
59 EventSinkRegistration::new("webhook", || Arc::new(DefaultWebhookSink))
60}
61
62struct DefaultWebhookSink;
65
66#[async_trait]
67impl EventSink for DefaultWebhookSink {
68 fn name(&self) -> &'static str {
69 "webhook"
70 }
71
72 async fn on_event(&self, _event: &RazeriEvent) -> Result<(), EventSinkError> {
73 Ok(())
74 }
75
76 async fn flush(&self) -> Result<(), EventSinkError> {
77 Ok(())
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::event::{RazeriEvent, WorkflowContext};
85 use chrono::Utc;
86
87 fn test_workflow() -> WorkflowContext {
88 WorkflowContext::new("test-wf").unwrap()
89 }
90
91 #[tokio::test]
92 async fn webhook_sink_accepts_events() {
93 let sink = WebhookSink::new("https://example.com/events");
94 assert_eq!(sink.name(), "webhook");
95 assert_eq!(sink.url(), "https://example.com/events");
96
97 let event = RazeriEvent::design_validated(
98 "webhook-test-1",
99 Utc::now(),
100 test_workflow(),
101 "test.yaml",
102 0,
103 0,
104 )
105 .unwrap();
106 let result = sink.on_event(&event).await;
107 assert!(result.is_ok());
108 }
109
110 #[tokio::test]
111 async fn webhook_sink_flush_is_noop() {
112 let sink = WebhookSink::new("https://example.com/events");
113 assert!(sink.flush().await.is_ok());
114 }
115}