github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  	"fmt"
     8  	"io"
     9  	"net/url"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/httprequest"
    13  	"github.com/juju/names"
    14  )
    15  
    16  // OldAgentError is returned when an api call is not supported
    17  // by the Juju agent.
    18  func OldAgentError(operation string, vers string) error {
    19  	return errors.NewNotSupported(
    20  		nil, fmt.Sprintf("%s not supported. Please upgrade API server to Juju %v or later", operation, vers))
    21  }
    22  
    23  // APICaller is implemented by the client-facing State object.
    24  // It defines the lowest level of API calls and is used by
    25  // the various API implementations to actually make
    26  // the calls to the API. It should not be used outside
    27  // of tests or the api/* hierarchy.
    28  type APICaller interface {
    29  	// APICall makes a call to the API server with the given object type,
    30  	// id, request and parameters. The response is filled in with the
    31  	// call's result if the call is successful.
    32  	APICall(objType string, version int, id, request string, params, response interface{}) error
    33  
    34  	// BestFacadeVersion returns the newest version of 'objType' that this
    35  	// client can use with the current API server.
    36  	BestFacadeVersion(facade string) int
    37  
    38  	// ModelTag returns the tag of the model the client is
    39  	// connected to.
    40  	ModelTag() (names.ModelTag, error)
    41  
    42  	// HTTPClient returns an httprequest.Client that can be used
    43  	// to make HTTP requests to the API. URLs passed to the client
    44  	// will be made relative to the API host and the current model.
    45  	//
    46  	// Note that the URLs in HTTP requests passed to the Client.Do
    47  	// method should not include a host part.
    48  	HTTPClient() (*httprequest.Client, error)
    49  
    50  	StreamConnector
    51  }
    52  
    53  // StreamConnector is implemented by the client-facing State object.
    54  type StreamConnector interface {
    55  	// ConnectStream connects to the given HTTP websocket
    56  	// endpoint path (interpreted relative to the receiver's
    57  	// model) and returns the resulting connection.
    58  	// The given parameters are used as URL query values
    59  	// when making the initial HTTP request.
    60  	//
    61  	// The path must start with a "/".
    62  	ConnectStream(path string, attrs url.Values) (Stream, error)
    63  }
    64  
    65  // Stream represents a streaming connection to the API.
    66  type Stream interface {
    67  	io.ReadWriteCloser
    68  
    69  	// WriteJSON encodes the given value as JSON
    70  	// and writes it to the connection.
    71  	WriteJSON(v interface{}) error
    72  
    73  	// ReadJSON reads a JSON value from the stream
    74  	// and decodes it into the element pointed to by
    75  	// the given value, which should be a pointer.
    76  	ReadJSON(v interface{}) error
    77  }
    78  
    79  // FacadeCaller is a wrapper for the common paradigm that a given client just
    80  // wants to make calls on a facade using the best known version of the API. And
    81  // without dealing with an id parameter.
    82  type FacadeCaller interface {
    83  	// FacadeCall will place a request against the API using the requested
    84  	// Facade and the best version that the API server supports that is
    85  	// also known to the client.
    86  	FacadeCall(request string, params, response interface{}) error
    87  
    88  	// Name returns the facade name.
    89  	Name() string
    90  
    91  	// BestAPIVersion returns the API version that we were able to
    92  	// determine is supported by both the client and the API Server
    93  	BestAPIVersion() int
    94  
    95  	// RawAPICaller returns the wrapped APICaller. This can be used if you need
    96  	// to switch what Facade you are calling (such as Facades that return
    97  	// Watchers and then need to use the Watcher facade)
    98  	RawAPICaller() APICaller
    99  }
   100  
   101  type facadeCaller struct {
   102  	facadeName  string
   103  	bestVersion int
   104  	caller      APICaller
   105  }
   106  
   107  var _ FacadeCaller = facadeCaller{}
   108  
   109  // FacadeCall will place a request against the API using the requested
   110  // Facade and the best version that the API server supports that is
   111  // also known to the client. (id is always passed as the empty string.)
   112  func (fc facadeCaller) FacadeCall(request string, params, response interface{}) error {
   113  	return fc.caller.APICall(
   114  		fc.facadeName, fc.bestVersion, "",
   115  		request, params, response)
   116  }
   117  
   118  // Name returns the facade name.
   119  func (fc facadeCaller) Name() string {
   120  	return fc.facadeName
   121  }
   122  
   123  // BestAPIVersion returns the version of the Facade that is going to be used
   124  // for calls. It is determined using the algorithm defined in api
   125  // BestFacadeVersion. Callers can use this to determine what methods must be
   126  // used for compatibility.
   127  func (fc facadeCaller) BestAPIVersion() int {
   128  	return fc.bestVersion
   129  }
   130  
   131  // RawAPICaller returns the wrapped APICaller. This can be used if you need to
   132  // switch what Facade you are calling (such as Facades that return Watchers and
   133  // then need to use the Watcher facade)
   134  func (fc facadeCaller) RawAPICaller() APICaller {
   135  	return fc.caller
   136  }
   137  
   138  // NewFacadeCaller wraps an APICaller for a given facade name and the
   139  // best available version.
   140  func NewFacadeCaller(caller APICaller, facadeName string) FacadeCaller {
   141  	return NewFacadeCallerForVersion(caller, facadeName, caller.BestFacadeVersion(facadeName))
   142  }
   143  
   144  // NewFacadeCallerForVersion wraps an APICaller for a given facade
   145  // name and version.
   146  func NewFacadeCallerForVersion(caller APICaller, facadeName string, version int) FacadeCaller {
   147  	return facadeCaller{
   148  		facadeName:  facadeName,
   149  		bestVersion: version,
   150  		caller:      caller,
   151  	}
   152  }