aves-kea 0.5.0

Specialized knowledge domain for the Aves async application runtime
use std::path::PathBuf;
use std::sync::{Arc, RwLock};

use tokio::sync::{broadcast, mpsc, oneshot};

use aves::bus::{BusRpcContext, EventBus};
use aves::config::ConfigBroadcast;

use super::actor::{Actor, run_actor};
use super::domain::{KnowledgeDomain, KnowledgeGeneratedHandler};
use super::messages::{KnowledgeBroadcast, KnowledgeRequest, KnowledgeRequestPayload};
use super::types::KnowledgeConfig;

pub(super) struct Handle<Root>
where
    Root: Clone + Send + 'static,
    KnowledgeBroadcast: Into<Root> + Clone + Send + 'static,
{
    generated_handler: KnowledgeGeneratedHandler<Root, KnowledgeBroadcast>,
    config_rx: broadcast::Receiver<Root>,
    actor_tasks: mpsc::Sender<KnowledgeRequest>,
}

impl<Root> Handle<Root>
where
    Root: Clone + Send + 'static,
    KnowledgeBroadcast: Into<Root> + Clone + Send + 'static,
    ConfigBroadcast: TryFrom<Root>,
{
    pub(super) async fn new(
        driver: &mut EventBus<Root>,
        root_context: BusRpcContext,
        config_dir: PathBuf,
        config: KnowledgeConfig,
        shared_root: Arc<RwLock<PathBuf>>,
    ) -> Self {
        let (actor_tasks, actor_tasks_rx) = mpsc::channel(64);

        let channels = driver.register::<KnowledgeDomain, KnowledgeRequest, KnowledgeBroadcast>();

        let (broadcast_tx, actor_broadcast_rx) = mpsc::channel(64);
        let config_rx = channels.broadcasts_tx.subscribe();

        let generated_handler = KnowledgeGeneratedHandler::new(
            channels.requests_rx,
            actor_tasks.clone(),
            channels.broadcasts_tx,
            actor_broadcast_rx,
        );

        let actor = Actor::new(
            actor_tasks_rx,
            root_context,
            config_dir,
            config,
            shared_root,
            broadcast_tx,
        )
        .await;
        tokio::spawn(run_actor(actor));

        Self {
            generated_handler,
            config_rx,
            actor_tasks,
        }
    }

    pub(super) async fn run(mut self) {
        let handler = self.generated_handler.run();
        tokio::pin!(handler);
        loop {
            tokio::select! {
                _ = &mut handler => break,
                event = self.config_rx.recv() => match event {
                    Ok(root) => {
                        let Ok(ConfigBroadcast::ConfigChanged { section, .. }) = ConfigBroadcast::try_from(root) else {
                            continue;
                        };
                        let payload = match section.as_str() {
                            "knowledge" => KnowledgeRequestPayload::KnowledgeConfigChanged,
                            _ => continue,
                        };
                        let (reply_to, _reply) = oneshot::channel();
                        if self.actor_tasks.send(KnowledgeRequest { payload, reply_to }).await.is_err() {
                            break;
                        }
                    }
                    Err(broadcast::error::RecvError::Lagged(_)) => continue,
                    Err(broadcast::error::RecvError::Closed) => break,
                },
            }
        }
    }
}