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(&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 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 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 pub fn cfg(&self) -> &Cfg {
199 &self.0
200 }
201
202 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 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 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 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
344unsafe impl<F, Cfg> Send for OnWorkerStartImpl<F, Cfg> where F: Send {}