Implement error reporting in IPC

This commit is contained in:
Ivan Molodetskikh
2024-02-11 09:19:37 +04:00
parent a388c25795
commit 0931447ec1
3 changed files with 45 additions and 28 deletions
+17 -5
View File
@@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
pub const SOCKET_PATH_ENV: &str = "NIRI_SOCKET";
/// Request from client to niri.
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum Request {
/// Request information about connected outputs.
Outputs,
@@ -18,9 +18,21 @@ pub enum Request {
Action(Action),
}
/// Response from niri to client.
#[derive(Debug, Serialize, Deserialize)]
/// Reply from niri to client.
///
/// Every request gets one reply.
///
/// * If an error had occurred, it will be an `Reply::Err`.
/// * If the request does not need any particular response, it will be
/// `Reply::Ok(Response::Handled)`. Kind of like an `Ok(())`.
/// * Otherwise, it will be `Reply::Ok(response)` with one of the other [`Response`] variants.
pub type Reply = Result<Response, String>;
/// Successful response from niri to client.
#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum Response {
/// A request that does not need a response was handled successfully.
Handled,
/// Information about connected outputs.
///
/// Map from connector name to output info.
@@ -30,7 +42,7 @@ pub enum Response {
/// Actions that niri can perform.
// Variants in this enum should match the spelling of the ones in niri-config. Most, but not all,
// variants from niri-config should be present here.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "clap", derive(clap::Parser))]
#[cfg_attr(feature = "clap", command(subcommand_value_name = "ACTION"))]
#[cfg_attr(feature = "clap", command(subcommand_help_heading = "Actions"))]
@@ -205,7 +217,7 @@ pub enum SizeChange {
}
/// Layout to switch to.
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum LayoutSwitchTarget {
/// The next configured layout.
Next,
+13 -14
View File
@@ -3,8 +3,8 @@ use std::io::{Read, Write};
use std::net::Shutdown;
use std::os::unix::net::UnixStream;
use anyhow::{bail, Context};
use niri_ipc::{Mode, Output, Request, Response};
use anyhow::{anyhow, bail, Context};
use niri_ipc::{Mode, Output, Reply, Request, Response};
use crate::cli::Msg;
@@ -36,20 +36,15 @@ pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> {
.read_to_end(&mut buf)
.context("error reading IPC response")?;
if matches!(msg, Msg::Action { .. }) {
if buf.is_empty() {
return Ok(());
} else {
bail!("unexpected response: expected no response, got {buf:?}");
}
}
let reply: Reply = serde_json::from_slice(&buf).context("error parsing IPC reply")?;
let response = reply
.map_err(|msg| anyhow!(msg))
.context("niri could not handle the request")?;
let response = serde_json::from_slice(&buf).context("error parsing IPC response")?;
match msg {
Msg::Outputs => {
#[allow(irrefutable_let_patterns)]
let Response::Outputs(outputs) = response
else {
let Response::Outputs(outputs) = response else {
bail!("unexpected response: expected Outputs, got {response:?}");
};
@@ -109,7 +104,11 @@ pub fn handle_msg(msg: Msg, json: bool) -> anyhow::Result<()> {
println!();
}
}
Msg::Action { .. } => unreachable!(),
Msg::Action { .. } => {
let Response::Handled = response else {
bail!("unexpected response: expected Handled, got {response:?}");
};
}
}
Ok(())
+15 -9
View File
@@ -110,7 +110,19 @@ async fn handle_client(ctx: ClientCtx, stream: Async<'_, UnixStream>) -> anyhow:
.await
.context("error reading request")?;
let request: Request = serde_json::from_str(&buf).context("error parsing request")?;
let reply = process(&ctx, &buf).map_err(|err| {
warn!("error processing IPC request: {err:?}");
err.to_string()
});
let buf = serde_json::to_vec(&reply).context("error formatting reply")?;
write.write_all(&buf).await.context("error writing reply")?;
Ok(())
}
fn process(ctx: &ClientCtx, buf: &str) -> anyhow::Result<Response> {
let request: Request = serde_json::from_str(buf).context("error parsing request")?;
let response = match request {
Request::Outputs => {
@@ -122,15 +134,9 @@ async fn handle_client(ctx: ClientCtx, stream: Async<'_, UnixStream>) -> anyhow:
ctx.event_loop.insert_idle(move |state| {
state.do_action(action);
});
return Ok(());
Response::Handled
}
};
let buf = serde_json::to_vec(&response).context("error formatting response")?;
write
.write_all(&buf)
.await
.context("error writing response")?;
Ok(())
Ok(response)
}