github.com/grafana/pyroscope@v1.18.0/pkg/util/httpgrpc/httpgrpc.go (about)

     1  package httpgrpc
     2  
     3  import (
     4  	"fmt"
     5  
     6  	log "github.com/sirupsen/logrus"
     7  	"google.golang.org/grpc/codes"
     8  	"google.golang.org/grpc/status"
     9  	"google.golang.org/protobuf/proto"
    10  	"google.golang.org/protobuf/types/known/anypb"
    11  )
    12  
    13  // Errorf returns a HTTP gRPC error than is correctly forwarded over
    14  // gRPC, and can eventually be converted back to a HTTP response with
    15  // HTTPResponseFromError.
    16  func Errorf(code int, tmpl string, args ...interface{}) error {
    17  	return ErrorFromHTTPResponse(&HTTPResponse{
    18  		Code: int32(code),
    19  		Body: []byte(fmt.Sprintf(tmpl, args...)),
    20  	})
    21  }
    22  
    23  // ErrorFromHTTPResponse converts an HTTP response into a grpc error
    24  func ErrorFromHTTPResponse(resp *HTTPResponse) error {
    25  	s := status.New(codes.Code(resp.Code), string(resp.Body))
    26  	s, err := s.WithDetails(resp)
    27  	if err != nil {
    28  		return err
    29  	}
    30  	return status.ErrorProto(s.Proto())
    31  }
    32  
    33  // HTTPResponseFromError converts a grpc error into an HTTP response
    34  func HTTPResponseFromError(err error) (*HTTPResponse, bool) {
    35  	s, ok := status.FromError(err)
    36  	if !ok {
    37  		return nil, false
    38  	}
    39  
    40  	status := s.Proto()
    41  	if len(status.Details) != 1 {
    42  		return nil, false
    43  	}
    44  
    45  	var resp HTTPResponse
    46  	if err := anypb.UnmarshalTo(status.Details[0], &resp, proto.UnmarshalOptions{}); err != nil {
    47  		log.Errorf("Got error containing non-response: %v", err)
    48  		return nil, false
    49  	}
    50  
    51  	return &resp, true
    52  }