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::{Affinity, LoadBalancing, NoConfig, Server, ServerAppConfig, WorkerPool};
10
11use super::accept::AcceptLoop;
12use super::config::ServiceConfig;
13use super::factory::{self, FactoryServiceType};
14use super::{Connection, 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 affinity(mut self, affinity: Affinity) -> Self {
154 self.pool = self.pool.affinity(affinity);
155 self
156 }
157
158 #[must_use]
159 pub fn load_balancing(mut self, balancing: LoadBalancing) -> Self {
163 self.pool = self.pool.load_balancing(balancing);
164 self
165 }
166
167 #[must_use]
168 pub fn graceful_shutdown(mut self) -> Self {
176 self.pool = self.pool.graceful_shutdown();
177 self
178 }
179
180 #[must_use]
181 pub fn graceful_shutdown_timeout<T: Into<Millis>>(mut self, timeout: T) -> Self {
194 self.pool = self.pool.graceful_shutdown_timeout(timeout);
195 self
196 }
197
198 pub async fn configure<F>(mut self, f: F) -> io::Result<Self>
206 where
207 F: AsyncFnOnce(ServiceConfig<Cfg>) -> io::Result<()>,
208 {
209 let cfg = ServiceConfig::new(self.token, self.backlog);
210
211 f(cfg.clone()).await?;
212
213 let (token, sockets, factory) = cfg.into_factory();
214 self.token = token;
215 self.sockets.extend(sockets);
216 self.services.push(factory);
217
218 Ok(self)
219 }
220
221 #[allow(clippy::needless_pass_by_value)]
222 pub fn bind<F, S, I>(
232 mut self,
233 name: impl AsRef<str>,
234 addr: impl net::ToSocketAddrs,
235 cfg: impl Into<SharedCfg>,
236 factory: F,
237 ) -> io::Result<Self>
238 where
239 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
240 S: Service<Cfg::State, Io> + 'static,
241 I: IntoService<S, Cfg::State, Io> + 'static,
242 {
243 let cfg = cfg.into();
244 let sockets = bind_addr(addr, self.backlog)?;
245
246 let mut tokens = Vec::new();
247 for lst in sockets {
248 let token = self.token.next();
249 self.sockets
250 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
251 tokens.push((token, cfg.clone()));
252 }
253
254 self.services.push(factory::create_factory_service(
255 name.as_ref().to_string(),
256 tokens,
257 factory,
258 ));
259
260 Ok(self)
261 }
262
263 #[cfg(unix)]
264 pub fn bind_uds<F, I, S>(
270 self,
271 name: impl AsRef<str>,
272 addr: impl AsRef<std::path::Path>,
273 cfg: impl Into<SharedCfg>,
274 factory: F,
275 ) -> io::Result<Self>
276 where
277 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
278 I: IntoService<S, Cfg::State, Io> + 'static,
279 S: Service<Cfg::State, Io> + '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, cfg.into(), factory)
294 }
295
296 #[cfg(unix)]
297 pub fn listen_uds<F, I, S>(
303 mut self,
304 name: impl AsRef<str>,
305 lst: std::os::unix::net::UnixListener,
306 cfg: impl Into<SharedCfg>,
307 factory: F,
308 ) -> io::Result<Self>
309 where
310 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
311 I: IntoService<S, Cfg::State, Io> + 'static,
312 S: Service<Cfg::State, Io> + 'static,
313 {
314 let token = self.token.next();
315 self.services.push(factory::create_factory_service(
316 name.as_ref().to_string(),
317 vec![(token, cfg.into())],
318 factory,
319 ));
320 self.sockets
321 .push((token, name.as_ref().to_string(), Listener::from_uds(lst)));
322 Ok(self)
323 }
324
325 pub fn listen<F, S, I>(
330 mut self,
331 name: impl AsRef<str>,
332 lst: net::TcpListener,
333 cfg: impl Into<SharedCfg>,
334 factory: F,
335 ) -> io::Result<Self>
336 where
337 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
338 S: Service<Cfg::State, Io> + 'static,
339 I: IntoService<S, Cfg::State, Io> + 'static,
340 {
341 let token = self.token.next();
342 self.services.push(factory::create_factory_service(
343 name.as_ref().to_string(),
344 vec![(token, cfg.into())],
345 factory,
346 ));
347 self.sockets
348 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
349 Ok(self)
350 }
351
352 pub fn run(self) -> Server<Connection> {
358 assert!(
359 !self.sockets.is_empty(),
360 "Server should have at least one bound socket"
361 );
362 let srv = StreamServer::new(self.accept.notify(), self.state, self.services);
363 let svc = self.pool.run(srv);
364
365 svc.metrics_ref().listeners(
366 self.sockets
367 .iter()
368 .map(|sock| (sock.1.clone(), sock.2.local_addr().to_string())),
369 );
370 let sockets = self
371 .sockets
372 .into_iter()
373 .map(|sock| {
374 log::info!("Starting \"{}\" service on {}", sock.1, sock.2);
375 (sock.0, sock.2)
376 })
377 .collect();
378 self.accept.start(sockets, svc.clone());
379
380 svc
381 }
382}
383
384impl<Cfg> fmt::Debug for ServerBuilder<Cfg> {
385 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386 f.debug_struct("ServerBuilder")
387 .field("name", &self.name)
388 .field("token", &self.token)
389 .field("backlog", &self.backlog)
390 .field("sockets", &self.sockets)
391 .field("accept", &self.accept)
392 .field("worker-pool", &self.pool)
393 .finish()
394 }
395}
396
397pub fn bind_addr<S: net::ToSocketAddrs>(
402 addr: S,
403 backlog: i32,
404) -> io::Result<Vec<net::TcpListener>> {
405 let mut err = None;
406 let mut succ = false;
407 let mut sockets = Vec::new();
408 for addr in addr.to_socket_addrs()? {
409 match create_tcp_listener(addr, backlog) {
410 Ok(lst) => {
411 succ = true;
412 sockets.push(lst);
413 }
414 Err(e) => err = Some(e),
415 }
416 }
417
418 if succ {
419 Ok(sockets)
420 } else if let Some(e) = err.take() {
421 Err(e)
422 } else {
423 Err(io::Error::new(
424 io::ErrorKind::InvalidInput,
425 "Cannot bind to address.",
426 ))
427 }
428}
429
430pub fn create_tcp_listener(addr: net::SocketAddr, backlog: i32) -> io::Result<net::TcpListener> {
432 let builder = match addr {
433 net::SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?,
434 net::SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?,
435 };
436
437 #[cfg(not(windows))]
441 builder.set_reuse_address(true)?;
442
443 builder.bind(&SockAddr::from(addr))?;
444 builder.listen(backlog)?;
445 Ok(net::TcpListener::from(builder))
446}
447
448#[cfg(test)]
449mod tests {
450 use super::*;
451
452 #[test]
453 fn test_bind_addr() {
454 let addrs: Vec<net::SocketAddr> = Vec::new();
455 assert!(bind_addr(&addrs[..], 10).is_err());
456 }
457
458 #[ntex::test]
459 async fn test_debug() {
460 let builder = ServerBuilder::default();
461 assert!(format!("{builder:?}").contains("ServerBuilder"));
462 }
463}