diff --git a/apiresp/resp.go b/apiresp/resp.go index 07d8cb5e..26aa0e6d 100644 --- a/apiresp/resp.go +++ b/apiresp/resp.go @@ -16,6 +16,7 @@ package apiresp import ( "encoding/json" + "errors" "reflect" "github.com/openimsdk/tools/errs" @@ -78,8 +79,8 @@ func ParseError(err error) *ApiResponse { if err == nil { return ApiSuccess(nil) } - unwrap := errs.Unwrap(err) - if codeErr, ok := unwrap.(errs.CodeError); ok { + var codeErr errs.CodeError + if errors.As(err, &codeErr) { resp := ApiResponse{ErrCode: codeErr.Code(), ErrMsg: codeErr.Msg(), ErrDlt: codeErr.Detail()} if resp.ErrDlt == "" { resp.ErrDlt = err.Error() diff --git a/errs/coderr.go b/errs/coderr.go index b91fc4eb..ee0c8ff1 100644 --- a/errs/coderr.go +++ b/errs/coderr.go @@ -1,24 +1,12 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package errs import ( + "errors" "fmt" - "github.com/openimsdk/tools/errs/stack" "strconv" "strings" + + "github.com/openimsdk/tools/errs/stack" ) const stackSkip = 4 @@ -82,7 +70,8 @@ func (e *codeError) WrapMsg(msg string, kv ...any) error { } func (e *codeError) Is(err error) bool { - codeErr, ok := Unwrap(err).(CodeError) + var codeErr CodeError + ok := errors.As(Unwrap(err), &codeErr) if !ok { if err == nil && e == nil { return true @@ -136,7 +125,7 @@ func WrapMsg(err error, msg string, kv ...any) error { if err == nil { return nil } - err = fmt.Errorf("%w: %s", err, toString(msg, kv)) + err = NewErrorWrapper(err, toString(msg, kv)) return stack.New(err, stackSkip) } diff --git a/errs/error.go b/errs/error.go index 9faff64e..37c4a00d 100644 --- a/errs/error.go +++ b/errs/error.go @@ -1,21 +1,8 @@ -// Copyright © 2024 OpenIM open source community. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package errs import ( "bytes" + "errors" "fmt" ) @@ -40,7 +27,8 @@ func (e *errorString) Is(err error) bool { if err == nil { return false } - t, ok := err.(*errorString) + var t *errorString + ok := errors.As(err, &t) return ok && e.s == t.s } diff --git a/errs/predefine.go b/errs/predefine.go index d8de582d..ab96ba99 100644 --- a/errs/predefine.go +++ b/errs/predefine.go @@ -1,17 +1,3 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package errs const ( diff --git a/errs/wrap_err.go b/errs/wrap_err.go new file mode 100644 index 00000000..8ffd3a05 --- /dev/null +++ b/errs/wrap_err.go @@ -0,0 +1,45 @@ +package errs + +import "errors" + +type ErrWrapper interface { + Is(err error) bool + Wrap() error + Unwrap() error + WrapMsg(msg string, kv ...any) error + error +} + +func NewErrorWrapper(err error, s string) ErrWrapper { + return &errorWrapper{error: err, s: s} +} + +type errorWrapper struct { + error + s string +} + +func (e *errorWrapper) Is(err error) bool { + if err == nil { + return false + } + var t *errorWrapper + ok := errors.As(err, &t) + return ok && e.s == t.s +} + +func (e *errorWrapper) Error() string { + return e.s +} + +func (e *errorWrapper) Wrap() error { + return Wrap(e) +} + +func (e *errorWrapper) WrapMsg(msg string, kv ...any) error { + return WrapMsg(e, msg, kv...) +} + +func (e *errorWrapper) Unwrap() error { + return e.error +} diff --git a/mw/rpc_client_interceptor.go b/mw/rpc_client_interceptor.go index c160148b..a5a22318 100644 --- a/mw/rpc_client_interceptor.go +++ b/mw/rpc_client_interceptor.go @@ -67,6 +67,7 @@ func RpcClientInterceptor(ctx context.Context, method string, req, resp any, cc s := strings.Join(errInfo.Warp, "->") + errInfo.Cause cErr := errs.NewCodeError(int(sta.Code()), sta.Message()).WithDetail(s).Wrap() log.ZAdaptive(ctx, "rpc client response failed", cErr, "method", method, "req", req) + return cErr } } cErr := errs.NewCodeError(int(sta.Code()), sta.Message()).Wrap() diff --git a/mw/rpc_server_interceptor.go b/mw/rpc_server_interceptor.go index af64586e..7dfd010f 100644 --- a/mw/rpc_server_interceptor.go +++ b/mw/rpc_server_interceptor.go @@ -3,11 +3,11 @@ package mw import ( "context" "fmt" - "github.com/openimsdk/tools/checker" "math" "github.com/openimsdk/protocol/constant" "github.com/openimsdk/protocol/errinfo" + "github.com/openimsdk/tools/checker" "github.com/openimsdk/tools/errs" "github.com/openimsdk/tools/log" "github.com/openimsdk/tools/mw/specialerror" @@ -81,21 +81,10 @@ func enrichContextWithMetadata(ctx context.Context, md metadata.MD) (context.Con } func handleError(ctx context.Context, method string, req any, err error) error { - codeErr := specialerror.ErrCode(errs.Unwrap(err)) - if codeErr == nil { - codeErr = errs.ErrInternalServer - } - code := codeErr.Code() - if code <= 0 || int64(code) > int64(math.MaxUint32) { - code = errs.ServerInternalError - } - if _, ok := errs.Unwrap(err).(errs.CodeError); ok { - log.ZAdaptive(ctx, "rpc server response failed", err, "method", method, "req", req) - } else { - log.ZAdaptive(ctx, "rpc server response failed", err, "rawerror", err, "method", method, "req", req) - } - grpcStatus := status.New(codes.Code(code), err.Error()) - errInfo := &errinfo.ErrorInfo{Cause: err.Error()} + codeErr := getErrData(err) + log.ZAdaptive(ctx, "rpc server response failed", err, "method", method, "req", req) + grpcStatus := status.New(codes.Code(codeErr.Code()), codeErr.Msg()) + errInfo := &errinfo.ErrorInfo{Cause: codeErr.Detail()} details, err := grpcStatus.WithDetails(errInfo) if err != nil { log.ZError(ctx, "rpc server response WithDetails failed", err, "method", method, "req", req) @@ -104,6 +93,52 @@ func handleError(ctx context.Context, method string, req any, err error) error { return details.Err() } +func getErrData(err error) errs.CodeError { + var ( + code int + msg, detail string + ) + codeErr := specialerror.ErrCode(err) + if codeErr != nil { + code = codeErr.Code() + msg = codeErr.Msg() + detail = codeErr.Detail() + } else { + code = errs.ServerInternalError + } + if code <= 0 || int64(code) > int64(math.MaxUint32) { + code = errs.ServerInternalError + } + + if msg == "" || detail == "" { + stringErr := specialerror.ErrString(err) + wrapErr := specialerror.ErrWrapper(err) + + if stringErr != nil { + if msg == "" { + msg = stringErr.Error() + } + } + + if wrapErr != nil { + if msg == "" { + msg = wrapErr.Error() + } + if detail == "" { + detail = wrapErr.Error() + } + } + } + if msg == "" { + msg = err.Error() + } + if detail == "" { + detail = msg + } + + return errs.NewCodeError(code, msg).WithDetail(detail) +} + func GrpcServer() grpc.ServerOption { return grpc.ChainUnaryInterceptor(RpcServerInterceptor) } diff --git a/mw/specialerror/error.go b/mw/specialerror/error.go index 335324ac..491e155e 100644 --- a/mw/specialerror/error.go +++ b/mw/specialerror/error.go @@ -1,20 +1,10 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - package specialerror -import "github.com/openimsdk/tools/errs" +import ( + "errors" + + "github.com/openimsdk/tools/errs" +) var handlers []func(err error) errs.CodeError @@ -28,7 +18,7 @@ func AddErrHandler(h func(err error) errs.CodeError) (err error) { func AddReplace(target error, codeErr errs.CodeError) error { handler := func(err error) errs.CodeError { - if err == target { + if errors.Is(err, target) { return codeErr } return nil @@ -42,7 +32,8 @@ func AddReplace(target error, codeErr errs.CodeError) error { } func ErrCode(err error) errs.CodeError { - if codeErr, ok := err.(errs.CodeError); ok { + var codeErr errs.CodeError + if errors.As(err, &codeErr) { return codeErr } for i := 0; i < len(handlers); i++ { @@ -52,3 +43,19 @@ func ErrCode(err error) errs.CodeError { } return nil } + +func ErrString(err error) errs.Error { + var codeErr errs.Error + if errors.As(err, &codeErr) { + return codeErr + } + return nil +} + +func ErrWrapper(err error) errs.ErrWrapper { + var codeErr errs.ErrWrapper + if errors.As(err, &codeErr) { + return codeErr + } + return nil +}