zc2 0.0.30

P2P compute broker with credit-based billing, WAL, and broker mesh support
//! Host backend: a WireGuard tunnel zc didn't bring up (the WireGuard app, or
//! `wg-quick` with wireguard-go: a `utunN` interface on macOS) already gives
//! this host a mesh address. `zc connect` records it and starts nothing
//! (mesh-routes ยง2), and `zc disconnect` forgets it and leaves the tunnel alone.

use crate::vpn::connector::Connector;
use crate::vpn::profile::WgProfile;
use crate::vpn::{Backend, ConnectionInfo, LocalMesh, NetError};

#[derive(Default)]
pub struct HostConnector;

/// The connection a host tunnel provides, as zc records it.
pub fn info_for(mesh: &LocalMesh) -> ConnectionInfo {
    ConnectionInfo {
        backend: Backend::Host,
        address: mesh.ip.clone(),
        link: mesh.interface.clone(),
        peers: vec![],
        host_routable: true,
        proxy: None,
        relay: None,
    }
}

/// Record `mesh` as this host's connection. Saving is best effort, as with
/// every backend.
pub fn record(mesh: &LocalMesh) -> ConnectionInfo {
    let info = info_for(mesh);
    crate::vpn::state::save_or_warn(&info);
    info
}

impl Connector for HostConnector {
    fn available(&self) -> bool {
        crate::vpn::local_mesh().is_some()
    }

    fn connect(&self, _profile: &WgProfile) -> Result<ConnectionInfo, NetError> {
        crate::vpn::local_mesh()
            .map(|m| record(&m))
            .ok_or_else(|| NetError::Backend("no local interface has a mesh address".into()))
    }

    fn status(&self) -> Result<Option<ConnectionInfo>, NetError> {
        let recorded = crate::vpn::state::load().is_some_and(|s| s.backend == Backend::Host);
        Ok(recorded
            .then(crate::vpn::local_mesh)
            .flatten()
            .map(|m| info_for(&m)))
    }

    fn disconnect(&self) -> Result<(), NetError> {
        // The tunnel belongs to whoever brought it up: only forget it.
        let _ = crate::vpn::state::clear();
        Ok(())
    }
}