feat(server): add per-domain web_events.sock router extension hook #39

Merged
rawdaGastan merged 2 commits from development_messaging_sse_subscribe into development 2026-05-04 12:42:46 +00:00
Member

Summary

Adds a generator hook so per-domain HTTP servers can register supplementary axum routes (e.g. SSE endpoints) on a dedicated web_events.sock, alongside the existing rpc.sock and ui.sock. Used by hero_osis to mount GET /events for the messaging archipelago's live update feed.

Backwards-compatible — domains without a registered extension are emitted exactly as before (extension: None, no extra socket bound).

Part of the multi-repo fix for hero_archipelagos #182 (messaging: no live updates — recipient must reload to see new messages).

This PR is the first of three:

  1. hero_rpc (this PR) — generator hook + spawn binding.
  2. hero_osis — server-side broadcaster + SSE endpoint + SDK subscribe().
  3. hero_archipelagos — UI consumer in the messaging archipelago.

Changes

crates/generator/src/build/build.rs

  • Adds OschemaBuildConfig::with_domain_router_ext(domain, fqfn) builder method backed by a new domain_router_ext: HashMap<String, String> field.
  • Both generator emission paths (single_bin and per_domain_bins) emit the extension: <expr> field on the generated DomainService literal — Some(<fqfn>()) if registered, None otherwise.

crates/server/src/server/spawn.rs

  • Adds an extension: Option<axum::Router> field on DomainService (default None).
  • When set, spawn_domain_server binds the router on a new $HERO_SOCKET_DIR/<service>/web_events.sock listener — sibling to rpc.sock and ui.sock. hero_router auto-discovers it via the standard web_<name>.sock convention (/<service>/eventsweb_events.sock at path /).
  • The RPC loop continues to use OServer::run() unchanged — the extension is not mounted on rpc.sock.

crates/server/src/server/server.rs and unified_server.rs

  • Adds OServer::run_with_extension(Option<Router>) and UnifiedServerBuilder::serve_with_extension(...) overloads. Existing run() / serve() delegate with None. (Kept for callers that want the legacy merge-onto-rpc.sock behaviour; the new spawn path no longer uses them.)

Test Plan

  • cargo check --workspace --lib --bins — clean.
  • cargo test -p hero_rpc_server -p hero_rpc_generator --lib — 13 + 105 tests pass, no regressions.
  • Pre-existing --all-targets failures in crates/osis/examples/ are unchanged from the development baseline (verified by stash + check).
  • Used end-to-end by the hero_osis PR — manual browser smoke confirmed live SSE updates arrive at the recipient without reload.

Notes

  • The per_domain_bins generator path still emits server.run_with_extension(<expr>) — would mount on rpc.sock like the original Step 1 design. We didn't update it because no current consumer uses that path. Worth a future cleanup to align with single_bin.
  • Cargo.lock and example regen drift in example/recipe_server/ are deliberately not committed.
## Summary Adds a generator hook so per-domain HTTP servers can register supplementary axum routes (e.g. SSE endpoints) on a dedicated `web_events.sock`, alongside the existing `rpc.sock` and `ui.sock`. Used by `hero_osis` to mount `GET /events` for the messaging archipelago's live update feed. Backwards-compatible — domains without a registered extension are emitted exactly as before (`extension: None`, no extra socket bound). ## Related Issue Part of the multi-repo fix for [hero_archipelagos #182](https://forge.ourworld.tf/lhumina_code/hero_archipelagos/issues/182) (messaging: no live updates — recipient must reload to see new messages). This PR is the first of three: 1. **hero_rpc** (this PR) — generator hook + spawn binding. 2. **hero_osis** — server-side broadcaster + SSE endpoint + SDK `subscribe()`. 3. **hero_archipelagos** — UI consumer in the messaging archipelago. ## Changes ### `crates/generator/src/build/build.rs` - Adds `OschemaBuildConfig::with_domain_router_ext(domain, fqfn)` builder method backed by a new `domain_router_ext: HashMap<String, String>` field. - Both generator emission paths (`single_bin` and `per_domain_bins`) emit the `extension: <expr>` field on the generated `DomainService` literal — `Some(<fqfn>())` if registered, `None` otherwise. ### `crates/server/src/server/spawn.rs` - Adds an `extension: Option<axum::Router>` field on `DomainService` (default `None`). - When set, `spawn_domain_server` binds the router on a new `$HERO_SOCKET_DIR/<service>/web_events.sock` listener — sibling to `rpc.sock` and `ui.sock`. hero_router auto-discovers it via the standard `web_<name>.sock` convention (`/<service>/events` → `web_events.sock` at path `/`). - The RPC loop continues to use `OServer::run()` unchanged — the extension is **not** mounted on `rpc.sock`. ### `crates/server/src/server/server.rs` and `unified_server.rs` - Adds `OServer::run_with_extension(Option<Router>)` and `UnifiedServerBuilder::serve_with_extension(...)` overloads. Existing `run()` / `serve()` delegate with `None`. (Kept for callers that want the legacy `merge`-onto-`rpc.sock` behaviour; the new spawn path no longer uses them.) ## Test Plan - [x] `cargo check --workspace --lib --bins` — clean. - [x] `cargo test -p hero_rpc_server -p hero_rpc_generator --lib` — 13 + 105 tests pass, no regressions. - [x] Pre-existing `--all-targets` failures in `crates/osis/examples/` are unchanged from the development baseline (verified by stash + check). - [x] Used end-to-end by the hero_osis PR — manual browser smoke confirmed live SSE updates arrive at the recipient without reload. ## Notes - The `per_domain_bins` generator path still emits `server.run_with_extension(<expr>)` — would mount on `rpc.sock` like the original Step 1 design. We didn't update it because no current consumer uses that path. Worth a future cleanup to align with `single_bin`. - `Cargo.lock` and example regen drift in `example/recipe_server/` are deliberately not committed.
feat(server): add with_domain_router_ext generator hook
Some checks failed
Test / test (pull_request) Successful in 1m9s
Test / test (push) Has been cancelled
5181978cb3
Lets consumer crates mount supplementary axum routes (e.g. SSE) on a
domain's rpc.sock. Backwards-compatible: existing callers pass None.

lhumina_code/hero_archipelagos#182
Merge branch 'development' of https://forge.ourworld.tf/lhumina_code/hero_rpc into development_messaging_sse_subscribe
All checks were successful
Test / test (push) Successful in 1m8s
Test / test (pull_request) Successful in 1m18s
e81ad7dc5a
rawdaGastan merged commit e512c1bf20 into development 2026-05-04 12:42:46 +00:00
rawdaGastan deleted branch development_messaging_sse_subscribe 2026-05-04 12:42:50 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_rpc!39
No description provided.