// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. package grpcx import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "github.com/gogf/gf/v2/errors/gcode" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gutil" "github.com/gogf/gf/contrib/rpc/grpcx/v2/internal/tracing" ) // ChainUnary returns a ServerOption that specifies the chained interceptor // for unary RPCs. The first interceptor will be the outermost, // while the last interceptor will be the innermost wrapper around the real call. // All unary interceptors added by this method will be chained. func (s modServer) ChainUnary(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption { return grpc.ChainUnaryInterceptor(interceptors...) } // ChainStream returns a ServerOption that specifies the chained interceptor // for stream RPCs. The first interceptor will be the outermost, // while the last interceptor will be the innermost wrapper around the real call. // All stream interceptors added by this method will be chained. func (s modServer) ChainStream(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption { return grpc.ChainStreamInterceptor(interceptors...) } // UnaryError is the default unary interceptor for error converting from custom error to grpc error. func (s modServer) UnaryError( ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (any, error) { res, err := handler(ctx, req) if err != nil { code := gerror.Code(err) if code.Code() != -1 { err = status.Error(codes.Code(code.Code()), err.Error()) } } return res, err } // UnaryRecover is the first interceptor that keep server not down from panics. func (s modServer) UnaryRecover( ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (res any, err error) { gutil.TryCatch(ctx, func(ctx2 context.Context) { res, err = handler(ctx, req) }, func(ctx context.Context, exception error) { err = gerror.WrapCode(gcode.New(int(codes.Internal), "", nil), exception, "panic recovered") }) return } // UnaryValidate Common validation unary interpreter. func (s modServer) UnaryValidate( ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (any, error) { // It does nothing if there's no validation tag in the struct definition. if err := g.Validator().Data(req).Run(ctx); err != nil { return nil, gerror.NewCode( gcode.New(int(codes.InvalidArgument), "", nil), gerror.Current(err).Error(), ) } return handler(ctx, req) } func (s modServer) UnaryAllowNilRes( ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (any, error) { res, err := handler(ctx, req) if g.IsNil(res) { res = proto.Message(nil) } return res, err } // UnaryTracing is a unary interceptor for adding tracing feature for gRPC server using OpenTelemetry. // The tracing feature is builtin enabled. func (s modServer) UnaryTracing( ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (any, error) { return tracing.UnaryServerInterceptor(ctx, req, info, handler) } // StreamTracing is a stream unary interceptor for adding tracing feature for gRPC server using OpenTelemetry. func (s modServer) StreamTracing( srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler, ) error { return tracing.StreamServerInterceptor(srv, ss, info, handler) }