use std::io::{Error, ErrorKind};
use prost::bytes::Bytes;
use tonic::transport::Channel;
pub struct Client {
inner: avalanche_proto::http::http_client::HttpClient<Channel>,
}
impl Client {
pub fn new(client_conn: Channel) -> Box<dyn crate::rpcchainvm::http::Handler + Send + Sync> {
Box::new(Client {
inner: avalanche_proto::http::http_client::HttpClient::new(client_conn),
})
}
}
#[tonic::async_trait]
impl crate::rpcchainvm::http::Handler for Client {
async fn serve_http(
&mut self,
_req: http::Request<String>,
) -> std::io::Result<http::Response<String>> {
Err(std::io::Error::new(
ErrorKind::Other,
format!("not implemented"),
))
}
async fn serve_http_simple(
&mut self,
req: http::Request<String>,
) -> std::io::Result<http::Response<String>> {
let req = get_http_simple_request(req)?;
let resp = self.inner.handle_simple(req).await.map_err(|e| {
Error::new(
ErrorKind::Other,
format!("handle simple request failed: {:?}", e),
)
})?;
get_http_response(resp.into_inner())
}
}
fn get_http_simple_request(
req: http::Request<String>,
) -> std::io::Result<avalanche_proto::http::HandleSimpleHttpRequest> {
let headers = convert_to_proto_headers(req.headers())?;
Ok(avalanche_proto::http::HandleSimpleHttpRequest {
method: req.method().to_string(),
url: req.uri().to_string(),
body: Bytes::from(req.body().as_bytes().to_vec()),
headers: headers,
})
}
fn get_http_response(
resp: avalanche_proto::http::HandleSimpleHttpResponse,
) -> std::io::Result<http::Response<String>> {
let mut http_resp = http::Response::builder().status(resp.code as u16);
for header in resp.headers.into_iter() {
http_resp = http_resp.header(header.key, header.values.concat());
}
let body = String::from_utf8_lossy(resp.body.as_ref()).to_string();
let http_resp = http_resp.body(body).map_err(|e| {
Error::new(
ErrorKind::Other,
format!("failed to generate http response {:?}", e),
)
});
http_resp
}
fn convert_to_proto_headers(
headers: &http::HeaderMap<http::HeaderValue>,
) -> std::io::Result<Vec<avalanche_proto::http::Element>> {
let mut vec_headers: Vec<avalanche_proto::http::Element> =
Vec::with_capacity(headers.keys_len());
for (key, value) in headers.into_iter() {
let element = avalanche_proto::http::Element {
key: key.to_string(),
values: vec![String::from_utf8_lossy(value.as_bytes()).to_string()],
};
vec_headers.push(element);
}
Ok(vec_headers)
}