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"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
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]]
|
[[package]]
|
||||||
name = "pf-driver-proto"
|
name = "pf-driver-proto"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
@@ -2927,21 +2946,14 @@ version = "0.8.2"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-channel",
|
"async-channel",
|
||||||
"ffmpeg-next",
|
|
||||||
"gtk4",
|
"gtk4",
|
||||||
"khronos-egl",
|
"khronos-egl",
|
||||||
"libadwaita",
|
"libadwaita",
|
||||||
"mdns-sd",
|
"pf-client-core",
|
||||||
"opus",
|
|
||||||
"pipewire",
|
|
||||||
"punktfunk-core",
|
"punktfunk-core",
|
||||||
"rustls",
|
|
||||||
"sdl3",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"ureq",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ members = [
|
|||||||
"crates/punktfunk-host",
|
"crates/punktfunk-host",
|
||||||
"crates/punktfunk-host/vendor/usbip-sim",
|
"crates/punktfunk-host/vendor/usbip-sim",
|
||||||
"crates/punktfunk-tray",
|
"crates/punktfunk-tray",
|
||||||
|
"crates/pf-client-core",
|
||||||
"crates/pf-driver-proto",
|
"crates/pf-driver-proto",
|
||||||
"clients/probe",
|
"clients/probe",
|
||||||
"clients/linux",
|
"clients/linux",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ punktfunk-core = { path = "../../../crates/punktfunk-core", features = ["quic"]
|
|||||||
jni = "0.21"
|
jni = "0.21"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
# LAN host discovery: browse the host's `_punktfunk._udp` mDNS advert — the SAME crate + service the
|
# 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
|
# `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
|
# 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.
|
# `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
|
//! 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
|
//! 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
|
//! 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
|
# 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.
|
# client lives in clients/apple); on other platforms this builds as a stub binary.
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[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"] }
|
punktfunk-core = { path = "../../crates/punktfunk-core", features = ["quic"] }
|
||||||
|
|
||||||
# UI shell. GraphicsOffload needs GTK ≥ 4.14; black-background ≥ 4.16. AlertDialog/
|
# 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"] }
|
adw = { package = "libadwaita", version = "0.9", features = ["v1_5"] }
|
||||||
async-channel = "2"
|
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
|
# 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.
|
# at runtime (`dynamic`) so GPU-less boxes and the software path never touch libEGL.
|
||||||
khronos-egl = { version = "6", features = ["dynamic"] }
|
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"
|
serde_json = "1"
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|||||||
@@ -78,15 +78,15 @@ src/
|
|||||||
ui_trust.rs TOFU / PIN-pairing / request-access dialogs
|
ui_trust.rs TOFU / PIN-pairing / request-access dialogs
|
||||||
ui_settings.rs resolution · refresh · decoder · bitrate · compositor · mic
|
ui_settings.rs resolution · refresh · decoder · bitrate · compositor · mic
|
||||||
ui_stream.rs the stream window (GtkGraphicsOffload present) + input capture
|
ui_stream.rs the stream window (GtkGraphicsOffload present) + input capture
|
||||||
launch.rs · session.rs session launch/UI glue; lifecycle over the NativeClient connector
|
launch.rs session launch/UI glue over the shared session pump
|
||||||
video.rs FFmpeg VAAPI / software decode → dmabuf / texture
|
video_gl.rs VAAPI dmabuf → RGBA GL presenter (EGL import, CICP-driven CSC)
|
||||||
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)
|
|
||||||
tools/screenshots.sh store screenshot capture (app self-capture; Xvfb fallback)
|
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
|
## Related
|
||||||
|
|
||||||
- **[Documentation](https://docs.punktfunk.unom.io)** — quick start, pairing, troubleshooting
|
- **[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,
|
//! mirrors the Apple client: persistent identity, TOFU prompt with the host fingerprint,
|
||||||
//! SPAKE2 PIN pairing.
|
//! 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")]
|
#[cfg(target_os = "linux")]
|
||||||
mod app;
|
mod app;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
mod audio;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
mod cli;
|
mod cli;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
mod discovery;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
mod gamepad;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
mod keymap;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
mod launch;
|
mod launch;
|
||||||
#[cfg(target_os = "linux")]
|
#[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;
|
mod ui_gamepad_library;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
mod ui_hosts;
|
mod ui_hosts;
|
||||||
@@ -38,12 +30,8 @@ mod ui_stream;
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
mod ui_trust;
|
mod ui_trust;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
mod video;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
mod video_gl;
|
mod video_gl;
|
||||||
|
|
||||||
mod wol;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
fn main() -> gtk::glib::ExitCode {
|
fn main() -> gtk::glib::ExitCode {
|
||||||
app::run()
|
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 = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
# Loopback HTTPS poll of GET /api/v1/local/summary. Same sync ureq + rustls(ring) stack and
|
# 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
|
# 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).
|
# pins the ring provider explicitly anyway).
|
||||||
ureq = { version = "2", default-features = false, features = ["tls"] }
|
ureq = { version = "2", default-features = false, features = ["tls"] }
|
||||||
|
|||||||
Reference in New Issue
Block a user