...

Source file src/github.com/grpc-ecosystem/go-grpc-middleware/chain.go

Documentation: github.com/grpc-ecosystem/go-grpc-middleware

     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  	"context"
    10  
    11  	"google.golang.org/grpc"
    12  )
    13  
    14  // ChainUnaryServer creates a single interceptor out of a chain of many interceptors.
    15  //
    16  // Execution is done in left-to-right order, including passing of context.
    17  // For example ChainUnaryServer(one, two, three) will execute one before two before three, and three
    18  // will see context changes of one and two.
    19  //
    20  // While this can be useful in some scenarios, it is generally advisable to use google.golang.org/grpc.ChainUnaryInterceptor directly.
    21  func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor {
    22  	n := len(interceptors)
    23  
    24  	// Dummy interceptor maintained for backward compatibility to avoid returning nil.
    25  	if n == 0 {
    26  		return func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    27  			return handler(ctx, req)
    28  		}
    29  	}
    30  
    31  	// The degenerate case, just return the single wrapped interceptor directly.
    32  	if n == 1 {
    33  		return interceptors[0]
    34  	}
    35  
    36  	// Return a function which satisfies the interceptor interface, and which is
    37  	// a closure over the given list of interceptors to be chained.
    38  	return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    39  		currHandler := handler
    40  		// Iterate backwards through all interceptors except the first (outermost).
    41  		// Wrap each one in a function which satisfies the handler interface, but
    42  		// is also a closure over the `info` and `handler` parameters. Then pass
    43  		// each pseudo-handler to the next outer interceptor as the handler to be called.
    44  		for i := n - 1; i > 0; i-- {
    45  			// Rebind to loop-local vars so they can be closed over.
    46  			innerHandler, i := currHandler, i
    47  			currHandler = func(currentCtx context.Context, currentReq interface{}) (interface{}, error) {
    48  				return interceptors[i](currentCtx, currentReq, info, innerHandler)
    49  			}
    50  		}
    51  		// Finally return the result of calling the outermost interceptor with the
    52  		// outermost pseudo-handler created above as its handler.
    53  		return interceptors[0](ctx, req, info, currHandler)
    54  	}
    55  }
    56  
    57  // ChainStreamServer creates a single interceptor out of a chain of many interceptors.
    58  //
    59  // Execution is done in left-to-right order, including passing of context.
    60  // For example ChainUnaryServer(one, two, three) will execute one before two before three.
    61  // If you want to pass context between interceptors, use WrapServerStream.
    62  //
    63  // While this can be useful in some scenarios, it is generally advisable to use google.golang.org/grpc.ChainStreamInterceptor directly.
    64  func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.StreamServerInterceptor {
    65  	n := len(interceptors)
    66  
    67  	// Dummy interceptor maintained for backward compatibility to avoid returning nil.
    68  	if n == 0 {
    69  		return func(srv interface{}, stream grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
    70  			return handler(srv, stream)
    71  		}
    72  	}
    73  
    74  	if n == 1 {
    75  		return interceptors[0]
    76  	}
    77  
    78  	return func(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
    79  		currHandler := handler
    80  		for i := n - 1; i > 0; i-- {
    81  			innerHandler, i := currHandler, i
    82  			currHandler = func(currentSrv interface{}, currentStream grpc.ServerStream) error {
    83  				return interceptors[i](currentSrv, currentStream, info, innerHandler)
    84  			}
    85  		}
    86  		return interceptors[0](srv, stream, info, currHandler)
    87  	}
    88  }
    89  
    90  // ChainUnaryClient creates a single interceptor out of a chain of many interceptors.
    91  //
    92  // Execution is done in left-to-right order, including passing of context.
    93  // For example ChainUnaryClient(one, two, three) will execute one before two before three.
    94  func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryClientInterceptor {
    95  	n := len(interceptors)
    96  
    97  	// Dummy interceptor maintained for backward compatibility to avoid returning nil.
    98  	if n == 0 {
    99  		return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
   100  			return invoker(ctx, method, req, reply, cc, opts...)
   101  		}
   102  	}
   103  
   104  	if n == 1 {
   105  		return interceptors[0]
   106  	}
   107  
   108  	return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
   109  		currInvoker := invoker
   110  		for i := n - 1; i > 0; i-- {
   111  			innerInvoker, i := currInvoker, i
   112  			currInvoker = func(currentCtx context.Context, currentMethod string, currentReq, currentRepl interface{}, currentConn *grpc.ClientConn, currentOpts ...grpc.CallOption) error {
   113  				return interceptors[i](currentCtx, currentMethod, currentReq, currentRepl, currentConn, innerInvoker, currentOpts...)
   114  			}
   115  		}
   116  		return interceptors[0](ctx, method, req, reply, cc, currInvoker, opts...)
   117  	}
   118  }
   119  
   120  // ChainStreamClient creates a single interceptor out of a chain of many interceptors.
   121  //
   122  // Execution is done in left-to-right order, including passing of context.
   123  // For example ChainStreamClient(one, two, three) will execute one before two before three.
   124  func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.StreamClientInterceptor {
   125  	n := len(interceptors)
   126  
   127  	// Dummy interceptor maintained for backward compatibility to avoid returning nil.
   128  	if n == 0 {
   129  		return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
   130  			return streamer(ctx, desc, cc, method, opts...)
   131  		}
   132  	}
   133  
   134  	if n == 1 {
   135  		return interceptors[0]
   136  	}
   137  
   138  	return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
   139  		currStreamer := streamer
   140  		for i := n - 1; i > 0; i-- {
   141  			innerStreamer, i := currStreamer, i
   142  			currStreamer = func(currentCtx context.Context, currentDesc *grpc.StreamDesc, currentConn *grpc.ClientConn, currentMethod string, currentOpts ...grpc.CallOption) (grpc.ClientStream, error) {
   143  				return interceptors[i](currentCtx, currentDesc, currentConn, currentMethod, innerStreamer, currentOpts...)
   144  			}
   145  		}
   146  		return interceptors[0](ctx, desc, cc, method, currStreamer, opts...)
   147  	}
   148  }
   149  
   150  // Chain creates a single interceptor out of a chain of many interceptors.
   151  //
   152  // WithUnaryServerChain is a grpc.Server config option that accepts multiple unary interceptors.
   153  // Basically syntactic sugar.
   154  //
   155  // Deprecated: use google.golang.org/grpc.ChainUnaryInterceptor instead.
   156  func WithUnaryServerChain(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption {
   157  	return grpc.ChainUnaryInterceptor(interceptors...)
   158  }
   159  
   160  // WithStreamServerChain is a grpc.Server config option that accepts multiple stream interceptors.
   161  // Basically syntactic sugar.
   162  //
   163  // Deprecated: use google.golang.org/grpc.ChainStreamInterceptor instead.
   164  func WithStreamServerChain(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption {
   165  	return grpc.ChainStreamInterceptor(interceptors...)
   166  }
   167  

View as plain text