falco_plugin/plugin/event/async_event.rs
1use crate::plugin::event::EventSource;
2use falco_event::fields::{FromBytes, ToBytes};
3use std::ffi::CStr;
4use std::fmt::{Debug, Formatter};
5
6/// Asynchronous event
7///
8/// This is the event type generated by [async event](`crate::async_event`) plugins.
9/// This differs from the autogenerated `falco_event_schema::types::PPME_ASYNCEVENT_E` type
10/// in the following ways:
11/// - none of the fields are `Option`s
12/// - the name is just a `&CStr`
13/// - serde serialization/deserialization is not supported
14/// - does not depend on the whole `falco_event_schema` crate
15///
16/// It handles encoding and decoding the payload automatically, so you can use any type that can be
17/// converted from/to a byte buffer (including a raw `&[u8]`) as the payload.
18///
19/// To store an arbitrary type inside the payload, make sure the data implements [`FromBytes`],
20/// [`ToBytes`] and [`EventSource`], for example:
21/// ```
22/// use std::io::Write;
23/// use falco_event::events::{AnyEventPayload, RawEvent};
24/// use falco_event::fields::{FromBytes, FromBytesError, ToBytes};
25/// use falco_plugin::event::{EventSource, AsyncEvent};
26/// use falco_plugin::event::events::Event;
27///
28/// struct MyEvent {
29/// param1: u32,
30/// param2: u32,
31/// }
32///
33/// impl EventSource for MyEvent {
34/// const SOURCE: Option<&'static str> = Some("my_plugin");
35/// }
36///
37/// impl FromBytes<'_> for MyEvent {
38/// fn from_bytes(buf: &mut &[u8]) -> Result<Self, FromBytesError> {
39/// if buf.len() < 2 * size_of::<u32>() {
40/// return Err(FromBytesError::InvalidLength);
41/// }
42///
43/// let param1 = u32::from_le_bytes(buf[..size_of::<u32>()].try_into().unwrap());
44/// let param2 = u32::from_le_bytes(buf[size_of::<u32>()..].try_into().unwrap());
45/// *buf = &buf[2 * size_of::<u32>()..];
46/// Ok(MyEvent { param1, param2 })
47/// }
48/// }
49///
50/// impl ToBytes for MyEvent {
51/// fn binary_size(&self) -> usize {
52/// 2 * size_of::<u32>()
53/// }
54///
55/// fn write<W: Write>(&self, mut writer: W) -> std::io::Result<()> {
56/// writer.write_all(&self.param1.to_le_bytes())?;
57/// writer.write_all(&self.param2.to_le_bytes())?;
58/// Ok(())
59/// }
60///
61/// fn default_repr() -> impl ToBytes {
62/// MyEvent { param1: 0, param2: 0 }
63/// }
64/// }
65///
66///# trait FakePluginTrait {
67///# type Event<'a>: AnyEventPayload + TryFrom<&'a RawEvent<'a>> where Self: 'a;
68///# }
69///# struct FakePlugin;
70///# impl FakePluginTrait for FakePlugin {
71/// // in a plugin trait implementation:
72/// type Event<'a> = Event<AsyncEvent<'a, MyEvent>>;
73///# }
74/// ```
75///
76/// *Note*: this SDK also provides support for [JSON-encoded payloads](`crate::event::JsonPayload`)
77/// since it's already necessary to talk to the Falco Plugin API. JSON is not a good choice
78/// for high-volume events, as it takes a lot of space and is pretty slow, compared to binary
79/// formats. See the source of `plugin::event:json` for what is needed to support a different
80/// serialization format and consider using e.g. [bincode](https://crates.io/crates/bincode) instead.
81#[derive(Default, falco_event::EventPayload)]
82#[event_payload(
83 source = <T as EventSource>::SOURCE,
84 code = 402,
85 length_type = u32,
86 from_bytes_bound(where T: FromBytes<'raw_event>),
87 to_bytes_bound(where T: ToBytes))]
88pub struct AsyncEvent<'a, T>
89where
90 T: EventSource,
91{
92 /// ID of the plugin that generated this event
93 pub plugin_id: u32,
94 /// Name of the plugin that generated this event
95 pub name: &'a CStr,
96 /// Payload, as a custom type
97 pub data: T,
98}
99
100impl<'a, T> Debug for AsyncEvent<'a, T>
101where
102 T: EventSource + Debug,
103{
104 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
105 write!(
106 f,
107 "> async plugin_id={} name={} data={:?}",
108 self.plugin_id,
109 self.name.to_string_lossy(),
110 self.data
111 )
112 }
113}