ci / web (push) Successful in 1m3s
ci / docs-site (push) Successful in 2m11s
ci / rust-arm64 (push) Successful in 2m41s
docker / builders (--build-arg FEDORA_VERSION=44, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm, -f44) (push) Successful in 11s
docker / builders (ci/android-ci.Dockerfile, punktfunk-android-ci) (push) Successful in 11s
docker / builders (ci/arch-ci.Dockerfile, punktfunk-arch-ci) (push) Successful in 24s
deb / build-publish-client-arm64 (push) Successful in 2m28s
docker / builders (ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 8s
docker / builders (ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 7s
docker / builders (ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 7s
docker / apps (., web/Dockerfile, punktfunk-web) (push) Successful in 13s
apple / swift (push) Successful in 4m48s
docker / apps (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m36s
arch / build-publish (push) Successful in 7m20s
ci / rust (push) Successful in 7m21s
deb / build-publish-host (push) Successful in 7m4s
docker / builders-arm64cross (push) Successful in 8s
deb / build-publish (push) Successful in 5m31s
docker / deploy-docs (push) Successful in 34s
android / android (push) Successful in 8m17s
windows-host / package (push) Successful in 10m43s
windows-host / winget-source (push) Skipped
windows-host / canary-manifest (push) Successful in 18s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 16m40s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Failing after 17m31s
apple / screenshots (push) Successful in 20m57s
Fallout from the documentation sweep: verifying doc claims against the code
turned up defects in the code and the shipped templates. Mostly comments that
describe behaviour we no longer have — which is how the docs went wrong in the
first place, since someone reads the comment and writes the page.
The one that mattered: a fresh deb/RPM/Arch install could not start the host at
all. The unit's `EnvironmentFile=` had no `-`, making host.env mandatory, and no
package creates it — all three ship only the templates under /usr/share and the
postinst merely prints the copy command. So `systemctl --user enable --now
punktfunk-host` died on "Failed to load environment files". Every field in
HostConfig::from_env resolves through unwrap_or/filter/None, so absent means all
defaults, exactly like a hand-run `serve`; the Nix module already wrote it as
`-${environmentFile}`. The Deck installer's own generated unit gets the same
prefix for the case where an operator later removes the file.
Shipped templates: PUNKTFUNK_SECURE_DDA is read by nothing (DDA/WGC are gone;
IDD-push is the sole Windows capture path and the secure desktop is
unconditional), so it stops being written into a fresh host.env;
PUNKTFUNK_INPUT_BACKEND offered a `uinput` value that does not exist and omitted
`kwin`, which is what a KDE session actually resolves to; PUNKTFUNK_RENDER_ADAPTER
no longer claims to pick a "Desktop-Duplication" GPU.
Comments corrected rather than deleted, since each explains a real why:
PUNKTFUNK_10BIT is default-on with explicit-off grammar, not an operator opt-in;
GNOME reaches EIS through Mutter's direct RemoteDesktop API, so it needs no portal
approval and is headless-capable; and the host does not run in session 0 — the
service is the session-0 supervisor and the host runs as SYSTEM in the interactive
console session, which is why game_term has to bind the input desktop at all.
packaging/bazzite/update-punktfunk.sh is now installed to /usr/share/punktfunk/,
so the command the docs promised exists.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
61 lines
4.1 KiB
Desktop File
61 lines
4.1 KiB
Desktop File
# punktfunk streaming host — systemd USER unit (`serve --gamestream` = native punktfunk/1 + the
|
|
# GameStream/Moonlight-compat planes). For a SECURE native-only host (no plain-HTTP pairing / legacy
|
|
# GCM nonce reuse — security-review #5/#9; native clients only), drop `--gamestream` from ExecStart.
|
|
#
|
|
# Install (against an already-running compositor session — the host auto-detects and follows it,
|
|
# so host.env needs no backend config):
|
|
# mkdir -p ~/.config/systemd/user && cp scripts/punktfunk-host.service ~/.config/systemd/user/
|
|
# cp scripts/host.env.example ~/.config/punktfunk/host.env # defaults are right for a desktop
|
|
# systemctl --user daemon-reload && systemctl --user enable --now punktfunk-host
|
|
#
|
|
# On that desktop-login route, ALSO install scripts/punktfunk-host-desktop-session.conf as a drop-in:
|
|
# it binds the host to graphical-session.target, so a Plasma/GNOME restart restarts the host instead
|
|
# of leaving it holding a dead Wayland socket + portal connection (the PartOf= below only covers the
|
|
# appliance route, where we start the compositor ourselves). The drop-in's header has the commands.
|
|
#
|
|
# The host does NOT need the login shell's environment: it detects the live session itself per
|
|
# connect and derives WAYLAND_DISPLAY, XDG_RUNTIME_DIR, DBUS_SESSION_BUS_ADDRESS, XDG_CURRENT_DESKTOP,
|
|
# HYPRLAND_INSTANCE_SIGNATURE and SWAYSOCK from the running compositor (vdisplay::apply_session_env).
|
|
# So host.env carries policy, not session plumbing, and `systemctl --user import-environment` is not
|
|
# a prerequisite — the host pushes the live values into the manager env itself when a session switch
|
|
# needs the portal to re-read them.
|
|
#
|
|
# Self-contained boot appliance (no login, no manual steps after boot). These routes PIN the
|
|
# backend via PUNKTFUNK_COMPOSITOR — correct for a dedicated single-session box, but it turns off
|
|
# live-session auto-detection, so never do it on a desktop that switches sessions (Game Mode etc.):
|
|
# - kwin backend (stream the Plasma desktop): also install + enable
|
|
# punktfunk-kde-session.service (it brings up the headless KWin session this After=s), and use
|
|
# the shipped packaging/kde/host.env (pins kwin + WAYLAND_DISPLAY=wayland-kde on purpose).
|
|
# - gamescope backend (stream a nested app, no desktop): set PUNKTFUNK_COMPOSITOR=gamescope in
|
|
# host.env — the host spawns gamescope per session, so no kde-session unit is needed.
|
|
# Then `sudo loginctl enable-linger "$USER"` so user units start at boot, and reboot.
|
|
#
|
|
# The host LISTENS as soon as it starts and only touches the compositor per session (on a client
|
|
# connect), so the After= below is a soft ordering, not a hard readiness gate — the kde-session
|
|
# unit (when present) just needs to be up by the time a client streams (seconds later, user-driven).
|
|
# A missing After= unit (e.g. gamescope backend, no kde-session installed) is simply ignored.
|
|
[Unit]
|
|
Description=punktfunk GameStream + punktfunk/1 host
|
|
After=pipewire.service punktfunk-kde-session.service
|
|
# PartOf the kwin session (when present): the host's libei input uses the RemoteDesktop portal,
|
|
# whose D-Bus connection goes stale if the compositor session restarts the portal under it — the
|
|
# in-process reopen loop can't recover that, but a full restart re-establishes it. So restart the
|
|
# host whenever the kde-session restarts. Ignored when punktfunk-kde-session isn't installed
|
|
# (gamescope / other backends).
|
|
PartOf=punktfunk-kde-session.service
|
|
|
|
[Service]
|
|
# '-' optional: NO package creates this file — deb/RPM/Arch ship only host.env.* templates under
|
|
# /usr/share and the postinst merely prints the copy command — so a mandatory read would fail a
|
|
# fresh install outright ("Failed to load environment files"), before the host ever ran. Absent
|
|
# just means every knob at its default (pf-host-config has one for each), which is exactly what
|
|
# `punktfunk-host serve` by hand already does. Contrast punktfunk-web.service, which marks
|
|
# mgmt-token mandatory ON PURPOSE so Restart waits for the host to write it — this is not that.
|
|
EnvironmentFile=-%h/.config/punktfunk/host.env
|
|
ExecStart=%h/punktfunk/target/release/punktfunk-host serve --gamestream
|
|
Restart=on-failure
|
|
RestartSec=2
|
|
|
|
[Install]
|
|
WantedBy=default.target
|