falco_plugin/plugin/event/
plugin_event.rs

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