desert_framework 0.1.1

Micro-framework for building backend applications in Rust with Axum
Documentation
use std::{
    any::{Any, TypeId},
    collections::HashMap,
    sync::Arc,
};

use tokio::sync::RwLock;

use crate::service::Service;

#[derive(Debug)]
pub struct DependencyManager {
    dependencies: Arc<RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>>,
}

impl Default for DependencyManager {
    fn default() -> Self {
        Self::new()
    }
}

impl DependencyManager {
    pub fn new() -> Self {
        Self {
            dependencies: Arc::new(RwLock::new(HashMap::new())),
        }
    }

    pub async fn register<T: Send + Sync + 'static + Service>(&self) -> Arc<T> {
        let deps = T::deps();

        let mut err_count = 0;

        log::info!("Checking deps {}", T::name());
        for dep in deps {
            if self.check_by_type_id(dep.type_id).await {
                log::info!("> {} ok", dep.name)
            } else {
                err_count += 1;
                log::error!("> {} error", dep.name)
            }
        }

        if err_count > 0 {
            log::error!("failed to create service");
            panic!("failed to create service {}", T::name())
        } else {
            log::info!("deps-check successfull");
        }

        let child_manager = Arc::new(Self {
            dependencies: self.dependencies.clone(),
        });

        let service_instance = Arc::new(T::new(child_manager).await);

        let mut services = self.dependencies.write().await;
        let type_id = TypeId::of::<T>();
        services.insert(
            type_id,
            service_instance.clone() as Arc<dyn Any + Send + Sync>,
        );

        service_instance
    }

    async fn check_by_type_id(&self, type_id: TypeId) -> bool {
        let deps = self.dependencies.read().await;
        let got = deps.get(&type_id);
        got.is_some()
    }

    pub async fn get<T: Send + Sync + 'static + Service>(&self, from: &str) -> Option<Arc<T>> {
        let deps = self.dependencies.read().await;
        let type_id = TypeId::of::<T>();

        let result = deps.get(&type_id).and_then(|arc_any| {
            let cloned = arc_any.clone();
            cloned.downcast::<T>().ok()
        });

        if result.is_none() {
            log::warn!("{} unable to get {} now", from, T::name())
        }

        result
    }
}