pajamax 0.4.0

Fast gRPC server framework in synchronous mode.
Documentation
use std::net::ToSocketAddrs;
use std::sync::Arc;
use std::time::Duration;

use crate::PajamaxService;

/// Configured server. Used to start the server.
///
/// Generated by [`Config::add_service`].
///
/// # Examples
///
/// ```
/// pajamax::Config::new()
///     .max_concurrent_connections(2000)
///     .add_service(GreeterServer::new(greeter))   // return ConfigedServer
///     .add_service(Greeter2Server::new(greeter2)) // add more services
///     .serve(addr)  // start the server!
///     .unwrap();
/// ```
pub struct ConfigedServer {
    pub(crate) config: Config,
    pub(crate) services: Vec<Arc<dyn PajamaxService + Send + Sync + 'static>>,
}

impl ConfigedServer {
    /// Add more services.
    pub fn add_service<S>(mut self, svc: S) -> Self
    where
        S: crate::PajamaxService + Send + Sync + 'static,
    {
        self.services.push(Arc::new(svc));
        self
    }

    /// Start the server!
    pub fn serve<A>(self, addr: A) -> std::io::Result<()>
    where
        A: ToSocketAddrs,
    {
        crate::connection::serve_with_config(self.services, self.config, addr)
    }
}

/// Configure the server.
///
/// Generally you should:
///
/// 1. first call the [`Self::new`] to create a configuration instance,
/// 2. then call some methods to configure options,
/// 3. finally call [`Self::add_service`] to add the first service and get a [`ConfigedServer`].
///
/// # Examples
///
/// ```
/// pajamax::Config::new()
///     .max_concurrent_connections(2000) // config some option
///     .add_service(GreeterServer::new(greeter))  // return ConfigedServer
///     .add_service(Greeter2Server::new(greeter2))
///     .serve(addr)
///     .unwrap();
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Config {
    pub(crate) max_concurrent_connections: usize,
    pub(crate) max_concurrent_streams: usize,
    pub(crate) max_frame_size: usize,
    pub(crate) max_flush_requests: usize,
    pub(crate) max_flush_size: usize,
    pub(crate) idle_timeout: Duration,
    pub(crate) write_timeout: Duration,
}

impl Config {
    /// Create a default configuration.
    pub fn new() -> Self {
        Self {
            max_concurrent_connections: 100,
            max_concurrent_streams: 1000,
            max_frame_size: 16 * 1024,
            max_flush_requests: 50,
            max_flush_size: 15000,
            idle_timeout: Duration::from_secs(60),
            write_timeout: Duration::from_secs(10),
        }
    }

    /// Since we create 1 (in Local mode) or 2 (in Dispatch mode) threads
    /// for each connection, so do not set this too big.
    ///
    /// Besides, the less connections, the high concurrent streams per
    /// connection, the more efficient batch processing. So you'd better
    /// keep the concurrent connections as low as possible.
    ///
    /// Default: 100
    pub fn max_concurrent_connections(self, n: usize) -> Self {
        Self {
            max_concurrent_connections: n,
            ..self
        }
    }

    /// Limit for each connection.
    ///
    /// We just send this HTTP2 setting to clients and hope them respect it.
    /// We do not check or limit this actually for simplicity.
    /// This is Ok because pajamax should be used only by internal service
    /// whose clients are also insiders but not external users.
    ///
    /// Default: 1000
    pub fn max_concurrent_streams(self, n: usize) -> Self {
        Self {
            max_concurrent_streams: n,
            ..self
        }
    }

    /// Default: 16 * 1024
    pub fn max_frame_size(self, n: usize) -> Self {
        Self {
            max_frame_size: n,
            ..self
        }
    }

    /// Flush the response direction at most this number requests.
    ///
    /// Default: 50
    pub fn max_flush_requests(self, n: usize) -> Self {
        Self {
            max_flush_requests: n,
            ..self
        }
    }

    /// Flush the response direction at most this size data.
    ///
    /// Default: 15000
    pub fn max_flush_size(self, n: usize) -> Self {
        Self {
            max_frame_size: n,
            ..self
        }
    }

    /// Close the connection after this time idle.
    ///
    /// Default: 60 seconds
    pub fn idle_timeout(self, d: Duration) -> Self {
        Self {
            idle_timeout: d,
            ..self
        }
    }

    /// Close the connection after this time writing block.
    ///
    /// Default: 10 seconds
    pub fn write_timeout(self, d: Duration) -> Self {
        Self {
            write_timeout: d,
            ..self
        }
    }

    /// Add the first service, and return a ConfigedServer.
    pub fn add_service<S>(self, svc: S) -> ConfigedServer
    where
        S: crate::PajamaxService + Send + Sync + 'static,
    {
        ConfigedServer {
            config: self,
            services: vec![Arc::new(svc)],
        }
    }
}