use std::collections::HashMap;
use std::net::SocketAddr;
use std::sync::Arc;
use derive_more::Constructor;
use tokio::sync::Mutex;
use tokio::task::JoinHandle;
pub type ServiceHeathCheckResult = Result<String, String>;
#[derive(Debug, Constructor)]
pub struct ServiceHealthCheckJob {
pub binding: SocketAddr,
pub info: String,
pub job: JoinHandle<ServiceHeathCheckResult>,
}
pub type FnSpawnServiceHeathCheck = fn(&SocketAddr) -> ServiceHealthCheckJob;
#[derive(Clone, Debug, Constructor)]
pub struct ServiceRegistration {
binding: SocketAddr,
check_fn: FnSpawnServiceHeathCheck,
}
impl ServiceRegistration {
#[must_use]
pub fn spawn_check(&self) -> ServiceHealthCheckJob {
(self.check_fn)(&self.binding)
}
}
pub type ServiceRegistrationForm = tokio::sync::oneshot::Sender<ServiceRegistration>;
pub type ServiceRegistry = Arc<Mutex<HashMap<SocketAddr, ServiceRegistration>>>;
#[derive(Clone, Debug)]
pub struct Registar {
registry: ServiceRegistry,
}
#[allow(clippy::derivable_impls)]
impl Default for Registar {
fn default() -> Self {
Self {
registry: ServiceRegistry::default(),
}
}
}
impl Registar {
pub fn new(register: ServiceRegistry) -> Self {
Self { registry: register }
}
#[must_use]
pub fn give_form(&self) -> ServiceRegistrationForm {
let (tx, rx) = tokio::sync::oneshot::channel::<ServiceRegistration>();
let register = self.clone();
tokio::spawn(async move {
register.insert(rx).await;
});
tx
}
async fn insert(&self, rx: tokio::sync::oneshot::Receiver<ServiceRegistration>) {
tracing::debug!("Waiting for the started service to send registration data ...");
let service_registration = rx
.await
.expect("it should receive the service registration from the started service");
let mut mutex = self.registry.lock().await;
mutex.insert(service_registration.binding, service_registration);
}
#[must_use]
pub fn entries(&self) -> ServiceRegistry {
self.registry.clone()
}
}