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 }