chain.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. // Copyright 2016 Michal Witkowski. All Rights Reserved.
  2. // See LICENSE for licensing terms.
  3. // gRPC Server Interceptor chaining middleware.
  4. package grpc_middleware
  5. import (
  6. "context"
  7. "google.golang.org/grpc"
  8. )
  9. // ChainUnaryServer creates a single interceptor out of a chain of many interceptors.
  10. //
  11. // Execution is done in left-to-right order, including passing of context.
  12. // For example ChainUnaryServer(one, two, three) will execute one before two before three, and three
  13. // will see context changes of one and two.
  14. func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor {
  15. n := len(interceptors)
  16. return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
  17. chainer := func(currentInter grpc.UnaryServerInterceptor, currentHandler grpc.UnaryHandler) grpc.UnaryHandler {
  18. return func(currentCtx context.Context, currentReq interface{}) (interface{}, error) {
  19. return currentInter(currentCtx, currentReq, info, currentHandler)
  20. }
  21. }
  22. chainedHandler := handler
  23. for i := n - 1; i >= 0; i-- {
  24. chainedHandler = chainer(interceptors[i], chainedHandler)
  25. }
  26. return chainedHandler(ctx, req)
  27. }
  28. }
  29. // ChainStreamServer creates a single interceptor out of a chain of many interceptors.
  30. //
  31. // Execution is done in left-to-right order, including passing of context.
  32. // For example ChainUnaryServer(one, two, three) will execute one before two before three.
  33. // If you want to pass context between interceptors, use WrapServerStream.
  34. func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.StreamServerInterceptor {
  35. n := len(interceptors)
  36. return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
  37. chainer := func(currentInter grpc.StreamServerInterceptor, currentHandler grpc.StreamHandler) grpc.StreamHandler {
  38. return func(currentSrv interface{}, currentStream grpc.ServerStream) error {
  39. return currentInter(currentSrv, currentStream, info, currentHandler)
  40. }
  41. }
  42. chainedHandler := handler
  43. for i := n - 1; i >= 0; i-- {
  44. chainedHandler = chainer(interceptors[i], chainedHandler)
  45. }
  46. return chainedHandler(srv, ss)
  47. }
  48. }
  49. // ChainUnaryClient creates a single interceptor out of a chain of many interceptors.
  50. //
  51. // Execution is done in left-to-right order, including passing of context.
  52. // For example ChainUnaryClient(one, two, three) will execute one before two before three.
  53. func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryClientInterceptor {
  54. n := len(interceptors)
  55. return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
  56. chainer := func(currentInter grpc.UnaryClientInterceptor, currentInvoker grpc.UnaryInvoker) grpc.UnaryInvoker {
  57. return func(currentCtx context.Context, currentMethod string, currentReq, currentRepl interface{}, currentConn *grpc.ClientConn, currentOpts ...grpc.CallOption) error {
  58. return currentInter(currentCtx, currentMethod, currentReq, currentRepl, currentConn, currentInvoker, currentOpts...)
  59. }
  60. }
  61. chainedInvoker := invoker
  62. for i := n - 1; i >= 0; i-- {
  63. chainedInvoker = chainer(interceptors[i], chainedInvoker)
  64. }
  65. return chainedInvoker(ctx, method, req, reply, cc, opts...)
  66. }
  67. }
  68. // ChainStreamClient creates a single interceptor out of a chain of many interceptors.
  69. //
  70. // Execution is done in left-to-right order, including passing of context.
  71. // For example ChainStreamClient(one, two, three) will execute one before two before three.
  72. func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.StreamClientInterceptor {
  73. n := len(interceptors)
  74. return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
  75. chainer := func(currentInter grpc.StreamClientInterceptor, currentStreamer grpc.Streamer) grpc.Streamer {
  76. return func(currentCtx context.Context, currentDesc *grpc.StreamDesc, currentConn *grpc.ClientConn, currentMethod string, currentOpts ...grpc.CallOption) (grpc.ClientStream, error) {
  77. return currentInter(currentCtx, currentDesc, currentConn, currentMethod, currentStreamer, currentOpts...)
  78. }
  79. }
  80. chainedStreamer := streamer
  81. for i := n - 1; i >= 0; i-- {
  82. chainedStreamer = chainer(interceptors[i], chainedStreamer)
  83. }
  84. return chainedStreamer(ctx, desc, cc, method, opts...)
  85. }
  86. }
  87. // Chain creates a single interceptor out of a chain of many interceptors.
  88. //
  89. // WithUnaryServerChain is a grpc.Server config option that accepts multiple unary interceptors.
  90. // Basically syntactic sugar.
  91. func WithUnaryServerChain(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption {
  92. return grpc.UnaryInterceptor(ChainUnaryServer(interceptors...))
  93. }
  94. // WithStreamServerChain is a grpc.Server config option that accepts multiple stream interceptors.
  95. // Basically syntactic sugar.
  96. func WithStreamServerChain(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption {
  97. return grpc.StreamInterceptor(ChainStreamServer(interceptors...))
  98. }