fix!: create IPC socket in user runtime directory (#1313)
Each user has their own runtime directory at `/run/user/<uid>`. Creating the IPC socket in there makes sure it is cleaned up regardless of whether `ncspot` exits normally. BREAKING CHANGE: move IPC socket location
This commit is contained in:
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
- Improve error messages generated by the command line
|
- Improve error messages generated by the command line
|
||||||
- Build with crossterm terminal backend by default
|
- Build with crossterm terminal backend by default
|
||||||
|
- Move UNIX IPC socket from the user's cache path to the user's runtime directory
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|||||||
10
doc/users.md
10
doc/users.md
@@ -180,10 +180,12 @@ Note: \<FOO\> - mandatory arg; [BAR] - optional arg
|
|||||||
| `save [current]` | Save selected item, if `current` is passed the currently playing item will be saved |
|
| `save [current]` | Save selected item, if `current` is passed the currently playing item will be saved |
|
||||||
|
|
||||||
## Remote control (IPC)
|
## Remote control (IPC)
|
||||||
Apart from MPRIS, ncspot will also create a domain socket on UNIX platforms
|
Apart from MPRIS, ncspot will also create a domain socket on UNIX platforms (Linux, macOS, *BSD).
|
||||||
(Linux, macOS, *BSD) at `~/.cache/ncspot/ncspot.sock`. Applications or scripts
|
The socket will be created in the platform's runtime directory. If XDG_RUNTIME_DIR is set, it will
|
||||||
can connect to this socket to send commands or be notified of the currently
|
be created under `$XDG_RUNTIME_DIR/ncspot`. If XDG_RUNTIME_DIR isn't set, it will be created under
|
||||||
playing track, i.e. with `netcat`:
|
`/run/user/<uid>` for Linux if it exists. In all other cases, it will be created under
|
||||||
|
`/tmp/ncspot-<uid>`. Applications or scripts can connect to this socket to send commands or be
|
||||||
|
notified of the currently playing track, i.e. with `netcat`:
|
||||||
|
|
||||||
```
|
```
|
||||||
% nc -U ~/.cache/ncspot/ncspot.sock
|
% nc -U ~/.cache/ncspot/ncspot.sock
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use crate::library::Library;
|
|||||||
use crate::queue::Queue;
|
use crate::queue::Queue;
|
||||||
use crate::spotify::{PlayerEvent, Spotify};
|
use crate::spotify::{PlayerEvent, Spotify};
|
||||||
use crate::ui::create_cursive;
|
use crate::ui::create_cursive;
|
||||||
use crate::{authentication, ui};
|
use crate::{authentication, ui, utils};
|
||||||
use crate::{command, queue, spotify};
|
use crate::{command, queue, spotify};
|
||||||
|
|
||||||
#[cfg(feature = "mpris")]
|
#[cfg(feature = "mpris")]
|
||||||
@@ -140,7 +140,9 @@ impl Application {
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let ipc = ipc::IpcSocket::new(
|
let ipc = ipc::IpcSocket::new(
|
||||||
ASYNC_RUNTIME.get().unwrap().handle(),
|
ASYNC_RUNTIME.get().unwrap().handle(),
|
||||||
crate::config::cache_path("ncspot.sock"),
|
utils::create_runtime_directory()
|
||||||
|
.unwrap()
|
||||||
|
.join("ncspot.sock"),
|
||||||
event_manager.clone(),
|
event_manager.clone(),
|
||||||
)
|
)
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|||||||
53
src/utils.rs
53
src/utils.rs
@@ -1,6 +1,6 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::fmt::Write;
|
use std::{fmt::Write, path::PathBuf};
|
||||||
|
|
||||||
/// Returns a human readable String of a Duration
|
/// Returns a human readable String of a Duration
|
||||||
///
|
///
|
||||||
@@ -59,3 +59,54 @@ pub fn download(url: String, path: std::path::PathBuf) -> Result<(), std::io::Er
|
|||||||
std::io::copy(&mut resp, &mut file)?;
|
std::io::copy(&mut resp, &mut file)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create the application specific runtime directory and return the path to it.
|
||||||
|
///
|
||||||
|
/// If the directory already exists and has the correct permissions, this function just returns the
|
||||||
|
/// existing directory. The contents stored in this directory are not necessarily persisted across
|
||||||
|
/// reboots. Stored files should be small since they could reside in memory (like on a tmpfs mount).
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn create_runtime_directory() -> Result<PathBuf, Box<dyn std::error::Error>> {
|
||||||
|
use std::{
|
||||||
|
fs::{self, Permissions},
|
||||||
|
os::unix::prelude::PermissionsExt,
|
||||||
|
};
|
||||||
|
|
||||||
|
let linux_runtime_directory =
|
||||||
|
PathBuf::from(format!("/run/user/{}/", unsafe { libc::getuid() }));
|
||||||
|
let unix_runtime_directory = PathBuf::from("/tmp/");
|
||||||
|
|
||||||
|
let user_runtime_directory = if let Some(xdg_runtime_directory) = xdg_runtime_directory() {
|
||||||
|
Some(xdg_runtime_directory.join("ncspot"))
|
||||||
|
} else if cfg!(linux) && linux_runtime_directory.exists() {
|
||||||
|
Some(linux_runtime_directory.join("ncspot"))
|
||||||
|
} else if unix_runtime_directory.exists() {
|
||||||
|
Some(unix_runtime_directory.join(format!("ncspot-{}", unsafe { libc::getuid() })))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
.ok_or("no runtime directory found")?;
|
||||||
|
|
||||||
|
let creation_result = fs::create_dir(&user_runtime_directory);
|
||||||
|
|
||||||
|
if creation_result.is_ok()
|
||||||
|
|| matches!(
|
||||||
|
creation_result.as_ref().unwrap_err().kind(),
|
||||||
|
std::io::ErrorKind::AlreadyExists
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Needed when created inside a world readable directory, to prevent unauthorized access.
|
||||||
|
// Doesn't hurt otherwise.
|
||||||
|
fs::set_permissions(&user_runtime_directory, Permissions::from_mode(0o700))?;
|
||||||
|
|
||||||
|
Ok(user_runtime_directory)
|
||||||
|
} else {
|
||||||
|
#[allow(clippy::unnecessary_unwrap)]
|
||||||
|
Err(Box::new(creation_result.unwrap_err()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn xdg_runtime_directory() -> Option<PathBuf> {
|
||||||
|
std::env::var("XDG_RUNTIME_DIR").ok().map(Into::into)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user