huskies: merge 766

This commit is contained in:
dave
2026-04-28 08:54:44 +00:00
parent 0d14fffe1c
commit 38e828979c
6 changed files with 107 additions and 584 deletions
-121
View File
@@ -513,127 +513,6 @@ pub async fn gateway_generate_token_handler(state: Data<&Arc<GatewayState>>) ->
.body(Body::from(serde_json::to_vec(&body).unwrap_or_default()))
}
/// Request body sent by a build agent when registering with the gateway.
#[derive(Deserialize)]
struct RegisterAgentRequest {
token: String,
label: String,
address: String,
}
/// `POST /gateway/register` — build agent presents its join token and registers.
#[handler]
pub async fn gateway_register_agent_handler(
body: Body,
state: Data<&Arc<GatewayState>>,
) -> Response {
let bytes = match body.into_bytes().await {
Ok(b) => b,
Err(_) => {
return Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::from("could not read request body"));
}
};
let req: RegisterAgentRequest = match serde_json::from_slice(&bytes) {
Ok(r) => r,
Err(_) => {
return Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::from("invalid JSON body"));
}
};
match gateway::register_agent(&state, &req.token, req.label, req.address).await {
Ok(agent) => {
let body = serde_json::to_vec(&agent).unwrap_or_default();
Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/json")
.body(Body::from(body))
}
Err(_) => Response::builder()
.status(StatusCode::UNAUTHORIZED)
.body(Body::from("invalid or already-used join token")),
}
}
/// `GET /gateway/agents` — list all registered build agents.
#[handler]
pub async fn gateway_list_agents_handler(state: Data<&Arc<GatewayState>>) -> Response {
let agents = state.joined_agents.read().await.clone();
let body = serde_json::to_vec(&agents).unwrap_or_default();
Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/json")
.body(Body::from(body))
}
/// `DELETE /gateway/agents/:id` — remove a registered build agent.
#[handler]
pub async fn gateway_remove_agent_handler(
PoemPath(id): PoemPath<String>,
state: Data<&Arc<GatewayState>>,
) -> Response {
if gateway::remove_agent(&state, &id).await {
Response::builder()
.status(StatusCode::NO_CONTENT)
.body(Body::empty())
} else {
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::from("agent not found"))
}
}
/// Request body for assigning an agent to a project.
#[derive(Deserialize)]
struct AssignAgentRequest {
project: Option<String>,
}
/// `POST /gateway/agents/:id/assign` — assign or unassign an agent to a project.
#[handler]
pub async fn gateway_assign_agent_handler(
PoemPath(id): PoemPath<String>,
body: Json<AssignAgentRequest>,
state: Data<&Arc<GatewayState>>,
) -> Response {
match gateway::assign_agent(&state, &id, body.0.project).await {
Ok(agent) => {
let body = serde_json::to_vec(&agent).unwrap_or_default();
Response::builder()
.status(StatusCode::OK)
.header("Content-Type", "application/json")
.body(Body::from(body))
}
Err(gateway::Error::ProjectNotFound(msg)) => Response::builder()
.status(StatusCode::BAD_REQUEST)
.body(Body::from(msg)),
Err(_) => Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::from("agent not found")),
}
}
/// `POST /gateway/agents/:id/heartbeat` — update an agent's last-seen timestamp.
#[handler]
pub async fn gateway_heartbeat_handler(
PoemPath(id): PoemPath<String>,
state: Data<&Arc<GatewayState>>,
) -> Response {
if gateway::heartbeat_agent(&state, &id).await {
Response::builder()
.status(StatusCode::NO_CONTENT)
.body(Body::empty())
} else {
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::from("agent not found"))
}
}
// ── Event-push WebSocket handler ────────────────────────────────────────────
/// Query parameters accepted on the `/gateway/events/push` WebSocket upgrade.