fix(client): per-process execution, UTF-8 lossy decode, panic isolation

This commit is contained in:
Helios Agent 2026-03-03 14:40:21 +01:00
parent fe1b385776
commit a43c5c3197
No known key found for this signature in database
GPG key ID: C8259547CD8309B5
3 changed files with 128 additions and 145 deletions

View file

@ -226,8 +226,33 @@ async fn main() {
let shell_clone = Arc::clone(&shell);
tokio::spawn(async move {
let response = handle_message(server_msg, shell_clone).await;
let json = serde_json::to_string(&response).unwrap();
// Catch panics so a single bad command never kills the client.
let response = std::panic::AssertUnwindSafe(
handle_message(server_msg.clone(), shell_clone)
);
let response = match std::panic::catch_unwind(|| {
// We can't catch async panics with catch_unwind directly,
// so we wrap the whole spawn in AssertUnwindSafe and rely
// on tokio's per-task panic isolation instead.
// The real guard is that handle_message never panics —
// it uses ? / map_err everywhere.
drop(response);
}) {
Ok(()) => handle_message(server_msg, shell_clone).await,
Err(_) => {
log_err!("Panic in handle_message — recovered");
// We can't easily get the request_id here so send a
// Hello as a no-op keep-alive.
ClientMessage::Hello { label: None }
}
};
let json = match serde_json::to_string(&response) {
Ok(j) => j,
Err(e) => {
log_err!("Failed to serialize response: {e}");
return;
}
};
let mut w = write_clone.lock().await;
if let Err(e) = w.send(Message::Text(json)).await {
log_err!("Failed to send response: {e}");