diff --git a/docs/integrations/matrix.md b/docs/integrations/matrix.md index f94247a0..6f683403 100644 --- a/docs/integrations/matrix.md +++ b/docs/integrations/matrix.md @@ -8,7 +8,7 @@ homeserver, on one host. Two namespaces configure it: - `services.hyperhive.swarm.matrix.*` — what the homeserver **is**, as every hive sees it: `serverName`, `gatewayHost`, ports, `allowEncryption`. - `services.hyperhive.deploy.matrix.*` — what the host running it decides: - `enable`, `gui.enable`, `openFirewall`, `trustedServers`, + `enable`, `gui.package`, `openFirewall`, `trustedServers`, `maxRequestSize`, `sso.clientSecretFile`. Vhost routing lives in [`gateway.md`](../networking/gateway.md). diff --git a/docs/swarm/ui.md b/docs/swarm/ui.md index ce7ec349..99017caf 100644 --- a/docs/swarm/ui.md +++ b/docs/swarm/ui.md @@ -113,19 +113,19 @@ same whichever host runs each service: | Grafana | `services.hyperhive.swarm.grafana.domain` | | Metrics | `services.hyperhive.swarm.victoriametrics.domain` | | Logs | `services.hyperhive.swarm.victorialogs.domain` | +| Matrix | `services.hyperhive.swarm.matrix.gatewayHost` | -`nix/host-modules/swarm-controller.nix` builds these entries. The -Matrix and Forge entries, and `swarm-ui.nix`'s entry for this UI's own API -docs, come from those services' own modules, and only when the controller's -host runs that service. An operator can add entries directly. An -empty list hides the button. +`nix/host-modules/swarm-controller.nix` builds these entries. The Forge +entry, and `swarm-ui.nix`'s entry for this UI's own API docs, come from +those services' own modules, and only when the controller's host runs that +service. An operator can add entries directly. An empty list hides the +button. The **Matrix** entry opens the swarm's matrix web client (fluffychat, `services.hyperhive.deploy.matrix.gui.package`) at the homeserver's -gateway host, `chat.` by default. `hive-matrix.nix` adds it -only when `services.hyperhive.deploy.matrix.gui.enable` is on and the -homeserver has a gateway host, the same condition under which that vhost -serves the client at `/`. +gateway host, `chat.` by default. The homeserver's host +always serves the client at `/` on that vhost, so the entry is present +whenever the swarm names a gateway host.
Adding a swarm service name: the two wiring sites diff --git a/hive-c0re/src/dashboard/state_snapshot.rs b/hive-c0re/src/dashboard/state_snapshot.rs index 1d48e896..8f4db3ca 100644 --- a/hive-c0re/src/dashboard/state_snapshot.rs +++ b/hive-c0re/src/dashboard/state_snapshot.rs @@ -73,12 +73,6 @@ pub(super) struct StateSnapshot { /// links each container's config + each approval's commit into the /// forge's `agent-configs` repos. forge_present: bool, - /// Whether `services.hyperhive.deploy.matrix.gui.enable` is on. Sourced - /// from the `HIVE_MATRIX_GUI_ENABLED` env var the c0re NixOS module - /// sets. The matrix client itself is served on the homeserver's - /// gateway vhost; the hive's `/matrix/` path redirects there - /// (`nix/host-modules/hive-gateway/vhosts.nix`). - matrix_gui_enabled: bool, /// Whether `hive-gateway` is in front of this dashboard. Sourced /// from the `HIVE_GATEWAY_ENABLED` env var, which the c0re NixOS /// module now always sets (the gateway runs unconditionally @@ -313,17 +307,10 @@ pub(super) async fn api_state( tombstones, port_conflicts, forge_present: crate::forge::is_present().await, - matrix_gui_enabled: std::env::var_os("HIVE_MATRIX_GUI_ENABLED").is_some_and(|v| { - // Accept any truthy string ("1", "true", "yes") since the - // env var is set by NixOS module wiring with the literal - // "1"; defensive parse so manual overrides also work. - let s = v.to_string_lossy().to_ascii_lowercase(); - matches!(s.as_str(), "1" | "true" | "yes") - }), gateway_enabled: std::env::var_os("HIVE_GATEWAY_ENABLED").is_some_and(|v| { - // Same truthy-string parse as `matrix_gui_enabled`; the - // env var is set by the c0re NixOS module to the literal - // "1" — the gateway always runs alongside hyperhive. + // Accept any truthy string ("1", "true", "yes"): the c0re + // NixOS module sets the literal "1" (the gateway always runs + // alongside hyperhive), and manual overrides also parse. let s = v.to_string_lossy().to_ascii_lowercase(); matches!(s.as_str(), "1" | "true" | "yes") }), diff --git a/hivectl/src/open.rs b/hivectl/src/open.rs index 1a50062a..d25c9f52 100644 --- a/hivectl/src/open.rs +++ b/hivectl/src/open.rs @@ -30,7 +30,7 @@ pub(crate) async fn open_url(socket: &Path, target: OpenTarget) -> Result<()> { ), OpenTarget::Matrix => ( urls.matrix, - "the matrix GUI URL needs `services.hyperhive.deploy.matrix.gui.enable = true`", + "the matrix GUI URL needs `services.hyperhive.swarm.matrix.gatewayHost` set", ), }; let url = url.with_context(|| format!("no URL available for this surface — {hint}"))?; diff --git a/nix/host-modules/deploy.nix b/nix/host-modules/deploy.nix index b02f3f89..f52dd989 100644 --- a/nix/host-modules/deploy.nix +++ b/nix/host-modules/deploy.nix @@ -277,10 +277,16 @@ in The old token file at /var/lib/hyperhive/matrix-register-token is read by nothing now and can be deleted. See docs/integrations/matrix.md. '') - (lib.mkRenamedOptionModule - [ "services" "hyperhive" "swarm" "matrix" "gui" "enable" ] - [ "services" "hyperhive" "deploy" "matrix" "gui" "enable" ] - ) + (lib.mkRemovedOptionModule [ "services" "hyperhive" "swarm" "matrix" "gui" "enable" ] '' + The matrix web client has no on/off switch: every host that runs the + homeserver serves it at services.hyperhive.swarm.matrix.gatewayHost, + and the swarm UI links to it. Remove this definition. + '') + (lib.mkRemovedOptionModule [ "services" "hyperhive" "deploy" "matrix" "gui" "enable" ] '' + The matrix web client has no on/off switch: every host that runs the + homeserver serves it at services.hyperhive.swarm.matrix.gatewayHost, + and the swarm UI links to it. Remove this definition. + '') (lib.mkRenamedOptionModule [ "services" "hyperhive" "swarm" "matrix" "sso" "clientSecretFile" ] [ "services" "hyperhive" "deploy" "matrix" "sso" "clientSecretFile" ] diff --git a/nix/host-modules/hive-c0re/environment.nix b/nix/host-modules/hive-c0re/environment.nix index c16f8fa0..85cd8f84 100644 --- a/nix/host-modules/hive-c0re/environment.nix +++ b/nix/host-modules/hive-c0re/environment.nix @@ -191,12 +191,6 @@ in # one. HIVE_MATRIX_API_URL = config.services.hyperhive.swarm.matrix.apiUrl; } -// lib.optionalAttrs config.services.hyperhive.deploy.matrix.gui.enable { - # Surfaces as `matrix_gui_enabled` in the dashboard's `/api/state`. - # The matrix GUI is served entirely by the gateway nginx. Gateway - # routing detail: docs/networking/gateway.md::Vhost map. - HIVE_MATRIX_GUI_ENABLED = "1"; -} // { # The gateway always runs, so the dashboard always builds # same-origin `/agent//` links (never the direct @@ -216,19 +210,13 @@ in # forge links rather than emitting one it can't justify. HIVE_FORGE_PUBLIC_URL = config.services.hyperhive.swarm.forge.publicUrl; } -// - lib.optionalAttrs - ( - config.services.hyperhive.deploy.matrix.gui.enable - && config.services.hyperhive.swarm.matrix.gatewayHost != null - ) - { - # Browser-facing matrix GUI (fluffychat) URL — the gateway - # vhost (`gatewayHost`, `chat.` by default). Surfaced via the daemon's `Urls` - # request for `hivectl open matrix`. Absent when the GUI is off - # or no gatewayHost is set (no browser-reachable matrix vhost). - HIVE_MATRIX_PUBLIC_URL = "https://${config.services.hyperhive.swarm.matrix.gatewayHost}/"; - } +// lib.optionalAttrs (config.services.hyperhive.swarm.matrix.gatewayHost != null) { + # Browser-facing matrix GUI (fluffychat) URL — the gateway + # vhost (`gatewayHost`, `chat.` by default). Surfaced via the daemon's `Urls` + # request for `hivectl open matrix`. Absent when no gatewayHost is + # set (no browser-reachable matrix vhost). + HIVE_MATRIX_PUBLIC_URL = "https://${config.services.hyperhive.swarm.matrix.gatewayHost}/"; +} // lib.optionalAttrs (config.services.hyperhive.swarm.snapshotStore.address != null) { # `host:port` of the swarm's single snapshot store, for pushing agent # snapshots (hive-c0re::snapshot_push). One per swarm, not one per diff --git a/nix/host-modules/hive-gateway/vhosts.nix b/nix/host-modules/hive-gateway/vhosts.nix index 1e0491f3..ed915dd7 100644 --- a/nix/host-modules/hive-gateway/vhosts.nix +++ b/nix/host-modules/hive-gateway/vhosts.nix @@ -46,8 +46,7 @@ let # by default; legacy deep-link shim during the fluffychat sub-domain move). # See `docs/networking/gateway.md`. matrixRedirectLocations = - lib.optionalAttrs - (matrixDeployCfg.enable && matrixDeployCfg.gui.enable && matrixCfg.gatewayHost != null) + lib.optionalAttrs (matrixDeployCfg.enable && matrixCfg.gatewayHost != null) ( let target = "${publicScheme}://${matrixCfg.gatewayHost}${publicPortSuffix}"; diff --git a/nix/host-modules/hive-matrix.nix b/nix/host-modules/hive-matrix.nix index bcb767f5..aa7ac4fc 100644 --- a/nix/host-modules/hive-matrix.nix +++ b/nix/host-modules/hive-matrix.nix @@ -537,22 +537,6 @@ in ''; }; - gui.enable = lib.mkOption { - type = lib.types.bool; - default = deployCfg.matrix.enable; - defaultText = lib.literalExpression "config.services.hyperhive.deploy.matrix.enable"; - description = '' - Serve a matrix web client at `gatewayHost`'s vhost (`chat.` - by default) and add the swarm UI's **Matrix** quick link to it - (`services.hyperhive.swarm.controller.links`). Requires - `gatewayHost != null`; the gateway itself always runs. See - `docs/networking/gateway.md` for the discovery flow that lets clients - auto-find the sub-domain. The client build itself is - `deploy.matrix.gui.package` — which client, as opposed to whether - this host serves it. - ''; - }; - gui.package = lib.mkOption { type = lib.types.package; default = fluffychat-web-fixed; @@ -667,19 +651,6 @@ in # through the hive's dnsmasq whether or not the gateway fronts it. services.hyperhive.gateway.dns.enable = lib.mkDefault true; - # This swarm-ui quick-links entry. Gated on `gui.enable` too, not just - # `gatewayHost != null`: `/` on that vhost only serves fluffychat - # (below) when the GUI is on — otherwise the link would 404. See - # docs/swarm/ui.md::Quick links and - # `services.hyperhive.swarm.controller.links`'s description. - services.hyperhive.swarm.controller.links = - lib.optional (cfg.gatewayHost != null && deployCfg.matrix.gui.enable) - { - label = "Matrix"; - icon = "💬"; - url = "https://${cfg.gatewayHost}/"; - }; - # Accept-header SPA map, used only by the `/` location below (see # docs/networking/gateway.md "SPA fallback"): text/html → index.html, else a # sentinel so `try_files` falls through to 404. `appendHttpConfig` @@ -687,7 +658,7 @@ in # contributes instead of replacing it. # # The dashboard needs no equivalent — it routes by path. - services.nginx.appendHttpConfig = lib.optionalString deployCfg.matrix.gui.enable '' + services.nginx.appendHttpConfig = '' map $http_accept $matrix_spa_target { default "/__matrix_spa_no_html_fallback"; "~*text/html" "/index.html"; @@ -695,8 +666,8 @@ in ''; # `server_name = gatewayHost`. `/_matrix/*` → tuwunel (CORS `*`, 50M - # body cap, 1h long-poll timeout). `/` serves fluffychat, or 404 - # with the GUI off. nginx's longest-prefix rule puts `/_matrix/` + # body cap, 1h long-poll timeout). `/` serves fluffychat. nginx's + # longest-prefix rule puts `/_matrix/` # ahead of `/` with no ordering needed. # # ⚠️ The `.well-known/matrix/*` delegation is deliberately NOT here. @@ -727,8 +698,6 @@ in add_header Access-Control-Allow-Origin *; ''; }; - } - // lib.optionalAttrs deployCfg.matrix.gui.enable { # fluffychat at sub-domain root, SPA-fallback via the # Accept-header `$matrix_spa_target` map above. "/" = { @@ -746,11 +715,6 @@ in return 200 '{"defaultHomeserver":"${hyperhiveDomain}"}'; ''; }; - } - // lib.optionalAttrs (!deployCfg.matrix.gui.enable) { - "/" = { - return = "404"; - }; }; }; }; diff --git a/nix/host-modules/swarm-controller.nix b/nix/host-modules/swarm-controller.nix index c97a81e6..5167a65b 100644 --- a/nix/host-modules/swarm-controller.nix +++ b/nix/host-modules/swarm-controller.nix @@ -51,7 +51,14 @@ let icon = "📜"; inherit (swarmCfg.victorialogs) domain; } - ]; + ] + # A null `gatewayHost` means no vhost fronts the homeserver, so there is + # no web client to link to. + ++ lib.optional (swarmCfg.matrix.gatewayHost != null) { + label = "Matrix"; + icon = "💬"; + url = "https://${swarmCfg.matrix.gatewayHost}/"; + }; # Where the secret store is, and whether this host holds the controller's # own leaf for it. ⚠️ The controller's pair, NOT `deploy.bao.clientCertFile` @@ -451,8 +458,9 @@ in or swarm-ui change. The Authelia, Grafana, Metrics and Logs entries come from - `services.hyperhive.swarm..domain`, so they are present - whichever host runs each service. `hive-matrix.nix`, + `services.hyperhive.swarm..domain`, and the Matrix entry + from `services.hyperhive.swarm.matrix.gatewayHost` when it is set, + so they are present whichever host runs each service. `hive-forge/default.nix` and `swarm-ui.nix` contribute their own entries, and only where they are enabled on this host. diff --git a/nix/module-eval/swarm-services-switch.nix b/nix/module-eval/swarm-services-switch.nix index 7d68a1c2..57567c64 100644 --- a/nix/module-eval/swarm-services-switch.nix +++ b/nix/module-eval/swarm-services-switch.nix @@ -115,9 +115,9 @@ let Grafana = s.grafana.domain; Metrics = s.victoriametrics.domain; Logs = s.victorialogs.domain; + Matrix = s.matrix.gatewayHost; # forge: added once hive-forge/default.nix drops its per-host link - # matrix: added once its GUI gate is settled - # bao: added once its UI gate is settled + # bao: its web UI at `swarm.bao.ui.domain` has no link yet }; swarmServiceLinksOf = cfg: