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,144 @@
use std::collections::BTreeMap;
use super::headers::should_skip_upstream_passthrough_header;
use super::snapshot::GatewayProviderTransportSnapshot;
fn collect_passthrough_headers(
headers: &http::HeaderMap,
extra_headers: &BTreeMap<String, String>,
) -> BTreeMap<String, String> {
let mut out = BTreeMap::new();
for (name, value) in headers.iter() {
let Ok(value) = value.to_str() else {
continue;
};
let key = name.as_str().to_ascii_lowercase();
if should_skip_upstream_passthrough_header(&key) {
continue;
}
let value = value.trim();
if value.is_empty() {
continue;
}
out.insert(key, value.to_string());
}
for (key, value) in extra_headers {
let normalized_key = key.to_ascii_lowercase();
let value = value.trim();
if value.is_empty() {
continue;
}
out.insert(normalized_key, value.to_string());
}
out
}
pub fn build_passthrough_headers(
headers: &http::HeaderMap,
extra_headers: &BTreeMap<String, String>,
content_type: Option<&str>,
) -> BTreeMap<String, String> {
let mut out = collect_passthrough_headers(headers, extra_headers);
out.entry("content-type".to_string()).or_insert_with(|| {
content_type
.filter(|value| !value.trim().is_empty())
.unwrap_or("application/json")
.trim()
.to_string()
});
out.remove("content-length");
out
}
pub fn build_openai_passthrough_headers(
headers: &http::HeaderMap,
auth_header: &str,
auth_value: &str,
extra_headers: &BTreeMap<String, String>,
content_type: Option<&str>,
) -> BTreeMap<String, String> {
let mut out = build_passthrough_headers(headers, extra_headers, content_type);
ensure_upstream_auth_header(&mut out, auth_header, auth_value);
out
}
pub fn build_passthrough_headers_with_auth(
headers: &http::HeaderMap,
auth_header: &str,
auth_value: &str,
extra_headers: &BTreeMap<String, String>,
) -> BTreeMap<String, String> {
let mut out = collect_passthrough_headers(headers, extra_headers);
ensure_upstream_auth_header(&mut out, auth_header, auth_value);
out.remove("content-length");
out
}
pub fn ensure_upstream_auth_header(
headers: &mut BTreeMap<String, String>,
auth_header: &str,
auth_value: &str,
) {
let header_name = auth_header.trim().to_ascii_lowercase();
let header_value = auth_value.trim();
if header_name.is_empty() || header_value.is_empty() {
return;
}
if headers
.get(&header_name)
.map(|value| value.trim().is_empty())
.unwrap_or(true)
{
headers.insert(header_name, header_value.to_string());
}
}
pub fn resolve_local_openai_chat_auth(
transport: &GatewayProviderTransportSnapshot,
) -> Option<(String, String)> {
let auth_type = transport.key.auth_type.trim().to_ascii_lowercase();
if !matches!(auth_type.as_str(), "api_key" | "bearer") {
return None;
}
let secret = transport.key.decrypted_api_key.trim();
if secret.is_empty() {
return None;
}
Some(("authorization".to_string(), format!("Bearer {secret}")))
}
pub fn resolve_local_standard_auth(
transport: &GatewayProviderTransportSnapshot,
) -> Option<(String, String)> {
let auth_type = transport.key.auth_type.trim().to_ascii_lowercase();
let secret = transport.key.decrypted_api_key.trim();
if secret.is_empty() {
return None;
}
match auth_type.as_str() {
"api_key" => Some(("x-api-key".to_string(), secret.to_string())),
"bearer" => Some(("authorization".to_string(), format!("Bearer {secret}"))),
_ => None,
}
}
pub fn resolve_local_gemini_auth(
transport: &GatewayProviderTransportSnapshot,
) -> Option<(String, String)> {
let auth_type = transport.key.auth_type.trim().to_ascii_lowercase();
let secret = transport.key.decrypted_api_key.trim();
if secret.is_empty() {
return None;
}
match auth_type.as_str() {
"api_key" => Some(("x-goog-api-key".to_string(), secret.to_string())),
"bearer" => Some(("authorization".to_string(), format!("Bearer {secret}"))),
_ => None,
}
}