mikros 0.3.0

An optionated crate to help building multi-purpose applications.
Documentation
use std::collections::HashMap;
use std::sync::Arc;

use futures::lock::Mutex;
use tokio::sync::watch;

use crate::plugin::service::ServiceExecutionMode;
use crate::service::context::Context;
use crate::service::lifecycle::Lifecycle;
use crate::{definition, env, errors, plugin};

#[async_trait::async_trait]
pub trait ScriptService: ScriptServiceClone + Lifecycle + Send {
    async fn run(&mut self, ctx: Arc<Context>) -> errors::Result<()>;
    async fn cleanup(&self, ctx: Arc<Context>);
}

pub trait ScriptServiceClone {
    fn clone_dyn(&self) -> Box<dyn ScriptService>;
}

impl<T> ScriptServiceClone for T
where
    T: 'static + ScriptService + Clone,
{
    fn clone_dyn(&self) -> Box<dyn ScriptService> {
        Box::new(self.clone())
    }
}

impl Clone for Box<dyn ScriptService> {
    fn clone(&self) -> Self {
        self.clone_dyn()
    }
}

#[derive(Clone)]
pub(crate) struct Script {
    svc: Arc<Mutex<Box<dyn ScriptService>>>,
}

impl Script {
    pub fn new(svc: Box<dyn ScriptService>) -> Self {
        Self {
            svc: Arc::new(Mutex::new(svc)),
        }
    }
}

#[async_trait::async_trait]
impl Lifecycle for Script {
    async fn on_start(&mut self, ctx: Arc<Context>) -> errors::Result<()> {
        self.svc.lock().await.on_start(ctx).await
    }

    async fn on_finish(&self) -> errors::Result<()> {
        self.svc.lock().await.on_finish().await
    }
}

#[async_trait::async_trait]
impl plugin::service::Service for Script {
    fn kind(&self) -> definition::ServiceKind {
        definition::ServiceKind::Script
    }

    fn info(&self) -> serde_json::Value {
        serde_json::json!({
            "kind": self.kind().to_string(),
        })
    }

    fn mode(&self) -> ServiceExecutionMode {
        ServiceExecutionMode::NonBlock
    }

    fn initialize(
        &mut self,
        _: Arc<Context>,
        _: Arc<definition::Definitions>,
        _: Arc<env::Env>,
        _: HashMap<String, serde_json::Value>,
    ) -> errors::Result<()> {
        Ok(())
    }

    async fn run(&mut self, ctx: Arc<Context>, _: watch::Receiver<()>) -> errors::Result<()> {
        self.svc.lock().await.run(ctx).await
    }

    async fn stop(&self, ctx: Arc<Context>) {
        self.svc.lock().await.cleanup(ctx).await;
    }
}