Codebase list golang-github-go-kit-kit / 8388e13 addsvc / add.go
8388e13

Tree @8388e13 (Download .tar.gz)

add.go @8388e13raw · history · blame

package main

import (
	"bytes"
	"net/http"
	"net/url"
	"strings"

	"github.com/go-kit/kit/log"

	"golang.org/x/net/context"

	"github.com/go-kit/kit/client"
	"github.com/go-kit/kit/transport/codec"
	httptransport "github.com/go-kit/kit/transport/http"
)

// Add is the abstract definition of what this service does. It could easily
// be an interface type with multiple methods, in which case each method would
// be an endpoint.
type Add func(context.Context, int64, int64) int64

func pureAdd(_ context.Context, a, b int64) int64 { return a + b }

func proxyAdd(e client.Endpoint) Add {
	return func(ctx context.Context, a, b int64) int64 {
		resp, err := e(ctx, &addRequest{a, b})
		if err != nil {
			log.DefaultLogger.Log("err", err)
			return 0
		}
		addResp, ok := resp.(*addResponse)
		if !ok {
			log.DefaultLogger.Log("err", client.ErrBadCast)
			return 0
		}
		return addResp.V
	}
}

type httpClient struct {
	*url.URL
	codec.Codec
	method string
	*http.Client
	before       []httptransport.BeforeFunc
	makeResponse func() interface{}
}

// TODO this needs to go to package client
func newHTTPClient(addr string, cdc codec.Codec, makeResponse func() interface{}, options ...httpClientOption) client.Endpoint {
	if !strings.HasPrefix(addr, "http") {
		addr = "http://" + addr
	}
	u, err := url.Parse(addr)
	if err != nil {
		panic(err)
	}

	c := httpClient{
		URL:          u,
		Codec:        cdc,
		method:       "GET",
		Client:       http.DefaultClient,
		makeResponse: makeResponse,
	}
	for _, option := range options {
		option(&c)
	}
	return c.endpoint
}

func (c httpClient) endpoint(ctx context.Context, request interface{}) (interface{}, error) {
	var buf bytes.Buffer
	if err := c.Codec.Encode(&buf, request); err != nil {
		return nil, err
	}

	req, err := http.NewRequest(c.method, c.URL.String(), &buf)
	if err != nil {
		return nil, err
	}

	for _, f := range c.before {
		f(ctx, req)
	}

	resp, err := c.Client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	response := c.makeResponse()
	ctx, err = c.Codec.Decode(ctx, resp.Body, response)
	if err != nil {
		return nil, err
	}

	return response, nil
}

type httpClientOption func(*httpClient)

func before(funcs ...httptransport.BeforeFunc) httpClientOption {
	return func(c *httpClient) { c.before = append(c.before, funcs...) }
}