github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/dispatch/dispatch.go (about)

     1  package dispatch
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/rs/zerolog"
     8  
     9  	log "github.com/authzed/spicedb/internal/logging"
    10  	v1 "github.com/authzed/spicedb/pkg/proto/dispatch/v1"
    11  )
    12  
    13  // ReadyState represents the ready state of the dispatcher.
    14  type ReadyState struct {
    15  	// Message is a human-readable status message for the current state.
    16  	Message string
    17  
    18  	// IsReady indicates whether the datastore is ready.
    19  	IsReady bool
    20  }
    21  
    22  // Dispatcher interface describes a method for passing subchecks off to additional machines.
    23  type Dispatcher interface {
    24  	Check
    25  	Expand
    26  	ReachableResources
    27  	LookupResources
    28  	LookupSubjects
    29  
    30  	// Close closes the dispatcher.
    31  	Close() error
    32  
    33  	// ReadyState returns true when dispatcher is able to respond to requests
    34  	ReadyState() ReadyState
    35  }
    36  
    37  // Check interface describes just the methods required to dispatch check requests.
    38  type Check interface {
    39  	// DispatchCheck submits a single check request and returns its result.
    40  	DispatchCheck(ctx context.Context, req *v1.DispatchCheckRequest) (*v1.DispatchCheckResponse, error)
    41  }
    42  
    43  // Expand interface describes just the methods required to dispatch expand requests.
    44  type Expand interface {
    45  	// DispatchExpand submits a single expand request and returns its result.
    46  	DispatchExpand(ctx context.Context, req *v1.DispatchExpandRequest) (*v1.DispatchExpandResponse, error)
    47  }
    48  
    49  // ReachableResourcesStream is an alias for the stream to which reachable resources will be written.
    50  type ReachableResourcesStream = Stream[*v1.DispatchReachableResourcesResponse]
    51  
    52  // ReachableResources interface describes just the methods required to dispatch reachable resources requests.
    53  type ReachableResources interface {
    54  	// DispatchReachableResources submits a single reachable resources request, writing its results to the specified stream.
    55  	DispatchReachableResources(
    56  		req *v1.DispatchReachableResourcesRequest,
    57  		stream ReachableResourcesStream,
    58  	) error
    59  }
    60  
    61  // LookupResourcesStream is an alias for the stream to which found resources will be written.
    62  type LookupResourcesStream = Stream[*v1.DispatchLookupResourcesResponse]
    63  
    64  // LookupResources interface describes just the methods required to dispatch LookupResources requests.
    65  type LookupResources interface {
    66  	// DispatchLookupResources submits a single lookup request and returns its result.
    67  	DispatchLookupResources(
    68  		req *v1.DispatchLookupResourcesRequest,
    69  		stream LookupResourcesStream,
    70  	) error
    71  }
    72  
    73  // LookupSubjectsStream is an alias for the stream to which found subjects will be written.
    74  type LookupSubjectsStream = Stream[*v1.DispatchLookupSubjectsResponse]
    75  
    76  // LookupSubjects interface describes just the methods required to dispatch lookup subjects requests.
    77  type LookupSubjects interface {
    78  	// DispatchLookupSubjects submits a single lookup subjects request, writing its results to the specified stream.
    79  	DispatchLookupSubjects(
    80  		req *v1.DispatchLookupSubjectsRequest,
    81  		stream LookupSubjectsStream,
    82  	) error
    83  }
    84  
    85  // DispatchableRequest is an interface for requests.
    86  type DispatchableRequest interface {
    87  	zerolog.LogObjectMarshaler
    88  
    89  	GetMetadata() *v1.ResolverMeta
    90  }
    91  
    92  // CheckDepth returns ErrMaxDepth if there is insufficient depth remaining to dispatch.
    93  func CheckDepth(ctx context.Context, req DispatchableRequest) error {
    94  	metadata := req.GetMetadata()
    95  	if metadata == nil {
    96  		log.Ctx(ctx).Warn().Object("request", req).Msg("request missing metadata")
    97  		return fmt.Errorf("request missing metadata")
    98  	}
    99  
   100  	if metadata.DepthRemaining == 0 {
   101  		return NewMaxDepthExceededError(req)
   102  	}
   103  
   104  	return nil
   105  }
   106  
   107  // AddResponseMetadata adds the metadata found in the incoming metadata to the existing
   108  // metadata, *modifying it in place*.
   109  func AddResponseMetadata(existing *v1.ResponseMeta, incoming *v1.ResponseMeta) {
   110  	existing.DispatchCount += incoming.DispatchCount
   111  	existing.CachedDispatchCount += incoming.CachedDispatchCount
   112  	existing.DepthRequired = max(existing.DepthRequired, incoming.DepthRequired)
   113  }