forked from twitchtv/twirp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclient_options.go
132 lines (121 loc) · 4.37 KB
/
client_options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// 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"
"net/http"
)
// ClientOption is a functional option for extending a Twirp client.
type ClientOption func(*ClientOptions)
// ClientOptions encapsulate the configurable parameters on a Twirp client.
type ClientOptions struct {
Interceptors []Interceptor
Hooks *ClientHooks
pathPrefix *string
}
func (opts *ClientOptions) PathPrefix() string {
if opts.pathPrefix == nil {
return "/twirp" // default prefix
}
return *opts.pathPrefix
}
// WithClientInterceptors defines the interceptors for a Twirp client.
func WithClientInterceptors(interceptors ...Interceptor) ClientOption {
return func(o *ClientOptions) {
o.Interceptors = append(o.Interceptors, interceptors...)
}
}
// WithClientHooks defines the hooks for a Twirp client.
func WithClientHooks(hooks *ClientHooks) ClientOption {
return func(o *ClientOptions) {
o.Hooks = hooks
}
}
// ClientHooks is a container for callbacks that can instrument a
// Twirp-generated client. These callbacks all accept a context and some return
// a context. They can use this to add to the context, appending values or
// deadlines to it.
//
// The RequestPrepared hook is special because it can return errors. If it
// returns non-nil error, handling for that request will be stopped at that
// point. The Error hook will then be triggered.
//
// The RequestPrepared hook will always be called first and will be called for
// each outgoing request from the Twirp client. The last hook to be called
// will either be Error or ResponseReceived, so be sure to handle both cases in
// your hooks.
type ClientHooks struct {
// RequestPrepared is called as soon as a request has been created and before
// it has been sent to the Twirp server.
RequestPrepared func(context.Context, *http.Request) (context.Context, error)
// ResponseReceived is called after a request has finished sending. Since this
// is terminal, the context is not returned. ResponseReceived will not be
// called in the case of an error being returned from the request.
ResponseReceived func(context.Context)
// Error hook is called whenever an error occurs during the sending of a
// request. The Error is passed as an argument to the hook.
Error func(context.Context, Error)
}
// ChainClientHooks creates a new *ClientHooks which chains the callbacks in
// each of the constituent hooks passed in. Each hook function will be
// called in the order of the ClientHooks values passed in.
//
// For the erroring hook, RequestPrepared, any returned
// errors prevent processing by later hooks.
func ChainClientHooks(hooks ...*ClientHooks) *ClientHooks {
if len(hooks) == 0 {
return nil
}
if len(hooks) == 1 {
return hooks[0]
}
return &ClientHooks{
RequestPrepared: func(ctx context.Context, req *http.Request) (context.Context, error) {
for _, h := range hooks {
if h != nil && h.RequestPrepared != nil {
var err error
ctx, err = h.RequestPrepared(ctx, req)
if err != nil {
return ctx, err
}
}
}
return ctx, nil
},
ResponseReceived: func(ctx context.Context) {
for _, h := range hooks {
if h != nil && h.ResponseReceived != nil {
h.ResponseReceived(ctx)
}
}
},
Error: func(ctx context.Context, twerr Error) {
for _, h := range hooks {
if h != nil && h.Error != nil {
h.Error(ctx, twerr)
}
}
},
}
}
// WithClientPathPrefix specifies a different prefix to use for routing.
// If not specified, the "/twirp" prefix is used by default.
// The service must be configured to serve on the same prefix.
// An empty value "" can be speficied to use no prefix.
// URL format: "<baseURL>[<prefix>]/<package>.<Service>/<Method>"
// More info on Twirp docs: https://twitchtv.github.io/twirp/docs/routing.html
func WithClientPathPrefix(prefix string) ClientOption {
return func(o *ClientOptions) {
o.pathPrefix = &prefix
}
}