wtx 0.45.0

A collection of different transport implementations and related tools focused primarily on web technologies.
Documentation
use crate::{
  codec::{
    Decode, DecodeWrapper, Encode, GenericCodec,
    protocol::{VerbatimDecoder, VerbatimEncoder},
  },
  collection::Vector,
  grpc::serialize,
  http::{
    Header, Headers, HttpClient, KnownHeaderName, ReqBuilder, ReqResBuffer, Response,
    WTX_USER_AGENT,
  },
  http2::{Http2, Http2Buffer},
  misc::{LeaseMut, SingleTypeStorage, UriRef},
  stream::StreamWriter,
};

/// Performs requests to gRPC servers.
#[derive(Debug)]
pub struct GrpcClient<C, DRSR> {
  client: C,
  drsr: DRSR,
  enc_buffer: Vector<u8>,
}

impl<C, DRSR, HB, SW> GrpcClient<C, DRSR>
where
  C: LeaseMut<Http2<HB, SW, true>> + SingleTypeStorage<Item = (HB, SW)>,
  HB: LeaseMut<Http2Buffer>,
  SW: StreamWriter,
{
  /// Constructor
  #[inline]
  pub const fn new(client: C, drsr: DRSR) -> Self {
    Self { client, drsr, enc_buffer: Vector::new() }
  }

  /// Deserialize From Response Bytes
  #[inline]
  pub fn des_from_res_bytes<'de, T>(&mut self, bytes: &mut &'de [u8]) -> crate::Result<T>
  where
    VerbatimDecoder<T>: for<'drsr> Decode<'de, GenericCodec<&'drsr mut DRSR, &'drsr mut DRSR>>,
  {
    let elem = if let [_, _, _, _, _, elem @ ..] = bytes { elem } else { &[] };
    Ok(VerbatimDecoder::decode(&mut DecodeWrapper::new(elem, &mut self.drsr))?.data)
  }

  /// Send Unary Request
  ///
  /// Builds a valid unary gRPC request and awaits for a raw response.
  ///
  /// It is necessary to call [`Self::des_from_res_bytes`] to create the corresponding decoded element.
  #[inline]
  pub async fn send_unary_req<T>(
    &mut self,
    data: T,
    mut rrb: ReqResBuffer,
    uri: UriRef<'_>,
  ) -> crate::Result<Response<ReqResBuffer>>
  where
    VerbatimEncoder<T>: for<'drsr> Encode<GenericCodec<&'drsr mut DRSR, &'drsr mut DRSR>>,
  {
    rrb.clear();
    serialize(&mut rrb.body, VerbatimEncoder { data }, &mut self.drsr)?;
    Self::push_headers(&mut rrb.headers)?;
    let rrd = (rrb.body.as_ref(), &rrb.headers, uri);
    let rb = ReqBuilder::post(rrd);
    let req_id = self.client.lease_mut().send_req(&mut self.enc_buffer, rb).await?;
    let res = self.client.lease_mut().recv_res(rrb, req_id).await?;
    Ok(Response::http2(res.rrd, res.status_code))
  }

  #[inline]
  fn push_headers(headers: &mut Headers) -> crate::Result<()> {
    headers.push_from_iter_many([
      Header::from_name_and_value(
        KnownHeaderName::ContentType.into(),
        ["application/grpc"].into_iter(),
      ),
      Header::from_name_and_value(KnownHeaderName::Te.into(), ["trailers"].into_iter()),
      Header::from_name_and_value(KnownHeaderName::UserAgent.into(), [WTX_USER_AGENT].into_iter()),
    ])?;
    Ok(())
  }
}