use std::future::Future;
use std::sync::Arc;
use futures::future::BoxFuture;
use crate::error::ServerlessError;
pub type FunctionHandler =
Arc<dyn Fn(Vec<u8>) -> BoxFuture<'static, Result<Vec<u8>, ServerlessError>> + Send + Sync>;
pub trait FunctionRegistry: Send + Sync + 'static {
fn function_name(&self) -> &'static str;
fn function_path(&self) -> &'static str {
self.function_name()
}
fn register(&self, server: &mut FunctionServer);
}
inventory::collect!(&'static dyn FunctionRegistry);
#[derive(Debug, Clone)]
pub struct ServerConfig {
pub host: String,
pub port: u16,
}
impl Default for ServerConfig {
fn default() -> Self {
Self {
host: "127.0.0.1".to_string(),
port: 3000,
}
}
}
impl ServerConfig {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn host(mut self, host: &str) -> Self {
self.host = host.to_string();
self
}
#[must_use]
pub fn port(mut self, port: u16) -> Self {
self.port = port;
self
}
}
pub struct FunctionServer {
config: ServerConfig,
router: Option<axum::Router>,
}
impl Default for FunctionServer {
fn default() -> Self {
Self::new()
}
}
impl FunctionServer {
#[must_use]
pub fn new() -> Self {
Self {
config: ServerConfig::default(),
router: Some(axum::Router::new()),
}
}
#[must_use]
pub fn with_config(config: ServerConfig) -> Self {
Self {
config,
router: Some(axum::Router::new()),
}
}
#[must_use]
pub fn host(mut self, host: &str) -> Self {
self.config.host = host.to_string();
self
}
#[must_use]
pub fn port(mut self, port: u16) -> Self {
self.config.port = port;
self
}
#[must_use]
pub fn config(&self) -> &ServerConfig {
&self.config
}
pub fn register_http_route<F, T>(&mut self, path: &str, handler: F)
where
F: axum::handler::Handler<T, ()> + Send + Sync + 'static,
T: 'static,
{
if let Some(ref mut router) = self.router {
let old_router = std::mem::replace(router, axum::Router::new());
*router = old_router.route(path, axum::routing::post(handler));
}
}
pub async fn start(mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
for registry in inventory::iter::<&'static dyn FunctionRegistry> {
registry.register(&mut self);
}
self.serve().await
}
pub async fn start_with_graceful_shutdown<F>(
mut self,
shutdown_signal: F,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
where
F: Future<Output = ()> + Send + 'static + Clone,
{
for registry in inventory::iter::<&'static dyn FunctionRegistry> {
registry.register(&mut self);
}
self.serve_with_shutdown(shutdown_signal).await
}
async fn serve(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
if let Some(ref router) = self.router {
let listener =
tokio::net::TcpListener::bind((self.config.host.as_str(), self.config.port))
.await?;
return axum::serve(listener, router.clone())
.await
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> { Box::new(e) });
}
Ok(())
}
async fn serve_with_shutdown<F>(
&self,
shutdown_signal: F,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
where
F: Future<Output = ()> + Send + 'static,
{
if let Some(ref router) = self.router {
let listener =
tokio::net::TcpListener::bind((self.config.host.as_str(), self.config.port))
.await?;
return axum::serve(listener, router.clone())
.with_graceful_shutdown(shutdown_signal)
.await
.map_err(|e| -> Box<dyn std::error::Error + Send + Sync> { Box::new(e) });
}
Ok(())
}
}
pub use FunctionServer as Server;