use std::io; use std::net::IpAddr; use distant_auth::Verifier; use serde::de::DeserializeOwned; use serde::Serialize; use crate::common::{PortRange, TcpListener}; use crate::server::{Server, ServerConfig, ServerHandler, TcpServerRef}; pub struct TcpServerBuilder(Server); impl Server { /// Consume [`Server`] and produce a builder for a TCP variant. pub fn into_tcp_builder(self) -> TcpServerBuilder { TcpServerBuilder(self) } } impl Default for TcpServerBuilder<()> { fn default() -> Self { Self(Server::new()) } } impl TcpServerBuilder { pub fn config(self, config: ServerConfig) -> Self { Self(self.0.config(config)) } pub fn handler(self, handler: U) -> TcpServerBuilder { TcpServerBuilder(self.0.handler(handler)) } pub fn verifier(self, verifier: Verifier) -> Self { Self(self.0.verifier(verifier)) } } impl TcpServerBuilder where T: ServerHandler + Sync + 'static, T::Request: DeserializeOwned + Send + Sync + 'static, T::Response: Serialize + Send + 'static, { pub async fn start

(self, addr: IpAddr, port: P) -> io::Result where P: Into + Send, { let listener = TcpListener::bind(addr, port).await?; let port = listener.port(); let inner = self.0.start(listener)?; Ok(TcpServerRef { addr, port, inner }) } } #[cfg(test)] mod tests { use std::net::{Ipv6Addr, SocketAddr}; use async_trait::async_trait; use distant_auth::DummyAuthHandler; use test_log::test; use super::*; use crate::client::Client; use crate::common::Request; use crate::server::RequestCtx; pub struct TestServerHandler; #[async_trait] impl ServerHandler for TestServerHandler { type Request = String; type Response = String; async fn on_request(&self, ctx: RequestCtx) { // Echo back what we received ctx.reply.send(ctx.request.payload.to_string()).unwrap(); } } #[test(tokio::test)] async fn should_invoke_handler_upon_receiving_a_request() { let server = TcpServerBuilder::default() .handler(TestServerHandler) .verifier(Verifier::none()) .start(IpAddr::V6(Ipv6Addr::LOCALHOST), 0) .await .expect("Failed to start TCP server"); let mut client: Client = Client::tcp(SocketAddr::from((server.ip_addr(), server.port()))) .auth_handler(DummyAuthHandler) .connect() .await .expect("Client failed to connect"); let response = client .send(Request::new("hello".to_string())) .await .expect("Failed to send message"); assert_eq!(response.payload, "hello"); } }