delete agent close

This commit is contained in:
lda
2026-04-14 05:49:49 +07:00 Unverified
parent 28dda76ee8
commit 7769db3906
6 changed files with 46 additions and 29 deletions
+4 -5
View File
@@ -72,12 +72,11 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
}); });
if (!res.ok) { if (!res.ok) {
let detail = ""; const raw = await res.text();
let detail = raw;
try { try {
detail = JSON.stringify(await res.json(), null, 2); detail = JSON.stringify(JSON.parse(raw), null, 2);
} catch { } catch {}
detail = await res.text();
}
throw new Error(`${res.status} ${res.statusText}\n${detail}`); throw new Error(`${res.status} ${res.statusText}\n${detail}`);
} }
+1 -1
View File
@@ -171,7 +171,7 @@ pub enum ClientMessage {
}, },
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")] #[serde(tag = "type", rename_all = "snake_case")]
pub enum ServerMessage { pub enum ServerMessage {
Command { Command {
+3 -3
View File
@@ -9,7 +9,7 @@ use uuid::Uuid;
use wakey_agent::protocol::{AgentCommand, ErrorPayload, RequestId, ServerMessage}; use wakey_agent::protocol::{AgentCommand, ErrorPayload, RequestId, ServerMessage};
use crate::api::json_error; use crate::api::json_error;
use crate::runtime::{AgentReply, AppState}; use crate::runtime::{AgentReply, AppState, SessionEvent};
use crate::state::AuditEventInput; use crate::state::AuditEventInput;
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
@@ -114,10 +114,10 @@ pub async fn run_command(
warn!(error = %err, "failed to append audit event for command dispatch"); warn!(error = %err, "failed to append audit event for command dispatch");
} }
if let Err(err) = tx.send(ServerMessage::Command { if let Err(err) = tx.send(SessionEvent::Message(ServerMessage::Command {
request_id, request_id,
command: req.command, command: req.command,
}) { })) {
state.pending.lock().await.remove(&request_id_string); state.pending.lock().await.remove(&request_id_string);
warn!(error = %err, "failed sending command to agent session"); warn!(error = %err, "failed sending command to agent session");
if let Err(audit_err) = state if let Err(audit_err) = state
+9 -4
View File
@@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
use tracing::{info, warn}; use tracing::{info, warn};
use crate::api::json_error; use crate::api::json_error;
use crate::runtime::AppState; use crate::runtime::{AppState, SessionEvent};
use crate::state::AuditEventInput; use crate::state::AuditEventInput;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@@ -288,8 +288,10 @@ pub async fn revoke_agent(
match state.store.revoke_agent(&agent_id).await { match state.store.revoke_agent(&agent_id).await {
Ok(revoked) => { Ok(revoked) => {
if revoked { if revoked {
// Remove any active session so this credential is also cut off at runtime. // Request a graceful websocket close, then remove session from active map.
state.sessions.write().await.remove(&agent_id); if let Some(session) = state.sessions.write().await.remove(&agent_id) {
let _ = session.tx.send(SessionEvent::Close);
}
} }
if let Err(err) = state if let Err(err) = state
@@ -318,7 +320,10 @@ pub async fn revoke_agent(
warn!(error = %err, "failed to append audit event for agent revoke"); warn!(error = %err, "failed to append audit event for agent revoke");
} }
Ok((StatusCode::OK, Json(RevokeAgentResponse { agent_id, revoked }))) Ok((
StatusCode::OK,
Json(RevokeAgentResponse { agent_id, revoked }),
))
} }
Err(err) => { Err(err) => {
warn!(error = %err, "failed to revoke agent credentials"); warn!(error = %err, "failed to revoke agent credentials");
+7 -2
View File
@@ -25,8 +25,8 @@ use crate::ws;
mod admin; mod admin;
mod process; mod process;
pub use admin::{issue_enroll_token, list_enroll_tokens, revoke_enroll_token, state_stats};
pub use admin::revoke_agent; pub use admin::revoke_agent;
pub use admin::{issue_enroll_token, list_enroll_tokens, revoke_enroll_token, state_stats};
pub use process::reload_daemon; pub use process::reload_daemon;
use process::{remove_pid_file, write_pid_file}; use process::{remove_pid_file, write_pid_file};
@@ -44,7 +44,12 @@ pub struct AppState {
#[derive(Clone)] #[derive(Clone)]
pub struct AgentSession { pub struct AgentSession {
pub connection_id: String, pub connection_id: String,
pub tx: mpsc::UnboundedSender<ServerMessage>, pub tx: mpsc::UnboundedSender<SessionEvent>,
}
#[derive(Clone)]
pub enum SessionEvent {
Message(ServerMessage),
Close,
} }
pub enum AgentReply { pub enum AgentReply {
+22 -14
View File
@@ -8,9 +8,9 @@ use std::time::Instant;
use tokio::sync::mpsc; use tokio::sync::mpsc;
use tracing::{debug, info, info_span, warn}; use tracing::{debug, info, info_span, warn};
use uuid::Uuid; use uuid::Uuid;
use wakey_agent::protocol::{ErrorPayload, RequestId, ServerMessage}; use wakey_agent::protocol::{ErrorPayload, RequestId};
use crate::runtime::{AgentReply, AgentSession, AppState}; use crate::runtime::{AgentReply, AgentSession, AppState, SessionEvent};
use crate::state::AuditEventInput; use crate::state::AuditEventInput;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@@ -48,20 +48,28 @@ async fn handle_agent_socket(state: AppState, socket: WebSocket) {
let connected_at = Instant::now(); let connected_at = Instant::now();
let (mut write, mut read) = socket.split(); let (mut write, mut read) = socket.split();
let (tx, mut rx) = mpsc::unbounded_channel::<ServerMessage>(); let (tx, mut rx) = mpsc::unbounded_channel::<SessionEvent>();
let writer = tokio::spawn(async move { let writer = tokio::spawn(async move {
while let Some(msg) = rx.recv().await { while let Some(event) = rx.recv().await {
let encoded = match serde_json::to_string(&msg) { match event {
Ok(s) => s, SessionEvent::Close => {
Err(err) => { let _ = write.send(Message::Close(None)).await;
warn!(error = %err, "failed to encode server websocket message"); break;
continue; }
SessionEvent::Message(msg) => {
let encoded = match serde_json::to_string(&msg) {
Ok(s) => s,
Err(err) => {
warn!(error = %err, "failed to encode server websocket message");
continue;
}
};
if let Err(err) = write.send(Message::Text(encoded.into())).await {
warn!(error = %err, "failed to send websocket message");
break;
}
} }
};
if let Err(err) = write.send(Message::Text(encoded.into())).await {
warn!(error = %err, "failed to send websocket message");
break;
} }
} }
debug!("websocket writer loop ended"); debug!("websocket writer loop ended");
@@ -148,7 +156,7 @@ async fn handle_agent_socket(state: AppState, socket: WebSocket) {
async fn process_agent_text( async fn process_agent_text(
state: &AppState, state: &AppState,
tx: &mpsc::UnboundedSender<ServerMessage>, tx: &mpsc::UnboundedSender<SessionEvent>,
connection_id: &str, connection_id: &str,
authed_agent_id: &mut Option<String>, authed_agent_id: &mut Option<String>,
hello_at: &mut Option<Instant>, hello_at: &mut Option<Instant>,