forked from juju/juju
/
caller.go
180 lines (150 loc) · 6.41 KB
/
caller.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package base
import (
"context"
"io"
"net/http"
"net/url"
"github.com/go-macaroon-bakery/macaroon-bakery/v3/bakery"
"github.com/juju/names/v4"
"gopkg.in/httprequest.v1"
"gopkg.in/macaroon.v2"
)
//go:generate go run github.com/golang/mock/mockgen -package mocks -destination mocks/caller_mock.go github.com/DavinZhang/juju/api/base APICaller,FacadeCaller
// APICaller is implemented by the client-facing State object.
// It defines the lowest level of API calls and is used by
// the various API implementations to actually make
// the calls to the API. It should not be used outside
// of tests or the api/* hierarchy.
type APICaller interface {
// APICall makes a call to the API server with the given object type,
// id, request and parameters. The response is filled in with the
// call's result if the call is successful.
APICall(objType string, version int, id, request string, params, response interface{}) error
// BestFacadeVersion returns the newest version of 'objType' that this
// client can use with the current API server.
BestFacadeVersion(facade string) int
// ModelTag returns the tag of the model the client is connected
// to if there is one. It returns false for a controller-only connection.
ModelTag() (names.ModelTag, bool)
// HTTPClient returns an httprequest.Client that can be used
// to make HTTP requests to the API. URLs passed to the client
// will be made relative to the API host and the current model.
//
// Note that the URLs in HTTP requests passed to the Client.Do
// method should not include a host part.
HTTPClient() (*httprequest.Client, error)
// BakeryClient returns the bakery client for this connection.
BakeryClient() MacaroonDischarger
// Context returns the standard context for this connection.
Context() context.Context
StreamConnector
ControllerStreamConnector
}
// MacaroonDischarger instances provide a method to discharge macaroons.
type MacaroonDischarger interface {
// DischargeAll attempts to acquire discharge macaroons for all the
// third party caveats in m, and returns a slice containing all
// of them bound to m.
DischargeAll(ctx context.Context, m *bakery.Macaroon) (macaroon.Slice, error)
}
// StreamConnector is implemented by the client-facing State object.
type StreamConnector interface {
// ConnectStream connects to the given HTTP websocket
// endpoint path (interpreted relative to the receiver's
// model) and returns the resulting connection.
// The given parameters are used as URL query values
// when making the initial HTTP request.
//
// The path must start with a "/".
ConnectStream(path string, attrs url.Values) (Stream, error)
}
// ControllerStreamConnector is implemented by the client-facing State object.
type ControllerStreamConnector interface {
// ConnectControllerStream connects to the given HTTP websocket
// endpoint path and returns the resulting connection. The given
// values are used as URL query values when making the initial
// HTTP request. Headers passed in will be added to the HTTP
// request.
//
// The path must be absolute and can't start with "/model".
ConnectControllerStream(path string, attrs url.Values, headers http.Header) (Stream, error)
}
// Stream represents a streaming connection to the API.
type Stream interface {
io.Closer
// NextReader is used to get direct access to the underlying Read methods
// on the websocket. Mostly just to read the initial error resonse.
NextReader() (messageType int, r io.Reader, err error)
// WriteJSON encodes the given value as JSON
// and writes it to the connection.
WriteJSON(v interface{}) error
// ReadJSON reads a JSON value from the stream
// and decodes it into the element pointed to by
// the given value, which should be a pointer.
ReadJSON(v interface{}) error
}
// FacadeCaller is a wrapper for the common paradigm that a given client just
// wants to make calls on a facade using the best known version of the API. And
// without dealing with an id parameter.
type FacadeCaller interface {
// FacadeCall will place a request against the API using the requested
// Facade and the best version that the API server supports that is
// also known to the client.
FacadeCall(request string, params, response interface{}) error
// Name returns the facade name.
Name() string
// BestAPIVersion returns the API version that we were able to
// determine is supported by both the client and the API Server
BestAPIVersion() int
// RawAPICaller returns the wrapped APICaller. This can be used if you need
// to switch what Facade you are calling (such as Facades that return
// Watchers and then need to use the Watcher facade)
RawAPICaller() APICaller
}
type facadeCaller struct {
facadeName string
bestVersion int
caller APICaller
}
var _ FacadeCaller = facadeCaller{}
// FacadeCall will place a request against the API using the requested
// Facade and the best version that the API server supports that is
// also known to the client. (id is always passed as the empty string.)
func (fc facadeCaller) FacadeCall(request string, params, response interface{}) error {
return fc.caller.APICall(
fc.facadeName, fc.bestVersion, "",
request, params, response)
}
// Name returns the facade name.
func (fc facadeCaller) Name() string {
return fc.facadeName
}
// BestAPIVersion returns the version of the Facade that is going to be used
// for calls. It is determined using the algorithm defined in api
// BestFacadeVersion. Callers can use this to determine what methods must be
// used for compatibility.
func (fc facadeCaller) BestAPIVersion() int {
return fc.bestVersion
}
// RawAPICaller returns the wrapped APICaller. This can be used if you need to
// switch what Facade you are calling (such as Facades that return Watchers and
// then need to use the Watcher facade)
func (fc facadeCaller) RawAPICaller() APICaller {
return fc.caller
}
// NewFacadeCaller wraps an APICaller for a given facade name and the
// best available version.
func NewFacadeCaller(caller APICaller, facadeName string) FacadeCaller {
return NewFacadeCallerForVersion(caller, facadeName, caller.BestFacadeVersion(facadeName))
}
// NewFacadeCallerForVersion wraps an APICaller for a given facade
// name and version.
func NewFacadeCallerForVersion(caller APICaller, facadeName string, version int) FacadeCaller {
return facadeCaller{
facadeName: facadeName,
bestVersion: version,
caller: caller,
}
}