use std::{collections::HashMap, sync::Arc}; use futures::Stream; use http::Http; use serde::Deserialize; use systemd::Systemd; use tcp::Tcp; use tokio::{ sync::watch::{Receiver, Sender}, task::JoinHandle, }; use tokio_stream::wrappers::WatchStream; use crate::{Error, Status}; pub mod http; pub mod systemd; pub mod tcp; pub type ServiceHandles = Arc>; pub trait ServiceSpawner { fn spawn( self, tx: Sender, ) -> impl std::future::Future> + std::marker::Send + 'static; } #[derive(Debug)] pub struct ServiceHandle { pub handle: JoinHandle>, pub rx: Receiver, } impl ServiceHandle { pub fn new(service: impl ServiceSpawner) -> Self { let (tx, rx) = tokio::sync::watch::channel(Status::default()); let handle = tokio::spawn(service.spawn(tx)); Self { handle, rx } } pub fn status(&self) -> Status { self.rx.borrow().clone() } pub fn into_stream(&self) -> impl Stream { WatchStream::new(self.rx.clone()) } } #[derive(Debug, Clone, Deserialize)] #[serde(untagged)] pub enum Service { Http(Http), Tcp(Tcp), Systemd(Systemd), } impl From for ServiceHandle { fn from(value: Service) -> Self { match value { Service::Http(s) => ServiceHandle::new(s), Service::Tcp(s) => ServiceHandle::new(s), Service::Systemd(s) => ServiceHandle::new(s), } } }