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