github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/base/caller.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package base 5 6 import ( 7 "io" 8 "net/http" 9 "net/url" 10 11 "github.com/juju/httprequest" 12 "gopkg.in/juju/names.v2" 13 "gopkg.in/macaroon-bakery.v2-unstable/httpbakery" 14 ) 15 16 //go:generate mockgen -package mocks -destination mocks/caller_mock.go github.com/juju/juju/api/base APICaller,FacadeCaller 17 18 // APICaller is implemented by the client-facing State object. 19 // It defines the lowest level of API calls and is used by 20 // the various API implementations to actually make 21 // the calls to the API. It should not be used outside 22 // of tests or the api/* hierarchy. 23 type APICaller interface { 24 // APICall makes a call to the API server with the given object type, 25 // id, request and parameters. The response is filled in with the 26 // call's result if the call is successful. 27 APICall(objType string, version int, id, request string, params, response interface{}) error 28 29 // BestFacadeVersion returns the newest version of 'objType' that this 30 // client can use with the current API server. 31 BestFacadeVersion(facade string) int 32 33 // ModelTag returns the tag of the model the client is connected 34 // to if there is one. It returns false for a controller-only connection. 35 ModelTag() (names.ModelTag, bool) 36 37 // HTTPClient returns an httprequest.Client that can be used 38 // to make HTTP requests to the API. URLs passed to the client 39 // will be made relative to the API host and the current model. 40 // 41 // Note that the URLs in HTTP requests passed to the Client.Do 42 // method should not include a host part. 43 HTTPClient() (*httprequest.Client, error) 44 45 // BakeryClient returns the bakery client for this connection. 46 BakeryClient() *httpbakery.Client 47 48 StreamConnector 49 ControllerStreamConnector 50 } 51 52 // StreamConnector is implemented by the client-facing State object. 53 type StreamConnector interface { 54 // ConnectStream connects to the given HTTP websocket 55 // endpoint path (interpreted relative to the receiver's 56 // model) and returns the resulting connection. 57 // The given parameters are used as URL query values 58 // when making the initial HTTP request. 59 // 60 // The path must start with a "/". 61 ConnectStream(path string, attrs url.Values) (Stream, error) 62 } 63 64 // ControllerStreamConnector is implemented by the client-facing State object. 65 type ControllerStreamConnector interface { 66 // ConnectControllerStream connects to the given HTTP websocket 67 // endpoint path and returns the resulting connection. The given 68 // values are used as URL query values when making the initial 69 // HTTP request. Headers passed in will be added to the HTTP 70 // request. 71 // 72 // The path must be absolute and can't start with "/model". 73 ConnectControllerStream(path string, attrs url.Values, headers http.Header) (Stream, error) 74 } 75 76 // Stream represents a streaming connection to the API. 77 type Stream interface { 78 io.Closer 79 80 // NextReader is used to get direct access to the underlying Read methods 81 // on the websocket. Mostly just to read the initial error resonse. 82 NextReader() (messageType int, r io.Reader, err error) 83 84 // WriteJSON encodes the given value as JSON 85 // and writes it to the connection. 86 WriteJSON(v interface{}) error 87 88 // ReadJSON reads a JSON value from the stream 89 // and decodes it into the element pointed to by 90 // the given value, which should be a pointer. 91 ReadJSON(v interface{}) error 92 } 93 94 // FacadeCaller is a wrapper for the common paradigm that a given client just 95 // wants to make calls on a facade using the best known version of the API. And 96 // without dealing with an id parameter. 97 type FacadeCaller interface { 98 // FacadeCall will place a request against the API using the requested 99 // Facade and the best version that the API server supports that is 100 // also known to the client. 101 FacadeCall(request string, params, response interface{}) error 102 103 // Name returns the facade name. 104 Name() string 105 106 // BestAPIVersion returns the API version that we were able to 107 // determine is supported by both the client and the API Server 108 BestAPIVersion() int 109 110 // RawAPICaller returns the wrapped APICaller. This can be used if you need 111 // to switch what Facade you are calling (such as Facades that return 112 // Watchers and then need to use the Watcher facade) 113 RawAPICaller() APICaller 114 } 115 116 type facadeCaller struct { 117 facadeName string 118 bestVersion int 119 caller APICaller 120 } 121 122 var _ FacadeCaller = facadeCaller{} 123 124 // FacadeCall will place a request against the API using the requested 125 // Facade and the best version that the API server supports that is 126 // also known to the client. (id is always passed as the empty string.) 127 func (fc facadeCaller) FacadeCall(request string, params, response interface{}) error { 128 return fc.caller.APICall( 129 fc.facadeName, fc.bestVersion, "", 130 request, params, response) 131 } 132 133 // Name returns the facade name. 134 func (fc facadeCaller) Name() string { 135 return fc.facadeName 136 } 137 138 // BestAPIVersion returns the version of the Facade that is going to be used 139 // for calls. It is determined using the algorithm defined in api 140 // BestFacadeVersion. Callers can use this to determine what methods must be 141 // used for compatibility. 142 func (fc facadeCaller) BestAPIVersion() int { 143 return fc.bestVersion 144 } 145 146 // RawAPICaller returns the wrapped APICaller. This can be used if you need to 147 // switch what Facade you are calling (such as Facades that return Watchers and 148 // then need to use the Watcher facade) 149 func (fc facadeCaller) RawAPICaller() APICaller { 150 return fc.caller 151 } 152 153 // NewFacadeCaller wraps an APICaller for a given facade name and the 154 // best available version. 155 func NewFacadeCaller(caller APICaller, facadeName string) FacadeCaller { 156 return NewFacadeCallerForVersion(caller, facadeName, caller.BestFacadeVersion(facadeName)) 157 } 158 159 // NewFacadeCallerForVersion wraps an APICaller for a given facade 160 // name and version. 161 func NewFacadeCallerForVersion(caller APICaller, facadeName string, version int) FacadeCaller { 162 return facadeCaller{ 163 facadeName: facadeName, 164 bestVersion: version, 165 caller: caller, 166 } 167 }