cabin/html/elements/
fire_event.rs

1use http::{HeaderName, HeaderValue};
2
3use super::SerializeEventFn;
4use crate::error::InternalError;
5use crate::render::Renderer;
6use crate::view::RenderFuture;
7use crate::View;
8
9pub struct FireEvent(pub Box<SerializeEventFn>);
10
11pub fn fire_event<E>(event: E) -> FireEvent
12where
13    E: serde::Serialize + 'static,
14{
15    FireEvent(Box::new(move || {
16        use std::hash::{Hash, Hasher};
17
18        let mut hasher = twox_hash::XxHash32::default();
19        std::any::TypeId::of::<E>().hash(&mut hasher);
20        let hash = hasher.finish() as u32;
21        serde_json::to_string(&event)
22            .map_err(|err| InternalError::Serialize {
23                what: "fire_event",
24                err,
25            })
26            .map(|json| (hash, json))
27    }))
28}
29
30impl View for FireEvent {
31    fn render(self, mut r: Renderer, _include_hash: bool) -> RenderFuture {
32        if r.is_update() {
33            let (id, payload) = match (self.0)() {
34                Ok(ok) => ok,
35                Err(err) => return RenderFuture::Ready(Some(Err(err.into()))),
36            };
37            let id_header = match HeaderValue::from_str(&id.to_string()) {
38                Ok(v) => v,
39                Err(err) => {
40                    tracing::error!(%err, "invalid header value for X-CABIN-EVENT");
41                    return RenderFuture::Ready(Some(Ok(r)));
42                }
43            };
44            let payload_header = match HeaderValue::from_str(&payload) {
45                Ok(v) => v,
46                Err(err) => {
47                    tracing::error!(%err, "invalid header value for X-CABIN-PAYLOAD");
48                    return RenderFuture::Ready(Some(Ok(r)));
49                }
50            };
51
52            let h = r.headers_mut();
53            h.insert(HeaderName::from_static("x-cabin-event"), id_header);
54            h.insert(HeaderName::from_static("x-cabin-payload"), payload_header);
55        }
56
57        RenderFuture::Ready(Some(Ok(r)))
58    }
59}