pajamax 0.4.0

Fast gRPC server framework in synchronous mode.
Documentation
use std::io::Write;
use std::net::TcpStream;
use std::sync::{Arc, Mutex};

use crate::config::Config;
use crate::hpack_encoder::Encoder;
use crate::http2;
use crate::macros::*;
use crate::Response;

pub struct ResponseEnd {
    c: Arc<Mutex<TcpStream>>,
    req_count: usize,
    hpack_encoder: Encoder,
    output: Vec<u8>,

    max_flush_requests: usize,
    max_flush_size: usize,
}

impl ResponseEnd {
    pub fn new(c: Arc<Mutex<TcpStream>>, config: &Config) -> Self {
        Self {
            c,
            req_count: 0,
            hpack_encoder: Encoder::new(),
            output: Vec::with_capacity(config.max_flush_size),

            max_flush_requests: config.max_flush_requests,
            max_flush_size: config.max_flush_size,
        }
    }

    // build response to output buffer
    // Used in local-mode.
    pub fn build<Reply>(
        &mut self,
        stream_id: u32,
        response: Response<Reply>,
    ) -> Result<(), std::io::Error>
    where
        Reply: prost::Message,
    {
        match response {
            Ok(reply) => {
                http2::build_response(
                    stream_id,
                    |output| reply.encode(output).unwrap(),
                    &mut self.hpack_encoder,
                    &mut self.output,
                );
            }
            Err(status) => {
                http2::build_status(stream_id, status, &mut self.hpack_encoder, &mut self.output);
            }
        }

        self.update()
    }

    // build response to output buffer
    // Used in dispatch-mode. We use dynamic-dispatch `dyn` here
    // to accept different response from multiple services.
    pub fn build_box(
        &mut self,
        stream_id: u32,
        response: Response<Box<dyn http2::ReplyEncode>>,
    ) -> Result<(), std::io::Error> {
        match response {
            Ok(reply) => {
                http2::build_response(
                    stream_id,
                    |output| reply.encode(output).unwrap(),
                    &mut self.hpack_encoder,
                    &mut self.output,
                );
            }
            Err(status) => {
                http2::build_status(stream_id, status, &mut self.hpack_encoder, &mut self.output);
            }
        }

        self.update()
    }

    fn update(&mut self) -> Result<(), std::io::Error> {
        self.req_count += 1;

        if self.req_count >= self.max_flush_requests || self.output.len() >= self.max_flush_size {
            self.flush()
        } else {
            Ok(())
        }
    }

    // flush the output buffer
    pub fn flush(&mut self) -> Result<(), std::io::Error> {
        if self.output.len() == 0 {
            return Ok(());
        }

        trace!(
            "flush response count:{} len:{}",
            self.req_count,
            self.output.len()
        );

        self.c.lock().unwrap().write_all(&self.output)?;

        self.output.clear();
        self.req_count = 0;
        Ok(())
    }

    pub fn window_update(&mut self, data_len: usize) {
        if data_len > 0 {
            http2::build_window_update(data_len, &mut self.output);
        }
    }
}