Commit Graph

3 Commits

Author SHA1 Message Date
27a6f4377c feat(cli): background the VPN daemon with re-exec + clean shutdown
`sunbeam connect` now fork-execs itself with a hidden `__vpn-daemon`
subcommand instead of running the daemon in-process. The user-facing
command spawns the child detached (stdio → log file, setsid for no
controlling TTY), polls the IPC socket until the daemon reaches
Running, prints a one-line status, and exits. The user gets back to
their shell immediately.

- src/cli.rs: `Connect { foreground }` instead of unit. Add hidden
  `__vpn-daemon` Verb that the spawned child runs.
- src/vpn_cmds.rs: split into spawn_background_daemon (default path)
  and run_daemon_foreground (used by both `connect --foreground` and
  `__vpn-daemon`). Detached child uses pre_exec(setsid) and inherits
  --context from the parent so it resolves the same VPN config.
  Refuses to start if a daemon is already running on the control
  socket; cleans up stale socket files. Switches the proxy bind from
  16443 (sienna's existing SSH tunnel uses it) to 16579.
- sunbeam-net/src/daemon/lifecycle: add a SocketGuard RAII type so the
  IPC control socket is unlinked when the daemon exits, regardless of
  shutdown path. Otherwise `vpn status` after a clean disconnect would
  see a stale socket and report an error.

End-to-end smoke test against the docker stack:
  $ sunbeam connect
  ==> VPN daemon spawned (pid 90072, ...)
      Connected (100.64.0.154, fd7a:115c:a1e0::9a) — 2 peers visible
  $ sunbeam vpn status
  VPN: running
    addresses: 100.64.0.154, fd7a:115c:a1e0::9a
    peers: 2
    derp home: region 0
  $ sunbeam disconnect
  ==> Asking VPN daemon to stop...
      Daemon acknowledged shutdown.
  $ sunbeam vpn status
  VPN: not running
2026-04-07 14:57:15 +01:00
7019937f6f feat(net): real IPC client + working remote shutdown
DaemonHandle's shutdown_tx (oneshot) is replaced with a CancellationToken
shared between the daemon loop and the IPC server. The token is the
single source of truth for "should we shut down" — `DaemonHandle::shutdown`
cancels it, and an IPC `Stop` request also cancels it.

- daemon/state: store the CancellationToken on DaemonHandle and clone it
  on Clone (so cached IPC handles can still trigger shutdown).
- daemon/ipc: IpcServer takes a daemon_shutdown token; `Stop` now cancels
  it instead of returning Ok and doing nothing. Add IpcClient with
  `request`, `status`, and `stop` methods so the CLI can drive a
  backgrounded daemon over the Unix socket.
- daemon/lifecycle: thread the token through run_daemon_loop and
  run_session, pass a clone to IpcServer::new.
- lib.rs: re-export IpcClient/IpcCommand/IpcResponse so callers don't
  have to reach into the daemon module.
- src/vpn_cmds.rs: `sunbeam disconnect` now actually talks to the daemon
  via IpcClient::stop, and `sunbeam vpn status` queries IpcClient::status
  and prints addresses + peer count + DERP home.
2026-04-07 14:46:47 +01:00
a57246fd9f feat(cli): wire sunbeam-net into sunbeam connect/disconnect/vpn
Adds the foreground VPN client commands. The daemon runs in-process
inside the CLI for the lifetime of `sunbeam connect` — no separate
background daemon yet, that can come later if needed.

- Cargo.toml: add sunbeam-net as a workspace dep, plus hostname/whoami
  for building a per-machine netmap label like "sienna@laptop"
- src/config.rs: new `vpn-url` and `vpn-auth-key` fields on Context
- src/cli.rs: `Connect`, `Disconnect`, and `Vpn { Status }` verbs
- src/vpn_cmds.rs: command handlers
  - cmd_connect reads VPN config from the active context, starts the
    daemon at ~/.sunbeam/vpn, polls for Running, then blocks on ^C
    before calling DaemonHandle::shutdown
  - cmd_disconnect / cmd_vpn_status are placeholders that report based
    on the control socket; actually talking to a backgrounded daemon
    needs an IPC client (not yet exposed from sunbeam-net)
- src/workflows/mod.rs: `..Default::default()` on Context literals so
  the new fields don't break the existing tests
2026-04-07 14:39:40 +01:00