Skip to main content

karyon_jsonrpc/client/http/
h1.rs

1//! HTTP/1.1 client over smol. No connection pooling: each request
2//! opens a fresh TCP connection.
3
4use std::net::SocketAddr;
5
6use bytes::Bytes;
7use http_body_util::Full;
8use hyper::Request;
9
10use karyon_core::{async_runtime::net::TcpStream, async_util::TaskGroup};
11use karyon_net::Endpoint;
12use smol_hyper::rt::FuturesIo;
13
14use crate::{
15    client::http::parse_response,
16    error::{Error, Result},
17    message,
18};
19
20pub(super) async fn send(
21    endpoint: &Endpoint,
22    msg: serde_json::Value,
23    task_group: &TaskGroup,
24) -> Result<message::Response> {
25    let body = serde_json::to_vec(&msg)?;
26
27    // Resolve the endpoint to a SocketAddr (handles both literal IPs
28    // and domain names via the system DNS).
29    let addr = SocketAddr::try_from(endpoint.clone())?;
30
31    let stream = TcpStream::connect(addr).await?;
32    let io = FuturesIo::new(stream);
33
34    let (mut sender, conn) = hyper::client::conn::http1::handshake(io)
35        .await
36        .map_err(|e| Error::HttpError(e.to_string()))?;
37
38    // hyper's HTTP/1.1 client splits I/O from request building: the
39    // returned `conn` future drives the wire protocol and must be
40    // polled concurrently, otherwise `sender` blocks forever. Spawn
41    // it via the Client task_group so it gets cancelled on stop.
42    task_group.spawn(driver_task(conn));
43
44    let req = Request::post(endpoint.to_string())
45        .header("Content-Type", "application/json")
46        .body(Full::new(Bytes::from(body)))
47        .map_err(|e| Error::HttpError(e.to_string()))?;
48
49    let response = sender
50        .send_request(req)
51        .await
52        .map_err(|e| Error::HttpError(e.to_string()))?;
53
54    parse_response(response).await
55}
56
57async fn driver_task<T>(conn: hyper::client::conn::http1::Connection<T, Full<Bytes>>)
58where
59    T: hyper::rt::Read + hyper::rt::Write + Unpin + Send + 'static,
60{
61    if let Err(err) = conn.await {
62        log::error!("HTTP client connection error: {err}");
63    }
64}