aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoreta <tor@eta.st>2022-02-25 18:13:02 +0000
committereta <tor@eta.st>2022-02-28 16:41:13 +0000
commit13ba0ea005ddd87bba2d53ab738ce948f031e1e8 (patch)
treeffc9345b923326c0c73406d47e54cc34aedf27f7
parent387ebda740081983cf1f051c630a7729dc6e7926 (diff)
downloadarti-13ba0ea005ddd87bba2d53ab738ce948f031e1e8.tar.gz
arti-13ba0ea005ddd87bba2d53ab738ce948f031e1e8.zip
arti-client: use PreferredRuntime by default, doc cleanups
This makes using the `PreferredRuntime` the first-class option inside `arti-client`, freeing users who don't want to think about runtimes from having to do so. `TorClient::create_unbootstrapped` and `builder` now automatically use this runtime, leaving only `builder_custom` for users who wish to manually specify a runtime. This lets us clean up the docs a lot: mentions of using custom runtimes are now relegated to nearer the end of the crate-level documentation, and we mostly just link to `tor_rtcompat`'s docs to explain more there. Instead, we take some more time to explain how you use the builder API to create clients synchronously. Other doc cleanups included getting rid of the explanation of `TorAddr` in the main crate-level doc; this is already well-documented elsewhere, and is something users should discover organically later. fixes arti#326
-rw-r--r--crates/arti-bench/src/main.rs8
-rw-r--r--crates/arti-client/examples/hook-tcp.rs14
-rw-r--r--crates/arti-client/examples/lazy-init.rs11
-rw-r--r--crates/arti-client/examples/readme.rs6
-rw-r--r--crates/arti-client/src/client.rs91
-rw-r--r--crates/arti-client/src/lib.rs134
-rw-r--r--crates/arti-hyper/examples/hyper.rs5
-rw-r--r--crates/arti/src/main.rs2
-rw-r--r--crates/tor-rtcompat/src/lib.rs24
9 files changed, 156 insertions, 139 deletions
diff --git a/crates/arti-bench/src/main.rs b/crates/arti-bench/src/main.rs
index ba0233d8a..680c05014 100644
--- a/crates/arti-bench/src/main.rs
+++ b/crates/arti-bench/src/main.rs
@@ -643,9 +643,11 @@ impl<R: Runtime> Benchmark<R> {
/// Benchmark through Arti, using the provided `TorClientConfig`.
fn with_arti(&mut self, tcc: TorClientConfig) -> Result<()> {
info!("Starting Arti...");
- let tor_client = self
- .runtime
- .block_on(TorClient::create_bootstrapped(self.runtime.clone(), tcc))?;
+ let tor_client = self.runtime.block_on(
+ TorClient::with_runtime(self.runtime.clone())
+ .config(tcc)
+ .create_bootstrapped(),
+ )?;
let addr = TorAddr::dangerously_from(self.connect_addr)?;
diff --git a/crates/arti-client/examples/hook-tcp.rs b/crates/arti-client/examples/hook-tcp.rs
index ac5627f24..4ad631ee7 100644
--- a/crates/arti-client/examples/hook-tcp.rs
+++ b/crates/arti-client/examples/hook-tcp.rs
@@ -14,10 +14,9 @@ use std::task::{Context, Poll};
use anyhow::Result;
use arti_client::{TorClient, TorClientConfig};
use tokio_crate as tokio;
-use tor_rtcompat::tokio::TokioNativeTlsRuntime;
use futures::{AsyncRead, AsyncWrite, FutureExt, Stream};
-use tor_rtcompat::{CompoundRuntime, TcpListener, TcpProvider};
+use tor_rtcompat::{CompoundRuntime, PreferredRuntime, TcpListener, TcpProvider};
use futures::io::{AsyncReadExt, AsyncWriteExt};
@@ -26,14 +25,19 @@ async fn main() -> Result<()> {
tracing_subscriber::fmt::init();
let config = TorClientConfig::default();
- let rt = TokioNativeTlsRuntime::current()?;
+ // Get the current preferred runtime.
+ let rt = PreferredRuntime::current()?;
// Instantiate our custom TCP provider (see implementation below).
let tcp_rt = CustomTcpProvider { inner: rt.clone() };
- // Create a `CompoundRuntime`, swapping out the TCP part of the runtime for our custom one.
+ // Create a `CompoundRuntime`, swapping out the TCP part of the preferred runtime for our custom one.
let rt = CompoundRuntime::new(rt.clone(), rt.clone(), tcp_rt, rt);
eprintln!("connecting to Tor...");
- let tor_client = TorClient::create_bootstrapped(rt, config).await?;
+ // Pass in our custom runtime using `with_runtime`.
+ let tor_client = TorClient::with_runtime(rt)
+ .config(config)
+ .create_bootstrapped()
+ .await?;
eprintln!("connecting to example.com...");
let mut stream = tor_client.connect(("example.com", 80)).await?;
diff --git a/crates/arti-client/examples/lazy-init.rs b/crates/arti-client/examples/lazy-init.rs
index 5f89c83fd..050fa2b4c 100644
--- a/crates/arti-client/examples/lazy-init.rs
+++ b/crates/arti-client/examples/lazy-init.rs
@@ -1,12 +1,12 @@
use anyhow::Result;
use arti_client::{TorClient, TorClientConfig};
use tokio_crate as tokio;
-use tor_rtcompat::tokio::TokioNativeTlsRuntime;
use futures::io::{AsyncReadExt, AsyncWriteExt};
use once_cell::sync::OnceCell;
+use tor_rtcompat::PreferredRuntime;
-static TOR_CLIENT: OnceCell<TorClient<TokioNativeTlsRuntime>> = OnceCell::new();
+static TOR_CLIENT: OnceCell<TorClient<PreferredRuntime>> = OnceCell::new();
/// Get a `TorClient` by copying the globally shared client stored in `TOR_CLIENT`.
/// If that client hasn't been initialized yet, initializes it first.
@@ -15,7 +15,7 @@ static TOR_CLIENT: OnceCell<TorClient<TokioNativeTlsRuntime>> = OnceCell::new();
///
/// Errors if called outside a Tokio runtime context, or creating the Tor client
/// failed.
-pub fn get_tor_client() -> Result<TorClient<TokioNativeTlsRuntime>> {
+pub fn get_tor_client() -> Result<TorClient<PreferredRuntime>> {
let client = TOR_CLIENT.get_or_try_init(|| -> Result<TorClient<_>> {
// The client config includes things like where to store persistent Tor network state.
// The defaults provided are the same as the Arti standalone application, and save data
@@ -23,14 +23,11 @@ pub fn get_tor_client() -> Result<TorClient<TokioNativeTlsRuntime>> {
// on Linux platforms)
let config = TorClientConfig::default();
- // Get a `tor_rtcompat::Runtime` from the currently running Tokio runtime.
- let rt = TokioNativeTlsRuntime::current()?;
-
eprintln!("creating unbootstrapped Tor client");
// Create an unbootstrapped Tor client. Bootstrapping will happen when the client is used,
// since `BootstrapBehavior::OnDemand` is the default.
- Ok(TorClient::builder(rt)
+ Ok(TorClient::builder()
.config(config)
.create_unbootstrapped()?)
})?;
diff --git a/crates/arti-client/examples/readme.rs b/crates/arti-client/examples/readme.rs
index d8d4dc662..5f67fd6a3 100644
--- a/crates/arti-client/examples/readme.rs
+++ b/crates/arti-client/examples/readme.rs
@@ -1,7 +1,6 @@
use anyhow::Result;
use arti_client::{TorClient, TorClientConfig};
use tokio_crate as tokio;
-use tor_rtcompat::tokio::TokioNativeTlsRuntime;
use futures::io::{AsyncReadExt, AsyncWriteExt};
@@ -15,15 +14,12 @@ async fn main() -> Result<()> {
// to a conventional place depending on operating system (for example, ~/.local/share/arti
// on Linux platforms)
let config = TorClientConfig::default();
- // Arti needs an async runtime handle to spawn async tasks.
- // (See "Multiple runtime support" below.)
- let rt = TokioNativeTlsRuntime::current()?;
eprintln!("connecting to Tor...");
// 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.)
- let tor_client = TorClient::create_bootstrapped(rt, config).await?;
+ let tor_client = TorClient::create_bootstrapped(config).await?;
eprintln!("connecting to example.com...");
diff --git a/crates/arti-client/src/client.rs b/crates/arti-client/src/client.rs
index a535e828e..ee81c098c 100644
--- a/crates/arti-client/src/client.rs
+++ b/crates/arti-client/src/client.rs
@@ -13,7 +13,7 @@ use tor_dirmgr::DirEvent;
use tor_persist::{FsStateMgr, StateMgr};
use tor_proto::circuit::ClientCirc;
use tor_proto::stream::{DataStream, IpVersionPreference, StreamParameters};
-use tor_rtcompat::{Runtime, SleepProviderExt};
+use tor_rtcompat::{PreferredRuntime, Runtime, SleepProviderExt};
use futures::lock::Mutex as AsyncMutex;
use futures::stream::StreamExt;
@@ -26,10 +26,6 @@ use std::time::Duration;
use crate::err::ErrorDetail;
use crate::{status, util, TorClientBuilder};
-#[cfg(feature = "async-std")]
-use tor_rtcompat::async_std::PreferredRuntime as PreferredAsyncStdRuntime;
-#[cfg(feature = "tokio")]
-use tor_rtcompat::tokio::PreferredRuntime as PreferredTokioRuntime;
use tracing::{debug, error, info, warn};
/// An active client session on the Tor network.
@@ -278,64 +274,61 @@ impl StreamPrefs {
// TODO: Add some way to be IPFlexible, and require exit to support both.
}
-#[cfg(feature = "tokio")]
-impl TorClient<PreferredTokioRuntime> {
- /// Bootstrap a connection to the Tor network, using the current Tokio runtime.
+impl TorClient<PreferredRuntime> {
+ /// Bootstrap a connection to the Tor network, using the provided `config`.
///
/// Returns a client once there is enough directory material to
/// connect safely over the Tor network.
///
- /// This is a convenience wrapper around [`TorClient::create_bootstrapped`].
+ /// Consider using [`TorClient::builder`] for more fine-grained control.
///
/// # Panics
///
- /// Panics if called outside of the context of a Tokio runtime.
- pub async fn bootstrap_with_tokio(
- config: TorClientConfig,
- ) -> crate::Result<TorClient<PreferredTokioRuntime>> {
- let rt = PreferredTokioRuntime::current().expect("called outside of Tokio runtime");
- Self::create_bootstrapped(rt, config).await
+ /// If Tokio is being used (the default), panics if created outside the context of a currently
+ /// running Tokio runtime. See the documentation for [`PreferredRuntime::current`] for
+ /// more information.
+ ///
+ /// If using `async-std`, either take care to ensure Arti is not compiled with Tokio support,
+ /// or manually create an `async-std` runtime using [`tor_rtcompat`] and use it with
+ /// [`TorClient::with_runtime`].
+ pub async fn create_bootstrapped(config: TorClientConfig) -> crate::Result<Self> {
+ let runtime = PreferredRuntime::current()
+ .expect("TorClient could not get an asynchronous runtime; are you running in the right context?");
+
+ Self::with_runtime(runtime)
+ .config(config)
+ .create_bootstrapped()
+ .await
}
-}
-#[cfg(feature = "async-std")]
-impl TorClient<PreferredAsyncStdRuntime> {
- /// Bootstrap a connection to the Tor network, using the current async-std runtime.
+ /// Return a new builder for creating TorClient objects.
///
- /// Returns a client once there is enough directory material to
- /// connect safely over the Tor network.
+ /// If you want to make a [`TorClient`] synchronously, this is what you want; call
+ /// `TorClientBuilder::create_unbootstrapped` on the returned builder.
///
- /// This is a convenience wrapper around [`TorClient::create_bootstrapped`].
- pub async fn bootstrap_with_async_std(
- config: TorClientConfig,
- ) -> crate::Result<TorClient<PreferredAsyncStdRuntime>> {
- // FIXME(eta): not actually possible for this to fail
- let rt = PreferredAsyncStdRuntime::current().expect("failed to get async-std runtime");
- Self::create_bootstrapped(rt, config).await
- }
-}
+ /// # Panics
+ ///
+ /// If Tokio is being used (the default), panics if created outside the context of a currently
+ /// running Tokio runtime. See the documentation for `tokio::runtime::Handle::current` for
+ /// more information.
+ ///
+ /// If using `async-std`, either take care to ensure Arti is not compiled with Tokio support,
+ /// or manually create an `async-std` runtime using [`tor_rtcompat`] and use it with
+ /// [`TorClient::with_runtime`].
+ pub fn builder() -> TorClientBuilder<PreferredRuntime> {
+ let runtime = PreferredRuntime::current()
+ .expect("TorClient could not get an asynchronous runtime; are you running in the right context?");
-impl<R: Runtime> TorClient<R> {
- /// Return a new builder for creating TorClient objects.
- pub fn builder(runtime: R) -> TorClientBuilder<R> {
TorClientBuilder::new(runtime)
}
+}
- /// 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.
+impl<R: Runtime> TorClient<R> {
+ /// Return a new builder for creating TorClient objects, with a custom provided [`Runtime`].
///
- /// Consider using a [`TorClientBuilder`] for more fine-grained control.
- pub async fn create_bootstrapped(
- runtime: R,
- config: TorClientConfig,
- ) -> crate::Result<TorClient<R>> {
- Self::builder(runtime)
- .config(config)
- .create_bootstrapped()
- .await
+ /// See the [`tor_rtcompat`] crate for more information on custom runtimes.
+ pub fn with_runtime(runtime: R) -> TorClientBuilder<R> {
+ TorClientBuilder::new(runtime)
}
/// Implementation of `create_unbootstrapped`, split out in order to avoid manually specifying
@@ -1081,7 +1074,7 @@ mod test {
let cfg = TorClientConfigBuilder::from_directories(state_dir, cache_dir)
.build()
.unwrap();
- let _ = TorClient::builder(rt)
+ let _ = TorClient::with_runtime(rt)
.config(cfg)
.bootstrap_behavior(BootstrapBehavior::Manual)
.create_unbootstrapped()
@@ -1097,7 +1090,7 @@ mod test {
let cfg = TorClientConfigBuilder::from_directories(state_dir, cache_dir)
.build()
.unwrap();
- let client = TorClient::builder(rt)
+ let client = TorClient::with_runtime(rt)
.config(cfg)
.bootstrap_behavior(BootstrapBehavior::Manual)
.create_unbootstrapped()
diff --git a/crates/arti-client/src/lib.rs b/crates/arti-client/src/lib.rs
index c8b91566f..523690ccf 100644
--- a/crates/arti-client/src/lib.rs
+++ b/crates/arti-client/src/lib.rs
@@ -3,9 +3,7 @@
//! # Overview
//!
//! The `arti-client` crate aims to provide a safe, easy-to-use API for
-//! applications that want to use Tor network to anonymize their traffic. It
-//! hides most of the underlying detail, letting other crates decide how exactly
-//! to use the Tor crate.
+//! applications that want to use the Tor network to anonymize their traffic.
//!
//! This crate is part of [Arti](https://gitlab.torproject.org/tpo/core/arti/),
//! a project to implement [Tor](https://www.torproject.org/) in Rust. It is the
@@ -28,28 +26,15 @@
//! The main entry point for this crate is the [`TorClient`], an object that
//! lets you make connections over the Tor network.
//!
+//! ## Connecting to Tor
+//!
//! Calling [`TorClient::create_bootstrapped`] establishes a connection to the Tor
//! network, pulling in necessary state about network consensus as required.
//! This state gets persisted to the locations specified in the
//! [`TorClientConfig`].
//!
-//! A client can then be used to make connections over Tor with
-//! [`TorClient::connect`], which accepts anything implementing [`IntoTorAddr`].
-//! This returns a [`DataStream`], an anonymized TCP stream type that implements
-//! [`AsyncRead`](futures::io::AsyncRead) and
-//! [`AsyncWrite`](futures::io::AsyncWrite), as well as the Tokio versions of
-//! those traits if the `tokio` crate feature is enabled.
-//!
-//! The [`TorAddr`] type is intended to ensure that DNS lookups are done via the
-//! Tor network instead of locally. Doing local DNS resolution can leak
-//! information about which hostnames you're connecting to to your local DNS
-//! resolver (i.e. your ISP), so it's much better to let Arti do it for you to
-//! maintain privacy.
-//!
-//! If you really want to connect to a raw IP address and know what you're
-//! doing, take a look at [`TorAddr::dangerously_from`] -- but be careful!
-//!
-//! ## Example: making connections over Tor
+//! (This method requires you to initialize the client in an `async fn`. Consider
+//! using the builder method, below, if that doesn't work for you.)
//!
//! ```no_run
//! # use anyhow::Result;
@@ -60,15 +45,60 @@
//! // The client configuration describes how to connect to the Tor network,
//! // and what directories to use for storing persistent state.
//! let config = TorClientConfig::default();
-//! // Arti needs a handle to an async runtime in order to spawn tasks and use the
-//! // network. (See "Multiple runtime support" below.)
-//! let rt = tor_rtcompat::tokio::TokioNativeTlsRuntime::current()?;
//!
//! // Start the Arti client, and let it bootstrap a connection to the Tor network.
//! // (This takes a while to gather the necessary directory information.
//! // It uses cached information when possible.)
-//! let tor_client = TorClient::create_bootstrapped(rt, config).await?;
+//! let tor_client = TorClient::create_bootstrapped(config).await?;
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ## Creating a client and connecting later
+//!
+//! You might wish to create a Tor client immediately, without waiting for it to bootstrap (or
+//! having to use an `await`). This can be done by making a [`TorClientBuilder`] with
+//! [`TorClient::builder`], and calling [`TorClientBuilder::create_unbootstrapped`].
+//!
+//! The returned client can be made to bootstrap when it is first used (the default), or not;
+//! see [`BootstrapBehavior`] for more details.
+//!
+//! ```no_run
+//! # use anyhow::Result;
+//! # use arti_client::{TorClient, TorClientConfig};
+//! # use tokio_crate as tokio;
+//! # use arti_client::BootstrapBehavior;
+//! # #[tokio::main]
+//! # async fn main() -> Result<()> {
+//! // Specifying `BootstrapBehavior::OnDemand` means the client will automatically
+//! // bootstrap when it is used. `Manual` exists if you'd rather have full control.
+//! let tor_client = TorClient::builder()
+//! .bootstrap_behavior(BootstrapBehavior::OnDemand)
+//! .create_unbootstrapped()?;
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! ## Using the client
+//!
+//! A client can then be used to make connections over Tor with
+//! [`TorClient::connect`], which accepts anything implementing [`IntoTorAddr`].
+//! This returns a [`DataStream`], an anonymized TCP stream type that implements
+//! [`AsyncRead`](futures::io::AsyncRead) and
+//! [`AsyncWrite`](futures::io::AsyncWrite), as well as the Tokio versions of
+//! those traits if the `tokio` crate feature is enabled.
+//!
+//! ## Example: making connections over Tor
//!
+//! ```no_run
+//! # use anyhow::Result;
+//! # use arti_client::{TorClient, TorClientConfig};
+//! # use tokio_crate as tokio;
+//! # #[tokio::main]
+//! # async fn main() -> Result<()> {
+//! # let config = TorClientConfig::default();
+//! # let tor_client = TorClient::create_bootstrapped(config).await?;
+//! #
//! // Initiate a connection over Tor to example.com, port 80.
//! let mut stream = tor_client.connect(("example.com", 80)).await?;
//!
@@ -118,45 +148,31 @@
//! runtimes; currently, both [Tokio](https://tokio.rs) and
//! [async-std](https://async.rs) are supported.
//!
-//! Functions in this crate, like [`TorClient::create_bootstrapped`], will expect a type
-//! that implements [`tor_rtcompat::Runtime`], which can be obtained:
-//!
-//! - for Tokio:
-//! - by calling [`tor_rtcompat::tokio::PreferredRuntime::current()`], if a
-//! Tokio reactor is already running
-//! - by calling [`tor_rtcompat::tokio::PreferredRuntime::create()`], to start
-//! a new reactor if one is not already running
-//! - as above, but explicitly specifying
-//! [`TokioNativeTlsRuntime`](tor_rtcompat::tokio::TokioNativeTlsRuntime) or
-//! [`TokioRustlsRuntime`](tor_rtcompat::tokio::TokioRustlsRuntime) in place
-//! of `PreferredRuntime`.
-//! - for async-std:
-//! - by calling [`tor_rtcompat::async_std::PreferredRuntime::current()`],
-//! which will create a runtime or 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`.
+//! The backend Arti uses for TCP connections ([`tor_rtcompat::TcpProvider`]) and for
+//! creating TLS sessions ([`tor_rtcompat::TlsProvider`]) is also configurable using
+//! this crate. This can be used to embed Arti in custom environments where you want
+//! lots of control over how it uses the network.
//!
+//! [**View the `tor_rtcompat` crate documentation**](tor_rtcompat) for more about these features.
//!
//! # Feature flags
//!
-//! `tokio` -- (Default) Build with support for the Tokio backend.
-//!
-//! `async-std` -- Build with support for the `async_std` backend.
-//!
-//! `static` -- Link with static versions of your system dependencies, including
-//! sqlite and/or openssl.
-//!
-//! `experimental-api` -- Build with experimental, unstable API support. Note
-//! that these APIs are NOT covered by semantic versioning guarantees: we might
-//! break them or remove them between patch versions.
-//!
-//! `error_detail` -- expose the `arti_client::Error` inner error type. Note
-//! that this API is NOT covered by semantic versioning guarantees: we might
-//! break it between patch versions.
+//! * `tokio` (default) -- build with [Tokio](https://tokio.rs/) support
+//! * `native-tls` (default) -- build with the [native-tls](https://github.com/sfackler/rust-native-tls)
+//! crate for TLS support
+//! * `async-std` -- build with [async-std](https://async.rs/) support
+//! * `rustls` -- build with the [rustls](https://github.com/rustls/rustls) crate for TLS support
+//! * `static` -- link with static versions of Arti's system dependencies, like SQLite and
+//! OpenSSL
+//! * `experimental-api` -- Build with experimental, unstable API support. Note
+//! that these APIs are NOT covered by semantic versioning guarantees: we might
+//! break them or remove them between patch versions.
+//! * `error_detail` -- expose the `arti_client::Error` inner error type. Note
+//! that this API is NOT covered by semantic versioning guarantees: we might
+//! break it between patch versions.
+//!
+//! Note that flags `tokio`, `native-tls`, `async-std`, `rustls` and `static` will enable
+//! the flags of the same name on the [`tor_rtcompat`] crate.
#![deny(missing_docs)]
#![warn(noop_method_call)]
diff --git a/crates/arti-hyper/examples/hyper.rs b/crates/arti-hyper/examples/hyper.rs
index 2f72a3cb5..090254d65 100644
--- a/crates/arti-hyper/examples/hyper.rs
+++ b/crates/arti-hyper/examples/hyper.rs
@@ -5,7 +5,6 @@ use anyhow::Result;
use arti_client::{TorClient, TorClientConfig};
use hyper::Body;
use std::convert::TryInto;
-use tor_rtcompat::tokio::TokioNativeTlsRuntime;
#[tokio::main]
async fn main() -> Result<()> {
@@ -27,12 +26,10 @@ async fn main() -> Result<()> {
// to a conventional place depending on operating system (for example, ~/.local/share/arti
// on Linux platforms)
let config = TorClientConfig::default();
- // Arti needs an async runtime handle to spawn async tasks.
- let rt: TokioNativeTlsRuntime = tokio::runtime::Handle::current().into();
// 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.)
- let tor_client = TorClient::create_bootstrapped(rt, config).await?;
+ let tor_client = TorClient::create_bootstrapped(config).await?;
// The `ArtiHttpConnector` lets us make HTTP requests via the Tor network.
let tor_connector = ArtiHttpConnector::new(tor_client);
diff --git a/crates/arti/src/main.rs b/crates/arti/src/main.rs
index 46d1b2580..e840fa05b 100644
--- a/crates/arti/src/main.rs
+++ b/crates/arti/src/main.rs
@@ -115,7 +115,7 @@ async fn run<R: Runtime>(
// for bootstrap to complete, rather than getting errors.
use arti_client::BootstrapBehavior::OnDemand;
use futures::FutureExt;
- let client = TorClient::builder(runtime.clone())
+ let client = TorClient::with_runtime(runtime.clone())
.config(client_config)
.bootstrap_behavior(OnDemand)
.create_unbootstrapped()?;
diff --git a/crates/tor-rtcompat/src/lib.rs b/crates/tor-rtcompat/src/lib.rs
index 9f8a3a446..bd655f5e7 100644
--- a/crates/tor-rtcompat/src/lib.rs
+++ b/crates/tor-rtcompat/src/lib.rs
@@ -69,7 +69,7 @@
//! [`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 `current()`.
//!
//! # Advanced usage: implementing runtimes yourself
@@ -244,18 +244,30 @@ crate::opaque::implement_opaque_runtime! {
any(feature = "async-std", feature = "tokio")
))]
impl PreferredRuntime {
- /// Create a [`PreferredRuntime`] from the currently running asynchronous runtime.
+ /// Obtain a [`PreferredRuntime`] from the currently running asynchronous runtime.
/// Generally, this is what you want.
///
- /// # Limitations
+ /// This tries to get a handle to a currently running asynchronous runtime, and
+ /// wraps it; the returned [`PreferredRuntime`] isn't the same thing as the
+ /// asynchronous runtime object itself (e.g. `tokio::runtime::Runtime`).
///
- /// If the `tor-rtcompat` crate was compiled with `tokio` support,
- /// this function will never return an `async_std` runtime.
+ /// # Panics
+ ///
+ /// When `tor-rtcompat` is compiled with the `tokio` feature enabled
+ /// (regardless of whether the `async-std` feature is also enabled),
+ /// panics if called outside of Tokio runtime context.
+ /// See [`tokio::runtime::Handle::current`].
///
/// # Usage notes
///
/// Once you have a runtime returned by this function, you should
/// just create more handles to it via [`Clone`].
+ ///
+ /// # Limitations
+ ///
+ /// If the `tor-rtcompat` crate was compiled with `tokio` support,
+ /// this function will never return a runtime based on `async_std`.
+ ///
//
// ## Note to Arti developers
//
@@ -275,7 +287,7 @@ impl PreferredRuntime {
/// Generally you should call this function at most 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
+ /// Tokio users may want to avoid this function and instead obtain a runtime using
/// [`PreferredRuntime::current`]: this function always _builds_ a runtime,
/// and if you already have a runtime, that isn't what you want with Tokio.
///