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 {
68 self.name = name.as_ref().to_string();
69 self.accept.name(self.name.as_str());
70 self.pool = self.pool.name(self.name.as_str());
71 self
72 }
73
74 #[must_use]
75 pub fn workers(mut self, num: usize) -> Self {
79 self.pool = self.pool.workers(num);
80 self
81 }
82
83 #[must_use]
84 pub fn backlog(mut self, num: i32) -> Self {
95 self.backlog = num;
96 self
97 }
98
99 #[must_use]
100 pub fn maxconn(self, num: usize) -> Self {
107 super::max_concurrent_connections(num);
108 self
109 }
110
111 #[must_use]
112 pub fn stop_runtime(mut self) -> Self {
116 self.pool = self.pool.stop_runtime();
117 self
118 }
119
120 #[must_use]
121 pub fn stop_on_panic(mut self) -> Self {
125 self.pool = self.pool.stop_on_panic();
126 self
127 }
128
129 #[must_use]
130 pub fn disable_signals(mut self) -> Self {
134 self.pool = self.pool.disable_signals();
135 self
136 }
137
138 #[must_use]
139 pub fn enable_affinity(mut self) -> Self {
143 self.pool = self.pool.enable_affinity();
144 self
145 }
146
147 #[must_use]
148 pub fn graceful_shutdown(mut self) -> Self {
154 self.pool = self.pool.graceful_shutdown();
155 self
156 }
157
158 #[must_use]
159 pub fn shutdown_timeout<T: Into<Millis>>(mut self, timeout: T) -> Self {
167 self.pool = self.pool.shutdown_timeout(timeout);
168 self
169 }
170
171 #[must_use]
172 pub fn status_handler<F>(mut self, handler: F) -> Self
176 where
177 F: FnMut(ServerStatus) + Send + 'static,
178 {
179 self.accept.set_status_handler(handler);
180 self
181 }
182
183 pub async fn configure<F>(mut self, f: F) -> io::Result<Self>
189 where
190 F: AsyncFnOnce(ServiceConfig<Cfg>) -> io::Result<()>,
191 {
192 let cfg = ServiceConfig::new(self.token, self.backlog);
193
194 f(cfg.clone()).await?;
195
196 let (token, sockets, factory) = cfg.into_factory();
197 self.token = token;
198 self.sockets.extend(sockets);
199 self.services.push(factory);
200
201 Ok(self)
202 }
203
204 #[allow(clippy::needless_pass_by_value)]
205 pub fn bind<F, S, I>(
207 mut self,
208 name: impl AsRef<str>,
209 addr: impl net::ToSocketAddrs,
210 cfg: impl Into<SharedCfg>,
211 factory: F,
212 ) -> io::Result<Self>
213 where
214 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
215 S: Service<Cfg::State, Io> + 'static,
216 I: IntoService<S, Cfg::State, Io> + 'static,
217 {
218 let cfg = cfg.into();
219 let sockets = bind_addr(addr, self.backlog)?;
220
221 let mut tokens = Vec::new();
222 for lst in sockets {
223 let token = self.token.next();
224 self.sockets
225 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
226 tokens.push((token, cfg.clone()));
227 }
228
229 self.services.push(factory::create_factory_service(
230 name.as_ref().to_string(),
231 tokens,
232 factory,
233 ));
234
235 Ok(self)
236 }
237
238 #[cfg(unix)]
239 pub fn bind_uds<F, I, S>(
241 self,
242 name: impl AsRef<str>,
243 addr: impl AsRef<std::path::Path>,
244 cfg: impl Into<SharedCfg>,
245 factory: F,
246 ) -> io::Result<Self>
247 where
248 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
249 I: IntoService<S, Cfg::State, Io> + 'static,
250 S: Service<Cfg::State, Io> + 'static,
251 {
252 use std::os::unix::net::UnixListener;
253
254 if let Err(e) = std::fs::remove_file(addr.as_ref()) {
257 if e.kind() != std::io::ErrorKind::NotFound {
259 return Err(e);
260 }
261 }
262
263 let lst = UnixListener::bind(addr)?;
264 self.listen_uds(name, lst, cfg.into(), factory)
265 }
266
267 #[cfg(unix)]
268 pub fn listen_uds<F, I, S>(
273 mut self,
274 name: impl AsRef<str>,
275 lst: std::os::unix::net::UnixListener,
276 cfg: impl Into<SharedCfg>,
277 factory: F,
278 ) -> io::Result<Self>
279 where
280 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
281 I: IntoService<S, Cfg::State, Io> + 'static,
282 S: Service<Cfg::State, Io> + 'static,
283 {
284 let token = self.token.next();
285 self.services.push(factory::create_factory_service(
286 name.as_ref().to_string(),
287 vec![(token, cfg.into())],
288 factory,
289 ));
290 self.sockets
291 .push((token, name.as_ref().to_string(), Listener::from_uds(lst)));
292 Ok(self)
293 }
294
295 pub fn listen<F, S, I>(
297 mut self,
298 name: impl AsRef<str>,
299 lst: net::TcpListener,
300 cfg: impl Into<SharedCfg>,
301 factory: F,
302 ) -> io::Result<Self>
303 where
304 F: AsyncFn(&Cfg::State) -> I + Send + Clone + 'static,
305 S: Service<Cfg::State, Io> + 'static,
306 I: IntoService<S, Cfg::State, Io> + 'static,
307 {
308 let token = self.token.next();
309 self.services.push(factory::create_factory_service(
310 name.as_ref().to_string(),
311 vec![(token, cfg.into())],
312 factory,
313 ));
314 self.sockets
315 .push((token, name.as_ref().to_string(), Listener::from_tcp(lst)));
316 Ok(self)
317 }
318
319 pub fn run(self) -> Server<Connection> {
321 assert!(
322 !self.sockets.is_empty(),
323 "Server should have at least one bound socket"
324 );
325 let srv = StreamServer::new(self.accept.notify(), self.state, self.services);
326 let svc = self.pool.run(srv);
327
328 let sockets = self
329 .sockets
330 .into_iter()
331 .map(|sock| {
332 log::info!("Starting \"{}\" service on {}", sock.1, sock.2);
333 (sock.0, sock.2)
334 })
335 .collect();
336 self.accept.start(sockets, svc.clone());
337
338 svc
339 }
340}
341
342impl<Cfg> fmt::Debug for ServerBuilder<Cfg> {
343 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344 f.debug_struct("ServerBuilder")
345 .field("name", &self.name)
346 .field("token", &self.token)
347 .field("backlog", &self.backlog)
348 .field("sockets", &self.sockets)
349 .field("accept", &self.accept)
350 .field("worker-pool", &self.pool)
351 .finish()
352 }
353}
354
355pub fn bind_addr<S: net::ToSocketAddrs>(
357 addr: S,
358 backlog: i32,
359) -> io::Result<Vec<net::TcpListener>> {
360 let mut err = None;
361 let mut succ = false;
362 let mut sockets = Vec::new();
363 for addr in addr.to_socket_addrs()? {
364 match create_tcp_listener(addr, backlog) {
365 Ok(lst) => {
366 succ = true;
367 sockets.push(lst);
368 }
369 Err(e) => err = Some(e),
370 }
371 }
372
373 if succ {
374 Ok(sockets)
375 } else if let Some(e) = err.take() {
376 Err(e)
377 } else {
378 Err(io::Error::new(
379 io::ErrorKind::InvalidInput,
380 "Cannot bind to address.",
381 ))
382 }
383}
384
385pub fn create_tcp_listener(addr: net::SocketAddr, backlog: i32) -> io::Result<net::TcpListener> {
387 let builder = match addr {
388 net::SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?,
389 net::SocketAddr::V6(_) => Socket::new(Domain::IPV6, Type::STREAM, None)?,
390 };
391
392 #[cfg(not(windows))]
396 builder.set_reuse_address(true)?;
397
398 builder.bind(&SockAddr::from(addr))?;
399 builder.listen(backlog)?;
400 Ok(net::TcpListener::from(builder))
401}
402
403#[cfg(test)]
404mod tests {
405 use super::*;
406
407 #[test]
408 fn test_bind_addr() {
409 let addrs: Vec<net::SocketAddr> = Vec::new();
410 assert!(bind_addr(&addrs[..], 10).is_err());
411 }
412
413 #[ntex::test]
414 async fn test_debug() {
415 let builder = ServerBuilder::default();
416 assert!(format!("{builder:?}").contains("ServerBuilder"));
417 }
418}