evcc-io/util/request/helper.go
2020-12-08 08:19:12 +01:00

135 lines
2.8 KiB
Go

package request
import (
"fmt"
"log"
"net/http"
"net/http/httputil"
"strings"
"time"
"github.com/andig/evcc/util"
)
// Helper provides utility primitives
type Helper struct {
*http.Client
log *log.Logger
last *http.Response // last response
}
// NewHelper creates http helper for simplified PUT GET logic
func NewHelper(log *util.Logger) *Helper {
r := &Helper{
Client: &http.Client{Timeout: 10 * time.Second},
}
// add logger
if log != nil {
r.log = log.TRACE
}
// intercept for logging
r.Transport(http.DefaultTransport)
return r
}
// LastResponse returns last http.Response that was read without error
func (r *Helper) LastResponse() *http.Response {
return r.last
}
type helperTransport struct {
log *log.Logger
detailed bool
lastResponse func(*http.Response)
roundTripper http.RoundTripper
}
func (r *helperTransport) RoundTrip(req *http.Request) (*http.Response, error) {
msg := fmt.Sprintf("%s %s", req.Method, req.URL)
if r.detailed {
if body, err := httputil.DumpRequest(req, true); err == nil {
msg += "\n" + strings.TrimSpace(string(body)) + "\n"
}
}
resp, err := r.roundTripper.RoundTrip(req)
r.lastResponse(resp)
if r.log != nil {
if resp != nil {
if r.detailed {
if body, err := httputil.DumpResponse(resp, true); err == nil {
msg += "\n" + strings.TrimSpace(string(body))
}
} else {
msg += "\n" + resp.Status
if body, _ := ReadBody(resp); len(body) > 0 {
const max = 2048
str := string(body)
if len(str) >= max {
str = str[:max]
}
msg += "\n" + strings.TrimSpace(str)
}
}
}
r.log.Println(msg)
}
return resp, err
}
// Transport wraps the provided transport with logging and sets it as client transport
func (r *Helper) Transport(roundTripper http.RoundTripper) {
r.Client.Transport = &helperTransport{
log: r.log,
roundTripper: roundTripper,
lastResponse: func(resp *http.Response) {
r.last = resp
},
}
}
// DoBody executes HTTP request and returns the response body
func (r *Helper) DoBody(req *http.Request) ([]byte, error) {
resp, err := r.Do(req)
var body []byte
if err == nil {
body, err = ReadBody(resp)
}
return body, err
}
// GetBody executes HTTP GET request and returns the response body
func (r *Helper) GetBody(url string) ([]byte, error) {
resp, err := r.Get(url)
var body []byte
if err == nil {
body, err = ReadBody(resp)
}
return body, err
}
// DoJSON executes HTTP request and decodes JSON response
func (r *Helper) DoJSON(req *http.Request, res interface{}) error {
resp, err := r.Do(req)
if err == nil {
err = DecodeJSON(resp, &res)
}
return err
}
// GetJSON executes HTTP GET request and decodes JSON response
func (r *Helper) GetJSON(url string, res interface{}) error {
resp, err := r.Get(url)
if err == nil {
err = DecodeJSON(resp, &res)
}
return err
}