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