use std::{path::Path, sync::Arc};
use async_trait::async_trait;
use loco_rs::{
app::{AppContext, Hooks, Initializer},
bgworker::{BackgroundWorker, Queue},
boot::{create_app, BootResult, StartMode},
config::Config,
controller::AppRoutes,
environment::Environment,
task::Tasks,
Result,
};
use migration::Migrator;
use crate::{controllers, platform::Platform, settings::Settings, workers};
pub struct App;
#[async_trait]
impl Hooks for App {
fn app_name() -> &'static str { env!("CARGO_CRATE_NAME") }
async fn boot(mode: StartMode, environment: &Environment, config: Config) -> Result<BootResult> {
create_app::<Self, Migrator>(mode, environment, config).await
}
fn init_logger(ctx: &AppContext) -> Result<bool> {
let s: Settings = ctx.config.settings()?;
if !s.telemetry.enabled { return Ok(false); }
bo_telemetry::init(&s.telemetry.service_name, &s.telemetry.otlp_endpoint)
.map_err(|e| loco_rs::Error::Message(e.to_string()))?;
Ok(true)
}
async fn after_context(ctx: AppContext) -> Result<AppContext> {
let settings: Settings = ctx.config.settings()?;
let platform = Platform::load(&ctx, &settings)
.await
.map_err(|e| loco_rs::Error::Message(format!("config/agents invalid: {e}")))?;
ctx.shared_store.insert(Arc::new(platform));
Ok(ctx)
}
fn routes(_ctx: &AppContext) -> AppRoutes {
AppRoutes::with_default_routes()
.add_route(controllers::agui::routes())
.add_route(controllers::agents::routes())
.add_route(controllers::documents::routes())
.add_route(controllers::webhooks::routes())
}
async fn initializers(_ctx: &AppContext) -> Result<Vec<Box<dyn Initializer>>> {
Ok(vec![])
}
async fn connect_workers(ctx: &AppContext, queue: &Queue) -> Result<()> {
queue.register(workers::ingest::IngestWorker::build(ctx)).await?;
queue.register(workers::drive_workflow::DriveWorkflowWorker::build(ctx)).await?;
Ok(())
}
fn register_tasks(tasks: &mut Tasks) {
tasks.register(crate::tasks::config_validate::ConfigValidate);
tasks.register(crate::tasks::schema_export::SchemaExport);
tasks.register(crate::tasks::retention::RetentionPurge);
tasks.register(crate::tasks::approval_expiry::ApprovalExpiry);
}
async fn truncate(_ctx: &AppContext) -> Result<()> { Ok(()) }
async fn seed(_ctx: &AppContext, _base: &Path) -> Result<()> { Ok(()) }
}
pub fn platform(ctx: &AppContext) -> Result<Arc<Platform>> {
ctx.shared_store
.get::<Arc<Platform>>()
.ok_or_else(|| loco_rs::Error::Message("platform not initialised".into()))
}