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 42654 additions and 21464 deletions
+63 -6
View File
@@ -6,12 +6,12 @@ use axum::http::Response;
use axum::http::StatusCode;
use serde_json::json;
use crate::gateway::constants::*;
use crate::gateway::headers::should_skip_response_header;
use crate::gateway::rate_limit::FrontdoorUserRpmRejection;
use crate::gateway::{
insert_header_if_missing, GatewayControlDecision, GatewayError, GatewayLocalAuthRejection,
};
use crate::constants::*;
use crate::control::GatewayControlDecision;
use crate::control::GatewayLocalAuthRejection;
use crate::headers::should_skip_response_header;
use crate::rate_limit::FrontdoorUserRpmRejection;
use crate::{insert_header_if_missing, GatewayError};
fn execution_runtime_candidate_header_value(decision: &GatewayControlDecision) -> &'static str {
if decision.is_execution_runtime_candidate() {
@@ -29,6 +29,28 @@ fn insert_execution_runtime_candidate_headers(
insert_header_if_missing(headers, CONTROL_EXECUTION_RUNTIME_HEADER, value)
}
fn response_is_sse(headers: &http::HeaderMap) -> bool {
headers
.get(http::header::CONTENT_TYPE)
.and_then(|value| value.to_str().ok())
.is_some_and(|value| value.to_ascii_lowercase().contains("text/event-stream"))
}
pub(crate) fn apply_streaming_response_headers(headers: &mut http::HeaderMap) {
if !response_is_sse(headers) {
return;
}
headers.insert(
http::header::CACHE_CONTROL,
HeaderValue::from_static("no-cache, no-transform"),
);
headers.insert(
HeaderName::from_static("x-accel-buffering"),
HeaderValue::from_static("no"),
);
}
pub(crate) fn build_client_response(
upstream_response: reqwest::Response,
trace_id: &str,
@@ -77,6 +99,7 @@ pub(crate) fn build_client_response_from_parts(
HeaderValue::from_str(value).map_err(|err| GatewayError::Internal(err.to_string()))?;
response.headers_mut().insert(header_name, header_value);
}
apply_streaming_response_headers(response.headers_mut());
insert_header_if_missing(response.headers_mut(), TRACE_ID_HEADER, trace_id)?;
insert_header_if_missing(response.headers_mut(), GATEWAY_HEADER, "rust-phase3b")?;
if let Some(decision) = control_decision {
@@ -104,6 +127,40 @@ pub(crate) fn build_client_response_from_parts(
Ok(response)
}
#[cfg(test)]
mod tests {
use super::build_client_response_from_parts;
use axum::body::Body;
use std::collections::BTreeMap;
#[test]
fn sse_responses_disable_proxy_buffering() {
let response = build_client_response_from_parts(
200,
&BTreeMap::from([("content-type".to_string(), "text/event-stream".to_string())]),
Body::from("data: hello\n\n"),
"trace-sse-buffering-1",
None,
)
.expect("response should build");
assert_eq!(
response
.headers()
.get(http::header::CACHE_CONTROL)
.and_then(|value| value.to_str().ok()),
Some("no-cache, no-transform")
);
assert_eq!(
response
.headers()
.get("x-accel-buffering")
.and_then(|value| value.to_str().ok()),
Some("no")
);
}
}
pub(crate) fn insert_candidate_id_header_if_present(
headers: &mut http::HeaderMap,
candidate_id: Option<&str>,