diff --git a/examples/dummy.rs b/examples/dummy.rs index 58707ab..5cd9c1f 100644 --- a/examples/dummy.rs +++ b/examples/dummy.rs @@ -1,7 +1,14 @@ +use log::debug; use env_logger::{Builder, Env}; -use opensmtpd::SmtpIn; +use opensmtpd::{Entry, EventHandler, MatchEvent, SmtpIn}; + +fn on_event(entry: &Entry) -> bool { + debug!("Event received: {:?}", entry); + true +} fn main() { Builder::from_env(Env::default().default_filter_or("debug")).init(); - SmtpIn::new().run(); + let h = vec![EventHandler::new(MatchEvent::All, on_event)]; + SmtpIn::new().event_handlers(h).run(); } diff --git a/src/errors.rs b/src/errors.rs index e2b6c11..95ad784 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,4 +1,5 @@ use crate::entry::Entry; +use crate::event_handlers::EventHandler; use std::fmt; pub struct Error { @@ -41,3 +42,9 @@ impl From> for Error { Error::new(&format!("IO error: {}", error)) } } + +impl From> for Error { + fn from(error: std::sync::mpsc::SendError) -> Self { + Error::new(&format!("IO error: {}", error)) + } +} diff --git a/src/event_handlers.rs b/src/event_handlers.rs new file mode 100644 index 0000000..6874721 --- /dev/null +++ b/src/event_handlers.rs @@ -0,0 +1,30 @@ +use crate::entry::{Entry, Event}; + +#[derive(Clone, Debug, PartialEq)] +pub enum MatchEvent { + Evt(Vec), + All, +} + +#[derive(Clone)] +pub struct EventHandler { + event: MatchEvent, + callback: (fn(&Entry) -> bool), +} + +impl EventHandler { + pub fn new(event: MatchEvent, callback: (fn(&Entry) -> bool)) -> Self { + EventHandler { event, callback } + } + + pub fn is_callable(&self, event: Event) -> bool { + match &self.event { + MatchEvent::All => true, + MatchEvent::Evt(v) => v.contains(&event), + } + } + + pub fn call(&self, entry: &Entry) -> bool { + (self.callback)(entry) + } +} diff --git a/src/lib.rs b/src/lib.rs index 0be2f4f..0915f3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,50 @@ mod entry; mod errors; +mod event_handlers; -use crate::entry::Entry; -use crate::errors::Error; use log::{debug, error, warn}; use std::collections::HashMap; use std::io; use std::sync::mpsc; use std::thread; +pub use crate::entry::{Entry, Event}; +pub use crate::errors::Error; +pub use crate::event_handlers::{EventHandler, MatchEvent}; + +struct SessionHandler { + entry_rx: mpsc::Receiver, + event_handlers: Vec, +} + +impl SessionHandler { + fn new(entry_rx: mpsc::Receiver, handlers_rx: mpsc::Receiver) -> Self { + debug!("New thread for session {}", thread::current().name().unwrap()); + let mut event_handlers = Vec::new(); + for h in handlers_rx.iter() { + debug!("Event handler registered"); + event_handlers.push(h); + } + SessionHandler { + entry_rx, + event_handlers, + } + } + + fn read_entries(&self) { + for e in self.entry_rx.iter() { + for h in self.event_handlers.iter() { + if h.is_callable(e.event.clone()) { + h.call(&e); + } + } + } + } +} + pub struct SmtpIn { sessions: HashMap, thread::JoinHandle<()>)>, + event_handlers: Vec, } impl SmtpIn { @@ -32,18 +66,16 @@ impl SmtpIn { let channel = match self.sessions.get(&entry.session_id) { Some((r, _)) => r, None => { - let (tx, rx) = mpsc::channel(); + let (handlers_tx, handlers_rx) = mpsc::channel(); + let (entry_tx, entry_rx) = mpsc::channel(); let name = entry.session_id.to_string(); let handle = thread::Builder::new().name(name).spawn(move || { - debug!( - "New thread for session {}", - thread::current().name().unwrap() - ); - for e in rx.iter() { - debug!("thread {}: {:?}", thread::current().name().unwrap(), e); - } + SessionHandler::new(entry_rx, handlers_rx).read_entries(); })?; - self.sessions.insert(entry.session_id, (tx, handle)); + for h in self.event_handlers.iter() { + handlers_tx.send(h.clone())?; + } + self.sessions.insert(entry.session_id, (entry_tx, handle)); let (r, _) = self.sessions.get(&entry.session_id).unwrap(); r } @@ -69,9 +101,15 @@ impl SmtpIn { pub fn new() -> Self { SmtpIn { sessions: HashMap::new(), + event_handlers: Vec::new(), } } + pub fn event_handlers(&mut self, handlers: Vec) -> &mut Self { + self.event_handlers = handlers.clone(); + self + } + /// Run the infinite loop that will read and process input from stdin. pub fn run(&mut self) { loop {