karyon_jsonrpc/client/http/
h1.rs1#[cfg(feature = "smol")]
10use std::net::SocketAddr;
11
12use bytes::Bytes;
13use http_body_util::Full;
14use hyper::{
15 header::{CONTENT_TYPE, HOST},
16 Request,
17};
18
19#[cfg(feature = "smol")]
20use hyper::{
21 client::conn::http1::{handshake, Connection},
22 rt::{Read, Write},
23};
24#[cfg(feature = "tokio")]
25use hyper_util::client::legacy::{connect::HttpConnector, Client as HyperClient};
26#[cfg(feature = "smol")]
27use log::error;
28#[cfg(feature = "smol")]
29use smol_hyper::rt::FuturesIo;
30
31#[cfg(feature = "smol")]
32use karyon_core::{async_runtime::net::TcpStream, async_util::TaskGroup};
33use karyon_net::Endpoint;
34
35use crate::{
36 client::http::{parse_response, HttpConfig},
37 codec::{encode_msg, JsonRpcCodec},
38 error::{Error, Result},
39 message,
40};
41
42#[cfg(feature = "smol")]
43pub(super) async fn send<C: JsonRpcCodec>(
44 endpoint: &Endpoint,
45 config: &HttpConfig,
46 msg: serde_json::Value,
47 task_group: &TaskGroup,
48 codec: &C,
49) -> Result<message::Response> {
50 let req = build_request(endpoint, config, &msg, codec)?;
51
52 let addr = SocketAddr::try_from(endpoint.clone())?;
55
56 let stream = TcpStream::connect(addr).await?;
57 let io = FuturesIo::new(stream);
58
59 let (mut sender, conn) = handshake(io)
60 .await
61 .map_err(|e| Error::HttpError(e.to_string()))?;
62
63 task_group.spawn(driver_task(conn));
68
69 let response = sender
70 .send_request(req)
71 .await
72 .map_err(|e| Error::HttpError(e.to_string()))?;
73
74 parse_response(response, codec).await
75}
76
77#[cfg(feature = "tokio")]
78pub(super) async fn send<C: JsonRpcCodec>(
79 client: &HyperClient<HttpConnector, Full<Bytes>>,
80 endpoint: &Endpoint,
81 config: &HttpConfig,
82 msg: serde_json::Value,
83 codec: &C,
84) -> Result<message::Response> {
85 let req = build_request(endpoint, config, &msg, codec)?;
86
87 let response = client
88 .request(req)
89 .await
90 .map_err(|e| Error::HttpError(e.to_string()))?;
91
92 parse_response(response, codec).await
93}
94
95fn build_request<C: JsonRpcCodec>(
97 endpoint: &Endpoint,
98 config: &HttpConfig,
99 msg: &serde_json::Value,
100 codec: &C,
101) -> Result<Request<Full<Bytes>>> {
102 let body = encode_msg(codec, msg)?;
103
104 let mut req =
105 Request::post(endpoint.to_string()).header(CONTENT_TYPE, config.content_type.as_str());
106 if let Some(host) = &config.host {
107 req = req.header(HOST, host);
108 }
109 req.body(Full::new(body))
110 .map_err(|e| Error::HttpError(e.to_string()))
111}
112
113#[cfg(feature = "smol")]
114async fn driver_task<T>(conn: Connection<T, Full<Bytes>>)
115where
116 T: Read + Write + Unpin + Send + 'static,
117{
118 if let Err(err) = conn.await {
119 error!("HTTP client connection error: {err}");
120 }
121}