Skip to main content

ntex_server/net/
mod.rs

1//! General-purpose network server.
2//!
3//! Use [`build()`] or [`ServerBuilder`] to register TCP or Unix domain socket
4//! services. Each worker receives its own service instance and processes
5//! connections on a single-threaded runtime.
6mod accept;
7mod builder;
8mod config;
9mod factory;
10mod service;
11mod socket;
12mod test;
13
14pub use crate::{
15    Affinity, ListenerMetrics, LoadBalancing, NoConfig, RuntimeMetrics, ServerAppConfig,
16    ServerMetrics, ServerStatus, WorkerMetrics,
17};
18
19pub use self::accept::{AcceptLoop, AcceptNotify, AcceptorCommand};
20pub use self::builder::{ServerBuilder, bind_addr, create_tcp_listener};
21pub use self::config::{ServiceConfig, ServiceRuntime};
22pub use self::service::StreamServer;
23pub use self::socket::{Connection, Stream};
24pub use self::test::{TestServer, TestServerBuilder, build_test_server, test_server};
25
26/// Controller for a running network server.
27pub type Server = crate::Server<Connection>;
28
29/// Identifier assigned to a registered listener.
30#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
31pub struct Token(usize);
32
33impl Token {
34    #[must_use]
35    #[allow(clippy::should_implement_trait)]
36    /// Returns the current token and advances this value to the next token.
37    pub fn next(&mut self) -> Token {
38        let token = Token(self.0);
39        self.0 += 1;
40        token
41    }
42}
43
44/// Creates a server builder with no application configuration.
45pub fn build() -> ServerBuilder {
46    ServerBuilder::default()
47}
48
49/// Creates a server builder with application configuration.
50pub fn build_with_config<Cfg>(state: Cfg) -> ServerBuilder<Cfg>
51where
52    Cfg: ServerAppConfig,
53{
54    ServerBuilder::new(state)
55}
56
57/// Default per-worker connection limit.
58const DEFAULT_MAX_CONNS: usize = 25600;
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    /// STATEMENT: Network server diagnostics describe listener configuration and worker services.
65    ///
66    /// HOW:
67    /// - Configure one named listener and check its token, backlog and socket name in diagnostics.
68    /// - Build the stream server and worker service, checking the factory count and token routing.
69    #[ntex::test]
70    async fn debug_network_services() {
71        use crate::ServerConfiguration;
72        use ntex_service::cfg::SharedCfg;
73
74        let config = ServiceConfig::<NoConfig>::new(Token(7), 64);
75        let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
76        config.listen("debug-listener", listener);
77        config.on_worker_start(async |runtime| {
78            runtime.service(
79                "debug-listener",
80                SharedCfg::default(),
81                ntex_service::fn_service(async |_: ntex_io::Io| Ok::<_, ()>(())),
82            );
83            Ok(())
84        });
85        let debug = format!("{config:?}");
86        assert!(debug.contains("ServiceConfigInner { token: Token(8), backlog: 64, sockets: ["));
87        assert!(debug.contains("name: \"debug-listener\""));
88        assert!(debug.contains("Token(7)"));
89
90        let (_, _sockets, factory) = config.into_factory();
91        let accept = AcceptLoop::new();
92        let server = StreamServer::new(
93            accept.notify(),
94            std::sync::Arc::new(NoConfig),
95            vec![factory],
96            DEFAULT_MAX_CONNS,
97        );
98        assert_eq!(
99            format!("{server:?}"),
100            "StreamServer { services: 1, max_conns: 25600 }"
101        );
102        let service = server.create().await.unwrap();
103        let debug = format!("{service:?}");
104        assert!(debug.starts_with("StreamService { tokens: {Token(7): (0, "));
105        assert!(debug.contains("conns: Counter("));
106        assert!(debug.contains("count: Cell { value: 0 }"));
107    }
108
109    #[test]
110    fn token_next() {
111        let mut token = Token(0);
112        assert_eq!(token.next(), Token(0));
113        assert_eq!(token.next(), Token(1));
114        assert_eq!(token, Token(2));
115    }
116}