1use std::future::Future;
4use std::sync::Arc;
5
6use futures::future::BoxFuture;
7
8use crate::error::ServerlessError;
9
10pub type FunctionHandler =
12 Arc<dyn Fn(Vec<u8>) -> BoxFuture<'static, Result<Vec<u8>, ServerlessError>> + Send + Sync>;
13
14pub trait FunctionRegistry: Send + Sync + 'static {
18 fn function_name(&self) -> &'static str;
20
21 fn function_path(&self) -> &'static str {
23 self.function_name()
24 }
25
26 fn register(&self, server: &mut FunctionServer);
28}
29
30inventory::collect!(&'static dyn FunctionRegistry);
32
33#[derive(Debug, Clone)]
35pub struct ServerConfig {
36 pub host: String,
38 pub port: u16,
40}
41
42impl Default for ServerConfig {
43 fn default() -> Self {
44 Self {
45 host: "127.0.0.1".to_string(),
46 port: 3000,
47 }
48 }
49}
50
51impl ServerConfig {
52 #[must_use]
54 pub fn new() -> Self {
55 Self::default()
56 }
57
58 #[must_use]
60 pub fn host(mut self, host: &str) -> Self {
61 self.host = host.to_string();
62 self
63 }
64
65 #[must_use]
67 pub fn port(mut self, port: u16) -> Self {
68 self.port = port;
69 self
70 }
71}
72
73pub struct FunctionServer {
99 config: ServerConfig,
100 router: Option<axum::Router>,
101}
102
103impl Default for FunctionServer {
104 fn default() -> Self {
105 Self::new()
106 }
107}
108
109impl FunctionServer {
110 #[must_use]
112 pub fn new() -> Self {
113 Self {
114 config: ServerConfig::default(),
115 router: Some(axum::Router::new()),
116 }
117 }
118
119 #[must_use]
121 pub fn with_config(config: ServerConfig) -> Self {
122 Self {
123 config,
124 router: Some(axum::Router::new()),
125 }
126 }
127
128 #[must_use]
130 pub fn host(mut self, host: &str) -> Self {
131 self.config.host = host.to_string();
132 self
133 }
134
135 #[must_use]
137 pub fn port(mut self, port: u16) -> Self {
138 self.config.port = port;
139 self
140 }
141
142 #[must_use]
144 pub fn config(&self) -> &ServerConfig {
145 &self.config
146 }
147
148 pub fn register_http_route<F, T>(&mut self, path: &str, handler: F)
150 where
151 F: axum::handler::Handler<T, ()> + Send + Sync + 'static,
152 T: 'static,
153 {
154 if let Some(ref mut router) = self.router {
155 let old_router = std::mem::replace(router, axum::Router::new());
156 *router = old_router.route(path, axum::routing::post(handler));
157 }
158 }
159
160 pub async fn start(mut self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
169 for registry in inventory::iter::<&'static dyn FunctionRegistry> {
171 registry.register(&mut self);
172 }
173
174 self.serve().await
175 }
176
177 pub async fn start_with_graceful_shutdown<F>(
183 mut self,
184 shutdown_signal: F,
185 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
186 where
187 F: Future<Output = ()> + Send + 'static + Clone,
188 {
189 for registry in inventory::iter::<&'static dyn FunctionRegistry> {
191 registry.register(&mut self);
192 }
193
194 self.serve_with_shutdown(shutdown_signal).await
195 }
196
197 async fn serve(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
199 if let Some(ref router) = self.router {
200 let listener =
201 tokio::net::TcpListener::bind((self.config.host.as_str(), self.config.port))
202 .await?;
203 return axum::serve(listener, router.clone())
204 .await
205 .map_err(|e| -> Box<dyn std::error::Error + Send + Sync> { Box::new(e) });
206 }
207
208 Ok(())
209 }
210
211 async fn serve_with_shutdown<F>(
213 &self,
214 shutdown_signal: F,
215 ) -> Result<(), Box<dyn std::error::Error + Send + Sync>>
216 where
217 F: Future<Output = ()> + Send + 'static,
218 {
219 if let Some(ref router) = self.router {
220 let listener =
221 tokio::net::TcpListener::bind((self.config.host.as_str(), self.config.port))
222 .await?;
223 return axum::serve(listener, router.clone())
224 .with_graceful_shutdown(shutdown_signal)
225 .await
226 .map_err(|e| -> Box<dyn std::error::Error + Send + Sync> { Box::new(e) });
227 }
228
229 Ok(())
230 }
231}
232
233pub use FunctionServer as Server;