Files
freedak f7a720204a Update: 将子项目从 submodule 转为完整内容
- 移除 GovAI, nomifun-tauri, 算力盒子 的 submodule 引用
- 添加所有子项目的完整源代码
- 保留原始 .git 为 .git.bak 备份
2026-07-04 19:20:46 +08:00

105 lines
4.0 KiB
Rust

//! Remote agent management API routes.
//!
//! Endpoints:
//!
//! - `GET /api/remote-agents` — list remote agents
//! - `POST /api/remote-agents` — create new remote agent
//! - `GET /api/remote-agents/{id}` — get remote agent details
//! - `PUT /api/remote-agents/{id}` — update remote agent
//! - `DELETE /api/remote-agents/{id}` — delete remote agent
//! - `POST /api/remote-agents/test-connection` — test connection to remote agent (without saving it)
//! - `POST /api/remote-agents/{id}/handshake` — perform handshake with the remote agent to verify connectivity and retrieve agent info
use axum::Router;
use axum::extract::rejection::JsonRejection;
use axum::extract::{Extension, Json, Path, State};
use axum::http::StatusCode;
use axum::routing::{get, post};
use nomifun_api_types::{
ApiResponse, CreateRemoteAgentRequest, HandshakeResponse, RemoteAgentListItem, RemoteAgentResponse,
TestRemoteAgentConnectionRequest, UpdateRemoteAgentRequest,
};
use nomifun_auth::CurrentUser;
use nomifun_common::AppError;
use super::state::RemoteAgentRouterState;
/// Build the remote agent router.
///
/// All routes require authentication (applied by the caller).
pub fn remote_agent_routes(state: RemoteAgentRouterState) -> Router {
Router::new()
.route("/api/remote-agents", get(list).post(create))
.route("/api/remote-agents/test-connection", post(test_connection))
.route("/api/remote-agents/{id}", get(get_one).put(update).delete(delete_one))
.route("/api/remote-agents/{id}/handshake", post(handshake))
.with_state(state)
}
async fn list(
State(state): State<RemoteAgentRouterState>,
Extension(_user): Extension<CurrentUser>,
) -> Result<Json<ApiResponse<Vec<RemoteAgentListItem>>>, AppError> {
let items = state.service.list().await?;
Ok(Json(ApiResponse::ok(items)))
}
async fn get_one(
State(state): State<RemoteAgentRouterState>,
Extension(_user): Extension<CurrentUser>,
Path(id): Path<String>,
) -> Result<Json<ApiResponse<RemoteAgentResponse>>, AppError> {
let agent = state.service.get(&id).await?;
Ok(Json(ApiResponse::ok(agent)))
}
async fn create(
State(state): State<RemoteAgentRouterState>,
Extension(_user): Extension<CurrentUser>,
body: Result<Json<CreateRemoteAgentRequest>, JsonRejection>,
) -> Result<(StatusCode, Json<ApiResponse<RemoteAgentResponse>>), AppError> {
let Json(req) = body.map_err(|e| AppError::BadRequest(e.to_string()))?;
let agent = state.service.create(req).await?;
Ok((StatusCode::CREATED, Json(ApiResponse::ok(agent))))
}
async fn update(
State(state): State<RemoteAgentRouterState>,
Extension(_user): Extension<CurrentUser>,
Path(id): Path<String>,
body: Result<Json<UpdateRemoteAgentRequest>, JsonRejection>,
) -> Result<Json<ApiResponse<RemoteAgentResponse>>, AppError> {
let Json(req) = body.map_err(|e| AppError::BadRequest(e.to_string()))?;
let agent = state.service.update(&id, req).await?;
Ok(Json(ApiResponse::ok(agent)))
}
async fn delete_one(
State(state): State<RemoteAgentRouterState>,
Extension(_user): Extension<CurrentUser>,
Path(id): Path<String>,
) -> Result<Json<ApiResponse<()>>, AppError> {
state.service.delete(&id).await?;
Ok(Json(ApiResponse::success()))
}
async fn test_connection(
State(state): State<RemoteAgentRouterState>,
Extension(_user): Extension<CurrentUser>,
body: Result<Json<TestRemoteAgentConnectionRequest>, JsonRejection>,
) -> Result<Json<ApiResponse<()>>, AppError> {
let Json(req) = body.map_err(|e| AppError::BadRequest(e.to_string()))?;
state.service.test_connection(req).await?;
Ok(Json(ApiResponse::success()))
}
async fn handshake(
State(state): State<RemoteAgentRouterState>,
Extension(_user): Extension<CurrentUser>,
Path(id): Path<String>,
) -> Result<Json<ApiResponse<HandshakeResponse>>, AppError> {
let resp = state.service.handshake(&id).await?;
Ok(Json(ApiResponse::ok(resp)))
}