package com.sptmobile.endpoint import com.sptmobile.browse.BrowsedInstance import com.sptmobile.browse.EndpointDirectory import com.sptmobile.browse.WireSubnet // [impl->REQ-DIGEST-DIRECT-ROUTE] /** * Most-direct-route digest choice (DESIGN.md ruling 4): a digest is served * only by a paired host CO-LOCATED with the target endpoint — the host's * endpoint listing names its co-located ids in the `local` section. Listings * arrive in dial order, so the first co-located host is the one we dial; no * co-located host means the caller renders the registry card + "pending * cross-node" instead of a digest. Pure (no Android/JNI) so the routing rule * is JVM-unit-testable. */ object DigestRouter { /** One linked host's parsed listing — [choose] input, in dial order. */ data class HostListing( val hostNode: String, val localIds: Set, val subnets: List, ) /** Node key of the first co-located linked host, or null (pending). */ fun choose(endpointId: String, listings: List): String? = listings.firstOrNull { endpointId in it.localIds }?.hostNode // [impl->REQ-ENDPOINT-INSTANCES] /** * The registry-card fallback: the endpoint's Instance rows (ruling 9 — * one row per node presence) unioned across every linked host's listing, * same merge the browser uses. */ fun registryCard(endpointId: String, listings: List): List = EndpointDirectory.merge(listings.map { it.hostNode to it.subnets }) .flatMap { subnet -> subnet.endpoints.filter { it.id == endpointId } } .flatMap { it.instances } }