services: Add mympd-service-type.
* gnu/services/audio.scm (mympd-service-type): New variable. * gnu/tests/audio.scm (%test-mympd): New variable. * doc/guix.texi: Document it. Signed-off-by: Liliana Marie Prikler <liliana.prikler@gmail.com>master
parent
637a9c3b26
commit
139c9a53cb
120
doc/guix.texi
120
doc/guix.texi
|
@ -113,6 +113,7 @@ Copyright @copyright{} 2022 Bruno Victal@*
|
|||
Copyright @copyright{} 2022 Ivan Vilata-i-Balaguer@*
|
||||
Copyright @copyright{} 2023 Giacomo Leidi@*
|
||||
Copyright @copyright{} 2022 Antero Mejr@*
|
||||
Copyright @copyright{} 2022 Bruno Victal@*
|
||||
|
||||
Permission is granted to copy, distribute and/or modify this document
|
||||
under the terms of the GNU Free Documentation License, Version 1.3 or
|
||||
|
@ -33396,6 +33397,125 @@ configures some of its plugins and provides a HTTP audio streaming output.
|
|||
(extra-options `((type . 0)))))))
|
||||
@end lisp
|
||||
|
||||
@subsubheading myMPD
|
||||
|
||||
@cindex MPD, web interface
|
||||
@cindex myMPD service
|
||||
|
||||
@uref{https://jcorporation.github.io/myMPD/, myMPD} is a web server
|
||||
frontend for MPD that provides a mobile friendly web client for MPD.
|
||||
|
||||
The following example shows a myMPD instance listening on port 80,
|
||||
with album cover caching disabled.
|
||||
|
||||
@lisp
|
||||
(service mympd-service-type
|
||||
(mympd-configuration
|
||||
(port 80)
|
||||
(covercache-ttl 0)))
|
||||
@end lisp
|
||||
|
||||
@defvar mympd-service-type
|
||||
The service type for @command{mympd}.
|
||||
@end defvar
|
||||
|
||||
@c %start of fragment
|
||||
@deftp {Data Type} mympd-configuration
|
||||
Available @code{mympd-configuration} fields are:
|
||||
|
||||
@table @asis
|
||||
@item @code{package} (default: @code{mympd}) (type: file-like)
|
||||
The package object of the myMPD server.
|
||||
|
||||
@item @code{shepherd-requirement} (default: @code{()}) (type: list-of-symbol)
|
||||
This is a list of symbols naming Shepherd services that this service
|
||||
will depend on.
|
||||
|
||||
@item @code{user} (default: @code{"mympd"}) (type: string)
|
||||
Owner of the @command{mympd} process.
|
||||
|
||||
@item @code{group} (default: @code{"nogroup"}) (type: string)
|
||||
Owner group of the @command{mympd} process.
|
||||
|
||||
@item @code{work-directory} (default: @code{"/var/lib/mympd"}) (type: string)
|
||||
Where myMPD will store its data.
|
||||
|
||||
@item @code{cache-directory} (default: @code{"/var/cache/mympd"}) (type: string)
|
||||
Where myMPD will store its cache.
|
||||
|
||||
@item @code{acl} (type: maybe-mympd-ip-acl)
|
||||
ACL to access the myMPD webserver.
|
||||
|
||||
@item @code{covercache-ttl} (default: @code{31}) (type: maybe-integer)
|
||||
How long to keep cached covers, @code{0} disables cover caching.
|
||||
|
||||
@item @code{http?} (default: @code{#t}) (type: boolean)
|
||||
HTTP support.
|
||||
|
||||
@item @code{host} (default: @code{"[::]"}) (type: string)
|
||||
Host name to listen on.
|
||||
|
||||
@item @code{port} (default: @code{80}) (type: maybe-port)
|
||||
HTTP port to listen on.
|
||||
|
||||
@item @code{log-level} (default: @code{5}) (type: integer)
|
||||
How much detail to include in logs, possible values: @code{0} to
|
||||
@code{7}.
|
||||
|
||||
@item @code{log-to} (default: @code{"/var/log/mympd/log"}) (type: string-or-symbol)
|
||||
Where to send logs. By default, the service logs to
|
||||
@file{/var/log/mympd.log}. The alternative is @code{'syslog}, which
|
||||
sends output to the running syslog service under the @samp{daemon}
|
||||
facility.
|
||||
|
||||
@item @code{lualibs} (default: @code{"all"}) (type: maybe-string)
|
||||
See
|
||||
@uref{https://jcorporation.github.io/myMPD/scripting/#lua-standard-libraries}.
|
||||
|
||||
@item @code{uri} (type: maybe-string)
|
||||
Override URI to myMPD. See
|
||||
@uref{https://github.com/jcorporation/myMPD/issues/950}.
|
||||
|
||||
@item @code{script-acl} (default: @code{(mympd-ip-acl (allow '("127.0.0.1")))}) (type: maybe-mympd-ip-acl)
|
||||
ACL to access the myMPD script backend.
|
||||
|
||||
@item @code{ssl?} (default: @code{#f}) (type: boolean)
|
||||
SSL/TLS support.
|
||||
|
||||
@item @code{ssl-port} (default: @code{443}) (type: maybe-port)
|
||||
Port to listen for HTTPS.
|
||||
|
||||
@item @code{ssl-cert} (type: maybe-string)
|
||||
Path to PEM encoded X.509 SSL/TLS certificate (public key).
|
||||
|
||||
@item @code{ssl-key} (type: maybe-string)
|
||||
Path to PEM encoded SSL/TLS private key.
|
||||
|
||||
@item @code{pin-hash} (type: maybe-string)
|
||||
SHA-256 hashed pin used by myMPD to control settings access by prompting
|
||||
a pin from the user.
|
||||
|
||||
@item @code{save-caches?} (type: maybe-boolean)
|
||||
Whether to preserve caches between service restarts.
|
||||
|
||||
@end table
|
||||
@end deftp
|
||||
@c %end of fragment
|
||||
|
||||
@c %start of fragment
|
||||
@deftp {Data Type} mympd-ip-acl
|
||||
Available @code{mympd-ip-acl} fields are:
|
||||
|
||||
@table @asis
|
||||
@item @code{allow} (default: @code{()}) (type: list-of-string)
|
||||
Allowed IP addresses.
|
||||
|
||||
@item @code{deny} (default: @code{()}) (type: list-of-string)
|
||||
Disallowed IP addresses.
|
||||
|
||||
@end table
|
||||
@end deftp
|
||||
@c %end of fragment
|
||||
|
||||
@node Virtualization Services
|
||||
@subsection Virtualization Services
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#:use-module (guix diagnostics)
|
||||
#:use-module (guix i18n)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services admin)
|
||||
#:use-module (gnu services configuration)
|
||||
#:use-module (gnu services shepherd)
|
||||
#:use-module (gnu services admin)
|
||||
|
@ -32,6 +33,7 @@
|
|||
#:use-module (gnu packages admin)
|
||||
#:use-module (gnu packages mpd)
|
||||
#:use-module (guix records)
|
||||
#:use-module (ice-9 format)
|
||||
#:use-module (ice-9 match)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-26)
|
||||
|
@ -90,7 +92,37 @@
|
|||
mpd-configuration-outputs
|
||||
mpd-configuration-playlist-plugins
|
||||
mpd-configuration-extra-options
|
||||
mpd-service-type))
|
||||
mpd-service-type
|
||||
|
||||
mympd-service-type
|
||||
mympd-configuration
|
||||
mympd-configuration?
|
||||
mympd-configuration-package
|
||||
mympd-configuration-shepherd-requirement
|
||||
mympd-configuration-user
|
||||
mympd-configuration-group
|
||||
mympd-configuration-work-directory
|
||||
mympd-configuration-cache-directory
|
||||
mympd-configuration-acl
|
||||
mympd-configuration-covercache-ttl
|
||||
mympd-configuration-http?
|
||||
mympd-configuration-host
|
||||
mympd-configuration-port
|
||||
mympd-configuration-log-level
|
||||
mympd-configuration-log-to
|
||||
mympd-configuration-lualibs
|
||||
mympd-configuration-uri
|
||||
mympd-configuration-script-acl
|
||||
mympd-configuration-ssl?
|
||||
mympd-configuration-ssl-port
|
||||
mympd-configuration-ssl-cert
|
||||
mympd-configuration-ssl-key
|
||||
mympd-configuration-pin-hash
|
||||
mympd-configuration-save-caches?
|
||||
mympd-ip-acl
|
||||
mympd-ip-acl?
|
||||
mympd-ip-acl-allow
|
||||
mympd-ip-acl-deny))
|
||||
|
||||
;;; Commentary:
|
||||
;;;
|
||||
|
@ -538,3 +570,238 @@ appended to the configuration.")
|
|||
(service-extension rottlog-service-type
|
||||
(compose list mpd-log-rotation))))
|
||||
(default-value (mpd-configuration))))
|
||||
|
||||
|
||||
;;;
|
||||
;;; myMPD
|
||||
;;;
|
||||
|
||||
(define (string-or-symbol? x)
|
||||
(or (symbol? x) (string? x)))
|
||||
|
||||
(define-configuration/no-serialization mympd-ip-acl
|
||||
(allow
|
||||
(list-of-string '())
|
||||
"Allowed IP addresses.")
|
||||
|
||||
(deny
|
||||
(list-of-string '())
|
||||
"Disallowed IP addresses."))
|
||||
|
||||
(define-maybe/no-serialization integer)
|
||||
(define-maybe/no-serialization mympd-ip-acl)
|
||||
|
||||
;; XXX: The serialization procedures are insufficient since we require
|
||||
;; access to multiple fields at once.
|
||||
;; Fields marked with empty-serializer are never serialized and are
|
||||
;; used for command-line arguments or by the service definition.
|
||||
(define-configuration/no-serialization mympd-configuration
|
||||
(package
|
||||
(file-like mympd)
|
||||
"The package object of the myMPD server."
|
||||
empty-serializer)
|
||||
|
||||
(shepherd-requirement
|
||||
(list-of-symbol '())
|
||||
"This is a list of symbols naming Shepherd services that this service
|
||||
will depend on."
|
||||
empty-serializer)
|
||||
|
||||
(user
|
||||
(string "mympd")
|
||||
"Owner of the @command{mympd} process."
|
||||
empty-serializer)
|
||||
|
||||
(group
|
||||
(string "nogroup")
|
||||
"Owner group of the @command{mympd} process."
|
||||
empty-serializer)
|
||||
|
||||
(work-directory
|
||||
(string "/var/lib/mympd")
|
||||
"Where myMPD will store its data."
|
||||
empty-serializer)
|
||||
|
||||
(cache-directory
|
||||
(string "/var/cache/mympd")
|
||||
"Where myMPD will store its cache."
|
||||
empty-serializer)
|
||||
|
||||
(acl
|
||||
maybe-mympd-ip-acl
|
||||
"ACL to access the myMPD webserver.")
|
||||
|
||||
(covercache-ttl
|
||||
(maybe-integer 31)
|
||||
"How long to keep cached covers, @code{0} disables cover caching.")
|
||||
|
||||
(http?
|
||||
(boolean #t)
|
||||
"HTTP support.")
|
||||
|
||||
(host
|
||||
(string "[::]")
|
||||
"Host name to listen on.")
|
||||
|
||||
(port
|
||||
(maybe-port 80)
|
||||
"HTTP port to listen on.")
|
||||
|
||||
(log-level
|
||||
(integer 5)
|
||||
"How much detail to include in logs, possible values: @code{0} to @code{7}.")
|
||||
|
||||
(log-to
|
||||
(string-or-symbol "/var/log/mympd/log")
|
||||
"Where to send logs. By default, the service logs to
|
||||
@file{/var/log/mympd.log}. The alternative is @code{'syslog}, which
|
||||
sends output to the running syslog service under the @samp{daemon} facility."
|
||||
empty-serializer)
|
||||
|
||||
(lualibs
|
||||
(maybe-string "all")
|
||||
"See
|
||||
@url{https://jcorporation.github.io/myMPD/scripting/#lua-standard-libraries}.")
|
||||
|
||||
(uri
|
||||
maybe-string
|
||||
"Override URI to myMPD.
|
||||
See @url{https://github.com/jcorporation/myMPD/issues/950}.")
|
||||
|
||||
(script-acl
|
||||
(maybe-mympd-ip-acl (mympd-ip-acl
|
||||
(allow '("127.0.0.1"))))
|
||||
"ACL to access the myMPD script backend.")
|
||||
|
||||
(ssl?
|
||||
(boolean #f)
|
||||
"SSL/TLS support.")
|
||||
|
||||
(ssl-port
|
||||
(maybe-port 443)
|
||||
"Port to listen for HTTPS.")
|
||||
|
||||
(ssl-cert
|
||||
maybe-string
|
||||
"Path to PEM encoded X.509 SSL/TLS certificate (public key).")
|
||||
|
||||
(ssl-key
|
||||
maybe-string
|
||||
"Path to PEM encoded SSL/TLS private key.")
|
||||
|
||||
(pin-hash
|
||||
maybe-string
|
||||
"SHA-256 hashed pin used by myMPD to control settings access by
|
||||
prompting a pin from the user.")
|
||||
|
||||
(save-caches?
|
||||
maybe-boolean
|
||||
"Whether to preserve caches between service restarts."))
|
||||
|
||||
(define (mympd-serialize-configuration config)
|
||||
(define serialize-value
|
||||
(match-lambda
|
||||
((? boolean? val) (if val "true" "false"))
|
||||
((? integer? val) (number->string val))
|
||||
((? mympd-ip-acl? val) (ip-acl-serialize-configuration val))
|
||||
((? string? val) val)))
|
||||
|
||||
(define (ip-acl-serialize-configuration config)
|
||||
(define (serialize-list-of-string prefix lst)
|
||||
(map (cut format #f "~a~a" prefix <>) lst))
|
||||
(string-join
|
||||
(append
|
||||
(serialize-list-of-string "+" (mympd-ip-acl-allow config))
|
||||
(serialize-list-of-string "-" (mympd-ip-acl-deny config))) ","))
|
||||
|
||||
;; myMPD configuration fields are serialized as individual files under
|
||||
;; <work-directory>/config/.
|
||||
(match-record config <mympd-configuration> (work-directory acl
|
||||
covercache-ttl http? host port
|
||||
log-level lualibs uri script-acl
|
||||
ssl? ssl-port ssl-cert ssl-key
|
||||
pin-hash save-caches?)
|
||||
(define (serialize-field filename value)
|
||||
(when (maybe-value-set? value)
|
||||
(list (format #f "~a/config/~a" work-directory filename)
|
||||
(mixed-text-file filename (serialize-value value)))))
|
||||
|
||||
(let ((filename-to-field `(("acl" . ,acl)
|
||||
("covercache_keep_days" . ,covercache-ttl)
|
||||
("http" . ,http?)
|
||||
("http_host" . ,host)
|
||||
("http_port" . ,port)
|
||||
("loglevel" . ,log-level)
|
||||
("lualibs" . ,lualibs)
|
||||
("mympd_uri" . ,uri)
|
||||
("scriptacl" . ,script-acl)
|
||||
("ssl" . ,ssl?)
|
||||
("ssl_port" . ,ssl-port)
|
||||
("ssl_cert" . ,ssl-cert)
|
||||
("ssl_key" . ,ssl-key)
|
||||
("pin_hash" . ,pin-hash)
|
||||
("save_caches" . ,save-caches?))))
|
||||
(filter list?
|
||||
(generic-serialize-alist list serialize-field
|
||||
filename-to-field)))))
|
||||
|
||||
(define (mympd-shepherd-service config)
|
||||
(match-record config <mympd-configuration> (package shepherd-requirement
|
||||
user work-directory
|
||||
cache-directory log-level log-to)
|
||||
(let ((log-level* (format #f "MYMPD_LOGLEVEL=~a" log-level)))
|
||||
(shepherd-service
|
||||
(documentation "Run the myMPD daemon.")
|
||||
(requirement `(loopback user-processes ,@shepherd-requirement))
|
||||
(provision '(mympd))
|
||||
(start #~(begin
|
||||
(let* ((pw (getpwnam #$user))
|
||||
(uid (passwd:uid pw))
|
||||
(gid (passwd:gid pw)))
|
||||
(for-each (lambda (dir)
|
||||
(mkdir-p dir)
|
||||
(chown dir uid gid))
|
||||
(list #$work-directory #$cache-directory)))
|
||||
|
||||
(make-forkexec-constructor
|
||||
`(#$(file-append package "/bin/mympd")
|
||||
"--user" #$user
|
||||
#$@(if (eqv? log-to 'syslog) '("--syslog") '())
|
||||
"--workdir" #$work-directory
|
||||
"--cachedir" #$cache-directory)
|
||||
#:environment-variables (list #$log-level*)
|
||||
#:log-file #$(if (string? log-to) log-to #f))))
|
||||
(stop #~(make-kill-destructor))))))
|
||||
|
||||
(define (mympd-accounts config)
|
||||
(match-record config <mympd-configuration> (user group)
|
||||
(list (user-group (name group)
|
||||
(system? #t))
|
||||
(user-account (name user)
|
||||
(group group)
|
||||
(system? #t)
|
||||
(comment "myMPD user")
|
||||
(home-directory "/var/empty")
|
||||
(shell (file-append shadow "/sbin/nologin"))))))
|
||||
|
||||
(define (mympd-log-rotation config)
|
||||
(match-record config <mympd-configuration> (log-to)
|
||||
(if (string? log-to)
|
||||
(list (log-rotation
|
||||
(files (list log-to))))
|
||||
'())))
|
||||
|
||||
(define mympd-service-type
|
||||
(service-type
|
||||
(name 'mympd)
|
||||
(extensions
|
||||
(list (service-extension shepherd-root-service-type
|
||||
(compose list mympd-shepherd-service))
|
||||
(service-extension account-service-type
|
||||
mympd-accounts)
|
||||
(service-extension special-files-service-type
|
||||
mympd-serialize-configuration)
|
||||
(service-extension rottlog-service-type
|
||||
mympd-log-rotation)))
|
||||
(description "Run myMPD, a frontend for MPD. (Music Player Daemon)")
|
||||
(default-value (mympd-configuration))))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2017 Peter Mikkelsen <petermikkelsen10@gmail.com>
|
||||
;;; Copyright © 2022 Bruno Victal <mirai@makinata.eu>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
|
@ -22,9 +23,11 @@
|
|||
#:use-module (gnu system vm)
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services audio)
|
||||
#:use-module (gnu services networking)
|
||||
#:use-module (gnu packages mpd)
|
||||
#:use-module (guix gexp)
|
||||
#:export (%test-mpd))
|
||||
#:export (%test-mpd
|
||||
%test-mympd))
|
||||
|
||||
(define %mpd-os
|
||||
(simple-operating-system
|
||||
|
@ -76,3 +79,51 @@
|
|||
(name "mpd")
|
||||
(description "Test that the mpd can run and be connected to.")
|
||||
(value (run-mpd-test))))
|
||||
|
||||
(define (run-mympd-test)
|
||||
(define os (marionette-operating-system
|
||||
(simple-operating-system (service dhcp-client-service-type)
|
||||
(service mympd-service-type))
|
||||
#:imported-modules '((gnu services herd))))
|
||||
|
||||
(define vm
|
||||
(virtual-machine
|
||||
(operating-system os)
|
||||
(port-forwardings '((8080 . 80)))))
|
||||
|
||||
(define test
|
||||
(with-imported-modules '((gnu build marionette))
|
||||
#~(begin
|
||||
(use-modules (srfi srfi-64)
|
||||
(srfi srfi-8)
|
||||
(web client)
|
||||
(web response)
|
||||
(gnu build marionette))
|
||||
|
||||
(define marionette
|
||||
(make-marionette (list #$vm)))
|
||||
|
||||
(test-runner-current (system-test-runner #$output))
|
||||
(test-begin "mympd")
|
||||
(test-assert "service is running"
|
||||
(marionette-eval '(begin
|
||||
(use-modules (gnu services herd))
|
||||
|
||||
(start-service 'mympd))
|
||||
marionette))
|
||||
|
||||
(test-assert "HTTP port ready"
|
||||
(wait-for-tcp-port 80 marionette))
|
||||
|
||||
(test-equal "http-head"
|
||||
200
|
||||
(receive (x _) (http-head "http://localhost:8080") (response-code x)))
|
||||
|
||||
(test-end))))
|
||||
(gexp->derivation "mympd-test" test))
|
||||
|
||||
(define %test-mympd
|
||||
(system-test
|
||||
(name "mympd")
|
||||
(description "Connect to a running myMPD service.")
|
||||
(value (run-mympd-test))))
|
||||
|
|
Reference in New Issue