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,
};
#[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,
{
#[inline]
pub const fn new(client: C, drsr: DRSR) -> Self {
Self { client, drsr, enc_buffer: Vector::new() }
}
#[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)
}
#[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(())
}
}