github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/go-grpc-middleware/chain.go (about)

     1  // Copyright 2016 Michal Witkowski. All Rights Reserved.
     2  // See LICENSE for licensing terms.
     3  
     4  // gRPC Server Interceptor chaining middleware.
     5  
     6  package grpc_middleware
     7  
     8  import (
     9  	"github.com/hxx258456/ccgo/grpc"
    10  	"github.com/hxx258456/ccgo/net/context"
    11  )
    12  
    13  // ChainUnaryServer creates a single interceptor out of a chain of many interceptors.
    14  //
    15  // Execution is done in left-to-right order, including passing of context.
    16  // For example ChainUnaryServer(one, two, three) will execute one before two before three, and three
    17  // will see context changes of one and two.
    18  func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor {
    19  	n := len(interceptors)
    20  
    21  	if n > 1 {
    22  		lastI := n - 1
    23  		return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    24  			var (
    25  				chainHandler grpc.UnaryHandler
    26  				curI         int
    27  			)
    28  
    29  			chainHandler = func(currentCtx context.Context, currentReq interface{}) (interface{}, error) {
    30  				if curI == lastI {
    31  					return handler(currentCtx, currentReq)
    32  				}
    33  				curI++
    34  				resp, err := interceptors[curI](currentCtx, currentReq, info, chainHandler)
    35  				curI--
    36  				return resp, err
    37  			}
    38  
    39  			return interceptors[0](ctx, req, info, chainHandler)
    40  		}
    41  	}
    42  
    43  	if n == 1 {
    44  		return interceptors[0]
    45  	}
    46  
    47  	// n == 0; Dummy interceptor maintained for backward compatibility to avoid returning nil.
    48  	return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    49  		return handler(ctx, req)
    50  	}
    51  }
    52  
    53  // ChainStreamServer creates a single interceptor out of a chain of many interceptors.
    54  //
    55  // Execution is done in left-to-right order, including passing of context.
    56  // For example ChainUnaryServer(one, two, three) will execute one before two before three.
    57  // If you want to pass context between interceptors, use WrapServerStream.
    58  func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.StreamServerInterceptor {
    59  	n := len(interceptors)
    60  
    61  	if n > 1 {
    62  		lastI := n - 1
    63  		return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
    64  			var (
    65  				chainHandler grpc.StreamHandler
    66  				curI         int
    67  			)
    68  
    69  			chainHandler = func(currentSrv interface{}, currentStream grpc.ServerStream) error {
    70  				if curI == lastI {
    71  					return handler(currentSrv, currentStream)
    72  				}
    73  				curI++
    74  				err := interceptors[curI](currentSrv, currentStream, info, chainHandler)
    75  				curI--
    76  				return err
    77  			}
    78  
    79  			return interceptors[0](srv, stream, info, chainHandler)
    80  		}
    81  	}
    82  
    83  	if n == 1 {
    84  		return interceptors[0]
    85  	}
    86  
    87  	// n == 0; Dummy interceptor maintained for backward compatibility to avoid returning nil.
    88  	return func(srv interface{}, stream grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
    89  		return handler(srv, stream)
    90  	}
    91  }
    92  
    93  // ChainUnaryClient creates a single interceptor out of a chain of many interceptors.
    94  //
    95  // Execution is done in left-to-right order, including passing of context.
    96  // For example ChainUnaryClient(one, two, three) will execute one before two before three.
    97  func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryClientInterceptor {
    98  	n := len(interceptors)
    99  
   100  	if n > 1 {
   101  		lastI := n - 1
   102  		return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
   103  			var (
   104  				chainHandler grpc.UnaryInvoker
   105  				curI         int
   106  			)
   107  
   108  			chainHandler = func(currentCtx context.Context, currentMethod string, currentReq, currentRepl interface{}, currentConn *grpc.ClientConn, currentOpts ...grpc.CallOption) error {
   109  				if curI == lastI {
   110  					return invoker(currentCtx, currentMethod, currentReq, currentRepl, currentConn, currentOpts...)
   111  				}
   112  				curI++
   113  				err := interceptors[curI](currentCtx, currentMethod, currentReq, currentRepl, currentConn, chainHandler, currentOpts...)
   114  				curI--
   115  				return err
   116  			}
   117  
   118  			return interceptors[0](ctx, method, req, reply, cc, chainHandler, opts...)
   119  		}
   120  	}
   121  
   122  	if n == 1 {
   123  		return interceptors[0]
   124  	}
   125  
   126  	// n == 0; Dummy interceptor maintained for backward compatibility to avoid returning nil.
   127  	return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
   128  		return invoker(ctx, method, req, reply, cc, opts...)
   129  	}
   130  }
   131  
   132  // ChainStreamClient creates a single interceptor out of a chain of many interceptors.
   133  //
   134  // Execution is done in left-to-right order, including passing of context.
   135  // For example ChainStreamClient(one, two, three) will execute one before two before three.
   136  func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.StreamClientInterceptor {
   137  	n := len(interceptors)
   138  
   139  	if n > 1 {
   140  		lastI := n - 1
   141  		return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
   142  			var (
   143  				chainHandler grpc.Streamer
   144  				curI         int
   145  			)
   146  
   147  			chainHandler = func(currentCtx context.Context, currentDesc *grpc.StreamDesc, currentConn *grpc.ClientConn, currentMethod string, currentOpts ...grpc.CallOption) (grpc.ClientStream, error) {
   148  				if curI == lastI {
   149  					return streamer(currentCtx, currentDesc, currentConn, currentMethod, currentOpts...)
   150  				}
   151  				curI++
   152  				stream, err := interceptors[curI](currentCtx, currentDesc, currentConn, currentMethod, chainHandler, currentOpts...)
   153  				curI--
   154  				return stream, err
   155  			}
   156  
   157  			return interceptors[0](ctx, desc, cc, method, chainHandler, opts...)
   158  		}
   159  	}
   160  
   161  	if n == 1 {
   162  		return interceptors[0]
   163  	}
   164  
   165  	// n == 0; Dummy interceptor maintained for backward compatibility to avoid returning nil.
   166  	return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
   167  		return streamer(ctx, desc, cc, method, opts...)
   168  	}
   169  }
   170  
   171  // Chain creates a single interceptor out of a chain of many interceptors.
   172  //
   173  // WithUnaryServerChain is a grpc.Server config option that accepts multiple unary interceptors.
   174  // Basically syntactic sugar.
   175  func WithUnaryServerChain(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption {
   176  	return grpc.UnaryInterceptor(ChainUnaryServer(interceptors...))
   177  }
   178  
   179  // WithStreamServerChain is a grpc.Server config option that accepts multiple stream interceptors.
   180  // Basically syntactic sugar.
   181  func WithStreamServerChain(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption {
   182  	return grpc.StreamInterceptor(ChainStreamServer(interceptors...))
   183  }