2026-04-28 17:55:23 +02:00
|
|
|
use color_eyre::Result;
|
|
|
|
|
use color_eyre::eyre::Context;
|
|
|
|
|
use launch_pad::ProcessKey;
|
|
|
|
|
use launch_pad::process::Process;
|
2023-11-09 14:34:29 -05:00
|
|
|
use rustix::fd::AsRawFd;
|
2026-04-28 17:55:23 +02:00
|
|
|
use std::os::fd::OwnedFd;
|
|
|
|
|
use std::os::unix::net::UnixStream;
|
|
|
|
|
use std::sync::Arc;
|
2025-10-20 18:59:32 -07:00
|
|
|
use tokio::sync::Mutex;
|
2023-07-20 15:35:35 -04:00
|
|
|
use tracing::Instrument;
|
2023-06-27 15:26:52 -04:00
|
|
|
|
2026-04-25 18:18:48 +02:00
|
|
|
pub const PANEL_NOTIFICATIONS_FD: &str = "PANEL_NOTIFICATIONS_FD";
|
|
|
|
|
pub const DAEMON_NOTIFICATIONS_FD: &str = "DAEMON_NOTIFICATIONS_FD";
|
|
|
|
|
|
2023-06-27 15:26:52 -04:00
|
|
|
pub fn create_socket() -> Result<(OwnedFd, OwnedFd)> {
|
|
|
|
|
// Create a new pair of unnamed Unix sockets
|
|
|
|
|
let (sock_1, sock_2) = UnixStream::pair().wrap_err("failed to create socket pair")?;
|
|
|
|
|
|
2023-07-07 16:50:22 -04:00
|
|
|
// Turn the sockets into non-blocking fd, which we can pass to the child
|
2023-06-27 15:26:52 -04:00
|
|
|
// process
|
2023-07-07 16:50:22 -04:00
|
|
|
sock_1
|
2023-07-20 15:35:35 -04:00
|
|
|
.set_nonblocking(true)
|
|
|
|
|
.wrap_err("failed to mark client socket as non-blocking")?;
|
2023-06-27 15:26:52 -04:00
|
|
|
|
2023-07-07 16:50:22 -04:00
|
|
|
sock_2
|
2023-07-20 15:35:35 -04:00
|
|
|
.set_nonblocking(true)
|
|
|
|
|
.wrap_err("failed to mark client socket as non-blocking")?;
|
2023-07-07 16:50:22 -04:00
|
|
|
|
|
|
|
|
Ok((OwnedFd::from(sock_1), OwnedFd::from(sock_2)))
|
2023-06-27 15:26:52 -04:00
|
|
|
}
|
2023-07-20 15:35:35 -04:00
|
|
|
|
2026-04-25 17:34:56 +02:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2023-07-20 15:35:35 -04:00
|
|
|
pub fn notifications_process(
|
|
|
|
|
span: tracing::Span,
|
|
|
|
|
cmd: &'static str,
|
|
|
|
|
key: Arc<Mutex<Option<ProcessKey>>>,
|
2023-11-09 09:50:58 -05:00
|
|
|
mut env_vars: Vec<(String, String)>,
|
2023-11-09 14:34:29 -05:00
|
|
|
fd: OwnedFd,
|
2023-07-20 15:35:35 -04:00
|
|
|
restart_span: tracing::Span,
|
|
|
|
|
restart_cmd: &'static str,
|
|
|
|
|
restart_key: Arc<Mutex<Option<ProcessKey>>>,
|
|
|
|
|
restart_env_vars: Vec<(String, String)>,
|
|
|
|
|
) -> Process {
|
2023-11-09 09:50:58 -05:00
|
|
|
env_vars.retain(|v| &v.0 != "WAYLAND_SOCKET");
|
|
|
|
|
|
2023-07-20 15:35:35 -04:00
|
|
|
let stdout_span = span.clone();
|
|
|
|
|
let stderr_span = span.clone();
|
|
|
|
|
let env_clone = env_vars.clone();
|
|
|
|
|
Process::new()
|
|
|
|
|
.with_executable(cmd)
|
2025-10-20 18:59:32 -07:00
|
|
|
.with_fds(move || vec![fd])
|
2023-07-20 15:35:35 -04:00
|
|
|
.with_on_stdout(move |_, _, line| {
|
|
|
|
|
let stdout_span = stdout_span.clone();
|
|
|
|
|
async move {
|
|
|
|
|
info!("{}", line);
|
|
|
|
|
}
|
|
|
|
|
.instrument(stdout_span)
|
|
|
|
|
})
|
|
|
|
|
.with_on_stderr(move |_, _, line| {
|
|
|
|
|
let stderr_span = stderr_span.clone();
|
|
|
|
|
async move {
|
|
|
|
|
warn!("{}", line);
|
|
|
|
|
}
|
|
|
|
|
.instrument(stderr_span)
|
|
|
|
|
})
|
2023-11-09 09:50:58 -05:00
|
|
|
.with_on_exit(move |pman, my_key, _, will_restart| {
|
2023-07-20 15:35:35 -04:00
|
|
|
// force restart of notifications / panel when the other exits
|
2023-11-09 14:34:29 -05:00
|
|
|
// also update the environment variables to use the new socket
|
|
|
|
|
let (my_fd, their_fd) = create_socket().expect("Failed to create notification socket");
|
|
|
|
|
let mut my_env_vars = env_clone.clone();
|
|
|
|
|
if let Some((_k, v)) = my_env_vars
|
|
|
|
|
.iter_mut()
|
|
|
|
|
.find(|(k, _v)| k == PANEL_NOTIFICATIONS_FD || k == DAEMON_NOTIFICATIONS_FD)
|
|
|
|
|
{
|
2024-01-12 10:31:19 +11:00
|
|
|
*v = my_fd.as_raw_fd().to_string();
|
2023-11-09 14:34:29 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut their_env_vars = restart_env_vars.clone();
|
|
|
|
|
if let Some((_k, v)) = their_env_vars
|
|
|
|
|
.iter_mut()
|
|
|
|
|
.find(|(k, _v)| k == PANEL_NOTIFICATIONS_FD || k == DAEMON_NOTIFICATIONS_FD)
|
|
|
|
|
{
|
2024-01-12 10:31:19 +11:00
|
|
|
*v = their_fd.as_raw_fd().to_string();
|
2023-11-09 14:34:29 -05:00
|
|
|
}
|
|
|
|
|
|
2023-07-20 15:35:35 -04:00
|
|
|
let new_process = notifications_process(
|
|
|
|
|
restart_span.clone(),
|
|
|
|
|
restart_cmd,
|
|
|
|
|
restart_key.clone(),
|
2023-11-09 14:34:29 -05:00
|
|
|
their_env_vars.clone(),
|
|
|
|
|
their_fd,
|
2023-07-20 15:35:35 -04:00
|
|
|
span.clone(),
|
|
|
|
|
cmd,
|
|
|
|
|
key.clone(),
|
2023-11-09 14:34:29 -05:00
|
|
|
my_env_vars.clone(),
|
2023-07-20 15:35:35 -04:00
|
|
|
);
|
|
|
|
|
let restart_key = restart_key.clone();
|
2023-11-09 09:50:58 -05:00
|
|
|
|
|
|
|
|
let mut pman_clone = pman.clone();
|
2023-07-20 15:35:35 -04:00
|
|
|
async move {
|
|
|
|
|
if will_restart {
|
2025-10-20 18:59:32 -07:00
|
|
|
if let Err(why) = pman_clone.update_process_env(&my_key, my_env_vars).await {
|
2023-11-09 09:50:58 -05:00
|
|
|
error!(?why, "Failed to update environment variables");
|
|
|
|
|
}
|
|
|
|
|
if let Err(why) = pman_clone
|
2025-10-20 18:59:32 -07:00
|
|
|
.update_process_fds(&my_key, move || vec![my_fd])
|
2023-11-09 09:50:58 -05:00
|
|
|
.await
|
|
|
|
|
{
|
|
|
|
|
error!(?why, "Failed to update fds");
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-12 10:31:19 +11:00
|
|
|
let Some(old) = *restart_key.lock().await else {
|
2023-11-09 09:50:58 -05:00
|
|
|
error!("Couldn't stop previous invocation of {}", cmd);
|
|
|
|
|
return;
|
2023-07-20 15:35:35 -04:00
|
|
|
};
|
|
|
|
|
_ = pman.stop_process(old).await;
|
|
|
|
|
|
|
|
|
|
if let Ok(new) = pman.start(new_process).await {
|
2024-01-12 10:31:19 +11:00
|
|
|
let mut guard = restart_key.lock().await;
|
2023-07-20 15:35:35 -04:00
|
|
|
*guard = Some(new);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.with_env(env_vars)
|
|
|
|
|
}
|