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> {
47 let sys = System::current();
48 let mut accept = AcceptLoop::default();
49 accept.name(sys.name());
50 if sys.testing() {
51 accept.testing();
52 }
53
54 ServerBuilder {
55 accept,
56 name: sys.name().to_string(),
57 token: Token(0),
58 state: Arc::new(cfg),
59 services: Vec::new(),
60 sockets: Vec::new(),
61 backlog: 2048,
62 pool: WorkerPool::default().name(sys.name()),
63 }
64 }
65
66 #[must_use]
67 pub fn name<T: AsRef<str>>(mut self, name: T) -> Self {
71 self.name = name.as_ref().to_string();
72 self.accept.name(self.name.as_str());
73 self.pool = self.pool.name(self.name.as_str());
74 self
75 }
76
77 #[must_use]
78 pub fn workers(mut self, num: usize) -> Self {
83 self.pool = self.pool.workers(num);
84 self
85 }
86
87 #[must_use]
88 pub fn backlog(mut self, num: i32) -> Self {
99 self.backlog = num;
100 self
101 }
102
103 #[must_use]
104 pub fn maxconn(self, num: usize) -> Self {
111 super::max_concurrent_connections(num);
112 self
113 }
114
115 #[must_use]
116 pub fn stop_runtime(mut self) -> Self {
120 self.pool = self.pool.stop_runtime();
121 self
122 }
123
124 #[must_use]
125 pub fn stop_on_panic(mut self) -> Self {
129 self.pool = self.pool.stop_on_panic();
130 self
131 }
132
133 #[must_use]
134 pub fn disable_signals(mut self) -> Self {
138 self.pool = self.pool.disable_signals();
139 self
140 }
141
142 #[must_use]
143 pub fn enable_affinity(mut self) -> Self {
147 self.pool = self.pool.enable_affinity();
148 self
149 }
150
151 #[must_use]
152 pub fn graceful_shutdown(mut self) -> Self {
158 self.pool = self.pool.graceful_shutdown();
159 self
160 }
161
162 #[must_use]
163 pub fn shutdown_timeout<T: Into<Millis>>(mut self, timeout: T) -> Self {
171 self.pool = self.pool.shutdown_timeout(timeout);
172 self
173 }
174
175 #[must_use]
176 pub fn status_handler<F>(mut self, handler: F) -> Self
180 where
181 F: FnMut(ServerStatus) + Send + 'static,
182 {
183 self.accept.set_status_handler(handler);
184 self
185 }
186
187 pub async fn configure<F>(mut self, f: F) -> io::Result<Self>
193 where
194 F: AsyncFnOnce(ServiceConfig<Cfg>) -> io::Result<()>,
195 {
196 let cfg = ServiceConfig::new(self.token, self.backlog);
197
198 f(cfg.clone()).await?;
199
200 let (token, sockets, factory) = cfg.into_factory();
201 self.token = token;
202 self.sockets.extend(sockets);
203 self.services.push(factory);
204
205 Ok(self)
206 }
207
208 #[allow(clippy::needless_pass_by_value)]
209 pub fn bind<F, S, I>(
211 mut self,
212 name: impl AsRef<str>,
213 addr: impl net::ToSocketAddrs,
214 cfg: impl Into<SharedCfg>,
215 factory: F,
216 ) -> io::Result<Self>
217 where
218 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
219 S: Service<Cfg::State, Io> + 'static,
220 I: IntoService<S, Cfg::State, Io> + 'static,
221 {
222 let cfg = cfg.into();
223 let sockets = bind_addr(addr, self.backlog)?;
224
225 let mut tokens = Vec::new();
226 for lst in sockets {
227 let token = self.token.next();
228 self.sockets
229 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
230 tokens.push((token, cfg.clone()));
231 }
232
233 self.services.push(factory::create_factory_service(
234 name.as_ref().to_string(),
235 tokens,
236 factory,
237 ));
238
239 Ok(self)
240 }
241
242 #[cfg(unix)]
243 pub fn bind_uds<F, I, S>(
245 self,
246 name: impl AsRef<str>,
247 addr: impl AsRef<std::path::Path>,
248 cfg: impl Into<SharedCfg>,
249 factory: F,
250 ) -> io::Result<Self>
251 where
252 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
253 I: IntoService<S, Cfg::State, Io> + 'static,
254 S: Service<Cfg::State, Io> + 'static,
255 {
256 use std::os::unix::net::UnixListener;
257
258 if let Err(e) = std::fs::remove_file(addr.as_ref()) {
261 if e.kind() != std::io::ErrorKind::NotFound {
263 return Err(e);
264 }
265 }
266
267 let lst = UnixListener::bind(addr)?;
268 self.listen_uds(name, lst, cfg.into(), factory)
269 }
270
271 #[cfg(unix)]
272 pub fn listen_uds<F, I, S>(
276 mut self,
277 name: impl AsRef<str>,
278 lst: std::os::unix::net::UnixListener,
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 let token = self.token.next();
288 self.services.push(factory::create_factory_service(
289 name.as_ref().to_string(),
290 vec![(token, cfg.into())],
291 factory,
292 ));
293 self.sockets
294 .push((token, name.as_ref().to_string(), Listener::from_uds(lst)));
295 Ok(self)
296 }
297
298 pub fn listen<F, S, I>(
300 mut self,
301 name: impl AsRef<str>,
302 lst: net::TcpListener,
303 cfg: impl Into<SharedCfg>,
304 factory: F,
305 ) -> io::Result<Self>
306 where
307 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
308 S: Service<Cfg::State, Io> + 'static,
309 I: IntoService<S, Cfg::State, Io> + '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, cfg.into())],
315 factory,
316 ));
317 self.sockets
318 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
319 Ok(self)
320 }
321
322 pub fn run(self) -> Server<Connection> {
324 assert!(
325 !self.sockets.is_empty(),
326 "Server should have at least one bound socket"
327 );
328 let srv = StreamServer::new(self.accept.notify(), self.state, self.services);
329 let svc = self.pool.run(srv);
330
331 let sockets = self
332 .sockets
333 .into_iter()
334 .map(|sock| {
335 log::info!("Starting \"{}\" service on {}", sock.1, sock.2);
336 (sock.0, sock.2)
337 })
338 .collect();
339 self.accept.start(sockets, svc.clone());
340
341 svc
342 }
343}
344
345impl<Cfg> fmt::Debug for ServerBuilder<Cfg> {
346 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
347 f.debug_struct("ServerBuilder")
348 .field("name", &self.name)
349 .field("token", &self.token)
350 .field("backlog", &self.backlog)
351 .field("sockets", &self.sockets)
352 .field("accept", &self.accept)
353 .field("worker-pool", &self.pool)
354 .finish()
355 }
356}
357
358pub fn bind_addr<S: net::ToSocketAddrs>(
359 addr: S,
360 backlog: i32,
361) -> io::Result<Vec<net::TcpListener>> {
362 let mut err = None;
363 let mut succ = false;
364 let mut sockets = Vec::new();
365 for addr in addr.to_socket_addrs()? {
366 match create_tcp_listener(addr, backlog) {
367 Ok(lst) => {
368 succ = true;
369 sockets.push(lst);
370 }
371 Err(e) => err = Some(e),
372 }
373 }
374
375 if succ {
376 Ok(sockets)
377 } else if let Some(e) = err.take() {
378 Err(e)
379 } else {
380 Err(io::Error::new(
381 io::ErrorKind::InvalidInput,
382 "Cannot bind to address.",
383 ))
384 }
385}
386
387pub fn create_tcp_listener(addr: net::SocketAddr, backlog: i32) -> io::Result<net::TcpListener> {
388 let builder = match addr {
389 net::SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?,
390 net::SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?,
391 };
392
393 #[cfg(not(windows))]
397 builder.set_reuse_address(true)?;
398
399 builder.bind(&SockAddr::from(addr))?;
400 builder.listen(backlog)?;
401 Ok(net::TcpListener::from(builder))
402}
403
404#[cfg(test)]
405mod tests {
406 use super::*;
407
408 #[test]
409 fn test_bind_addr() {
410 let addrs: Vec<net::SocketAddr> = Vec::new();
411 assert!(bind_addr(&addrs[..], 10).is_err());
412 }
413
414 #[ntex::test]
415 async fn test_debug() {
416 let builder = ServerBuilder::default();
417 assert!(format!("{builder:?}").contains("ServerBuilder"));
418 }
419}