Skip to main content

veilid_core/
component.rs

1use super::*;
2
3impl_veilid_log_facility!("registry");
4
5pub(crate) trait AsAnyArcSendSync {
6    fn as_any_arc_send_sync(self: Arc<Self>) -> Arc<dyn core::any::Any + Send + Sync>;
7}
8
9impl<T: Send + Sync + 'static> AsAnyArcSendSync for T {
10    fn as_any_arc_send_sync(self: Arc<Self>) -> Arc<dyn core::any::Any + Send + Sync> {
11        self
12    }
13}
14
15pub(crate) trait VeilidComponent:
16    AsAnyArcSendSync + VeilidComponentRegistryAccessor + core::fmt::Debug
17{
18    fn name(&self) -> &'static str;
19    fn log_facilities(&self) -> VeilidComponentLogFacilities;
20    fn init(&self) -> PinBoxFuture<'_, EyreResult<()>>;
21    fn post_init(&self) -> PinBoxFuture<'_, EyreResult<()>>;
22    fn pre_terminate(&self) -> PinBoxFuture<'_, ()>;
23    fn terminate(&self) -> PinBoxFuture<'_, ()>;
24}
25
26pub(crate) trait VeilidComponentRegistryAccessor {
27    fn registry(&self) -> VeilidComponentRegistry;
28
29    fn config(&self) -> Arc<VeilidConfig> {
30        self.registry().unlocked_inner.startup_options.config()
31    }
32    fn update_callback(&self) -> UpdateCallback {
33        self.registry()
34            .unlocked_inner
35            .startup_options
36            .update_callback()
37    }
38    fn event_bus(&self) -> EventBus {
39        self.registry().event_bus()
40    }
41    fn log_key(&self) -> VeilidLogKey {
42        self.registry().log_key()
43    }
44}
45
46/// Borrow guard holding a shared reference to a registered component for the duration of `'a`.
47pub struct VeilidComponentGuard<'a, T: Send + Sync + 'static> {
48    component: Arc<T>,
49    _phantom: core::marker::PhantomData<&'a T>,
50}
51
52impl<T> core::ops::Deref for VeilidComponentGuard<'_, T>
53where
54    T: Send + Sync + 'static,
55{
56    type Target = T;
57
58    fn deref(&self) -> &Self::Target {
59        &self.component
60    }
61}
62
63#[derive(Debug)]
64struct VeilidComponentRegistryInner {
65    type_map: HashMap<core::any::TypeId, Arc<dyn VeilidComponent + Send + Sync>>,
66    init_order: Vec<core::any::TypeId>,
67    #[cfg(any(test, feature = "test-util"))]
68    mock: bool,
69}
70
71#[derive(Debug)]
72struct VeilidComponentRegistryUnlockedInner {
73    inner: Mutex<VeilidComponentRegistryInner>,
74    startup_options: VeilidStartupOptions,
75    namespace: &'static str,
76    program_name: &'static str,
77    log_key: &'static str,
78    event_bus: EventBus,
79    init_lock: AsyncMutex<bool>,
80}
81
82#[derive(Clone, Debug)]
83pub(crate) struct VeilidComponentRegistry {
84    unlocked_inner: Arc<VeilidComponentRegistryUnlockedInner>,
85}
86
87impl VeilidComponentRegistry {
88    pub fn new(startup_options: VeilidStartupOptions) -> Self {
89        let namespace = startup_options.config().namespace.to_static_str();
90        let program_name = startup_options.config().program_name.to_static_str();
91
92        let log_key = VeilidLayerFilter::make_veilid_log_key(program_name, namespace);
93
94        Self {
95            unlocked_inner: Arc::new(VeilidComponentRegistryUnlockedInner {
96                inner: Mutex::new(VeilidComponentRegistryInner {
97                    type_map: HashMap::new(),
98                    init_order: Vec::new(),
99                    #[cfg(any(test, feature = "test-util"))]
100                    mock: false,
101                }),
102                startup_options,
103                namespace,
104                program_name,
105                log_key,
106                event_bus: EventBus::new(),
107                init_lock: AsyncMutex::new(false),
108            }),
109        }
110    }
111
112    #[cfg(any(test, feature = "test-util"))]
113    pub fn enable_mock(&self) {
114        let mut inner = self.unlocked_inner.inner.lock();
115        inner.mock = true;
116    }
117    // #[cfg(any(test, feature = "test-util"))]
118    // pub fn is_mock(&self) -> bool {
119    //     let inner = self.unlocked_inner.inner.lock();
120    //     inner.mock
121    // }
122
123    #[expect(dead_code)]
124    pub fn namespace(&self) -> &'static str {
125        self.unlocked_inner.namespace
126    }
127
128    #[allow(dead_code)]
129    pub fn program_name(&self) -> &'static str {
130        self.unlocked_inner.program_name
131    }
132
133    pub fn log_key(&self) -> VeilidLogKey {
134        self.unlocked_inner.log_key
135    }
136
137    pub fn event_bus(&self) -> EventBus {
138        self.unlocked_inner.event_bus.clone()
139    }
140
141    pub fn register<
142        T: VeilidComponent + Send + Sync + 'static,
143        F: FnOnce(VeilidComponentRegistry) -> T,
144    >(
145        &self,
146        component_constructor: F,
147    ) {
148        let component = Arc::new(component_constructor(self.clone()));
149        let component_type_id = core::any::TypeId::of::<T>();
150
151        // Add to type map and initialization order
152        let mut inner = self.unlocked_inner.inner.lock();
153        if inner
154            .type_map
155            .insert(component_type_id, component)
156            .is_some()
157        {
158            veilid_log!(self error "should not register same component twice");
159            return;
160        }
161        inner.init_order.push(component_type_id);
162    }
163
164    pub fn register_with_context<
165        C,
166        T: VeilidComponent + Send + Sync + 'static,
167        F: FnOnce(VeilidComponentRegistry, C) -> T,
168    >(
169        &self,
170        component_constructor: F,
171        context: C,
172    ) {
173        let component = Arc::new(component_constructor(self.clone(), context));
174        let component_type_id = core::any::TypeId::of::<T>();
175
176        // Add to type map and initialization order
177        let mut inner = self.unlocked_inner.inner.lock();
178        if inner
179            .type_map
180            .insert(component_type_id, component)
181            .is_some()
182        {
183            veilid_log!(self error "should not register same component twice");
184            return;
185        }
186        inner.init_order.push(component_type_id);
187    }
188
189    pub async fn init(&self) -> EyreResult<()> {
190        let Some(mut _init_guard) = self.unlocked_inner.init_lock.try_lock() else {
191            bail!("init should only happen one at a time");
192        };
193        if *_init_guard {
194            bail!("already initialized");
195        }
196
197        VeilidLayerFilter::init_veilid_component_log_facilities(
198            self.log_key(),
199            self.get_init_order()
200                .into_iter()
201                .map(|x| x.log_facilities())
202                .collect(),
203        )?;
204
205        // Event bus starts up early
206        self.unlocked_inner.event_bus.startup()?;
207
208        // Process components in initialization order
209        let init_order = self.get_init_order();
210        let mut initialized = vec![];
211        for component in init_order {
212            if let Err(e) = component.init().await {
213                veilid_log!(self error "Error initializing component '{}': {}", component.name(), e);
214                self.terminate_inner(initialized).await;
215                self.unlocked_inner.event_bus.shutdown().await;
216                return Err(e);
217            }
218            initialized.push(component);
219        }
220
221        *_init_guard = true;
222        Ok(())
223    }
224
225    pub async fn post_init(&self) -> EyreResult<()> {
226        let Some(mut _init_guard) = self.unlocked_inner.init_lock.try_lock() else {
227            bail!("init should only happen one at a time");
228        };
229        if !*_init_guard {
230            bail!("not initialized");
231        }
232
233        let init_order = self.get_init_order();
234        let mut post_initialized = vec![];
235        for component in init_order {
236            if let Err(e) = component.post_init().await {
237                self.pre_terminate_inner(post_initialized).await;
238                return Err(e);
239            }
240            post_initialized.push(component)
241        }
242        Ok(())
243    }
244
245    pub async fn pre_terminate(&self) {
246        let Some(mut _init_guard) = self.unlocked_inner.init_lock.try_lock() else {
247            veilid_log!(self error "terminate should only happen one at a time");
248            return;
249        };
250        if !*_init_guard {
251            veilid_log!(self error "not initialized");
252            return;
253        }
254
255        let init_order = self.get_init_order();
256        self.pre_terminate_inner(init_order).await;
257    }
258
259    pub async fn terminate(&self) {
260        let Some(mut _init_guard) = self.unlocked_inner.init_lock.try_lock() else {
261            veilid_log!(self error "terminate should only happen one at a time");
262            return;
263        };
264        if !*_init_guard {
265            veilid_log!(self error "not initialized");
266            return;
267        }
268
269        // Terminate components in reverse initialization order
270        let init_order = self.get_init_order();
271        self.terminate_inner(init_order).await;
272
273        // Event bus shuts down last
274        self.unlocked_inner.event_bus.shutdown().await;
275
276        // Remoave all registered component log facilities from VeilidLayerFilter for this log key
277        if let Err(e) = VeilidLayerFilter::terminate_veilid_component_log_facilities(self.log_key())
278        {
279            eprintln!("Error terminating log facilities: {}", e);
280        }
281
282        *_init_guard = false;
283    }
284
285    async fn pre_terminate_inner(
286        &self,
287        pre_initialized: Vec<Arc<dyn VeilidComponent + Send + Sync>>,
288    ) {
289        for component in pre_initialized.iter().rev() {
290            component.pre_terminate().await;
291        }
292    }
293    async fn terminate_inner(&self, initialized: Vec<Arc<dyn VeilidComponent + Send + Sync>>) {
294        for component in initialized.iter().rev() {
295            let refs = Arc::strong_count(component);
296            if refs > 2 {
297                veilid_log!(self warn
298                    "Terminating component '{}' while still referenced ({} extra references)",
299                    component.name(),
300                    refs - 2
301                );
302            }
303            component.terminate().await;
304        }
305    }
306
307    fn get_init_order(&self) -> Vec<Arc<dyn VeilidComponent + Send + Sync>> {
308        let inner = self.unlocked_inner.inner.lock();
309        inner
310            .init_order
311            .iter()
312            .map(|id| inner.type_map.get(id).unwrap_or_log().clone())
313            .collect::<Vec<_>>()
314    }
315
316    //////////////////////////////////////////////////////////////
317
318    pub fn lookup<'a, T: VeilidComponent + Send + Sync + 'static>(
319        &self,
320    ) -> Option<VeilidComponentGuard<'a, T>> {
321        let inner = self.unlocked_inner.inner.lock();
322        let component_type_id = core::any::TypeId::of::<T>();
323        let component_dyn = inner.type_map.get(&component_type_id)?.clone();
324        let component = component_dyn
325            .as_any_arc_send_sync()
326            .downcast::<T>()
327            .unwrap_or_log();
328        Some(VeilidComponentGuard {
329            component,
330            _phantom: core::marker::PhantomData {},
331        })
332    }
333}
334
335impl VeilidComponentRegistryAccessor for VeilidComponentRegistry {
336    fn registry(&self) -> VeilidComponentRegistry {
337        self.clone()
338    }
339}
340
341impl VeilidComponentRegistryAccessor for &VeilidComponentRegistry {
342    fn registry(&self) -> VeilidComponentRegistry {
343        (*self).clone()
344    }
345}
346
347////////////////////////////////////////////////////////////////////
348
349macro_rules! impl_veilid_component_accessors {
350    ($struct_name:ty) => {
351        impl VeilidComponentRegistryAccessor for $struct_name {
352            fn registry(&self) -> VeilidComponentRegistry {
353                self.registry.clone()
354            }
355        }
356        impl VeilidComponentRegistryAccessor for &$struct_name {
357            fn registry(&self) -> VeilidComponentRegistry {
358                self.registry.clone()
359            }
360        }
361    };
362}
363
364pub(crate) use impl_veilid_component_accessors;
365
366/////////////////////////////////////////////////////////////////////
367
368macro_rules! impl_veilid_component {
369    ($component_name:ty) => {
370        impl_veilid_component_accessors!($component_name);
371
372        impl VeilidComponent for $component_name {
373            fn name(&self) -> &'static str {
374                stringify!($component_name)
375            }
376
377            fn log_facilities(&self) -> VeilidComponentLogFacilities {
378                <$component_name>::log_facilities_impl(self)
379            }
380
381            fn init(&self) -> PinBoxFuture<'_, EyreResult<()>> {
382                Box::pin(async { self.init_async().await })
383            }
384
385            fn post_init(&self) -> PinBoxFuture<'_, EyreResult<()>> {
386                Box::pin(async { self.post_init_async().await })
387            }
388
389            fn pre_terminate(&self) -> PinBoxFuture<'_, ()> {
390                Box::pin(async { self.pre_terminate_async().await })
391            }
392
393            fn terminate(&self) -> PinBoxFuture<'_, ()> {
394                Box::pin(async { self.terminate_async().await })
395            }
396        }
397    };
398}
399
400pub(crate) use impl_veilid_component;
401
402/////////////////////////////////////////////////////////////////////
403
404// Utility macro for setting up a background TickTask
405// Should be called during new/construction of a component with background tasks
406// and before any post-init 'tick' operations are started
407macro_rules! impl_setup_task {
408    ($this:expr, $this_type:ty, $task_name:ident, $task_routine:ident ) => {{
409        let registry = $this.registry();
410        $this.$task_name.set_routine(move |s, l, t| {
411            let registry = registry.clone();
412            Box::pin(async move {
413                let this = registry.lookup::<$this_type>().unwrap_or_log();
414                this.$task_routine(s, Timestamp::new(l), Timestamp::new(t))
415            })
416        });
417    }};
418}
419
420pub(crate) use impl_setup_task;
421
422macro_rules! impl_setup_task_clone {
423    ($this:expr, $task_name:ident, $task_routine:ident ) => {{
424        let this = $this.clone();
425        $this.$task_name.set_routine(move |s, l, t| {
426            let this = this.clone();
427            Box::pin(async move { this.$task_routine(s, Timestamp::new(l), Timestamp::new(t)) })
428        });
429    }};
430}
431
432pub(crate) use impl_setup_task_clone;
433
434macro_rules! impl_setup_task_async {
435    ($this:expr, $this_type:ty, $task_name:ident, $task_routine:ident ) => {{
436        let registry = $this.registry();
437        $this.$task_name.set_routine(move |s, l, t| {
438            let registry = registry.clone();
439            Box::pin(async move {
440                let this = registry.lookup::<$this_type>().unwrap_or_log();
441                this.$task_routine(s, Timestamp::new(l), Timestamp::new(t))
442                    .await
443            })
444        });
445    }};
446}
447
448pub(crate) use impl_setup_task_async;
449
450macro_rules! impl_setup_task_async_clone {
451    ($this:expr, $task_name:ident, $task_routine:ident ) => {{
452        let this = $this.clone();
453        $this.$task_name.set_routine(move |s, l, t| {
454            let this = this.clone();
455            Box::pin(async move {
456                this.$task_routine(s, Timestamp::new(l), Timestamp::new(t))
457                    .await
458            })
459        });
460    }};
461}
462
463pub(crate) use impl_setup_task_async_clone;
464
465// Utility macro for setting up an event bus handler
466// Should be called after init, during post-init or later
467// Subscription should be unsubscribed before termination
468macro_rules! impl_subscribe_event_bus {
469    ($this:expr, $this_type:ty, $event_handler:ident ) => {{
470        let registry = $this.registry();
471        $this.event_bus().subscribe(move |evt| {
472            let registry = registry.clone();
473            Box::pin(async move {
474                let this = registry.lookup::<$this_type>().unwrap_or_log();
475                this.$event_handler(evt);
476            })
477        })
478    }};
479}
480
481pub(crate) use impl_subscribe_event_bus;
482
483macro_rules! impl_subscribe_event_bus_async {
484    ($this:expr, $this_type:ty, $event_handler:ident ) => {{
485        let registry = $this.registry();
486        $this.event_bus().subscribe(move |evt| {
487            let registry = registry.clone();
488            Box::pin(async move {
489                let this = registry.lookup::<$this_type>().unwrap_or_log();
490                this.$event_handler(evt).await;
491            })
492        })
493    }};
494}
495
496pub(crate) use impl_subscribe_event_bus_async;
497
498macro_rules! impl_subscribe_event_bus_async_clone {
499    ($this:expr, $event_handler:ident ) => {{
500        let this = $this.clone();
501        $this.event_bus().subscribe(move |evt| {
502            let this = this.clone();
503            Box::pin(async move {
504                this.$event_handler(evt).await;
505            })
506        })
507    }};
508}
509
510pub(crate) use impl_subscribe_event_bus_async_clone;
511
512macro_rules! impl_subscribe_event_bus_clone {
513    ($this:expr, $event_handler:ident ) => {{
514        let this = $this.clone();
515        $this.event_bus().subscribe(move |evt| {
516            let this = this.clone();
517            Box::pin(async move {
518                this.$event_handler(evt);
519            })
520        })
521    }};
522}
523
524pub(crate) use impl_subscribe_event_bus_clone;