Skip to content

tech debt: TunnelTCPInterface only mirrors first foreground TCP entity #74

Description

@torlando-tech

Follow-up from the dual-interface refactor (ea2e57e on feat/enable-tunnel-flip-flag).

Current behaviour

AppServices.registerTunnelInterface() picks the host/port to mirror via:

guard let endpoint = tcpEndpoints.values.first else {
    DiagLog.log("[TUNNEL] registerTunnelInterface — no foreground TCP endpoint to mirror, skipping")
    return
}

If the user has multiple enabled tcpClient InterfaceEntity rows (Settings → Interface Management → multiple TCP relays), only the first (per Dictionary.values.first — unspecified iteration order) ends up with a tunnel-path mirror. The others stay foreground-only and lose their rnsd path the moment the host app suspends. Phase B notifications would only fire for messages routed through the one mirrored relay.

What it should do

For each enabled foreground TCP interface, register a paired TunnelTCPInterface with a unique id (e.g., "tcp-tunnel-\(foregroundEntityId)"), publish each endpoint into tunnelTCPEndpointsKey, and have ExtensionFrameReader's routing dispatch by id to the right tunnel interface.

PacketTunnelProvider.loadInterfaceConfigs already iterates tunnelTCPEndpointsKey and opens a connection per entry, so the extension side scales naturally; the app side just needs to mirror per-entity instead of picking the first.

Suggested implementation sketch

  • registerTunnelInterface() loops over tcpEndpoints, creating one TunnelTCPInterface per foreground entity.
  • Hold them in a [String: TunnelTCPInterface] keyed by foreground entity id (or by tunnel entity id).
  • deregisterTunnelInterface() tears all of them down.
  • connectTCPInterface / stopTCPInterface invalidate / refresh the matching tunnel mirror.
  • The entityId used by TunnelManager.sendFrameExtensionFrameReader routing needs to be derived from the per-pair id, not the hard-coded TUNNEL_TCP_INTERFACE_ID constant.

Why deferred

For Phase B's MVP, a single tunnel mirror was enough to validate the architecture end-to-end (suspended_notification scenario went green with one relay). Tyler ships with one TCP relay in his test deployment, so this never fires in dev. Worth fixing before users with multi-relay setups exercise Background Transport.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions