diff --git a/Cargo.toml b/Cargo.toml index f353bef..1ae174e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,7 +53,7 @@ harness = false name = "transport_smtp" [features] -async = ["async-std", "async-trait", "async-attributes"] +async-std1 = ["async-std", "async-trait", "async-attributes"] builder = ["mime", "base64", "hyperx", "rand", "quoted_printable"] default = ["file-transport", "smtp-transport", "native-tls", "hostname", "r2d2", "sendmail-transport", "builder"] file-transport = ["serde", "serde_json"] diff --git a/src/lib.rs b/src/lib.rs index e35f293..1e19b11 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,6 +55,8 @@ pub use crate::transport::smtp::r2d2::SmtpConnectionManager; #[cfg(feature = "smtp-transport")] pub use crate::transport::smtp::{SmtpTransport, Tls}; pub use crate::{address::Address, transport::stub::StubTransport}; +#[cfg(feature = "async-std1")] +use async_trait::async_trait; #[cfg(feature = "builder")] use std::convert::TryFrom; use std::{error::Error as StdError, fmt}; @@ -151,33 +153,24 @@ pub trait Transport { fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result; } -#[cfg(feature = "async")] -pub mod r#async { +/// Async Transport method for emails +#[cfg(feature = "async-std1")] +#[async_trait] +pub trait AsyncStd1Transport { + /// Result types for the transport + type Ok: fmt::Debug; + type Error: StdError; - use super::*; - use async_trait::async_trait; - - #[async_trait] - pub trait Transport { - /// Result types for the transport - type Ok: fmt::Debug; - type Error: StdError; - - /// Sends the email - #[cfg(feature = "builder")] - // TODO take &Message - async fn send(&self, message: Message) -> Result { - let raw = message.formatted(); - let envelope = message.envelope(); - self.send_raw(&envelope, &raw).await - } - - async fn send_raw( - &self, - envelope: &Envelope, - email: &[u8], - ) -> Result; + /// Sends the email + #[cfg(feature = "builder")] + // TODO take &Message + async fn send(&self, message: Message) -> Result { + let raw = message.formatted(); + let envelope = message.envelope(); + self.send_raw(&envelope, &raw).await } + + async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result; } #[cfg(test)] diff --git a/src/transport/file/mod.rs b/src/transport/file/mod.rs index bc2a28e..dda3292 100644 --- a/src/transport/file/mod.rs +++ b/src/transport/file/mod.rs @@ -35,10 +35,12 @@ //! TODO //! ``` +#[cfg(feature = "async-std1")] +use crate::AsyncStd1Transport; use crate::{transport::file::error::Error, Envelope, Transport}; +#[cfg(feature = "async-std1")] +use async_trait::async_trait; use std::{ - fs::File, - io::prelude::*, path::{Path, PathBuf}, str, }; @@ -72,11 +74,12 @@ struct SerializableEmail<'a> { message: Option<&'a str>, } -impl Transport for FileTransport { - type Ok = Id; - type Error = Error; - - fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result { +impl FileTransport { + fn send_raw_impl( + &self, + envelope: &Envelope, + email: &[u8], + ) -> Result<(Uuid, PathBuf, String), serde_json::Error> { let email_id = Uuid::new_v4(); let file = self.path.join(format!("{}.json", email_id)); @@ -94,51 +97,40 @@ impl Transport for FileTransport { }), }?; - File::create(file.as_path())?.write_all(serialized.as_bytes())?; + Ok((email_id, file, serialized)) + } +} + +impl Transport for FileTransport { + type Ok = Id; + type Error = Error; + + fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result { + use std::fs::File; + use std::io::Write; + + let (email_id, file, serialized) = self.send_raw_impl(envelope, email)?; + + let mut file = File::create(file)?; + file.write_all(serialized.as_bytes())?; Ok(email_id.to_string()) } } -#[cfg(feature = "async")] -pub mod r#async { - use super::{FileTransport, Id, SerializableEmail}; - use crate::{r#async::Transport, transport::file::error::Error, Envelope}; - use async_std::fs::File; - use async_std::prelude::*; - use async_trait::async_trait; - use std::str; - use uuid::Uuid; +#[cfg(feature = "async-std1")] +#[async_trait] +impl AsyncStd1Transport for FileTransport { + type Ok = Id; + type Error = Error; - #[async_trait] - impl Transport for FileTransport { - type Ok = Id; - type Error = Error; + async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result { + use async_std::fs::File; + use async_std::io::prelude::WriteExt; - async fn send_raw( - &self, - envelope: &Envelope, - email: &[u8], - ) -> Result { - let email_id = Uuid::new_v4(); - let file = self.path.join(format!("{}.json", email_id)); + let (email_id, file, serialized) = self.send_raw_impl(envelope, email)?; - let serialized = match str::from_utf8(email) { - // Serialize as UTF-8 string if possible - Ok(m) => serde_json::to_string(&SerializableEmail { - envelope: envelope.clone(), - message: Some(m), - raw_message: None, - }), - Err(_) => serde_json::to_string(&SerializableEmail { - envelope: envelope.clone(), - message: None, - raw_message: Some(email), - }), - }?; - - let mut file = File::create(file.as_path()).await?; - file.write_all(serialized.as_bytes()).await?; - Ok(email_id.to_string()) - } + let mut file = File::create(file).await?; + file.write_all(serialized.as_bytes()).await?; + Ok(email_id.to_string()) } } diff --git a/src/transport/sendmail/mod.rs b/src/transport/sendmail/mod.rs index e8f3f32..3a9df98 100644 --- a/src/transport/sendmail/mod.rs +++ b/src/transport/sendmail/mod.rs @@ -23,7 +23,11 @@ //! # } //! ``` +#[cfg(feature = "async-std1")] +use crate::AsyncStd1Transport; use crate::{transport::sendmail::error::Error, Envelope, Transport}; +#[cfg(feature = "async-std1")] +use async_trait::async_trait; use std::{ convert::AsRef, ffi::OsString, @@ -88,41 +92,30 @@ impl Transport for SendmailTransport { } } -#[cfg(feature = "async")] -pub mod r#async { - use super::SendmailTransport; - use crate::{r#async::Transport, transport::sendmail::error::Error, Envelope}; - use async_trait::async_trait; - use std::io::Write; +#[cfg(feature = "async-std1")] +#[async_trait] +impl AsyncStd1Transport for SendmailTransport { + type Ok = (); + type Error = Error; - #[async_trait] - impl Transport for SendmailTransport { - type Ok = (); - type Error = Error; + async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result { + let mut command = self.command(envelope); + let email = email.to_vec(); // TODO: Convert to real async, once async-std has a process implementation. - async fn send_raw( - &self, - envelope: &Envelope, - email: &[u8], - ) -> Result { - let mut command = self.command(envelope); - let email = email.to_vec(); + let output = async_std::task::spawn_blocking(move || { + // Spawn the sendmail command + let mut process = command.spawn()?; - let output = async_std::task::spawn_blocking(move || { - // Spawn the sendmail command - let mut process = command.spawn()?; + process.stdin.as_mut().unwrap().write_all(&email)?; + process.wait_with_output() + }) + .await?; - process.stdin.as_mut().unwrap().write_all(&email)?; - process.wait_with_output() - }) - .await?; - - if output.status.success() { - Ok(()) - } else { - Err(Error::Client(String::from_utf8(output.stderr)?)) - } + if output.status.success() { + Ok(()) + } else { + Err(Error::Client(String::from_utf8(output.stderr)?)) } } } diff --git a/src/transport/stub/mod.rs b/src/transport/stub/mod.rs index dc5c3f6..0ab2a86 100644 --- a/src/transport/stub/mod.rs +++ b/src/transport/stub/mod.rs @@ -22,7 +22,11 @@ //! assert!(result.is_ok()); //! ``` +#[cfg(feature = "async-std1")] +use crate::AsyncStd1Transport; use crate::{Envelope, Transport}; +#[cfg(feature = "async-std1")] +use async_trait::async_trait; use std::{error::Error as StdError, fmt}; #[derive(Debug, Copy, Clone)] @@ -74,23 +78,13 @@ impl Transport for StubTransport { } } -#[cfg(feature = "async")] -pub mod r#async { - use super::StubTransport; - use crate::{r#async::Transport, transport::stub::Error, Envelope}; - use async_trait::async_trait; +#[cfg(feature = "async-std1")] +#[async_trait] +impl AsyncStd1Transport for StubTransport { + type Ok = (); + type Error = Error; - #[async_trait] - impl Transport for StubTransport { - type Ok = (); - type Error = Error; - - async fn send_raw( - &self, - _envelope: &Envelope, - _email: &[u8], - ) -> Result { - self.response - } + async fn send_raw(&self, _envelope: &Envelope, _email: &[u8]) -> Result { + self.response } }