Refactor async-std support to prepare for more async runtimes
Renames the async feature to async-std1 Moves things out of mod async since it makes things have to be written as r#async and makes them feel less important.
This commit is contained in:
@@ -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"]
|
||||
|
||||
43
src/lib.rs
43
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<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
#[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<Self::Ok, Self::Error> {
|
||||
let raw = message.formatted();
|
||||
let envelope = message.envelope();
|
||||
self.send_raw(&envelope, &raw).await
|
||||
}
|
||||
|
||||
async fn send_raw(
|
||||
&self,
|
||||
envelope: &Envelope,
|
||||
email: &[u8],
|
||||
) -> Result<Self::Ok, Self::Error>;
|
||||
/// Sends the email
|
||||
#[cfg(feature = "builder")]
|
||||
// TODO take &Message
|
||||
async fn send(&self, message: Message) -> Result<Self::Ok, Self::Error> {
|
||||
let raw = message.formatted();
|
||||
let envelope = message.envelope();
|
||||
self.send_raw(&envelope, &raw).await
|
||||
}
|
||||
|
||||
async fn send_raw(&self, envelope: &Envelope, email: &[u8]) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -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<Self::Ok, Self::Error> {
|
||||
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<Self::Ok, Self::Error> {
|
||||
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<Self::Ok, Self::Error> {
|
||||
use async_std::fs::File;
|
||||
use async_std::io::prelude::WriteExt;
|
||||
|
||||
async fn send_raw(
|
||||
&self,
|
||||
envelope: &Envelope,
|
||||
email: &[u8],
|
||||
) -> Result<Self::Ok, Self::Error> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Self::Ok, Self::Error> {
|
||||
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<Self::Ok, Self::Error> {
|
||||
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)?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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::Ok, Self::Error> {
|
||||
self.response
|
||||
}
|
||||
async fn send_raw(&self, _envelope: &Envelope, _email: &[u8]) -> Result<Self::Ok, Self::Error> {
|
||||
self.response
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user