reqwest_proxy 0.1.7

Seamlessly proxy reqwest traffic through Shadowsocks, Hysteria2, and more. / 通过 Shadowsocks、Hysteria2 等多种协议无缝代理 reqwest 流量。
use std::{
  io,
  sync::Arc,
  task::{self, Poll},
};

use ::hysteria2::{DuplexStream, config::Config, connect};
use hyper::Uri;
use hyper_util::rt::TokioIo;
use tower::Service;

use crate::conn::hysteria2::ConnFuture;
use crate::{middleware::ProxyMiddleware, stream::Stream};

pub const SCHEME: &str = "hysteria2";
pub type StreamType = Stream<DuplexStream>;
pub type StreamEnumType = StreamType;

#[derive(Clone)]
pub struct Conn {
  conf: Arc<Config>,
}

impl Conn {
  pub fn new(url: &str) -> crate::Result<Self> {
    Ok(Self {
      conf: Arc::new(Config::from_url(url)?),
    })
  }
}

impl Service<Uri> for Conn {
  type Response = Stream<DuplexStream>;
  type Error = io::Error;
  type Future = ConnFuture;

  fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> Poll<Result<(), Self::Error>> {
    Poll::Ready(Ok(()))
  }

  fn call(&mut self, uri: Uri) -> Self::Future {
    let conf = self.conf.clone();
    let fut = Box::pin(async move {
      let (host, port) = uri_to_host_port::parse(&uri).map_err(io::Error::other)?;
      let client = connect(&conf).await.map_err(io::Error::other)?;
      let stream = client
        .tcp_connect(format!("{host}:{port}"))
        .await
        .map_err(io::Error::other)?;
      Ok(Stream(TokioIo::new(stream)))
    });
    ConnFuture { fut }
  }
}

pub fn from_url(url: &str) -> crate::Result<ProxyMiddleware<Conn>> {
  let connector = Conn::new(url)?;
  Ok(ProxyMiddleware::new(connector))
}