// Package downstream defines the verified internal command contract used by the // gateway after the authenticated edge pipeline succeeds. package downstream import ( "context" "errors" ) var ( // ErrRouteNotFound reports that Router does not have an exact-match handler // for the supplied authenticated message type. ErrRouteNotFound = errors.New("downstream route not found") // ErrDownstreamUnavailable reports that the resolved downstream dependency is // temporarily unavailable. ErrDownstreamUnavailable = errors.New("downstream service is unavailable") ) // AuthenticatedCommand is the minimum verified unary command context the // gateway may forward to downstream business services. type AuthenticatedCommand struct { // ProtocolVersion is the authenticated transport protocol version accepted // by the gateway. ProtocolVersion string // UserID is the authenticated user identity resolved from SessionCache. UserID string // DeviceSessionID is the authenticated device session that originated the // command. DeviceSessionID string // MessageType is the stable exact-match downstream routing key. MessageType string // TimestampMS is the client-supplied request timestamp that already passed // freshness verification. TimestampMS int64 // RequestID is the transport correlation and anti-replay identifier. RequestID string // TraceID is the optional client-supplied correlation identifier. TraceID string // PayloadBytes carries the verified opaque business payload bytes. PayloadBytes []byte } // UnaryResult is the minimum downstream unary result the gateway needs in // order to build a signed authenticated client response. type UnaryResult struct { // ResultCode is the stable opaque downstream result code returned to the // client without business reinterpretation by the gateway. ResultCode string // PayloadBytes carries the opaque downstream response payload bytes. PayloadBytes []byte } // Client executes a verified authenticated unary command against one concrete // downstream service or adapter. type Client interface { // ExecuteCommand executes command and returns the downstream unary result. ExecuteCommand(ctx context.Context, command AuthenticatedCommand) (UnaryResult, error) } // Router resolves the downstream unary client for one exact authenticated // message_type value. type Router interface { // Route returns the downstream client for messageType. Implementations must // wrap ErrRouteNotFound when the route table does not contain messageType. Route(messageType string) (Client, error) } // StaticRouter resolves exact message_type literals from an immutable route // map supplied at construction time. type StaticRouter struct { routes map[string]Client } // NewStaticRouter constructs a StaticRouter with a defensive copy of routes. func NewStaticRouter(routes map[string]Client) *StaticRouter { clonedRoutes := make(map[string]Client, len(routes)) for messageType, client := range routes { if client == nil { continue } clonedRoutes[messageType] = client } return &StaticRouter{routes: clonedRoutes} } // Route returns the exact-match client for messageType. func (r *StaticRouter) Route(messageType string) (Client, error) { if r == nil { return nil, ErrRouteNotFound } client, ok := r.routes[messageType] if !ok || client == nil { return nil, ErrRouteNotFound } return client, nil }