use std::{
cmp::Ordering,
hash::{Hash, Hasher},
sync::Arc,
};
use async_trait::async_trait;
use downcast_rs::{impl_downcast, DowncastSync};
use crate::event::Observable;
use super::{
service_manager::ServiceManager,
types::{Priority, Status},
BoxedError, LifetimedPinnedBoxedFutureResult,
};
#[derive(Debug)]
pub struct ServiceInfo {
pub id: String,
pub name: String,
pub priority: Priority,
pub status: Observable<Status>,
}
impl ServiceInfo {
pub fn new(id: &str, name: &str, priority: Priority) -> Self {
Self {
id: id.to_string(),
name: name.to_string(),
priority,
status: Observable::new(Status::Stopped, format!("{}_status_change", id)),
}
}
}
impl PartialEq for ServiceInfo {
fn eq(&self, other: &Self) -> bool {
self.id == other.id
}
}
impl Eq for ServiceInfo {}
impl Ord for ServiceInfo {
fn cmp(&self, other: &Self) -> Ordering {
self.name.cmp(&other.name)
}
}
impl PartialOrd for ServiceInfo {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for ServiceInfo {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
}
}
#[async_trait]
pub trait Service: DowncastSync {
fn info(&self) -> &ServiceInfo;
async fn start(&mut self, service_manager: Arc<ServiceManager>) -> Result<(), BoxedError>;
async fn stop(&mut self) -> Result<(), BoxedError>;
fn task<'a>(&self) -> Option<LifetimedPinnedBoxedFutureResult<'a, ()>> {
None
}
async fn is_available(&self) -> bool {
matches!(self.info().status.get().await, Status::Started)
}
}
impl_downcast!(sync Service);
impl Eq for dyn Service {}
impl PartialEq for dyn Service {
fn eq(&self, other: &Self) -> bool {
self.info() == other.info()
}
}
impl Ord for dyn Service {
fn cmp(&self, other: &Self) -> Ordering {
self.info().cmp(other.info())
}
}
impl PartialOrd for dyn Service {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for dyn Service {
fn hash<H: Hasher>(&self, state: &mut H) {
self.info().hash(state);
}
}