refactor(client): extract UI-agnostic plumbing into pf-client-core (phase 0)
Session pump, FFmpeg decode, PipeWire audio, SDL3 gamepads, keymap, trust store, mDNS discovery, library client and Wake-on-LAN move verbatim from clients/linux into crates/pf-client-core, shared with the upcoming Vulkan session binary (punktfunk-planning: linux-client-rearchitecture.md). The GTK client re-exports them at the crate root so every existing crate::-path keeps resolving; its manifest drops the moved-only deps. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Generated
+20
-8
@@ -2740,6 +2740,25 @@ version = "2.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||
|
||||
[[package]]
|
||||
name = "pf-client-core"
|
||||
version = "0.8.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel",
|
||||
"ffmpeg-next",
|
||||
"mdns-sd",
|
||||
"opus",
|
||||
"pipewire",
|
||||
"punktfunk-core",
|
||||
"rustls",
|
||||
"sdl3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pf-driver-proto"
|
||||
version = "0.0.1"
|
||||
@@ -2927,21 +2946,14 @@ version = "0.8.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel",
|
||||
"ffmpeg-next",
|
||||
"gtk4",
|
||||
"khronos-egl",
|
||||
"libadwaita",
|
||||
"mdns-sd",
|
||||
"opus",
|
||||
"pipewire",
|
||||
"pf-client-core",
|
||||
"punktfunk-core",
|
||||
"rustls",
|
||||
"sdl3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -5,6 +5,7 @@ members = [
|
||||
"crates/punktfunk-host",
|
||||
"crates/punktfunk-host/vendor/usbip-sim",
|
||||
"crates/punktfunk-tray",
|
||||
"crates/pf-client-core",
|
||||
"crates/pf-driver-proto",
|
||||
"clients/probe",
|
||||
"clients/linux",
|
||||
|
||||
@@ -20,7 +20,7 @@ punktfunk-core = { path = "../../../crates/punktfunk-core", features = ["quic"]
|
||||
jni = "0.21"
|
||||
log = "0.4"
|
||||
# LAN host discovery: browse the host's `_punktfunk._udp` mDNS advert — the SAME crate + service the
|
||||
# Linux/Windows clients use (`clients/linux/src/discovery.rs`), replacing Android's per-OEM
|
||||
# Linux/Windows clients use (`crates/pf-client-core/src/discovery.rs`), replacing Android's per-OEM
|
||||
# `NsdManager` system daemon with one tested browse path. Pure Rust (socket2/if-addrs/mio), so it
|
||||
# cross-compiles to the Android targets AND builds on the host (the JNI seam links into
|
||||
# `cargo build --workspace`). Kotlin keeps only the Wi-Fi `MulticastLock` + permission UX.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! LAN host discovery over mDNS, in Rust via `mdns-sd` — the same crate + service type the
|
||||
//! Linux/Windows clients use (`clients/linux/src/discovery.rs`), exposed to Kotlin over JNI.
|
||||
//! Linux/Windows clients use (`crates/pf-client-core/src/discovery.rs`), exposed to Kotlin over JNI.
|
||||
//!
|
||||
//! Why not `NsdManager`: that API delegates to a per-OEM system mDNS daemon whose reliability
|
||||
//! varies wildly (the Android client's discovery was "mostly broken"). Browsing in our own Rust
|
||||
|
||||
@@ -15,6 +15,10 @@ path = "src/main.rs"
|
||||
# Everything is Linux-gated so `cargo build --workspace` stays green on macOS (the Mac
|
||||
# client lives in clients/apple); on other platforms this builds as a stub binary.
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
# Session pump, decode, audio, gamepads, trust, discovery, keymap — the UI-agnostic
|
||||
# plumbing, shared with the upcoming Vulkan session binary (design: punktfunk-planning
|
||||
# linux-client-rearchitecture.md). This crate keeps only the GTK shell + GL presenter.
|
||||
pf-client-core = { path = "../../crates/pf-client-core" }
|
||||
punktfunk-core = { path = "../../crates/punktfunk-core", features = ["quic"] }
|
||||
|
||||
# UI shell. GraphicsOffload needs GTK ≥ 4.14; black-background ≥ 4.16. AlertDialog/
|
||||
@@ -23,25 +27,10 @@ gtk = { package = "gtk4", version = "0.11", features = ["v4_16"] }
|
||||
adw = { package = "libadwaita", version = "0.9", features = ["v1_5"] }
|
||||
async-channel = "2"
|
||||
|
||||
# Video decode (same FFmpeg pin as the host) and audio.
|
||||
ffmpeg-next = "8"
|
||||
opus = "0.3"
|
||||
pipewire = "0.9"
|
||||
|
||||
# Gamepads: capture + feedback (full DualSense fidelity — touchpad/motion/triggers/LEDs
|
||||
# need the hidapi driver).
|
||||
sdl3 = { version = "0.18", features = ["hidapi"] }
|
||||
# The VAAPI GL presenter (video_gl.rs): EGL dmabuf import into a GDK-shared context, dlopened
|
||||
# at runtime (`dynamic`) so GPU-less boxes and the software path never touch libEGL.
|
||||
khronos-egl = { version = "6", features = ["dynamic"] }
|
||||
|
||||
mdns-sd = "0.20"
|
||||
# Game-library fetch from the host's management API over mTLS + fingerprint pinning.
|
||||
# `ureq` is small + sync (the host uses it too) and its rustls unifies with the
|
||||
# workspace's (quinn's) 0.23; the pinning verifier mirrors core's private `PinVerify`.
|
||||
ureq = "2"
|
||||
rustls = { version = "0.23", features = ["ring"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
anyhow = "1"
|
||||
tracing = "0.1"
|
||||
|
||||
@@ -78,15 +78,15 @@ src/
|
||||
ui_trust.rs TOFU / PIN-pairing / request-access dialogs
|
||||
ui_settings.rs resolution · refresh · decoder · bitrate · compositor · mic
|
||||
ui_stream.rs the stream window (GtkGraphicsOffload present) + input capture
|
||||
launch.rs · session.rs session launch/UI glue; lifecycle over the NativeClient connector
|
||||
video.rs FFmpeg VAAPI / software decode → dmabuf / texture
|
||||
audio.rs PipeWire playback + mic uplink
|
||||
gamepad.rs · keymap.rs SDL3 controllers + feedback; keyboard VK mapping
|
||||
trust.rs · discovery.rs persistent identity, known hosts + settings, mDNS browse
|
||||
library.rs mgmt-API library client (mTLS + pinned fingerprint, art proxy)
|
||||
launch.rs session launch/UI glue over the shared session pump
|
||||
video_gl.rs VAAPI dmabuf → RGBA GL presenter (EGL import, CICP-driven CSC)
|
||||
tools/screenshots.sh store screenshot capture (app self-capture; Xvfb fallback)
|
||||
```
|
||||
|
||||
The UI-agnostic plumbing — session pump, FFmpeg decode, PipeWire audio, SDL3 gamepads +
|
||||
keymap, trust store, mDNS discovery, library client, Wake-on-LAN — lives in
|
||||
`crates/pf-client-core`, shared with the Vulkan session binary.
|
||||
|
||||
## Related
|
||||
|
||||
- **[Documentation](https://docs.punktfunk.unom.io)** — quick start, pairing, troubleshooting
|
||||
|
||||
@@ -5,27 +5,19 @@
|
||||
//! mirrors the Apple client: persistent identity, TOFU prompt with the host fingerprint,
|
||||
//! SPAKE2 PIN pairing.
|
||||
|
||||
// The UI-agnostic plumbing lives in `pf-client-core`, shared with the upcoming Vulkan
|
||||
// session binary (design: punktfunk-planning linux-client-rearchitecture.md, Phase 0).
|
||||
// Root re-exports keep every existing `crate::video`-style path resolving unchanged.
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use pf_client_core::{audio, discovery, gamepad, keymap, library, session, trust, video, wol};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod app;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod audio;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod cli;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod discovery;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod gamepad;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod keymap;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod launch;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod library;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod session;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod trust;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod ui_gamepad_library;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod ui_hosts;
|
||||
@@ -38,12 +30,8 @@ mod ui_stream;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod ui_trust;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod video;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod video_gl;
|
||||
|
||||
mod wol;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main() -> gtk::glib::ExitCode {
|
||||
app::run()
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
[package]
|
||||
name = "pf-client-core"
|
||||
description = "Shared Linux-client plumbing — session pump, FFmpeg decode, PipeWire audio, SDL3 gamepads, trust store, discovery — extracted from the GTK client so the shell and the Vulkan session binary build on one implementation"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
# Same Linux gating as clients/linux: `cargo build --workspace` stays green on macOS
|
||||
# (the Mac client lives in clients/apple); elsewhere this crate is `wol` plus stubs-free
|
||||
# emptiness. `wol` is pure std and stays cross-platform, matching the old main.rs.
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
punktfunk-core = { path = "../punktfunk-core", features = ["quic"] }
|
||||
async-channel = "2"
|
||||
|
||||
# Video decode (same FFmpeg pin as the host) and audio.
|
||||
ffmpeg-next = "8"
|
||||
opus = "0.3"
|
||||
pipewire = "0.9"
|
||||
|
||||
# Gamepads: capture + feedback (full DualSense fidelity — touchpad/motion/triggers/LEDs
|
||||
# need the hidapi driver).
|
||||
sdl3 = { version = "0.18", features = ["hidapi"] }
|
||||
|
||||
mdns-sd = "0.20"
|
||||
# Game-library fetch from the host's management API over mTLS + fingerprint pinning.
|
||||
# `ureq` is small + sync (the host uses it too) and its rustls unifies with the
|
||||
# workspace's (quinn's) 0.23; the pinning verifier mirrors core's private `PinVerify`.
|
||||
ureq = "2"
|
||||
rustls = { version = "0.23", features = ["ring"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
anyhow = "1"
|
||||
tracing = "0.1"
|
||||
@@ -0,0 +1,26 @@
|
||||
//! Shared, UI-agnostic Linux-client plumbing, extracted verbatim from the GTK client
|
||||
//! (design: punktfunk-planning `linux-client-rearchitecture.md`, Phase 0) so the desktop
|
||||
//! shell and the Vulkan session binary build on one implementation.
|
||||
//!
|
||||
//! Nothing here may depend on a UI toolkit: the presenter contract is `session`'s
|
||||
//! channels (`SessionHandle`) and `video`'s `DecodedImage` (RGBA bytes or dmabuf fds +
|
||||
//! plane layout) — how frames reach the screen is the consumer's business.
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod audio;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod discovery;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod gamepad;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod keymap;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod library;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod session;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod trust;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod video;
|
||||
|
||||
pub mod wol;
|
||||
@@ -23,7 +23,7 @@ anyhow = "1"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
# Loopback HTTPS poll of GET /api/v1/local/summary. Same sync ureq + rustls(ring) stack and
|
||||
# custom-verifier pattern as the Linux client's library fetch (clients/linux/src/library.rs) —
|
||||
# custom-verifier pattern as the Linux client's library fetch (crates/pf-client-core/src/library.rs) —
|
||||
# but ring-only (no default aws-lc-rs provider: it needs a C toolchain per target and the agent
|
||||
# pins the ring provider explicitly anyway).
|
||||
ureq = { version = "2", default-features = false, features = ["tls"] }
|
||||
|
||||
Reference in New Issue
Block a user