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 {
169 self.pool = self.pool.graceful_shutdown();
170 self
171 }
172
173 #[must_use]
174 pub fn shutdown_timeout<T: Into<Millis>>(mut self, timeout: T) -> Self {
182 self.pool = self.pool.shutdown_timeout(timeout);
183 self
184 }
185
186 #[must_use]
187 pub fn status_handler<F>(mut self, handler: F) -> Self
191 where
192 F: FnMut(ServerStatus) + Send + 'static,
193 {
194 self.accept.set_status_handler(handler);
195 self
196 }
197
198 pub async fn configure<F>(mut self, f: F) -> io::Result<ServerBuilder>
204 where
205 F: AsyncFn(ServiceConfig) -> io::Result<()>,
206 {
207 let cfg = ServiceConfig::new(self.token, self.backlog);
208
209 f(cfg.clone()).await?;
210
211 let (token, sockets, factory) = cfg.into_factory();
212 self.token = token;
213 self.sockets.extend(sockets);
214 self.services.push(factory);
215
216 Ok(self)
217 }
218
219 #[must_use]
220 pub fn on_worker_start<F, E>(mut self, f: F) -> Self
225 where
226 F: AsyncFn() -> Result<(), E> + Send + Clone + 'static,
227 E: fmt::Display + 'static,
228 {
229 self.on_worker_start.push(OnWorkerStartWrapper::create(f));
230 self
231 }
232
233 #[must_use]
234 pub fn on_accept<F, E>(mut self, f: F) -> Self
238 where
239 F: AsyncFn(Arc<str>, Stream) -> Result<Stream, E> + Send + Clone + 'static,
240 E: fmt::Display + 'static,
241 {
242 self.on_accept = Some(OnAcceptWrapper::create(f));
243 self
244 }
245
246 pub fn bind<F, U, N, R>(mut self, name: N, addr: U, factory: F) -> io::Result<Self>
248 where
249 U: net::ToSocketAddrs,
250 N: AsRef<str>,
251 F: AsyncFn(Config) -> R + Send + Clone + 'static,
252 R: ServiceFactory<Io, SharedCfg> + 'static,
253 {
254 let sockets = bind_addr(addr, self.backlog)?;
255
256 let mut tokens = Vec::new();
257 for lst in sockets {
258 let token = self.token.next();
259 self.sockets
260 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
261 tokens.push((token, SharedCfg::default()));
262 }
263
264 self.services.push(factory::create_factory_service(
265 name.as_ref().to_string(),
266 tokens,
267 factory,
268 ));
269
270 Ok(self)
271 }
272
273 #[cfg(unix)]
274 pub fn bind_uds<F, U, N, R>(self, name: N, addr: U, factory: F) -> io::Result<Self>
276 where
277 N: AsRef<str>,
278 U: AsRef<std::path::Path>,
279 F: AsyncFn(Config) -> R + Send + Clone + 'static,
280 R: ServiceFactory<Io, SharedCfg> + 'static,
281 {
282 use std::os::unix::net::UnixListener;
283
284 if let Err(e) = std::fs::remove_file(addr.as_ref()) {
287 if e.kind() != std::io::ErrorKind::NotFound {
289 return Err(e);
290 }
291 }
292
293 let lst = UnixListener::bind(addr)?;
294 self.listen_uds(name, lst, factory)
295 }
296
297 #[cfg(unix)]
298 pub fn listen_uds<F, N: AsRef<str>, R>(
302 mut self,
303 name: N,
304 lst: std::os::unix::net::UnixListener,
305 factory: F,
306 ) -> io::Result<Self>
307 where
308 F: AsyncFn(Config) -> R + Send + Clone + 'static,
309 R: ServiceFactory<Io, SharedCfg> + 'static,
310 {
311 let token = self.token.next();
312 self.services.push(factory::create_factory_service(
313 name.as_ref().to_string(),
314 vec![(token, SharedCfg::default())],
315 factory,
316 ));
317 self.sockets
318 .push((token, name.as_ref().to_string(), Listener::from_uds(lst)));
319 Ok(self)
320 }
321
322 pub fn listen<F, N: AsRef<str>, R>(
324 mut self,
325 name: N,
326 lst: net::TcpListener,
327 factory: F,
328 ) -> io::Result<Self>
329 where
330 F: AsyncFn(Config) -> R + Send + Clone + 'static,
331 R: ServiceFactory<Io, SharedCfg> + 'static,
332 {
333 let token = self.token.next();
334 self.services.push(factory::create_factory_service(
335 name.as_ref().to_string(),
336 vec![(token, SharedCfg::default())],
337 factory,
338 ));
339 self.sockets
340 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
341 Ok(self)
342 }
343
344 #[must_use]
345 pub fn config<N, U>(mut self, name: N, cfg: U) -> Self
351 where
352 N: AsRef<str>,
353 U: Into<SharedCfg>,
354 {
355 let cfg = cfg.into();
356 let mut token = None;
357 for sock in &self.sockets {
358 if sock.1 == name.as_ref() {
359 token = Some(sock.0);
360 break;
361 }
362 }
363
364 if let Some(token) = token {
365 for svc in &mut self.services {
366 if svc.name(token) == name.as_ref() {
367 svc.set_config(token, cfg.clone());
368 }
369 }
370 } else {
371 panic!("Cannot find service by name {:?}", name.as_ref());
372 }
373
374 self
375 }
376
377 pub fn run(self) -> Server<Connection> {
379 assert!(
380 !self.sockets.is_empty(),
381 "Server should have at least one bound socket"
382 );
383 let srv = StreamServer::new(
384 self.accept.notify(),
385 self.services,
386 self.on_worker_start,
387 self.on_accept,
388 );
389 let svc = self.pool.run(srv);
390
391 let sockets = self
392 .sockets
393 .into_iter()
394 .map(|sock| {
395 log::info!("Starting \"{}\" service on {}", sock.1, sock.2);
396 (sock.0, sock.2)
397 })
398 .collect();
399 self.accept.start(sockets, svc.clone());
400
401 svc
402 }
403}
404
405pub fn bind_addr<S: net::ToSocketAddrs>(
406 addr: S,
407 backlog: i32,
408) -> io::Result<Vec<net::TcpListener>> {
409 let mut err = None;
410 let mut succ = false;
411 let mut sockets = Vec::new();
412 for addr in addr.to_socket_addrs()? {
413 match create_tcp_listener(addr, backlog) {
414 Ok(lst) => {
415 succ = true;
416 sockets.push(lst);
417 }
418 Err(e) => err = Some(e),
419 }
420 }
421
422 if succ {
423 Ok(sockets)
424 } else if let Some(e) = err.take() {
425 Err(e)
426 } else {
427 Err(io::Error::new(
428 io::ErrorKind::InvalidInput,
429 "Cannot bind to address.",
430 ))
431 }
432}
433
434pub fn create_tcp_listener(
435 addr: net::SocketAddr,
436 backlog: i32,
437) -> io::Result<net::TcpListener> {
438 let builder = match addr {
439 net::SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?,
440 net::SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?,
441 };
442
443 #[cfg(not(windows))]
447 builder.set_reuse_address(true)?;
448
449 builder.bind(&SockAddr::from(addr))?;
450 builder.listen(backlog)?;
451 Ok(net::TcpListener::from(builder))
452}
453
454#[cfg(test)]
455mod tests {
456 use super::*;
457
458 #[test]
459 fn test_bind_addr() {
460 let addrs: Vec<net::SocketAddr> = Vec::new();
461 assert!(bind_addr(&addrs[..], 10).is_err());
462 }
463
464 #[ntex::test]
465 async fn test_debug() {
466 let builder = ServerBuilder::default();
467 assert!(format!("{builder:?}").contains("ServerBuilder"));
468 }
469}