feat(packaging): bundle the web console into the RPM / Arch / bootc host packages
ci / rust (push) Successful in 1m13s
android / android (push) Failing after 1m42s
ci / web (push) Successful in 27s
ci / bench (push) Successful in 1m50s
decky / build-publish (push) Successful in 11s
deb / build-publish (push) Failing after 2m38s
apple / swift (push) Successful in 54s
ci / docs-site (push) Successful in 32s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 2m57s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
flatpak / build-publish (push) Failing after 2s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 2m33s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 5m20s
docker / deploy-docs (push) Successful in 17s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 5m11s
ci / rust (push) Successful in 1m13s
android / android (push) Failing after 1m42s
ci / web (push) Successful in 27s
ci / bench (push) Successful in 1m50s
decky / build-publish (push) Successful in 11s
deb / build-publish (push) Failing after 2m38s
apple / swift (push) Successful in 54s
ci / docs-site (push) Successful in 32s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 2m57s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 4s
flatpak / build-publish (push) Failing after 2s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 2m33s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 5m20s
docker / deploy-docs (push) Successful in 17s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 5m11s
The punktfunk-web management console (pairing + status) shipped only via apt. Extend it to the other HOST packaging methods, mirroring the Debian punktfunk-web .deb (flatpak is the client, correctly excluded): - rpm/punktfunk.spec: new noarch `punktfunk-web` subpackage (the .output bundle + a /usr/bin/punktfunk-web-server node launcher + both systemd --user units + web-init.sh + web.env.example), gated behind `%bcond_with web`. OFF by default because building the Nitro/Node SSR bundle needs `bun`, which a plain rpmbuild / COPR mock chroot lacks. Host package weak-Recommends punktfunk-web. - ci/fedora-rpm.Dockerfile: install bun (+ unzip) so the CI builder can build the console. - rpm.yml: build `PF_WITH_WEB=1` (Prep bootstraps bun to stay green pre-image-rebuild); the publish loop already globs the new noarch rpm into the registry. build-rpm.sh: `--with web` when PF_WITH_WEB=1. - bootc/Containerfile: install from the Gitea RPM registry (which carries punktfunk-web) instead of COPR — `dnf5 install punktfunk punktfunk-web`. - arch/PKGBUILD: opt-in `punktfunk-web` split member (PF_WITH_WEB=1 appends it + bun) so a default makepkg still builds host+client with no JS tooling — matching the spec's bcond. - docs: packaging/README, rpm/README, copr/README (the no-bun caveat), bazzite/README (Path B rewritten COPR→Gitea registry), arch/README — enable + journal-password steps. Reviewed across methods by an adversarial multi-agent pass (rpm/ci/arch/bootc/consistency lenses, each blocking finding 3x-verified); fixed the two it confirmed real — the Arch bun-mandatory regression (now opt-in) and the stale COPR wording in bazzite Path B. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+12
-1
@@ -91,9 +91,20 @@ ujust add-user-to-input-group # virtual gamepads need /dev/uinput (the
|
||||
mkdir -p ~/.config/punktfunk
|
||||
cp /usr/share/punktfunk/host.env.bazzite ~/.config/punktfunk/host.env # edit (gamescope app, etc.)
|
||||
systemctl --user enable --now punktfunk-host
|
||||
|
||||
# Management web console (pairing + status) — pulled in by default (the host RPM Recommends it;
|
||||
# `--no-install-recommends` / headless-only boxes can skip it). Enable it and read the login password:
|
||||
systemctl --user enable --now punktfunk-web
|
||||
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' # then open http://<host-ip>:3000
|
||||
```
|
||||
|
||||
Pair a stock Moonlight client (mDNS-discovered), or connect the native punktfunk/1 client.
|
||||
Pair a stock Moonlight client (mDNS-discovered), or connect the native punktfunk/1 client — via the
|
||||
web console at `http://<host-ip>:3000` or directly.
|
||||
|
||||
> ⚠️ **COPR caveat:** COPR's mock chroot has no `bun`, so a COPR build produces only
|
||||
> `punktfunk` + `punktfunk-client` — **not** `punktfunk-web`. For the console on a COPR/bootc host,
|
||||
> install from the **Gitea RPM registry** (Option A — it carries `punktfunk-web`), which is also why
|
||||
> `bootc/Containerfile` installs from there rather than COPR.
|
||||
|
||||
## Why not Flatpak (for the HOST)?
|
||||
|
||||
|
||||
+41
-1
@@ -14,6 +14,10 @@
|
||||
# NVIDIA hosts; an AMD Deck-as-HOST needs a VAAPI backend first. The CLIENT decodes via VAAPI
|
||||
# (AMD/Intel, incl. the Deck) with a software fallback, so it works everywhere. See README.md.
|
||||
pkgbase=punktfunk
|
||||
# punktfunk-web (the browser console) is OPT-IN: building it needs `bun` (AUR-only as bun-bin on
|
||||
# stock Arch/SteamOS), so a default makepkg builds only host+client with no JS tooling — mirroring
|
||||
# the RPM spec's `%bcond_with web` (off by default). Set PF_WITH_WEB=1 to also build punktfunk-web
|
||||
# (appended to pkgname + bun to makedepends below).
|
||||
pkgname=('punktfunk-host' 'punktfunk-client')
|
||||
pkgver=0.0.1
|
||||
pkgrel=1
|
||||
@@ -26,6 +30,12 @@ license=('MIT OR Apache-2.0')
|
||||
makedepends=('rust' 'cargo' 'clang' 'cmake' 'nasm' 'pkgconf' 'git'
|
||||
'gtk4' 'libadwaita' 'sdl3' 'ffmpeg' 'pipewire' 'wayland' 'libxkbcommon' 'opus' 'libei')
|
||||
|
||||
# Opt-in punktfunk-web: only then is bun (build tool; the console runs on plain nodejs) required.
|
||||
if [ "${PF_WITH_WEB:-0}" = 1 ]; then
|
||||
pkgname+=('punktfunk-web')
|
||||
makedepends+=('bun') # `bun-bin` from the AUR if bun isn't in your configured repos
|
||||
fi
|
||||
|
||||
# AUR source (a tagged release). For an in-tree CI build, set PF_SRCDIR to the repo root and
|
||||
# build() uses it instead; see the README.
|
||||
source=("git+https://git.unom.io/unom/punktfunk.git#tag=v${pkgver}")
|
||||
@@ -40,6 +50,10 @@ build() {
|
||||
# NVIDIA builder. On a GPU-less builder symlink the CUDA stub into the link path first (same
|
||||
# caveat the RPM documents): ln -s "$(find / -name libcuda.so -path '*stubs*'|head -1)" /usr/lib/
|
||||
cargo build --release --locked -p punktfunk-host -p punktfunk-client-linux
|
||||
# Management web console (opt-in): the node-server .output bundle (built with bun, run with node).
|
||||
if [ "${PF_WITH_WEB:-0}" = 1 ]; then
|
||||
( cd web && bun install --frozen-lockfile && bun run build )
|
||||
fi
|
||||
}
|
||||
|
||||
package_punktfunk-host() {
|
||||
@@ -54,7 +68,8 @@ package_punktfunk-host() {
|
||||
'mutter: stream a GNOME desktop (Mutter RecordVirtual backend)'
|
||||
'sway: stream a wlroots desktop (Sway VirtualDisplay backend)'
|
||||
'xdg-desktop-portal-kde: portal for the headless KDE session helper'
|
||||
'xdg-desktop-portal-wlr: portal for the headless Sway session helper')
|
||||
'xdg-desktop-portal-wlr: portal for the headless Sway session helper'
|
||||
'punktfunk-web: browser management console (device pairing + status)')
|
||||
install=punktfunk-host.install
|
||||
local R; R="$(_repo)"; local T="$srcdir/target/release"
|
||||
|
||||
@@ -107,3 +122,28 @@ package_punktfunk-client() {
|
||||
install -Dm0644 "$R/LICENSE-MIT" "$pkgdir/usr/share/licenses/punktfunk-client/LICENSE-MIT"
|
||||
install -Dm0644 "$R/LICENSE-APACHE" "$pkgdir/usr/share/licenses/punktfunk-client/LICENSE-APACHE"
|
||||
}
|
||||
|
||||
package_punktfunk-web() {
|
||||
pkgdesc="punktfunk management web console (Nitro/Node SSR) — pairing + status in the browser"
|
||||
arch=('any')
|
||||
# Runtime is plain node (the .output is portable JS — bun was only the build tool). Auto-wired to
|
||||
# the host's mgmt token via the systemd --user units; enable with `systemctl --user enable --now punktfunk-web`.
|
||||
depends=('nodejs')
|
||||
local R; R="$(_repo)"
|
||||
|
||||
# Pre-built node-server bundle (from build()) + a PATH-stable launcher (matches the .deb/.rpm).
|
||||
install -d "$pkgdir/usr/share/punktfunk-web/.output"
|
||||
cp -r "$R/web/.output/server" "$pkgdir/usr/share/punktfunk-web/.output/server"
|
||||
cp -r "$R/web/.output/public" "$pkgdir/usr/share/punktfunk-web/.output/public"
|
||||
install -d "$pkgdir/usr/bin"
|
||||
printf '%s\n' '#!/bin/sh' 'exec /usr/bin/node /usr/share/punktfunk-web/.output/server/index.mjs "$@"' \
|
||||
> "$pkgdir/usr/bin/punktfunk-web-server"
|
||||
chmod 0755 "$pkgdir/usr/bin/punktfunk-web-server"
|
||||
# systemd USER units: the console runs per-user; web-init generates the login password on first start.
|
||||
install -Dm0644 "$R/scripts/punktfunk-web.service" "$pkgdir/usr/lib/systemd/user/punktfunk-web.service"
|
||||
install -Dm0644 "$R/scripts/punktfunk-web-init.service" "$pkgdir/usr/lib/systemd/user/punktfunk-web-init.service"
|
||||
install -Dm0755 "$R/scripts/web-init.sh" "$pkgdir/usr/share/punktfunk-web/web-init.sh"
|
||||
install -Dm0644 "$R/web/web.env.example" "$pkgdir/usr/share/punktfunk-web/web.env.example"
|
||||
install -Dm0644 "$R/LICENSE-MIT" "$pkgdir/usr/share/licenses/punktfunk-web/LICENSE-MIT"
|
||||
install -Dm0644 "$R/LICENSE-APACHE" "$pkgdir/usr/share/licenses/punktfunk-web/LICENSE-APACHE"
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
# punktfunk on Arch Linux / SteamOS
|
||||
|
||||
Packaging for punktfunk on Arch and Arch-derived immutable distros (SteamOS 3, etc.). The
|
||||
`PKGBUILD` is a **split package** producing both **`punktfunk-host`** (the gaming-rig host) and
|
||||
`PKGBUILD` is a **split package** producing **`punktfunk-host`** (the gaming-rig host) and
|
||||
**`punktfunk-client`** (the GTK4 couch/Deck client) — mirrors the rpm subpackages
|
||||
(`packaging/rpm/punktfunk.spec`) and the two deb build scripts. On a **Steam Deck you want
|
||||
(`packaging/rpm/punktfunk.spec`) and the deb build scripts. On a **Steam Deck you want
|
||||
`punktfunk-client`** (it's what the [Decky plugin](../../clients/decky/) launches); on a gaming
|
||||
rig, `punktfunk-host`.
|
||||
|
||||
A third member, **`punktfunk-web`** (the browser management console — pairing + status), is
|
||||
**opt-in**: build it by setting `PF_WITH_WEB=1`, which requires **`bun`** at build time (`bun-bin`
|
||||
from the AUR if it isn't in your repos; the console then runs on plain `nodejs`). A default
|
||||
`makepkg` builds only host+client with no JS tooling — mirroring the RPM spec's `%bcond_with web`.
|
||||
|
||||
> ⚠️ **Host encode is NVENC-only today.** `crates/punktfunk-host/src/encode/linux.rs` implements
|
||||
> `hevc_nvenc`/`av1_nvenc`/`h264_nvenc` + a CUDA zero-copy path — there is **no VAAPI encoder**. So
|
||||
> `punktfunk-host` works on **Arch + NVIDIA** (incl. `bazzite-deck-nvidia`); an **AMD Deck-as-host**
|
||||
@@ -22,6 +27,8 @@ cd packaging/arch
|
||||
PF_SRCDIR="$(git rev-parse --show-toplevel)" makepkg -f --holdver
|
||||
# …or build the tagged release the AUR way:
|
||||
makepkg -si
|
||||
# …add the web console too (needs bun / bun-bin):
|
||||
PF_WITH_WEB=1 PF_SRCDIR="$(git rev-parse --show-toplevel)" makepkg -f --holdver
|
||||
```
|
||||
Then the standard first-run (printed by the install scriptlet):
|
||||
```sh
|
||||
@@ -29,6 +36,9 @@ sudo usermod -aG input "$USER" # virtual gamepads; re-login after
|
||||
mkdir -p ~/.config/punktfunk
|
||||
cp /usr/share/punktfunk/host.env.bazzite ~/.config/punktfunk/host.env # gamescope backend
|
||||
systemctl --user enable --now punktfunk-host
|
||||
# Web console (if you installed the punktfunk-web package): enable it + read the login password.
|
||||
systemctl --user enable --now punktfunk-web
|
||||
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' # open http://<host-ip>:3000
|
||||
```
|
||||
NVENC/EGL come from the NVIDIA driver: `sudo pacman -S --needed nvidia-utils`. Arch's stock
|
||||
`ffmpeg` already has NVENC built in — no RPM-Fusion-style swap needed (unlike Fedora).
|
||||
|
||||
@@ -32,10 +32,12 @@ There are two supported paths on Bazzite, driven by different files in `packagin
|
||||
| **B — bootc / OCI image** | `packaging/bootc/Containerfile` | Bakes punktfunk into a `FROM bazzite-nvidia` image once; you `bootc switch` any number of hosts onto it | Fleets, reproducible appliances, no per-host drift |
|
||||
|
||||
**Trade-off:** Path A is a per-host package layer — simple, but each host accumulates its own
|
||||
layered-package state. Path B builds one image (RPM Fusion + COPR + the package + udev rule
|
||||
pre-installed) that you push to a registry and rebase hosts onto atomically — no per-host
|
||||
`rpm-ostree install` drift, at the cost of running a `podman build`/`push` pipeline. Both
|
||||
ultimately install the **same RPM** and require the **same first-run setup** (sections 3–6).
|
||||
layered-package state. Path B builds one image (RPM Fusion + the Gitea RPM repo + the host and
|
||||
**web console** + udev rule pre-installed) that you push to a registry and rebase hosts onto
|
||||
atomically — no per-host `rpm-ostree install` drift, at the cost of running a `podman build`/`push`
|
||||
pipeline. Both require the **same first-run setup** (sections 3–6); note Path B installs from the
|
||||
**Gitea RPM registry** (which carries `punktfunk-web`), whereas Path A's COPR builds host+client
|
||||
only — for the web console on Path A, layer from the Gitea registry instead (`../rpm/README.md`).
|
||||
|
||||
### Path A — rpm-ostree layering from the COPR
|
||||
|
||||
@@ -64,8 +66,10 @@ systemctl reboot
|
||||
|
||||
The image is built **off-host** (on any machine with `podman`) from
|
||||
`packaging/bootc/Containerfile`, which bases on `ghcr.io/ublue-os/bazzite-nvidia:stable`
|
||||
(override with `--build-arg BASE_IMAGE=…`), enables RPM Fusion free + nonfree, enables the COPR
|
||||
(`--build-arg PUNKTFUNK_COPR=…`, default `enricobuehler/punktfunk`), and installs the package.
|
||||
(override with `--build-arg BASE_IMAGE=…`), enables RPM Fusion free + nonfree, adds the Gitea RPM
|
||||
repo (`--build-arg PUNKTFUNK_RPM_GROUP=…`, default `bazzite`), and installs the host **and the web
|
||||
console** (`punktfunk punktfunk-web`). It uses the Gitea registry rather than the COPR specifically
|
||||
because the registry carries `punktfunk-web` (COPR's mock chroot can't build it — no `bun`).
|
||||
|
||||
```sh
|
||||
# Build + push (run from the repo root, on your builder machine):
|
||||
@@ -76,9 +80,10 @@ podman push ghcr.io/<you>/bazzite-punktfunk
|
||||
sudo bootc switch ghcr.io/<you>/bazzite-punktfunk && systemctl reboot
|
||||
```
|
||||
|
||||
> ⚠️ The image build runs `dnf5 copr enable enricobuehler/punktfunk` — so **Path B also depends on
|
||||
> the COPR being published** (or on you pointing `PUNKTFUNK_COPR` at a COPR you've built yourself).
|
||||
> If the COPR doesn't exist, the `podman build` fails at the install step.
|
||||
> ⚠️ The image installs from the **Gitea RPM registry** (group `bazzite`), so **Path B depends on
|
||||
> that registry being populated** — CI (`.gitea/workflows/rpm.yml`) publishes `punktfunk` +
|
||||
> `punktfunk-web` on every push to `main`. Packages are unsigned with GPG-signed metadata
|
||||
> (`repo_gpgcheck=1`), matching `packaging/rpm/README.md`.
|
||||
|
||||
---
|
||||
|
||||
@@ -215,6 +220,10 @@ into the user unit directory.
|
||||
```sh
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable --now punktfunk-host
|
||||
# Management web console (pairing + status), if you installed punktfunk-web (it ships in the Gitea
|
||||
# RPM registry / bootc image — COPR can't build it; see ../rpm/README.md). Read the login password:
|
||||
systemctl --user enable --now punktfunk-web
|
||||
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p' # then open http://<host-ip>:3000
|
||||
```
|
||||
|
||||
Check health and logs:
|
||||
|
||||
@@ -15,8 +15,12 @@
|
||||
ARG BASE_IMAGE=ghcr.io/ublue-os/bazzite-nvidia:stable
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
# COPR project that hosts the punktfunk RPM (see packaging/copr/README). Override at build.
|
||||
ARG PUNKTFUNK_COPR=enricobuehler/punktfunk
|
||||
# punktfunk's RPMs come from unom's Gitea RPM registry (the recommended path — see
|
||||
# packaging/rpm/README). Use it rather than COPR specifically because it carries the
|
||||
# punktfunk-web management console subpackage, which COPR's mock chroot can't build (no `bun`).
|
||||
# Group "bazzite" == the Fedora 43 base; override for a different base. Gitea signs the repo
|
||||
# metadata (repo_gpgcheck=1); the packages themselves are unsigned (gpgcheck=0).
|
||||
ARG PUNKTFUNK_RPM_GROUP=bazzite
|
||||
|
||||
# RPM Fusion nonfree provides the NVENC-capable ffmpeg-libs punktfunk records/encodes with.
|
||||
# (Bazzite usually has RPM Fusion enabled already; this is belt-and-suspenders.)
|
||||
@@ -25,15 +29,20 @@ RUN dnf5 -y install \
|
||||
https://mirrors.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm \
|
||||
|| true
|
||||
|
||||
# Enable our COPR and install punktfunk.
|
||||
RUN dnf5 -y copr enable ${PUNKTFUNK_COPR} && \
|
||||
dnf5 -y install punktfunk && \
|
||||
dnf5 -y copr disable ${PUNKTFUNK_COPR} && \
|
||||
dnf5 clean all
|
||||
# Add the Gitea RPM repo and install the host + the web console (punktfunk-web pulls nodejs).
|
||||
RUN printf '%s\n' \
|
||||
'[gitea-unom-punktfunk]' \
|
||||
'name=punktfunk (unom)' \
|
||||
"baseurl=https://git.unom.io/api/packages/unom/rpm/${PUNKTFUNK_RPM_GROUP}" \
|
||||
'enabled=1' 'gpgcheck=0' 'repo_gpgcheck=1' \
|
||||
'gpgkey=https://git.unom.io/api/packages/unom/rpm/repository.key' \
|
||||
> /etc/yum.repos.d/punktfunk.repo \
|
||||
&& dnf5 -y install punktfunk punktfunk-web \
|
||||
&& dnf5 clean all
|
||||
|
||||
# The udev rule + systemd *user* unit ship in the RPM; nothing else to enable at image
|
||||
# build time (the host runs per-user in the graphical session, enabled with
|
||||
# `systemctl --user enable --now punktfunk-host` after first boot).
|
||||
# The udev rule + systemd *user* units ship in the RPMs; nothing else to enable at image build
|
||||
# time (host + console run per-user in the graphical session, enabled after first boot with
|
||||
# `systemctl --user enable --now punktfunk-host punktfunk-web`).
|
||||
|
||||
# bootc image hygiene: the container build must leave a clean ostree commit.
|
||||
RUN ostree container commit
|
||||
|
||||
@@ -33,3 +33,16 @@ copr-cli buildscm punktfunk \
|
||||
Note: COPR caps build time/RAM; a full `cargo build --release` of the host (FFmpeg/PipeWire
|
||||
sys-crates + aws-lc-rs) is heavy but within the default COPR limits. If a chroot OOMs, lower
|
||||
parallelism with `CARGO_BUILD_JOBS` in the spec's `%build`.
|
||||
|
||||
## The web console subpackage (`punktfunk-web`)
|
||||
|
||||
The spec can also build the management web console as a noarch `punktfunk-web` subpackage, but it's
|
||||
gated behind `%bcond_with web` and **OFF by default** — building the Nitro/Node SSR bundle needs
|
||||
`bun`, which COPR's mock chroot does not provide. So a stock COPR build produces only `punktfunk`
|
||||
+ `punktfunk-client`.
|
||||
|
||||
Two ways to get the console:
|
||||
- **Recommended:** install it from the Gitea RPM registry (`packaging/rpm/README.md`, Option A),
|
||||
whose CI builder image has `bun` and builds `--with web`. (This is what `bootc/Containerfile` does.)
|
||||
- **In COPR:** add `bun` to the chroot (a custom mock config / external repo) and set the build
|
||||
option `--with web` on the project, then `dnf install punktfunk-web`.
|
||||
|
||||
+10
-3
@@ -29,8 +29,10 @@ repo_gpgcheck=1
|
||||
gpgkey=https://git.unom.io/api/packages/unom/rpm/repository.key
|
||||
REPO
|
||||
|
||||
# Layer the package, then reboot into the new deployment.
|
||||
rpm-ostree install punktfunk
|
||||
# Layer the host + the web console (pairing/status), then reboot into the new deployment.
|
||||
# (punktfunk Recommends punktfunk-web; list it explicitly so it's pulled regardless of weak-dep
|
||||
# settings. The registry carries punktfunk-web because CI builds the spec --with web; COPR can't.)
|
||||
rpm-ostree install punktfunk punktfunk-web
|
||||
systemctl reboot
|
||||
```
|
||||
|
||||
@@ -46,6 +48,9 @@ ujust add-user-to-input-group # virtual gamepads need /dev/uinput (re-
|
||||
mkdir -p ~/.config/punktfunk
|
||||
cp /usr/share/punktfunk/host.env.bazzite ~/.config/punktfunk/host.env # gamescope defaults
|
||||
systemctl --user enable --now punktfunk-host
|
||||
# Web console — enable it and read the auto-generated login password (then open http://<host-ip>:3000):
|
||||
systemctl --user enable --now punktfunk-web
|
||||
journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'
|
||||
```
|
||||
|
||||
(See [`../bazzite/README.md`](../bazzite/README.md) for the full appliance walkthrough —
|
||||
@@ -65,7 +70,9 @@ tracking: `rpm-ostree override` / `rpm-ostree uninstall punktfunk`.
|
||||
## Build an RPM locally
|
||||
|
||||
```sh
|
||||
PF_VERSION=0.0.1 bash packaging/rpm/build-rpm.sh # -> dist/punktfunk-0.0.1-1.fcNN.x86_64.rpm
|
||||
PF_VERSION=0.0.1 bash packaging/rpm/build-rpm.sh # host + client
|
||||
PF_VERSION=0.0.1 PF_WITH_WEB=1 bash packaging/rpm/build-rpm.sh # + the noarch punktfunk-web (needs bun on PATH)
|
||||
# -> dist/punktfunk-0.0.1-1.fcNN.x86_64.rpm (+ punktfunk-web-0.0.1-1.fcNN.noarch.rpm with PF_WITH_WEB=1)
|
||||
```
|
||||
|
||||
Run it inside the Fedora 43 builder image so the deps resolve and match Bazzite:
|
||||
|
||||
@@ -11,6 +11,10 @@ set -euo pipefail
|
||||
|
||||
PF_VERSION="${PF_VERSION:-0.0.1}"
|
||||
PF_RELEASE="${PF_RELEASE:-1}"
|
||||
# PF_WITH_WEB=1 builds the punktfunk-web subpackage too (needs `bun` on PATH — present in the CI
|
||||
# builder image, not in a plain mock chroot). Default off so a bare `rpmbuild`/COPR still works.
|
||||
WEB_OPT=()
|
||||
[ "${PF_WITH_WEB:-0}" = "1" ] && WEB_OPT=(--with web)
|
||||
ROOTDIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
cd "$ROOTDIR"
|
||||
|
||||
@@ -28,7 +32,7 @@ git archive --format=tar.gz --prefix="punktfunk-${PF_VERSION}/" \
|
||||
# resolves them from RPMs. Our builder image provides the toolchain via rustup (so
|
||||
# rust-toolchain.toml's pinned channel works) and the -devel libs via dnf, neither of which
|
||||
# rpmbuild's RPM-level check sees — skip it; a genuinely missing dep fails the compile/link.
|
||||
rpmbuild -bb --nodeps \
|
||||
rpmbuild -bb --nodeps "${WEB_OPT[@]}" \
|
||||
--define "_topdir $TOP" \
|
||||
--define "pf_version ${PF_VERSION}" \
|
||||
--define "pf_release ${PF_RELEASE}" \
|
||||
|
||||
@@ -39,6 +39,13 @@ ExclusiveArch: x86_64 aarch64
|
||||
# Recommends). Drop it from the auto-Requires, mirroring the Debian package's NVIDIA filter.
|
||||
%global __requires_exclude ^libcuda\\.so.*$
|
||||
|
||||
# Management web console subpackage (punktfunk-web). OFF by default: building the Nitro/Node SSR
|
||||
# bundle needs `bun`, which a plain rpmbuild / COPR mock chroot does NOT have. CI's builder image
|
||||
# (ci/fedora-rpm.Dockerfile) DOES have bun and builds with `--with web`, so the Gitea RPM registry
|
||||
# carries punktfunk-web. COPR (no bun) builds host+client only — use the Gitea registry for the
|
||||
# console, or enable bun + `--with web` in the COPR project. Mirrors the Debian punktfunk-web .deb.
|
||||
%bcond_with web
|
||||
|
||||
# --- Build toolchain ---------------------------------------------------------
|
||||
BuildRequires: cargo
|
||||
BuildRequires: rust
|
||||
@@ -90,6 +97,10 @@ Suggests: kwin
|
||||
Suggests: mutter
|
||||
# NVENC + GPU EGL come from the NVIDIA driver; on Bazzite the -nvidia image has it.
|
||||
Recommends: (xorg-x11-drv-nvidia-cuda if xorg-x11-drv-nvidia)
|
||||
# The management web console (pairing + status) every user needs — a separate noarch subpackage.
|
||||
# Weak-dep so `dnf install punktfunk` pulls it where it exists (the Gitea registry); harmless where
|
||||
# it doesn't (a COPR build without `--with web` simply has no punktfunk-web to satisfy).
|
||||
Recommends: punktfunk-web
|
||||
|
||||
%description
|
||||
punktfunk is a Linux-first, low-latency desktop and game streaming host. It speaks
|
||||
@@ -114,6 +125,23 @@ audio, microphone passthrough, and full gamepad support including DualSense
|
||||
touchpad, motion, adaptive triggers and lightbar through SDL3. The host creates a
|
||||
virtual output at exactly this client's resolution and refresh rate — no scaling.
|
||||
|
||||
%if %{with web}
|
||||
%package web
|
||||
Summary: punktfunk management web console (Nitro/Node SSR + React)
|
||||
BuildArch: noarch
|
||||
# Runtime is plain node (the .output is portable JS — bun is only the build tool). Fedora 41+
|
||||
# ships nodejs >= 20, which the node-server build needs.
|
||||
Requires: nodejs
|
||||
|
||||
%description web
|
||||
The browser console for a punktfunk streaming host: status, paired devices, and the SPAKE2
|
||||
PIN pairing flow every client needs. Runs as a systemd --user service on port 3000, login-gated
|
||||
(a password generated on first start), proxying the host's loopback HTTPS management API with a
|
||||
bearer token injected server-side (never sent to the browser). Auto-wired to the host on a
|
||||
packaged install — it sources the host's mgmt token and a generated login password, no env
|
||||
editing. Enable with `systemctl --user enable --now punktfunk-web`.
|
||||
%endif
|
||||
|
||||
%prep
|
||||
%autosetup -n %{name}-%{version}
|
||||
|
||||
@@ -123,6 +151,16 @@ virtual output at exactly this client's resolution and refresh rate — no scali
|
||||
export RUSTFLAGS="%{?build_rustflags}"
|
||||
cargo build --release -p punktfunk-host -p punktfunk-client-linux
|
||||
|
||||
%if %{with web}
|
||||
# Management web console: build the Nitro/Node SSR bundle (node-server preset) with bun. The
|
||||
# .output is portable JS run at runtime by plain node; bun is only the build tool (CI image).
|
||||
(cd web && bun install --frozen-lockfile && bun run build)
|
||||
if grep -q 'Bun\.serve' web/.output/server/index.mjs; then
|
||||
echo "ERROR: web build is a bun bundle (Bun.serve) — need the node-server preset" >&2
|
||||
exit 1
|
||||
fi
|
||||
%endif
|
||||
|
||||
%install
|
||||
# Binary
|
||||
install -Dm0755 target/release/punktfunk-host %{buildroot}%{_bindir}/punktfunk-host
|
||||
@@ -177,6 +215,24 @@ install -d %{buildroot}%{_datadir}/%{name}/bazzite
|
||||
install -Dm0755 packaging/bazzite/kde-desktop-setup.sh %{buildroot}%{_datadir}/%{name}/bazzite/kde-desktop-setup.sh
|
||||
install -Dm0644 docs/api/openapi.json %{buildroot}%{_datadir}/%{name}/openapi.json
|
||||
|
||||
%if %{with web}
|
||||
# --- web console subpackage (punktfunk-web) ---
|
||||
install -d %{buildroot}%{_datadir}/punktfunk-web/.output
|
||||
cp -r web/.output/server %{buildroot}%{_datadir}/punktfunk-web/.output/server
|
||||
cp -r web/.output/public %{buildroot}%{_datadir}/punktfunk-web/.output/public
|
||||
# PATH-stable launcher (matches the .deb's /usr/bin/punktfunk-web-server).
|
||||
cat > %{buildroot}%{_bindir}/punktfunk-web-server <<'WRAP'
|
||||
#!/bin/sh
|
||||
exec /usr/bin/node /usr/share/punktfunk-web/.output/server/index.mjs "$@"
|
||||
WRAP
|
||||
chmod 0755 %{buildroot}%{_bindir}/punktfunk-web-server
|
||||
# systemd --user units: the console runs per-user; web-init generates the login password.
|
||||
install -Dm0644 scripts/punktfunk-web.service %{buildroot}%{_userunitdir}/punktfunk-web.service
|
||||
install -Dm0644 scripts/punktfunk-web-init.service %{buildroot}%{_userunitdir}/punktfunk-web-init.service
|
||||
install -Dm0755 scripts/web-init.sh %{buildroot}%{_datadir}/punktfunk-web/web-init.sh
|
||||
install -Dm0644 web/web.env.example %{buildroot}%{_datadir}/punktfunk-web/web.env.example
|
||||
%endif
|
||||
|
||||
%files
|
||||
%license LICENSE-MIT LICENSE-APACHE
|
||||
%doc README.md docs/implementation-plan.md packaging/README.md
|
||||
@@ -195,6 +251,18 @@ install -Dm0644 docs/api/openapi.json %{buildroot}%{_datadir}/%
|
||||
%{_udevrulesdir}/70-punktfunk-client.rules
|
||||
%{_prefix}/lib/sysctl.d/99-punktfunk-client-net.conf
|
||||
|
||||
%if %{with web}
|
||||
%files web
|
||||
%license LICENSE-MIT LICENSE-APACHE
|
||||
%{_bindir}/punktfunk-web-server
|
||||
%dir %{_datadir}/punktfunk-web
|
||||
%{_datadir}/punktfunk-web/.output
|
||||
%{_datadir}/punktfunk-web/web-init.sh
|
||||
%{_datadir}/punktfunk-web/web.env.example
|
||||
%{_userunitdir}/punktfunk-web.service
|
||||
%{_userunitdir}/punktfunk-web-init.service
|
||||
%endif
|
||||
|
||||
%post client
|
||||
# Pick up the DualSense hidraw rule without a reboot (best-effort; on rpm-ostree it
|
||||
# applies on the next boot into the layered deployment).
|
||||
@@ -215,6 +283,17 @@ echo "punktfunk installed. Add yourself to the 'input' group (sudo usermod -aG i
|
||||
echo "then enable the host: systemctl --user enable --now punktfunk-host"
|
||||
echo "Config: cp %{_datadir}/%{name}/host.env.bazzite ~/.config/punktfunk/host.env"
|
||||
|
||||
%if %{with web}
|
||||
%post web
|
||||
echo "punktfunk-web installed. Enable the console for your user:"
|
||||
echo " systemctl --user enable --now punktfunk-web"
|
||||
echo "A login password is generated on first start — read it with:"
|
||||
echo " journalctl --user -u punktfunk-web-init | sed -n 's/.*password generated: //p'"
|
||||
echo "Then open http://<host-ip>:3000"
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Sun Jun 15 2026 punktfunk <noreply@anthropic.com> - 0.0.1-2
|
||||
- Add punktfunk-web subpackage (management console, --with web; auto-wired to the host token).
|
||||
* Wed Jun 10 2026 punktfunk <noreply@anthropic.com> - 0.0.1-1
|
||||
- Initial RPM: punktfunk-host + udev rule + systemd user unit + headless helpers.
|
||||
|
||||
Reference in New Issue
Block a user