Merge branch 'rtcompat-refactor' into 'main'
Refactor the tor-rtcompat API. Closes #301 and #300 See merge request tpo/core/arti!263
This commit is contained in:
commit
2f39dbd587
|
@ -28,11 +28,12 @@ rust-latest:
|
||||||
- target/x86_64-unknown-linux-gnu/debug/arti
|
- target/x86_64-unknown-linux-gnu/debug/arti
|
||||||
expire_in: 1 hours
|
expire_in: 1 hours
|
||||||
|
|
||||||
rust-latest-async-std:
|
rust-latest-async-std-rustls:
|
||||||
stage: build
|
stage: build
|
||||||
image: rust:latest
|
image: rust:latest
|
||||||
script:
|
script:
|
||||||
- cd crates/arti-client && cargo check --no-default-features --features=async-std
|
- rustup component add clippy
|
||||||
|
- cd crates/arti-client && cargo clippy --no-default-features --features=async-std,rustls
|
||||||
tags:
|
tags:
|
||||||
- amd64
|
- amd64
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,7 @@ dependencies = [
|
||||||
"arti-client",
|
"arti-client",
|
||||||
"arti-config",
|
"arti-config",
|
||||||
"async-ctrlc",
|
"async-ctrlc",
|
||||||
|
"cfg-if",
|
||||||
"clap",
|
"clap",
|
||||||
"config",
|
"config",
|
||||||
"futures",
|
"futures",
|
||||||
|
|
|
@ -21,7 +21,7 @@ serde_json = "1.0.50"
|
||||||
tracing = "0.1.18"
|
tracing = "0.1.18"
|
||||||
tracing-subscriber = { version = "0.3.0", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.0", features = ["env-filter"] }
|
||||||
tokio = { version = "1.4", features = ["full"] }
|
tokio = { version = "1.4", features = ["full"] }
|
||||||
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features = ["tokio"] }
|
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features = ["tokio", "native-tls"] }
|
||||||
arti-config = { path="../arti-config", version = "0.0.3"}
|
arti-config = { path="../arti-config", version = "0.0.3"}
|
||||||
arti-client = { package="arti-client", path = "../arti-client", version = "0.0.3"}
|
arti-client = { package="arti-client", path = "../arti-client", version = "0.0.3"}
|
||||||
tokio-socks = "0.5"
|
tokio-socks = "0.5"
|
||||||
|
|
|
@ -371,7 +371,7 @@ fn main() -> Result<()> {
|
||||||
concurrent: parallel,
|
concurrent: parallel,
|
||||||
upload_payload,
|
upload_payload,
|
||||||
download_payload,
|
download_payload,
|
||||||
runtime: tor_rtcompat::tokio::create_runtime()?,
|
runtime: tor_rtcompat::tokio::TokioNativeTlsRuntime::create()?,
|
||||||
results: Default::default(),
|
results: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,11 @@ categories = [ "network-programming", "cryptography" ]
|
||||||
repository="https://gitlab.torproject.org/tpo/core/arti.git/"
|
repository="https://gitlab.torproject.org/tpo/core/arti.git/"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "tokio" ]
|
default = [ "tokio", "native-tls" ]
|
||||||
async-std = [ "tor-rtcompat/async-std" ]
|
async-std = [ "tor-rtcompat/async-std" ]
|
||||||
tokio = [ "tor-rtcompat/tokio", "tor-proto/tokio" ]
|
tokio = [ "tor-rtcompat/tokio", "tor-proto/tokio" ]
|
||||||
|
native-tls = [ "tor-rtcompat/native-tls" ]
|
||||||
|
rustls = [ "tor-rtcompat/rustls" ]
|
||||||
static = [ "tor-rtcompat/static", "tor-dirmgr/static" ]
|
static = [ "tor-rtcompat/static", "tor-dirmgr/static" ]
|
||||||
|
|
||||||
# Enable experimental APIs that are not yet officially supported.
|
# Enable experimental APIs that are not yet officially supported.
|
||||||
|
@ -42,7 +44,7 @@ serde = { version = "1.0.103", features = ["derive"] }
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio"] }
|
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio", "native-tls" ] }
|
||||||
tokio-crate = { package = "tokio", version = "1.4", features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros" ] }
|
tokio-crate = { package = "tokio", version = "1.4", features = ["rt", "rt-multi-thread", "io-util", "net", "time", "macros" ] }
|
||||||
hyper = { version = "0.14", features = ["http1", "client", "runtime"] }
|
hyper = { version = "0.14", features = ["http1", "client", "runtime"] }
|
||||||
pin-project = "1"
|
pin-project = "1"
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::pin::Pin;
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
|
||||||
use tokio_crate as tokio;
|
use tokio_crate as tokio;
|
||||||
use tor_rtcompat::tokio::TokioRuntimeHandle;
|
use tor_rtcompat::tokio::TokioNativeTlsRuntime;
|
||||||
use tor_rtcompat::Runtime;
|
use tor_rtcompat::Runtime;
|
||||||
|
|
||||||
/// A `hyper` connector to proxy HTTP connections via the Tor network, using Arti.
|
/// A `hyper` connector to proxy HTTP connections via the Tor network, using Arti.
|
||||||
|
@ -138,7 +138,7 @@ async fn main() -> Result<()> {
|
||||||
// on Linux platforms)
|
// on Linux platforms)
|
||||||
let config = TorClientConfig::default();
|
let config = TorClientConfig::default();
|
||||||
// Arti needs an async runtime handle to spawn async tasks.
|
// Arti needs an async runtime handle to spawn async tasks.
|
||||||
let rt: TokioRuntimeHandle = tokio_crate::runtime::Handle::current().into();
|
let rt: TokioNativeTlsRuntime = tokio_crate::runtime::Handle::current().into();
|
||||||
|
|
||||||
// We now let the Arti client start and bootstrap a connection to the network.
|
// We now let the Arti client start and bootstrap a connection to the network.
|
||||||
// (This takes a while to gather the necessary consensus state, etc.)
|
// (This takes a while to gather the necessary consensus state, etc.)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use arti_client::{TorClient, TorClientConfig};
|
use arti_client::{TorClient, TorClientConfig};
|
||||||
use tokio_crate as tokio;
|
use tokio_crate as tokio;
|
||||||
|
use tor_rtcompat::tokio::TokioNativeTlsRuntime;
|
||||||
|
|
||||||
use futures::io::{AsyncReadExt, AsyncWriteExt};
|
use futures::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ async fn main() -> Result<()> {
|
||||||
let config = TorClientConfig::default();
|
let config = TorClientConfig::default();
|
||||||
// Arti needs an async runtime handle to spawn async tasks.
|
// Arti needs an async runtime handle to spawn async tasks.
|
||||||
// (See "Multiple runtime support" below.)
|
// (See "Multiple runtime support" below.)
|
||||||
let rt = tor_rtcompat::tokio::current_runtime()?;
|
let rt = TokioNativeTlsRuntime::current()?;
|
||||||
|
|
||||||
eprintln!("connecting to Tor...");
|
eprintln!("connecting to Tor...");
|
||||||
|
|
||||||
|
|
|
@ -24,9 +24,9 @@ use std::time::Duration;
|
||||||
|
|
||||||
use crate::{status, Error, Result};
|
use crate::{status, Error, Result};
|
||||||
#[cfg(feature = "async-std")]
|
#[cfg(feature = "async-std")]
|
||||||
use tor_rtcompat::async_std::AsyncStdRuntime;
|
use tor_rtcompat::async_std::PreferredRuntime as PreferredAsyncStdRuntime;
|
||||||
#[cfg(feature = "tokio")]
|
#[cfg(feature = "tokio")]
|
||||||
use tor_rtcompat::tokio::TokioRuntimeHandle;
|
use tor_rtcompat::tokio::PreferredRuntime as PreferredTokioRuntime;
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
/// An active client session on the Tor network.
|
/// An active client session on the Tor network.
|
||||||
|
@ -246,7 +246,7 @@ impl StreamPrefs {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tokio")]
|
#[cfg(feature = "tokio")]
|
||||||
impl TorClient<TokioRuntimeHandle> {
|
impl TorClient<PreferredTokioRuntime> {
|
||||||
/// Bootstrap a connection to the Tor network, using the current Tokio runtime.
|
/// Bootstrap a connection to the Tor network, using the current Tokio runtime.
|
||||||
///
|
///
|
||||||
/// Returns a client once there is enough directory material to
|
/// Returns a client once there is enough directory material to
|
||||||
|
@ -259,14 +259,14 @@ impl TorClient<TokioRuntimeHandle> {
|
||||||
/// Panics if called outside of the context of a Tokio runtime.
|
/// Panics if called outside of the context of a Tokio runtime.
|
||||||
pub async fn bootstrap_with_tokio(
|
pub async fn bootstrap_with_tokio(
|
||||||
config: TorClientConfig,
|
config: TorClientConfig,
|
||||||
) -> Result<TorClient<TokioRuntimeHandle>> {
|
) -> Result<TorClient<PreferredTokioRuntime>> {
|
||||||
let rt = tor_rtcompat::tokio::current_runtime().expect("called outside of Tokio runtime");
|
let rt = PreferredTokioRuntime::current().expect("called outside of Tokio runtime");
|
||||||
Self::bootstrap(rt, config).await
|
Self::bootstrap(rt, config).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "async-std")]
|
#[cfg(feature = "async-std")]
|
||||||
impl TorClient<AsyncStdRuntime> {
|
impl TorClient<PreferredAsyncStdRuntime> {
|
||||||
/// Bootstrap a connection to the Tor network, using the current async-std runtime.
|
/// Bootstrap a connection to the Tor network, using the current async-std runtime.
|
||||||
///
|
///
|
||||||
/// Returns a client once there is enough directory material to
|
/// Returns a client once there is enough directory material to
|
||||||
|
@ -275,10 +275,9 @@ impl TorClient<AsyncStdRuntime> {
|
||||||
/// This is a convenience wrapper around [`TorClient::bootstrap`].
|
/// This is a convenience wrapper around [`TorClient::bootstrap`].
|
||||||
pub async fn bootstrap_with_async_std(
|
pub async fn bootstrap_with_async_std(
|
||||||
config: TorClientConfig,
|
config: TorClientConfig,
|
||||||
) -> Result<TorClient<AsyncStdRuntime>> {
|
) -> Result<TorClient<PreferredAsyncStdRuntime>> {
|
||||||
// FIXME(eta): not actually possible for this to fail
|
// FIXME(eta): not actually possible for this to fail
|
||||||
let rt =
|
let rt = PreferredAsyncStdRuntime::current().expect("failed to get async-std runtime");
|
||||||
tor_rtcompat::async_std::current_runtime().expect("failed to get async-std runtime");
|
|
||||||
Self::bootstrap(rt, config).await
|
Self::bootstrap(rt, config).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
//! let config = TorClientConfig::default();
|
//! let config = TorClientConfig::default();
|
||||||
//! // Arti needs a handle to an async runtime in order to spawn tasks and use the
|
//! // Arti needs a handle to an async runtime in order to spawn tasks and use the
|
||||||
//! // network. (See "Multiple runtime support" below.)
|
//! // network. (See "Multiple runtime support" below.)
|
||||||
//! let rt = tor_rtcompat::tokio::current_runtime()?;
|
//! let rt = tor_rtcompat::tokio::TokioNativeTlsRuntime::current()?;
|
||||||
//!
|
//!
|
||||||
//! // Start the Arti client, and let it bootstrap a connection to the Tor network.
|
//! // Start the Arti client, and let it bootstrap a connection to the Tor network.
|
||||||
//! // (This takes a while to gather the necessary directory information.
|
//! // (This takes a while to gather the necessary directory information.
|
||||||
|
@ -118,14 +118,16 @@
|
||||||
//! will expect a type that implements [`tor_rtcompat::Runtime`], which can be obtained:
|
//! will expect a type that implements [`tor_rtcompat::Runtime`], which can be obtained:
|
||||||
//!
|
//!
|
||||||
//! - for Tokio:
|
//! - for Tokio:
|
||||||
//! - by calling [`tor_rtcompat::tokio::current_runtime`], if a Tokio reactor is already running
|
//! - by calling [`tor_rtcompat::tokio::PreferredRuntime::current()`], if a Tokio reactor is already running
|
||||||
//! - by calling [`tor_rtcompat::tokio::create_runtime`], to start a new reactor if one is not
|
//! - by calling [`tor_rtcompat::tokio::PreferredRuntime::create()`], to start a new reactor if one is not
|
||||||
//! already running
|
//! already running
|
||||||
//! - by manually creating a [`TokioRuntimeHandle`](tor_rtcompat::tokio::TokioRuntimeHandle) from
|
//! - as above, but explicitly specifying [`TokioNativeTlsRuntime`](tor_rtcompat::tokio::TokioNativeTlsRuntime)
|
||||||
//! an existing Tokio runtime handle
|
//! or [`TokioRustlsRuntime`](tor_rtcompat::tokio::TokioRustlsRuntime) in place of `PreferredRuntime`.
|
||||||
//! - for async-std:
|
//! - for async-std:
|
||||||
//! - by calling [`tor_rtcompat::async_std::current_runtime`], which will create a runtime or
|
//! - by calling [`tor_rtcompat::async_std::PreferredRuntime::current()`], which will create a runtime or
|
||||||
//! retrieve the existing one, if one has already been started
|
//! retrieve the existing one, if one has already been started
|
||||||
|
//! - as above, but explicitly specifying [`AsyncStdNativeTlsRuntime`](tor_rtcompat::async_std::AsyncStdNativeTlsRuntime)
|
||||||
|
//! or [`AsyncStdRustlsRuntime`](tor_rtcompat::async_std::AsyncStdRustlsRuntime) in place of `PreferredRuntime`.
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
//! # Feature flags
|
//! # Feature flags
|
||||||
|
|
|
@ -11,14 +11,16 @@ categories = [ "command-line-utilities", "cryptography" ]
|
||||||
repository="https://gitlab.torproject.org/tpo/core/arti.git/"
|
repository="https://gitlab.torproject.org/tpo/core/arti.git/"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "tokio" ]
|
default = [ "tokio", "native-tls" ]
|
||||||
async-std = [ "arti-client/async-std", "tor-rtcompat/async-std", "async-ctrlc", "once_cell" ]
|
async-std = [ "arti-client/async-std", "tor-rtcompat/async-std", "async-ctrlc", "once_cell" ]
|
||||||
tokio = [ "tokio-crate", "arti-client/tokio", "tor-rtcompat/tokio" ]
|
tokio = [ "tokio-crate", "arti-client/tokio", "tor-rtcompat/tokio" ]
|
||||||
|
native-tls = [ "arti-client/native-tls", "tor-rtcompat/native-tls" ]
|
||||||
|
rustls = [ "arti-client/rustls", "tor-rtcompat/rustls" ]
|
||||||
static = [ "arti-client/static" ]
|
static = [ "arti-client/static" ]
|
||||||
journald = [ "tracing-journald" ]
|
journald = [ "tracing-journald" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
arti-client = { package="arti-client", path = "../arti-client", version = "0.0.3"}
|
arti-client = { package="arti-client", path = "../arti-client", version = "0.0.3", default-features=false}
|
||||||
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", default-features=false }
|
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", default-features=false }
|
||||||
tor-socksproto = { path="../tor-socksproto", version = "0.0.3"}
|
tor-socksproto = { path="../tor-socksproto", version = "0.0.3"}
|
||||||
arti-config = { path="../arti-config", version = "0.0.3"}
|
arti-config = { path="../arti-config", version = "0.0.3"}
|
||||||
|
@ -26,6 +28,7 @@ arti-config = { path="../arti-config", version = "0.0.3"}
|
||||||
anyhow = "1.0.5"
|
anyhow = "1.0.5"
|
||||||
async-ctrlc = { version = "1.2.0", optional = true }
|
async-ctrlc = { version = "1.2.0", optional = true }
|
||||||
config = { version = "0.11.0", default-features = false }
|
config = { version = "0.11.0", default-features = false }
|
||||||
|
cfg-if = "1.0.0"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
tracing = "0.1.18"
|
tracing = "0.1.18"
|
||||||
once_cell = { version = "1", optional = true }
|
once_cell = { version = "1", optional = true }
|
||||||
|
|
|
@ -96,7 +96,7 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use arti_client::{TorClient, TorClientConfig};
|
use arti_client::{TorClient, TorClientConfig};
|
||||||
use arti_config::ArtiConfig;
|
use arti_config::ArtiConfig;
|
||||||
use tor_rtcompat::{Runtime, SpawnBlocking};
|
use tor_rtcompat::{BlockOn, Runtime};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::{App, AppSettings, Arg, SubCommand};
|
use clap::{App, AppSettings, Arg, SubCommand};
|
||||||
|
@ -229,10 +229,19 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
process::use_max_file_limit();
|
process::use_max_file_limit();
|
||||||
|
|
||||||
#[cfg(feature = "tokio")]
|
cfg_if::cfg_if! {
|
||||||
let runtime = tor_rtcompat::tokio::create_runtime()?;
|
if #[cfg(all(feature="tokio", feature="native-tls"))] {
|
||||||
#[cfg(all(feature = "async-std", not(feature = "tokio")))]
|
use tor_rtcompat::tokio::TokioNativeTlsRuntime as ChosenRuntime;
|
||||||
let runtime = tor_rtcompat::async_std::create_runtime()?;
|
} else if #[cfg(all(feature="tokio", feature="rustls"))] {
|
||||||
|
use tor_rtcompat::tokio::TokioRustlsRuntime as ChosenRuntime;
|
||||||
|
} else if #[cfg(all(feature="async-std", feature="native-tls"))] {
|
||||||
|
use tor_rtcompat::tokio::TokioRustlsRuntime as ChosenRuntime;
|
||||||
|
} else if #[cfg(all(feature="async-std", feature="rustls"))] {
|
||||||
|
use tor_rtcompat::tokio::TokioRustlsRuntime as ChosenRuntime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let runtime = ChosenRuntime::create()?;
|
||||||
|
|
||||||
let rt_copy = runtime.clone();
|
let rt_copy = runtime.clone();
|
||||||
rt_copy.block_on(run(runtime, socks_port, client_config))?;
|
rt_copy.block_on(run(runtime, socks_port, client_config))?;
|
||||||
|
|
|
@ -30,4 +30,4 @@ float_eq = "0.7"
|
||||||
futures-await-test = "0.3.0"
|
futures-await-test = "0.3.0"
|
||||||
hex-literal = "0.3"
|
hex-literal = "0.3"
|
||||||
tor-rtmock = { path="../tor-rtmock", version = "0.0.3"}
|
tor-rtmock = { path="../tor-rtmock", version = "0.0.3"}
|
||||||
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio"] }
|
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio", "native-tls"] }
|
||||||
|
|
|
@ -50,4 +50,4 @@ tor-guardmgr = { path="../tor-guardmgr", version = "0.0.3", features=["testing"]
|
||||||
tor-llcrypto = { path="../tor-llcrypto", version = "0.0.3"}
|
tor-llcrypto = { path="../tor-llcrypto", version = "0.0.3"}
|
||||||
tor-netdir = { path="../tor-netdir", version = "0.0.3", features=["testing"] }
|
tor-netdir = { path="../tor-netdir", version = "0.0.3", features=["testing"] }
|
||||||
tor-persist = { path="../tor-persist", version = "0.0.3", features=["testing"] }
|
tor-persist = { path="../tor-persist", version = "0.0.3", features=["testing"] }
|
||||||
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio"] }
|
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio", "native-tls" ] }
|
||||||
|
|
|
@ -440,7 +440,7 @@ mod test {
|
||||||
|
|
||||||
/// Helper type used to help type inference.
|
/// Helper type used to help type inference.
|
||||||
pub(crate) type OptDummyGuardMgr<'a> =
|
pub(crate) type OptDummyGuardMgr<'a> =
|
||||||
Option<&'a tor_guardmgr::GuardMgr<tor_rtcompat::tokio::TokioRuntime>>;
|
Option<&'a tor_guardmgr::GuardMgr<tor_rtcompat::tokio::TokioNativeTlsRuntime>>;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn get_params() {
|
fn get_params() {
|
||||||
|
|
|
@ -38,5 +38,5 @@ thiserror = "1"
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
futures-await-test = "0.3.0"
|
futures-await-test = "0.3.0"
|
||||||
tor-rtmock = { path="../tor-rtmock", version = "0.0.3"}
|
tor-rtmock = { path="../tor-rtmock", version = "0.0.3"}
|
||||||
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio"] }
|
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio", "native-tls" ] }
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,5 @@ humantime-serde = "1"
|
||||||
futures-await-test = "0.3.0"
|
futures-await-test = "0.3.0"
|
||||||
hex-literal = "0.3"
|
hex-literal = "0.3"
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
tor-rtcompat = { path = "../tor-rtcompat", version = "0.0.3", features = [
|
tor-rtcompat = { path = "../tor-rtcompat", version = "0.0.3", features = [ "tokio", "native-tls" ] }
|
||||||
"tokio",
|
|
||||||
] }
|
|
||||||
float_eq = "0.7"
|
float_eq = "0.7"
|
||||||
|
|
|
@ -42,5 +42,5 @@ tracing = "0.1.18"
|
||||||
tor-netdir = { path="../tor-netdir", version = "0.0.3", features=["testing"]}
|
tor-netdir = { path="../tor-netdir", version = "0.0.3", features=["testing"]}
|
||||||
tor-netdoc = { path="../tor-netdoc", version = "0.0.3"}
|
tor-netdoc = { path="../tor-netdoc", version = "0.0.3"}
|
||||||
tor-persist = { path="../tor-persist", version = "0.0.3", features=["testing"]}
|
tor-persist = { path="../tor-persist", version = "0.0.3", features=["testing"]}
|
||||||
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio"]}
|
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio", "native-tls"]}
|
||||||
tor-rtmock = { path="../tor-rtmock", version = "0.0.3"}
|
tor-rtmock = { path="../tor-rtmock", version = "0.0.3"}
|
||||||
|
|
|
@ -49,8 +49,6 @@ tokio-util = { version = "0.6", features = ["compat"], optional = true }
|
||||||
coarsetime = { version = "0.1.20", optional = true }
|
coarsetime = { version = "0.1.20", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tor-rtcompat = { path = "../tor-rtcompat", version = "0.0.3", features = [
|
tor-rtcompat = { path = "../tor-rtcompat", version = "0.0.3", features = [ "tokio", "native-tls" ] }
|
||||||
"tokio",
|
|
||||||
] }
|
|
||||||
hex-literal = "0.3"
|
hex-literal = "0.3"
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|
|
@ -81,9 +81,6 @@
|
||||||
//! I bet that there are deadlocks somewhere in this code. I fixed
|
//! I bet that there are deadlocks somewhere in this code. I fixed
|
||||||
//! all the ones I could find or think of, but it would be great to
|
//! all the ones I could find or think of, but it would be great to
|
||||||
//! find a good way to eliminate every lock that we have.
|
//! find a good way to eliminate every lock that we have.
|
||||||
//!
|
|
||||||
//! This crate doesn't work with rusttls because of a limitation in the
|
|
||||||
//! webpki crate.
|
|
||||||
|
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![warn(noop_method_call)]
|
#![warn(noop_method_call)]
|
||||||
|
|
|
@ -15,7 +15,10 @@ repository="https://gitlab.torproject.org/tpo/core/arti.git/"
|
||||||
default = [ ]
|
default = [ ]
|
||||||
async-std = [ "async-std-crate", "async-io", "async_executors/async_std" ]
|
async-std = [ "async-std-crate", "async-io", "async_executors/async_std" ]
|
||||||
tokio = [ "tokio-crate", "tokio-util", "async_executors/tokio_tp" ]
|
tokio = [ "tokio-crate", "tokio-util", "async_executors/tokio_tp" ]
|
||||||
static = [ "native-tls/vendored" ]
|
# TODO: This feature makes us link native-tls statically even if we
|
||||||
|
# don't want to use native-tls in the first place. That's not so clever!
|
||||||
|
static = [ "native-tls-crate/vendored" ]
|
||||||
|
native-tls = [ "native-tls-crate", "async-native-tls" ]
|
||||||
rustls = [ "rustls-crate", "async-rustls", "x509-signature" ]
|
rustls = [ "rustls-crate", "async-rustls", "x509-signature" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -24,15 +27,20 @@ async_executors = { version = "0.4", default_features = false }
|
||||||
async-trait = "0.1.2"
|
async-trait = "0.1.2"
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
pin-project = "1"
|
pin-project = "1"
|
||||||
native-tls = "0.2"
|
native-tls-crate = { package = "native-tls", version = "0.2", optional = true }
|
||||||
rustls-crate = { package = "rustls", version = "0.19", optional = true, features = [ "dangerous_configuration" ] }
|
rustls-crate = { package = "rustls", version = "0.19", optional = true, features = [ "dangerous_configuration" ] }
|
||||||
|
|
||||||
async-std-crate = { package = "async-std", version = "1.7.0", optional = true }
|
async-std-crate = { package = "async-std", version = "1.7.0", optional = true }
|
||||||
async-io = { version = "1.4.1", optional = true }
|
async-io = { version = "1.4.1", optional = true }
|
||||||
async-native-tls = { version = "0.4.0" }
|
async-native-tls = { version = "0.4.0", optional = true }
|
||||||
|
|
||||||
tokio-crate = { package = "tokio", version = "1.4", optional = true, features = ["rt", "rt-multi-thread", "io-util", "net", "time" ] }
|
tokio-crate = { package = "tokio", version = "1.4", optional = true, features = ["rt", "rt-multi-thread", "io-util", "net", "time" ] }
|
||||||
tokio-util = { version = "0.6", features = ["compat"], optional = true }
|
tokio-util = { version = "0.6", features = ["compat"], optional = true }
|
||||||
|
|
||||||
async-rustls = { version = "0.2.0", optional = true }
|
async-rustls = { version = "0.2.0", optional = true }
|
||||||
x509-signature = { version = "0.5.0", optional = true }
|
x509-signature = { version = "0.5.0", optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
# Used for testing our TLS implementation.
|
||||||
|
native-tls-crate = { package = "native-tls", version = "0.2" }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Run a provided command over all possible subsets of important
|
||||||
|
# tor-rtcompat features.
|
||||||
|
|
||||||
|
import sys, subprocess
|
||||||
|
|
||||||
|
if sys.argv[1:] == []:
|
||||||
|
print("You need to name a program to run with different features")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
FEATURES = [ "tokio", "async-std", "native-tls", "rustls" ]
|
||||||
|
|
||||||
|
COMBINATIONS = [ [] ]
|
||||||
|
|
||||||
|
# Generate all combinations of features.
|
||||||
|
for feature in FEATURES:
|
||||||
|
new_combinations = [ c + [ feature ] for c in COMBINATIONS ]
|
||||||
|
COMBINATIONS.extend(new_combinations)
|
||||||
|
|
||||||
|
for c in COMBINATIONS:
|
||||||
|
arg = "--features={}".format(",".join(c))
|
||||||
|
commandline = sys.argv[1:] + [arg]
|
||||||
|
print(" ".join(commandline))
|
||||||
|
subprocess.check_call(commandline)
|
||||||
|
|
|
@ -1,27 +1,46 @@
|
||||||
//! Entry points for use with async_std runtimes.
|
//! Entry points for use with async_std runtimes.
|
||||||
pub use crate::impls::async_std::create_runtime as create_runtime_impl;
|
pub use crate::impls::async_std::create_runtime as create_runtime_impl;
|
||||||
use crate::{compound::CompoundRuntime, SpawnBlocking};
|
use crate::{compound::CompoundRuntime, BlockOn};
|
||||||
|
use std::io::Result as IoResult;
|
||||||
|
|
||||||
|
#[cfg(feature = "native-tls")]
|
||||||
use crate::impls::native_tls::NativeTlsProvider;
|
use crate::impls::native_tls::NativeTlsProvider;
|
||||||
|
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
use crate::impls::rustls::RustlsProvider;
|
use crate::impls::rustls::RustlsProvider;
|
||||||
use async_std_crate::net::TcpStream;
|
use async_std_crate::net::TcpStream;
|
||||||
|
|
||||||
use async_executors::AsyncStd;
|
use async_executors::AsyncStd;
|
||||||
|
|
||||||
|
/// An alias for the async_std runtime that we prefer to use, based on whatever TLS
|
||||||
|
/// implementation has been enabled.
|
||||||
|
///
|
||||||
|
/// If only one of `native_tls` and `rustls` bas been enabled within the
|
||||||
|
/// `tor-rtcompat` crate, that will be the TLS backend that this uses.
|
||||||
|
///
|
||||||
|
/// Currently, `native_tls` is preferred over `rustls` when both are available,
|
||||||
|
/// because of its maturity within Arti. However, this might change in the
|
||||||
|
/// future.
|
||||||
|
#[cfg(all(feature = "native-tls"))]
|
||||||
|
pub use AsyncStdNativeTlsRuntime as PreferredRuntime;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "rustls", not(feature = "native-tls")))]
|
||||||
|
pub use AsyncStdRustlsRuntime as PreferredRuntime;
|
||||||
|
|
||||||
/// A [`Runtime`](crate::Runtime) powered by `async_std` and `native_tls`.
|
/// A [`Runtime`](crate::Runtime) powered by `async_std` and `native_tls`.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AsyncStdRuntime {
|
#[cfg(all(feature = "native-tls"))]
|
||||||
|
pub struct AsyncStdNativeTlsRuntime {
|
||||||
/// The actual runtime object.
|
/// The actual runtime object.
|
||||||
inner: NativeTlsInner,
|
inner: NativeTlsInner,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation type for AsyncStdRuntime.
|
/// Implementation type for AsyncStdRuntime.
|
||||||
|
#[cfg(all(feature = "native-tls"))]
|
||||||
type NativeTlsInner = CompoundRuntime<AsyncStd, AsyncStd, AsyncStd, NativeTlsProvider<TcpStream>>;
|
type NativeTlsInner = CompoundRuntime<AsyncStd, AsyncStd, AsyncStd, NativeTlsProvider<TcpStream>>;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "native-tls"))]
|
||||||
crate::opaque::implement_opaque_runtime! {
|
crate::opaque::implement_opaque_runtime! {
|
||||||
AsyncStdRuntime { inner : NativeTlsInner }
|
AsyncStdNativeTlsRuntime { inner : NativeTlsInner }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
|
@ -41,40 +60,80 @@ crate::opaque::implement_opaque_runtime! {
|
||||||
AsyncStdRustlsRuntime { inner: RustlsInner }
|
AsyncStdRustlsRuntime { inner: RustlsInner }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a new async-std-based [`Runtime`](crate::Runtime).
|
#[cfg(all(feature = "native-tls"))]
|
||||||
///
|
impl AsyncStdNativeTlsRuntime {
|
||||||
/// Generally you should call this function only once, and then use
|
/// Return a new [`AsyncStdNativeTlsRuntime`]
|
||||||
/// [`Clone::clone()`] to create additional references to that
|
///
|
||||||
/// runtime.
|
/// Generally you should call this function only once, and then use
|
||||||
pub fn create_runtime() -> std::io::Result<AsyncStdRuntime> {
|
/// [`Clone::clone()`] to create additional references to that
|
||||||
let rt = create_runtime_impl();
|
/// runtime.
|
||||||
Ok(AsyncStdRuntime {
|
pub fn create() -> IoResult<Self> {
|
||||||
inner: CompoundRuntime::new(rt, rt, rt, NativeTlsProvider::default()),
|
let rt = create_runtime_impl();
|
||||||
})
|
Ok(AsyncStdNativeTlsRuntime {
|
||||||
|
inner: CompoundRuntime::new(rt, rt, rt, NativeTlsProvider::default()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return an [`AsyncStdNativeTlsRuntime`] for the currently running
|
||||||
|
/// `async_std` executor.
|
||||||
|
///
|
||||||
|
/// Note that since async_std executors are global, there is no distinction
|
||||||
|
/// between this method and [`AsyncStdNativeTlsRuntime::create()`]: it is
|
||||||
|
/// provided only for API consistency with the Tokio runtimes.
|
||||||
|
pub fn current() -> IoResult<Self> {
|
||||||
|
Self::create()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper to run a single test function in a freshly created runtime.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if we can't create this runtime.
|
||||||
|
pub fn run_test<P, F, O>(func: P) -> O
|
||||||
|
where
|
||||||
|
P: FnOnce(Self) -> F,
|
||||||
|
F: futures::Future<Output = O>,
|
||||||
|
{
|
||||||
|
let runtime = Self::create().expect("Failed to create runtime");
|
||||||
|
runtime.clone().block_on(func(runtime))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a new [`Runtime`](crate::Runtime) based on `async_std` and `rustls`.
|
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
pub fn create_rustls_runtime() -> std::io::Result<AsyncStdRustlsRuntime> {
|
impl AsyncStdRustlsRuntime {
|
||||||
let rt = create_runtime_impl();
|
/// Return a new [`AsyncStdRustlsRuntime`]
|
||||||
Ok(AsyncStdRustlsRuntime {
|
///
|
||||||
inner: CompoundRuntime::new(rt, rt, rt, RustlsProvider::default()),
|
/// Generally you should call this function only once, and then use
|
||||||
})
|
/// [`Clone::clone()`] to create additional references to that
|
||||||
}
|
/// runtime.
|
||||||
|
pub fn create() -> IoResult<Self> {
|
||||||
|
let rt = create_runtime_impl();
|
||||||
|
Ok(AsyncStdRustlsRuntime {
|
||||||
|
inner: CompoundRuntime::new(rt, rt, rt, RustlsProvider::default()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Try to return an instance of the currently running async_std
|
/// Return an [`AsyncStdRustlsRuntime`] for the currently running
|
||||||
/// [`Runtime`](crate::Runtime).
|
/// `async_std` executor.
|
||||||
pub fn current_runtime() -> std::io::Result<AsyncStdRuntime> {
|
///
|
||||||
// In async_std, the runtime is a global singleton.
|
/// Note that since async_std executors are global, there is no distinction
|
||||||
create_runtime()
|
/// between this method and [`AsyncStdNativeTlsRuntime::create()`]: it is
|
||||||
}
|
/// provided only for API consistency with the Tokio runtimes.
|
||||||
|
pub fn current() -> IoResult<Self> {
|
||||||
|
Self::create()
|
||||||
|
}
|
||||||
|
|
||||||
/// Run a test function using a freshly created async_std runtime.
|
/// Helper to run a single test function in a freshly created runtime.
|
||||||
pub fn test_with_runtime<P, F, O>(func: P) -> O
|
///
|
||||||
where
|
/// # Panics
|
||||||
P: FnOnce(AsyncStdRuntime) -> F,
|
///
|
||||||
F: futures::Future<Output = O>,
|
/// Panics if we can't create this runtime.
|
||||||
{
|
pub fn run_test<P, F, O>(func: P) -> O
|
||||||
let runtime = current_runtime().expect("Couldn't get global async_std runtime?");
|
where
|
||||||
runtime.clone().block_on(func(runtime))
|
P: FnOnce(Self) -> F,
|
||||||
|
F: futures::Future<Output = O>,
|
||||||
|
{
|
||||||
|
let runtime = Self::create().expect("Failed to create runtime");
|
||||||
|
runtime.clone().block_on(func(runtime))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use std::io::Result as IoResult;
|
||||||
|
|
||||||
/// A runtime made of several parts, each of which implements one trait-group.
|
/// A runtime made of several parts, each of which implements one trait-group.
|
||||||
///
|
///
|
||||||
/// The `SpawnR` component should implements [`Spawn`] and [`SpawnBlocking`];
|
/// The `SpawnR` component should implements [`Spawn`] and [`BlockOn`];
|
||||||
/// the `SleepR` component should implement [`SleepProvider`]; the `TcpR`
|
/// the `SleepR` component should implement [`SleepProvider`]; the `TcpR`
|
||||||
/// component should implement [`TcpProvider`]; and the `TlsR` component should
|
/// component should implement [`TcpProvider`]; and the `TlsR` component should
|
||||||
/// implement [`TlsProvider`].
|
/// implement [`TlsProvider`].
|
||||||
|
@ -18,7 +18,6 @@ use std::io::Result as IoResult;
|
||||||
/// You can use this structure to create new runtimes in two ways: either by
|
/// You can use this structure to create new runtimes in two ways: either by
|
||||||
/// overriding a single part of an existing runtime, or by building an entirely
|
/// overriding a single part of an existing runtime, or by building an entirely
|
||||||
/// new runtime from pieces.
|
/// new runtime from pieces.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct CompoundRuntime<SpawnR, SleepR, TcpR, TlsR> {
|
pub struct CompoundRuntime<SpawnR, SleepR, TcpR, TlsR> {
|
||||||
/// The actual collection of Runtime objects.
|
/// The actual collection of Runtime objects.
|
||||||
///
|
///
|
||||||
|
@ -27,9 +26,19 @@ pub struct CompoundRuntime<SpawnR, SleepR, TcpR, TlsR> {
|
||||||
inner: Arc<Inner<SpawnR, SleepR, TcpR, TlsR>>,
|
inner: Arc<Inner<SpawnR, SleepR, TcpR, TlsR>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have to provide this ourselves, since derive(Clone) wrongly infers a
|
||||||
|
// `where S: Clone` bound (from the generic argument).
|
||||||
|
impl<SpawnR, SleepR, TcpR, TlsR> Clone for CompoundRuntime<SpawnR, SleepR, TcpR, TlsR> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Arc::clone(&self.inner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A collection of objects implementing that traits that make up a [`Runtime`]
|
/// A collection of objects implementing that traits that make up a [`Runtime`]
|
||||||
struct Inner<SpawnR, SleepR, TcpR, TlsR> {
|
struct Inner<SpawnR, SleepR, TcpR, TlsR> {
|
||||||
/// A `Spawn` and `SpawnBlocking` implementation.
|
/// A `Spawn` and `BlockOn` implementation.
|
||||||
spawn: SpawnR,
|
spawn: SpawnR,
|
||||||
/// A `SleepProvider` implementation.
|
/// A `SleepProvider` implementation.
|
||||||
sleep: SleepR,
|
sleep: SleepR,
|
||||||
|
@ -63,9 +72,9 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SpawnR, SleepR, TcpR, TlsR> SpawnBlocking for CompoundRuntime<SpawnR, SleepR, TcpR, TlsR>
|
impl<SpawnR, SleepR, TcpR, TlsR> BlockOn for CompoundRuntime<SpawnR, SleepR, TcpR, TlsR>
|
||||||
where
|
where
|
||||||
SpawnR: SpawnBlocking,
|
SpawnR: BlockOn,
|
||||||
{
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn block_on<F: futures::Future>(&self, future: F) -> F::Output {
|
fn block_on<F: futures::Future>(&self, future: F) -> F::Output {
|
||||||
|
|
|
@ -11,4 +11,5 @@ pub(crate) mod tokio;
|
||||||
#[cfg(all(feature = "rustls"))]
|
#[cfg(all(feature = "rustls"))]
|
||||||
pub(crate) mod rustls;
|
pub(crate) mod rustls;
|
||||||
|
|
||||||
|
#[cfg(all(feature = "native-tls"))]
|
||||||
pub(crate) mod native_tls;
|
pub(crate) mod native_tls;
|
||||||
|
|
|
@ -131,7 +131,7 @@ impl SleepProvider for async_executors::AsyncStd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpawnBlocking for async_executors::AsyncStd {
|
impl BlockOn for async_executors::AsyncStd {
|
||||||
fn block_on<F: Future>(&self, f: F) -> F::Output {
|
fn block_on<F: Future>(&self, f: F) -> F::Output {
|
||||||
async_executors::AsyncStd::block_on(f)
|
async_executors::AsyncStd::block_on(f)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::traits::{CertifiedConn, TlsConnector, TlsProvider};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::{AsyncRead, AsyncWrite};
|
use futures::{AsyncRead, AsyncWrite};
|
||||||
|
use native_tls_crate as native_tls;
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryInto,
|
convert::TryInto,
|
||||||
io::{Error as IoError, Result as IoResult},
|
io::{Error as IoError, Result as IoResult},
|
||||||
|
@ -103,13 +104,3 @@ impl<S> Default for NativeTlsProvider<S> {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to provide this ourselves, since derive(Clone) wrongly infers a
|
|
||||||
// `where S: Clone` bound (from the generic argument).
|
|
||||||
impl<S> Clone for NativeTlsProvider<S> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
_phantom: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -100,28 +100,6 @@ impl<S> Default for RustlsProvider<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to provide this ourselves, since derive(Clone) wrongly infers a
|
|
||||||
// `where S: Clone` bound (from the generic argument).
|
|
||||||
impl<S> Clone for RustlsProvider<S> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
config: Arc::clone(&self.config),
|
|
||||||
_phantom: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have to provide this ourselves, since derive(Clone) wrongly infers a
|
|
||||||
// `where S: Clone` bound (from the generic argument).
|
|
||||||
impl<S> Clone for RustlsConnector<S> {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
connector: self.connector.clone(),
|
|
||||||
_phantom: std::marker::PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [`rustls::ServerCertVerifier`] based on the [`x509_signature`] crate.
|
/// A [`rustls::ServerCertVerifier`] based on the [`x509_signature`] crate.
|
||||||
///
|
///
|
||||||
/// This verifier is necessary since Tor relays doesn't participate in the web
|
/// This verifier is necessary since Tor relays doesn't participate in the web
|
||||||
|
|
|
@ -124,40 +124,34 @@ use futures::Future;
|
||||||
use std::io::Result as IoResult;
|
use std::io::Result as IoResult;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
/// Helper: Declare that a given tokio runtime object implements the
|
impl SleepProvider for TokioRuntimeHandle {
|
||||||
/// prerequisites for Runtime.
|
type SleepFuture = tokio_crate::time::Sleep;
|
||||||
// TODO: Maybe we can do this more simply with a simpler trait?
|
fn sleep(&self, duration: Duration) -> Self::SleepFuture {
|
||||||
macro_rules! implement_traits_for {
|
tokio_crate::time::sleep(duration)
|
||||||
($runtime:ty) => {
|
}
|
||||||
impl SleepProvider for $runtime {
|
}
|
||||||
type SleepFuture = tokio_crate::time::Sleep;
|
|
||||||
fn sleep(&self, duration: Duration) -> Self::SleepFuture {
|
|
||||||
tokio_crate::time::sleep(duration)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl crate::traits::TcpProvider for $runtime {
|
impl crate::traits::TcpProvider for TokioRuntimeHandle {
|
||||||
type TcpStream = net::TcpStream;
|
type TcpStream = net::TcpStream;
|
||||||
type TcpListener = net::TcpListener;
|
type TcpListener = net::TcpListener;
|
||||||
|
|
||||||
async fn connect(&self, addr: &std::net::SocketAddr) -> IoResult<Self::TcpStream> {
|
async fn connect(&self, addr: &std::net::SocketAddr) -> IoResult<Self::TcpStream> {
|
||||||
let s = net::TokioTcpStream::connect(addr).await?;
|
let s = net::TokioTcpStream::connect(addr).await?;
|
||||||
Ok(s.into())
|
Ok(s.into())
|
||||||
}
|
}
|
||||||
async fn listen(&self, addr: &std::net::SocketAddr) -> IoResult<Self::TcpListener> {
|
async fn listen(&self, addr: &std::net::SocketAddr) -> IoResult<Self::TcpListener> {
|
||||||
let lis = net::TokioTcpListener::bind(*addr).await?;
|
let lis = net::TokioTcpListener::bind(*addr).await?;
|
||||||
Ok(net::TcpListener { lis })
|
Ok(net::TcpListener { lis })
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create and return a new Tokio multithreaded runtime.
|
/// Create and return a new Tokio multithreaded runtime.
|
||||||
pub(crate) fn create_runtime() -> IoResult<async_executors::TokioTp> {
|
pub(crate) fn create_runtime() -> IoResult<TokioRuntimeHandle> {
|
||||||
let mut builder = async_executors::TokioTpBuilder::new();
|
let mut builder = async_executors::TokioTpBuilder::new();
|
||||||
builder.tokio_builder().enable_all();
|
builder.tokio_builder().enable_all();
|
||||||
builder.build()
|
let owned = builder.build()?;
|
||||||
|
Ok(owned.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper around a Handle to a tokio runtime.
|
/// Wrapper around a Handle to a tokio runtime.
|
||||||
|
@ -174,6 +168,12 @@ pub(crate) fn create_runtime() -> IoResult<async_executors::TokioTp> {
|
||||||
/// that when creating this object.
|
/// that when creating this object.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TokioRuntimeHandle {
|
pub struct TokioRuntimeHandle {
|
||||||
|
/// If present, the tokio executor that we've created (and which we own).
|
||||||
|
///
|
||||||
|
/// We never access this directly; only through `handle`. We keep it here
|
||||||
|
/// so that our Runtime types can be agnostic about whether they own the
|
||||||
|
/// executor.
|
||||||
|
owned: Option<async_executors::TokioTp>,
|
||||||
/// The underlying Handle.
|
/// The underlying Handle.
|
||||||
handle: tokio_crate::runtime::Handle,
|
handle: tokio_crate::runtime::Handle,
|
||||||
}
|
}
|
||||||
|
@ -189,21 +189,33 @@ impl TokioRuntimeHandle {
|
||||||
pub(crate) fn new(handle: tokio_crate::runtime::Handle) -> Self {
|
pub(crate) fn new(handle: tokio_crate::runtime::Handle) -> Self {
|
||||||
handle.into()
|
handle.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return true if this handle owns the executor that it points to.
|
||||||
|
pub fn is_owned(&self) -> bool {
|
||||||
|
self.owned.is_some()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<tokio_crate::runtime::Handle> for TokioRuntimeHandle {
|
impl From<tokio_crate::runtime::Handle> for TokioRuntimeHandle {
|
||||||
fn from(handle: tokio_crate::runtime::Handle) -> Self {
|
fn from(handle: tokio_crate::runtime::Handle) -> Self {
|
||||||
Self { handle }
|
Self {
|
||||||
|
owned: None,
|
||||||
|
handle,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpawnBlocking for async_executors::TokioTp {
|
impl From<async_executors::TokioTp> for TokioRuntimeHandle {
|
||||||
fn block_on<F: Future>(&self, f: F) -> F::Output {
|
fn from(owner: async_executors::TokioTp) -> TokioRuntimeHandle {
|
||||||
async_executors::TokioTp::block_on(self, f)
|
let handle = owner.block_on(async { tokio_crate::runtime::Handle::current() });
|
||||||
|
Self {
|
||||||
|
owned: Some(owner),
|
||||||
|
handle,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpawnBlocking for TokioRuntimeHandle {
|
impl BlockOn for TokioRuntimeHandle {
|
||||||
fn block_on<F: Future>(&self, f: F) -> F::Output {
|
fn block_on<F: Future>(&self, f: F) -> F::Output {
|
||||||
self.handle.block_on(f)
|
self.handle.block_on(f)
|
||||||
}
|
}
|
||||||
|
@ -219,6 +231,3 @@ impl futures::task::Spawn for TokioRuntimeHandle {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
implement_traits_for! {async_executors::TokioTp}
|
|
||||||
implement_traits_for! {TokioRuntimeHandle}
|
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
//! The `tor-rtcompat` crate provides several traits that
|
//! The `tor-rtcompat` crate provides several traits that
|
||||||
//! encapsulate different runtime capabilities.
|
//! encapsulate different runtime capabilities.
|
||||||
//!
|
//!
|
||||||
//! * A runtime is a [`SpawnBlocking`] if it can block on a future.
|
//! * A runtime is a [`BlockOn`] if it can block on a future.
|
||||||
//! * A runtime is a [`SleepProvider`] if it can make timer futures that
|
//! * A runtime is a [`SleepProvider`] if it can make timer futures that
|
||||||
//! become Ready after a given interval of time.
|
//! become Ready after a given interval of time.
|
||||||
//! * A runtime is a [`TcpProvider`] if it can make and receive TCP
|
//! * A runtime is a [`TcpProvider`] if it can make and receive TCP
|
||||||
|
@ -60,11 +60,13 @@
|
||||||
//! * If you want to construct a default runtime that you won't be
|
//! * If you want to construct a default runtime that you won't be
|
||||||
//! using for anything besides Arti, you can use [`create_runtime()`].
|
//! using for anything besides Arti, you can use [`create_runtime()`].
|
||||||
//!
|
//!
|
||||||
//! * If you want to explicitly construct a runtime with a specific
|
//! * If you want to use a runtime with an explicitly chosen backend,
|
||||||
//! backend, you can do so with [`async_std::create_runtime`] or
|
//! name its type directly as [`async_std::AsyncStdNativeTlsRuntime`],
|
||||||
//! [`tokio::create_runtime`]. Or if you have already constructed a
|
//! [`async_std::AsyncStdRustlsRuntime`], [`tokio::TokioNativeTlsRuntime`],
|
||||||
|
//! or [`tokio::TokioRustlsRuntime`]. To construct one of these runtimes,
|
||||||
|
//! call its `create()` method. Or if you have already constructed a
|
||||||
//! tokio runtime that you want to use, you can wrap it as a
|
//! tokio runtime that you want to use, you can wrap it as a
|
||||||
//! [`Runtime`] explicitly with [`tokio::TokioRuntimeHandle`].
|
//! [`Runtime`] explicitly with `current()`.
|
||||||
//!
|
//!
|
||||||
//! # Cargo features
|
//! # Cargo features
|
||||||
//!
|
//!
|
||||||
|
@ -92,7 +94,7 @@
|
||||||
//! We could simplify this code significantly by removing most of the
|
//! We could simplify this code significantly by removing most of the
|
||||||
//! traits it exposes, and instead just exposing a single
|
//! traits it exposes, and instead just exposing a single
|
||||||
//! implementation. For example, instead of exposing a
|
//! implementation. For example, instead of exposing a
|
||||||
//! [`SpawnBlocking`] trait to represent blocking until a task is
|
//! [`BlockOn`] trait to represent blocking until a task is
|
||||||
//! done, we could just provide a single global `block_on` function.
|
//! done, we could just provide a single global `block_on` function.
|
||||||
//!
|
//!
|
||||||
//! That simplification would come at a cost, however. First of all,
|
//! That simplification would come at a cost, however. First of all,
|
||||||
|
@ -140,6 +142,10 @@
|
||||||
#![warn(clippy::unseparated_literal_suffix)]
|
#![warn(clippy::unseparated_literal_suffix)]
|
||||||
#![deny(clippy::unwrap_used)]
|
#![deny(clippy::unwrap_used)]
|
||||||
|
|
||||||
|
#[cfg(all(
|
||||||
|
any(feature = "native-tls", feature = "rustls"),
|
||||||
|
any(feature = "async-std", feature = "tokio")
|
||||||
|
))]
|
||||||
pub(crate) mod impls;
|
pub(crate) mod impls;
|
||||||
pub mod task;
|
pub mod task;
|
||||||
|
|
||||||
|
@ -148,11 +154,15 @@ mod opaque;
|
||||||
mod timer;
|
mod timer;
|
||||||
mod traits;
|
mod traits;
|
||||||
|
|
||||||
#[cfg(all(test, any(feature = "tokio", feature = "async-std")))]
|
#[cfg(all(
|
||||||
|
test,
|
||||||
|
any(feature = "native-tls", feature = "rustls"),
|
||||||
|
any(feature = "async-std", feature = "tokio")
|
||||||
|
))]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
pub use traits::{
|
pub use traits::{
|
||||||
CertifiedConn, Runtime, SleepProvider, SpawnBlocking, TcpListener, TcpProvider, TlsProvider,
|
BlockOn, CertifiedConn, Runtime, SleepProvider, TcpListener, TcpProvider, TlsProvider,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use timer::{SleepProviderExt, Timeout, TimeoutError};
|
pub use timer::{SleepProviderExt, Timeout, TimeoutError};
|
||||||
|
@ -163,14 +173,36 @@ pub mod tls {
|
||||||
pub use crate::traits::{CertifiedConn, TlsConnector};
|
pub use crate::traits::{CertifiedConn, TlsConnector};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tokio")]
|
#[cfg(all(any(feature = "native-tls", feature = "rustls"), feature = "tokio"))]
|
||||||
pub mod tokio;
|
pub mod tokio;
|
||||||
|
|
||||||
#[cfg(feature = "async-std")]
|
#[cfg(all(any(feature = "native-tls", feature = "rustls"), feature = "async-std"))]
|
||||||
pub mod async_std;
|
pub mod async_std;
|
||||||
|
|
||||||
pub use compound::CompoundRuntime;
|
pub use compound::CompoundRuntime;
|
||||||
|
|
||||||
|
#[cfg(all(
|
||||||
|
any(feature = "native-tls", feature = "rustls"),
|
||||||
|
feature = "async-std",
|
||||||
|
not(feature = "tokio")
|
||||||
|
))]
|
||||||
|
use async_std as preferred_backend_mod;
|
||||||
|
#[cfg(all(any(feature = "native-tls", feature = "rustls"), feature = "tokio"))]
|
||||||
|
use tokio as preferred_backend_mod;
|
||||||
|
|
||||||
|
/// The runtime that we prefer to use, out of all the runtimes compiled into the
|
||||||
|
/// tor-rtcompat crate.
|
||||||
|
///
|
||||||
|
/// If `tokio` and `async-std` are both available, we prefer `tokio` for its
|
||||||
|
/// performance.
|
||||||
|
/// If `native_tls` and `rustls` are both available, we prefer `native_tls` since
|
||||||
|
/// it has been used in Arti for longer.
|
||||||
|
#[cfg(all(
|
||||||
|
any(feature = "native-tls", feature = "rustls"),
|
||||||
|
any(feature = "async-std", feature = "tokio")
|
||||||
|
))]
|
||||||
|
pub use preferred_backend_mod::PreferredRuntime;
|
||||||
|
|
||||||
/// Try to return an instance of the currently running [`Runtime`].
|
/// Try to return an instance of the currently running [`Runtime`].
|
||||||
///
|
///
|
||||||
/// # Limitations
|
/// # Limitations
|
||||||
|
@ -188,47 +220,50 @@ pub use compound::CompoundRuntime;
|
||||||
///
|
///
|
||||||
/// Once you have a runtime returned by this function, you should
|
/// Once you have a runtime returned by this function, you should
|
||||||
/// just create more handles to it via [`Clone`].
|
/// just create more handles to it via [`Clone`].
|
||||||
#[cfg(any(feature = "async-std", feature = "tokio"))]
|
///
|
||||||
|
/// This function returns a type-erased `impl Runtime` rather than a specific
|
||||||
|
/// runtime implementation, so that you can be sure that your code doesn't
|
||||||
|
/// depend on any runtime-specific features. If that's not what you want, you
|
||||||
|
/// can call [`PreferredRuntime::current`], or the `create` function on some
|
||||||
|
/// specific runtime in the `tokio` or `async_std` modules.
|
||||||
|
#[cfg(all(
|
||||||
|
any(feature = "native-tls", feature = "rustls"),
|
||||||
|
any(feature = "async-std", feature = "tokio")
|
||||||
|
))]
|
||||||
pub fn current_user_runtime() -> std::io::Result<impl Runtime> {
|
pub fn current_user_runtime() -> std::io::Result<impl Runtime> {
|
||||||
#[cfg(feature = "tokio")]
|
PreferredRuntime::current()
|
||||||
{
|
|
||||||
crate::tokio::current_runtime()
|
|
||||||
}
|
|
||||||
#[cfg(all(feature = "async-std", not(feature = "tokio")))]
|
|
||||||
{
|
|
||||||
crate::async_std::current_runtime()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a new instance of the default [`Runtime`].
|
/// Return a new instance of the default [`Runtime`].
|
||||||
///
|
///
|
||||||
/// Generally you should call this function at most once, and then use
|
/// Generally you should call this function at most once, and then use
|
||||||
/// [`Clone::clone()`] to create additional references to that
|
/// [`Clone::clone()`] to create additional references to that runtime.
|
||||||
/// runtime.
|
|
||||||
///
|
///
|
||||||
/// Tokio users may want to avoid this function and instead make a
|
/// Tokio users may want to avoid this function and instead make a runtime using
|
||||||
/// runtime using [`current_user_runtime()`] or
|
/// [`current_user_runtime()`] or [`tokio::PreferredRuntime::current()`]: this
|
||||||
/// [`tokio::current_runtime()`]: this function always _builds_ a
|
/// function always _builds_ a runtime, and if you already have a runtime, that
|
||||||
/// runtime, and if you already have a runtime, that isn't what you
|
/// isn't what you want with Tokio.
|
||||||
/// want with Tokio.
|
|
||||||
///
|
///
|
||||||
/// If you need more fine-grained control over a runtime, you can
|
/// If you need more fine-grained control over a runtime, you can create it
|
||||||
/// create it using an appropriate builder type or function.
|
/// using an appropriate builder type or function.
|
||||||
#[cfg(any(feature = "async-std", feature = "tokio"))]
|
///
|
||||||
|
/// This function returns a type-erased `impl Runtime` rather than a specific
|
||||||
|
/// runtime implementation, so that you can be sure that your code doesn't
|
||||||
|
/// depend on any runtime-specific features. If that's not what you want, you
|
||||||
|
/// can call [`PreferredRuntime::create`], or the `create` function on some
|
||||||
|
/// specific runtime in the `tokio` or `async_std` modules.
|
||||||
|
#[cfg(all(
|
||||||
|
any(feature = "native-tls", feature = "rustls"),
|
||||||
|
any(feature = "async-std", feature = "tokio")
|
||||||
|
))]
|
||||||
pub fn create_runtime() -> std::io::Result<impl Runtime> {
|
pub fn create_runtime() -> std::io::Result<impl Runtime> {
|
||||||
#[cfg(feature = "tokio")]
|
PreferredRuntime::create()
|
||||||
{
|
|
||||||
crate::tokio::create_runtime()
|
|
||||||
}
|
|
||||||
#[cfg(all(feature = "async-std", not(feature = "tokio")))]
|
|
||||||
{
|
|
||||||
crate::async_std::create_runtime()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helpers for test_with_all_runtimes
|
/// Helpers for test_with_all_runtimes
|
||||||
pub mod testing__ {
|
pub mod testing__ {
|
||||||
/// A trait for an object that might represent a test failure.
|
/// A trait for an object that might represent a test failure, or which
|
||||||
|
/// might just be `()`.
|
||||||
pub trait TestOutcome {
|
pub trait TestOutcome {
|
||||||
/// Abort if the test has failed.
|
/// Abort if the test has failed.
|
||||||
fn check_ok(&self);
|
fn check_ok(&self);
|
||||||
|
@ -236,42 +271,88 @@ pub mod testing__ {
|
||||||
impl TestOutcome for () {
|
impl TestOutcome for () {
|
||||||
fn check_ok(&self) {}
|
fn check_ok(&self) {}
|
||||||
}
|
}
|
||||||
impl<T, E> TestOutcome for Result<T, E> {
|
impl<E: std::fmt::Debug> TestOutcome for Result<(), E> {
|
||||||
fn check_ok(&self) {
|
fn check_ok(&self) {
|
||||||
assert!(self.is_ok());
|
self.as_ref().expect("Test failure");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper: define a macro that expands a token tree iff a pair of features are
|
||||||
|
/// both present.
|
||||||
|
macro_rules! declare_conditional_macro {
|
||||||
|
( $(#[$meta:meta])* macro $name:ident = ($f1:expr, $f2:expr) ) => {
|
||||||
|
$( #[$meta] )*
|
||||||
|
#[cfg(all(feature=$f1, feature=$f2))]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! $name {
|
||||||
|
($tt:tt) => {
|
||||||
|
$tt
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
$( #[$meta] )*
|
||||||
|
#[cfg(not(all(feature=$f1, feature=$f2)))]
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! $name {
|
||||||
|
($tt:tt) => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Needed so that we can access this macro at this path, both within the
|
||||||
|
// crate and without.
|
||||||
|
pub use $name;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Defines macros that will expand when certain runtimes are available.
|
||||||
|
pub mod cond {
|
||||||
|
declare_conditional_macro! {
|
||||||
|
/// Expand a token tree if the TokioNativeTlsRuntime is available.
|
||||||
|
macro if_tokio_native_tls_present = ("tokio", "native-tls")
|
||||||
|
}
|
||||||
|
declare_conditional_macro! {
|
||||||
|
/// Expand a token tree if the TokioRustlsRuntime is available.
|
||||||
|
macro if_tokio_rustls_present = ("tokio", "rustls")
|
||||||
|
}
|
||||||
|
declare_conditional_macro! {
|
||||||
|
/// Expand a token tree if the TokioNativeTlsRuntime is available.
|
||||||
|
macro if_async_std_native_tls_present = ("async-std", "native-tls")
|
||||||
|
}
|
||||||
|
declare_conditional_macro! {
|
||||||
|
/// Expand a token tree if the TokioNativeTlsRuntime is available.
|
||||||
|
macro if_async_std_rustls_present = ("async-std", "rustls")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Run a test closure, passing as argument every supported runtime.
|
/// Run a test closure, passing as argument every supported runtime.
|
||||||
///
|
///
|
||||||
/// (This is a macro so that it can repeat the closure as two separate
|
/// (This is a macro so that it can repeat the closure as multiple separate
|
||||||
/// expressions, so it can take on two different types, if needed.)
|
/// expressions, so it can take on two different types, if needed.)
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[cfg(all(feature = "tokio", feature = "async-std"))]
|
#[cfg(all(
|
||||||
|
any(feature = "native-tls", feature = "rustls"),
|
||||||
|
any(feature = "tokio", feature = "async-std"),
|
||||||
|
))]
|
||||||
macro_rules! test_with_all_runtimes {
|
macro_rules! test_with_all_runtimes {
|
||||||
( $fn:expr ) => {{
|
( $fn:expr ) => {{
|
||||||
|
use $crate::cond::*;
|
||||||
use $crate::testing__::TestOutcome;
|
use $crate::testing__::TestOutcome;
|
||||||
$crate::tokio::test_with_runtime($fn).check_ok();
|
// We have to do this outcome-checking business rather than just using
|
||||||
$crate::async_std::test_with_runtime($fn)
|
// the ? operator or calling expect() because some of the closures that
|
||||||
}};
|
// we use this macro with return (), and some return Result.
|
||||||
}
|
|
||||||
|
|
||||||
/// Run a test closure, passing as argument every supported runtime.
|
if_tokio_native_tls_present! {{
|
||||||
#[macro_export]
|
$crate::tokio::TokioNativeTlsRuntime::run_test($fn).check_ok();
|
||||||
#[cfg(all(feature = "tokio", not(feature = "async-std")))]
|
}}
|
||||||
macro_rules! test_with_all_runtimes {
|
if_tokio_rustls_present! {{
|
||||||
( $fn:expr ) => {{
|
$crate::tokio::TokioRustlsRuntime::run_test($fn).check_ok();
|
||||||
$crate::tokio::test_with_runtime($fn)
|
}}
|
||||||
}};
|
if_async_std_native_tls_present! {{
|
||||||
}
|
$crate::async_std::AsyncStdNativeTlsRuntime::run_test($fn).check_ok();
|
||||||
|
}}
|
||||||
/// Run a test closure, passing as argument every supported runtime.
|
if_async_std_rustls_present! {{
|
||||||
#[macro_export]
|
$crate::async_std::AsyncStdRustlsRuntime::run_test($fn).check_ok();
|
||||||
#[cfg(all(not(feature = "tokio"), feature = "async-std"))]
|
}}
|
||||||
macro_rules! test_with_all_runtimes {
|
|
||||||
( $fn:expr ) => {{
|
|
||||||
$crate::async_std::test_with_runtime($fn)
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,20 +360,12 @@ macro_rules! test_with_all_runtimes {
|
||||||
///
|
///
|
||||||
/// (Always prefers tokio if present.)
|
/// (Always prefers tokio if present.)
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
#[cfg(feature = "tokio")]
|
#[cfg(all(
|
||||||
|
any(feature = "native-tls", feature = "rustls"),
|
||||||
|
any(feature = "tokio", feature = "async-std"),
|
||||||
|
))]
|
||||||
macro_rules! test_with_one_runtime {
|
macro_rules! test_with_one_runtime {
|
||||||
( $fn:expr ) => {{
|
( $fn:expr ) => {{
|
||||||
$crate::tokio::test_with_runtime($fn)
|
$crate::PreferredRuntime::run_test($fn)
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run a test closure, passing as argument one supported runtime.
|
|
||||||
///
|
|
||||||
/// (Always prefers tokio if present.)
|
|
||||||
#[macro_export]
|
|
||||||
#[cfg(all(not(feature = "tokio"), feature = "async-std"))]
|
|
||||||
macro_rules! test_with_one_runtime {
|
|
||||||
( $fn:expr ) => {{
|
|
||||||
$crate::async_std::test_with_runtime($fn)
|
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ macro_rules! implement_opaque_runtime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $crate::traits::SpawnBlocking for $t {
|
impl $crate::traits::BlockOn for $t {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn block_on<F: futures::Future>(&self, future: F) -> F::Output {
|
fn block_on<F: futures::Future>(&self, future: F) -> F::Output {
|
||||||
self.$member.block_on(future)
|
self.$member.block_on(future)
|
||||||
|
|
|
@ -38,7 +38,11 @@ impl Future for YieldFuture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(test, any(feature = "tokio", feature = "async-std")))]
|
#[cfg(all(
|
||||||
|
test,
|
||||||
|
any(feature = "native-tls", feature = "rustls"),
|
||||||
|
any(feature = "tokio", feature = "async-std")
|
||||||
|
))]
|
||||||
mod test {
|
mod test {
|
||||||
use super::yield_now;
|
use super::yield_now;
|
||||||
use crate::test_with_all_runtimes;
|
use crate::test_with_all_runtimes;
|
||||||
|
@ -46,7 +50,7 @@ mod test {
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_yield() -> std::io::Result<()> {
|
fn test_yield() {
|
||||||
test_with_all_runtimes!(|_| async {
|
test_with_all_runtimes!(|_| async {
|
||||||
let b = AtomicBool::new(false);
|
let b = AtomicBool::new(false);
|
||||||
use Ordering::SeqCst;
|
use Ordering::SeqCst;
|
||||||
|
@ -77,7 +81,6 @@ mod test {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
std::io::Result::Ok(())
|
std::io::Result::Ok(())
|
||||||
})?;
|
});
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::traits::*;
|
||||||
|
|
||||||
use futures::io::{AsyncReadExt, AsyncWriteExt};
|
use futures::io::{AsyncReadExt, AsyncWriteExt};
|
||||||
use futures::stream::StreamExt;
|
use futures::stream::StreamExt;
|
||||||
|
use native_tls_crate as native_tls;
|
||||||
use std::io::Result as IoResult;
|
use std::io::Result as IoResult;
|
||||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||||
use std::time::{Duration, Instant, SystemTime};
|
use std::time::{Duration, Instant, SystemTime};
|
||||||
|
@ -225,7 +226,7 @@ macro_rules! runtime_tests {
|
||||||
$(
|
$(
|
||||||
#[test]
|
#[test]
|
||||||
fn $id() -> IoResult<()> {
|
fn $id() -> IoResult<()> {
|
||||||
super::$id(&crate::tokio::create_runtime()?)
|
super::$id(&crate::tokio::PreferredRuntime::create()?)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
@ -235,7 +236,7 @@ macro_rules! runtime_tests {
|
||||||
$(
|
$(
|
||||||
#[test]
|
#[test]
|
||||||
fn $id() -> IoResult<()> {
|
fn $id() -> IoResult<()> {
|
||||||
super::$id(&crate::async_std::create_runtime()?)
|
super::$id(&crate::async_std::PreferredRuntime::create()?)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
@ -244,44 +245,44 @@ macro_rules! runtime_tests {
|
||||||
|
|
||||||
macro_rules! tls_runtime_tests {
|
macro_rules! tls_runtime_tests {
|
||||||
{ $($id:ident),* $(,)? } => {
|
{ $($id:ident),* $(,)? } => {
|
||||||
#[cfg(feature="tokio")]
|
#[cfg(all(feature="tokio", feature = "native-tls"))]
|
||||||
mod tokio_native_tls_tests {
|
mod tokio_native_tls_tests {
|
||||||
use std::io::Result as IoResult;
|
use std::io::Result as IoResult;
|
||||||
$(
|
$(
|
||||||
#[test]
|
#[test]
|
||||||
fn $id() -> IoResult<()> {
|
fn $id() -> IoResult<()> {
|
||||||
super::$id(&crate::tokio::create_runtime()?)
|
super::$id(&crate::tokio::TokioNativeTlsRuntime::create()?)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
#[cfg(feature="async-std")]
|
#[cfg(all(feature="async-std", feature = "native-tls"))]
|
||||||
mod async_std_native_tls_tests {
|
mod async_std_native_tls_tests {
|
||||||
use std::io::Result as IoResult;
|
use std::io::Result as IoResult;
|
||||||
$(
|
$(
|
||||||
#[test]
|
#[test]
|
||||||
fn $id() -> IoResult<()> {
|
fn $id() -> IoResult<()> {
|
||||||
super::$id(&crate::async_std::create_runtime()?)
|
super::$id(&crate::async_std::AsyncStdNativeTlsRuntime::create()?)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature="tokio", feature="rustls"))]
|
#[cfg(all(feature="tokio", feature="rustls"))]
|
||||||
mod tokio_rusttls_tests {
|
mod tokio_rustls_tests {
|
||||||
use std::io::Result as IoResult;
|
use std::io::Result as IoResult;
|
||||||
$(
|
$(
|
||||||
#[test]
|
#[test]
|
||||||
fn $id() -> IoResult<()> {
|
fn $id() -> IoResult<()> {
|
||||||
super::$id(&crate::tokio::create_rustls_runtime()?)
|
super::$id(&crate::tokio::TokioRustlsRuntime::create()?)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
#[cfg(all(feature="async-std", feature="rustls"))]
|
#[cfg(all(feature="async-std", feature="rustls"))]
|
||||||
mod async_std_rusttls_tests {
|
mod async_std_rustls_tests {
|
||||||
use std::io::Result as IoResult;
|
use std::io::Result as IoResult;
|
||||||
$(
|
$(
|
||||||
#[test]
|
#[test]
|
||||||
fn $id() -> IoResult<()> {
|
fn $id() -> IoResult<()> {
|
||||||
super::$id(&crate::async_std::create_rustls_runtime()?)
|
super::$id(&crate::async_std::AsyncStdRustlsRuntime::create()?)
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,30 @@
|
||||||
//! Entry points for use with Tokio runtimes.
|
//! Entry points for use with Tokio runtimes.
|
||||||
use crate::impls::native_tls::NativeTlsProvider;
|
|
||||||
use crate::impls::tokio::TokioRuntimeHandle as Handle;
|
use crate::impls::tokio::TokioRuntimeHandle as Handle;
|
||||||
use async_executors::TokioTp;
|
|
||||||
|
|
||||||
use crate::{CompoundRuntime, Runtime, SpawnBlocking};
|
use crate::{BlockOn, CompoundRuntime};
|
||||||
use std::io::{Error as IoError, ErrorKind, Result as IoResult};
|
use std::io::{Error as IoError, ErrorKind, Result as IoResult};
|
||||||
|
|
||||||
|
#[cfg(feature = "native-tls")]
|
||||||
|
use crate::impls::native_tls::NativeTlsProvider;
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
use crate::impls::rustls::RustlsProvider;
|
use crate::impls::rustls::RustlsProvider;
|
||||||
use crate::impls::tokio::net::TcpStream;
|
use crate::impls::tokio::net::TcpStream;
|
||||||
|
|
||||||
/// A [`Runtime`] built around a Handle to a tokio runtime, and `native_tls`.
|
/// An alias for the Tokio runtime that we prefer to use, based on whatever TLS
|
||||||
|
/// implementation has been enabled.
|
||||||
|
///
|
||||||
|
/// If only one of `native_tls` and `rustls` bas been enabled within the
|
||||||
|
/// `tor-rtcompat` crate, that will be the TLS backend that this uses.
|
||||||
|
///
|
||||||
|
/// Currently, `native_tls` is preferred over `rustls` when both are available,
|
||||||
|
/// because of its maturity within Arti. However, this might change in the
|
||||||
|
/// future.
|
||||||
|
#[cfg(feature = "native-tls")]
|
||||||
|
pub use TokioNativeTlsRuntime as PreferredRuntime;
|
||||||
|
#[cfg(all(feature = "rustls", not(feature = "native-tls")))]
|
||||||
|
pub use TokioRustlsRuntime as PreferredRuntime;
|
||||||
|
|
||||||
|
/// A [`Runtime`](crate::Runtime) built around a Handle to a tokio runtime, and `native_tls`.
|
||||||
///
|
///
|
||||||
/// # Limitations
|
/// # Limitations
|
||||||
///
|
///
|
||||||
|
@ -18,18 +32,20 @@ use crate::impls::tokio::net::TcpStream;
|
||||||
/// implementations for Tokio's time, net, and io facilities, but we have
|
/// implementations for Tokio's time, net, and io facilities, but we have
|
||||||
/// no good way to check that when creating this object.
|
/// no good way to check that when creating this object.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct TokioRuntimeHandle {
|
#[cfg(feature = "native-tls")]
|
||||||
|
pub struct TokioNativeTlsRuntime {
|
||||||
/// The actual [`CompoundRuntime`] that implements this.
|
/// The actual [`CompoundRuntime`] that implements this.
|
||||||
inner: HandleInner,
|
inner: HandleInner,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implementation type for a TokioRuntimeHandle.
|
/// Implementation type for a TokioRuntimeHandle.
|
||||||
|
#[cfg(feature = "native-tls")]
|
||||||
type HandleInner = CompoundRuntime<Handle, Handle, Handle, NativeTlsProvider<TcpStream>>;
|
type HandleInner = CompoundRuntime<Handle, Handle, Handle, NativeTlsProvider<TcpStream>>;
|
||||||
|
|
||||||
/// A [`Runtime`] built around a Handle to a tokio runtime, and `rustls`.
|
/// A [`Runtime`](crate::Runtime) built around a Handle to a tokio runtime, and `rustls`.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
pub struct TokioRustlsRuntimeHandle {
|
pub struct TokioRustlsRuntime {
|
||||||
/// The actual [`CompoundRuntime`] that implements this.
|
/// The actual [`CompoundRuntime`] that implements this.
|
||||||
inner: RustlsHandleInner,
|
inner: RustlsHandleInner,
|
||||||
}
|
}
|
||||||
|
@ -38,143 +54,132 @@ pub struct TokioRustlsRuntimeHandle {
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
type RustlsHandleInner = CompoundRuntime<Handle, Handle, Handle, RustlsProvider<TcpStream>>;
|
type RustlsHandleInner = CompoundRuntime<Handle, Handle, Handle, RustlsProvider<TcpStream>>;
|
||||||
|
|
||||||
/// A [`Runtime`] built around an owned `TokioTp` executor, and `native_tls`.
|
#[cfg(feature = "native-tls")]
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct TokioRuntime {
|
|
||||||
/// The actual [`CompoundRuntime`] that implements this.
|
|
||||||
inner: TokioRuntimeInner,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A [`Runtime`] built around an owned `TokioTp` executor, and `rustls`.
|
|
||||||
#[derive(Clone)]
|
|
||||||
#[cfg(feature = "rustls")]
|
|
||||||
pub struct TokioRustlsRuntime {
|
|
||||||
/// The actual [`CompoundRuntime`] that implements this.
|
|
||||||
inner: TokioRustlsRuntimeInner,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implementation type for TokioRuntime.
|
|
||||||
type TokioRuntimeInner = CompoundRuntime<TokioTp, TokioTp, TokioTp, NativeTlsProvider<TcpStream>>;
|
|
||||||
|
|
||||||
/// Implementation type for TokioRustlsRuntime.
|
|
||||||
#[cfg(feature = "rustls")]
|
|
||||||
type TokioRustlsRuntimeInner =
|
|
||||||
CompoundRuntime<TokioTp, TokioTp, TokioTp, RustlsProvider<TcpStream>>;
|
|
||||||
|
|
||||||
crate::opaque::implement_opaque_runtime! {
|
crate::opaque::implement_opaque_runtime! {
|
||||||
TokioRuntimeHandle { inner : HandleInner }
|
TokioNativeTlsRuntime { inner : HandleInner }
|
||||||
}
|
|
||||||
|
|
||||||
crate::opaque::implement_opaque_runtime! {
|
|
||||||
TokioRuntime { inner : TokioRuntimeInner }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
crate::opaque::implement_opaque_runtime! {
|
crate::opaque::implement_opaque_runtime! {
|
||||||
TokioRustlsRuntimeHandle { inner : RustlsHandleInner }
|
TokioRustlsRuntime { inner : RustlsHandleInner }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "native-tls")]
|
||||||
crate::opaque::implement_opaque_runtime! {
|
impl From<tokio_crate::runtime::Handle> for TokioNativeTlsRuntime {
|
||||||
TokioRustlsRuntime { inner : TokioRustlsRuntimeInner }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<tokio_crate::runtime::Handle> for TokioRuntimeHandle {
|
|
||||||
fn from(h: tokio_crate::runtime::Handle) -> Self {
|
fn from(h: tokio_crate::runtime::Handle) -> Self {
|
||||||
let h = Handle::new(h);
|
let h = Handle::new(h);
|
||||||
TokioRuntimeHandle {
|
TokioNativeTlsRuntime {
|
||||||
inner: CompoundRuntime::new(h.clone(), h.clone(), h, NativeTlsProvider::default()),
|
inner: CompoundRuntime::new(h.clone(), h.clone(), h, NativeTlsProvider::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create and return a new Tokio multithreaded runtime.
|
|
||||||
fn create_tokio_runtime() -> IoResult<TokioRuntime> {
|
|
||||||
crate::impls::tokio::create_runtime().map(|r| TokioRuntime {
|
|
||||||
inner: CompoundRuntime::new(r.clone(), r.clone(), r, NativeTlsProvider::default()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create and return a new Tokio multithreaded runtime configured to use `rustls`.
|
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
fn create_tokio_rustls_runtime() -> IoResult<TokioRustlsRuntime> {
|
impl From<tokio_crate::runtime::Handle> for TokioRustlsRuntime {
|
||||||
crate::impls::tokio::create_runtime().map(|r| TokioRustlsRuntime {
|
fn from(h: tokio_crate::runtime::Handle) -> Self {
|
||||||
inner: CompoundRuntime::new(r.clone(), r.clone(), r, RustlsProvider::default()),
|
let h = Handle::new(h);
|
||||||
})
|
TokioRustlsRuntime {
|
||||||
|
inner: CompoundRuntime::new(h.clone(), h.clone(), h, RustlsProvider::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Tokio-based [`Runtime`].
|
#[cfg(feature = "native-tls")]
|
||||||
///
|
impl TokioNativeTlsRuntime {
|
||||||
/// Generally you should call this function only once, and then use
|
/// Create a new [`TokioNativeTlsRuntime`].
|
||||||
/// [`Clone::clone()`] to create additional references to that
|
///
|
||||||
/// runtime.
|
/// The return value will own the underlying Tokio runtime object, which
|
||||||
///
|
/// will be dropped when the last copy of this handle is freed.
|
||||||
/// Tokio users may want to avoid this function and instead make a
|
///
|
||||||
/// runtime using [`current_runtime()`]: this function always _builds_ a
|
/// If you want to use a currently running runtime instead, call
|
||||||
/// runtime, and if you already have a runtime, that isn't what you
|
/// [`TokioNativeTlsRuntime::current()`].
|
||||||
/// want with Tokio.
|
pub fn create() -> IoResult<Self> {
|
||||||
pub fn create_runtime() -> std::io::Result<impl Runtime> {
|
crate::impls::tokio::create_runtime().map(|r| TokioNativeTlsRuntime {
|
||||||
create_tokio_runtime()
|
inner: CompoundRuntime::new(r.clone(), r.clone(), r, NativeTlsProvider::default()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a [`TokioNativeTlsRuntime`] wrapping the currently running
|
||||||
|
/// Tokio runtime.
|
||||||
|
///
|
||||||
|
/// # Usage note
|
||||||
|
///
|
||||||
|
/// We should never call this from inside other Arti crates, or from library
|
||||||
|
/// crates that want to support multiple runtimes! This function is for
|
||||||
|
/// Arti _users_ who want to wrap some existing Tokio runtime as a
|
||||||
|
/// [`Runtime`](crate::Runtime). It is not for library crates that want to work with
|
||||||
|
/// multiple runtimes.
|
||||||
|
///
|
||||||
|
/// Once you have a runtime returned by this function, you should just
|
||||||
|
/// create more handles to it via [`Clone`].
|
||||||
|
pub fn current() -> IoResult<Self> {
|
||||||
|
Ok(current_handle()?.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper to run a single test function in a freshly created runtime.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if we can't create this runtime.
|
||||||
|
pub fn run_test<P, F, O>(func: P) -> O
|
||||||
|
where
|
||||||
|
P: FnOnce(Self) -> F,
|
||||||
|
F: futures::Future<Output = O>,
|
||||||
|
{
|
||||||
|
let runtime = Self::create().expect("Failed to create runtime");
|
||||||
|
runtime.clone().block_on(func(runtime))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new Tokio-based [`Runtime`] with `rustls`.
|
|
||||||
///
|
|
||||||
/// Generally you should call this function only once, and then use
|
|
||||||
/// [`Clone::clone()`] to create additional references to that
|
|
||||||
/// runtime.
|
|
||||||
///
|
|
||||||
/// Tokio users may want to avoid this function and instead make a
|
|
||||||
/// runtime using [`current_runtime()`]: this function always _builds_ a
|
|
||||||
/// runtime, and if you already have a runtime, that isn't what you
|
|
||||||
/// want with Tokio.
|
|
||||||
#[cfg(feature = "rustls")]
|
#[cfg(feature = "rustls")]
|
||||||
pub fn create_rustls_runtime() -> std::io::Result<impl Runtime> {
|
impl TokioRustlsRuntime {
|
||||||
create_tokio_rustls_runtime()
|
/// Create a new [`TokioRustlsRuntime`].
|
||||||
|
///
|
||||||
|
/// The return value will own the underlying Tokio runtime object, which
|
||||||
|
/// will be dropped when the last copy of this handle is freed.
|
||||||
|
///
|
||||||
|
/// If you want to use a currently running runtime instead, call
|
||||||
|
/// [`TokioRustlsRuntime::current()`].
|
||||||
|
pub fn create() -> IoResult<Self> {
|
||||||
|
crate::impls::tokio::create_runtime().map(|r| TokioRustlsRuntime {
|
||||||
|
inner: CompoundRuntime::new(r.clone(), r.clone(), r, RustlsProvider::default()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a [`TokioRustlsRuntime`] wrapping the currently running
|
||||||
|
/// Tokio runtime.
|
||||||
|
///
|
||||||
|
/// # Usage note
|
||||||
|
///
|
||||||
|
/// We should never call this from inside other Arti crates, or from library
|
||||||
|
/// crates that want to support multiple runtimes! This function is for
|
||||||
|
/// Arti _users_ who want to wrap some existing Tokio runtime as a
|
||||||
|
/// [`Runtime`](crate::Runtime). It is not for library crates that want to work with
|
||||||
|
/// multiple runtimes.
|
||||||
|
///
|
||||||
|
/// Once you have a runtime returned by this function, you should just
|
||||||
|
/// create more handles to it via [`Clone`].
|
||||||
|
pub fn current() -> IoResult<Self> {
|
||||||
|
Ok(current_handle()?.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper to run a single test function in a freshly created runtime.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics if we can't create this runtime.
|
||||||
|
pub fn run_test<P, F, O>(func: P) -> O
|
||||||
|
where
|
||||||
|
P: FnOnce(Self) -> F,
|
||||||
|
F: futures::Future<Output = O>,
|
||||||
|
{
|
||||||
|
let runtime = Self::create().expect("Failed to create runtime");
|
||||||
|
runtime.clone().block_on(func(runtime))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to return an instance of the currently running tokio [`Runtime`].
|
/// As `Handle::try_current()`, but return an IoError on failure.
|
||||||
///
|
#[cfg(any(feature = "native-tls", feature = "rustls"))]
|
||||||
/// # Usage note
|
fn current_handle() -> std::io::Result<tokio_crate::runtime::Handle> {
|
||||||
///
|
tokio_crate::runtime::Handle::try_current().map_err(|e| IoError::new(ErrorKind::Other, e))
|
||||||
/// We should never call this from inside other Arti crates, or from
|
|
||||||
/// library crates that want to support multiple runtimes! This
|
|
||||||
/// function is for Arti _users_ who want to wrap some existing Tokio
|
|
||||||
/// runtime as a [`Runtime`]. It is not for library
|
|
||||||
/// crates that want to work with multiple runtimes.
|
|
||||||
///
|
|
||||||
/// Once you have a runtime returned by this function, you should
|
|
||||||
/// just create more handles to it via [`Clone`].
|
|
||||||
pub fn current_runtime() -> std::io::Result<TokioRuntimeHandle> {
|
|
||||||
let handle = tokio_crate::runtime::Handle::try_current()
|
|
||||||
.map_err(|e| IoError::new(ErrorKind::Other, e))?;
|
|
||||||
let h = Handle::new(handle);
|
|
||||||
Ok(TokioRuntimeHandle {
|
|
||||||
inner: CompoundRuntime::new(h.clone(), h.clone(), h, NativeTlsProvider::default()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return an instance of the currently running tokio [`Runtime`], wrapped to
|
|
||||||
/// use `rustls`.
|
|
||||||
#[cfg(feature = "rustls")]
|
|
||||||
pub fn current_runtime_rustls() -> std::io::Result<TokioRustlsRuntimeHandle> {
|
|
||||||
let handle = tokio_crate::runtime::Handle::try_current()
|
|
||||||
.map_err(|e| IoError::new(ErrorKind::Other, e))?;
|
|
||||||
let h = Handle::new(handle);
|
|
||||||
Ok(TokioRustlsRuntimeHandle {
|
|
||||||
inner: CompoundRuntime::new(h.clone(), h.clone(), h, RustlsProvider::default()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run a test function using a freshly created tokio runtime.
|
|
||||||
///
|
|
||||||
/// # Panics
|
|
||||||
///
|
|
||||||
/// Panics if we can't create a tokio runtime.
|
|
||||||
pub fn test_with_runtime<P, F, O>(func: P) -> O
|
|
||||||
where
|
|
||||||
P: FnOnce(TokioRuntime) -> F,
|
|
||||||
F: futures::Future<Output = O>,
|
|
||||||
{
|
|
||||||
let runtime = create_tokio_runtime().expect("Failed to create a tokio runtime");
|
|
||||||
runtime.clone().block_on(func(runtime))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ use std::time::{Duration, Instant, SystemTime};
|
||||||
/// * [`SleepProvider`] to pause a task for a given amount of time.
|
/// * [`SleepProvider`] to pause a task for a given amount of time.
|
||||||
/// * [`TcpProvider`] to launch and accept TCP connections.
|
/// * [`TcpProvider`] to launch and accept TCP connections.
|
||||||
/// * [`TlsProvider`] to launch TLS connections.
|
/// * [`TlsProvider`] to launch TLS connections.
|
||||||
/// * [`SpawnBlocking`] to block on a future and run it to completion
|
/// * [`BlockOn`] to block on a future and run it to completion
|
||||||
/// (This may become optional in the future, if/when we add WASM
|
/// (This may become optional in the future, if/when we add WASM
|
||||||
/// support).
|
/// support).
|
||||||
///
|
///
|
||||||
|
@ -29,7 +29,7 @@ pub trait Runtime:
|
||||||
Sync
|
Sync
|
||||||
+ Send
|
+ Send
|
||||||
+ Spawn
|
+ Spawn
|
||||||
+ SpawnBlocking
|
+ BlockOn
|
||||||
+ Clone
|
+ Clone
|
||||||
+ SleepProvider
|
+ SleepProvider
|
||||||
+ TcpProvider
|
+ TcpProvider
|
||||||
|
@ -42,7 +42,7 @@ impl<T> Runtime for T where
|
||||||
T: Sync
|
T: Sync
|
||||||
+ Send
|
+ Send
|
||||||
+ Spawn
|
+ Spawn
|
||||||
+ SpawnBlocking
|
+ BlockOn
|
||||||
+ Clone
|
+ Clone
|
||||||
+ SleepProvider
|
+ SleepProvider
|
||||||
+ TcpProvider
|
+ TcpProvider
|
||||||
|
@ -105,7 +105,7 @@ pub trait SleepProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for a runtime that can block on a future.
|
/// Trait for a runtime that can block on a future.
|
||||||
pub trait SpawnBlocking {
|
pub trait BlockOn {
|
||||||
/// Run `future` until it is ready, and return its output.
|
/// Run `future` until it is ready, and return its output.
|
||||||
fn block_on<F: Future>(&self, future: F) -> F::Output;
|
fn block_on<F: Future>(&self, future: F) -> F::Output;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,4 +22,4 @@ tor-rtcompat = { version = "0.0.3", path = "../tor-rtcompat" }
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
futures-await-test = "0.3.0"
|
futures-await-test = "0.3.0"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio"] }
|
tor-rtcompat = { path="../tor-rtcompat", version = "0.0.3", features=["tokio", "native-tls" ] }
|
||||||
|
|
|
@ -502,7 +502,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn end_to_end() -> IoResult<()> {
|
fn end_to_end() {
|
||||||
test_with_all_runtimes!(|_rt| async {
|
test_with_all_runtimes!(|_rt| async {
|
||||||
let (client1, client2) = client_pair();
|
let (client1, client2) = client_pair();
|
||||||
let lis = client2.listen(&"0.0.0.0:99".parse().unwrap()).await?;
|
let lis = client2.listen(&"0.0.0.0:99".parse().unwrap()).await?;
|
||||||
|
@ -532,7 +532,7 @@ mod test {
|
||||||
r1?;
|
r1?;
|
||||||
r2?;
|
r2?;
|
||||||
IoResult::Ok(())
|
IoResult::Ok(())
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -573,7 +573,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn listener_stream() -> IoResult<()> {
|
fn listener_stream() {
|
||||||
test_with_all_runtimes!(|_rt| async {
|
test_with_all_runtimes!(|_rt| async {
|
||||||
let (client1, client2) = client_pair();
|
let (client1, client2) = client_pair();
|
||||||
|
|
||||||
|
@ -602,16 +602,18 @@ mod test {
|
||||||
r1?;
|
r1?;
|
||||||
r2?;
|
r2?;
|
||||||
IoResult::Ok(())
|
IoResult::Ok(())
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn tls_basics() -> IoResult<()> {
|
fn tls_basics() {
|
||||||
let (client1, client2) = client_pair();
|
let (client1, client2) = client_pair();
|
||||||
let cert = b"I am certified for something I assure you.";
|
let cert = b"I am certified for something I assure you.";
|
||||||
|
|
||||||
let lis = client2.listen_tls(&"0.0.0.0:0".parse().unwrap(), cert[..].into())?;
|
let lis = client2
|
||||||
let address = lis.local_addr()?;
|
.listen_tls(&"0.0.0.0:0".parse().unwrap(), cert[..].into())
|
||||||
|
.unwrap();
|
||||||
|
let address = lis.local_addr().unwrap();
|
||||||
|
|
||||||
test_with_all_runtimes!(|_rt| async {
|
test_with_all_runtimes!(|_rt| async {
|
||||||
let (r1, r2): (IoResult<()>, IoResult<()>) = futures::join!(
|
let (r1, r2): (IoResult<()>, IoResult<()>) = futures::join!(
|
||||||
|
@ -642,6 +644,6 @@ mod test {
|
||||||
r1?;
|
r1?;
|
||||||
r2?;
|
r2?;
|
||||||
IoResult::Ok(())
|
IoResult::Ok(())
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// we should make it so that more code is more shared.
|
// we should make it so that more code is more shared.
|
||||||
|
|
||||||
use crate::net::MockNetProvider;
|
use crate::net::MockNetProvider;
|
||||||
use tor_rtcompat::{Runtime, SleepProvider, SpawnBlocking, TcpProvider, TlsProvider};
|
use tor_rtcompat::{BlockOn, Runtime, SleepProvider, TcpProvider, TlsProvider};
|
||||||
|
|
||||||
use crate::io::LocalStream;
|
use crate::io::LocalStream;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
@ -48,7 +48,7 @@ impl<R: Runtime> Spawn for MockNetRuntime<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Runtime> SpawnBlocking for MockNetRuntime<R> {
|
impl<R: Runtime> BlockOn for MockNetRuntime<R> {
|
||||||
fn block_on<F: Future>(&self, future: F) -> F::Output {
|
fn block_on<F: Future>(&self, future: F) -> F::Output {
|
||||||
self.runtime.block_on(future)
|
self.runtime.block_on(future)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Declare MockSleepRuntime.
|
//! Declare MockSleepRuntime.
|
||||||
|
|
||||||
use crate::time::MockSleepProvider;
|
use crate::time::MockSleepProvider;
|
||||||
use tor_rtcompat::{Runtime, SleepProvider, SpawnBlocking, TcpProvider, TlsProvider};
|
use tor_rtcompat::{BlockOn, Runtime, SleepProvider, TcpProvider, TlsProvider};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use futures::task::{FutureObj, Spawn, SpawnError};
|
use futures::task::{FutureObj, Spawn, SpawnError};
|
||||||
|
@ -86,7 +86,7 @@ impl<R: Runtime> Spawn for MockSleepRuntime<R> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Runtime> SpawnBlocking for MockSleepRuntime<R> {
|
impl<R: Runtime> BlockOn for MockSleepRuntime<R> {
|
||||||
fn block_on<F: Future>(&self, future: F) -> F::Output {
|
fn block_on<F: Future>(&self, future: F) -> F::Output {
|
||||||
self.runtime.block_on(future)
|
self.runtime.block_on(future)
|
||||||
}
|
}
|
||||||
|
|
|
@ -455,7 +455,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn time_moves_on() -> std::io::Result<()> {
|
fn time_moves_on() {
|
||||||
test_with_all_runtimes!(|_| async {
|
test_with_all_runtimes!(|_| async {
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
@ -514,6 +514,6 @@ mod test {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
std::io::Result::Ok(())
|
std::io::Result::Ok(())
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue