1#![allow(clippy::missing_panics_doc)]
2use std::{fmt, io, net, sync::Arc};
3
4use ntex_io::Io;
5use ntex_rt::System;
6use ntex_service::{ServiceFactory, cfg::SharedCfg};
7use ntex_util::time::Millis;
8use socket2::{Domain, SockAddr, Socket, Type};
9
10use crate::{Server, WorkerPool};
11
12use super::accept::AcceptLoop;
13use super::config::{Config, ServiceConfig};
14use super::factory::{self, FactoryServiceType};
15use super::factory::{OnAccept, OnAcceptWrapper, OnWorkerStart, OnWorkerStartWrapper};
16use super::{Connection, ServerStatus, Stream, StreamServer, Token, socket::Listener};
17
18pub struct ServerBuilder {
23 name: String,
24 token: Token,
25 backlog: i32,
26 services: Vec<FactoryServiceType>,
27 sockets: Vec<(Token, String, Listener)>,
28 on_worker_start: Vec<Box<dyn OnWorkerStart + Send>>,
29 on_accept: Option<Box<dyn OnAccept + Send>>,
30 accept: AcceptLoop,
31 pool: WorkerPool,
32}
33
34impl Default for ServerBuilder {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40impl fmt::Debug for ServerBuilder {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 f.debug_struct("ServerBuilder")
43 .field("name", &self.name)
44 .field("token", &self.token)
45 .field("backlog", &self.backlog)
46 .field("sockets", &self.sockets)
47 .field("accept", &self.accept)
48 .field("worker-pool", &self.pool)
49 .finish()
50 }
51}
52
53impl ServerBuilder {
54 #[must_use]
55 pub fn new() -> ServerBuilder {
57 let sys = System::current();
58 let mut accept = AcceptLoop::default();
59 accept.name(sys.name());
60 if sys.testing() {
61 accept.testing();
62 }
63
64 ServerBuilder {
65 accept,
66 name: sys.name().to_string(),
67 token: Token(0),
68 services: Vec::new(),
69 sockets: Vec::new(),
70 on_accept: None,
71 on_worker_start: Vec::new(),
72 backlog: 2048,
73 pool: WorkerPool::default().name(sys.name()),
74 }
75 }
76
77 #[must_use]
78 pub fn name<T: AsRef<str>>(mut self, name: T) -> Self {
82 self.name = name.as_ref().to_string();
83 self.accept.name(self.name.as_str());
84 self.pool = self.pool.name(self.name.as_str());
85 self
86 }
87
88 #[must_use]
89 pub fn workers(mut self, num: usize) -> Self {
94 self.pool = self.pool.workers(num);
95 self
96 }
97
98 #[must_use]
99 pub fn backlog(mut self, num: i32) -> Self {
110 self.backlog = num;
111 self
112 }
113
114 #[must_use]
115 pub fn maxconn(self, num: usize) -> Self {
122 super::max_concurrent_connections(num);
123 self
124 }
125
126 #[must_use]
127 pub fn stop_runtime(mut self) -> Self {
131 self.pool = self.pool.stop_runtime();
132 self
133 }
134
135 #[must_use]
136 pub fn stop_on_panic(mut self) -> Self {
140 self.pool = self.pool.stop_on_panic();
141 self
142 }
143
144 #[must_use]
145 pub fn disable_signals(mut self) -> Self {
149 self.pool = self.pool.disable_signals();
150 self
151 }
152
153 #[must_use]
154 pub fn enable_affinity(mut self) -> Self {
158 self.pool = self.pool.enable_affinity();
159 self
160 }
161
162 #[must_use]
163 pub fn graceful_shutdown(mut self) -> Self {
168 self.pool = self.pool.graceful_shutdown();
169 self
170 }
171
172 #[must_use]
173 pub fn shutdown_timeout<T: Into<Millis>>(mut self, timeout: T) -> Self {
181 self.pool = self.pool.shutdown_timeout(timeout);
182 self
183 }
184
185 #[must_use]
186 pub fn status_handler<F>(mut self, handler: F) -> Self
190 where
191 F: FnMut(ServerStatus) + Send + 'static,
192 {
193 self.accept.set_status_handler(handler);
194 self
195 }
196
197 pub async fn configure<F>(mut self, f: F) -> io::Result<ServerBuilder>
203 where
204 F: AsyncFn(ServiceConfig) -> io::Result<()>,
205 {
206 let cfg = ServiceConfig::new(self.token, self.backlog);
207
208 f(cfg.clone()).await?;
209
210 let (token, sockets, factory) = cfg.into_factory();
211 self.token = token;
212 self.sockets.extend(sockets);
213 self.services.push(factory);
214
215 Ok(self)
216 }
217
218 #[must_use]
219 pub fn on_worker_start<F, E>(mut self, f: F) -> Self
224 where
225 F: AsyncFn() -> Result<(), E> + Send + Clone + 'static,
226 E: fmt::Display + 'static,
227 {
228 self.on_worker_start.push(OnWorkerStartWrapper::create(f));
229 self
230 }
231
232 #[must_use]
233 pub fn on_accept<F, E>(mut self, f: F) -> Self
237 where
238 F: AsyncFn(Arc<str>, Stream) -> Result<Stream, E> + Send + Clone + 'static,
239 E: fmt::Display + 'static,
240 {
241 self.on_accept = Some(OnAcceptWrapper::create(f));
242 self
243 }
244
245 pub fn bind<F, U, N, R>(mut self, name: N, addr: U, factory: F) -> io::Result<Self>
247 where
248 U: net::ToSocketAddrs,
249 N: AsRef<str>,
250 F: AsyncFn(Config) -> R + Send + Clone + 'static,
251 R: ServiceFactory<Io, SharedCfg> + 'static,
252 {
253 let sockets = bind_addr(addr, self.backlog)?;
254
255 let mut tokens = Vec::new();
256 for lst in sockets {
257 let token = self.token.next();
258 self.sockets
259 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
260 tokens.push((token, SharedCfg::default()));
261 }
262
263 self.services.push(factory::create_factory_service(
264 name.as_ref().to_string(),
265 tokens,
266 factory,
267 ));
268
269 Ok(self)
270 }
271
272 #[cfg(unix)]
273 pub fn bind_uds<F, U, N, R>(self, name: N, addr: U, factory: F) -> io::Result<Self>
275 where
276 N: AsRef<str>,
277 U: AsRef<std::path::Path>,
278 F: AsyncFn(Config) -> R + Send + Clone + 'static,
279 R: ServiceFactory<Io, SharedCfg> + 'static,
280 {
281 use std::os::unix::net::UnixListener;
282
283 if let Err(e) = std::fs::remove_file(addr.as_ref()) {
286 if e.kind() != std::io::ErrorKind::NotFound {
288 return Err(e);
289 }
290 }
291
292 let lst = UnixListener::bind(addr)?;
293 self.listen_uds(name, lst, factory)
294 }
295
296 #[cfg(unix)]
297 pub fn listen_uds<F, N: AsRef<str>, R>(
301 mut self,
302 name: N,
303 lst: std::os::unix::net::UnixListener,
304 factory: F,
305 ) -> io::Result<Self>
306 where
307 F: AsyncFn(Config) -> R + Send + Clone + 'static,
308 R: ServiceFactory<Io, SharedCfg> + 'static,
309 {
310 let token = self.token.next();
311 self.services.push(factory::create_factory_service(
312 name.as_ref().to_string(),
313 vec![(token, SharedCfg::default())],
314 factory,
315 ));
316 self.sockets
317 .push((token, name.as_ref().to_string(), Listener::from_uds(lst)));
318 Ok(self)
319 }
320
321 pub fn listen<F, N: AsRef<str>, R>(
323 mut self,
324 name: N,
325 lst: net::TcpListener,
326 factory: F,
327 ) -> io::Result<Self>
328 where
329 F: AsyncFn(Config) -> R + Send + Clone + 'static,
330 R: ServiceFactory<Io, SharedCfg> + 'static,
331 {
332 let token = self.token.next();
333 self.services.push(factory::create_factory_service(
334 name.as_ref().to_string(),
335 vec![(token, SharedCfg::default())],
336 factory,
337 ));
338 self.sockets
339 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
340 Ok(self)
341 }
342
343 #[must_use]
344 pub fn config<N, U>(mut self, name: N, cfg: U) -> Self
350 where
351 N: AsRef<str>,
352 U: Into<SharedCfg>,
353 {
354 let cfg = cfg.into();
355 let mut token = None;
356 for sock in &self.sockets {
357 if sock.1 == name.as_ref() {
358 token = Some(sock.0);
359 break;
360 }
361 }
362
363 if let Some(token) = token {
364 for svc in &mut self.services {
365 if svc.name(token) == name.as_ref() {
366 svc.set_config(token, cfg.clone());
367 }
368 }
369 } else {
370 panic!("Cannot find service by name {:?}", name.as_ref());
371 }
372
373 self
374 }
375
376 pub fn run(self) -> Server<Connection> {
378 assert!(
379 !self.sockets.is_empty(),
380 "Server should have at least one bound socket"
381 );
382 let srv = StreamServer::new(
383 self.accept.notify(),
384 self.services,
385 self.on_worker_start,
386 self.on_accept,
387 );
388 let svc = self.pool.run(srv);
389
390 let sockets = self
391 .sockets
392 .into_iter()
393 .map(|sock| {
394 log::info!("Starting \"{}\" service on {}", sock.1, sock.2);
395 (sock.0, sock.2)
396 })
397 .collect();
398 self.accept.start(sockets, svc.clone());
399
400 svc
401 }
402}
403
404pub fn bind_addr<S: net::ToSocketAddrs>(
405 addr: S,
406 backlog: i32,
407) -> io::Result<Vec<net::TcpListener>> {
408 let mut err = None;
409 let mut succ = false;
410 let mut sockets = Vec::new();
411 for addr in addr.to_socket_addrs()? {
412 match create_tcp_listener(addr, backlog) {
413 Ok(lst) => {
414 succ = true;
415 sockets.push(lst);
416 }
417 Err(e) => err = Some(e),
418 }
419 }
420
421 if succ {
422 Ok(sockets)
423 } else if let Some(e) = err.take() {
424 Err(e)
425 } else {
426 Err(io::Error::new(
427 io::ErrorKind::InvalidInput,
428 "Cannot bind to address.",
429 ))
430 }
431}
432
433pub fn create_tcp_listener(
434 addr: net::SocketAddr,
435 backlog: i32,
436) -> io::Result<net::TcpListener> {
437 let builder = match addr {
438 net::SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?,
439 net::SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?,
440 };
441
442 #[cfg(not(windows))]
446 builder.set_reuse_address(true)?;
447
448 builder.bind(&SockAddr::from(addr))?;
449 builder.listen(backlog)?;
450 Ok(net::TcpListener::from(builder))
451}
452
453#[cfg(test)]
454mod tests {
455 use super::*;
456
457 #[test]
458 fn test_bind_addr() {
459 let addrs: Vec<net::SocketAddr> = Vec::new();
460 assert!(bind_addr(&addrs[..], 10).is_err());
461 }
462
463 #[ntex::test]
464 async fn test_debug() {
465 let builder = ServerBuilder::default();
466 assert!(format!("{builder:?}").contains("ServerBuilder"));
467 }
468}