docs(design): trim shipped plans, consolidate cluster, add index
Much of design/ described work that has since shipped. Trim each doc to
its durable rationale + still-open items (the code is the source of truth
for shipped detail; git history holds the full originals).
- Shipped plans -> status stubs: stats-capture, gamestream-host-plan,
apple-stage2-presenter, windows-service.
- Trimmed completed-out / open-kept: implementation-plan, hdr-pipeline,
host-latency, gpu-contention (fixed stale status table), game-library,
linux-setup (fixed m0->spike + stale zero-copy claim),
session-aware-host-followups, windows-client-bootstrap,
windows-dualsense-{scoping,game-detection}, windows-virtual-display,
security-review (per-finding status table; #12 still open),
apollo-comparison (shipped backlog collapsed to one-liners).
- Windows-host cluster consolidated: windows-host.md -> redirect into
windows-host-rewrite.md (whose stale scorecard is corrected -- goal1 is
merged, M4 done); windows-secure-desktop.md archived (now a fallback
behind IDD-push primary).
- Kept evergreen: ci.md, gamescope-multiuser.md, windows-build-and-packaging.md.
- New design/README.md: per-doc status table + consolidated open-items
roll-up so nothing is tracked in only one buried doc.
- Repoint 5 code comments to the archived secure-desktop doc path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+20
-101
@@ -1,110 +1,29 @@
|
||||
# Windows service (deployment)
|
||||
|
||||
The `PunktfunkHost` Windows service is the end-user way to run the host on Windows. It replaces the
|
||||
manual bring-up chain (a scheduled task → `PsExec64 -s -i 1` → `wscript launch.vbs` → `host-run.cmd`)
|
||||
with one command, auto-start on boot, and supervision.
|
||||
**Status: SHIPPED.** The `PunktfunkHost` LocalSystem SCM service is the end-user way to run the host
|
||||
on Windows, installed by the signed Inno Setup installer. Sources / details:
|
||||
|
||||
## Install (installer — recommended)
|
||||
- `crates/punktfunk-host/src/windows/service.rs` — the supervisor.
|
||||
- [`packaging/windows/README.md`](../packaging/windows/README.md) — installer + driver packaging.
|
||||
- `punktfunk-host service --help` — install / start / stop / status / uninstall.
|
||||
|
||||
Download the signed installer from the package registry
|
||||
(`punktfunk-host-windows`, <https://git.unom.io/unom/-/packages>) and run it (it elevates itself):
|
||||
## Why it works the way it does (the durable rationale)
|
||||
|
||||
```
|
||||
punktfunk-host-setup-<ver>.exe # wizard
|
||||
punktfunk-host-setup-<ver>.exe /VERYSILENT # unattended
|
||||
```
|
||||
The host must capture the **secure desktop** (UAC / lock / login) and inject input there. Desktop
|
||||
Duplication of the secure desktop and `SendInput` both require **SYSTEM**, while capture and injection
|
||||
require the **interactive console session** — which a plain Session-0 service is *not* in. One process
|
||||
must therefore be SYSTEM *and* in the interactive session.
|
||||
|
||||
It lays the host into `C:\Program Files\punktfunk`, optionally installs the bundled **SudoVDA**
|
||||
virtual-display driver, then runs `service install` + `service start` for you. Upgrades stop the
|
||||
service first and re-point it; uninstall (Add/Remove Programs) runs `service uninstall`. Packaging
|
||||
details: [`packaging/windows/README.md`](../packaging/windows/README.md). A self-signed CI build also
|
||||
publishes a `.cer` — import it once (`Import-Certificate -FilePath punktfunk-host-windows.cer
|
||||
-CertStoreLocation Cert:\LocalMachine\TrustedPublisher`) so Windows trusts the signed setup.
|
||||
The service resolves this the same way Sunshine/Apollo do: it runs as **LocalSystem in Session 0** but
|
||||
**never captures**. Instead it duplicates its own LocalSystem token, retargets it to the active console
|
||||
session (`SetTokenInformation(TokenSessionId)`), and launches the host there with
|
||||
`CreateProcessAsUserW` (`lpDesktop = winsta0\default`) — supervising it across exits and console-session
|
||||
switches, with a kill-on-close Job Object so a service crash never orphans the SYSTEM host.
|
||||
|
||||
## Install (manual / CLI)
|
||||
`service run` is the **SCM entry point only** — don't run it by hand (it errors with a hint).
|
||||
|
||||
From an **elevated** (Administrator) prompt:
|
||||
## Open item — graceful stop
|
||||
|
||||
```powershell
|
||||
punktfunk-host service install # register auto-start LocalSystem service + firewall rules + default host.env
|
||||
punktfunk-host service start # start it now (also starts automatically on every boot)
|
||||
```
|
||||
|
||||
`service install` is idempotent — run it again after upgrading the exe to re-point the service at the
|
||||
new binary. Register whatever location you keep the exe in (e.g. `C:\Program Files\punktfunk\`); the
|
||||
service records the current exe path.
|
||||
|
||||
Other subcommands:
|
||||
|
||||
```powershell
|
||||
punktfunk-host service stop
|
||||
punktfunk-host service status
|
||||
punktfunk-host service uninstall # stop + delete the service + remove its firewall rules
|
||||
```
|
||||
|
||||
## How it works
|
||||
|
||||
The host must run **as SYSTEM in the interactive session** (Session 1+): Desktop Duplication of the
|
||||
secure desktop (UAC / lock / login) and `SendInput` need SYSTEM, and capture/injection need the
|
||||
interactive session, which a plain Session-0 service is not in.
|
||||
|
||||
So the service (itself in Session 0) **never captures**. On start, and whenever the active console
|
||||
session changes, it:
|
||||
|
||||
1. resolves the active console session (`WTSGetActiveConsoleSessionId`),
|
||||
2. duplicates its own LocalSystem token and retargets it to that session (`SetTokenInformation`
|
||||
`TokenSessionId`),
|
||||
3. launches the host there with `CreateProcessAsUserW` (`lpDesktop = winsta0\default`),
|
||||
4. supervises it: relaunches on exit/crash (with backoff) and on a console connect/disconnect.
|
||||
|
||||
A kill-on-close **job object** ensures a service crash never orphans the SYSTEM host. The host in turn
|
||||
spawns the WGC helper into the *user* session (see [`windows-secure-desktop.md`](windows-secure-desktop.md))
|
||||
— two nested launches. Lock/unlock are handled inside the host (the `DesktopWatcher` DDA↔WGC mux), so
|
||||
the service deliberately does **not** relaunch on lock/unlock — only on a real session switch.
|
||||
|
||||
This is the same model Sunshine/Apollo use.
|
||||
|
||||
## Configuration
|
||||
|
||||
Config lives in **`%ProgramData%\punktfunk\host.env`** (KEY=VALUE lines, `#` comments). `service
|
||||
install` writes a default if none exists. Template: [`scripts/windows/host.env.example`](../scripts/windows/host.env.example).
|
||||
|
||||
```ini
|
||||
PUNKTFUNK_ENCODER=nvenc
|
||||
PUNKTFUNK_VIDEO_SOURCE=virtual
|
||||
PUNKTFUNK_SECURE_DDA=1
|
||||
RUST_LOG=info
|
||||
# PUNKTFUNK_HOST_CMD=serve --gamestream # the host subcommand the service launches (default: native + Moonlight)
|
||||
```
|
||||
|
||||
The service loads these into its environment and carries `PUNKTFUNK_*` + `RUST_LOG` to the host child
|
||||
(the same env-merge the WGC helper uses). Restart the service after editing:
|
||||
|
||||
```powershell
|
||||
punktfunk-host service stop; punktfunk-host service start
|
||||
```
|
||||
|
||||
The host's identity (cert/pairing/mgmt token/library) also lives under `%ProgramData%\punktfunk` — a
|
||||
machine-wide dir the SYSTEM service and the interactive user share, surviving user logout.
|
||||
`PUNKTFUNK_CONFIG_DIR` overrides the location (both platforms; handy for tests).
|
||||
|
||||
## Logs
|
||||
|
||||
- `%ProgramData%\punktfunk\logs\service.log` — the service's own supervision log (spawn/exit/session
|
||||
switches).
|
||||
- `%ProgramData%\punktfunk\logs\host.log` — the host child's stdout/stderr.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The host built with `--features nvenc` for NVENC (the driver ships `nvEncodeAPI64.dll`; no SDK
|
||||
needed at runtime). Software encode otherwise.
|
||||
- The **SudoVDA** indirect display driver installed (for `PUNKTFUNK_VIDEO_SOURCE=virtual`).
|
||||
- **ViGEmBus** for virtual gamepads (optional).
|
||||
|
||||
## Gotchas
|
||||
|
||||
- `service install`/`uninstall` need an **elevated** prompt (the SCM rejects non-admin).
|
||||
- `service run` is the SCM entry point — don't run it by hand (it errors with a hint).
|
||||
- A **graceful** stop currently `TerminateProcess`es the host, so its RAII teardown (SudoVDA monitor
|
||||
REMOVE) doesn't run; a stale virtual monitor can linger until the next start. A cooperative-stop
|
||||
signal is a follow-up.
|
||||
A service stop currently `TerminateProcess`es the host, which **skips RAII teardown**, so a stale
|
||||
virtual monitor can linger until the next start. The follow-up is a cooperative-stop signal
|
||||
(event/pipe) that lets the host unwind cleanly before exit.
|
||||
|
||||
Reference in New Issue
Block a user