1use std::{fmt, io, net, sync::Arc};
2
3use ntex_io::Io;
4use ntex_rt::System;
5use ntex_service::{IntoService, Service, cfg::SharedCfg};
6use ntex_util::time::Millis;
7use socket2::{Domain, SockAddr, Socket, Type};
8
9use crate::{NoConfig, Server, ServerAppConfig, WorkerPool};
10
11use super::accept::AcceptLoop;
12use super::config::ServiceConfig;
13use super::factory::{self, FactoryServiceType};
14use super::{Connection, ServerStatus, StreamServer, Token, socket::Listener};
15
16pub struct ServerBuilder<Cfg = NoConfig> {
21 name: String,
22 token: Token,
23 backlog: i32,
24 state: Arc<Cfg>,
25 services: Vec<FactoryServiceType<Cfg>>,
26 sockets: Vec<(Token, String, Listener)>,
27 accept: AcceptLoop,
28 pool: WorkerPool,
29}
30
31impl Default for ServerBuilder {
32 fn default() -> Self {
33 Self::new(NoConfig)
34 }
35}
36
37impl<Cfg> ServerBuilder<Cfg>
38where
39 Cfg: ServerAppConfig,
40{
41 #[must_use]
42 pub fn new(cfg: Cfg) -> ServerBuilder<Cfg> {
44 let sys = System::current();
45 let mut accept = AcceptLoop::default();
46 accept.name(sys.name());
47 if sys.testing() {
48 accept.testing();
49 }
50
51 ServerBuilder {
52 accept,
53 name: sys.name().to_string(),
54 token: Token(0),
55 state: Arc::new(cfg),
56 services: Vec::new(),
57 sockets: Vec::new(),
58 backlog: 2048,
59 pool: WorkerPool::default().name(sys.name()),
60 }
61 }
62
63 #[must_use]
64 pub fn name<T: AsRef<str>>(mut self, name: T) -> Self {
69 self.name = name.as_ref().to_string();
70 self.accept.name(self.name.as_str());
71 self.pool = self.pool.name(self.name.as_str());
72 self
73 }
74
75 #[must_use]
76 pub fn workers(mut self, num: usize) -> Self {
80 self.pool = self.pool.workers(num);
81 self
82 }
83
84 #[must_use]
85 pub fn backlog(mut self, num: i32) -> Self {
98 self.backlog = num;
99 self
100 }
101
102 #[must_use]
103 pub fn max_connections(self, num: usize) -> Self {
114 super::max_concurrent_connections(num);
115 self
116 }
117
118 #[must_use]
119 pub fn stop_runtime(mut self) -> Self {
123 self.pool = self.pool.stop_runtime();
124 self
125 }
126
127 #[must_use]
128 pub fn stop_on_panic(mut self) -> Self {
136 self.pool = self.pool.stop_on_panic();
137 self
138 }
139
140 #[must_use]
141 pub fn disable_signals(mut self) -> Self {
145 self.pool = self.pool.disable_signals();
146 self
147 }
148
149 #[must_use]
150 pub fn enable_affinity(mut self) -> Self {
154 self.pool = self.pool.enable_affinity();
155 self
156 }
157
158 #[must_use]
159 pub fn graceful_shutdown(mut self) -> Self {
167 self.pool = self.pool.graceful_shutdown();
168 self
169 }
170
171 #[must_use]
172 pub fn graceful_shutdown_timeout<T: Into<Millis>>(mut self, timeout: T) -> Self {
185 self.pool = self.pool.graceful_shutdown_timeout(timeout);
186 self
187 }
188
189 #[must_use]
190 pub fn status_handler<F>(mut self, handler: F) -> Self
197 where
198 F: FnMut(ServerStatus) + Send + 'static,
199 {
200 self.accept.set_status_handler(handler);
201 self
202 }
203
204 pub async fn configure<F>(mut self, f: F) -> io::Result<Self>
212 where
213 F: AsyncFnOnce(ServiceConfig<Cfg>) -> io::Result<()>,
214 {
215 let cfg = ServiceConfig::new(self.token, self.backlog);
216
217 f(cfg.clone()).await?;
218
219 let (token, sockets, factory) = cfg.into_factory();
220 self.token = token;
221 self.sockets.extend(sockets);
222 self.services.push(factory);
223
224 Ok(self)
225 }
226
227 #[allow(clippy::needless_pass_by_value)]
228 pub fn bind<F, S, I>(
238 mut self,
239 name: impl AsRef<str>,
240 addr: impl net::ToSocketAddrs,
241 cfg: impl Into<SharedCfg>,
242 factory: F,
243 ) -> io::Result<Self>
244 where
245 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
246 S: Service<Cfg::State, Io> + 'static,
247 I: IntoService<S, Cfg::State, Io> + 'static,
248 {
249 let cfg = cfg.into();
250 let sockets = bind_addr(addr, self.backlog)?;
251
252 let mut tokens = Vec::new();
253 for lst in sockets {
254 let token = self.token.next();
255 self.sockets
256 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
257 tokens.push((token, cfg.clone()));
258 }
259
260 self.services.push(factory::create_factory_service(
261 name.as_ref().to_string(),
262 tokens,
263 factory,
264 ));
265
266 Ok(self)
267 }
268
269 #[cfg(unix)]
270 pub fn bind_uds<F, I, S>(
276 self,
277 name: impl AsRef<str>,
278 addr: impl AsRef<std::path::Path>,
279 cfg: impl Into<SharedCfg>,
280 factory: F,
281 ) -> io::Result<Self>
282 where
283 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
284 I: IntoService<S, Cfg::State, Io> + 'static,
285 S: Service<Cfg::State, Io> + 'static,
286 {
287 use std::os::unix::net::UnixListener;
288
289 if let Err(e) = std::fs::remove_file(addr.as_ref()) {
292 if e.kind() != std::io::ErrorKind::NotFound {
294 return Err(e);
295 }
296 }
297
298 let lst = UnixListener::bind(addr)?;
299 self.listen_uds(name, lst, cfg.into(), factory)
300 }
301
302 #[cfg(unix)]
303 pub fn listen_uds<F, I, S>(
309 mut self,
310 name: impl AsRef<str>,
311 lst: std::os::unix::net::UnixListener,
312 cfg: impl Into<SharedCfg>,
313 factory: F,
314 ) -> io::Result<Self>
315 where
316 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
317 I: IntoService<S, Cfg::State, Io> + 'static,
318 S: Service<Cfg::State, Io> + 'static,
319 {
320 let token = self.token.next();
321 self.services.push(factory::create_factory_service(
322 name.as_ref().to_string(),
323 vec![(token, cfg.into())],
324 factory,
325 ));
326 self.sockets
327 .push((token, name.as_ref().to_string(), Listener::from_uds(lst)));
328 Ok(self)
329 }
330
331 pub fn listen<F, S, I>(
336 mut self,
337 name: impl AsRef<str>,
338 lst: net::TcpListener,
339 cfg: impl Into<SharedCfg>,
340 factory: F,
341 ) -> io::Result<Self>
342 where
343 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
344 S: Service<Cfg::State, Io> + 'static,
345 I: IntoService<S, Cfg::State, Io> + 'static,
346 {
347 let token = self.token.next();
348 self.services.push(factory::create_factory_service(
349 name.as_ref().to_string(),
350 vec![(token, cfg.into())],
351 factory,
352 ));
353 self.sockets
354 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
355 Ok(self)
356 }
357
358 pub fn run(self) -> Server<Connection> {
364 assert!(
365 !self.sockets.is_empty(),
366 "Server should have at least one bound socket"
367 );
368 let srv = StreamServer::new(self.accept.notify(), self.state, self.services);
369 let svc = self.pool.run(srv);
370
371 let sockets = self
372 .sockets
373 .into_iter()
374 .map(|sock| {
375 log::info!("Starting \"{}\" service on {}", sock.1, sock.2);
376 (sock.0, sock.2)
377 })
378 .collect();
379 self.accept.start(sockets, svc.clone());
380
381 svc
382 }
383}
384
385impl<Cfg> fmt::Debug for ServerBuilder<Cfg> {
386 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
387 f.debug_struct("ServerBuilder")
388 .field("name", &self.name)
389 .field("token", &self.token)
390 .field("backlog", &self.backlog)
391 .field("sockets", &self.sockets)
392 .field("accept", &self.accept)
393 .field("worker-pool", &self.pool)
394 .finish()
395 }
396}
397
398pub fn bind_addr<S: net::ToSocketAddrs>(
403 addr: S,
404 backlog: i32,
405) -> io::Result<Vec<net::TcpListener>> {
406 let mut err = None;
407 let mut succ = false;
408 let mut sockets = Vec::new();
409 for addr in addr.to_socket_addrs()? {
410 match create_tcp_listener(addr, backlog) {
411 Ok(lst) => {
412 succ = true;
413 sockets.push(lst);
414 }
415 Err(e) => err = Some(e),
416 }
417 }
418
419 if succ {
420 Ok(sockets)
421 } else if let Some(e) = err.take() {
422 Err(e)
423 } else {
424 Err(io::Error::new(
425 io::ErrorKind::InvalidInput,
426 "Cannot bind to address.",
427 ))
428 }
429}
430
431pub fn create_tcp_listener(addr: net::SocketAddr, backlog: i32) -> io::Result<net::TcpListener> {
433 let builder = match addr {
434 net::SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?,
435 net::SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?,
436 };
437
438 #[cfg(not(windows))]
442 builder.set_reuse_address(true)?;
443
444 builder.bind(&SockAddr::from(addr))?;
445 builder.listen(backlog)?;
446 Ok(net::TcpListener::from(builder))
447}
448
449#[cfg(test)]
450mod tests {
451 use super::*;
452
453 #[test]
454 fn test_bind_addr() {
455 let addrs: Vec<net::SocketAddr> = Vec::new();
456 assert!(bind_addr(&addrs[..], 10).is_err());
457 }
458
459 #[ntex::test]
460 async fn test_debug() {
461 let builder = ServerBuilder::default();
462 assert!(format!("{builder:?}").contains("ServerBuilder"));
463 }
464}