Compare commits
3 changed files with 44 additions and 63 deletions
|
|
@ -51,6 +51,17 @@ pub async fn serve(port: u16, coord: Arc<Coordinator>) -> Result<()> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
tracing::info!(static_dir = %static_dir.display(), "dashboard static dir resolved");
|
tracing::info!(static_dir = %static_dir.display(), "dashboard static dir resolved");
|
||||||
|
// Optional matrix-GUI static dist (#607). When `HIVE_MATRIX_GUI_DIR`
|
||||||
|
// is set and the dir exists, mount it at `/matrix/` as a sibling
|
||||||
|
// ServeDir before the SPA fallback. Pre-#15 (nginx front) this
|
||||||
|
// is the simplest way to put fluffychat-web on the same origin as
|
||||||
|
// the dashboard so the operator has matrix chat one tab away.
|
||||||
|
let matrix_gui_dir: Option<PathBuf> = std::env::var_os("HIVE_MATRIX_GUI_DIR")
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.filter(|p| p.is_dir());
|
||||||
|
if let Some(dir) = &matrix_gui_dir {
|
||||||
|
tracing::info!(matrix_gui_dir = %dir.display(), "matrix GUI mount enabled at /matrix");
|
||||||
|
}
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/api/state", get(api_state))
|
.route("/api/state", get(api_state))
|
||||||
.route("/approve/{id}", post(post_approve))
|
.route("/approve/{id}", post(post_approve))
|
||||||
|
|
@ -92,6 +103,14 @@ pub async fn serve(port: u16, coord: Arc<Coordinator>) -> Result<()> {
|
||||||
// /static/dashboard.css → dist/static/dashboard.css, etc.).
|
// /static/dashboard.css → dist/static/dashboard.css, etc.).
|
||||||
.fallback_service(ServeDir::new(&static_dir))
|
.fallback_service(ServeDir::new(&static_dir))
|
||||||
.with_state(AppState { coord });
|
.with_state(AppState { coord });
|
||||||
|
// Sibling static mount for the optional matrix GUI dist. Layered
|
||||||
|
// before the SPA fallback so `/matrix/...` resolves there instead
|
||||||
|
// of falling through to the dashboard.
|
||||||
|
let app = if let Some(dir) = matrix_gui_dir {
|
||||||
|
app.nest_service("/matrix", ServeDir::new(dir))
|
||||||
|
} else {
|
||||||
|
app
|
||||||
|
};
|
||||||
let addr = SocketAddr::from(([0, 0, 0, 0], port));
|
let addr = SocketAddr::from(([0, 0, 0, 0], port));
|
||||||
let listener = bind_with_retry(addr).await?;
|
let listener = bind_with_retry(addr).await?;
|
||||||
tracing::info!(%port, "dashboard listening");
|
tracing::info!(%port, "dashboard listening");
|
||||||
|
|
@ -223,13 +242,10 @@ struct StateSnapshot {
|
||||||
/// links each container's config + each approval's commit into the
|
/// links each container's config + each approval's commit into the
|
||||||
/// forge's `agent-configs` repos.
|
/// forge's `agent-configs` repos.
|
||||||
forge_present: bool,
|
forge_present: bool,
|
||||||
/// Whether the matrix GUI is reachable at `/matrix/`. Sourced from
|
/// Whether the matrix GUI static dist is mounted at `/matrix/`
|
||||||
/// `HIVE_MATRIX_GUI_ENABLED` env var (set by the c0re NixOS module
|
/// (`HIVE_MATRIX_GUI_DIR` set + dir exists). Drives the dashboard's
|
||||||
/// when `services.hyperhive.matrix.gui.enable` is on). The gateway
|
/// `M4TR1X →` tab-strip entry so it doesn't flash a dead link when
|
||||||
/// (hive-gateway.nix) does the actual `/matrix/` static serving;
|
/// the operator hasn't opted in (#607).
|
||||||
/// this flag is just an availability signal for iris's dashboard
|
|
||||||
/// chrome so the `M4TR1X →` tab doesn't flash when the GUI is off
|
|
||||||
/// (#607, #634).
|
|
||||||
matrix_gui_enabled: bool,
|
matrix_gui_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -423,13 +439,9 @@ async fn api_state(headers: HeaderMap, State(state): State<AppState>) -> axum::J
|
||||||
port_conflicts,
|
port_conflicts,
|
||||||
rebuild_queue: state.coord.rebuild_queue.snapshot(),
|
rebuild_queue: state.coord.rebuild_queue.snapshot(),
|
||||||
forge_present: crate::forge::is_present().await,
|
forge_present: crate::forge::is_present().await,
|
||||||
matrix_gui_enabled: std::env::var_os("HIVE_MATRIX_GUI_ENABLED").is_some_and(|v| {
|
matrix_gui_enabled: std::env::var_os("HIVE_MATRIX_GUI_DIR")
|
||||||
// Accept any truthy string ("1", "true", "yes") since the
|
.map(PathBuf::from)
|
||||||
// env var is set by NixOS module wiring with the literal
|
.is_some_and(|p| p.is_dir()),
|
||||||
// "1"; defensive parse so manual overrides also work.
|
|
||||||
let s = v.to_string_lossy().to_ascii_lowercase();
|
|
||||||
matches!(s.as_str(), "1" | "true" | "yes")
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -241,15 +241,6 @@ in
|
||||||
# Agents poll this URL for Forgejo notifications. Derived from
|
# Agents poll this URL for Forgejo notifications. Derived from
|
||||||
# services.hyperhive.forge.{domain,httpPort} so it tracks forge config changes.
|
# services.hyperhive.forge.{domain,httpPort} so it tracks forge config changes.
|
||||||
HIVE_FORGE_URL = "http://${config.services.hyperhive.forge.domain}:${toString config.services.hyperhive.forge.httpPort}";
|
HIVE_FORGE_URL = "http://${config.services.hyperhive.forge.domain}:${toString config.services.hyperhive.forge.httpPort}";
|
||||||
}
|
|
||||||
// lib.optionalAttrs config.services.hyperhive.matrix.gui.enable {
|
|
||||||
# Availability flag for `/api/state.matrix_gui_enabled`. The
|
|
||||||
# gateway (hive-gateway.nix) does the actual static serving of
|
|
||||||
# fluffychat-web at `/matrix/`; c0re doesn't host the dist
|
|
||||||
# itself (#634, mara on PR #620). This env var just tells the
|
|
||||||
# dashboard chrome whether the GUI is reachable so iris's
|
|
||||||
# `M4TR1X →` tab doesn't show when the GUI is off.
|
|
||||||
HIVE_MATRIX_GUI_ENABLED = "1";
|
|
||||||
};
|
};
|
||||||
# Matrix GUI static serving lives entirely on the hive-gateway
|
# Matrix GUI static serving lives entirely on the hive-gateway
|
||||||
# nginx since #609 — when gateway is off the operator opts out
|
# nginx since #609 — when gateway is off the operator opts out
|
||||||
|
|
|
||||||
|
|
@ -159,56 +159,34 @@ in
|
||||||
gui = {
|
gui = {
|
||||||
enable = lib.mkOption {
|
enable = lib.mkOption {
|
||||||
type = lib.types.bool;
|
type = lib.types.bool;
|
||||||
default = cfg.enable;
|
default = false;
|
||||||
defaultText = lib.literalExpression "config.services.hyperhive.matrix.enable";
|
|
||||||
description = ''
|
description = ''
|
||||||
Serve a matrix web client (default `pkgs.fluffychat-web`) as
|
Mount a matrix web client (default `pkgs.fluffychat-web`) as
|
||||||
a static dist at `/matrix/` via the hive-gateway nginx
|
a static sibling of the dashboard at `/matrix/`, served by
|
||||||
(#607 / #634). Defaults to whatever
|
hive-c0re's own axum router via the `HIVE_MATRIX_GUI_DIR`
|
||||||
`services.hyperhive.matrix.enable` is — turning on the
|
env var (#607 v0). Off by default; flip to `true` once the
|
||||||
homeserver gives you the web client by default; set to
|
operator wants matrix chat one tab away from the dashboard
|
||||||
`false` explicitly to opt out of the GUI while keeping
|
without standing up a separate gateway.
|
||||||
the homeserver running for agents. Requires
|
|
||||||
`services.hyperhive.gateway.enable` (default on); when
|
|
||||||
gateway is off no one hosts the GUI and the
|
|
||||||
`M4TR1X →` dashboard tab is hidden.
|
|
||||||
|
|
||||||
fluffychat-web supports per-login server pick — point it at
|
Same-origin via hive-c0re is the simplest single-host
|
||||||
the in-host tuwunel URL (`http://localhost:8008` by
|
shape; the post-#15 nginx-front re-root (`https://matrix.''${services.hyperhive.domain}`)
|
||||||
default) the first time. The post-#15 nginx-front re-root
|
is tracked separately in #609. fluffychat-web supports
|
||||||
(`https://matrix.''${services.hyperhive.domain}`) is tracked
|
per-login server pick — point it at the in-host tuwunel URL
|
||||||
separately in #609.
|
(`http://localhost:8008` by default) the first time.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
package = lib.mkOption {
|
package = lib.mkOption {
|
||||||
type = lib.types.package;
|
type = lib.types.package;
|
||||||
default = pkgs.fluffychat-web.overrideAttrs (old: {
|
default = pkgs.fluffychat-web;
|
||||||
# fluffychat-web ships with `<base href="/">` baked into its
|
defaultText = lib.literalExpression "pkgs.fluffychat-web";
|
||||||
# index.html — flutter's `--base-href` build flag replaces
|
|
||||||
# that placeholder. Default upstream build is `--base-href "/"`
|
|
||||||
# which is wrong for hyperhive's `/matrix/` sub-path mount:
|
|
||||||
# the browser resolves relative asset paths (`Imaging.js`,
|
|
||||||
# `flutter.js`, `splash/*`) against the document ROOT,
|
|
||||||
# producing 404s for every asset (#634). Inject the right
|
|
||||||
# base-href into the build via nixpkgs's `buildFlutterApplication`
|
|
||||||
# targetFlags. When subdomain routing lands (#609 —
|
|
||||||
# `matrix.${hyperhiveDomain}`), drop this override; upstream's
|
|
||||||
# `/` base-href is correct at the root of a dedicated subdomain.
|
|
||||||
targetFlags = (old.targetFlags or [ ]) ++ [
|
|
||||||
"--base-href"
|
|
||||||
"/matrix/"
|
|
||||||
];
|
|
||||||
});
|
|
||||||
defaultText = lib.literalMD "`pkgs.fluffychat-web` rebuilt with `--base-href /matrix/` via `targetFlags`.";
|
|
||||||
description = ''
|
description = ''
|
||||||
Static web client dist to serve at `/matrix/`. Defaults to
|
Static web client dist to serve at `/matrix/`. Defaults to
|
||||||
`pkgs.fluffychat-web` rebuilt with `--base-href "/matrix/"`
|
`pkgs.fluffychat-web` — first-class threads support, e2ee
|
||||||
so relative asset paths resolve under the sub-path mount
|
+ voice + spaces, full feature surface in the flutter→web
|
||||||
(#634). Override to swap for `hydrogen-web` (lightest),
|
build. Override to swap for `hydrogen-web` (lightest),
|
||||||
`cinny` (no threads), `element-web` (heaviest, full
|
`cinny` (no threads), `element-web` (heaviest, full
|
||||||
features), or an out-of-tree client dist — any replacement
|
features), or an out-of-tree client dist.
|
||||||
also needs its `<base href>` aligned with the mount path.
|
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue