haproxy_spoa_hub_plugin_api/
lib.rs1#![allow(non_camel_case_types, non_local_definitions)]
3
4pub mod plugin_trait;
5pub mod types;
6
7pub use abi_stable;
8pub use abi_stable::std_types::{RHashMap, RString, RVec, Tuple2};
9pub use plugin_trait::{PluginBox, PluginMod, PluginMod_Ref, SpoePlugin, SpoePlugin_TO};
10pub use types::{
11 ConfigValue, PluginContext, ProcessingResult, SpoeMessage, SpoeValue, TxnVariable, VarScope,
12};
13
14#[macro_export]
58macro_rules! define_plugin {
59 ($plugin_ty:ty, {
61 fn new() -> Self $new_body:block
62
63 fn init(&mut self, $ctx_param:ident : &PluginContext $(,)?) -> Result<(), Box<dyn std::error::Error + Send + Sync>> $init_body:block
64
65 fn name(&self) -> &str $name_body:block
66
67 fn version(&self) -> &str $version_body:block
68
69 fn process(
70 &self,
71 $msg_param:ident : &SpoeMessage $(,)?
72 ) -> Result<ProcessingResult, Box<dyn std::error::Error + Send + Sync>> $process_body:block
73
74 fn config_schema(&self) -> Option<&str> $schema_body:block
75 }) => {
76 $crate::__define_plugin_impl!($plugin_ty,
77 new: $new_body,
78 init($ctx_param): $init_body,
79 name: $name_body,
80 version: $version_body,
81 process($msg_param): $process_body,
82 schema: { $schema_body }
83 );
84 };
85
86 ($plugin_ty:ty, {
88 fn new() -> Self $new_body:block
89
90 fn init(&mut self, $ctx_param:ident : &PluginContext $(,)?) -> Result<(), Box<dyn std::error::Error + Send + Sync>> $init_body:block
91
92 fn name(&self) -> &str $name_body:block
93
94 fn version(&self) -> &str $version_body:block
95
96 fn process(
97 &self,
98 $msg_param:ident : &SpoeMessage $(,)?
99 ) -> Result<ProcessingResult, Box<dyn std::error::Error + Send + Sync>> $process_body:block
100 }) => {
101 $crate::__define_plugin_impl!($plugin_ty,
102 new: $new_body,
103 init($ctx_param): $init_body,
104 name: $name_body,
105 version: $version_body,
106 process($msg_param): $process_body,
107 schema: { { None } }
108 );
109 };
110}
111
112#[doc(hidden)]
113#[macro_export]
114macro_rules! __define_plugin_impl {
115 ($plugin_ty:ty,
116 new: $new_body:block,
117 init($ctx_param:ident): $init_body:block,
118 name: $name_body:block,
119 version: $version_body:block,
120 process($msg_param:ident): $process_body:block,
121 schema: { $schema_body:block }
122 ) => {
123 mod __plugin_impl {
124 use super::*;
125 use $crate::abi_stable::std_types::{
126 RBoxError, ROption, RResult, RStr, RString,
127 };
128 use $crate::abi_stable::sabi_trait::prelude::TD_Opaque;
129
130 impl $plugin_ty {
131 pub fn __new() -> Self $new_body
132 #[allow(clippy::unnecessary_wraps)]
133 pub fn __init(
134 &mut self,
135 $ctx_param: &$crate::PluginContext,
136 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> $init_body
137 pub fn __name(&self) -> &str $name_body
138 pub fn __version(&self) -> &str $version_body
139 #[allow(clippy::unnecessary_wraps)]
140 pub fn __process(
141 &self,
142 $msg_param: &$crate::SpoeMessage,
143 ) -> Result<$crate::ProcessingResult, Box<dyn std::error::Error + Send + Sync>> $process_body
144 #[allow(clippy::unnecessary_wraps)]
145 pub fn __config_schema(&self) -> Option<&str> $schema_body
146 }
147
148 impl $crate::SpoePlugin for $plugin_ty {
149 fn init(
150 &mut self,
151 context: &$crate::PluginContext,
152 ) -> RResult<(), RBoxError> {
153 self.__init(context).map_err(RBoxError::from_box).into()
154 }
155
156 fn process(
157 &self,
158 message: &$crate::SpoeMessage,
159 ) -> RResult<$crate::ProcessingResult, RBoxError> {
160 match std::panic::catch_unwind(
161 std::panic::AssertUnwindSafe(|| self.__process(message)),
162 ) {
163 Ok(res) => res.map_err(RBoxError::from_box).into(),
164 Err(_) => {
165 RResult::RErr(RBoxError::new(
166 $crate::PluginPanicError,
167 ))
168 }
169 }
170 }
171
172 fn name(&self) -> RStr<'_> {
173 self.__name().into()
174 }
175
176 fn version(&self) -> RStr<'_> {
177 self.__version().into()
178 }
179
180 fn shutdown(&self) {}
181
182 fn config_schema(&self) -> ROption<RString> {
183 self.__config_schema().map(RString::from).into()
184 }
185 }
186
187 #[$crate::abi_stable::export_root_module]
188 pub fn get_root_module() -> $crate::PluginMod_Ref {
189 use $crate::abi_stable::prefix_type::PrefixTypeTrait;
190 $crate::PluginMod {
191 new: __create_plugin,
192 }
193 .leak_into_prefix()
194 }
195
196 extern "C" fn __create_plugin() -> RResult<$crate::PluginBox, RBoxError> {
197 let plugin = <$plugin_ty>::__new();
198 RResult::ROk($crate::SpoePlugin_TO::from_value(plugin, TD_Opaque))
199 }
200 }
201 };
202}
203
204#[derive(Debug)]
206pub struct PluginPanicError;
207
208impl std::fmt::Display for PluginPanicError {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 write!(f, "plugin panicked during message processing")
211 }
212}
213
214impl std::error::Error for PluginPanicError {}