refactor: 移除 Python upstream 依赖,清理全部 legacy/Python 兼容层

- 移除 upstream_base_url 参数及 AETHER_GATEWAY_UPSTREAM 环境变量,gateway 不再需要指向 Python 宿主
- 删除所有 LEGACY_*/PYTHON_* 常量、路由组、header 定义及 sunset/phaseout 机制
- 将 legacy_gateway_bridge 重命名为 internal_gateway,executor 相关命名统一为 execution_runtime
- dev.sh 新增 Postgres/Redis 预检查,移除 upstream 相关启动参数和提示
- 新增 ai_public 路由处理器
- 全量适配 handler、test、state、control 等模块的命名和接口变更
This commit is contained in:
fawney19
2026-04-04 01:40:24 +08:00
parent 1d9c77522a
commit cbc811f6ce
484 changed files with 11046 additions and 3925 deletions
@@ -1,4 +1,18 @@
use super::*;
use super::INTERNAL_GATEWAY_PATH_PREFIXES;
use super::{
admin_monitoring_bad_request_response, admin_monitoring_escape_like_pattern,
admin_monitoring_usage_is_error, admin_monitoring_user_behavior_user_id_from_path,
parse_admin_monitoring_days, parse_admin_monitoring_event_type_filter,
parse_admin_monitoring_hours, parse_admin_monitoring_limit, parse_admin_monitoring_offset,
parse_admin_monitoring_username_filter,
};
use crate::gateway::{AppState, GatewayError, GatewayPublicRequestContext};
use axum::{
body::Body,
response::{IntoResponse, Response},
Json,
};
use serde_json::json;
use sqlx::Row;
fn build_admin_monitoring_audit_logs_payload(
@@ -434,11 +448,9 @@ pub(super) async fn build_admin_monitoring_system_status_response(
"nodes": tunnel.nodes,
"active_streams": tunnel.active_streams,
},
"legacy_bridge": {
"status": LEGACY_INTERNAL_GATEWAY_PHASEOUT_STATUS,
"sunset_date": LEGACY_INTERNAL_GATEWAY_SUNSET_DATE,
"sunset_http_date": LEGACY_INTERNAL_GATEWAY_SUNSET_HTTP_DATE,
"metric_name": "legacy_internal_bridge_total",
"internal_gateway": {
"status": "rust_native_control_plane",
"path_prefixes": INTERNAL_GATEWAY_PATH_PREFIXES,
},
"recent_errors": recent_errors,
}))
@@ -1,4 +1,42 @@
use super::*;
use super::{
admin_monitoring_bad_request_response, admin_monitoring_cache_affinity_delete_params_from_path,
admin_monitoring_cache_affinity_not_found_response, admin_monitoring_cache_affinity_sort_value,
admin_monitoring_cache_affinity_unavailable_response,
admin_monitoring_cache_affinity_user_identifier_from_path,
admin_monitoring_cache_model_mapping_provider_params_from_path,
admin_monitoring_cache_model_name_from_path, admin_monitoring_cache_provider_id_from_path,
admin_monitoring_cache_redis_category_from_path,
admin_monitoring_cache_users_not_found_response,
admin_monitoring_cache_users_user_identifier_from_path,
admin_monitoring_find_user_summary_by_id, admin_monitoring_has_test_redis_keys,
admin_monitoring_list_export_api_key_records_by_ids,
admin_monitoring_load_affinity_identity_maps, admin_monitoring_masked_provider_key_prefix,
admin_monitoring_masked_user_api_key_prefix, admin_monitoring_not_found_response,
admin_monitoring_redis_unavailable_response, build_admin_monitoring_cache_snapshot,
clear_admin_monitoring_scheduler_affinity_entries,
delete_admin_monitoring_cache_affinity_raw_keys, delete_admin_monitoring_namespaced_keys,
list_admin_monitoring_cache_affinity_records,
list_admin_monitoring_cache_affinity_records_by_affinity_keys,
list_admin_monitoring_namespaced_keys, load_admin_monitoring_cache_affinity_entries_for_tests,
parse_admin_monitoring_keyword_filter, parse_admin_monitoring_limit,
parse_admin_monitoring_offset, ADMIN_MONITORING_CACHE_AFFINITY_DEFAULT_TTL_SECS,
ADMIN_MONITORING_CACHE_RESERVATION_RATIO,
ADMIN_MONITORING_DYNAMIC_RESERVATION_HIGH_LOAD_THRESHOLD,
ADMIN_MONITORING_DYNAMIC_RESERVATION_LOW_LOAD_THRESHOLD,
ADMIN_MONITORING_DYNAMIC_RESERVATION_PROBE_PHASE_REQUESTS,
ADMIN_MONITORING_DYNAMIC_RESERVATION_PROBE_RESERVATION,
ADMIN_MONITORING_DYNAMIC_RESERVATION_STABLE_MAX_RESERVATION,
ADMIN_MONITORING_DYNAMIC_RESERVATION_STABLE_MIN_RESERVATION,
ADMIN_MONITORING_REDIS_CACHE_CATEGORIES,
};
use crate::gateway::{AppState, GatewayError, GatewayPublicRequestContext};
use axum::{
body::Body,
http,
response::{IntoResponse, Response},
Json,
};
use serde_json::json;
pub(super) async fn build_admin_monitoring_cache_stats_response(
state: &AppState,
@@ -1,4 +1,5 @@
use super::*;
use super::AdminMonitoringCacheAffinityRecord;
use crate::gateway::{AppState, GatewayError};
fn parse_admin_monitoring_cache_affinity_key(raw_key: &str) -> Option<(String, String, String)> {
let parts = raw_key.split(':').collect::<Vec<_>>();
@@ -1,4 +1,5 @@
use super::*;
use super::AdminMonitoringCacheAffinityRecord;
use crate::gateway::{AppState, GatewayError};
pub(super) async fn admin_monitoring_list_export_api_key_records_by_ids(
state: &AppState,
@@ -1,4 +1,7 @@
use super::*;
use crate::gateway::AppState;
use aether_crypto::decrypt_python_fernet_ciphertext;
#[cfg(test)]
use aether_crypto::DEVELOPMENT_ENCRYPTION_KEY;
pub(super) fn admin_monitoring_masked_user_api_key_prefix(
state: &AppState,
@@ -1,4 +1,14 @@
use super::*;
use super::{
ADMIN_MONITORING_CACHE_AFFINITY_REDIS_REQUIRED_DETAIL, ADMIN_MONITORING_REDIS_REQUIRED_DETAIL,
};
use crate::gateway::handlers::query_param_value;
use axum::{
body::Body,
http,
response::{IntoResponse, Response},
Json,
};
use serde_json::json;
pub(super) fn parse_admin_monitoring_keyword_filter(query: Option<&str>) -> Option<String> {
query_param_value(query, "keyword")
@@ -1,5 +1,7 @@
use super::super::round_to;
use super::cache_affinity::admin_monitoring_cache_affinity_record;
use super::*;
use super::{AdminMonitoringCacheAffinityRecord, AdminMonitoringCacheSnapshot};
use crate::gateway::{AppState, GatewayError};
async fn count_admin_monitoring_cache_affinity_entries(state: &AppState) -> usize {
let Some(runner) = state.redis_kv_runner() else {
@@ -1,4 +1,11 @@
use super::*;
use super::ADMIN_MONITORING_DATA_UNAVAILABLE_DETAIL;
use axum::{
body::Body,
http,
response::{IntoResponse, Response},
Json,
};
use serde_json::json;
pub(super) struct AdminMonitoringCacheSnapshot {
pub(super) scheduler_name: String,
@@ -28,10 +35,10 @@ pub(super) struct AdminMonitoringCacheAffinityRecord {
pub(super) request_count: u64,
}
pub(super) fn admin_monitoring_maintenance_response() -> Response<Body> {
pub(super) fn admin_monitoring_data_unavailable_response() -> Response<Body> {
(
http::StatusCode::SERVICE_UNAVAILABLE,
Json(json!({ "detail": ADMIN_MONITORING_RUST_BACKEND_DETAIL })),
Json(json!({ "detail": ADMIN_MONITORING_DATA_UNAVAILABLE_DETAIL })),
)
.into_response()
}
@@ -1,4 +1,15 @@
use super::*;
use super::{admin_monitoring_bad_request_response, admin_monitoring_usage_is_error};
use crate::gateway::handlers::{
provider_key_health_summary, query_param_value, unix_secs_to_rfc3339,
};
use crate::gateway::{AppState, GatewayError, GatewayPublicRequestContext};
use axum::{
body::Body,
response::{IntoResponse, Response},
Json,
};
use serde_json::json;
use std::collections::BTreeMap;
struct AdminMonitoringResilienceSnapshot {
timestamp: chrono::DateTime<chrono::Utc>,
@@ -1,4 +1,4 @@
use super::*;
use crate::gateway::handlers::query_param_value;
pub(super) fn admin_monitoring_escape_like_pattern(value: &str) -> String {
value
@@ -1,4 +1,27 @@
use super::*;
use super::{
build_admin_monitoring_audit_logs_response, build_admin_monitoring_cache_affinities_response,
build_admin_monitoring_cache_affinity_delete_response,
build_admin_monitoring_cache_affinity_response, build_admin_monitoring_cache_config_response,
build_admin_monitoring_cache_flush_response, build_admin_monitoring_cache_metrics_response,
build_admin_monitoring_cache_provider_delete_response,
build_admin_monitoring_cache_stats_response,
build_admin_monitoring_cache_users_delete_response,
build_admin_monitoring_model_mapping_delete_model_response,
build_admin_monitoring_model_mapping_delete_provider_response,
build_admin_monitoring_model_mapping_delete_response,
build_admin_monitoring_model_mapping_stats_response,
build_admin_monitoring_redis_cache_categories_response,
build_admin_monitoring_redis_keys_delete_response,
build_admin_monitoring_reset_error_stats_response,
build_admin_monitoring_resilience_circuit_history_response,
build_admin_monitoring_resilience_status_response,
build_admin_monitoring_suspicious_activities_response,
build_admin_monitoring_system_status_response,
build_admin_monitoring_trace_provider_stats_response,
build_admin_monitoring_trace_request_response, build_admin_monitoring_user_behavior_response,
};
use crate::gateway::{AppState, GatewayError, GatewayPublicRequestContext};
use axum::{body::Body, http, response::Response};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) enum AdminMonitoringRoute {
@@ -1,6 +1,7 @@
use super::*;
use crate::gateway::GatewayPublicRequestContext;
use aether_crypto::{encrypt_python_fernet_plaintext, DEVELOPMENT_ENCRYPTION_KEY};
use axum::http::Uri;
use axum::http::{self, Uri};
use serde_json::json;
use aether_data::repository::auth::StoredAuthApiKeyExportRecord;
use aether_data::repository::candidates::{RequestCandidateStatus, StoredRequestCandidate};
@@ -1,6 +1,7 @@
use super::test_support::*;
use super::*;
use super::{maybe_build_local_admin_monitoring_response, AppState};
use axum::body::to_bytes;
use serde_json::json;
use std::sync::Arc;
use aether_data::repository::auth::{
@@ -23,7 +24,7 @@ mod basics;
#[tokio::test]
async fn admin_monitoring_cache_affinities_returns_empty_payload_without_runtime_or_test_entries() {
let state = AppState::new("http://127.0.0.1:9").expect("state should build");
let state = AppState::new().expect("state should build");
let context = request_context(http::Method::GET, "/api/admin/monitoring/cache/affinities");
let response = maybe_build_local_admin_monitoring_response(&state, &context)
@@ -54,7 +55,7 @@ async fn admin_monitoring_cache_affinity_returns_not_found_without_runtime_or_te
sample_monitoring_export_api_key("user-1", "user-key-1"),
]),
);
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_data_state_for_tests(
crate::gateway::gateway_data::GatewayDataState::with_user_reader_for_tests(
@@ -102,7 +103,7 @@ async fn admin_monitoring_cache_affinities_and_affinity_return_local_payload_fro
vec![sample_monitoring_catalog_endpoint()],
vec![sample_monitoring_catalog_key()],
));
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_data_state_for_tests(
crate::gateway::gateway_data::GatewayDataState::with_provider_catalog_reader_for_tests(
@@ -208,7 +209,7 @@ async fn admin_monitoring_cache_users_delete_returns_local_payload_from_test_sto
sample_monitoring_export_api_key("user-1", "user-key-1"),
]),
);
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_data_state_for_tests(
crate::gateway::gateway_data::GatewayDataState::with_user_reader_for_tests(
@@ -270,7 +271,7 @@ async fn admin_monitoring_cache_users_delete_returns_local_payload_from_test_sto
#[tokio::test]
async fn admin_monitoring_cache_users_delete_returns_not_found_for_unknown_identifier() {
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_admin_monitoring_cache_affinity_entry_for_tests(
"cache_affinity:user-key-1:openai:model-alpha",
@@ -308,7 +309,7 @@ async fn admin_monitoring_cache_users_delete_returns_not_found_for_unknown_ident
#[tokio::test]
async fn admin_monitoring_cache_flush_returns_local_payload_from_test_store() {
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_admin_monitoring_cache_affinity_entry_for_tests(
"cache_affinity:user-key-1:openai:model-alpha",
@@ -356,7 +357,7 @@ async fn admin_monitoring_cache_flush_returns_local_payload_from_test_store() {
#[tokio::test]
async fn admin_monitoring_cache_provider_delete_returns_local_payload_from_test_store() {
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_admin_monitoring_cache_affinity_entry_for_tests(
"cache_affinity:user-key-1:openai:model-alpha",
@@ -414,7 +415,7 @@ async fn admin_monitoring_cache_provider_delete_returns_local_payload_from_test_
#[tokio::test]
async fn admin_monitoring_model_mapping_delete_returns_local_payload_from_test_store() {
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_admin_monitoring_redis_key_for_tests("model:id:model-1", json!({"id": "model-1"}))
.with_admin_monitoring_redis_key_for_tests(
@@ -456,7 +457,7 @@ async fn admin_monitoring_model_mapping_delete_returns_local_payload_from_test_s
#[tokio::test]
async fn admin_monitoring_model_mapping_delete_model_returns_local_payload_from_test_store() {
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_admin_monitoring_redis_key_for_tests(
"global_model:name:model-alpha",
@@ -504,7 +505,7 @@ async fn admin_monitoring_model_mapping_delete_model_returns_local_payload_from_
#[tokio::test]
async fn admin_monitoring_model_mapping_delete_provider_returns_local_payload_from_test_store() {
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_admin_monitoring_redis_key_for_tests(
"model:provider_global:provider-1:model-alpha",
@@ -553,7 +554,7 @@ async fn admin_monitoring_model_mapping_delete_provider_returns_local_payload_fr
#[tokio::test]
async fn admin_monitoring_redis_keys_delete_returns_local_payload_from_test_store() {
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_admin_monitoring_redis_key_for_tests("dashboard:summary:user-1", json!({"ok": true}))
.with_admin_monitoring_redis_key_for_tests("dashboard:stats:user-1", json!({"ok": true}))
@@ -596,7 +597,7 @@ async fn admin_monitoring_cache_affinity_delete_returns_local_payload_from_test_
sample_monitoring_export_api_key("user-1", "user-key-1"),
]),
);
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_data_state_for_tests(
crate::gateway::gateway_data::GatewayDataState::with_user_reader_for_tests(
@@ -657,7 +658,7 @@ async fn admin_monitoring_cache_affinity_delete_returns_local_payload_from_test_
#[tokio::test]
async fn admin_monitoring_cache_affinity_delete_returns_not_found_for_mismatched_endpoint() {
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_admin_monitoring_cache_affinity_entry_for_tests(
"cache_affinity:user-key-1:openai:model-alpha",
@@ -716,7 +717,7 @@ async fn admin_monitoring_cache_metrics_returns_local_payload() {
now - 120,
),
]));
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_data_state_for_tests(
crate::gateway::gateway_data::GatewayDataState::with_usage_reader_for_tests(
@@ -757,7 +758,7 @@ async fn admin_monitoring_cache_metrics_returns_local_payload() {
#[tokio::test]
async fn admin_monitoring_cache_config_returns_local_payload() {
let state = AppState::new("http://127.0.0.1:9").expect("state should build");
let state = AppState::new().expect("state should build");
let context = request_context(http::Method::GET, "/api/admin/monitoring/cache/config");
let response = maybe_build_local_admin_monitoring_response(&state, &context)
@@ -793,7 +794,7 @@ async fn admin_monitoring_cache_config_returns_local_payload() {
#[tokio::test]
async fn admin_monitoring_model_mapping_stats_returns_local_payload_without_redis() {
let state = AppState::new("http://127.0.0.1:9").expect("state should build");
let state = AppState::new().expect("state should build");
let context = request_context(
http::Method::GET,
"/api/admin/monitoring/cache/model-mapping/stats",
@@ -848,7 +849,7 @@ async fn admin_monitoring_reset_error_stats_returns_local_payload_and_clears_fut
Some(502),
now - 120,
)]));
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_data_state_for_tests(
crate::gateway::gateway_data::GatewayDataState::with_provider_catalog_and_usage_reader_for_tests(
@@ -903,7 +904,7 @@ async fn admin_monitoring_reset_error_stats_returns_local_payload_and_clears_fut
#[tokio::test]
async fn admin_monitoring_redis_keys_returns_local_payload_without_redis() {
let state = AppState::new("http://127.0.0.1:9").expect("state should build");
let state = AppState::new().expect("state should build");
let context = request_context(http::Method::GET, "/api/admin/monitoring/cache/redis-keys");
let response = maybe_build_local_admin_monitoring_response(&state, &context)
@@ -923,7 +924,7 @@ async fn admin_monitoring_redis_keys_returns_local_payload_without_redis() {
#[tokio::test]
async fn admin_monitoring_redis_keys_delete_returns_unavailable_without_redis() {
let state = AppState::new("http://127.0.0.1:9").expect("state should build");
let state = AppState::new().expect("state should build");
let context = request_context(
http::Method::DELETE,
"/api/admin/monitoring/cache/redis-keys/upstream_models",
@@ -965,7 +966,7 @@ async fn admin_monitoring_circuit_history_returns_local_payload() {
})),
)],
));
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_data_state_for_tests(
crate::gateway::gateway_data::GatewayDataState::with_provider_catalog_reader_for_tests(
@@ -1,4 +1,14 @@
use super::*;
use super::super::test_support::{request_context, sample_key, sample_provider, sample_usage};
use super::super::{
match_admin_monitoring_route, maybe_build_local_admin_monitoring_response,
AdminMonitoringRoute, ADMIN_MONITORING_REDIS_REQUIRED_DETAIL,
};
use crate::gateway::AppState;
use aether_data::repository::provider_catalog::InMemoryProviderCatalogReadRepository;
use aether_data::repository::usage::InMemoryUsageReadRepository;
use axum::body::to_bytes;
use serde_json::json;
use std::sync::Arc;
#[test]
fn admin_monitoring_matches_typical_routes() {
@@ -61,7 +71,7 @@ fn admin_monitoring_matches_cache_delete_shapes_and_trailing_slashes() {
#[tokio::test]
async fn admin_monitoring_model_mapping_delete_requires_redis_without_runtime_or_test_entries() {
let state = AppState::new("http://127.0.0.1:9").expect("state should build");
let state = AppState::new().expect("state should build");
let context = request_context(
http::Method::DELETE,
"/api/admin/monitoring/cache/model-mapping",
@@ -84,7 +94,7 @@ async fn admin_monitoring_model_mapping_delete_requires_redis_without_runtime_or
#[tokio::test]
async fn admin_monitoring_user_behavior_returns_empty_local_payload_without_postgres() {
let state = AppState::new("http://127.0.0.1:9").expect("state should build");
let state = AppState::new().expect("state should build");
let context = request_context(
http::Method::GET,
"/api/admin/monitoring/user-behavior/user-123?days=30",
@@ -112,7 +122,7 @@ async fn admin_monitoring_user_behavior_returns_empty_local_payload_without_post
#[tokio::test]
async fn admin_monitoring_audit_logs_returns_empty_local_payload_without_postgres() {
let state = AppState::new("http://127.0.0.1:9").expect("state should build");
let state = AppState::new().expect("state should build");
let context = request_context(
http::Method::GET,
"/api/admin/monitoring/audit-logs?username=alice&event_type=login_failed&days=14&limit=20&offset=5",
@@ -140,7 +150,7 @@ async fn admin_monitoring_audit_logs_returns_empty_local_payload_without_postgre
#[tokio::test]
async fn admin_monitoring_suspicious_activities_returns_empty_local_payload_without_postgres() {
let state = AppState::new("http://127.0.0.1:9").expect("state should build");
let state = AppState::new().expect("state should build");
let context = request_context(
http::Method::GET,
"/api/admin/monitoring/suspicious-activities?hours=48",
@@ -204,7 +214,7 @@ async fn admin_monitoring_resilience_status_returns_local_payload() {
now - 172_800,
),
]));
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_data_state_for_tests(
crate::gateway::gateway_data::GatewayDataState::with_provider_catalog_and_usage_reader_for_tests(
@@ -275,7 +285,7 @@ async fn admin_monitoring_cache_stats_returns_local_payload() {
now - 120,
),
]));
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_data_state_for_tests(
crate::gateway::gateway_data::GatewayDataState::with_usage_reader_for_tests(
@@ -1,6 +1,10 @@
use super::test_support::*;
use super::*;
use super::super::maybe_build_local_admin_monitoring_response;
use super::super::test_support::{
request_context, sample_candidate, sample_endpoint, sample_key, sample_provider,
};
use crate::gateway::AppState;
use axum::body::to_bytes;
use serde_json::json;
use std::sync::Arc;
use aether_data::repository::candidates::{
@@ -35,7 +39,7 @@ async fn admin_monitoring_trace_request_returns_local_payload() {
vec![sample_endpoint()],
vec![sample_key()],
));
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_decision_trace_data_readers_for_tests(request_candidates, provider_catalog);
let context = request_context(
@@ -121,7 +125,7 @@ async fn admin_monitoring_trace_provider_stats_returns_local_payload() {
None,
),
]));
let state = AppState::new("http://127.0.0.1:9")
let state = AppState::new()
.expect("state should build")
.with_request_candidate_data_reader_for_tests(request_candidates);
let context = request_context(
@@ -1,4 +1,15 @@
use super::*;
use super::{
admin_monitoring_bad_request_response, admin_monitoring_not_found_response,
parse_admin_monitoring_limit,
};
use crate::gateway::handlers::{query_param_value, unix_secs_to_rfc3339};
use crate::gateway::{AppState, GatewayError, GatewayPublicRequestContext};
use axum::{
body::Body,
response::{IntoResponse, Response},
Json,
};
use serde_json::json;
fn admin_monitoring_trace_request_id_from_path(request_path: &str) -> Option<String> {
let value = request_path