refactor: 拆分 gateway 单体为独立 crate,新增 systemd 部署方案

将 gateway 内部的 model-fetch、provider-transport、scheduler-core、
usage-runtime、video-tasks-core 模块提取为独立 crate;重构 gateway
内部模块结构(state/router/cache/data/query 等);移除大量遗留模块
文件;新增 systemd 二进制部署骨架及相关文档;更新前端 usage 相关
API 和组件。
This commit is contained in:
fawney19
2026-04-05 20:23:16 +08:00
parent cbc811f6ce
commit 763ff03a7b
777 changed files with 42659 additions and 21469 deletions

View File

@@ -0,0 +1,131 @@
use axum::body::Body;
use axum::http::{self, Response};
use tracing::{info, warn};
use crate::control::GatewayControlDecision;
#[derive(Debug, Clone)]
pub(crate) struct AdminAuditEvent {
pub(crate) event_name: &'static str,
pub(crate) action: &'static str,
pub(crate) target_type: &'static str,
pub(crate) target_id: String,
}
pub(crate) fn attach_admin_audit_event(
response: &mut Response<Body>,
event_name: &'static str,
action: &'static str,
target_type: &'static str,
target_id: impl Into<String>,
) {
response.extensions_mut().insert(AdminAuditEvent {
event_name,
action,
target_type,
target_id: target_id.into(),
});
}
pub(crate) fn emit_admin_audit(
response: &mut Response<Body>,
trace_id: &str,
method: &http::Method,
path_and_query: &str,
control_decision: Option<&GatewayControlDecision>,
) {
let Some(decision) = control_decision else {
return;
};
let Some(admin_principal) = decision.admin_principal.as_ref() else {
return;
};
let attached_event = response.extensions_mut().remove::<AdminAuditEvent>();
let route_family = decision.route_family.as_deref().unwrap_or("unknown");
let route_kind = decision.route_kind.as_deref().unwrap_or("unknown");
let status_code = response.status().as_u16();
if attached_event.is_none() && !is_admin_mutation_method(method) {
return;
}
let (event_name, action, target_type, target_id) = if let Some(event) = attached_event {
(
event.event_name,
event.action,
event.target_type,
event.target_id,
)
} else {
(
if response.status().is_success() {
"admin_mutation_completed"
} else {
"admin_mutation_failed"
},
route_kind,
default_target_type(route_family),
path_and_query.to_string(),
)
};
let audit_status = if response.status().is_success() {
"completed"
} else {
"failed"
};
if response.status().is_success() {
info!(
event_name,
log_type = "audit",
status = audit_status,
status_code,
trace_id = %trace_id,
admin_user_id = admin_principal.user_id.as_str(),
admin_user_role = admin_principal.user_role.as_str(),
admin_session_id = admin_principal.session_id.as_deref().unwrap_or("-"),
admin_management_token_id = admin_principal.management_token_id.as_deref().unwrap_or("-"),
route_family,
route_kind,
method = %method,
path = %path_and_query,
action,
target_type,
target_id = %target_id,
"admin mutation audit event"
);
} else {
warn!(
event_name,
log_type = "audit",
status = audit_status,
status_code,
trace_id = %trace_id,
admin_user_id = admin_principal.user_id.as_str(),
admin_user_role = admin_principal.user_role.as_str(),
admin_session_id = admin_principal.session_id.as_deref().unwrap_or("-"),
admin_management_token_id = admin_principal.management_token_id.as_deref().unwrap_or("-"),
route_family,
route_kind,
method = %method,
path = %path_and_query,
action,
target_type,
target_id = %target_id,
"admin mutation audit event"
);
}
}
fn default_target_type(route_family: &str) -> &str {
route_family
.strip_suffix("_manage")
.unwrap_or(route_family)
.trim()
}
fn is_admin_mutation_method(method: &http::Method) -> bool {
matches!(
*method,
http::Method::POST | http::Method::PUT | http::Method::PATCH | http::Method::DELETE
)
}

View File

@@ -6,7 +6,7 @@ use axum::Json;
use serde::{Deserialize, Serialize};
use serde_json::json;
use crate::gateway::{AppState, GatewayError};
use crate::{AppState, GatewayError};
const DEFAULT_RECENT_LIMIT: usize = 20;
const MAX_RECENT_LIMIT: usize = 200;
@@ -80,7 +80,10 @@ pub(crate) async fn get_request_candidate_trace(
State(state): State<AppState>,
Path(request_id): Path<String>,
Query(query): Query<GetRequestCandidateTraceQuery>,
) -> Result<Json<crate::gateway::gateway_data::RequestCandidateTrace>, axum::response::Response> {
) -> Result<
Json<crate::data::candidates::RequestCandidateTrace>,
axum::response::Response,
> {
let attempted_only = query.attempted_only.unwrap_or(false);
let trace = state
.read_request_candidate_trace(&request_id, attempted_only)
@@ -105,7 +108,10 @@ pub(crate) async fn get_decision_trace(
State(state): State<AppState>,
Path(request_id): Path<String>,
Query(query): Query<GetRequestCandidateTraceQuery>,
) -> Result<Json<crate::gateway::gateway_data::DecisionTrace>, axum::response::Response> {
) -> Result<
Json<crate::data::decision_trace::DecisionTrace>,
axum::response::Response,
> {
let attempted_only = query.attempted_only.unwrap_or(false);
let trace = state
.read_decision_trace(&request_id, attempted_only)
@@ -130,7 +136,7 @@ pub(crate) async fn get_auth_api_key_snapshot(
State(state): State<AppState>,
Path((user_id, api_key_id)): Path<(String, String)>,
) -> Result<
Json<crate::gateway::gateway_data::StoredGatewayAuthApiKeySnapshot>,
Json<crate::data::auth::GatewayAuthApiKeySnapshot>,
axum::response::Response,
> {
let snapshot = state

View File

@@ -1,6 +1,8 @@
mod admin;
mod http;
mod shadow;
pub(crate) use admin::{attach_admin_audit_event, emit_admin_audit, AdminAuditEvent};
pub(crate) use http::get_auth_api_key_snapshot;
pub(crate) use http::get_decision_trace;
pub(crate) use http::get_request_candidate_trace;

View File

@@ -8,11 +8,12 @@ use axum::http::header::CONTENT_TYPE;
use axum::http::Response;
use tracing::warn;
use crate::gateway::constants::{
use crate::constants::{
CONTROL_CANDIDATE_ID_HEADER, CONTROL_REQUEST_ID_HEADER, EXECUTION_PATH_CONTROL_EXECUTE_STREAM,
EXECUTION_PATH_CONTROL_EXECUTE_SYNC,
};
use crate::gateway::{AppState, GatewayControlDecision};
use crate::control::GatewayControlDecision;
use crate::AppState;
pub(crate) fn record_shadow_result_non_blocking(
state: AppState,
@@ -130,11 +131,12 @@ mod tests {
use axum::http::{Method, Response, StatusCode};
use super::record_shadow_result_non_blocking;
use crate::gateway::constants::{
use crate::constants::{
CONTROL_REQUEST_ID_HEADER, EXECUTION_PATH_CONTROL_EXECUTE_SYNC,
EXECUTION_PATH_EXECUTION_RUNTIME_SYNC,
};
use crate::gateway::{AppState, GatewayControlDecision};
use crate::control::GatewayControlDecision;
use crate::AppState;
fn sample_decision() -> GatewayControlDecision {
GatewayControlDecision {