Skip to content

Host the Hub broker on a foreign listener; drop the shelf endpoint (v1.56.0)#112

Merged
gmpassos merged 2 commits into
masterfrom
feat/hub-service-mount
Jul 12, 2026
Merged

Host the Hub broker on a foreign listener; drop the shelf endpoint (v1.56.0)#112
gmpassos merged 2 commits into
masterfrom
feat/hub-service-mount

Conversation

@gmpassos

Copy link
Copy Markdown
Contributor

Why

The Hub broker can now be hosted on a listener OmnyShell does not own — so another Hub (an OmnyServer Hub) can serve OmnyShell nodes on its own port, at its own path, beside its own surfaces. One Hub, one certificate, one port, two kinds of node.

The integration is one method

Two things made this a wiring job rather than a rewrite:

  • HubBroker was already transport-agnostic — its entry point is void accept(OmnyShellConnection), it owns no listener, and its own doc says so. The only thing tying it to a socket was a 72-line WsServerEndpoint.
  • FrameConnection.wrap(omnyhub.Connection) already existed, and omnyhub's Service.handleConnection hands over exactly that type.
class OmnyShellHubService extends omnyhub.ServiceBase {
  @override
  void handleConnection(omnyhub.Connection connection, omnyhub.HubRequest request) =>
      broker.accept(FrameConnection.wrap(connection));
}

Nodes need no change at all. NodeRuntime dials config.hubUri verbatim, so omnyshell node start --hub wss://hub:8443/shell (and service install node --hub …/shell) already work.

⚠️ The broker authenticates in band — it speaks first, with a challenge — so this route must not be given a ConnectionAuthenticator; one would consume the very frames the broker is waiting for. Note omnyhub treats a route's null connection authenticator as inherit the hub-wide one, not none. Documented on the class.

Changed

OmnyShellHub is rebuilt on omnyhub's OmnyHub, hosting the service at / — which matches every path, exactly as the old listener did (it upgraded a WebSocket regardless of path), so existing clients dialling wss://host:8443 are unaffected. Its public API (start/stop/port/isRunning/nodes/sessions/audit) is unchanged.

  • TLS becomes an omnyhub TlsProvider: StaticTls for a securityContext, ReloadableFileTls for a tlsDirectory. Renewal still rebinds the listener gap-free; omnyhub now performs it and reports TLS certificate renewed rather than the old …rebound….
  • Logging regression caught and fixed: omnyhub logs through its own Logger, which defaults to NoopLogger. Without a bridge, an OmnyShell Hub would have silently lost all lifecycle, TLS-renewal and unhandled-error logging. HubConfig.logger is now wired into it.
  • WsServerEndpoint deleted — it was the last user of shelf, so shelf and shelf_web_socket are dropped from the dependencies.
  • PemTlsSource is retained: tunnels are separate raw TCP listeners and still use it.

Added

NodeConfig.home overrides where a node persists its UID (<home>/.omnyshell/node.uid). The UID file is keyed by the machine, so two node runtimes in one process — an embedded shell node beside another agent — otherwise contend on it and warn about the UID changing under them. Mirrors the existing gitCredentialsHome hatch.

Tests

813 (up from 808). The regression gate: the 808 existing tests pass unmodified, except one — hub_tls_dir_test asserted on the log text rebound, which is now omnyhub's renewed. The behaviour it really cares about (a fresh client round-trips on the renewed listener) is untouched.

New hub_service_mount_test.dart proves the premise directly: a bare omnyhub hub with the broker at /shell and another service at /other — a node registers, a client opens a session and runs a command through it, the host keeps its own surface on the same port, and NodeConfig.home isolates the UID.

format / analyze --fatal-infos --fatal-warnings / dependency_validator / dart doc / publish --dry-run all green.

🤖 Generated with Claude Code

gmpassos and others added 2 commits July 12, 2026 18:55
omnydrive 1.12.2 is itself just the omnyhub ^1.3.0 bump. The previous
^1.12.1 constraint already resolved to it, so this only makes the
constraint name the version OmnyShell is built and tested against.

No behaviour change and no API change: the full suite passes unmodified
(808 pass, 9 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…1.56.0)

The Hub broker can now be hosted on a listener OmnyShell does not own, so another
Hub — an OmnyServer Hub, say — can serve OmnyShell nodes on its own port, at its
own path, beside its own surfaces. One Hub, one certificate, one port, two kinds
of node.

Nothing changes for a standalone OmnyShell Hub: OmnyShellHub's API and wire
behaviour are unchanged, and its 808 existing tests pass untouched.

Added:
- OmnyShellHubService — the broker as an omnyhub Service. HubBroker was already
  transport-agnostic (driven by accept()ing connections), and FrameConnection
  already wraps an omnyhub Connection, so this is only an adapter: the whole
  integration is one method. Nodes need no change at all — they dial hubUri
  verbatim, so `omnyshell node start --hub wss://hub:8443/shell` already works.
- NodeConfig.home overrides where a node persists its UID. The UID file is keyed
  by the machine, so two node runtimes in one process (an embedded shell node
  beside another agent) otherwise contend on ~/.omnyshell/node.uid and warn about
  the UID changing under them. Mirrors the existing gitCredentialsHome hatch.

Changed:
- OmnyShellHub is rebuilt on omnyhub's OmnyHub, hosting an OmnyShellHubService at
  '/' — which matches every path, exactly as the old listener did (it upgraded a
  WebSocket regardless of path), so existing clients are unaffected.
- TLS is now an omnyhub TlsProvider: StaticTls for a securityContext,
  ReloadableFileTls for a tlsDirectory. Renewal still rebinds the listener
  gap-free, but omnyhub performs it and reports "TLS certificate renewed".
- The hub's lifecycle/TLS/error messages are bridged into HubConfig.logger, which
  would otherwise have gone to omnyhub's default no-op logger and vanished.
- Removed WsServerEndpoint, the last user of shelf: shelf and shelf_web_socket are
  dropped from the dependencies.
- PemTlsSource is retained — tunnels are separate raw TCP listeners and still use it.

813 tests (up from 808); format/analyze/dependency_validator/doc green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.87179% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
lib/src/application/hub/omnyshell_hub.dart 92.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@gmpassos
gmpassos merged commit 6ab246f into master Jul 12, 2026
6 checks passed
@gmpassos
gmpassos deleted the feat/hub-service-mount branch July 12, 2026 23:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant