Merge branch 'eta/182' into 'main'

Improve the layout of crate exports; add runtime convenience functions

See merge request tpo/core/arti!235
This commit is contained in:
Nick Mathewson 2022-01-11 18:42:15 +00:00
commit b4761f8cfd
7 changed files with 95 additions and 20 deletions

View File

@ -23,6 +23,10 @@ use std::sync::{Arc, Mutex, Weak};
use std::time::Duration;
use crate::{Error, Result};
#[cfg(feature = "async-std")]
use tor_rtcompat::async_std::AsyncStdRuntime;
#[cfg(feature = "tokio")]
use tor_rtcompat::tokio::TokioRuntimeHandle;
use tracing::{debug, error, info, warn};
/// An active client session on the Tor network.
@ -166,10 +170,49 @@ impl ConnectPrefs {
// TODO: Add some way to be IPFlexible, and require exit to support both.
}
impl<R: Runtime> TorClient<R> {
/// Bootstrap a network connection configured by `dir_cfg` and `circ_cfg`.
#[cfg(feature = "tokio")]
impl TorClient<TokioRuntimeHandle> {
/// Bootstrap a connection to the Tor network, using the current Tokio runtime.
///
/// Return a client once there is enough directory material to
/// Returns a client once there is enough directory material to
/// connect safely over the Tor network.
///
/// This is a convenience wrapper around [`TorClient::bootstrap`].
///
/// # Panics
///
/// Panics if called outside of the context of a Tokio runtime.
pub async fn bootstrap_with_tokio(
config: TorClientConfig,
) -> Result<TorClient<TokioRuntimeHandle>> {
let rt = tor_rtcompat::tokio::current_runtime().expect("called outside of Tokio runtime");
Self::bootstrap(rt, config).await
}
}
#[cfg(feature = "async-std")]
impl TorClient<AsyncStdRuntime> {
/// Bootstrap a connection to the Tor network, using the current async-std runtime.
///
/// Returns a client once there is enough directory material to
/// connect safely over the Tor network.
///
/// This is a convenience wrapper around [`TorClient::bootstrap`].
pub async fn bootstrap_with_async_std(
config: TorClientConfig,
) -> Result<TorClient<AsyncStdRuntime>> {
// FIXME(eta): not actually possible for this to fail
let rt =
tor_rtcompat::async_std::current_runtime().expect("failed to get async-std runtime");
Self::bootstrap(rt, config).await
}
}
impl<R: Runtime> TorClient<R> {
/// Bootstrap a connection to the Tor network, using the provided `config` and `runtime` (a
/// [`tor_rtcompat`] [`Runtime`](tor_rtcompat::Runtime)).
///
/// Returns a client once there is enough directory material to
/// connect safely over the Tor network.
pub async fn bootstrap(runtime: R, config: TorClientConfig) -> Result<TorClient<R>> {
let circ_cfg = config.get_circmgr_config()?;

View File

@ -8,9 +8,7 @@ use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
use std::time::Duration;
use tor_config::CfgPath;
pub use tor_config::ConfigBuildError;
pub use tor_config::{CfgPath, ConfigBuildError};
/// Types for configuring how Tor circuits are built.
pub mod circ {

View File

@ -182,7 +182,7 @@ pub use client::{ConnectPrefs, TorClient};
pub use config::TorClientConfig;
pub use tor_circmgr::IsolationToken;
pub use tor_proto::stream::DataStream;
pub use tor_proto::stream::{DataReader, DataStream, DataWriter};
mod err;
pub use err::Error;

View File

@ -14,7 +14,7 @@ mod params;
mod raw;
mod resolve;
pub use data::DataStream;
pub use data::{DataReader, DataStream, DataWriter};
pub use params::StreamParameters;
pub use raw::StreamReader;
pub use resolve::ResolveStream;

View File

@ -74,6 +74,12 @@ use tor_cell::relaycell::msg::{Data, RelayMsg};
/// data has actually been sent, you need to make sure that
/// [`AsyncWrite::poll_flush`] runs to completion: probably via
/// [`AsyncWriteExt::flush`](futures::io::AsyncWriteExt::flush).
///
/// # Splitting the type
///
/// This type is internally composed of a [`DataReader`] and a [`DataWriter`]; the
/// `DataStream::split` method can be used to split it into those two parts, for more
/// convenient usage with e.g. stream combinators.
// # Semver note
//
// Note that this type is re-exported as a part of the public API of
@ -86,11 +92,22 @@ pub struct DataStream {
r: DataReader,
}
/// Wrapper for the Write part of a DataStream.
/// The write half of a [`DataStream`], implementing [`futures::io::AsyncWrite`].
///
/// Note that this implementation writes Tor cells lazily, so it is
/// essential to flush the stream when you need the data to be sent
/// out right away.
/// See the [`DataStream`] docs for more information. In particular, note
/// that this writer requires `poll_flush` to complete in order to guarantee that
/// all data has been written.
///
/// # Usage with Tokio
///
/// If the `tokio` crate feature is enabled, this type also implements
/// [`tokio::io::AsyncWrite`](tokio_crate::io::AsyncWrite) for easier integration
/// with code that expects that trait.
// # Semver note
//
// Note that this type is re-exported as a part of the public API of
// the `arti-client` crate. Any changes to its API here in
// `tor-proto` need to be reflected above.
pub struct DataWriter {
/// Internal state for this writer
///
@ -100,7 +117,21 @@ pub struct DataWriter {
state: Option<DataWriterState>,
}
/// Wrapper for the Read part of a DataStream
/// The read half of a [`DataStream`], implementing [`futures::io::AsyncRead`].
///
/// See the [`DataStream`] docs for more information.
///
/// # Usage with Tokio
///
/// If the `tokio` crate feature is enabled, this type also implements
/// [`tokio::io::AsyncRead`](tokio_crate::io::AsyncRead) for easier integration
/// with code that expects that trait.
//
// # Semver note
//
// Note that this type is re-exported as a part of the public API of
// the `arti-client` crate. Any changes to its API here in
// `tor-proto` need to be reflected above.
pub struct DataReader {
/// Internal state for this reader.
///

View File

@ -1,20 +1,23 @@
//! Entry points for use with async_std runtimes.
pub use crate::impls::async_std::create_runtime as create_async_std_runtime;
use crate::{Runtime, SpawnBlocking};
use crate::SpawnBlocking;
/// Return a new async-std-based [`Runtime`].
/// A [`Runtime`](crate::Runtime) powered by async-std.
pub use async_executors::AsyncStd as AsyncStdRuntime;
/// Return a new async-std-based [`Runtime`](crate::Runtime).
///
/// Generally you should call this function only once, and then use
/// [`Clone::clone()`] to create additional references to that
/// runtime.
pub fn create_runtime() -> std::io::Result<impl Runtime> {
pub fn create_runtime() -> std::io::Result<AsyncStdRuntime> {
Ok(create_async_std_runtime())
}
/// Try to return an instance of the currently running async_std
/// [`Runtime`].
pub fn current_runtime() -> std::io::Result<impl Runtime> {
/// [`Runtime`](crate::Runtime).
pub fn current_runtime() -> std::io::Result<AsyncStdRuntime> {
// In async_std, the runtime is a global singleton.
create_runtime()
}
@ -22,7 +25,7 @@ pub fn current_runtime() -> std::io::Result<impl Runtime> {
/// Run a test function using a freshly created async_std runtime.
pub fn test_with_runtime<P, F, O>(func: P) -> O
where
P: FnOnce(async_executors::AsyncStd) -> F,
P: FnOnce(AsyncStdRuntime) -> F,
F: futures::Future<Output = O>,
{
let runtime = create_async_std_runtime();

View File

@ -32,7 +32,7 @@ pub fn create_runtime() -> std::io::Result<impl Runtime> {
///
/// 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<impl Runtime> {
pub fn current_runtime() -> std::io::Result<TokioRuntimeHandle> {
let handle = tokio_crate::runtime::Handle::try_current()
.map_err(|e| IoError::new(ErrorKind::Other, e))?;
Ok(TokioRuntimeHandle::new(handle))