schnutibox/vendor/github.com/twitchtv/twirp/interceptors.go

73 lines
2.6 KiB
Go
Raw Normal View History

// Copyright 2018 Twitch Interactive, Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may not
// use this file except in compliance with the License. A copy of the License is
// located at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// or in the "license" file accompanying this file. This file is distributed on
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
package twirp
import (
"context"
)
// Interceptor is a form of middleware for Twirp requests, that can be installed on both
// clients and servers. To intercept RPC calls in the client, use the option
// `twirp.WithClientInterceptors` on the client constructor. To intercept RPC calls in the server,
// use the option `twirp.WithServerInterceptors` on the server constructor.
//
// Just like http middleware, interceptors can mutate requests and responses.
// This can enable some powerful integrations, but it should be used with much care
// becuase it may result in code that is very hard to debug.
//
// Example of an interceptor that logs every request and response:
//
// func LogInterceptor(l *log.Logger) twirp.Interceptor {
// return func(next twirp.Method) twirp.Method {
// return func(ctx context.Context, req interface{}) (interface{}, error) {
// l.Printf("Service: %s, Method: %s, Request: %v",
// twirp.ServiceName(ctx), twirp.MethodName(ctx), req)
// resp, err := next(ctx, req)
// l.Printf("Response: %v, Error: %v", resp)
// return resp, err
// }
// }
// }
//
type Interceptor func(Method) Method
// Method is a generic representation of a Twirp-generated RPC method.
// It is used to define Interceptors.
type Method func(ctx context.Context, request interface{}) (interface{}, error)
// ChainInterceptors chains multiple Interceptors into a single Interceptor.
// The first interceptor wraps the second one, and so on.
// Returns nil if interceptors is empty. Nil interceptors are ignored.
func ChainInterceptors(interceptors ...Interceptor) Interceptor {
filtered := make([]Interceptor, 0, len(interceptors))
for _, interceptor := range interceptors {
if interceptor != nil {
filtered = append(filtered, interceptor)
}
}
switch n := len(filtered); n {
case 0:
return nil
case 1:
return filtered[0]
default:
first := filtered[0]
return func(next Method) Method {
for i := len(filtered) - 1; i > 0; i-- {
next = filtered[i](next)
}
return first(next)
}
}
}