extern crate email_format;
extern crate lettre;
extern crate trust_dns_resolver;
extern crate uuid;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
extern crate native_tls;
extern crate toml;
#[cfg(test)]
mod tests;
pub mod config;
use config::Config;
mod worker;
pub use worker::WorkerStatus;
use worker::{Message, Worker};
pub mod error;
use error::Error;
mod delivery_result;
pub use delivery_result::DeliveryResult;
mod recipient_status;
pub use recipient_status::RecipientStatus;
mod message_status;
pub use message_status::MessageStatus;
mod prepared_email;
pub mod storage;
use storage::MailstromStorage;
use email_format::Email;
use std::ops::Drop;
use std::sync::{mpsc, Arc, RwLock};
use std::thread;
pub struct Mailstrom<S: MailstromStorage + 'static> {
config: Config,
sender: mpsc::Sender<Message>,
worker_status: Arc<RwLock<u8>>,
storage: Arc<RwLock<S>>,
}
impl<S: MailstromStorage + 'static> Mailstrom<S> {
pub fn new(config: Config, storage: S) -> Mailstrom<S>
{
let (sender, receiver) = mpsc::channel();
let storage = Arc::new(RwLock::new(storage));
let worker_status = Arc::new(RwLock::new(WorkerStatus::Ok as u8));
let mut worker = Worker::new(
receiver,
Arc::clone(&storage),
Arc::clone(&worker_status),
config.clone(),
);
let _ = thread::spawn(move || {
worker.run();
});
Mailstrom {
config,
sender,
worker_status,
storage,
}
}
pub fn start(&mut self) -> Result<(), Error> {
self.sender.send(Message::Start)?;
Ok(())
}
pub fn die(&mut self) -> Result<(), Error> {
self.sender.send(Message::Terminate)?;
Ok(())
}
pub fn worker_status(&self) -> WorkerStatus {
let ws = *self.worker_status.read().unwrap();
WorkerStatus::from_u8(ws)
}
pub fn send_email(&mut self, email: Email) -> Result<String, Error> {
let (prepared_email, internal_message_status) =
crate::prepared_email::prepare_email(email, &*self.config.helo_name)?;
let message_id = internal_message_status.message_id.clone();
{
let mut guard = match (*self.storage).write() {
Ok(guard) => guard,
Err(_) => return Err(Error::Lock),
};
(*guard).store(prepared_email, internal_message_status)?;
}
self.sender.send(Message::SendEmail(message_id.clone()))?;
info!("Passed email {} off to worker", &*message_id);
Ok(message_id)
}
pub fn query_status(&mut self, message_id: &str) -> Result<MessageStatus, Error> {
let guard = match (*self.storage).read() {
Ok(guard) => guard,
Err(_) => return Err(Error::Lock),
};
let status = (*guard).retrieve_status(message_id)?;
Ok(status.as_message_status())
}
pub fn query_recent(&mut self) -> Result<Vec<MessageStatus>, Error> {
let mut guard = match (*self.storage).write() {
Ok(guard) => guard,
Err(_) => return Err(Error::Lock),
};
let vec_statuses = (*guard).retrieve_all_recent()?;
Ok(vec_statuses.iter().map(|s| s.as_message_status()).collect())
}
}
impl<S: MailstromStorage + 'static> Drop for Mailstrom<S> {
fn drop(&mut self) {
info!("Mailstrom is terminating.");
let _ = self.sender.send(Message::Terminate);
}
}