feat(tunnel): add tunnel up/down IPC endpoints [RD-209] - #1507
Merged
Merged
Conversation
Separate tunnel lifecycle from authentication. Until now the tunnel
came up only on login and tore down only on logout, conflating 'who am
I' with 'is the netstack running'. This adds two endpoints that drive
Manager.BringUp/TearDown without touching the token:
POST /v1/tunnel/up bring the netstack online using the persisted
token. Synchronous, idempotent (already_up),
409 when logged out (no token to dial with).
POST /v1/tunnel/down tear the netstack down, keep the token.
Idempotent (already_down). User stays logged in.
This lets a user pause/resume the tunnel without re-authenticating.
Changes:
- ipc.Service: add Up/Down methods with TunnelUp/DownResponse types.
- ipc.Server: handlers + routes; new ErrNotLoggedIn sentinel mapping to
409 (distinct from 401 control-token rejection).
- ipc.Client: Up/Down round-trip methods.
- daemonService: Up reuses BringUp (folds ErrAlreadyUp into already_up);
Down reuses TearDown; both leave the token and config untouched.
- openapi.yaml: document both endpoints + the not_logged_in code.
- tests: handler-level (200/409/idempotent) and service-level
(logged-out -> ErrNotLoggedIn, idle Down no-op, Down keeps token).
🤖 Generated with Mister Maluco
Co-Authored-By: MisterMal <teskeslab@lucasteske.dev>
Contributor
Migration Safety AnalysisNo database migrations were changed in this PR. Safe to deploy to sandbox. |
Contributor
|
✅ Build Completed with Success, Version=1507.0.0-g977c18d |
The daemon fetched the connection list once at bring-up and never
again, so connections created or deleted on the gateway never showed
up until a full logout/login. This adds automatic + manual refresh.
Concurrency-safe registry (tunnel/tunnelmgr/registry.go):
Replaces the bare subTypeByName map (shared by reference into the
netstack accept/handler closures AND Snapshot — an unsynchronized
data race waiting to happen) with connRegistry, an RWMutex-guarded
name -> {subtype, active} store. The accept path reads it via
subTypeOf(); a refresh writes it via reconcile(). Snapshot now
carries a value-copied []ConnInfo of active connections instead of
the live map, removing the shared-map hazard end to end.
Refresh mechanics (manager.go):
- loadConnections() factors out fetch + allocate + reconcile, shared
by buildTunnel (initial) and the new Manager.Refresh (re-load).
- Refresh re-fetches and reconciles into the LIVE tunnel without
touching the netstack, routes, or in-flight flows. New names become
routable immediately (allocator + resolver hold live refs); deleted
ones are marked inactive (hidden from listings, new SYNs rejected)
but keep their reserved IP — the allocator is append-only and
deterministic, so a reappearing connection regains its address.
Triggers:
- Periodic: daemonService.StartAutoRefresh runs a ticker
(--refresh-interval, default 60s, HSH_TUNNELD_REFRESH_INTERVAL
override; 0 disables) for the daemon lifetime. It no-ops while the
tunnel is down and never tears the tunnel down on a fetch blip.
- Manual: POST /v1/connections/refresh + ipc.Client.RefreshConnections.
Tests:
- registry: reconcile add/retire/reactivate, idempotence, and a
-race concurrent reader/writer regression guard.
- ipc handler: 200 + running/count, down no-op.
- service: refresh no-op when down, Manager.Refresh no-op when idle.
All of ./tunnel/... green under -race.
🤖 Generated with Mister Maluco
Co-Authored-By: MisterMal <teskeslab@lucasteske.dev>
Contributor
Author
Update: periodic + on-demand connection-list refresh addedExpanded this PR to also fix the 'connection list never updates' gap (the daemon fetched once at bring-up and never again).
Paired CLI command Automated by MisterMal |
Contributor
|
✅ Build Completed with Success, Version=1507.0.0-gb8e0f4d |
EmanuelJr
approved these changes
Jun 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Separates the tunnel netstack lifecycle from authentication. Until now the tunnel came up only on login and tore down only on logout, conflating 'who am I' with 'is the netstack running'.
Adds two IPC endpoints that drive
Manager.BringUp/TearDownwithout touching the token:POST /v1/tunnel/upalready_up). Returns 409 not_logged_in when logged out (no token to dial with).POST /v1/tunnel/downalready_down). User stays logged in.This lets a user pause/resume the tunnel without re-authenticating.
Changes
ipc.Service:Up/Downmethods +TunnelUpResponse/TunnelDownResponse.ipc.Server: handlers, routes, and a newErrNotLoggedInsentinel that maps to 409 (distinct from 401 control-token rejection).ipc.Client:Up/Downround-trip methods.daemonService:UpreusesBringUp(foldsErrAlreadyUpintoalready_up);DownreusesTearDown; neither touches the token or config file.openapi.yaml: both endpoints + thenot_logged_incode.Testing
already_up/already_down, 409not_logged_in.ErrNotLoggedIn, idleDownno-op,Downkeeps the token (lifecycle/auth separation).go build ./tunnel/...,go vet ./tunnel/...,go test ./tunnel/...all green.Consumer
Paired with hoophq/hsh PR (tunnel up/down CLI + unified login). The CLI degrades gracefully against an older daemon (501).
Automated by MisterMal