Allow the use of custom context
The main goal of events/reports is to update a context object, which will be used in filters to generate a response. It is now possible to use any object implementing both Clone and Default as a context object. It is also possible to define no context at all.
This commit is contained in:
parent
dd7f4d1a86
commit
4b1f99db7e
6 changed files with 75 additions and 18 deletions
|
@ -4,21 +4,61 @@ use proc_macro::TokenStream;
|
||||||
use syn::{parse_macro_input, ItemFn};
|
use syn::{parse_macro_input, ItemFn};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
|
fn get_type(
|
||||||
|
params: &syn::punctuated::Punctuated<syn::FnArg, syn::token::Comma>,
|
||||||
|
) -> Result<(Box<syn::Type>, syn::Type), ()> {
|
||||||
|
match params.iter().count() {
|
||||||
|
1 => {
|
||||||
|
let ctx = Box::new(syn::Type::Verbatim(syn::TypeVerbatim {
|
||||||
|
tts: quote! {
|
||||||
|
opensmtpd::NoContext
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
let cb = syn::Type::Verbatim(syn::TypeVerbatim {
|
||||||
|
tts: quote!{ opensmtpd::Callback::NoCtx },
|
||||||
|
});
|
||||||
|
Ok((ctx, cb))
|
||||||
|
}
|
||||||
|
2 => match params.iter().next().unwrap() {
|
||||||
|
syn::FnArg::Captured(ref a) => match &a.ty {
|
||||||
|
syn::Type::Reference(r) => {
|
||||||
|
let cb = match r.mutability {
|
||||||
|
Some(_) => syn::Type::Verbatim(syn::TypeVerbatim {
|
||||||
|
tts: quote!{ opensmtpd::Callback::CtxMut },
|
||||||
|
}),
|
||||||
|
None => syn::Type::Verbatim(syn::TypeVerbatim {
|
||||||
|
tts: quote!{ opensmtpd::Callback::Ctx },
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
Ok((r.elem.clone(), cb))
|
||||||
|
}
|
||||||
|
_ => Err(()),
|
||||||
|
},
|
||||||
|
_ => Err(()),
|
||||||
|
},
|
||||||
|
_ => Err(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn event(attr: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn event(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let attr = attr.to_string();
|
let attr = attr.to_string();
|
||||||
let item = parse_macro_input!(input as ItemFn);
|
let item = parse_macro_input!(input as ItemFn);
|
||||||
let fn_name = &item.ident;
|
let fn_name = &item.ident;
|
||||||
let fn_params = &item.decl.inputs;
|
let fn_params = &item.decl.inputs;
|
||||||
|
let (ctx_type, callback_type) = match get_type(fn_params) {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(_) => {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
};
|
||||||
let fn_body = &item.block;
|
let fn_body = &item.block;
|
||||||
let fn_output = &item.decl.output;
|
let fn_output = &item.decl.output;
|
||||||
let output = quote! {
|
let output = quote! {
|
||||||
// TODO: set the correct EventHandler type
|
fn #fn_name() -> opensmtpd::EventHandler<#ctx_type> {
|
||||||
fn #fn_name() -> opensmtpd::EventHandler<opensmtpd::NoContext> {
|
|
||||||
// TODO: set the correct Callback type
|
|
||||||
opensmtpd::EventHandler::new(
|
opensmtpd::EventHandler::new(
|
||||||
#attr,
|
#attr,
|
||||||
opensmtpd::Callback::CtxMut(|#fn_params| #fn_output #fn_body)
|
#callback_type(|#fn_params| #fn_output #fn_body)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,5 +20,9 @@ opensmtpd_derive = { path = "../opensmtpd-derive", version="0.1" }
|
||||||
name = "dummy"
|
name = "dummy"
|
||||||
path = "examples/dummy.rs"
|
path = "examples/dummy.rs"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "counter"
|
||||||
|
path = "examples/session_event_counter.rs"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.6"
|
env_logger = "0.6"
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use env_logger::{Builder, Env};
|
use env_logger::{Builder, Env};
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use opensmtpd::{event, handlers, Entry, NoContext, SmtpIn};
|
use opensmtpd::{event, handlers, Entry, SmtpIn};
|
||||||
|
|
||||||
#[event(Any)]
|
#[event(Any)]
|
||||||
fn on_event(_context: &mut NoContext, entry: &Entry) {
|
fn on_event(entry: &Entry) {
|
||||||
debug!("Event received: {:?}", entry);
|
debug!("Event received: {:?}", entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[event(LinkConnect)]
|
#[event(LinkConnect)]
|
||||||
fn on_connect(_context: &mut NoContext, entry: &Entry) {
|
fn on_connect(entry: &Entry) {
|
||||||
info!("New client on session {:x}.", entry.session_id);
|
info!("New client on session {:x}.", entry.session_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
19
opensmtpd/examples/session_event_counter.rs
Normal file
19
opensmtpd/examples/session_event_counter.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
use env_logger::{Builder, Env};
|
||||||
|
use log::info;
|
||||||
|
use opensmtpd::{event, handlers, Entry, SmtpIn};
|
||||||
|
|
||||||
|
#[derive(Clone, Default)]
|
||||||
|
struct MyContext {
|
||||||
|
nb: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[event(Any)]
|
||||||
|
fn on_event(ctx: &mut MyContext, entry: &Entry) {
|
||||||
|
ctx.nb += 1;
|
||||||
|
info!("Event received: {}, {}", entry.session_id, ctx.nb);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
Builder::from_env(Env::default().default_filter_or("debug")).init();
|
||||||
|
SmtpIn::new().event_handlers(handlers!(on_event)).run();
|
||||||
|
}
|
|
@ -65,11 +65,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_eventhandler_build_noctx() {
|
fn test_eventhandler_build_noctx() {
|
||||||
// TODO: Remove the ::<NoContext>
|
EventHandler::new("Any", Callback::NoCtx::<NoContext>(|_entry: &Entry| {}));
|
||||||
EventHandler::new(
|
|
||||||
"Any",
|
|
||||||
Callback::NoCtx::<NoContext>(|_entry: &Entry| {}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -79,16 +79,14 @@ impl<T: Clone + Default + 'static> SmtpIn<T> {
|
||||||
let mut evts = Vec::new();
|
let mut evts = Vec::new();
|
||||||
for eh in self.event_handlers.iter() {
|
for eh in self.event_handlers.iter() {
|
||||||
match eh.event {
|
match eh.event {
|
||||||
MatchEvent::Evt(ref v) => {
|
MatchEvent::Evt(ref v) => for e in v.iter() {
|
||||||
for e in v.iter() {
|
|
||||||
evts.push(e);
|
evts.push(e);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
MatchEvent::All => {
|
MatchEvent::All => {
|
||||||
println!("register|report|smtp-in|*");
|
println!("register|report|smtp-in|*");
|
||||||
evts.clear();
|
evts.clear();
|
||||||
break;
|
break;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
evts.dedup();
|
evts.dedup();
|
||||||
|
|
Reference in a new issue