use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use hyper_util::rt::TokioIo;
use tokio::net::TcpStream;
use tower::Service;
use crate::tonic::naming::{BoxError, TargetResolver};
#[derive(Clone)]
pub struct TargetConnector {
inner: Arc<Inner>,
}
struct Inner {
resolver: Arc<dyn TargetResolver>,
}
impl TargetConnector {
pub fn new(resolver: Arc<dyn TargetResolver>) -> Self {
Self {
inner: Arc::new(Inner { resolver }),
}
}
}
impl Service<http::Uri> for TargetConnector {
type Response = TokioIo<TcpStream>;
type Error = BoxError;
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
fn poll_ready(&mut self, _: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, _placeholder_uri: http::Uri) -> Self::Future {
let inner = self.inner.clone();
Box::pin(async move {
let target = inner.resolver.resolve().await?;
let stream = TcpStream::connect((target.host.as_str(), target.port))
.await
.map_err(|e| Box::new(e) as BoxError)?;
Ok(TokioIo::new(stream))
})
}
}
pub struct TargetConnectorBuilder {
resolver: Option<Arc<dyn TargetResolver>>,
}
impl TargetConnectorBuilder {
pub fn new() -> Self {
Self { resolver: None }
}
pub fn resolver(mut self, r: Arc<dyn TargetResolver>) -> Self {
self.resolver = Some(r);
self
}
pub fn build(self) -> TargetConnector {
let resolver = self
.resolver
.expect("TargetConnectorBuilder::resolver is required");
TargetConnector::new(resolver)
}
}
impl Default for TargetConnectorBuilder {
fn default() -> Self {
Self::new()
}
}