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}