Files
2026-04-02 19:18:42 +02:00

109 lines
3.3 KiB
Go

// 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
}