Skip to content

feat: runtime independent examples #21

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 17 additions & 22 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,38 +19,33 @@ is-it-maintained-issue-resolution = { repository = "async-email/async-imap" }
is-it-maintained-open-issues = { repository = "async-email/async-imap" }

[features]
default = []
default = ["runtime-async-std"]

runtime-async-std = ["async-std", "async-native-tls/runtime-async-std"]
runtime-tokio = ["tokio", "async-native-tls/runtime-tokio"]

[dependencies]
imap-proto = "0.14.3"
nom = "6.0"
imap-proto = "0.16.1"
nom = "7.0"
base64 = "0.13"
chrono = "0.4"
async-native-tls = { version = "0.3.3" }
async-std = { version = "1.8.0", default-features = false, features = ["std"] }
pin-utils = "0.1.0-alpha.4"
futures = "0.3.15"
ouroboros = "0.9"
ouroboros = "0.15"
stop-token = "0.7"
byte-pool = "0.2.2"
once_cell = "1.8.0"
log = "0.4.8"
thiserror = "1.0.9"
async-channel = "1.6.1"

async-native-tls = { version = "0.4", default-features = false }
async-std = { version = "1.8.0", default-features = false, features = ["std"], optional = true }
tokio = { version = "1", features = ["net", "sync", "time"], optional = true }


[dev-dependencies]
lettre_email = "0.9"
pretty_assertions = "0.6.1"
async-smtp = { version = "0.3.0" }
async-std = { version = "1.8.0", default-features = false, features = ["std", "attributes"] }

[[example]]
name = "basic"
required-features = ["default"]

[[example]]
name = "gmail_oauth2"
required-features = ["default"]

[[test]]
name = "imap_integration"
required-features = ["default"]
pretty_assertions = "1.2"
async-std = { version = "1.8.0", features = ["std", "attributes"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

25 changes: 25 additions & 0 deletions examples/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[package]
name = "async-imap-examples"
version = "0.1.0"
publish = false
authors = ["dignifiedquire <[email protected]>"]
license = "Apache-2.0/MIT"
edition = "2018"

[features]
default = ["runtime-async-std"]

runtime-async-std = ["async-std", "async-native-tls/runtime-async-std", "async-smtp/runtime-async-std", "async-imap/runtime-async-std"]
runtime-tokio = ["tokio", "async-native-tls/runtime-tokio", "async-smtp/runtime-tokio", "async-imap/runtime-tokio"]

[dependencies]
async-imap = { path = "../", default-features = false }
async-native-tls = { version = "0.4", default-features = false }
async-smtp = { version = "0.4", default-features = false, features = ["smtp-transport"] }

async-std = { version = "1.8.0", features = ["std", "attributes"], optional = true }
futures = "0.3.21"
tokio = { version = "1", features = ["rt-multi-thread", "macros"], optional = true }

[patch.crates-io]
async-smtp = { git = "https://github.com/async-email/async-smtp", branch = "tokio" }
6 changes: 4 additions & 2 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ Examples:
* basic - This is a very basic example of using the client.

* idle - This is a basic example of how to perform an IMAP IDLE call
and interrupt it based on typing a line into stdin.
and interrupt it based on typing a line into stdin.

* gmail_oauth2 - This is an example using oauth2 for logging into
gmail via the OAUTH2 mechanism.
gmail via the OAUTH2 mechanism.

* futures - The basic example, but using the `futures` executor.
63 changes: 0 additions & 63 deletions examples/gmail_oauth2.rs

This file was deleted.

59 changes: 59 additions & 0 deletions examples/src/bin/basic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::env;

use async_imap::error::{Error, Result};
use futures::TryStreamExt;

#[cfg_attr(feature = "runtime-tokio", tokio::main)]
#[cfg_attr(feature = "runtime-async-std", async_std::main)]
async fn main() -> Result<()> {
let args: Vec<String> = env::args().collect();
if args.len() != 4 {
eprintln!("need three arguments: imap-server login password");
Err(Error::Bad("need three arguments".into()))
} else {
let res = fetch_inbox_top(&args[1], &args[2], &args[3]).await?;
println!("**result:\n{}", res.unwrap());
Ok(())
}
}

async fn fetch_inbox_top(imap_server: &str, login: &str, password: &str) -> Result<Option<String>> {
let tls = async_native_tls::TlsConnector::new();
let imap_addr = (imap_server, 993);

// we pass in the imap_server twice to check that the server's TLS
// certificate is valid for the imap_server we're connecting to.
let client = async_imap::connect(imap_addr, imap_server, tls).await?;
println!("-- connected to {}:{}", imap_addr.0, imap_addr.1);

// the client we have here is unauthenticated.
// to do anything useful with the e-mails, we need to log in
let mut imap_session = client.login(login, password).await.map_err(|e| e.0)?;
println!("-- logged in a {}", login);

// we want to fetch the first email in the INBOX mailbox
imap_session.select("INBOX").await?;
println!("-- INBOX selected");

// fetch message number 1 in this mailbox, along with its RFC822 field.
// RFC 822 dictates the format of the body of e-mails
let messages_stream = imap_session.fetch("1", "RFC822").await?;
let messages: Vec<_> = messages_stream.try_collect().await?;
let message = if let Some(m) = messages.first() {
m
} else {
return Ok(None);
};

// extract the message's body
let body = message.body().expect("message did not have a body!");
let body = std::str::from_utf8(body)
.expect("message was not valid utf-8")
.to_string();
println!("-- 1 message received, logging out");

// be nice to the server and log out
imap_session.logout().await?;

Ok(Some(body))
}
15 changes: 7 additions & 8 deletions examples/basic.rs → examples/src/bin/futures.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use async_imap::error::{Error, Result};
use async_std::prelude::*;
use async_std::task;
use std::env;

use async_imap::error::{Error, Result};
use futures::TryStreamExt;

fn main() -> Result<()> {
task::block_on(async {
futures::executor::block_on(async {
let args: Vec<String> = env::args().collect();
if args.len() != 4 {
eprintln!("need three arguments: imap-server login password");
Expand All @@ -19,12 +19,11 @@ fn main() -> Result<()> {

async fn fetch_inbox_top(imap_server: &str, login: &str, password: &str) -> Result<Option<String>> {
let tls = async_native_tls::TlsConnector::new();
let imap_addr = (imap_server, 993);

// we pass in the imap_server twice to check that the server's TLS
// certificate is valid for the imap_server we're connecting to.
let client = async_imap::connect(imap_addr, imap_server, tls).await?;
println!("-- connected to {}:{}", imap_addr.0, imap_addr.1);
let client = async_imap::connect((imap_server, 993), imap_server, tls).await?;
println!("-- connected to {}:{}", imap_server, 993);

// the client we have here is unauthenticated.
// to do anything useful with the e-mails, we need to log in
Expand All @@ -38,7 +37,7 @@ async fn fetch_inbox_top(imap_server: &str, login: &str, password: &str) -> Resu
// fetch message number 1 in this mailbox, along with its RFC822 field.
// RFC 822 dictates the format of the body of e-mails
let messages_stream = imap_session.fetch("1", "RFC822").await?;
let messages: Vec<_> = messages_stream.collect::<Result<_>>().await?;
let messages: Vec<_> = messages_stream.try_collect().await?;
let message = if let Some(m) = messages.first() {
m
} else {
Expand Down
59 changes: 59 additions & 0 deletions examples/src/bin/gmail_oauth2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use async_imap::error::Result;
use futures::StreamExt;

struct GmailOAuth2 {
user: String,
access_token: String,
}

impl async_imap::Authenticator for &GmailOAuth2 {
type Response = String;

fn process(&mut self, _data: &[u8]) -> Self::Response {
format!(
"user={}\x01auth=Bearer {}\x01\x01",
self.user, self.access_token
)
}
}

#[cfg_attr(feature = "runtime-tokio", tokio::main)]
#[cfg_attr(feature = "runtime-async-std", async_std::main)]
async fn main() -> Result<()> {
let gmail_auth = GmailOAuth2 {
user: String::from("[email protected]"),
access_token: String::from("<access_token>"),
};
let domain = "imap.gmail.com";
let port = 993;
let socket_addr = (domain, port);
let tls = async_native_tls::TlsConnector::new();
let client = async_imap::connect(socket_addr, domain, tls).await?;

let mut imap_session = match client.authenticate("XOAUTH2", &gmail_auth).await {
Ok(c) => c,
Err((e, _unauth_client)) => {
println!("error authenticating: {}", e);
return Err(e);
}
};

match imap_session.select("INBOX").await {
Ok(mailbox) => println!("{}", mailbox),
Err(e) => println!("Error selecting INBOX: {}", e),
};

{
let mut msgs = imap_session.fetch("2", "body[text]").await.map_err(|e| {
eprintln!("Error Fetching email 2: {}", e);
e
})?;

while let Some(msg) = msgs.next().await {
print!("{:?}", msg?);
}
}

imap_session.logout().await?;
Ok(())
}
39 changes: 22 additions & 17 deletions examples/idle.rs → examples/src/bin/idle.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
use async_imap::error::{Error, Result};
use async_std::prelude::*;
// use async_std::io;
use async_imap::extensions::idle::IdleResponse::*;
use async_std::task;
use std::env;
use std::time::Duration;

fn main() -> Result<()> {
task::block_on(async {
let args: Vec<String> = env::args().collect();
if args.len() != 4 {
eprintln!("need three arguments: imap-server login password");
Err(Error::Bad("need three arguments".into()))
} else {
fetch_and_idle(&args[1], &args[2], &args[3]).await?;
Ok(())
}
})
use async_imap::error::{Error, Result};
use async_imap::extensions::idle::IdleResponse::*;
use futures::StreamExt;

#[cfg(feature = "runtime-async-std")]
use async_std::{task, task::sleep};

#[cfg(feature = "runtime-tokio")]
use tokio::{task, time::sleep};

#[cfg_attr(feature = "runtime-tokio", tokio::main)]
#[cfg_attr(feature = "runtime-async-std", async_std::main)]
async fn main() -> Result<()> {
let args: Vec<String> = env::args().collect();
if args.len() != 4 {
eprintln!("need three arguments: imap-server login password");
Err(Error::Bad("need three arguments".into()))
} else {
fetch_and_idle(&args[1], &args[2], &args[3]).await?;
Ok(())
}
}

async fn fetch_and_idle(imap_server: &str, login: &str, password: &str) -> Result<()> {
Expand Down Expand Up @@ -59,7 +64,7 @@ async fn fetch_and_idle(imap_server: &str, login: &str, password: &str) -> Resul

task::spawn(async move {
println!("-- thread: waiting for 30s");
task::sleep(Duration::from_secs(30)).await;
sleep(Duration::from_secs(30)).await;
println!("-- thread: waited 30 secs, now interrupting idle");
drop(interrupt);
});
Expand Down
Loading