1use std::{fmt, io, marker::PhantomData, net};
2
3use ntex_io::Io;
4use ntex_rt::System;
5use ntex_service::{IntoService, Service, cfg::SharedCfg, state::State};
6use ntex_util::time::Millis;
7use socket2::{Domain, SockAddr, Socket, Type};
8
9use crate::{Server, WorkerPool};
10
11use super::accept::AcceptLoop;
12use super::config::ServiceConfig;
13use super::factory::{self, FactoryServiceType};
14use super::state::{StateFactory, state_factory};
15use super::{Connection, ServerStatus, StreamServer, Token, socket::Listener};
16
17pub struct ServerBuilder<St = ()> {
22 name: String,
23 token: Token,
24 backlog: i32,
25 state: Box<dyn StateFactory<St> + Send>,
26 services: Vec<FactoryServiceType<St>>,
27 sockets: Vec<(Token, String, Listener)>,
28 accept: AcceptLoop,
29 pool: WorkerPool,
30 st: PhantomData<St>,
31}
32
33impl Default for ServerBuilder {
34 fn default() -> Self {
35 Self::new(async || Ok(()))
36 }
37}
38
39impl<St> ServerBuilder<St>
40where
41 St: State<St, Io> + Clone + 'static,
42{
43 #[must_use]
44 pub fn new<F>(state: F) -> ServerBuilder<St>
49 where
50 F: AsyncFn() -> Result<St, &'static str> + Send + Clone + 'static,
51 {
52 let sys = System::current();
53 let mut accept = AcceptLoop::default();
54 accept.name(sys.name());
55 if sys.testing() {
56 accept.testing();
57 }
58
59 ServerBuilder {
60 accept,
61 name: sys.name().to_string(),
62 token: Token(0),
63 state: state_factory(state),
64 services: Vec::new(),
65 sockets: Vec::new(),
66 backlog: 2048,
67 pool: WorkerPool::default().name(sys.name()),
68 st: PhantomData,
69 }
70 }
71
72 #[must_use]
73 pub fn with_default() -> ServerBuilder<St>
75 where
76 St: Default,
77 {
78 Self::new(async || Ok(St::default()))
79 }
80
81 #[must_use]
82 pub fn name<T: AsRef<str>>(mut self, name: T) -> Self {
86 self.name = name.as_ref().to_string();
87 self.accept.name(self.name.as_str());
88 self.pool = self.pool.name(self.name.as_str());
89 self
90 }
91
92 #[must_use]
93 pub fn workers(mut self, num: usize) -> Self {
98 self.pool = self.pool.workers(num);
99 self
100 }
101
102 #[must_use]
103 pub fn backlog(mut self, num: i32) -> Self {
114 self.backlog = num;
115 self
116 }
117
118 #[must_use]
119 pub fn maxconn(self, num: usize) -> Self {
126 super::max_concurrent_connections(num);
127 self
128 }
129
130 #[must_use]
131 pub fn stop_runtime(mut self) -> Self {
135 self.pool = self.pool.stop_runtime();
136 self
137 }
138
139 #[must_use]
140 pub fn stop_on_panic(mut self) -> Self {
144 self.pool = self.pool.stop_on_panic();
145 self
146 }
147
148 #[must_use]
149 pub fn disable_signals(mut self) -> Self {
153 self.pool = self.pool.disable_signals();
154 self
155 }
156
157 #[must_use]
158 pub fn enable_affinity(mut self) -> Self {
162 self.pool = self.pool.enable_affinity();
163 self
164 }
165
166 #[must_use]
167 pub fn graceful_shutdown(mut self) -> Self {
173 self.pool = self.pool.graceful_shutdown();
174 self
175 }
176
177 #[must_use]
178 pub fn shutdown_timeout<T: Into<Millis>>(mut self, timeout: T) -> Self {
186 self.pool = self.pool.shutdown_timeout(timeout);
187 self
188 }
189
190 #[must_use]
191 pub fn status_handler<F>(mut self, handler: F) -> Self
195 where
196 F: FnMut(ServerStatus) + Send + 'static,
197 {
198 self.accept.set_status_handler(handler);
199 self
200 }
201
202 pub async fn configure<F>(mut self, f: F) -> io::Result<Self>
208 where
209 F: AsyncFn(ServiceConfig<St>) -> io::Result<()>,
210 {
211 let cfg = ServiceConfig::new(self.token, self.backlog);
212
213 f(cfg.clone()).await?;
214
215 let (token, sockets, factory) = cfg.into_factory();
216 self.token = token;
217 self.sockets.extend(sockets);
218 self.services.push(factory);
219
220 Ok(self)
221 }
222
223 #[allow(clippy::needless_pass_by_value)]
224 pub fn bind<F, S, I>(
226 mut self,
227 name: impl AsRef<str>,
228 addr: impl net::ToSocketAddrs,
229 cfg: impl Into<SharedCfg>,
230 factory: F,
231 ) -> io::Result<Self>
232 where
233 F: AsyncFn(&St) -> I + Send + Clone + 'static,
234 S: Service<St, Io> + 'static,
235 I: IntoService<S, St, Io> + 'static,
236 St: State<St, Io> + 'static,
237 {
238 let cfg = cfg.into();
239 let sockets = bind_addr(addr, self.backlog)?;
240
241 let mut tokens = Vec::new();
242 for lst in sockets {
243 let token = self.token.next();
244 self.sockets
245 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
246 tokens.push((token, cfg.clone()));
247 }
248
249 self.services.push(factory::create_factory_service(
250 name.as_ref().to_string(),
251 tokens,
252 factory,
253 ));
254
255 Ok(self)
256 }
257
258 #[cfg(unix)]
259 pub fn bind_uds<F, I, S>(
261 self,
262 name: impl AsRef<str>,
263 addr: impl AsRef<std::path::Path>,
264 cfg: impl Into<SharedCfg>,
265 factory: F,
266 ) -> io::Result<Self>
267 where
268 F: AsyncFn(&St) -> I + Send + Clone + 'static,
269 I: IntoService<S, St, Io> + 'static,
270 S: Service<St, Io> + 'static,
271 St: State<St, Io> + 'static,
272 {
273 use std::os::unix::net::UnixListener;
274
275 if let Err(e) = std::fs::remove_file(addr.as_ref()) {
278 if e.kind() != std::io::ErrorKind::NotFound {
280 return Err(e);
281 }
282 }
283
284 let lst = UnixListener::bind(addr)?;
285 self.listen_uds(name, lst, cfg.into(), factory)
286 }
287
288 #[cfg(unix)]
289 pub fn listen_uds<F, I, S>(
293 mut self,
294 name: impl AsRef<str>,
295 lst: std::os::unix::net::UnixListener,
296 cfg: impl Into<SharedCfg>,
297 factory: F,
298 ) -> io::Result<Self>
299 where
300 F: AsyncFn(&St) -> I + Send + Clone + 'static,
301 I: IntoService<S, St, Io> + 'static,
302 S: Service<St, Io> + 'static,
303 St: State<St, Io> + 'static,
304 {
305 let token = self.token.next();
306 self.services.push(factory::create_factory_service(
307 name.as_ref().to_string(),
308 vec![(token, cfg.into())],
309 factory,
310 ));
311 self.sockets
312 .push((token, name.as_ref().to_string(), Listener::from_uds(lst)));
313 Ok(self)
314 }
315
316 pub fn listen<F, S, I>(
318 mut self,
319 name: impl AsRef<str>,
320 lst: net::TcpListener,
321 cfg: impl Into<SharedCfg>,
322 factory: F,
323 ) -> io::Result<Self>
324 where
325 F: AsyncFn(&St) -> I + Send + Clone + 'static,
326 S: Service<St, Io> + 'static,
327 I: IntoService<S, St, Io> + 'static,
328 St: State<St, Io> + 'static,
329 {
330 let token = self.token.next();
331 self.services.push(factory::create_factory_service(
332 name.as_ref().to_string(),
333 vec![(token, cfg.into())],
334 factory,
335 ));
336 self.sockets
337 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
338 Ok(self)
339 }
340
341 pub fn run(self) -> Server<Connection> {
343 assert!(
344 !self.sockets.is_empty(),
345 "Server should have at least one bound socket"
346 );
347 let srv = StreamServer::new(self.accept.notify(), self.state, self.services);
348 let svc = self.pool.run(srv);
349
350 let sockets = self
351 .sockets
352 .into_iter()
353 .map(|sock| {
354 log::info!("Starting \"{}\" service on {}", sock.1, sock.2);
355 (sock.0, sock.2)
356 })
357 .collect();
358 self.accept.start(sockets, svc.clone());
359
360 svc
361 }
362}
363
364impl<St> fmt::Debug for ServerBuilder<St> {
365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366 f.debug_struct("ServerBuilder")
367 .field("name", &self.name)
368 .field("token", &self.token)
369 .field("backlog", &self.backlog)
370 .field("sockets", &self.sockets)
371 .field("accept", &self.accept)
372 .field("worker-pool", &self.pool)
373 .finish()
374 }
375}
376
377pub fn bind_addr<S: net::ToSocketAddrs>(
378 addr: S,
379 backlog: i32,
380) -> io::Result<Vec<net::TcpListener>> {
381 let mut err = None;
382 let mut succ = false;
383 let mut sockets = Vec::new();
384 for addr in addr.to_socket_addrs()? {
385 match create_tcp_listener(addr, backlog) {
386 Ok(lst) => {
387 succ = true;
388 sockets.push(lst);
389 }
390 Err(e) => err = Some(e),
391 }
392 }
393
394 if succ {
395 Ok(sockets)
396 } else if let Some(e) = err.take() {
397 Err(e)
398 } else {
399 Err(io::Error::new(
400 io::ErrorKind::InvalidInput,
401 "Cannot bind to address.",
402 ))
403 }
404}
405
406pub fn create_tcp_listener(addr: net::SocketAddr, backlog: i32) -> io::Result<net::TcpListener> {
407 let builder = match addr {
408 net::SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?,
409 net::SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?,
410 };
411
412 #[cfg(not(windows))]
416 builder.set_reuse_address(true)?;
417
418 builder.bind(&SockAddr::from(addr))?;
419 builder.listen(backlog)?;
420 Ok(net::TcpListener::from(builder))
421}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426
427 #[test]
428 fn test_bind_addr() {
429 let addrs: Vec<net::SocketAddr> = Vec::new();
430 assert!(bind_addr(&addrs[..], 10).is_err());
431 }
432
433 #[ntex::test]
434 async fn test_debug() {
435 let builder = ServerBuilder::default();
436 assert!(format!("{builder:?}").contains("ServerBuilder"));
437 }
438}