github.com/weaveworks/common@v0.0.0-20230728070032-dd9e68f319d5/httpgrpc/httpgrpc.go (about)

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