/
outbound_call.go
131 lines (116 loc) · 4.44 KB
/
outbound_call.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
// Copyright (c) 2021 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package encoding
import (
"context"
"go.uber.org/yarpc/api/transport"
"go.uber.org/yarpc/yarpcerrors"
)
// OutboundCall is an outgoing call. It holds per-call options for a request.
//
// Encoding authors may use OutboundCall to provide a CallOption-based request
// customization mechanism, including returning response headers through
// ResponseHeaders.
type OutboundCall struct {
// request attributes to fill if non-nil
headers []keyValuePair
shardKey *string
routingKey *string
routingDelegate *string
// If non-nil, response headers should be written here.
responseHeaders *map[string]string
}
// NewOutboundCall constructs a new OutboundCall with the given options.
func NewOutboundCall(options ...CallOption) *OutboundCall {
var call OutboundCall
for _, opt := range options {
opt.apply(&call)
}
return &call
}
// NewStreamOutboundCall constructs a new OutboundCall with the given
// options and enforces the OutboundCall is valid for streams.
func NewStreamOutboundCall(options ...CallOption) (*OutboundCall, error) {
call := NewOutboundCall(options...)
if call.responseHeaders != nil {
return nil, yarpcerrors.InvalidArgumentErrorf("response headers are not supported for streams")
}
return call, nil
}
// WriteToRequest fills the given request with request-specific options from
// the call.
//
// The context MAY be replaced by the OutboundCall.
func (c *OutboundCall) WriteToRequest(ctx context.Context, req *transport.Request) (context.Context, error) {
for _, h := range c.headers {
req.Headers = req.Headers.With(h.k, h.v)
}
if c.shardKey != nil {
req.ShardKey = *c.shardKey
}
if c.routingKey != nil {
req.RoutingKey = *c.routingKey
}
if c.routingDelegate != nil {
req.RoutingDelegate = *c.routingDelegate
}
// NB(abg): context and error are unused for now but we want to leave room
// for CallOptions which can fail or modify the context.
return ctx, nil
}
// WriteToRequestMeta fills the given request with request-specific options from
// the call.
//
// The context MAY be replaced by the OutboundCall.
func (c *OutboundCall) WriteToRequestMeta(ctx context.Context, reqMeta *transport.RequestMeta) (context.Context, error) {
for _, h := range c.headers {
reqMeta.Headers = reqMeta.Headers.With(h.k, h.v)
}
if c.shardKey != nil {
reqMeta.ShardKey = *c.shardKey
}
if c.routingKey != nil {
reqMeta.RoutingKey = *c.routingKey
}
if c.routingDelegate != nil {
reqMeta.RoutingDelegate = *c.routingDelegate
}
// NB(abg): context and error are unused for now but we want to leave room
// for CallOptions which can fail or modify the context.
return ctx, nil
}
// ReadFromResponse reads information from the response for this call.
//
// This should be called only if the request is unary.
func (c *OutboundCall) ReadFromResponse(ctx context.Context, res *transport.Response) (context.Context, error) {
// We're not using ctx right now but we may in the future.
if c.responseHeaders != nil && res.Headers.Len() > 0 {
// We make a copy of the response headers because Headers.Items() must
// never be mutated.
headers := make(map[string]string, res.Headers.Len())
for k, v := range res.Headers.Items() {
headers[k] = v
}
*c.responseHeaders = headers
}
// NB(abg): context and error are unused for now but we want to leave room
// for CallOptions which can fail or modify the context.
return ctx, nil
}