diff --git a/go.mod b/go.mod index 003621a5..f17b278a 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( go.uber.org/mock v0.4.0 golang.org/x/oauth2 v0.23.0 golang.org/x/sync v0.8.0 + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 google.golang.org/grpc v1.67.0 google.golang.org/protobuf v1.34.2 ) @@ -203,7 +204,6 @@ require ( golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.25.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/internal/connectors/plugins/errors.go b/internal/connectors/plugins/errors.go index 94ebe530..127ea696 100644 --- a/internal/connectors/plugins/errors.go +++ b/internal/connectors/plugins/errors.go @@ -1,8 +1,83 @@ package plugins -import "errors" +import ( + "errors" + "fmt" + + "github.com/formancehq/payments/internal/connectors/httpwrapper" + "github.com/formancehq/payments/internal/models" + "google.golang.org/genproto/googleapis/rpc/errdetails" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const ( + FailureReasonInvalidRequest = "INVALID_REQUEST" + FailureReasonInvalidConfig = "INVALID_CONFIG" + FailureReasonBadRequestToUpstream = "BAD_REQUEST_TO_UPSTREAM" + FailureReasonUnimplemented = "UNIMPLEMENTED" +) var ( ErrNotImplemented = errors.New("not implemented") ErrNotYetInstalled = errors.New("not yet installed") ) + +type Error struct { + RawMessage string + Status *status.Status +} + +func NewError(code codes.Code, reason string, err error) error { + st := status.Newf(code, err.Error()) + var dtErr error + st, dtErr = st.WithDetails(&errdetails.ErrorInfo{ + Reason: reason, + }) + if dtErr != nil { + return Error{ + RawMessage: fmt.Sprintf("%s (%s)", err.Error(), dtErr.Error()), + Status: status.Newf(code, err.Error()), + } + } + + return Error{ + RawMessage: err.Error(), + Status: st, + } +} + +func (e Error) Error() string { + return fmt.Sprintf("PLUGIN ERROR: %d, %s", e.Status.Code(), e.RawMessage) +} + +func (e Error) GRPCStatus() *status.Status { + return e.Status +} + +func translateErrorToGRPC(err error) error { + var ( + code codes.Code + reason string + ) + + switch { + case errors.Is(err, ErrNotImplemented): + code = codes.Unimplemented + reason = FailureReasonUnimplemented + case errors.Is(err, models.ErrMissingFromPayloadInRequest), + errors.Is(err, models.ErrMissingAccountInMetadata): + code = codes.FailedPrecondition + reason = FailureReasonInvalidRequest + case errors.Is(err, models.ErrInvalidConfig): + code = codes.FailedPrecondition + reason = FailureReasonInvalidConfig + case errors.Is(err, httpwrapper.ErrStatusCodeClientError): + code = codes.InvalidArgument + reason = FailureReasonBadRequestToUpstream + default: + code = codes.Internal + } + + return NewError(code, reason, err) +} diff --git a/internal/connectors/plugins/grpc.go b/internal/connectors/plugins/grpc.go index a0891f9f..4e1a6bb5 100644 --- a/internal/connectors/plugins/grpc.go +++ b/internal/connectors/plugins/grpc.go @@ -2,7 +2,6 @@ package plugins import ( "context" - "errors" "os" "github.com/formancehq/payments/internal/connectors/grpc" @@ -10,8 +9,6 @@ import ( "github.com/formancehq/payments/internal/connectors/grpc/proto/services" "github.com/formancehq/payments/internal/models" "github.com/hashicorp/go-hclog" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" ) type impl struct { @@ -313,12 +310,3 @@ func (i *impl) TranslateWebhook(ctx context.Context, req *services.TranslateWebh } var _ grpc.PSP = &impl{} - -func translateErrorToGRPC(err error) error { - switch { - case errors.Is(err, models.ErrInvalidConfig): - return status.Errorf(codes.InvalidArgument, err.Error()) - default: - return status.Errorf(codes.Internal, err.Error()) - } -}