Skip to content

Commit

Permalink
Merge branch 'add_bus_type_config' into pr_collection
Browse files Browse the repository at this point in the history
  • Loading branch information
eladyn committed Mar 4, 2022
2 parents 85a3696 + 3e96276 commit 453dcd2
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 12 deletions.
17 changes: 12 additions & 5 deletions docs/src/config/File.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,20 @@ password_cmd = "command_that_writes_password_to_stdout"
# can't be used simultaneously.
use_keyring = true

#
# If set to true, `spotifyd` tries to bind to the session dbus
# and expose MPRIS controls. When running headless, without a dbus session,
# then set this to false to avoid binding errors
#
# If set to true, `spotifyd` tries to bind to dbus (default is the session bus)
# and expose MPRIS controls. When running headless, without the session bus,
# you should set this to false, to avoid errors. If you still want to use MPRIS,
# have a look at the `dbus_type` option.
use_mpris = true

# The bus to bind to with the MPRIS interface.
# Possible values: "session", "system"
# The system bus can be used if no graphical session is available
# (e.g. on headless systems) but you still want to be able to use MPRIS.
# NOTE: You might need to add appropriate policies to allow spotifyd to
# own the name.
dbus_type = "session"

# The audio backend used to play the your music. To get
# a list of possible backends, run `spotifyd --help`.
backend = "alsa" # use portaudio for macOS [homebrew]
Expand Down
52 changes: 51 additions & 1 deletion src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,37 @@ impl From<Bitrate> for LSBitrate {
}
}

#[cfg(feature = "dbus_mpris")]
static DBUSTYPE_VALUES: &[&str] = &["session", "system"];

#[derive(Clone, Copy, Debug, Deserialize, PartialEq, StructOpt)]
#[serde(rename_all = "snake_case")]
pub enum DBusType {
Session,
System,
}

impl FromStr for DBusType {
type Err = ParseError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"session" => Ok(DBusType::Session),
"system" => Ok(DBusType::System),
_ => unreachable!(),
}
}
}

impl ToString for DBusType {
fn to_string(&self) -> String {
match self {
DBusType::Session => "session".to_string(),
DBusType::System => "system".to_string(),
}
}
}

#[derive(Debug, Default, StructOpt)]
#[structopt(
about = "A Spotify daemon",
Expand Down Expand Up @@ -280,6 +311,7 @@ pub struct SharedConfigValues {
#[cfg_attr(not(feature = "dbus_keyring"), structopt(skip), serde(skip))]
use_keyring: bool,

/// Enables the MPRIS interface
#[cfg_attr(
feature = "dbus_mpris",
structopt(long),
Expand All @@ -288,6 +320,18 @@ pub struct SharedConfigValues {
#[cfg_attr(not(feature = "dbus_mpris"), structopt(skip), serde(skip))]
use_mpris: Option<bool>,

/// The Bus-type to use for the MPRIS interface
#[cfg_attr(
feature = "dbus_mpris",
structopt(
long,
possible_values = &DBUSTYPE_VALUES,
value_name = "string",
)
)]
#[cfg_attr(not(feature = "dbus_mpris"), structopt(skip))]
dbus_type: Option<DBusType>,

/// A command that can be used to retrieve the Spotify account password
#[structopt(
conflicts_with = "password",
Expand Down Expand Up @@ -442,6 +486,7 @@ impl fmt::Debug for SharedConfigValues {
.field("password_cmd", &password_cmd_value)
.field("use_keyring", &self.use_keyring)
.field("use_mpris", &self.use_mpris)
.field("dbus_type", &self.dbus_type)
.field("on_song_change_hook", &self.on_song_change_hook)
.field("cache_path", &self.cache_path)
.field("no-audio-cache", &self.no_audio_cache)
Expand Down Expand Up @@ -520,7 +565,8 @@ impl SharedConfigValues {
zeroconf_port,
proxy,
device_type,
use_mpris
use_mpris,
dbus_type
);

// Handles boolean merging.
Expand Down Expand Up @@ -554,6 +600,7 @@ pub(crate) struct SpotifydConfig {
#[allow(unused)]
pub(crate) use_keyring: bool,
pub(crate) use_mpris: bool,
pub(crate) dbus_type: DBusType,
pub(crate) cache: Option<Cache>,
pub(crate) backend: Option<String>,
pub(crate) audio_device: Option<String>,
Expand Down Expand Up @@ -641,6 +688,8 @@ pub(crate) fn get_internal_config(config: CliConfig) -> SpotifydConfig {
.unwrap_or(DeviceType::Speaker)
.to_string();

let dbus_type: DBusType = config.shared_config.dbus_type.unwrap_or(DBusType::Session);

let pid = config.pid.map(|f| {
f.into_os_string()
.into_string()
Expand Down Expand Up @@ -710,6 +759,7 @@ pub(crate) fn get_internal_config(config: CliConfig) -> SpotifydConfig {
password,
use_keyring: config.shared_config.use_keyring,
use_mpris: config.shared_config.use_mpris.unwrap_or(true),
dbus_type,
cache,
backend: Some(backend),
audio_device: config.shared_config.device,
Expand Down
26 changes: 21 additions & 5 deletions src/dbus_mpris.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::config::DBusType;
use chrono::prelude::*;
use dbus::arg::{RefArg, Variant};
use dbus::channel::MatchingReceiver;
Expand Down Expand Up @@ -25,6 +26,7 @@ use std::{collections::HashMap, env};
pub struct DbusServer {
session: Session,
spirc: Arc<Spirc>,
dbus_type: DBusType,
api_token: RspotifyToken,
#[allow(clippy::type_complexity)]
token_request: Option<Pin<Box<dyn Future<Output = Result<LibrespotToken, MercuryError>>>>>,
Expand All @@ -41,10 +43,16 @@ const SCOPE: &str = "user-read-playback-state,user-read-private,\
user-read-recently-played";

impl DbusServer {
pub fn new(session: Session, spirc: Arc<Spirc>, device_name: String) -> DbusServer {
pub fn new(
session: Session,
spirc: Arc<Spirc>,
device_name: String,
dbus_type: DBusType,
) -> DbusServer {
DbusServer {
session,
spirc,
dbus_type,
api_token: RspotifyToken::default(),
token_request: None,
dbus_future: None,
Expand Down Expand Up @@ -77,6 +85,7 @@ impl Future for DbusServer {
self.api_token.clone(),
self.spirc.clone(),
self.device_name.clone(),
self.dbus_type,
)));
// TODO: for reasons I don't _entirely_ understand, the token request completing
// convinces callers that they don't need to re-check the status of this future
Expand Down Expand Up @@ -110,10 +119,17 @@ fn create_spotify_api(token: &RspotifyToken) -> Spotify {
Spotify::default().access_token(&token.access_token).build()
}

async fn create_dbus_server(api_token: RspotifyToken, spirc: Arc<Spirc>, device_name: String) {
// TODO: allow other DBus types through CLI and config entry.
let (resource, conn) =
connection::new_session_sync().expect("Failed to initialize DBus connection");
async fn create_dbus_server(
api_token: RspotifyToken,
spirc: Arc<Spirc>,
device_name: String,
dbus_type: DBusType,
) {
let (resource, conn) = match dbus_type {
DBusType::Session => connection::new_session_sync(),
DBusType::System => connection::new_system_sync(),
}
.expect("Failed to initialize DBus connection");
tokio::spawn(async {
let err = resource.await;
panic!("Lost connection to D-Bus: {}", err);
Expand Down
12 changes: 11 additions & 1 deletion src/main_loop.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::config::DBusType;
#[cfg(feature = "dbus_mpris")]
use crate::dbus_mpris::DbusServer;
use crate::process::{spawn_program_on_event, Child};
Expand Down Expand Up @@ -67,15 +68,22 @@ fn new_dbus_server(
session: Session,
spirc: Arc<Spirc>,
device_name: String,
dbus_type: DBusType,
) -> Option<Pin<Box<dyn Future<Output = ()>>>> {
Some(Box::pin(DbusServer::new(session, spirc, device_name)))
Some(Box::pin(DbusServer::new(
session,
spirc,
device_name,
dbus_type,
)))
}

#[cfg(not(feature = "dbus_mpris"))]
fn new_dbus_server(
_: Session,
_: Arc<Spirc>,
_: String,
_: DBusType,
) -> Option<Pin<Box<dyn Future<Output = ()>>>> {
None
}
Expand All @@ -93,6 +101,7 @@ pub(crate) struct MainLoopState {
pub(crate) shell: String,
pub(crate) device_type: DeviceType,
pub(crate) use_mpris: bool,
pub(crate) dbus_type: DBusType,
}

impl Future for MainLoopState {
Expand Down Expand Up @@ -184,6 +193,7 @@ impl Future for MainLoopState {
session,
shared_spirc,
self.spotifyd_state.device_name.clone(),
self.dbus_type,
);
}
} else if self
Expand Down
1 change: 1 addition & 0 deletions src/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pub(crate) fn initial_state(config: config::SpotifydConfig) -> main_loop::MainLo
device_type,
autoplay,
use_mpris: config.use_mpris,
dbus_type: config.dbus_type,
}
}

Expand Down

0 comments on commit 453dcd2

Please sign in to comment.