use std::collections::HashMap; use futures::{StreamExt, TryStreamExt}; use serde::Deserialize; use tokio_stream::{Stream, StreamMap}; use crate::Status; pub mod command; pub mod http; pub mod tcp; pub type ServiceHandles = HashMap; pub trait IntoService { type Error: std::error::Error + Sync + Send + Sized; fn into_service(self) -> impl Stream> + Send; } pub trait IntoServiceMap { type Error: std::error::Error + Sync + Send + Sized; fn into_service_map(self) -> impl Stream)> + Send; } impl IntoServiceMap for T where T: IntoIterator, V: IntoService, K: std::hash::Hash + std::cmp::Eq + std::clone::Clone + std::marker::Unpin + std::marker::Send, { type Error = V::Error; fn into_service_map(self) -> impl Stream)> + Send { let mut map = StreamMap::new(); for (name, srv) in self.into_iter() { map.insert(name, Box::pin(srv.into_service())); } map } } pub fn default_interval() -> std::time::Duration { std::time::Duration::from_secs(5) } #[derive(Debug, Clone, Deserialize)] pub struct ServiceConfig { pub name: String, #[serde(flatten)] pub kind: ServiceKind, } #[derive(Debug, Clone, Deserialize)] #[serde(rename_all = "lowercase")] pub enum ServiceKind { Http(http::Http), Tcp(tcp::Tcp), Exec(command::Command), } #[derive(Debug, thiserror::Error)] pub enum ServiceError { #[error(transparent)] Http(#[from] http::Error), #[error(transparent)] Tcp(#[from] tcp::Error), #[error(transparent)] Command(#[from] command::Error), } impl IntoService for ServiceKind { type Error = ServiceError; fn into_service(self) -> impl Stream> + Send { match self { ServiceKind::Http(h) => h.into_service().map_err(ServiceError::from).boxed(), ServiceKind::Tcp(t) => t.into_service().map_err(ServiceError::from).boxed(), ServiceKind::Exec(c) => c.into_service().map_err(ServiceError::from).boxed(), } } }