|
|
|
|
package nstatus
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
|
"google.golang.org/grpc/metadata"
|
|
|
|
|
"google.golang.org/grpc/status"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// UnaryServerInterceptor grpc 错误拦截 服务端拦截器
|
|
|
|
|
// 将服务端传递出的任何错误拦截并转换为标准grpc-status,保持code与msg,不进行翻译
|
|
|
|
|
// 将Result中的Type加入到metadata中进行传递
|
|
|
|
|
func UnaryServerInterceptor() grpc.UnaryServerInterceptor {
|
|
|
|
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
|
|
|
|
|
resp, err = handler(ctx, req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
cause := errors.Cause(err)
|
|
|
|
|
e := ConvertErr(cause)
|
|
|
|
|
if e != nil {
|
|
|
|
|
writeResultTypeCtx(ctx, e)
|
|
|
|
|
// 转换为grpc-err
|
|
|
|
|
err = status.Error(codes.Code(e.Code), e.Msg)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func writeResultTypeCtx(ctx context.Context, r *Result) {
|
|
|
|
|
_ = grpc.SetHeader(ctx, metadata.Pairs(GrpcResultTypeKey, string(r.Type)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UnaryClientInterceptor 将客户端调用后产生的grpc-err转换为 *Result
|
|
|
|
|
// 客户端直接强转为*Result 或 再次调用 ConvertErr 即可使用
|
|
|
|
|
func UnaryClientInterceptor() grpc.UnaryClientInterceptor {
|
|
|
|
|
return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
|
|
|
|
|
err := invoker(ctx, method, req, reply, cc, opts...)
|
|
|
|
|
if err == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
e := ConvertErr(err)
|
|
|
|
|
// 读取header(metadata)中的GrpcResultType
|
|
|
|
|
md, ok := metadata.FromOutgoingContext(ctx)
|
|
|
|
|
if ok {
|
|
|
|
|
rt := md.Get(GrpcResultTypeKey)
|
|
|
|
|
if len(rt) > 0 {
|
|
|
|
|
e.Type = ResultType(rt[0])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
}
|