use std::sync::Arc;
use core::{future::Future, pin::Pin};
use crate::definition::Definitions;
use crate::env::Env;
use crate::errors;
use crate::service::context::Context;
#[async_trait::async_trait]
pub trait Feature: Send + FeatureClone + std::any::Any {
fn name(&self) -> &str;
fn info(&self) -> Option<serde_json::Value>;
fn is_enabled(&self) -> bool;
fn can_be_initialized(
&self,
definitions: Arc<Definitions>,
envs: Arc<Env>,
) -> errors::Result<bool>;
async fn initialize(&mut self, ctx: Arc<Context>) -> errors::Result<()>;
async fn cleanup(&self);
fn service_api(&self) -> Option<&dyn std::any::Any>;
}
pub trait FeatureClone {
fn clone_box(&self) -> Box<dyn Feature>;
}
impl<T> FeatureClone for T
where
T: 'static + Feature + Clone,
{
fn clone_box(&self) -> Box<dyn Feature> {
Box::new(self.clone())
}
}
impl Clone for Box<dyn Feature> {
fn clone(&self) -> Box<dyn Feature> {
self.clone_box()
}
}
pub type BoxResultFuture<'a, T> = Pin<Box<dyn Future<Output = errors::Result<T>> + Send + 'a>>;
#[macro_export]
macro_rules! impl_feature_public_api {
($api_trait:ident, $api_struct:ident, $feature_name:expr) => {
pub fn new() -> Box<dyn mikros::plugin::feature::Feature> {
Box::new($api_struct::default())
}
pub async fn execute_on<F, T>(ctx: Arc<Context>, f: F) -> mikros::errors::Result<T>
where
F: for<'a> FnOnce(&'a dyn $api_trait) -> mikros::plugin::feature::BoxResultFuture<'a, T>,
{
let feature = ctx.feature($feature_name).await?;
if let Some(api) = to_api(&feature) {
return f(api).await;
}
Err(mikros::errors::ServiceError::internal(ctx, &format!("feature {} not found", $feature_name)))
}
fn to_api(feature: &Box<dyn mikros::plugin::feature::Feature>) -> Option<&dyn $api_trait> {
feature
.service_api()?
.downcast_ref::<$api_struct>()
.map(|s| s as &dyn $api_trait)
}
};
}
pub fn box_result<'a, F, T>(fut: F) -> BoxResultFuture<'a, T>
where
F: Future<Output = errors::Result<T>> + Send + 'a,
{
Box::pin(fut)
}
#[macro_export]
macro_rules! feature_async {
($e:expr) => {
mikros::plugin::feature::box_result(async move { $e })
};
}