Support multiple IPC sockets (#1171)

For instance for when multiple ncspot instances are running. In that case the
PID will be appended to the path, i.e. `~/.cache/ncspot/ncspot.20707.sock`.

Also ncspot will now delete the socket on shutdown.

Fixes #1158
This commit is contained in:
Henrik Friedrichsen
2023-05-22 22:14:59 +02:00
committed by GitHub
parent d8faa87431
commit e6ed4ea024

View File

@@ -15,6 +15,7 @@ use crate::spotify::PlayerEvent;
pub struct IpcSocket { pub struct IpcSocket {
tx: Sender<Status>, tx: Sender<Status>,
path: PathBuf,
} }
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug, Serialize)]
@@ -23,11 +24,25 @@ struct Status {
playable: Option<Playable>, playable: Option<Playable>,
} }
impl Drop for IpcSocket {
fn drop(&mut self) {
log::info!("Removing IPC socket: {:?}", self.path);
std::fs::remove_file(&self.path).expect("Could not remove IPC socket");
}
}
impl IpcSocket { impl IpcSocket {
pub fn new(handle: &Handle, path: PathBuf, ev: EventManager) -> io::Result<IpcSocket> { pub fn new(handle: &Handle, path: PathBuf, ev: EventManager) -> io::Result<IpcSocket> {
if path.exists() { let path = if path.exists() && Self::is_open_socket(&path) {
let mut new_path = path;
new_path.set_file_name(format!("ncspot.{}.sock", std::process::id()));
new_path
} else if path.exists() && !Self::is_open_socket(&path) {
std::fs::remove_file(&path)?; std::fs::remove_file(&path)?;
} path
} else {
path
};
info!("Creating IPC domain socket at {path:?}"); info!("Creating IPC domain socket at {path:?}");
@@ -37,12 +52,18 @@ impl IpcSocket {
}; };
let (tx, rx) = tokio::sync::watch::channel(status); let (tx, rx) = tokio::sync::watch::channel(status);
let listener_path = path.clone();
handle.spawn(async move { handle.spawn(async move {
let listener = UnixListener::bind(path).expect("Could not create IPC domain socket"); let listener =
UnixListener::bind(listener_path).expect("Could not create IPC domain socket");
Self::worker(listener, ev, rx.clone()).await; Self::worker(listener, ev, rx.clone()).await;
}); });
Ok(IpcSocket { tx }) Ok(IpcSocket { tx, path })
}
fn is_open_socket(path: &PathBuf) -> bool {
std::os::unix::net::UnixStream::connect(path).is_ok()
} }
pub fn publish(&self, event: &PlayerEvent, playable: Option<Playable>) { pub fn publish(&self, event: &PlayerEvent, playable: Option<Playable>) {