mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
Implement error reporting in IPC
This commit is contained in:
+17
-5
@@ -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
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user