Add runtime status checker + headless/X11 docs; distro-support refinements

- status.sh: runtime health check (service state, boot wiring, display backend auto-detect, encoder, ports, web UI, /dev/uinput, pairing) ending in a g2g verdict or concrete TODO list

- docs: TROUBLESHOOTING §12 (headless graphical-session.target boot trap) + §13 (X11/NVENC path & stale wlr drop-in env conflict); ARCHITECTURE capture-backend comparison; FOLLOWUPS P3 (installer X11/Ubuntu support); README diagnostics pointer

- lib/{config,packages,permissions,service}.sh, files/sway-headless.service: in-progress Debian/Ubuntu + headless support refinements

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 22:57:03 +00:00
parent ee1379d5be
commit ab23107300
10 changed files with 623 additions and 38 deletions

View File

@@ -4,23 +4,46 @@
# Sway-headless capture path, also installs + enables sway-headless.service
# and wires sunshine.service to depend on it.
# Resolves the actual unit file to operate on. Exports:
# SUNSHINE_ENABLE_NAME - the name to pass to `systemctl --user enable`. May
# be sunshine.service or app-dev.lizardbyte....service
# depending on how the package shipped the unit.
# SUNSHINE_SERVICE - the short name we use everywhere else (start, restart,
# status, drop-ins). Always sunshine.service — systemd
# resolves it via Alias= or our installed unit.
ensure_sunshine_unit_present() {
# Case 1: a sunshine.service unit already exists in any path systemd-user
# scans. The LizardByte .deb on Ubuntu drops it at /lib/systemd/user/.
# sunshine-bin on Arch drops it at /usr/lib/systemd/user/.
SUNSHINE_SERVICE="sunshine.service"
# Clean up a broken symlink from older runs that pointed sunshine.service
# at the FQDN unit. The upstream .deb already declares Alias=sunshine.service
# in [Install], so the symlink we used to create conflicts with systemd's
# enable path ("Refusing to operate on alias name").
local user_unit="$HOME/.config/systemd/user/sunshine.service"
if [[ -L "$user_unit" ]] && readlink "$user_unit" 2>/dev/null \
| grep -q 'app-dev.lizardbyte.app.Sunshine.service$'; then
info "Removing stale alias symlink at $user_unit (upstream unit declares Alias=)"
rm -f "$user_unit"
fi
# Case 1: a real sunshine.service unit ships in a system path (sunshine-bin
# on Arch drops it at /usr/lib/systemd/user/).
for p in \
/lib/systemd/user/sunshine.service \
/usr/lib/systemd/user/sunshine.service \
/etc/systemd/user/sunshine.service \
"$HOME/.config/systemd/user/sunshine.service" \
"$HOME/.local/share/systemd/user/sunshine.service"
do
[[ -e "$p" ]] && return 0
if [[ -f "$p" && ! -L "$p" ]]; then
SUNSHINE_ENABLE_NAME="sunshine.service"
export SUNSHINE_ENABLE_NAME SUNSHINE_SERVICE
return 0
fi
done
# Case 2: the AUR source 'sunshine' package ships the unit under a
# Flatpak-style reverse-DNS name. Symlink it as sunshine.service so the rest
# of our tooling can keep using the short name.
# Case 2: the LizardByte .deb (Ubuntu) and the AUR source package ship the
# unit under a reverse-DNS FQDN with Alias=sunshine.service in [Install].
# Do NOT symlink — `systemctl --user enable` on the FQDN name creates the
# alias symlink itself in ~/.config/systemd/user/.
local fqdn_unit=""
for p in \
/usr/lib/systemd/user/app-dev.lizardbyte.app.Sunshine.service \
@@ -30,10 +53,9 @@ ensure_sunshine_unit_present() {
[[ -f "$p" ]] && { fqdn_unit="$p"; break; }
done
if [[ -n "$fqdn_unit" ]]; then
info "Found packaged unit at $fqdn_unit"
info "Aliasing it as sunshine.service in $HOME/.config/systemd/user/"
mkdir -p "$HOME/.config/systemd/user"
ln -sf "$fqdn_unit" "$HOME/.config/systemd/user/sunshine.service"
info "Found packaged unit at $fqdn_unit (enables via alias)"
SUNSHINE_ENABLE_NAME="app-dev.lizardbyte.app.Sunshine.service"
export SUNSHINE_ENABLE_NAME SUNSHINE_SERVICE
return 0
fi
@@ -47,6 +69,8 @@ ensure_sunshine_unit_present() {
mkdir -p "$HOME/.config/systemd/user"
install -m 0644 "$fallback" "$HOME/.config/systemd/user/sunshine.service"
ok "Installed $HOME/.config/systemd/user/sunshine.service"
SUNSHINE_ENABLE_NAME="sunshine.service"
export SUNSHINE_ENABLE_NAME SUNSHINE_SERVICE
}
# Install and enable the headless sway compositor unit + config (Debian/Ubuntu
@@ -114,8 +138,8 @@ enable_sunshine_service() {
install_headless_prestart_dropin
fi
if ! systemctl --user list-unit-files sunshine.service >/dev/null 2>&1; then
err "sunshine.service still not found after fallback. Inspect: find /usr /lib ~/.config -name sunshine.service"
if ! systemctl --user list-unit-files "$SUNSHINE_ENABLE_NAME" >/dev/null 2>&1; then
err "$SUNSHINE_ENABLE_NAME not found after fallback. Inspect: find /usr /lib ~/.config -name '*[Ss]unshine*'"
return 1
fi
@@ -126,8 +150,8 @@ enable_sunshine_service() {
ok "User lingering already enabled"
fi
info "Enabling sunshine.service (user)"
systemctl --user enable sunshine.service >/dev/null
info "Enabling ${SUNSHINE_ENABLE_NAME} (user)"
systemctl --user enable "$SUNSHINE_ENABLE_NAME" >/dev/null
# Clear any prior start-limit state from a failed run so this attempt isn't
# immediately rejected with "Start request repeated too quickly."