client.go 2.4 KB
Newer Older
O
ob-robot 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
package http

import (
	"bytes"
	"context"
	"encoding/json"
	"io/ioutil"
	"net"
	"net/http"
	"strings"
	"time"
)

func CanConnect(network, addr string, timeout time.Duration) bool {
	conn, err := net.DialTimeout(network, addr, timeout)
	ret := err == nil
	if conn != nil {
		_ = conn.Close()
	}
	return ret
}

type ApiClient struct {
	protocol string
	host     string
	hc       *http.Client
}

func NewSocketApiClient(socket string, timeout time.Duration) *ApiClient {
	return &ApiClient{
		protocol: "http",
		host:     "socket",
		hc: &http.Client{
			Timeout: timeout,
			Transport: &http.Transport{
				DisableKeepAlives: true,
				DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
					return net.Dial("unix", socket)
				},
			},
		},
	}
}

const ContentTypeJson = "application/json"

func (ac *ApiClient) Call(api string, param interface{}, retPtr interface{}) error {
	var inputData []byte
	var err error
	if param != nil {
		inputData, err = json.Marshal(param)
		if err != nil {
			return EncodeRequestFailedErr.NewError().WithCause(err)
		}
	}
	reader := bytes.NewReader(inputData)
	resp, err := ac.hc.Post(ac.url(api), ContentTypeJson, reader)
	if err != nil {
		return ApiRequestFailedErr.NewError(api).WithCause(err)
	}
	defer ac.hc.CloseIdleConnections()
	defer resp.Body.Close()

	envelop := OcpAgentResponse{
		Data: retPtr,
	}
	bs, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return ApiRequestFailedErr.NewError(api).WithCause(err)
	}
	cpResp := make([]byte, len(bs))
	copy(cpResp, bs)
	respReader := bytes.NewReader(bs)

	if resp.StatusCode != http.StatusOK {
		err = json.NewDecoder(respReader).Decode(&envelop)
		if err == nil {
			return ApiRequestGotFailResultErr.NewError(api, envelop.Error.Code, envelop.Error.Message)
		}
		return ApiRequestGotFailResultErr.WithMessageTemplate("api %s, resp code %d, status %s, decode resp %s err %s").
			NewError(api, resp.StatusCode, resp.Status, cpResp, err)
	}
	err = json.NewDecoder(respReader).Decode(&envelop)
	if err != nil {
		return DecodeResultFailedErr.WithMessageTemplate("api %s, decode resp %s").NewError(api, cpResp).WithCause(err)
	}
	if envelop.Successful {
		return nil
	}
	return ApiRequestGotFailResultErr.NewError(api, envelop.Error.Code, envelop.Error.Message)
}

func (ac *ApiClient) url(api string) string {
	url := ac.protocol + "://" + ac.host
	if !strings.HasPrefix(api, "/") {
		url += "/"
	}
	return url + api
}