wsb-daemon 0.258.6441

wsb's daemon: the workbench, the GitHub mirror's schedule and peer continuity, for every workspace on the machine
use wsb::prelude::*;
use axum::{extract::State, http::StatusCode, Json};

use crate::web::state::WebState;

/// The version of the workspace this route was reached through.
///
/// From the state rather than from the process's directory: one daemon serves
/// every workspace on the machine, and its own directory belongs to none of
/// them.
pub async fn get_version(
    State(state): State<WebState>,
) -> Result<Json<serde_json::Value>, (StatusCode, Json<serde_json::Value>)> {
    let workspace_root = state.workspace_root.clone();
    let workspace_version =
        wsb::state::read_version_from_path(&workspace_root).map_err(internal_error)?;

    Ok(Json(serde_json::json!({
        "version": wsb::get_version(),
        // The machine the workbench is being served FROM, which is not always
        // the machine it is being read on: the daemon can serve a remote
        // browser, and a page that looked identical on two hosts is one an
        // operator can act on while looking at the wrong workspace.
        "host": machine_hostname(),
        "backend_build_id": env!("WSB_BACKEND_BUILD_ID"),
        "frontend_build_id": env!("WSB_FRONTEND_BUILD_ID"),
        "read_only": false,
        "workspace_root": workspace_root.display().to_string(),
        "workspace_version": workspace_version.full_version
    })))
}

/// This machine's name, as the operating system gives it.
///
/// `None` when it cannot be read. It is a label rather than a fact anything
/// acts on, so the page shows what it has and omits what it does not —
/// inventing "localhost" would be a wrong answer dressed as a right one.
#[cfg(unix)]
fn machine_hostname() -> Option<String> {
    let mut buffer = vec![0u8; 256];
    // SAFETY: the pointer and length describe `buffer`, which is live for the
    // whole call, and gethostname writes at most `len` bytes into it.
    let answered = unsafe { libc::gethostname(buffer.as_mut_ptr().cast(), buffer.len()) };
    if answered != 0 {
        return None;
    }
    // POSIX does not promise a terminator when the name was truncated, so the
    // whole buffer is the bound rather than a NUL that may not be there.
    let end = buffer.iter().position(|byte| *byte == 0).unwrap_or(buffer.len());
    buffer.truncate(end);
    let name = String::from_utf8(buffer).ok()?;
    let name = name.trim().to_string();
    (!name.is_empty()).then_some(name)
}

/// Windows publishes it in the environment, set by the system rather than by
/// a shell — so unlike unix's `HOSTNAME`, it is there to be read.
#[cfg(windows)]
fn machine_hostname() -> Option<String> {
    let name = std::env::var("COMPUTERNAME").ok()?;
    let name = name.trim().to_string();
    (!name.is_empty()).then_some(name)
}

fn internal_error(error: anyhow::Error) -> (StatusCode, Json<serde_json::Value>) {
    (
        StatusCode::INTERNAL_SERVER_ERROR,
        Json(serde_json::json!({
            "error": error.to_string()
        })),
    )
}