9c8fa9340c
apple / swift (push) Failing after 40s
audit / cargo-audit (push) Failing after 1m12s
windows-msix / package (push) Successful in 1m37s
windows / build (push) Successful in 1m14s
android / android (push) Successful in 4m48s
ci / web (push) Successful in 27s
ci / rust (push) Successful in 4m21s
ci / docs-site (push) Successful in 31s
ci / bench (push) Successful in 4m39s
decky / build-publish (push) Successful in 11s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
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 19s
deb / build-publish (push) Successful in 6m3s
flatpak / build-publish (push) Successful in 4m13s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m15s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m16s
docker / deploy-docs (push) Successful in 18s
Two bodies of work in one commit (the rename moved files the fixes also touched). Naming/structure cleanup (pre-launch): - Host modules m3.rs->punktfunk1.rs, m0.rs->spike.rs; CLI m3-host->punktfunk1-host, m0->spike; bare `punktfunk-host` now prints help. Types M3Options/M3Source-> Punktfunk1Options/Punktfunk1Source. - Clients consolidated out of crates/ into clients/: punktfunk-client-rs-> clients/probe (crate punktfunk-probe), client-linux->clients/linux, client-windows->clients/windows, punktfunk-android->clients/android/native (crate punktfunk-client-android; kept [lib] name=punktfunk_android so the JNI contract is unchanged). crates/ now holds only core + host. - Milestone codes M0-M4 purged from code/CLI/CLAUDE.md/README/docs/docs-site, kept only in docs/implementation-plan.md. docs/m2-plan.md-> docs/gamestream-host-plan.md. CI/gradle/flatpak paths updated. Client loss-recovery (video froze and never recovered after a brief drop): - Export punktfunk_connection_frames_dropped through the C ABI (the core already tracked it for the client keyframe-recovery loop; it was never reachable from the ABI clients). Regenerated punktfunk_core.h. - Apple (StreamPump + Stage2Pipeline) and Android (decode.rs) now poll frames_dropped and request a keyframe when it climbs -- the same loss-driven recovery Linux/Windows already had. Under infinite GOP the decoder silently conceals reference-missing frames, so the decode-error trigger rarely fires. Apple rumble robustness (worked then went spotty -- DualSense + Xbox): - Add CHHapticEngine stopped/reset handlers (rebuild on app background / audio interruption / server reset) and drop the permanent `broken` latch on a transient drive failure; latch only when the controller truly has no haptics. - Surface swallowed SDL set_rumble errors on Linux/Windows + diagnostic logging. Verified: cargo build/clippy/fmt --workspace, C-ABI harness, header drift. Not runnable on this box (verify in CI): Gitea workflows, gradle/Android, flatpak, Swift/decky. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
81 lines
4.3 KiB
Markdown
81 lines
4.3 KiB
Markdown
# punktfunk Windows client — MSIX packaging
|
|
|
|
The Windows client ships as a **signed MSIX** so Windows boxes get a real package (Start tile,
|
|
clean install/uninstall) instead of a loose exe. CI builds + publishes it from
|
|
[`.gitea/workflows/windows-msix.yml`](../../../.gitea/workflows/windows-msix.yml) to Gitea's
|
|
**generic** package registry (`https://git.unom.io/unom/-/packages`), on every `main` push that
|
|
touches the client and on `win-v*` release tags.
|
|
|
|
## What's in the package
|
|
|
|
`pack-msix.ps1` assembles a layout from a `cargo build --release` and runs `makeappx` + `signtool`:
|
|
|
|
| File | Source |
|
|
|---|---|
|
|
| `punktfunk-client.exe` | the release build |
|
|
| `Microsoft.WindowsAppRuntime.Bootstrap.dll`, `resources.pri` | auto-staged by windows-reactor's `build.rs` |
|
|
| `SDL3.dll` | auto-staged by the `sdl3` crate |
|
|
| `avcodec/avformat/avutil/swscale/swresample/...-*.dll` | `FFMPEG_DIR\bin` |
|
|
| `Assets\*.png` | checked-in tile/store logos (rasterized from `packaging/flatpak/io.unom.Punktfunk.svg`) |
|
|
| `AppxManifest.xml` | the template here, with `{VERSION}`/`{PUBLISHER}` substituted |
|
|
|
|
### Why an "unpackaged" WinUI app packages cleanly
|
|
|
|
windows-reactor calls `MddBootstrapInitialize2` with `OnPackageIdentity_NOOP`
|
|
(`crates/libs/reactor/src/app.rs`), so under MSIX **package identity** the App SDK bootstrapper is
|
|
a no-op and the runtime is resolved from the manifest's `<PackageDependency>` on
|
|
`Microsoft.WindowsAppRuntime.2` instead (reactor pins `WINDOWSAPPSDK_RELEASE_MAJORMINOR = 0x20000`
|
|
= 2.0). It's a full-trust Win32 app (`EntryPoint="Windows.FullTrustApplication"` + `runFullTrust`)
|
|
because it owns raw D3D11, Win32 low-level input hooks, WASAPI and SDL3.
|
|
|
|
## Versioning
|
|
|
|
MSIX requires a strictly 4-part numeric version. The workflow computes:
|
|
- `win-vX.Y.Z` tag → `X.Y.Z.0` (a real client release; `win-v*` is its own tag namespace, kept off
|
|
the host's `host-v*` and Apple's `v*` to avoid the version-shadow bug).
|
|
- `main` push / `workflow_dispatch` → `0.2.<run_number>.0` (rolling, climbs by run number).
|
|
|
|
## Signing & install
|
|
|
|
CI signs every build with a **stable self-signed code-signing cert** (`CN=unom`, SHA-1
|
|
`CD1EFDEEEC9743AFC38F56C5AF30C5A3009BE941`, valid to 2036). Its public half is checked in as
|
|
[`punktfunk-codesign.cer`](punktfunk-codesign.cer); the private `.pfx` + password live in the
|
|
`MSIX_CERT_PFX_B64` / `MSIX_CERT_PASSWORD` Actions secrets. Because it's the *same* cert every build,
|
|
trusting it is **one-time, per machine** — once imported, every future build and in-place upgrade is
|
|
trusted with no further prompt:
|
|
|
|
```powershell
|
|
# once per machine (elevated): trust the publisher
|
|
Import-Certificate -FilePath .\punktfunk-codesign.cer -CertStoreLocation Cert:\LocalMachine\TrustedPeople
|
|
# then install (and re-run for each upgrade — no re-trust needed)
|
|
Add-AppxPackage -Path .\punktfunk-client-windows_<ver>_x64.msix
|
|
```
|
|
|
|
The matching `.cer` is also published next to each `.msix` in the registry, so it's always at hand.
|
|
|
|
The MSIX declares a dependency on the Windows App SDK 2.x runtime; install
|
|
[the App SDK runtime](https://aka.ms/windowsappsdk) if `Add-AppxPackage` reports a missing
|
|
`Microsoft.WindowsAppRuntime.2` framework.
|
|
|
|
`pack-msix.ps1` signing precedence: it uses the **`MSIX_CERT_PFX_B64` / `MSIX_CERT_PASSWORD`** secrets
|
|
when present (the stable cert above), else generates an *ephemeral* self-signed cert (forks / local
|
|
builds without the secrets). Either way it exports the signing cert's public `.cer` for the import.
|
|
**To move to a publicly-trusted (no-import) cert** — Azure Artifact Signing or a public OV cert —
|
|
replace the two secrets with the new `.pfx`; the cert's subject DN must equal the manifest
|
|
`Publisher`, so pass a matching `-Publisher` (it's stamped into the package `Identity`, and changing
|
|
it changes the package identity → a one-time reinstall).
|
|
|
|
## Building locally
|
|
|
|
On the Windows runner / dev VM (MSVC + Windows SDK present), after a release build:
|
|
|
|
```powershell
|
|
cargo build --release -p punktfunk-client-windows
|
|
pwsh -File clients/windows/packaging/pack-msix.ps1 `
|
|
-Version 0.2.0.0 -TargetDir C:\t\release -OutDir C:\t\msix
|
|
```
|
|
|
|
Validated end-to-end on the build VM (pack → sign → `Add-AppxPackage` → framework-dependency
|
|
resolution). The only step that needs a real display is *launching* the WinUI window (same
|
|
on-glass constraint as the rest of the client).
|