cabin/html/elements/
fire_event.rs1use 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}