Skip to main content

torrust_server_lib/
registar.rs

1//! Registar. Registers Services for Health Check.
2
3use std::collections::HashMap;
4use std::sync::Arc;
5
6use derive_more::Constructor;
7use tokio::sync::Mutex;
8use tokio::task::JoinHandle;
9use torrust_net_primitives::service_binding::ServiceBinding;
10
11/// A [`ServiceHeathCheckResult`] is returned by a completed health check.
12pub type ServiceHeathCheckResult = Result<String, String>;
13
14/// The [`ServiceHealthCheckJob`] has a health check job with it's metadata
15///
16/// The `job` awaits a [`ServiceHeathCheckResult`].
17#[derive(Debug, Constructor)]
18pub struct ServiceHealthCheckJob {
19    pub service_binding: ServiceBinding,
20    pub info: String,
21    pub service_type: String,
22    pub job: JoinHandle<ServiceHeathCheckResult>,
23}
24
25/// The function specification [`FnSpawnServiceHeathCheck`].
26///
27/// A function fulfilling this specification will spawn a new [`ServiceHealthCheckJob`].
28pub type FnSpawnServiceHeathCheck = fn(&ServiceBinding) -> ServiceHealthCheckJob;
29
30/// A [`ServiceRegistration`] is provided to the [`Registar`] for registration.
31///
32/// Each registration includes a function that fulfils the [`FnSpawnServiceHeathCheck`] specification.
33#[derive(Clone, Debug, Constructor)]
34pub struct ServiceRegistration {
35    service_binding: ServiceBinding,
36    check_fn: FnSpawnServiceHeathCheck,
37}
38
39impl ServiceRegistration {
40    #[must_use]
41    pub fn spawn_check(&self) -> ServiceHealthCheckJob {
42        (self.check_fn)(&self.service_binding)
43    }
44}
45
46/// A [`ServiceRegistrationForm`] will return a completed [`ServiceRegistration`] to the [`Registar`].
47pub type ServiceRegistrationForm = tokio::sync::oneshot::Sender<ServiceRegistration>;
48
49/// The [`ServiceRegistry`] contains each unique [`ServiceRegistration`] by it's [`SocketAddr`].
50pub type ServiceRegistry = Arc<Mutex<HashMap<ServiceBinding, ServiceRegistration>>>;
51
52/// The [`Registar`] manages the [`ServiceRegistry`].
53#[derive(Clone, Debug)]
54pub struct Registar {
55    registry: ServiceRegistry,
56}
57
58#[allow(clippy::derivable_impls)]
59impl Default for Registar {
60    fn default() -> Self {
61        Self {
62            registry: ServiceRegistry::default(),
63        }
64    }
65}
66
67impl Registar {
68    pub fn new(register: ServiceRegistry) -> Self {
69        Self { registry: register }
70    }
71
72    /// Registers a Service
73    #[must_use]
74    pub fn give_form(&self) -> ServiceRegistrationForm {
75        let (tx, rx) = tokio::sync::oneshot::channel::<ServiceRegistration>();
76        let register = self.clone();
77        tokio::spawn(async move {
78            register.insert(rx).await;
79        });
80        tx
81    }
82
83    /// Inserts a listing into the registry.
84    async fn insert(&self, rx: tokio::sync::oneshot::Receiver<ServiceRegistration>) {
85        tracing::debug!("Waiting for the started service to send registration data ...");
86
87        let service_registration = rx
88            .await
89            .expect("it should receive the service registration from the started service");
90
91        let mut mutex = self.registry.lock().await;
92
93        mutex.insert(service_registration.service_binding.clone(), service_registration);
94    }
95
96    /// Returns the [`ServiceRegistry`] of services
97    #[must_use]
98    pub fn entries(&self) -> ServiceRegistry {
99        self.registry.clone()
100    }
101}