Skip to main content

ntex_server/net/
config.rs

1use std::{cell::RefCell, fmt, io, marker::PhantomData, mem, net, rc::Rc, sync::Arc};
2
3use ntex_io::Io;
4use ntex_service::{IntoService, Pipeline, Service, cfg::SharedCfg};
5use ntex_util::{HashMap, future::BoxFuture};
6
7use super::factory::{FactoryService, FactoryServiceType, NetService, ServerService};
8use super::{ServerAppConfig, Token, builder::bind_addr, socket::Listener};
9
10#[derive(Debug)]
11pub struct ServiceConfig<Cfg: ServerAppConfig>(pub(super) Rc<RefCell<ServiceConfigInner<Cfg>>>);
12
13#[derive(Debug)]
14struct Socket {
15    name: String,
16    sockets: Vec<(Token, Listener, SharedCfg)>,
17}
18
19pub(super) struct ServiceConfigInner<Cfg: ServerAppConfig> {
20    token: Token,
21    on_start_set: bool,
22    on_start: Vec<Box<dyn OnWorkerStart<Cfg::State>>>,
23    sockets: Vec<Socket>,
24    backlog: i32,
25}
26
27impl<Cfg: ServerAppConfig> fmt::Debug for ServiceConfigInner<Cfg> {
28    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29        f.debug_struct("ServiceConfigInner")
30            .field("token", &self.token)
31            .field("backlog", &self.backlog)
32            .field("sockets", &self.sockets)
33            .finish()
34    }
35}
36
37impl<Cfg: ServerAppConfig> Clone for ServiceConfig<Cfg> {
38    fn clone(&self) -> Self {
39        Self(self.0.clone())
40    }
41}
42
43impl<Cfg: ServerAppConfig> ServiceConfig<Cfg> {
44    pub(super) fn new(token: Token, backlog: i32) -> Self {
45        ServiceConfig(Rc::new(RefCell::new(ServiceConfigInner {
46            token,
47            backlog,
48            sockets: Vec::new(),
49            on_start_set: false,
50            on_start: vec![on_worker_start(async |_| {
51                not_configured();
52                Ok(())
53            })],
54        })))
55    }
56
57    /// Add new service to the server.
58    pub fn bind(&self, name: impl AsRef<str>, addr: impl net::ToSocketAddrs) -> io::Result<&Self> {
59        let mut inner = self.0.borrow_mut();
60
61        let sockets = bind_addr(addr, inner.backlog)?;
62        let socket = Socket {
63            name: name.as_ref().to_string(),
64            sockets: sockets
65                .into_iter()
66                .map(|lst| {
67                    (
68                        inner.token.next(),
69                        Listener::from_tcp(lst),
70                        SharedCfg::default(),
71                    )
72                })
73                .collect(),
74        };
75        inner.sockets.push(socket);
76
77        Ok(self)
78    }
79
80    /// Add new service to the server.
81    pub fn listen(&self, name: impl AsRef<str>, lst: net::TcpListener) -> &Self {
82        let mut inner = self.0.borrow_mut();
83        let socket = Socket {
84            name: name.as_ref().to_string(),
85            sockets: vec![(
86                inner.token.next(),
87                Listener::from_tcp(lst),
88                SharedCfg::default(),
89            )],
90        };
91        inner.sockets.push(socket);
92
93        self
94    }
95
96    /// Register async service configuration function.
97    ///
98    /// This function get called during worker runtime configuration stage.
99    /// It get executed in the worker thread.
100    pub fn on_worker_start<F>(&self, f: F) -> &Self
101    where
102        F: AsyncFnOnce(ServiceRuntime<Cfg::State>) -> io::Result<()> + Send + Clone + 'static,
103    {
104        let mut inner = self.0.borrow_mut();
105        if !inner.on_start_set {
106            inner.on_start.clear();
107            inner.on_start_set = true;
108        }
109        inner.on_start.push(on_worker_start(f));
110        self
111    }
112
113    pub(super) fn into_factory(
114        self,
115    ) -> (
116        Token,
117        Vec<(Token, String, Listener)>,
118        FactoryServiceType<Cfg>,
119    ) {
120        let mut inner = self.0.borrow_mut();
121
122        let mut sockets = Vec::new();
123        let mut names = HashMap::default();
124        for (idx, s) in mem::take(&mut inner.sockets).into_iter().enumerate() {
125            names.insert(
126                s.name.clone(),
127                Entry {
128                    idx,
129                    name: s.name.clone(),
130                    tokens: s
131                        .sockets
132                        .iter()
133                        .map(|(token, _, cfg)| (*token, cfg.clone()))
134                        .collect(),
135                },
136            );
137
138            sockets.extend(
139                s.sockets
140                    .into_iter()
141                    .map(|(token, lst, _)| (token, s.name.clone(), lst)),
142            );
143        }
144
145        (
146            inner.token,
147            sockets,
148            Box::new(ConfiguredService {
149                names,
150                on_start: mem::take(&mut inner.on_start),
151            }),
152        )
153    }
154}
155
156pub struct ServiceRuntime<Cfg>(Cfg, Rc<RefCell<ServiceRuntimeInner>>);
157
158#[derive(Debug, Clone)]
159struct Entry {
160    idx: usize,
161    name: String,
162    tokens: Vec<(Token, SharedCfg)>,
163}
164
165struct ServiceRuntimeInner {
166    names: HashMap<String, Entry>,
167    services: Vec<Option<Box<dyn NetService>>>,
168}
169
170impl<Cfg> fmt::Debug for ServiceRuntime<Cfg> {
171    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172        let inner = self.1.borrow();
173        f.debug_struct("ServiceRuntimer")
174            .field("names", &inner.names)
175            .finish()
176    }
177}
178
179impl<Cfg: Clone + 'static> ServiceRuntime<Cfg> {
180    fn new(st: Cfg, names: HashMap<String, Entry>) -> Self {
181        let services = (0..names.len()).map(|_| None).collect();
182        ServiceRuntime(
183            st,
184            Rc::new(RefCell::new(ServiceRuntimeInner { names, services })),
185        )
186    }
187
188    fn validate(&self) {
189        let inner = self.1.as_ref().borrow();
190        for (name, item) in &inner.names {
191            if inner.services[item.idx].is_none() {
192                log::error!("Service {name:?} is not configured");
193            }
194        }
195    }
196
197    /// Server configuration
198    pub fn cfg(&self) -> &Cfg {
199        &self.0
200    }
201
202    /// Register service.
203    ///
204    /// Name of the service must be registered during configuration stage with
205    /// `ServiceConfig::bind()` or `ServiceConfig::listen()` methods.
206    ///
207    /// # Panics
208    ///
209    /// Panics if service with specified name is registered already
210    pub fn service<S>(
211        &self,
212        name: &str,
213        cfg: impl Into<SharedCfg>,
214        svc: impl IntoService<S, Cfg, Io>,
215    ) -> &Self
216    where
217        S: Service<Cfg, Io> + 'static,
218    {
219        let shared = cfg.into();
220        let mut inner = self.1.borrow_mut();
221        if let Some(entry) = inner.names.get_mut(name) {
222            let idx = entry.idx;
223            for token in &mut entry.tokens {
224                token.1 = shared.clone();
225            }
226            let pipeline = Pipeline::with(
227                self.0.clone(),
228                svc.into_service().map(|_| ()).map_err(|_| ()),
229            );
230            let svc: Box<dyn NetService> = Box::new(ServerService { pipeline });
231            inner.services[idx] = Some(svc);
232        } else {
233            panic!("Unknown service: {name:?}");
234        }
235        self
236    }
237
238    /// Map server configuration.
239    pub fn map_cfg<T>(&self, st: T) -> ServiceRuntime<T>
240    where
241        T: Clone + 'static,
242    {
243        ServiceRuntime(st, self.1.clone())
244    }
245}
246
247struct ConfiguredService<Cfg: ServerAppConfig> {
248    names: HashMap<String, Entry>,
249    on_start: Vec<Box<dyn OnWorkerStart<Cfg::State>>>,
250}
251
252impl<Cfg: ServerAppConfig> FactoryService<Cfg> for ConfiguredService<Cfg> {
253    fn clo(&self) -> FactoryServiceType<Cfg> {
254        Box::new(Self {
255            names: self.names.clone(),
256            on_start: self.on_start.iter().map(|cb| (*cb).clo()).collect(),
257        })
258    }
259
260    fn create(
261        &self,
262        st: Cfg::State,
263    ) -> BoxFuture<'static, io::Result<Vec<(Box<dyn NetService>, Arc<str>, Vec<(Token, SharedCfg)>)>>>
264    {
265        // configure services
266        let rt = ServiceRuntime::new(st.clone(), self.names.clone());
267        let on_start: Vec<_> = self
268            .on_start
269            .iter()
270            .map(|cb| cb.run(ServiceRuntime(st.clone(), rt.1.clone())))
271            .collect();
272
273        // construct services
274        Box::pin(async move {
275            for fut in on_start {
276                fut.await?;
277            }
278            rt.validate();
279
280            let names = mem::take(&mut rt.1.borrow_mut().names);
281            let mut services = mem::take(&mut rt.1.borrow_mut().services);
282
283            let mut res = Vec::new();
284            while let Some(svc) = services.pop() {
285                if let Some(svc) = svc {
286                    for entry in names.values() {
287                        if entry.idx == services.len() {
288                            res.push((
289                                svc,
290                                std::sync::Arc::from(entry.name.clone()),
291                                entry.tokens.clone(),
292                            ));
293                            break;
294                        }
295                    }
296                }
297            }
298            Ok(res)
299        })
300    }
301}
302
303fn not_configured() {
304    log::error!("Service is not configured");
305}
306
307trait OnWorkerStart<Cfg>: Send {
308    fn clo(&self) -> Box<dyn OnWorkerStart<Cfg>>;
309
310    fn run(&self, rt: ServiceRuntime<Cfg>) -> BoxFuture<'static, io::Result<()>>;
311}
312
313struct OnWorkerStartImpl<F, Cfg> {
314    f: F,
315    st: PhantomData<Cfg>,
316}
317
318fn on_worker_start<F, Cfg>(f: F) -> Box<dyn OnWorkerStart<Cfg> + Send>
319where
320    F: AsyncFnOnce(ServiceRuntime<Cfg>) -> io::Result<()> + Send + Clone + 'static,
321    Cfg: 'static,
322{
323    Box::new(OnWorkerStartImpl { f, st: PhantomData })
324}
325
326impl<F, Cfg> OnWorkerStart<Cfg> for OnWorkerStartImpl<F, Cfg>
327where
328    F: AsyncFnOnce(ServiceRuntime<Cfg>) -> io::Result<()> + Send + Clone + 'static,
329    Cfg: 'static,
330{
331    fn clo(&self) -> Box<dyn OnWorkerStart<Cfg>> {
332        Box::new(Self {
333            f: self.f.clone(),
334            st: PhantomData,
335        })
336    }
337
338    fn run(&self, rt: ServiceRuntime<Cfg>) -> BoxFuture<'static, io::Result<()>> {
339        let f = self.f.clone();
340        Box::pin(async move { (f)(rt).await })
341    }
342}
343
344// SAFETY: Send cannot be provided authomatically because of R param
345// but R always get executed in one thread and never leave it
346unsafe impl<F, Cfg> Send for OnWorkerStartImpl<F, Cfg> where F: Send {}