cdevents_sdk/
cloudevents.rs

1use cloudevents::{Data, Event};
2use time::format_description::well_known::Rfc3339;
3
4use crate::CDEvent;
5
6pub trait BuilderExt: Sized {
7    type Error;
8    fn with_cdevent(self, cdevent: CDEvent) -> Result<Self, Self::Error>;
9}
10
11impl BuilderExt for cloudevents::EventBuilderV10 {
12    type Error = cloudevents::message::Error;
13
14    fn with_cdevent(self, cdevent: CDEvent) -> Result<Self, Self::Error> {
15        Ok(
16            self.id(cdevent.id())
17                .ty(cdevent.ty())
18                .source(cdevent.source().as_str())
19                .subject(cdevent.subject().id())
20                .time(cdevent.timestamp().format(&Rfc3339).map_err(|e| Self::Error::Other{source: Box::new(e)})?)
21                .data("application/json", serde_json::to_value(cdevent).map_err(Self::Error::from)?)
22        )
23    }
24}
25
26impl TryFrom<CDEvent> for Event {
27    type Error = cloudevents::message::Error;
28
29    fn try_from(value: CDEvent) -> Result<Self, Self::Error> {
30        use ::cloudevents::{EventBuilder, EventBuilderV10};
31        EventBuilderV10::new()
32            .with_cdevent(value)?
33            .build().map_err(Self::Error::from)
34    }
35}
36
37impl TryFrom<Data> for CDEvent {
38    type Error = serde_json::Error;
39
40    fn try_from(value: Data) -> Result<Self, Self::Error> {
41        let json = match value {
42            Data::Binary(v) => serde_json::from_slice(&v)?,
43            Data::Json(v) => v,
44            Data::String(s) => serde_json::from_str(&s)?,
45        };
46        serde_json::from_value(json) //doesn't work due to the unsupported variant definition
47    }
48}
49
50impl TryFrom<Event> for CDEvent {
51    type Error = crate::Error;
52
53    fn try_from(value: Event) -> Result<Self, Self::Error> {
54        let mut event = value;
55        let (_, _, data) = event.take_data();
56        data.ok_or(Self::Error::DataNotFoundInCloudEvent)?
57            .try_into().map_err(Self::Error::from)
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use ::cloudevents::{AttributesReader, EventBuilder, EventBuilderV10};
64    use crate::*;
65    use super::*;
66
67    #[test]
68    fn test_into_cloudevent() -> Result<(), Box<dyn std::error::Error>> {
69        let cdevent = CDEvent::from(
70            Subject::from(latest::build_queued::Content{})
71                .with_id("subject123".try_into()?)
72                .with_source("/event/source/123".try_into()?)
73        )
74        .with_id("271069a8-fc18-44f1-b38f-9d70a1695819".try_into()?)
75        .with_source("https://dev.cdevents".try_into()?)
76        ;
77
78        let cloudevent_via_builder = EventBuilderV10::new()
79            .with_cdevent(cdevent.clone())?
80            .build()?;
81        let mut cloudevent: Event = cdevent.clone().try_into()?;
82        assert_eq!(cloudevent_via_builder, cloudevent);
83
84        assert_eq!(cloudevent.id(), "271069a8-fc18-44f1-b38f-9d70a1695819");
85        assert_eq!(cloudevent.id(), cdevent.id().to_string());
86
87        let (_, _, data) = cloudevent.take_data();
88        let cdevent_extracted: CDEvent = data.ok_or(Error::DataNotFoundInCloudEvent)?.try_into()?;
89        assert_eq!(cloudevent.id(), cdevent_extracted.id().to_string());
90        assert_eq!(cdevent, cdevent_extracted);
91        Ok(())
92    }
93}