Rust异步运行时兼容库tor-rtcompat的使用,实现跨Tokio和async-std运行时的无缝切换

Rust异步运行时兼容库tor-rtcompat的使用,实现跨Tokio和async-std运行时的无缝切换

概述

Rust对异步编程的支持很强大,但还不够成熟:有多个强大的运行时可供使用,但它们没有暴露一致的接口。

futures API抽象了这些运行时库之间的许多差异,但仍有一些领域尚未存在标准API,包括:

  • 网络编程
  • 时间和延迟
  • 启动新任务
  • 阻塞直到任务完成

此外,futures提供的AsyncReadAsyncWrite traits与tokio提供的不同,需要使用兼容性包装器。

使用tor-rtcompat

tor-rtcompat crate提供了几个封装不同运行时能力的traits:

  • ToplevelBlockOn - 运行时可以阻塞在顶级future上
  • SleepProvider - 运行时可以创建定时器future
  • CoarseTimeProvider - 运行时提供单调时钟
  • NetStreamProvider<std::net::SocketAddr> - 运行时可以建立和接收TCP连接
  • TlsProvider - 运行时可以建立TLS连接

完整示例代码

首先需要添加依赖到Cargo.toml:

[dependencies]
tor-rtcompat = { version = "0.3", features = ["tokio", "async-std", "native-tls"] }
tokio = { version = "1.0", features = ["full"] }
async-std = "1.0"

然后是一个完整的示例展示如何在不同运行时之间切换:

use tor_rtcompat::{PreferredRuntime, Runtime};
use std::time::Duration;

// 通用的异步函数,可在任何Runtime下运行
async fn common_async_task(runtime: impl Runtime) {
    println!("Starting async task...");
    
    // 使用运行时提供的sleep功能
    runtime.sleep(Duration::from_secs(1)).await;
    
    println!("Task completed after 1 second");
}

// 使用Tokio运行时
#[tokio::main]
async fn tokio_example() {
    let runtime = PreferredRuntime::current().unwrap();
    common_async_task(runtime).await;
}

// 使用async-std运行时
#[async_std::main]
async fn async_std_example() {
    let runtime = PreferredRuntime::current().unwrap();
    common_async_task(runtime).await;
}

// 显式创建运行时
fn explicit_runtime_example() {
    // 创建Tokio运行时(使用native-tls)
    let runtime = tor_rtcompat::tokio::TokioNativeTlsRuntime::create().unwrap();
    
    runtime.block_on(async {
        common_async_task(runtime).await;
    });
}

// 主函数选择运行不同的示例
fn main() {
    // 取消注释想要运行的示例
    
    // tokio_example();
    // async_std_example();
    explicit_runtime_example();
}

Cargo features配置

在Cargo.toml中配置features:

# 默认使用Tokio + native-tls
tor-rtcompat = { version = "0.3", features = ["tokio", "native-tls"] }

# 或者使用async-std + rustls
tor-rtcompat = { version = "0.3", features = ["async-std", "rustls"] }

# 或者全部启用
tor-rtcompat = { version = "0.3", features = ["tokio", "async-std", "native-tls", "rustls"] }

1 回复

以下是基于您提供的内容整理的tor-rtcompat完整示例演示:

基础TCP服务器示例(包含运行时选择)

use tor_rtcompat::{Runtime, TcpListener, TcpStream};
use std::io::{self, Write};

// 处理TCP连接的异步函数
async fn handle_connection(mut stream: TcpStream) -> io::Result<()> {
    // 模拟处理逻辑
    stream.write_all(b"HTTP/1.1 200 OK\r\n\r\nHello from tor-rtcompat!").await?;
    Ok(())
}

// 通用的TCP服务器实现
async fn run_server<R: Runtime>(rt: R) -> io::Result<()> {
    let listener = rt.listen("127.0.0.1:8080").await?;
    println!("Server running on 127.0.0.1:8080");
    
    loop {
        let (stream, _) = listener.accept().await?;
        rt.spawn(async move {
            if let Err(e) = handle_connection(stream).await {
                eprintln!("Connection error: {}", e);
            }
        });
    }
}

// 根据选择的运行时启动服务器
fn main() -> io::Result<()> {
    // 使用Tokio运行时
    #[cfg(feature = "tokio")]
    {
        use tor_rtcompat::tokio::PreferredRuntime;
        let rt = PreferredRuntime::new()?;
        rt.block_on(run_server(rt))
    }
    
    // 使用async-std运行时
    #[cfg(feature = "async-std")]
    {
        use tor_rtcompat::async_std::PreferredRuntime;
        let rt = PreferredRuntime::new()?;
        rt.block_on(run_server(rt))
    }
}

定时器与TCP客户端示例

use tor_rtcompat::{Runtime, Sleep, TcpStream};
use std::time::Duration;

// 带超时的TCP客户端
async fn fetch_with_timeout<R: Runtime>(rt: R) -> io::Result<()> {
    // 设置1秒超时
    let sleep = Sleep::new(&rt, Duration::from_secs(1));
    
    // 尝试连接
    let connect_fut = TcpStream::connect(&rt, "example.com:80");
    
    tokio::select! {
        _ = sleep => {
            eprintln!("Connection timed out");
            Err(io::Error::new(io::ErrorKind::TimedOut, "Connection timeout"))
        }
        res = connect_fut => {
            let mut stream = res?;
            println!("Connected successfully!");
            // 这里可以添加实际的请求逻辑
            Ok(())
        }
    }
}

// 运行时特征检测示例
fn check_runtime<R: Runtime>(rt: &R) {
    println!("Runtime supports I/O: {}", rt.supports_io());
    println!("Runtime supports time: {}", rt.supports_time());
}

Cargo.toml配置示例

[package]
name = "tor-rtcompat-demo"
version = "0.1.0"
edition = "2021"

# 选择其中一个运行时特性
[dependencies]
tor-rtcompat = { version = "0.3", features = ["tokio"] }
# 或者
# tor-rtcompat = { version = "0.3", features = ["async-std"] }

# 根据选择的运行时添加相应依赖
[features]
default = ["tokio"]
tokio = ["tor-rtcompat/tokio"]
async-std = ["tor-rtcompat/async-std"]

自定义运行时适配器示例

use tor_rtcompat::{Runtime, Sleep, TcpListener, TcpStream};
use std::time::Duration;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};

struct DummyRuntime;

impl Runtime for DummyRuntime {
    fn sleep(&self, duration: Duration) -> Sleep {
        Sleep::new(self, duration)
    }
    
    fn listen(&self, addr: &str) -> Pin<Box<dyn Future<Output = io::Result<TcpListener>> + Send + 'static>> {
        Box::pin(async move {
            Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
        })
    }
    
    fn spawn(&self, future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>) {
        // 简单的spawn实现
        tokio::spawn(future);
    }
    
    fn supports_io(&self) -> bool { false }
    fn supports_time(&self) -> bool { true }
}

测试建议

#[cfg(test)]
mod tests {
    use super::*;
    
    #[cfg(feature = "tokio")]
    #[tokio::test]
    async fn test_with_tokio() {
        let rt = tor_rtcompat::tokio::PreferredRuntime::new().unwrap();
        // 测试代码...
    }
    
    #[cfg(feature = "async-std")]
    #[async_std::test]
    async fn test_with_async_std() {
        let rt = tor_rtcompat::async_std::PreferredRuntime::new().unwrap();
        // 测试代码...
    }
}

这些示例展示了tor-rtcompat的核心用法,包括:

  1. 基础TCP服务器实现
  2. 运行时无关的异步操作
  3. 跨运行时的定时器使用
  4. 自定义运行时适配器
  5. 多运行时测试方案

实际使用时,请根据项目需求选择合适的运行时,并在Cargo.toml中配置相应的feature。

回到顶部