client: further clarify external interfaces

This commit is contained in:
Brian Waldon 2014-10-31 14:53:59 -07:00
parent 17c6f21d68
commit 58af26736c
4 changed files with 82 additions and 102 deletions

View File

@ -1,96 +0,0 @@
/*
Copyright 2014 CoreOS, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License 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 client
import (
"net/http"
"net/url"
"github.com/coreos/etcd/Godeps/_workspace/src/code.google.com/p/go.net/context"
)
type HTTPClient interface {
Do(context.Context, HTTPAction) (*http.Response, []byte, error)
Sync() error
}
type httpActionDo interface {
Do(context.Context, HTTPAction) (*http.Response, []byte, error)
}
type HTTPAction interface {
HTTPRequest(url.URL) *http.Request
}
// CancelableTransport mimics http.Transport to provide an interface which can be
// substituted for testing (since the RoundTripper interface alone does not
// require the CancelRequest method)
type CancelableTransport interface {
http.RoundTripper
CancelRequest(req *http.Request)
}
func NewHTTPClient(tr CancelableTransport, eps []string) (*httpClusterClient, error) {
c := httpClusterClient{
transport: tr,
endpoints: make([]httpActionDo, len(eps)),
}
for i, ep := range eps {
u, err := url.Parse(ep)
if err != nil {
return nil, err
}
c.endpoints[i] = &httpClient{
transport: tr,
endpoint: *u,
}
}
return &c, nil
}
type httpClusterClient struct {
transport CancelableTransport
endpoints []httpActionDo
}
func (c *httpClusterClient) Do(ctx context.Context, act HTTPAction) (*http.Response, []byte, error) {
//TODO(bcwaldon): introduce retry logic so all endpoints are attempted
return c.endpoints[0].Do(ctx, act)
}
func (c *httpClusterClient) Sync(ctx context.Context) error {
mAPI := NewMembersAPI(c)
ms, err := mAPI.List(ctx)
if err != nil {
return err
}
eps := make([]string, 0)
for _, m := range ms {
eps = append(eps, m.ClientURLs...)
}
nc, err := NewHTTPClient(c.transport, eps)
if err != nil {
return err
}
*c = *nc
return nil
}

View File

@ -30,6 +30,82 @@ var (
DefaultRequestTimeout = 5 * time.Second
)
type SyncableHTTPClient interface {
HTTPClient
Sync(context.Context) error
}
type HTTPClient interface {
Do(context.Context, HTTPAction) (*http.Response, []byte, error)
}
type HTTPAction interface {
HTTPRequest(url.URL) *http.Request
}
// CancelableTransport mimics http.Transport to provide an interface which can be
// substituted for testing (since the RoundTripper interface alone does not
// require the CancelRequest method)
type CancelableTransport interface {
http.RoundTripper
CancelRequest(req *http.Request)
}
func NewHTTPClient(tr CancelableTransport, eps []string) (SyncableHTTPClient, error) {
return newHTTPClusterClient(tr, eps)
}
func newHTTPClusterClient(tr CancelableTransport, eps []string) (*httpClusterClient, error) {
c := httpClusterClient{
transport: tr,
endpoints: make([]HTTPClient, len(eps)),
}
for i, ep := range eps {
u, err := url.Parse(ep)
if err != nil {
return nil, err
}
c.endpoints[i] = &httpClient{
transport: tr,
endpoint: *u,
}
}
return &c, nil
}
type httpClusterClient struct {
transport CancelableTransport
endpoints []HTTPClient
}
func (c *httpClusterClient) Do(ctx context.Context, act HTTPAction) (*http.Response, []byte, error) {
//TODO(bcwaldon): introduce retry logic so all endpoints are attempted
return c.endpoints[0].Do(ctx, act)
}
func (c *httpClusterClient) Sync(ctx context.Context) error {
mAPI := NewMembersAPI(c)
ms, err := mAPI.List(ctx)
if err != nil {
return err
}
eps := make([]string, 0)
for _, m := range ms {
eps = append(eps, m.ClientURLs...)
}
nc, err := newHTTPClusterClient(c.transport, eps)
if err != nil {
return err
}
*c = *nc
return nil
}
type roundTripResponse struct {
resp *http.Response
err error

View File

@ -41,14 +41,14 @@ var (
ErrKeyExists = errors.New("client: key already exists")
)
func NewKeysAPI(c httpActionDo) KeysAPI {
func NewKeysAPI(c HTTPClient) KeysAPI {
return &httpKeysAPI{
client: c,
prefix: DefaultV2KeysPrefix,
}
}
func NewDiscoveryKeysAPI(c httpActionDo) KeysAPI {
func NewDiscoveryKeysAPI(c HTTPClient) KeysAPI {
return &httpKeysAPI{
client: c,
prefix: "",
@ -87,7 +87,7 @@ func (n *Node) String() string {
}
type httpKeysAPI struct {
client httpActionDo
client HTTPClient
prefix string
}
@ -150,7 +150,7 @@ func (k *httpKeysAPI) RecursiveWatch(key string, idx uint64) Watcher {
}
type httpWatcher struct {
client httpActionDo
client HTTPClient
nextWait waitAction
}

View File

@ -33,7 +33,7 @@ var (
DefaultV2MembersPrefix = "/v2/members"
)
func NewMembersAPI(c httpActionDo) MembersAPI {
func NewMembersAPI(c HTTPClient) MembersAPI {
return &httpMembersAPI{
client: c,
}
@ -46,7 +46,7 @@ type MembersAPI interface {
}
type httpMembersAPI struct {
client httpActionDo
client HTTPClient
}
func (m *httpMembersAPI) List(ctx context.Context) ([]httptypes.Member, error) {