mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-07 18:07:47 +08:00
refactor: 大规模模块拆分与重组,新增 aether-admin crate
- 新建独立 aether-admin crate 承载 admin 相关共享契约与纯辅助函数 - 拆分 ai_pipeline 下 kiro/private_envelope/conversion/planner 等大文件为子模块目录 - 重组 admin handlers 各业务域(billing/oauth/provider/system/users 等)为目录结构,移除 shared.rs/builders.rs 等反模式 - 移除 ai_pipeline runtime adapters 旧实现(claude/openai/gemini/kiro/vertex/antigravity 等),改由 provider transport 统一承载 - 移除 control_facade/execution_facade/auth_snapshot_facade 等冗余 facade 层 - 拆分 query/billing 与 query/monitoring 模块、state/runtime/payments 与 security 模块 - 扩展架构测试覆盖 admin_billing/admin_model/admin_users 等新模块 - 删除 docs/architecture/refactor-execution-plan.md 已完成的执行计划文档
This commit is contained in:
@@ -1,14 +1,8 @@
|
||||
use super::extractors::{admin_health_key_id, admin_recover_key_id};
|
||||
use super::health_builders::{
|
||||
build_admin_endpoint_health_status_payload, build_admin_health_summary_payload,
|
||||
build_admin_key_health_payload, recover_admin_key_health, recover_all_admin_key_health,
|
||||
};
|
||||
use crate::control::GatewayPublicRequestContext;
|
||||
use crate::handlers::admin::request::{AdminAppState, AdminRequestContext};
|
||||
use crate::handlers::admin::shared::query_param_value;
|
||||
use crate::handlers::public::{
|
||||
build_api_format_health_monitor_payload, ApiFormatHealthMonitorOptions,
|
||||
};
|
||||
use crate::{AppState, GatewayError};
|
||||
use crate::handlers::public::ApiFormatHealthMonitorOptions;
|
||||
use crate::GatewayError;
|
||||
use axum::{
|
||||
body::Body,
|
||||
http,
|
||||
@@ -29,21 +23,21 @@ fn build_admin_endpoint_health_data_unavailable_response() -> Response<Body> {
|
||||
}
|
||||
|
||||
pub(super) async fn maybe_build_local_admin_endpoints_health_response(
|
||||
state: &AppState,
|
||||
request_context: &GatewayPublicRequestContext,
|
||||
state: &AdminAppState<'_>,
|
||||
request_context: &AdminRequestContext<'_>,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
let Some(decision) = request_context.control_decision.as_ref() else {
|
||||
let Some(decision) = request_context.decision() else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
if decision.route_family.as_deref() == Some("endpoints_health")
|
||||
&& decision.route_kind.as_deref() == Some("health_summary")
|
||||
&& request_context.request_path == "/api/admin/endpoints/health/summary"
|
||||
&& request_context.path() == "/api/admin/endpoints/health/summary"
|
||||
{
|
||||
if !state.has_provider_catalog_data_reader() {
|
||||
return Ok(Some(build_admin_endpoint_health_data_unavailable_response()));
|
||||
}
|
||||
let Some(payload) = build_admin_health_summary_payload(state).await else {
|
||||
let Some(payload) = state.build_admin_health_summary_payload().await else {
|
||||
return Ok(Some(build_admin_endpoint_health_data_unavailable_response()));
|
||||
};
|
||||
return Ok(Some(Json(payload).into_response()));
|
||||
@@ -58,7 +52,7 @@ pub(super) async fn maybe_build_local_admin_endpoints_health_response(
|
||||
if !state.has_provider_catalog_data_reader() {
|
||||
return Ok(Some(build_admin_endpoint_health_data_unavailable_response()));
|
||||
}
|
||||
let Some(key_id) = admin_health_key_id(&request_context.request_path) else {
|
||||
let Some(key_id) = admin_health_key_id(request_context.path()) else {
|
||||
return Ok(Some(
|
||||
(
|
||||
http::StatusCode::NOT_FOUND,
|
||||
@@ -67,12 +61,12 @@ pub(super) async fn maybe_build_local_admin_endpoints_health_response(
|
||||
.into_response(),
|
||||
));
|
||||
};
|
||||
let api_format = query_param_value(
|
||||
request_context.request_query_string.as_deref(),
|
||||
"api_format",
|
||||
);
|
||||
let api_format = query_param_value(request_context.query_string(), "api_format");
|
||||
return Ok(Some(
|
||||
match build_admin_key_health_payload(state, &key_id, api_format.as_deref()).await {
|
||||
match state
|
||||
.build_admin_key_health_payload(&key_id, api_format.as_deref())
|
||||
.await
|
||||
{
|
||||
Some(payload) => Json(payload).into_response(),
|
||||
None => (
|
||||
http::StatusCode::NOT_FOUND,
|
||||
@@ -92,7 +86,7 @@ pub(super) async fn maybe_build_local_admin_endpoints_health_response(
|
||||
if !state.has_provider_catalog_data_reader() || !state.has_provider_catalog_data_writer() {
|
||||
return Ok(Some(build_admin_endpoint_health_data_unavailable_response()));
|
||||
}
|
||||
let Some(key_id) = admin_recover_key_id(&request_context.request_path) else {
|
||||
let Some(key_id) = admin_recover_key_id(request_context.path()) else {
|
||||
return Ok(Some(
|
||||
(
|
||||
http::StatusCode::NOT_FOUND,
|
||||
@@ -101,12 +95,12 @@ pub(super) async fn maybe_build_local_admin_endpoints_health_response(
|
||||
.into_response(),
|
||||
));
|
||||
};
|
||||
let api_format = query_param_value(
|
||||
request_context.request_query_string.as_deref(),
|
||||
"api_format",
|
||||
);
|
||||
let api_format = query_param_value(request_context.query_string(), "api_format");
|
||||
return Ok(Some(
|
||||
match recover_admin_key_health(state, &key_id, api_format.as_deref()).await {
|
||||
match state
|
||||
.recover_admin_key_health(&key_id, api_format.as_deref())
|
||||
.await
|
||||
{
|
||||
Some(payload) => Json(payload).into_response(),
|
||||
None => (
|
||||
http::StatusCode::NOT_FOUND,
|
||||
@@ -119,12 +113,12 @@ pub(super) async fn maybe_build_local_admin_endpoints_health_response(
|
||||
|
||||
if decision.route_family.as_deref() == Some("endpoints_health")
|
||||
&& decision.route_kind.as_deref() == Some("recover_all_keys_health")
|
||||
&& request_context.request_path == "/api/admin/endpoints/health/keys"
|
||||
&& request_context.path() == "/api/admin/endpoints/health/keys"
|
||||
{
|
||||
if !state.has_provider_catalog_data_reader() || !state.has_provider_catalog_data_writer() {
|
||||
return Ok(Some(build_admin_endpoint_health_data_unavailable_response()));
|
||||
}
|
||||
let Some(payload) = recover_all_admin_key_health(state).await else {
|
||||
let Some(payload) = state.recover_all_admin_key_health().await else {
|
||||
return Ok(Some(build_admin_endpoint_health_data_unavailable_response()));
|
||||
};
|
||||
return Ok(Some(Json(payload).into_response()));
|
||||
@@ -132,36 +126,31 @@ pub(super) async fn maybe_build_local_admin_endpoints_health_response(
|
||||
|
||||
if decision.route_family.as_deref() == Some("endpoints_health")
|
||||
&& decision.route_kind.as_deref() == Some("health_api_formats")
|
||||
&& request_context.request_path == "/api/admin/endpoints/health/api-formats"
|
||||
&& request_context.path() == "/api/admin/endpoints/health/api-formats"
|
||||
{
|
||||
if !state.has_provider_catalog_data_reader() || !state.has_request_candidate_data_reader() {
|
||||
return Ok(Some(build_admin_endpoint_health_data_unavailable_response()));
|
||||
}
|
||||
let lookback_hours = query_param_value(
|
||||
request_context.request_query_string.as_deref(),
|
||||
"lookback_hours",
|
||||
)
|
||||
.and_then(|value| value.parse::<u64>().ok())
|
||||
.filter(|value| (1..=72).contains(value))
|
||||
.unwrap_or(6);
|
||||
let per_format_limit = query_param_value(
|
||||
request_context.request_query_string.as_deref(),
|
||||
"per_format_limit",
|
||||
)
|
||||
.and_then(|value| value.parse::<usize>().ok())
|
||||
.filter(|value| (10..=200).contains(value))
|
||||
.unwrap_or(60);
|
||||
let Some(payload) = build_api_format_health_monitor_payload(
|
||||
state,
|
||||
lookback_hours,
|
||||
per_format_limit,
|
||||
ApiFormatHealthMonitorOptions {
|
||||
include_api_path: false,
|
||||
include_provider_count: true,
|
||||
include_key_count: true,
|
||||
},
|
||||
)
|
||||
.await
|
||||
let lookback_hours = query_param_value(request_context.query_string(), "lookback_hours")
|
||||
.and_then(|value| value.parse::<u64>().ok())
|
||||
.filter(|value| (1..=72).contains(value))
|
||||
.unwrap_or(6);
|
||||
let per_format_limit =
|
||||
query_param_value(request_context.query_string(), "per_format_limit")
|
||||
.and_then(|value| value.parse::<usize>().ok())
|
||||
.filter(|value| (10..=200).contains(value))
|
||||
.unwrap_or(60);
|
||||
let Some(payload) = state
|
||||
.build_api_format_health_monitor_payload(
|
||||
lookback_hours,
|
||||
per_format_limit,
|
||||
ApiFormatHealthMonitorOptions {
|
||||
include_api_path: false,
|
||||
include_provider_count: true,
|
||||
include_key_count: true,
|
||||
},
|
||||
)
|
||||
.await
|
||||
else {
|
||||
return Ok(Some(build_admin_endpoint_health_data_unavailable_response()));
|
||||
};
|
||||
@@ -170,19 +159,18 @@ pub(super) async fn maybe_build_local_admin_endpoints_health_response(
|
||||
|
||||
if decision.route_family.as_deref() == Some("endpoints_health")
|
||||
&& decision.route_kind.as_deref() == Some("health_status")
|
||||
&& request_context.request_path == "/api/admin/endpoints/health/status"
|
||||
&& request_context.path() == "/api/admin/endpoints/health/status"
|
||||
{
|
||||
if !state.has_provider_catalog_data_reader() || !state.has_request_candidate_data_reader() {
|
||||
return Ok(Some(build_admin_endpoint_health_data_unavailable_response()));
|
||||
}
|
||||
let lookback_hours = query_param_value(
|
||||
request_context.request_query_string.as_deref(),
|
||||
"lookback_hours",
|
||||
)
|
||||
.and_then(|value| value.parse::<u64>().ok())
|
||||
.filter(|value| (1..=72).contains(value))
|
||||
.unwrap_or(6);
|
||||
let Some(payload) = build_admin_endpoint_health_status_payload(state, lookback_hours).await
|
||||
let lookback_hours = query_param_value(request_context.query_string(), "lookback_hours")
|
||||
.and_then(|value| value.parse::<u64>().ok())
|
||||
.filter(|value| (1..=72).contains(value))
|
||||
.unwrap_or(6);
|
||||
let Some(payload) = state
|
||||
.build_admin_endpoint_health_status_payload(lookback_hours)
|
||||
.await
|
||||
else {
|
||||
return Ok(Some(build_admin_endpoint_health_data_unavailable_response()));
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use crate::handlers::admin::request::AdminAppState;
|
||||
use crate::handlers::public::provider_key_api_formats;
|
||||
use crate::AppState;
|
||||
use aether_scheduler_core::count_recent_rpm_requests_for_provider_key_since;
|
||||
use serde_json::json;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
pub(crate) async fn build_admin_key_health_payload(
|
||||
state: &AppState,
|
||||
state: &AdminAppState<'_>,
|
||||
key_id: &str,
|
||||
api_format: Option<&str>,
|
||||
) -> Option<serde_json::Value> {
|
||||
@@ -172,7 +172,7 @@ pub(crate) async fn build_admin_key_health_payload(
|
||||
}
|
||||
|
||||
pub(crate) async fn build_admin_key_rpm_payload(
|
||||
state: &AppState,
|
||||
state: &AdminAppState<'_>,
|
||||
key_id: &str,
|
||||
) -> Option<serde_json::Value> {
|
||||
if !state.has_provider_catalog_data_reader() {
|
||||
@@ -225,7 +225,7 @@ fn default_key_circuit_payload() -> serde_json::Value {
|
||||
}
|
||||
|
||||
pub(crate) async fn recover_admin_key_health(
|
||||
state: &AppState,
|
||||
state: &AdminAppState<'_>,
|
||||
key_id: &str,
|
||||
api_format: Option<&str>,
|
||||
) -> Option<serde_json::Value> {
|
||||
@@ -295,7 +295,9 @@ pub(crate) async fn recover_admin_key_health(
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) async fn recover_all_admin_key_health(state: &AppState) -> Option<serde_json::Value> {
|
||||
pub(crate) async fn recover_all_admin_key_health(
|
||||
state: &AdminAppState<'_>,
|
||||
) -> Option<serde_json::Value> {
|
||||
if !state.has_provider_catalog_data_reader() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
mod keys;
|
||||
mod status;
|
||||
|
||||
pub(super) use self::keys::{
|
||||
pub(crate) use self::keys::{
|
||||
build_admin_key_health_payload, build_admin_key_rpm_payload, recover_admin_key_health,
|
||||
recover_all_admin_key_health,
|
||||
};
|
||||
pub(crate) use self::status::build_admin_endpoint_health_status_payload;
|
||||
pub(super) use self::status::build_admin_health_summary_payload;
|
||||
pub(crate) use self::status::build_admin_health_summary_payload;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::handlers::admin::request::AdminAppState;
|
||||
use crate::handlers::admin::shared::unix_secs_to_rfc3339;
|
||||
use crate::handlers::public::{
|
||||
api_format_display_name, build_public_health_timeline, provider_key_api_formats,
|
||||
};
|
||||
use crate::AppState;
|
||||
use aether_data_contracts::repository::candidates::PublicHealthTimelineBucket;
|
||||
use aether_scheduler_core::{is_provider_key_circuit_open, provider_key_health_score};
|
||||
use serde_json::json;
|
||||
@@ -10,7 +10,7 @@ use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
pub(crate) async fn build_admin_endpoint_health_status_payload(
|
||||
state: &AppState,
|
||||
state: &AdminAppState<'_>,
|
||||
lookback_hours: u64,
|
||||
) -> Option<serde_json::Value> {
|
||||
if !state.has_provider_catalog_data_reader() || !state.has_request_candidate_data_reader() {
|
||||
@@ -210,7 +210,7 @@ pub(crate) async fn build_admin_endpoint_health_status_payload(
|
||||
}
|
||||
|
||||
pub(crate) async fn build_admin_health_summary_payload(
|
||||
state: &AppState,
|
||||
state: &AdminAppState<'_>,
|
||||
) -> Option<serde_json::Value> {
|
||||
if !state.has_provider_catalog_data_reader() {
|
||||
return None;
|
||||
|
||||
@@ -1,52 +1,13 @@
|
||||
use crate::control::GatewayPublicRequestContext;
|
||||
use crate::handlers::admin::provider::{endpoint_keys, endpoints_admin};
|
||||
use crate::{AppState, GatewayError};
|
||||
use axum::body::{Body, Bytes};
|
||||
use axum::http::Response;
|
||||
|
||||
mod extractors;
|
||||
mod health;
|
||||
mod health_builders;
|
||||
mod routes;
|
||||
mod rpm;
|
||||
|
||||
pub(crate) use self::health_builders::build_admin_endpoint_health_status_payload;
|
||||
|
||||
pub(crate) async fn maybe_build_local_admin_endpoints_response(
|
||||
state: &AppState,
|
||||
request_context: &GatewayPublicRequestContext,
|
||||
request_body: Option<&Bytes>,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
if let Some(response) =
|
||||
health::maybe_build_local_admin_endpoints_health_response(state, request_context).await?
|
||||
{
|
||||
return Ok(Some(response));
|
||||
}
|
||||
|
||||
if let Some(response) =
|
||||
rpm::maybe_build_local_admin_endpoints_rpm_response(state, request_context).await?
|
||||
{
|
||||
return Ok(Some(response));
|
||||
}
|
||||
|
||||
if let Some(response) = endpoint_keys::maybe_build_local_admin_endpoints_keys_response(
|
||||
state,
|
||||
request_context,
|
||||
request_body,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(Some(response));
|
||||
}
|
||||
|
||||
if let Some(response) = endpoints_admin::maybe_build_local_admin_endpoints_routes_response(
|
||||
state,
|
||||
request_context,
|
||||
request_body,
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(Some(response));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
pub(super) use self::health_builders::build_admin_health_summary_payload;
|
||||
pub(super) use self::health_builders::build_admin_key_health_payload;
|
||||
pub(super) use self::health_builders::build_admin_key_rpm_payload;
|
||||
pub(super) use self::health_builders::recover_admin_key_health;
|
||||
pub(super) use self::health_builders::recover_all_admin_key_health;
|
||||
pub(super) use self::routes::maybe_build_local_admin_endpoints_response;
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use super::{health, rpm};
|
||||
use crate::handlers::admin::provider::{endpoint_keys, endpoints_admin};
|
||||
use crate::handlers::admin::request::{AdminRouteRequest, AdminRouteResult};
|
||||
|
||||
pub(crate) async fn maybe_build_local_admin_endpoints_response(
|
||||
request: AdminRouteRequest<'_>,
|
||||
) -> AdminRouteResult {
|
||||
if let Some(response) = health::maybe_build_local_admin_endpoints_health_response(
|
||||
&request.state(),
|
||||
&request.request_context(),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(Some(response));
|
||||
}
|
||||
|
||||
if let Some(response) = rpm::maybe_build_local_admin_endpoints_rpm_response(
|
||||
&request.state(),
|
||||
&request.request_context(),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(Some(response));
|
||||
}
|
||||
|
||||
if let Some(response) = endpoint_keys::maybe_build_local_admin_endpoints_keys_response(
|
||||
&request.state(),
|
||||
&request.request_context(),
|
||||
request.request_body(),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(Some(response));
|
||||
}
|
||||
|
||||
if let Some(response) = endpoints_admin::maybe_build_local_admin_endpoints_routes_response(
|
||||
&request.state(),
|
||||
&request.request_context(),
|
||||
request.request_body(),
|
||||
)
|
||||
.await?
|
||||
{
|
||||
return Ok(Some(response));
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::extractors::admin_rpm_key_id;
|
||||
use super::health_builders::build_admin_key_rpm_payload;
|
||||
use crate::control::GatewayPublicRequestContext;
|
||||
use crate::{AppState, GatewayError};
|
||||
use crate::handlers::admin::request::{AdminAppState, AdminRequestContext};
|
||||
use crate::GatewayError;
|
||||
use axum::{
|
||||
body::Body,
|
||||
http,
|
||||
@@ -12,20 +11,20 @@ use serde_json::json;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
pub(super) async fn maybe_build_local_admin_endpoints_rpm_response(
|
||||
state: &AppState,
|
||||
request_context: &GatewayPublicRequestContext,
|
||||
state: &AdminAppState<'_>,
|
||||
request_context: &AdminRequestContext<'_>,
|
||||
) -> Result<Option<Response<Body>>, GatewayError> {
|
||||
let Some(decision) = request_context.control_decision.as_ref() else {
|
||||
let Some(decision) = request_context.decision() else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
if decision.route_family.as_deref() == Some("endpoints_rpm")
|
||||
&& decision.route_kind.as_deref() == Some("key_rpm")
|
||||
&& request_context
|
||||
.request_path
|
||||
.path()
|
||||
.starts_with("/api/admin/endpoints/rpm/key/")
|
||||
{
|
||||
let Some(key_id) = admin_rpm_key_id(&request_context.request_path) else {
|
||||
let Some(key_id) = admin_rpm_key_id(request_context.path()) else {
|
||||
return Ok(Some(
|
||||
(
|
||||
http::StatusCode::NOT_FOUND,
|
||||
@@ -35,7 +34,7 @@ pub(super) async fn maybe_build_local_admin_endpoints_rpm_response(
|
||||
));
|
||||
};
|
||||
return Ok(Some(
|
||||
match build_admin_key_rpm_payload(state, &key_id).await {
|
||||
match state.build_admin_key_rpm_payload(&key_id).await {
|
||||
Some(payload) => Json(payload).into_response(),
|
||||
None => (
|
||||
http::StatusCode::NOT_FOUND,
|
||||
@@ -48,12 +47,12 @@ pub(super) async fn maybe_build_local_admin_endpoints_rpm_response(
|
||||
|
||||
if decision.route_family.as_deref() == Some("endpoints_rpm")
|
||||
&& decision.route_kind.as_deref() == Some("reset_key_rpm")
|
||||
&& request_context.request_method == http::Method::DELETE
|
||||
&& request_context.method() == http::Method::DELETE
|
||||
&& request_context
|
||||
.request_path
|
||||
.path()
|
||||
.starts_with("/api/admin/endpoints/rpm/key/")
|
||||
{
|
||||
let Some(key_id) = admin_rpm_key_id(&request_context.request_path) else {
|
||||
let Some(key_id) = admin_rpm_key_id(request_context.path()) else {
|
||||
return Ok(Some(
|
||||
(
|
||||
http::StatusCode::NOT_FOUND,
|
||||
|
||||
Reference in New Issue
Block a user