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 pub fn bind(
59 &self,
60 name: impl AsRef<str>,
61 addr: impl net::ToSocketAddrs,
62 cfg: impl Into<SharedCfg>,
63 ) -> io::Result<&Self> {
64 let mut inner = self.0.borrow_mut();
65
66 let cfg = cfg.into();
67 let sockets = bind_addr(addr, inner.backlog)?;
68 let socket = Socket {
69 name: name.as_ref().to_string(),
70 sockets: sockets
71 .into_iter()
72 .map(|lst| (inner.token.next(), Listener::from_tcp(lst), cfg.clone()))
73 .collect(),
74 };
75 inner.sockets.push(socket);
76
77 Ok(self)
78 }
79
80 pub fn listen(
82 &self,
83 name: impl AsRef<str>,
84 lst: net::TcpListener,
85 cfg: impl Into<SharedCfg>,
86 ) -> &Self {
87 let mut inner = self.0.borrow_mut();
88 let socket = Socket {
89 name: name.as_ref().to_string(),
90 sockets: vec![(inner.token.next(), Listener::from_tcp(lst), cfg.into())],
91 };
92 inner.sockets.push(socket);
93
94 self
95 }
96
97 pub fn on_worker_start<F>(&self, f: F) -> &Self
102 where
103 F: AsyncFn(ServiceRuntime<Cfg::State>) -> io::Result<()> + Send + Clone + 'static,
104 {
105 let mut inner = self.0.borrow_mut();
106 if !inner.on_start_set {
107 inner.on_start.clear();
108 inner.on_start_set = true;
109 }
110 inner.on_start.push(on_worker_start(f));
111 self
112 }
113
114 pub(super) fn into_factory(
115 self,
116 ) -> (
117 Token,
118 Vec<(Token, String, Listener)>,
119 FactoryServiceType<Cfg>,
120 ) {
121 let mut inner = self.0.borrow_mut();
122
123 let mut sockets = Vec::new();
124 let mut names = HashMap::default();
125 for (idx, s) in mem::take(&mut inner.sockets).into_iter().enumerate() {
126 names.insert(
127 s.name.clone(),
128 Entry {
129 idx,
130 name: s.name.clone(),
131 tokens: s
132 .sockets
133 .iter()
134 .map(|(token, _, cfg)| (*token, cfg.clone()))
135 .collect(),
136 },
137 );
138
139 sockets.extend(
140 s.sockets
141 .into_iter()
142 .map(|(token, lst, _)| (token, s.name.clone(), lst)),
143 );
144 }
145
146 (
147 inner.token,
148 sockets,
149 Box::new(ConfiguredService {
150 names,
151 on_start: mem::take(&mut inner.on_start),
152 }),
153 )
154 }
155}
156
157pub struct ServiceRuntime<Cfg>(Cfg, Rc<RefCell<ServiceRuntimeInner>>);
158
159#[derive(Debug, Clone)]
160struct Entry {
161 idx: usize,
162 name: String,
163 tokens: Vec<(Token, SharedCfg)>,
164}
165
166struct ServiceRuntimeInner {
167 names: HashMap<String, Entry>,
168 services: Vec<Option<Box<dyn NetService>>>,
169}
170
171impl<Cfg> fmt::Debug for ServiceRuntime<Cfg> {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 let inner = self.1.borrow();
174 f.debug_struct("ServiceRuntimer")
175 .field("names", &inner.names)
176 .finish()
177 }
178}
179
180impl<Cfg: Clone + 'static> ServiceRuntime<Cfg> {
181 fn new(st: Cfg, names: HashMap<String, Entry>) -> Self {
182 let services = (0..names.len()).map(|_| None).collect();
183 ServiceRuntime(
184 st,
185 Rc::new(RefCell::new(ServiceRuntimeInner { names, services })),
186 )
187 }
188
189 fn validate(&self) {
190 let inner = self.1.as_ref().borrow();
191 for (name, item) in &inner.names {
192 if inner.services[item.idx].is_none() {
193 log::error!("Service {name:?} is not configured");
194 }
195 }
196 }
197
198 pub fn cfg(&self) -> &Cfg {
200 &self.0
201 }
202
203 pub fn service<S>(&self, name: &str, svc: impl IntoService<S, Cfg, Io>) -> &Self
212 where
213 S: Service<Cfg, Io> + 'static,
214 {
215 let mut inner = self.1.borrow_mut();
216 if let Some(entry) = inner.names.get_mut(name) {
217 let idx = entry.idx;
218 let pipeline = Pipeline::with(
219 self.0.clone(),
220 svc.into_service().map(|_| ()).map_err(|_| ()),
221 );
222 let svc: Box<dyn NetService> = Box::new(ServerService { pipeline });
223 inner.services[idx] = Some(svc);
224 } else {
225 panic!("Unknown service: {name:?}");
226 }
227 self
228 }
229
230 pub fn map_cfg<T>(&self, st: T) -> ServiceRuntime<T>
232 where
233 T: Clone + 'static,
234 {
235 ServiceRuntime(st, self.1.clone())
236 }
237}
238
239struct ConfiguredService<Cfg: ServerAppConfig> {
240 names: HashMap<String, Entry>,
241 on_start: Vec<Box<dyn OnWorkerStart<Cfg::State>>>,
242}
243
244impl<Cfg: ServerAppConfig> FactoryService<Cfg> for ConfiguredService<Cfg> {
245 fn clo(&self) -> FactoryServiceType<Cfg> {
246 Box::new(Self {
247 names: self.names.clone(),
248 on_start: self.on_start.iter().map(|cb| (*cb).clo()).collect(),
249 })
250 }
251
252 fn create(
253 &self,
254 st: Cfg::State,
255 ) -> BoxFuture<'static, io::Result<Vec<(Box<dyn NetService>, Arc<str>, Vec<(Token, SharedCfg)>)>>>
256 {
257 let rt = ServiceRuntime::new(st.clone(), self.names.clone());
259 let on_start: Vec<_> = self
260 .on_start
261 .iter()
262 .map(|cb| cb.run(ServiceRuntime(st.clone(), rt.1.clone())))
263 .collect();
264
265 Box::pin(async move {
267 for fut in on_start {
268 fut.await?;
269 }
270 rt.validate();
271
272 let names = mem::take(&mut rt.1.borrow_mut().names);
273 let mut services = mem::take(&mut rt.1.borrow_mut().services);
274
275 let mut res = Vec::new();
276 while let Some(svc) = services.pop() {
277 if let Some(svc) = svc {
278 for entry in names.values() {
279 if entry.idx == services.len() {
280 res.push((
281 svc,
282 std::sync::Arc::from(entry.name.clone()),
283 entry.tokens.clone(),
284 ));
285 break;
286 }
287 }
288 }
289 }
290 Ok(res)
291 })
292 }
293}
294
295fn not_configured() {
296 log::error!("Service is not configured");
297}
298
299trait OnWorkerStart<Cfg>: Send {
300 fn clo(&self) -> Box<dyn OnWorkerStart<Cfg>>;
301
302 fn run(&self, rt: ServiceRuntime<Cfg>) -> BoxFuture<'static, io::Result<()>>;
303}
304
305struct OnWorkerStartImpl<F, Cfg> {
306 f: F,
307 st: PhantomData<Cfg>,
308}
309
310fn on_worker_start<F, Cfg>(f: F) -> Box<dyn OnWorkerStart<Cfg> + Send>
311where
312 F: AsyncFn(ServiceRuntime<Cfg>) -> io::Result<()> + Send + Clone + 'static,
313 Cfg: 'static,
314{
315 Box::new(OnWorkerStartImpl { f, st: PhantomData })
316}
317
318impl<F, Cfg> OnWorkerStart<Cfg> for OnWorkerStartImpl<F, Cfg>
319where
320 F: AsyncFn(ServiceRuntime<Cfg>) -> io::Result<()> + Send + Clone + 'static,
321 Cfg: 'static,
322{
323 fn clo(&self) -> Box<dyn OnWorkerStart<Cfg>> {
324 Box::new(Self {
325 f: self.f.clone(),
326 st: PhantomData,
327 })
328 }
329
330 fn run(&self, rt: ServiceRuntime<Cfg>) -> BoxFuture<'static, io::Result<()>> {
331 let f = self.f.clone();
332 Box::pin(async move { (f)(rt).await })
333 }
334}
335
336unsafe impl<F, Cfg> Send for OnWorkerStartImpl<F, Cfg> where F: Send {}