use super::structural_incidents::StructuralIncidents;
use async_trait::async_trait;
use mockforge_contracts::contract_drift::types::{DriftBudget, DriftBudgetConfig};
use mockforge_foundation::incidents_types::DriftIncident;
mod budgets;
mod gitops;
mod incidents;
mod metrics;
mod scoped_budgets;
pub use budgets::*;
pub use gitops::*;
pub use incidents::*;
pub use metrics::*;
pub use scoped_budgets::*;
pub trait DriftBudgetSource: Send + Sync {
fn config(&self) -> &DriftBudgetConfig;
fn get_budget_for_endpoint(
&self,
endpoint: &str,
method: &str,
workspace_id: Option<&str>,
service_name: Option<&str>,
tags: Option<&[String]>,
) -> DriftBudget;
}
#[async_trait]
pub trait DriftGitOps: Send + Sync {
async fn generate_pr_from_incidents(
&self,
incidents: &[DriftIncident],
) -> mockforge_foundation::Result<Option<crate::pr_generation::PRResult>>;
}
pub trait DriftBudgetStateProvider: Clone + Send + Sync + 'static {
type Engine: DriftBudgetSource;
type Incidents: StructuralIncidents;
type GitOps: DriftGitOps;
fn engine(&self) -> &Self::Engine;
fn incident_manager(&self) -> &Self::Incidents;
fn gitops_handler(&self) -> Option<&Self::GitOps>;
fn publish_drift_threshold(
&self,
_workspace: uuid::Uuid,
_endpoint: String,
_exceeded: i32,
_total: i32,
) {
}
}
pub fn drift_budget_router<S: DriftBudgetStateProvider>(state: S) -> axum::Router {
use axum::{
routing::{get, patch, post},
Router,
};
Router::new()
.route("/api/v1/drift/budgets", post(create_budget::<S>))
.route("/api/v1/drift/budgets", get(list_budgets::<S>))
.route("/api/v1/drift/budgets/lookup", get(get_budget_for_endpoint::<S>))
.route("/api/v1/drift/budgets/workspace", post(create_workspace_budget::<S>))
.route("/api/v1/drift/budgets/service", post(create_service_budget::<S>))
.route("/api/v1/drift/budgets/{id}", get(get_budget::<S>))
.route("/api/v1/drift/incidents", get(list_incidents::<S>))
.route("/api/v1/drift/incidents/stats", get(get_incident_stats::<S>))
.route("/api/v1/drift/incidents/{id}", get(get_incident::<S>))
.route("/api/v1/drift/incidents/{id}", patch(update_incident::<S>))
.route("/api/v1/drift/incidents/{id}/resolve", post(resolve_incident::<S>))
.route("/api/v1/drift/gitops/generate-pr", post(generate_gitops_pr::<S>))
.route("/api/v1/drift/metrics", get(get_drift_metrics::<S>))
.with_state(state)
}
impl DriftBudgetSource for mockforge_contracts::contract_drift::DriftBudgetEngine {
fn config(&self) -> &DriftBudgetConfig {
mockforge_contracts::contract_drift::DriftBudgetEngine::config(self)
}
fn get_budget_for_endpoint(
&self,
endpoint: &str,
method: &str,
workspace_id: Option<&str>,
service_name: Option<&str>,
tags: Option<&[String]>,
) -> DriftBudget {
mockforge_contracts::contract_drift::DriftBudgetEngine::get_budget_for_endpoint(
self,
endpoint,
method,
workspace_id,
service_name,
tags,
)
}
}