mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
feat(proxy): 实现代理节点批量升级回滚、隧道重定向跟随及远程配置管理
核心功能: - 新增代理节点批量升级回滚工作流,支持分批升级、健康探针、跳过/重试/取消等操作 - proxy 隧道流处理器支持 HTTP 重定向跟随(最多 10 跳),区分 307/308 可重播与不可重播请求体 - proxy 协议新增 follow_redirects / http1_only 字段,网关侧同步支持 - 新增代理节点远端配置变更接口(名称、允许端口、调度状态、升级目标等) - 新增代理节点注册/反注册/心跳的 Admin API,及节点过期清理维护任务 - gateway 隧道 owner-relay 支持流式代理大请求体,新增 5 MiB 默认限制 - 新增 ProxyNodeRegistrationMutation / ProxyNodeRemoteConfigMutation 数据类型 - proxy 配置新增重定向重播预算、心跳间隔等参数,TUI 安装向导同步更新 - 前端 ProxyNodes 页面新增批量升级操作面板及滚动进度展示
This commit is contained in:
@@ -820,7 +820,11 @@ pub(crate) async fn maybe_build_local_internal_proxy_response_impl(
|
||||
};
|
||||
|
||||
let response = match state.apply_proxy_node_heartbeat(&mutation).await {
|
||||
Ok(Some(node)) => Json(build_internal_tunnel_heartbeat_ack(&node)).into_response(),
|
||||
Ok(Some(node)) => Json(build_internal_tunnel_heartbeat_ack(
|
||||
&node,
|
||||
payload.heartbeat_id,
|
||||
))
|
||||
.into_response(),
|
||||
Ok(None) => build_internal_control_error_response(
|
||||
http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("heartbeat sync failed: ProxyNode {node_id} 不存在"),
|
||||
@@ -850,7 +854,7 @@ pub(crate) async fn maybe_build_local_internal_proxy_response_impl(
|
||||
connected: payload.connected,
|
||||
conn_count: payload.conn_count,
|
||||
detail: None,
|
||||
observed_at_unix_secs: None,
|
||||
observed_at_unix_secs: payload.observed_at_unix_secs,
|
||||
};
|
||||
|
||||
let response = match state.update_proxy_node_tunnel_status(&mutation).await {
|
||||
|
||||
@@ -349,22 +349,26 @@ pub(crate) fn gateway_error_message(error: GatewayError) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn build_internal_tunnel_heartbeat_ack(node: &StoredProxyNode) -> serde_json::Value {
|
||||
let Some(remote_config) = node.remote_config.as_ref() else {
|
||||
return json!({});
|
||||
};
|
||||
|
||||
pub(crate) fn build_internal_tunnel_heartbeat_ack(
|
||||
node: &StoredProxyNode,
|
||||
heartbeat_id: Option<u64>,
|
||||
) -> serde_json::Value {
|
||||
let mut payload = serde_json::Map::new();
|
||||
payload.insert("remote_config".to_string(), remote_config.clone());
|
||||
payload.insert("config_version".to_string(), json!(node.config_version));
|
||||
if let Some(upgrade_to) = remote_config
|
||||
.as_object()
|
||||
.and_then(|value| value.get("upgrade_to"))
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
{
|
||||
payload.insert("upgrade_to".to_string(), json!(upgrade_to));
|
||||
if let Some(heartbeat_id) = heartbeat_id {
|
||||
payload.insert("heartbeat_id".to_string(), json!(heartbeat_id));
|
||||
}
|
||||
if let Some(remote_config) = node.remote_config.as_ref() {
|
||||
payload.insert("remote_config".to_string(), remote_config.clone());
|
||||
payload.insert("config_version".to_string(), json!(node.config_version));
|
||||
if let Some(upgrade_to) = remote_config
|
||||
.as_object()
|
||||
.and_then(|value| value.get("upgrade_to"))
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
{
|
||||
payload.insert("upgrade_to".to_string(), json!(upgrade_to));
|
||||
}
|
||||
}
|
||||
serde_json::Value::Object(payload)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user