avalanche-types 0.0.54

Avalanche types
Documentation
use std::io::{Error, ErrorKind};

use prost::bytes::Bytes;
use tonic::transport::Channel;

/// Client which interacts with gRPC HTTP service
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"),
        ))
    }

    /// http client takes an http request and sends to server.  Does not support websockets.
    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())
    }
}

/// convert from [http::Request] to [avalanche_proto::http::HandleSimpleHttpRequest]
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,
    })
}

/// convert from [avalanche_proto::http::HandleSimpleHttpResponse] to [http::Response]
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
}

/// converts [http::HeaderMap] to a vec of elements that avalanche proto can use
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)
}