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