Files
galaxy/crates/remote_server/src/host_response.rs
T

91 lines
3.5 KiB
Rust

//! Helpers for interpreting raw host-scoped `ServerMessage` responses.
//!
//! Host-scoped requests dispatched via [`crate::manager::RemoteServerManager`]
//! resolve to a raw [`ServerMessage`] (the manager only unwraps the top-level
//! [`server_message::Message::Error`] transport error). Operation-specific
//! failures, however, are nested inside the per-operation response variants
//! (e.g. [`WriteFileResponse`] can carry a [`FileOperationError`]). These
//! helpers centralize that parsing so call sites across crates don't each
//! re-implement it — and crucially so a nested error is never silently
//! treated as success.
//!
//! Each helper returns `Ok(())` on success or `Err(message)` with the
//! server-provided error message on failure. Failure includes both an
//! `Error` variant and a missing (`None`) `result`: the daemon always
//! populates exactly one of `success`/`error`, so an unset result is a
//! malformed/never-populated response, never a benign success.
//!
//! Convention for new host-scoped operations: an op whose response is a
//! plain success/error result should get a parser here; an op that returns
//! richer data (e.g. `ReadFileContext`, `GetDiffState`) is parsed at its
//! manager call site instead. The exhaustiveness guard test in
//! `host_response_tests.rs` forces every new request variant to be
//! classified one way or the other.
use crate::proto::{server_message, ServerMessage};
/// Interprets a per-operation response with the standard
/// `Success | Error | (unset)` result shape. A missing `result` is an error
/// (see module docs).
macro_rules! file_op_result {
($msg:expr, $variant:path, $result:path, $op:literal) => {{
use $result as R;
match &$msg.message {
Some($variant(resp)) => match &resp.result {
Some(R::Success(_)) => Ok(()),
Some(R::Error(e)) => Err(e.message.clone()),
None => Err(format!("Empty {} response", $op)),
},
other => Err(unexpected_variant($op, other)),
}
}};
}
/// Interprets a [`ServerMessage`] as the result of a `WriteFile` request.
pub fn write_file_result(msg: &ServerMessage) -> Result<(), String> {
file_op_result!(
msg,
server_message::Message::WriteFileResponse,
crate::proto::write_file_response::Result,
"WriteFile"
)
}
/// Interprets a [`ServerMessage`] as the result of a `SaveBuffer` request.
pub fn save_buffer_result(msg: &ServerMessage) -> Result<(), String> {
file_op_result!(
msg,
server_message::Message::SaveBufferResponse,
crate::proto::save_buffer_response::Result,
"SaveBuffer"
)
}
/// Interprets a [`ServerMessage`] as the result of a `DeleteFile` request.
pub fn delete_file_result(msg: &ServerMessage) -> Result<(), String> {
file_op_result!(
msg,
server_message::Message::DeleteFileResponse,
crate::proto::delete_file_response::Result,
"DeleteFile"
)
}
/// Interprets a [`ServerMessage`] as the result of a `DiscardFiles` request.
pub fn discard_files_result(msg: &ServerMessage) -> Result<(), String> {
file_op_result!(
msg,
server_message::Message::DiscardFilesResponse,
crate::proto::discard_files_response::Result,
"DiscardFiles"
)
}
fn unexpected_variant(op: &str, other: &Option<server_message::Message>) -> String {
format!("Unexpected response variant for {op}: {other:?}")
}
#[cfg(test)]
#[path = "host_response_tests.rs"]
mod tests;