github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/middleware/serverversion/serverversion.go (about)

     1  package serverversion
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/authzed/authzed-go/pkg/requestmeta"
     7  	"github.com/authzed/authzed-go/pkg/responsemeta"
     8  	"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors"
     9  	"google.golang.org/grpc"
    10  	"google.golang.org/grpc/metadata"
    11  
    12  	log "github.com/authzed/spicedb/internal/logging"
    13  	"github.com/authzed/spicedb/pkg/releases"
    14  )
    15  
    16  // HandleServerVersion defines a middleware for returning the version of the server
    17  // when requested via the RequestServerVersion header.
    18  type HandleServerVersion struct {
    19  	// IsEnabled is whether the middleware is enabled.
    20  	IsEnabled bool
    21  
    22  	// GetVersion is the function used to retrieve the service version.
    23  	GetVersion func() (string, error)
    24  }
    25  
    26  func (r *HandleServerVersion) ServerReporter(ctx context.Context, _ interceptors.CallMeta) (interceptors.Reporter, context.Context) {
    27  	if r.IsEnabled {
    28  		if md, ok := metadata.FromIncomingContext(ctx); ok {
    29  			if _, isRequestingVersion := md[string(requestmeta.RequestServerVersion)]; isRequestingVersion {
    30  				version, err := r.GetVersion()
    31  				if err != nil {
    32  					log.Ctx(ctx).Err(err).Msg("could not load current service version")
    33  					return interceptors.NoopReporter{}, ctx
    34  				}
    35  
    36  				err = responsemeta.SetResponseHeaderMetadata(ctx, map[responsemeta.ResponseMetadataHeaderKey]string{
    37  					responsemeta.ServerVersion: version,
    38  				})
    39  				// if context is cancelled, the stream will be closed, and gRPC will return ErrIllegalHeaderWrite
    40  				// this prevents logging unnecessary error messages
    41  				if err := ctx.Err(); err != nil {
    42  					return interceptors.NoopReporter{}, ctx
    43  				}
    44  				if err != nil {
    45  					log.Ctx(ctx).Warn().Err(err).Msg("serverversion: could not report metadata")
    46  				}
    47  			}
    48  		}
    49  	}
    50  
    51  	return interceptors.NoopReporter{}, ctx
    52  }
    53  
    54  // UnaryServerInterceptor returns a new interceptor which handles server version requests.
    55  func UnaryServerInterceptor(isEnabled bool) grpc.UnaryServerInterceptor {
    56  	return interceptors.UnaryServerInterceptor(&HandleServerVersion{isEnabled, releases.CurrentVersion})
    57  }
    58  
    59  // StreamServerInterceptor returns a new interceptor which handles server version requests.
    60  func StreamServerInterceptor(isEnabled bool) grpc.StreamServerInterceptor {
    61  	return interceptors.StreamServerInterceptor(&HandleServerVersion{isEnabled, releases.CurrentVersion})
    62  }