use crate::events::{DomainEvent, EventFilter};
use crate::manifest::Manifest;
pub type ExtResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
pub struct Migration {
pub version: u32,
pub description: &'static str,
pub up: &'static str,
}
#[derive(Debug, Clone, serde::Serialize)]
pub enum Health {
Ok,
Degraded { reason: String },
Down { reason: String },
}
#[derive(Debug, Clone, serde::Serialize)]
pub struct Metric {
pub name: String,
pub value: f64,
pub labels: Vec<(String, String)>,
}
pub struct ScheduledTask {
pub name: &'static str,
pub cron: &'static str,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct McpToolDef {
pub name: String,
pub description: String,
pub method: String,
pub path: String,
pub input_schema: serde_json::Value,
pub min_ring: String,
#[serde(default)]
pub path_params: Vec<String>,
}
pub trait Extension: Send + Sync {
fn manifest(&self) -> Manifest;
fn migrations(&self) -> Vec<Migration> {
vec![]
}
fn routes(&self, ctx: &AppContext) -> Option<axum::Router> {
let _ = ctx;
None
}
fn on_start(&self, ctx: &AppContext) -> ExtResult<()> {
let _ = ctx;
Ok(())
}
fn on_shutdown(&self) -> ExtResult<()> {
Ok(())
}
fn health(&self) -> Health {
Health::Ok
}
fn metrics(&self) -> Vec<Metric> {
vec![]
}
fn subscriptions(&self) -> Vec<EventFilter> {
vec![]
}
fn on_event(&self, event: &DomainEvent) {
let _ = event;
}
fn scheduled_tasks(&self) -> Vec<ScheduledTask> {
vec![]
}
fn on_scheduled_task(&self, task_name: &str) {
let _ = task_name;
}
fn on_config_change(&self, key: &str, value: &serde_json::Value) -> ExtResult<()> {
let _ = (key, value);
Ok(())
}
fn mcp_tools(&self) -> Vec<McpToolDef> {
vec![]
}
}
#[derive(Default)]
pub struct AppContext {
resources: std::collections::HashMap<
std::any::TypeId,
std::sync::Arc<dyn std::any::Any + Send + Sync>,
>,
}
impl AppContext {
pub fn new() -> Self {
Self::default()
}
pub fn insert<T: 'static + Send + Sync>(&mut self, val: T) {
self.resources
.insert(std::any::TypeId::of::<T>(), std::sync::Arc::new(val));
}
pub fn get<T: 'static + Send + Sync>(&self) -> Option<&T> {
self.resources
.get(&std::any::TypeId::of::<T>())
.and_then(|v| v.downcast_ref())
}
pub fn get_arc<T: 'static + Send + Sync>(&self) -> Option<std::sync::Arc<T>> {
self.resources
.get(&std::any::TypeId::of::<T>())
.and_then(|v| v.clone().downcast().ok())
}
}