mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 09:20:22 +08:00
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:
@@ -5,7 +5,7 @@ use axum::http::Uri;
|
||||
use sha2::{Digest, Sha256};
|
||||
use url::form_urlencoded;
|
||||
|
||||
use crate::gateway::headers::{header_value_str, is_json_request};
|
||||
use crate::headers::{header_value_str, is_json_request};
|
||||
|
||||
use super::super::GatewayControlDecision;
|
||||
use super::types::{
|
||||
@@ -68,7 +68,7 @@ pub(super) fn extract_request_credentials(
|
||||
}
|
||||
|
||||
fn has_trusted_gateway_marker(headers: &http::HeaderMap) -> bool {
|
||||
header_value_str(headers, crate::gateway::constants::GATEWAY_HEADER)
|
||||
header_value_str(headers, crate::constants::GATEWAY_HEADER)
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_ascii_lowercase()
|
||||
@@ -128,23 +128,23 @@ fn extract_trusted_auth_headers(headers: &http::HeaderMap) -> Option<GatewayTrus
|
||||
}
|
||||
let user_id = header_value_str(
|
||||
headers,
|
||||
crate::gateway::constants::TRUSTED_AUTH_USER_ID_HEADER,
|
||||
crate::constants::TRUSTED_AUTH_USER_ID_HEADER,
|
||||
)
|
||||
.filter(|value| !value.is_empty())?;
|
||||
let api_key_id = header_value_str(
|
||||
headers,
|
||||
crate::gateway::constants::TRUSTED_AUTH_API_KEY_ID_HEADER,
|
||||
crate::constants::TRUSTED_AUTH_API_KEY_ID_HEADER,
|
||||
)
|
||||
.filter(|value| !value.is_empty())?;
|
||||
let balance_remaining = header_value_str(
|
||||
headers,
|
||||
crate::gateway::constants::TRUSTED_AUTH_BALANCE_HEADER,
|
||||
crate::constants::TRUSTED_AUTH_BALANCE_HEADER,
|
||||
)
|
||||
.as_deref()
|
||||
.and_then(parse_f64_header);
|
||||
let access_allowed = header_value_str(
|
||||
headers,
|
||||
crate::gateway::constants::TRUSTED_AUTH_ACCESS_ALLOWED_HEADER,
|
||||
crate::constants::TRUSTED_AUTH_ACCESS_ALLOWED_HEADER,
|
||||
)
|
||||
.as_deref()
|
||||
.and_then(parse_bool_header);
|
||||
@@ -165,7 +165,7 @@ pub(super) fn extract_trusted_admin_headers(
|
||||
}
|
||||
let user_id = header_value_str(
|
||||
headers,
|
||||
crate::gateway::constants::TRUSTED_ADMIN_USER_ID_HEADER,
|
||||
crate::constants::TRUSTED_ADMIN_USER_ID_HEADER,
|
||||
)?
|
||||
.trim()
|
||||
.to_string();
|
||||
@@ -174,7 +174,7 @@ pub(super) fn extract_trusted_admin_headers(
|
||||
}
|
||||
let user_role = header_value_str(
|
||||
headers,
|
||||
crate::gateway::constants::TRUSTED_ADMIN_USER_ROLE_HEADER,
|
||||
crate::constants::TRUSTED_ADMIN_USER_ROLE_HEADER,
|
||||
)?
|
||||
.trim()
|
||||
.to_string();
|
||||
@@ -183,13 +183,13 @@ pub(super) fn extract_trusted_admin_headers(
|
||||
}
|
||||
let session_id = header_value_str(
|
||||
headers,
|
||||
crate::gateway::constants::TRUSTED_ADMIN_SESSION_ID_HEADER,
|
||||
crate::constants::TRUSTED_ADMIN_SESSION_ID_HEADER,
|
||||
)
|
||||
.map(|value| value.trim().to_string())
|
||||
.filter(|value| !value.is_empty());
|
||||
let management_token_id = header_value_str(
|
||||
headers,
|
||||
crate::gateway::constants::TRUSTED_ADMIN_MANAGEMENT_TOKEN_ID_HEADER,
|
||||
crate::constants::TRUSTED_ADMIN_MANAGEMENT_TOKEN_ID_HEADER,
|
||||
)
|
||||
.map(|value| value.trim().to_string())
|
||||
.filter(|value| !value.is_empty());
|
||||
@@ -519,23 +519,23 @@ mod tests {
|
||||
fn extracts_trusted_auth_headers() {
|
||||
let mut headers = http::HeaderMap::new();
|
||||
headers.insert(
|
||||
crate::gateway::constants::GATEWAY_HEADER,
|
||||
crate::constants::GATEWAY_HEADER,
|
||||
"rust-phase3b".parse().unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_AUTH_USER_ID_HEADER,
|
||||
crate::constants::TRUSTED_AUTH_USER_ID_HEADER,
|
||||
"user-1".parse().unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_AUTH_API_KEY_ID_HEADER,
|
||||
crate::constants::TRUSTED_AUTH_API_KEY_ID_HEADER,
|
||||
"key-1".parse().unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_AUTH_BALANCE_HEADER,
|
||||
crate::constants::TRUSTED_AUTH_BALANCE_HEADER,
|
||||
"1.5".parse().unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_AUTH_ACCESS_ALLOWED_HEADER,
|
||||
crate::constants::TRUSTED_AUTH_ACCESS_ALLOWED_HEADER,
|
||||
"true".parse().unwrap(),
|
||||
);
|
||||
|
||||
@@ -557,11 +557,11 @@ mod tests {
|
||||
fn ignores_trusted_auth_headers_without_gateway_marker() {
|
||||
let mut headers = http::HeaderMap::new();
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_AUTH_USER_ID_HEADER,
|
||||
crate::constants::TRUSTED_AUTH_USER_ID_HEADER,
|
||||
"user-1".parse().unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_AUTH_API_KEY_ID_HEADER,
|
||||
crate::constants::TRUSTED_AUTH_API_KEY_ID_HEADER,
|
||||
"key-1".parse().unwrap(),
|
||||
);
|
||||
|
||||
@@ -574,19 +574,19 @@ mod tests {
|
||||
fn extracts_trusted_admin_headers() {
|
||||
let mut headers = http::HeaderMap::new();
|
||||
headers.insert(
|
||||
crate::gateway::constants::GATEWAY_HEADER,
|
||||
crate::constants::GATEWAY_HEADER,
|
||||
"rust-phase3b".parse().unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_ADMIN_USER_ID_HEADER,
|
||||
crate::constants::TRUSTED_ADMIN_USER_ID_HEADER,
|
||||
"admin-user-1".parse().unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_ADMIN_USER_ROLE_HEADER,
|
||||
crate::constants::TRUSTED_ADMIN_USER_ROLE_HEADER,
|
||||
"admin".parse().unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_ADMIN_SESSION_ID_HEADER,
|
||||
crate::constants::TRUSTED_ADMIN_SESSION_ID_HEADER,
|
||||
"sess-1".parse().unwrap(),
|
||||
);
|
||||
|
||||
@@ -610,15 +610,15 @@ mod tests {
|
||||
fn ignores_trusted_admin_headers_without_gateway_marker() {
|
||||
let mut headers = http::HeaderMap::new();
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_ADMIN_USER_ID_HEADER,
|
||||
crate::constants::TRUSTED_ADMIN_USER_ID_HEADER,
|
||||
"admin-user-1".parse().unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_ADMIN_USER_ROLE_HEADER,
|
||||
crate::constants::TRUSTED_ADMIN_USER_ROLE_HEADER,
|
||||
"admin".parse().unwrap(),
|
||||
);
|
||||
headers.insert(
|
||||
crate::gateway::constants::TRUSTED_ADMIN_SESSION_ID_HEADER,
|
||||
crate::constants::TRUSTED_ADMIN_SESSION_ID_HEADER,
|
||||
"sess-1".parse().unwrap(),
|
||||
);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ pub(crate) fn should_buffer_request_for_local_auth(
|
||||
};
|
||||
decision.route_class.as_deref() == Some("ai_public")
|
||||
&& decision.route_kind.as_deref() != Some("files")
|
||||
&& crate::gateway::headers::is_json_request(headers)
|
||||
&& crate::headers::is_json_request(headers)
|
||||
}
|
||||
|
||||
pub(crate) fn request_model_local_rejection(
|
||||
|
||||
@@ -35,7 +35,7 @@ pub(super) fn derive_principal_candidate(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{derive_principal_candidate, GatewayPrincipalCandidate};
|
||||
use crate::gateway::control::auth::types::{
|
||||
use crate::control::auth::types::{
|
||||
GatewayCredentialBundle, GatewayCredentialCarrier, GatewayExtractedCredentials,
|
||||
GatewayPrimaryCredential, GatewayTrustedAuthHeaders,
|
||||
};
|
||||
|
||||
@@ -5,8 +5,12 @@ use base64::Engine as _;
|
||||
use hmac::Mac;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::gateway::{AppState, GatewayError};
|
||||
use crate::wallet_runtime::{
|
||||
local_rejection_from_wallet_access, resolve_wallet_auth_gate,
|
||||
};
|
||||
use crate::{AppState, GatewayError};
|
||||
|
||||
use super::super::GatewayControlDecision;
|
||||
use super::credentials::{
|
||||
@@ -16,8 +20,7 @@ use super::credentials::{
|
||||
use super::gate::GatewayLocalAuthRejection;
|
||||
use super::principal::derive_principal_candidate;
|
||||
use super::types::{GatewayPrincipalCandidate, GatewayTrustedAuthHeaders};
|
||||
use crate::gateway::headers::header_value_str;
|
||||
use crate::gateway::{local_rejection_from_wallet_access, resolve_wallet_auth_gate};
|
||||
use crate::headers::header_value_str;
|
||||
|
||||
const AUTH_CONTEXT_CACHE_TTL: Duration = Duration::from_secs(60);
|
||||
const AUTH_CONTEXT_CACHE_MAX_ENTRIES: usize = 256;
|
||||
@@ -56,11 +59,13 @@ pub(in super::super) async fn resolve_control_decision_auth(
|
||||
state: &AppState,
|
||||
headers: &http::HeaderMap,
|
||||
uri: &Uri,
|
||||
trace_id: &str,
|
||||
mut decision: GatewayControlDecision,
|
||||
) -> Result<ControlDecisionAuthResolution, GatewayError> {
|
||||
if let Some(admin_principal) =
|
||||
resolve_trusted_admin_principal(headers, decision.auth_endpoint_signature.as_deref())
|
||||
{
|
||||
log_admin_principal_resolution(trace_id, &decision, "trusted_headers", &admin_principal);
|
||||
decision.admin_principal = Some(admin_principal);
|
||||
} else if let Some(admin_principal) = resolve_local_admin_principal(
|
||||
state,
|
||||
@@ -70,6 +75,7 @@ pub(in super::super) async fn resolve_control_decision_auth(
|
||||
)
|
||||
.await?
|
||||
{
|
||||
log_admin_principal_resolution(trace_id, &decision, "local_session", &admin_principal);
|
||||
decision.admin_principal = Some(admin_principal);
|
||||
}
|
||||
|
||||
@@ -81,6 +87,7 @@ pub(in super::super) async fn resolve_control_decision_auth(
|
||||
)
|
||||
.await?
|
||||
{
|
||||
log_auth_context_resolution(trace_id, &decision, &auth_context);
|
||||
decision.local_auth_rejection = auth_context.local_rejection.clone();
|
||||
if !auth_context.user_id.is_empty() && !auth_context.api_key_id.is_empty() {
|
||||
if let Some(cache_key) = decision
|
||||
@@ -95,6 +102,7 @@ pub(in super::super) async fn resolve_control_decision_auth(
|
||||
}
|
||||
|
||||
if decision.local_auth_rejection.is_some() {
|
||||
log_local_auth_rejection(trace_id, &decision);
|
||||
return Ok(ControlDecisionAuthResolution::Resolved(decision));
|
||||
}
|
||||
|
||||
@@ -113,6 +121,93 @@ pub(in super::super) async fn resolve_control_decision_auth(
|
||||
Ok(ControlDecisionAuthResolution::Resolved(decision))
|
||||
}
|
||||
|
||||
fn log_admin_principal_resolution(
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
resolution: &'static str,
|
||||
admin_principal: &GatewayAdminPrincipalContext,
|
||||
) {
|
||||
debug!(
|
||||
event_name = "admin_principal_resolved",
|
||||
log_type = "debug",
|
||||
debug_context = "control_auth",
|
||||
trace_id = %trace_id,
|
||||
route_class = decision.route_class.as_deref().unwrap_or("unknown"),
|
||||
route_family = decision.route_family.as_deref().unwrap_or("unknown"),
|
||||
route_kind = decision.route_kind.as_deref().unwrap_or("unknown"),
|
||||
resolution,
|
||||
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("-"),
|
||||
"resolved admin principal for control decision"
|
||||
);
|
||||
}
|
||||
|
||||
fn log_auth_context_resolution(
|
||||
trace_id: &str,
|
||||
decision: &GatewayControlDecision,
|
||||
auth_context: &GatewayControlAuthContext,
|
||||
) {
|
||||
info!(
|
||||
event_name = "auth_context_resolved",
|
||||
log_type = "event",
|
||||
status = if auth_context.access_allowed {
|
||||
"allowed"
|
||||
} else {
|
||||
"blocked"
|
||||
},
|
||||
trace_id = %trace_id,
|
||||
route_class = decision.route_class.as_deref().unwrap_or("unknown"),
|
||||
route_family = decision.route_family.as_deref().unwrap_or("unknown"),
|
||||
route_kind = decision.route_kind.as_deref().unwrap_or("unknown"),
|
||||
user_id = auth_context.user_id.as_str(),
|
||||
api_key_id = auth_context.api_key_id.as_str(),
|
||||
access_allowed = auth_context.access_allowed,
|
||||
api_key_is_standalone = auth_context.api_key_is_standalone,
|
||||
has_local_rejection = auth_context.local_rejection.is_some(),
|
||||
"resolved data-backed auth context for control decision"
|
||||
);
|
||||
}
|
||||
|
||||
fn log_local_auth_rejection(trace_id: &str, decision: &GatewayControlDecision) {
|
||||
let Some(rejection) = decision.local_auth_rejection.as_ref() else {
|
||||
return;
|
||||
};
|
||||
let (rejection_kind, rejection_detail) = match rejection {
|
||||
GatewayLocalAuthRejection::InvalidApiKey => ("invalid_api_key", "-".to_string()),
|
||||
GatewayLocalAuthRejection::LockedApiKey => ("locked_api_key", "-".to_string()),
|
||||
GatewayLocalAuthRejection::WalletUnavailable => ("wallet_unavailable", "-".to_string()),
|
||||
GatewayLocalAuthRejection::BalanceDenied { remaining } => (
|
||||
"balance_denied",
|
||||
remaining
|
||||
.map(|value| format!("remaining_usd={value:.4}"))
|
||||
.unwrap_or_else(|| "remaining_usd=unknown".to_string()),
|
||||
),
|
||||
GatewayLocalAuthRejection::ProviderNotAllowed { provider } => {
|
||||
("provider_not_allowed", provider.clone())
|
||||
}
|
||||
GatewayLocalAuthRejection::ApiFormatNotAllowed { api_format } => {
|
||||
("api_format_not_allowed", api_format.clone())
|
||||
}
|
||||
GatewayLocalAuthRejection::ModelNotAllowed { model } => {
|
||||
("model_not_allowed", model.clone())
|
||||
}
|
||||
};
|
||||
info!(
|
||||
event_name = "local_auth_rejected",
|
||||
log_type = "event",
|
||||
status = "rejected",
|
||||
trace_id = %trace_id,
|
||||
route_class = decision.route_class.as_deref().unwrap_or("unknown"),
|
||||
route_family = decision.route_family.as_deref().unwrap_or("unknown"),
|
||||
route_kind = decision.route_kind.as_deref().unwrap_or("unknown"),
|
||||
rejection_kind,
|
||||
rejection_detail = %rejection_detail,
|
||||
"rejected local control request during auth gate resolution"
|
||||
);
|
||||
}
|
||||
|
||||
fn allows_missing_data_backed_auth_context(decision: &GatewayControlDecision) -> bool {
|
||||
matches!(
|
||||
decision.route_kind.as_deref(),
|
||||
@@ -463,7 +558,7 @@ async fn resolve_trusted_auth_context(
|
||||
}
|
||||
|
||||
fn build_data_backed_auth_context(
|
||||
snapshot: crate::gateway::gateway_data::StoredGatewayAuthApiKeySnapshot,
|
||||
snapshot: crate::data::auth::GatewayAuthApiKeySnapshot,
|
||||
auth_endpoint_signature: &str,
|
||||
header_access_allowed: Option<bool>,
|
||||
balance_remaining: Option<f64>,
|
||||
@@ -551,8 +646,9 @@ mod tests {
|
||||
use axum::http::{HeaderMap, Uri};
|
||||
|
||||
use super::resolve_data_backed_auth_context;
|
||||
use crate::gateway::control::auth::credentials::hash_api_key;
|
||||
use crate::gateway::{AppState, GatewayDataState};
|
||||
use crate::control::auth::credentials::hash_api_key;
|
||||
use crate::data::GatewayDataState;
|
||||
use crate::AppState;
|
||||
|
||||
fn sample_snapshot(api_key_id: &str, user_id: &str) -> StoredAuthApiKeySnapshot {
|
||||
StoredAuthApiKeySnapshot::new(
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use axum::body::{Body, Bytes};
|
||||
use axum::http::{HeaderName, HeaderValue, Response};
|
||||
|
||||
use crate::gateway::constants::CONTROL_EXECUTED_HEADER;
|
||||
use crate::gateway::{AppState, GatewayControlDecision, GatewayError};
|
||||
use crate::constants::CONTROL_EXECUTED_HEADER;
|
||||
use crate::control::GatewayControlDecision;
|
||||
use crate::{AppState, GatewayError};
|
||||
|
||||
use super::resolve_execution_runtime_auth_context;
|
||||
|
||||
@@ -37,7 +38,7 @@ pub(crate) async fn maybe_execute_via_control(
|
||||
}
|
||||
|
||||
let response = if require_stream {
|
||||
crate::gateway::maybe_execute_via_execution_runtime_stream(
|
||||
crate::execution_runtime::maybe_execute_via_execution_runtime_stream(
|
||||
state,
|
||||
parts,
|
||||
&body_bytes,
|
||||
@@ -46,7 +47,7 @@ pub(crate) async fn maybe_execute_via_control(
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
crate::gateway::maybe_execute_via_execution_runtime_sync(
|
||||
crate::execution_runtime::maybe_execute_via_execution_runtime_sync(
|
||||
state,
|
||||
parts,
|
||||
&body_bytes,
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
#[cfg(test)]
|
||||
use axum::http::Uri;
|
||||
|
||||
#[path = "auth/mod.rs"]
|
||||
mod auth;
|
||||
#[path = "execute.rs"]
|
||||
mod execute;
|
||||
#[path = "public.rs"]
|
||||
mod public;
|
||||
#[path = "route.rs"]
|
||||
mod route;
|
||||
|
||||
pub(crate) use auth::{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use axum::http::Uri;
|
||||
|
||||
use crate::gateway::headers::header_value_str;
|
||||
use crate::gateway::{AppState, GatewayError};
|
||||
use crate::headers::header_value_str;
|
||||
use crate::{AppState, GatewayError};
|
||||
|
||||
use super::{resolve_control_route, GatewayControlDecision};
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use super::{classified, ClassifiedRoute};
|
||||
use crate::gateway::{is_tunnel_heartbeat_path, is_tunnel_node_status_path, TUNNEL_ROUTE_FAMILY};
|
||||
use crate::tunnel::{
|
||||
is_tunnel_heartbeat_path, is_tunnel_node_status_path, TUNNEL_ROUTE_FAMILY,
|
||||
};
|
||||
|
||||
pub(super) fn classify_internal_route(
|
||||
method: &http::Method,
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
use axum::http::Uri;
|
||||
|
||||
use crate::gateway::headers::header_value_str;
|
||||
use crate::gateway::{AppState, GatewayError};
|
||||
use crate::headers::header_value_str;
|
||||
use crate::{AppState, GatewayError};
|
||||
|
||||
#[path = "route/admin.rs"]
|
||||
mod admin;
|
||||
#[path = "route/ai.rs"]
|
||||
mod ai;
|
||||
#[path = "route/internal.rs"]
|
||||
mod internal;
|
||||
#[path = "route/oauth.rs"]
|
||||
mod oauth;
|
||||
#[path = "route/public_support.rs"]
|
||||
mod public_support;
|
||||
|
||||
use super::auth::{resolve_control_decision_auth, ControlDecisionAuthResolution};
|
||||
@@ -122,14 +117,14 @@ pub(crate) async fn resolve_control_route(
|
||||
method: &http::Method,
|
||||
uri: &Uri,
|
||||
headers: &http::HeaderMap,
|
||||
_trace_id: &str,
|
||||
trace_id: &str,
|
||||
) -> Result<Option<GatewayControlDecision>, GatewayError> {
|
||||
let Some(mut decision) = classify_control_route(method, uri, headers) else {
|
||||
return Ok(None);
|
||||
};
|
||||
decision.public_query_string = uri.query().map(ToOwned::to_owned);
|
||||
|
||||
match resolve_control_decision_auth(state, headers, uri, decision).await? {
|
||||
match resolve_control_decision_auth(state, headers, uri, trace_id, decision).await? {
|
||||
ControlDecisionAuthResolution::Resolved(decision) => Ok(Some(decision)),
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use http::Uri;
|
||||
|
||||
use super::{classify_control_route, headers};
|
||||
use crate::tunnel::TUNNEL_ROUTE_FAMILY;
|
||||
|
||||
#[test]
|
||||
fn classifies_internal_tunnel_heartbeat_as_internal_proxy_route() {
|
||||
@@ -12,10 +13,7 @@ fn classifies_internal_tunnel_heartbeat_as_internal_proxy_route() {
|
||||
classify_control_route(&http::Method::POST, &uri, &headers).expect("route should classify");
|
||||
|
||||
assert_eq!(decision.route_class.as_deref(), Some("internal_proxy"));
|
||||
assert_eq!(
|
||||
decision.route_family.as_deref(),
|
||||
Some(crate::gateway::TUNNEL_ROUTE_FAMILY)
|
||||
);
|
||||
assert_eq!(decision.route_family.as_deref(), Some(TUNNEL_ROUTE_FAMILY));
|
||||
assert_eq!(decision.route_kind.as_deref(), Some("heartbeat"));
|
||||
assert_eq!(decision.auth_endpoint_signature.as_deref(), Some(""));
|
||||
assert!(!decision.is_execution_runtime_candidate());
|
||||
@@ -47,10 +45,7 @@ fn classifies_internal_tunnel_node_status_as_internal_proxy_route() {
|
||||
classify_control_route(&http::Method::POST, &uri, &headers).expect("route should classify");
|
||||
|
||||
assert_eq!(decision.route_class.as_deref(), Some("internal_proxy"));
|
||||
assert_eq!(
|
||||
decision.route_family.as_deref(),
|
||||
Some(crate::gateway::TUNNEL_ROUTE_FAMILY)
|
||||
);
|
||||
assert_eq!(decision.route_family.as_deref(), Some(TUNNEL_ROUTE_FAMILY));
|
||||
assert_eq!(decision.route_kind.as_deref(), Some("node_status"));
|
||||
assert_eq!(decision.auth_endpoint_signature.as_deref(), Some(""));
|
||||
assert!(!decision.is_execution_runtime_candidate());
|
||||
|
||||
Reference in New Issue
Block a user