Created
June 9, 2018 21:51
-
-
Save emmanuelrosa/352caf7de134b3f5a67697ecdb6d13f0 to your computer and use it in GitHub Desktop.
WIP code for a NixOS MPD (Music Player Daemon) module which supports systemd user services.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ config, lib, pkgs, ... }: | |
with lib; | |
let | |
name = "mpd"; | |
uid = config.ids.uids.mpd; | |
gid = config.ids.gids.mpd; | |
cfg = config.services.mpd; | |
mpdConf = pkgs.writeText "mpd.conf" '' | |
music_directory "${cfg.musicDirectory}" | |
playlist_directory "${cfg.playlistDirectory}" | |
db_file "${cfg.dbFile}" | |
state_file "${cfg.dataDir}/state" | |
sticker_file "${cfg.dataDir}/sticker.sql" | |
log_file "syslog" | |
${optionalString cfg.systemWide ''user "${cfg.user}"''} | |
${optionalString cfg.systemWide ''group "${cfg.group}"''} | |
${optionalString (cfg.network.listenAddress != "any") ''bind_to_address "${cfg.network.listenAddress}"''} | |
${optionalString (cfg.network.port != 6600) ''port "${toString cfg.network.port}"''} | |
${cfg.extraConfig} | |
''; | |
socket = { | |
description = "Music Player Daemon Socket"; | |
wantedBy = [ "sockets.target" ]; | |
listenStreams = [ | |
"${optionalString (cfg.network.listenAddress != "any") "${cfg.network.listenAddress}:"}${toString cfg.network.port}" | |
]; | |
socketConfig = { | |
Backlog = 5; | |
KeepAlive = true; | |
PassCredentials = true; | |
}; | |
}; | |
service = { | |
after = [ "network.target" "sound.target" ]; | |
description = "Music Player Daemon"; | |
wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target"; | |
preStart = if cfg.systemWide then '' | |
mkdir -p "${cfg.dataDir}" && chown -R ${cfg.user}:${cfg.group} "${cfg.dataDir}" | |
mkdir -p "${cfg.playlistDirectory}" && chown -R ${cfg.user}:${cfg.group} "${cfg.playlistDirectory}" | |
'' else '' | |
mkdir -p "${cfg.dataDir}" | |
mkdir -p "${cfg.musicDirectory}" | |
mkdir -p "${cfg.playlistDirectory}" | |
''; | |
serviceConfig = { | |
User = mkIf cfg.systemWide "${cfg.user}"; | |
PermissionsStartOnly = true; | |
ExecStart = "${pkgs.mpd}/bin/mpd --no-daemon ${mpdConf}"; | |
Type = "notify"; | |
LimitRTPRIO = 50; | |
LimitRTTIME = "infinity"; | |
ProtectSystem = true; | |
NoNewPrivileges = true; | |
ProtectKernelTunables = true; | |
ProtectControlGroups = true; | |
ProtectKernelModules = if cfg.systemWide then true else false; | |
RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX AF_NETLINK"; | |
RestrictNamespaces = true; | |
}; | |
}; | |
in { | |
###### interface | |
options = { | |
services.mpd = { | |
enable = mkOption { | |
type = types.bool; | |
default = false; | |
description = '' | |
Whether to enable MPD, the music player daemon. | |
''; | |
}; | |
startWhenNeeded = mkOption { | |
type = types.bool; | |
default = false; | |
description = '' | |
If set, <command>mpd</command> is socket-activated; that | |
is, instead of having it permanently running as a daemon, | |
systemd will start it on the first incoming connection. | |
''; | |
}; | |
musicDirectory = mkOption { | |
type = types.str; | |
default = "${cfg.dataDir}/music"; | |
defaultText = ''''${dataDir}/music''; | |
description = '' | |
The directory where mpd reads music from. | |
''; | |
}; | |
playlistDirectory = mkOption { | |
type = types.str; | |
default = "${cfg.dataDir}/playlists"; | |
defaultText = ''''${dataDir}/playlists''; | |
description = '' | |
The directory where mpd stores playlists. | |
''; | |
}; | |
extraConfig = mkOption { | |
type = types.lines; | |
default = ""; | |
description = '' | |
Extra directives added to to the end of MPD's configuration file, | |
mpd.conf. Basic configuration like file location and uid/gid | |
is added automatically to the beginning of the file. For available | |
options see <literal>man 5 mpd.conf</literal>'. | |
''; | |
}; | |
dataDir = mkOption { | |
type = types.str; | |
default = "/var/lib/${name}"; | |
description = '' | |
The directory where MPD stores its state, tag cache, | |
playlists etc. | |
''; | |
}; | |
user = mkOption { | |
type = types.str; | |
default = name; | |
description = "User account under which MPD runs."; | |
}; | |
group = mkOption { | |
type = types.str; | |
default = name; | |
description = "Group account under which MPD runs."; | |
}; | |
network = { | |
listenAddress = mkOption { | |
type = types.str; | |
default = "127.0.0.1"; | |
example = "any"; | |
description = '' | |
The address for the daemon to listen on. | |
Use <literal>any</literal> to listen on all addresses. | |
''; | |
}; | |
port = mkOption { | |
type = types.int; | |
default = 6600; | |
description = '' | |
This setting is the TCP port that is desired for the daemon to get assigned | |
to. | |
''; | |
}; | |
}; | |
dbFile = mkOption { | |
type = types.str; | |
default = "${cfg.dataDir}/tag_cache"; | |
defaultText = ''''${dataDir}/tag_cache''; | |
description = '' | |
The path to MPD's database. | |
''; | |
}; | |
systemWide = mkOption { | |
type = types.bool; | |
default = true; | |
description = '' | |
If true, MPD is launched as a systemd service in the "system" slice; | |
This is the default behavior (for backwards compatability). | |
If false, MPD is launched as a systemd user service. | |
When using PulseAudio, this setting should be the same as | |
hardware.pulseaudio.systemWide. | |
''; | |
}; | |
}; | |
}; | |
###### implementation | |
config = mkIf cfg.enable { | |
systemd.sockets.mpd = mkIf (cfg.startWhenNeeded && cfg.systemWide) socket; | |
systemd.user.sockets.mpd = mkIf (cfg.startWhenNeeded && !cfg.systemWide) socket; | |
systemd.services.mpd = mkIf cfg.systemWide service; | |
systemd.user.services.mpd = mkIf (!cfg.systemWide) service; | |
users.extraUsers = optionalAttrs (cfg.user == name && cfg.systemWide) (singleton { | |
inherit uid; | |
inherit name; | |
group = cfg.group; | |
extraGroups = [ "audio" ]; | |
description = "Music Player Daemon user"; | |
home = "${cfg.dataDir}"; | |
}); | |
users.extraGroups = optionalAttrs (cfg.group == name && cfg.systemWide) (singleton { | |
inherit name; | |
gid = gid; | |
}); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment