greentic-runner-host 0.4.73

Host runtime shim for Greentic runner: config, pack loading, activity handling
Documentation
pub mod adapt_events_email;
pub mod adapt_messaging;
pub mod adapt_slack;
pub mod adapt_teams;
pub mod adapt_timer;
pub mod adapt_webchat;
pub mod adapt_webex;
pub mod adapt_webhook;
pub mod adapt_whatsapp;
pub mod contract_cache;
pub mod contract_introspection;
pub mod engine;
pub mod flow_adapter;
pub mod i18n;
pub mod ingress_util;
pub mod invocation;
pub mod mocks;
pub mod operator;
pub mod schema_validator;
pub mod templating;

use std::net::SocketAddr;
use std::sync::Arc;

use anyhow::Result;
use axum::routing::{any, get, post};
use axum::{Router, serve};
use tokio::net::TcpListener;

use crate::http::{self, admin, auth::AdminAuth, health::HealthState};
use crate::routing::TenantRouting;
use crate::runtime::ActivePacks;
use crate::watcher::PackReloadHandle;

pub struct HostServer {
    addr: SocketAddr,
    router: Router,
    _state: ServerState,
}

impl HostServer {
    pub fn new(
        port: u16,
        active: Arc<ActivePacks>,
        routing: TenantRouting,
        health: Arc<HealthState>,
        reload: Option<PackReloadHandle>,
        admin: AdminAuth,
    ) -> Result<Self> {
        let addr = SocketAddr::from(([0, 0, 0, 0], port));
        let state = ServerState {
            active,
            routing,
            health,
            reload,
            admin,
        };
        let router = Router::new()
            .route(
                "/messaging/telegram/webhook",
                post(adapt_messaging::telegram_webhook),
            )
            .route("/webchat/activities", post(adapt_webchat::activities))
            .route("/teams/activities", post(adapt_teams::activities))
            .route("/slack/events", post(adapt_slack::events))
            .route("/slack/interactive", post(adapt_slack::interactive))
            .route("/webex/webhook", post(adapt_webex::webhook))
            .route(
                "/whatsapp/webhook",
                get(adapt_whatsapp::verify).post(adapt_whatsapp::webhook),
            )
            .route("/webhook/{flow_id}", any(adapt_webhook::dispatch))
            .route("/operator/op/invoke", post(operator::invoke))
            .route("/healthz", get(http::health::handler))
            .route("/admin/packs/status", get(admin::status))
            .route("/admin/packs/reload", post(admin::reload))
            .with_state(state.clone());
        Ok(Self {
            addr,
            router,
            _state: state,
        })
    }

    pub async fn serve(self) -> Result<()> {
        tracing::info!(addr = %self.addr, "starting host server");
        let listener = TcpListener::bind(self.addr).await?;
        serve(
            listener,
            self.router
                .into_make_service_with_connect_info::<SocketAddr>(),
        )
        .await?;
        Ok(())
    }
}

#[derive(Clone)]
pub struct ServerState {
    pub active: Arc<ActivePacks>,
    pub routing: TenantRouting,
    pub health: Arc<HealthState>,
    pub reload: Option<PackReloadHandle>,
    pub admin: AdminAuth,
}