torrust_tracker/servers/
registar.rs

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