refactor #15

Closed
opened 2026-04-06 08:51:12 +00:00 by despiegk · 3 comments
Owner

hero_router_server

  • has all the routing functionality (proxy, ...)
  • All UI sockets are now HTML-only. RPC routing (POST /rpc, GET /openrpc.json) is exclusively handled by hero_router mapping //rpc/ → rpc.sock., so router does this for each /admin/ ($name_ui) service, so we automatically proxy this

hero_router_ui

  • admin UI only
  • uses hero_router_sdk or directly the openrpc on sockets/hero_router/rpc (there is cors there so ok)

skills to use

/hero_sockets

## hero_router_server - has all the routing functionality (proxy, ...) - All UI sockets are now HTML-only. RPC routing (POST /rpc, GET /openrpc.json) is exclusively handled by hero_router mapping /<service>/rpc/ → rpc.sock., so router does this for each /admin/ ($name_ui) service, so we automatically proxy this ## hero_router_ui - admin UI only - uses hero_router_sdk or directly the openrpc on sockets/hero_router/rpc (there is cors there so ok) ## skills to use /hero_sockets
Author
Owner

Implementation Spec — Issue #15: Refactor

Objective

Decouple hero_router_ui from its own independent socket scanner and make it consume service data from hero_router_server via proxied RPC calls to the server socket. Make hero_router_ui a pure dashboard consumer. Also enforce that ui.sock sockets are HTML-only during probing.

What is already done

  • hero_router_server (9998) runs build_proxy_router — all /<service>/rpc, /<service>/admin, /:webname routing
  • hero_router_ui (9997) runs build_dashboard_router — HTML dashboard only, no proxy routes
  • CORS enabled on server for /rpc
  • Flat socket support removed, per-service directory layout only
  • derive_group_name correctly handles per-service paths

What still needs to be done

Step 1 — Fix probe_ui_socket to be HTML-only

File: crates/hero_router/src/scanner.rs

Remove try_http_openrpc_discover call from probe_ui_socket. ui.sock is HTML-only by spec. Remove the OpenRPC probing block — only check_health + fetch_heroservice_manifest + check_serves_html. Always assign protocols = vec![ServiceProtocol::Web].

Step 2 — Add server_socket field to AppState

File: crates/hero_router/src/server/routes.rs

Add pub server_socket: Option<String> to AppState. When Some(path), the dashboard RPC/SSE handlers proxy to that socket instead of dispatching locally. build_proxy_router sets it to None; build_dashboard_router receives it as part of AppState.

Step 3 — Proxy /rpc in build_dashboard_router

File: crates/hero_router/src/server/routes.rs

In rpc_handler: when state.server_socket is Some(path), forward the raw POST body to path at /rpc using the existing proxy_to_socket infrastructure. Return the proxied response. When None, dispatch locally as now.

For /api/events SSE: update the dashboard JS (EventSource) to point at http://localhost:9998/api/events directly (CORS is open) rather than bridging in Rust.

Step 4 — Remove scanner/cache from hero_router_ui

File: crates/hero_router_ui/src/main.rs

Remove: Scanner, RouterCache, Manifest, SseBroadcaster, RpcState construction, spawn_discovery calls, and the self-registration block. The UI only needs RouterConfig, SocketProxy, and HeroUiServer. Pass server_socket = Some(cfg.server_socket_path_flat().to_string_lossy().to_string()) into AppState.

Step 5 — Move self-registration to server

File: crates/hero_router_server/src/main.rs

Move the "Hero Router" self-registration block (pinned ServiceEntry) from the UI into the server's build_and_start.

Acceptance Criteria

  • probe_ui_socket never calls try_http_openrpc_discover
  • hero_router_ui contains no Scanner, RouterCache, or RpcState construction
  • Dashboard /rpc calls proxy to hero_router_server.sock
  • Self-registration is in hero_router_server, not hero_router_ui
  • cargo build --workspace passes
# Implementation Spec — Issue #15: Refactor ## Objective Decouple `hero_router_ui` from its own independent socket scanner and make it consume service data from `hero_router_server` via proxied RPC calls to the server socket. Make `hero_router_ui` a pure dashboard consumer. Also enforce that `ui.sock` sockets are HTML-only during probing. ## What is already done - `hero_router_server` (9998) runs `build_proxy_router` — all `/<service>/rpc`, `/<service>/admin`, `/:webname` routing - `hero_router_ui` (9997) runs `build_dashboard_router` — HTML dashboard only, no proxy routes - CORS enabled on server for `/rpc` - Flat socket support removed, per-service directory layout only - `derive_group_name` correctly handles per-service paths ## What still needs to be done ### Step 1 — Fix `probe_ui_socket` to be HTML-only **File:** `crates/hero_router/src/scanner.rs` Remove `try_http_openrpc_discover` call from `probe_ui_socket`. `ui.sock` is HTML-only by spec. Remove the OpenRPC probing block — only `check_health` + `fetch_heroservice_manifest` + `check_serves_html`. Always assign `protocols = vec![ServiceProtocol::Web]`. ### Step 2 — Add `server_socket` field to `AppState` **File:** `crates/hero_router/src/server/routes.rs` Add `pub server_socket: Option<String>` to `AppState`. When `Some(path)`, the dashboard RPC/SSE handlers proxy to that socket instead of dispatching locally. `build_proxy_router` sets it to `None`; `build_dashboard_router` receives it as part of `AppState`. ### Step 3 — Proxy `/rpc` in `build_dashboard_router` **File:** `crates/hero_router/src/server/routes.rs` In `rpc_handler`: when `state.server_socket` is `Some(path)`, forward the raw POST body to `path` at `/rpc` using the existing `proxy_to_socket` infrastructure. Return the proxied response. When `None`, dispatch locally as now. For `/api/events` SSE: update the dashboard JS (`EventSource`) to point at `http://localhost:9998/api/events` directly (CORS is open) rather than bridging in Rust. ### Step 4 — Remove scanner/cache from `hero_router_ui` **File:** `crates/hero_router_ui/src/main.rs` Remove: `Scanner`, `RouterCache`, `Manifest`, `SseBroadcaster`, `RpcState` construction, `spawn_discovery` calls, and the self-registration block. The UI only needs `RouterConfig`, `SocketProxy`, and `HeroUiServer`. Pass `server_socket = Some(cfg.server_socket_path_flat().to_string_lossy().to_string())` into `AppState`. ### Step 5 — Move self-registration to server **File:** `crates/hero_router_server/src/main.rs` Move the "Hero Router" self-registration block (pinned `ServiceEntry`) from the UI into the server's `build_and_start`. ## Acceptance Criteria - [ ] `probe_ui_socket` never calls `try_http_openrpc_discover` - [ ] `hero_router_ui` contains no `Scanner`, `RouterCache`, or `RpcState` construction - [ ] Dashboard `/rpc` calls proxy to `hero_router_server.sock` - [ ] Self-registration is in `hero_router_server`, not `hero_router_ui` - [ ] `cargo build --workspace` passes
Author
Owner

Test Results

Date: 2026-04-06
Status: PASS

Summary

All tests passed. The workspace compiled successfully in 13.19s.

Crates Tested

Crate Tests Run Passed Failed
hero_router_examples 0 0 0
hero_router_sdk 0 0 0
hero_router_server 0 0 0
hero_router_ui 0 0 0
herolib_router 0 0 0
hero_router (bin) 0 0 0

Doc Tests

Crate Tests Run Passed Failed
hero_router_examples 0 0 0
hero_router_sdk 0 0 0
herolib_router 0 0 0

Command

cargo test --workspace

Output

Compiling herolib_router v0.1.0
Compiling hero_router_examples v0.1.0
Compiling hero_router_sdk v0.1.0
Compiling hero_router_ui v0.1.0
Compiling hero_router_server v0.1.0
Finished `test` profile [unoptimized + debuginfo] target(s) in 13.19s

All test suites: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

Note: No unit tests are currently defined in the workspace. All crates compiled without errors.

## Test Results **Date:** 2026-04-06 **Status:** PASS ### Summary All tests passed. The workspace compiled successfully in 13.19s. ### Crates Tested | Crate | Tests Run | Passed | Failed | |-------|-----------|--------|--------| | `hero_router_examples` | 0 | 0 | 0 | | `hero_router_sdk` | 0 | 0 | 0 | | `hero_router_server` | 0 | 0 | 0 | | `hero_router_ui` | 0 | 0 | 0 | | `herolib_router` | 0 | 0 | 0 | | `hero_router` (bin) | 0 | 0 | 0 | ### Doc Tests | Crate | Tests Run | Passed | Failed | |-------|-----------|--------|--------| | `hero_router_examples` | 0 | 0 | 0 | | `hero_router_sdk` | 0 | 0 | 0 | | `herolib_router` | 0 | 0 | 0 | ### Command ``` cargo test --workspace ``` ### Output ``` Compiling herolib_router v0.1.0 Compiling hero_router_examples v0.1.0 Compiling hero_router_sdk v0.1.0 Compiling hero_router_ui v0.1.0 Compiling hero_router_server v0.1.0 Finished `test` profile [unoptimized + debuginfo] target(s) in 13.19s All test suites: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` > Note: No unit tests are currently defined in the workspace. All crates compiled without errors.
Author
Owner

Implementation committed: 5a1ae0f

Browse: 5a1ae0f

Changes

  • scanner.rsprobe_ui_socket is now HTML-only (removed OpenRPC probing from ui.sock)
  • routes.rsAppState gains server_socket: Option<String>; rpc_handler proxies to server when set
  • hero_router_server/main.rs — self-registration moved from UI to server (authoritative cache owner)
  • hero_router_ui/main.rsspawn_discovery removed; replaced with spawn_cache_sync (SDK-based 30s sync from server); /rpc proxies to hero_router_server.sock
  • hero_router_ui/Cargo.toml — added hero_router_sdk dependency
Implementation committed: `5a1ae0f` Browse: https://forge.ourworld.tf/lhumina_code/hero_router/commit/5a1ae0f ## Changes - `scanner.rs` — `probe_ui_socket` is now HTML-only (removed OpenRPC probing from `ui.sock`) - `routes.rs` — `AppState` gains `server_socket: Option<String>`; `rpc_handler` proxies to server when set - `hero_router_server/main.rs` — self-registration moved from UI to server (authoritative cache owner) - `hero_router_ui/main.rs` — `spawn_discovery` removed; replaced with `spawn_cache_sync` (SDK-based 30s sync from server); `/rpc` proxies to `hero_router_server.sock` - `hero_router_ui/Cargo.toml` — added `hero_router_sdk` dependency
Sign in to join this conversation.
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_router#15
No description provided.