blob: ea3738b896cfd93d2189c6fd1fe31db09fb52063 [file] [log] [blame]
Girish Kumar2ed051b2020-07-28 16:35:25 +00001// Copyright 2016 Michal Witkowski. All Rights Reserved.
2// See LICENSE for licensing terms.
3
4// gRPC Server Interceptor chaining middleware.
5
6package grpc_middleware
7
8import (
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +00009 "context"
10
Girish Kumar2ed051b2020-07-28 16:35:25 +000011 "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.
19func ChainUnaryServer(interceptors ...grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor {
20 n := len(interceptors)
21
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000022 return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
23 chainer := func(currentInter grpc.UnaryServerInterceptor, currentHandler grpc.UnaryHandler) grpc.UnaryHandler {
24 return func(currentCtx context.Context, currentReq interface{}) (interface{}, error) {
25 return currentInter(currentCtx, currentReq, info, currentHandler)
Girish Kumar2ed051b2020-07-28 16:35:25 +000026 }
Girish Kumar2ed051b2020-07-28 16:35:25 +000027 }
Girish Kumar2ed051b2020-07-28 16:35:25 +000028
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000029 chainedHandler := handler
30 for i := n - 1; i >= 0; i-- {
31 chainedHandler = chainer(interceptors[i], chainedHandler)
32 }
Girish Kumar2ed051b2020-07-28 16:35:25 +000033
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000034 return chainedHandler(ctx, req)
Girish Kumar2ed051b2020-07-28 16:35:25 +000035 }
36}
37
38// ChainStreamServer creates a single interceptor out of a chain of many interceptors.
39//
40// Execution is done in left-to-right order, including passing of context.
41// For example ChainUnaryServer(one, two, three) will execute one before two before three.
42// If you want to pass context between interceptors, use WrapServerStream.
43func ChainStreamServer(interceptors ...grpc.StreamServerInterceptor) grpc.StreamServerInterceptor {
44 n := len(interceptors)
45
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000046 return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
47 chainer := func(currentInter grpc.StreamServerInterceptor, currentHandler grpc.StreamHandler) grpc.StreamHandler {
48 return func(currentSrv interface{}, currentStream grpc.ServerStream) error {
49 return currentInter(currentSrv, currentStream, info, currentHandler)
Girish Kumar2ed051b2020-07-28 16:35:25 +000050 }
Girish Kumar2ed051b2020-07-28 16:35:25 +000051 }
Girish Kumar2ed051b2020-07-28 16:35:25 +000052
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000053 chainedHandler := handler
54 for i := n - 1; i >= 0; i-- {
55 chainedHandler = chainer(interceptors[i], chainedHandler)
56 }
Girish Kumar2ed051b2020-07-28 16:35:25 +000057
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000058 return chainedHandler(srv, ss)
Girish Kumar2ed051b2020-07-28 16:35:25 +000059 }
60}
61
62// ChainUnaryClient creates a single interceptor out of a chain of many interceptors.
63//
64// Execution is done in left-to-right order, including passing of context.
65// For example ChainUnaryClient(one, two, three) will execute one before two before three.
66func ChainUnaryClient(interceptors ...grpc.UnaryClientInterceptor) grpc.UnaryClientInterceptor {
67 n := len(interceptors)
68
Girish Kumar2ed051b2020-07-28 16:35:25 +000069 return func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000070 chainer := func(currentInter grpc.UnaryClientInterceptor, currentInvoker grpc.UnaryInvoker) grpc.UnaryInvoker {
71 return func(currentCtx context.Context, currentMethod string, currentReq, currentRepl interface{}, currentConn *grpc.ClientConn, currentOpts ...grpc.CallOption) error {
72 return currentInter(currentCtx, currentMethod, currentReq, currentRepl, currentConn, currentInvoker, currentOpts...)
73 }
74 }
75
76 chainedInvoker := invoker
77 for i := n - 1; i >= 0; i-- {
78 chainedInvoker = chainer(interceptors[i], chainedInvoker)
79 }
80
81 return chainedInvoker(ctx, method, req, reply, cc, opts...)
Girish Kumar2ed051b2020-07-28 16:35:25 +000082 }
83}
84
85// ChainStreamClient creates a single interceptor out of a chain of many interceptors.
86//
87// Execution is done in left-to-right order, including passing of context.
88// For example ChainStreamClient(one, two, three) will execute one before two before three.
89func ChainStreamClient(interceptors ...grpc.StreamClientInterceptor) grpc.StreamClientInterceptor {
90 n := len(interceptors)
91
Girish Kumar2ed051b2020-07-28 16:35:25 +000092 return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) {
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +000093 chainer := func(currentInter grpc.StreamClientInterceptor, currentStreamer grpc.Streamer) grpc.Streamer {
94 return func(currentCtx context.Context, currentDesc *grpc.StreamDesc, currentConn *grpc.ClientConn, currentMethod string, currentOpts ...grpc.CallOption) (grpc.ClientStream, error) {
95 return currentInter(currentCtx, currentDesc, currentConn, currentMethod, currentStreamer, currentOpts...)
96 }
97 }
98
99 chainedStreamer := streamer
100 for i := n - 1; i >= 0; i-- {
101 chainedStreamer = chainer(interceptors[i], chainedStreamer)
102 }
103
104 return chainedStreamer(ctx, desc, cc, method, opts...)
Girish Kumar2ed051b2020-07-28 16:35:25 +0000105 }
106}
107
108// Chain creates a single interceptor out of a chain of many interceptors.
109//
110// WithUnaryServerChain is a grpc.Server config option that accepts multiple unary interceptors.
111// Basically syntactic sugar.
112func WithUnaryServerChain(interceptors ...grpc.UnaryServerInterceptor) grpc.ServerOption {
113 return grpc.UnaryInterceptor(ChainUnaryServer(interceptors...))
114}
115
116// WithStreamServerChain is a grpc.Server config option that accepts multiple stream interceptors.
117// Basically syntactic sugar.
118func WithStreamServerChain(interceptors ...grpc.StreamServerInterceptor) grpc.ServerOption {
119 return grpc.StreamInterceptor(ChainStreamServer(interceptors...))
120}