package xerrors import ( "errors" "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) const ( // UnknownCode is unknown code for error info. UnknownCode = 500 // UnknownReason is unknown reason for error info. UnknownReason = "" ) type Error struct { Status int Message string Reason string Metadata map[string]string } func (e *Error) WithMetadata(data map[string]string) *Error { err := Clone(e) err.Metadata = data return err } func (s *Error) Error() string { return s.Message } func New(code int, reason, message string) *Error { return &Error{ Status: code, Message: message, Reason: reason, Metadata: map[string]string{}, } } func (e *Error) GRPCStatus() *status.Status { s, _ := status.New(codes.Code(e.Status), e.Message). WithDetails(&errdetails.ErrorInfo{ Reason: e.Reason, Metadata: e.Metadata, }) return s } func Clone(err *Error) *Error { if err == nil { return nil } metadata := make(map[string]string, len(err.Metadata)) for k, v := range err.Metadata { metadata[k] = v } return &Error{ Status: err.Status, Reason: err.Reason, Message: err.Message, Metadata: metadata, } } func Code(err error) int { if err == nil { return 200 } return FromError(err).Status } func FromError(err error) *Error { if err == nil { return nil } if se := new(Error); errors.As(err, &se) { return se } //gs, ok := status.FromError(err) //if !ok { return New(UnknownCode, UnknownReason, err.Error()) //} // }