Closes build order items 7 (the systemd half) and 9 (D11 in deferrals.md). velox-nmhost (nmhost/src/main.cpp, 185 lines): a poll()-driven byte pump between Firefox's native-messaging framing on stdio (4-byte native-byte-order length prefix) and veloxd's own NDJSON framing on the Unix socket. Reframes each direction, no JSON parsing, no retry/backoff (the extension relaunches a fresh host on its own reconnect), exits the moment either side closes. Deliberately dependency-free — no veloxd_* library, no nlohmann_json — since it runs unconfined outside Firefox's sandbox regardless of packaging format. Two real bugs found and fixed while getting the integration test to actually pass rather than hang, both exactly the class of bug a "trivial pump" invites: 1. Never set the pumped fds non-blocking, so the "drain what's available" read loop blocked on its own second read() instead of returning to poll(). 2. stdin and stdout are two different descriptors (0 and 1), not one — an early draft polled POLLOUT on fd 0, which is opened read-only, so EOF and writability were never both observable through the same pollfd entry. packaging/nativehost/com.velox.host.json + its own README.md supersede AGENT-DAEMON.md's stale "four locations" line: spike S1 / ADR 0003 found only three manifest locations are real (~/.mozilla/native-messaging-hosts/ for BOTH deb/tarball and snap Firefox, /usr/lib/mozilla/... for deb/tarball only, the flatpak sandbox path) — the fourth, ~/snap/firefox/common/.mozilla/..., is not read by snap Firefox at all. The README spells out the per-user-manifest / postinst enumeration implication for PKG/QA (postinst runs once as root; the two ~/-relative locations are per-user) and flags that docs/07-packaging.md's own install-layout line only shows the one root-owned path. Socket activation: rpc/systemd_activation.cpp is a from-scratch sd_listen_fds() (env vars only — LISTEN_PID/LISTEN_FDS, fd 3 — no libsystemd link) that UdsServer::start() checks first, skipping its own create/bind/chmod/listen when systemd already bound the socket. packaging/systemd/velox.socket + velox.service are the unit pair, verified both by systemd-analyze verify and by an actual fork/dup2/execve simulation of the activation handshake — a real session.hello round-tripped over the handed-off fd with no bind() ever called inside the daemon for that run. velox.service deliberately skips ProtectSystem=/ProtectHome=/ReadWritePaths=: saveTo.allowedRoots is user-configurable to anywhere on the filesystem, and a sandbox here would turn a legitimately-configured save location into an opaque EROFS/EACCES instead of the daemon's own clear -32011. cli/man/velox.1 documents the CLI as it actually exists today (add/ls/pause/resume/rm, --json) — the queue/settings subcommands AGENT-DAEMON.md's build order originally sketched aren't implemented in cli/src/main.cpp yet, so the page doesn't claim they are. Checked warning-free with groff -mandoc -ww -z. Full ctest: 57/57 (excluding the pre-existing, unrelated conformance failure noted in earlier commits). Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01GRDjHGgpYmMoPE2UFbe7pP
39 lines
1.8 KiB
Desktop File
39 lines
1.8 KiB
Desktop File
[Unit]
|
|
Description=Velox download manager daemon
|
|
Documentation=man:velox(1)
|
|
# Socket activation (velox.socket) means this unit does not need to be enabled or started
|
|
# directly for the RPC transport to come up on demand — the first connection attempt after
|
|
# boot starts veloxd with the listening socket already bound (see velox.socket's own
|
|
# comment). Requires=/After= still matter for a manual `systemctl --user start velox`.
|
|
Requires=velox.socket
|
|
After=velox.socket
|
|
|
|
# Never more than one real instance for this user regardless of how it was started — the
|
|
# abstract-socket single-instance lock (main.cpp, keyed off the resolved runtime dir) is
|
|
# the actual enforcement; this just keeps systemd itself from racing two starts.
|
|
StartLimitIntervalSec=60
|
|
StartLimitBurst=5
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/usr/bin/veloxd
|
|
# main.cpp's SIGTERM handler stops the event loop and falls through to a clean shutdown
|
|
# (flushes buffers, closes the store, releases the single-instance lock) — the default
|
|
# KillSignal=SIGTERM and TimeoutStopSec are already the right shape for that; no
|
|
# ExecStop/KillMode override needed.
|
|
Restart=on-failure
|
|
RestartSec=2
|
|
|
|
# Hardening deliberately stops here, not at ProtectSystem=/ProtectHome=/ReadWritePaths=:
|
|
# saveTo.allowedRoots is user-configurable to anywhere (an external drive, a second
|
|
# mount — fs/safepath.hpp is the daemon's own validation boundary, not a fixed set of
|
|
# directories a unit file could enumerate up front). A filesystem-level sandbox here would
|
|
# silently turn a legitimately-configured save location into an opaque EROFS/EACCES the
|
|
# daemon can't explain, instead of its own clear -32011 — worse than no sandbox, for a
|
|
# download manager specifically. NoNewPrivileges is free of that trade-off.
|
|
NoNewPrivileges=yes
|
|
|
|
[Install]
|
|
WantedBy=default.target
|
|
Also=velox.socket
|