Jelajahi Sumber

init project

gaoyagang 1 tahun lalu
melakukan
404792569d
8 mengubah file dengan 1083 tambahan dan 0 penghapusan
  1. 3 0
      .gitignore
  2. 336 0
      envitem/func.go
  3. 78 0
      envitem/func_test.go
  4. 48 0
      envitem/types.go
  5. 17 0
      envitem/vars.go
  6. 10 0
      go.mod
  7. 15 0
      go.sum
  8. 576 0
      httplib/httplib.go

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+.idea
+
+vendor

+ 336 - 0
envitem/func.go

@@ -0,0 +1,336 @@
+package envitem
+
+import (
+	"Gt/common/httplib"
+	"context"
+	"database/sql/driver"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func SetOptions(options Options) {
+	snapUrl = fmt.Sprintf("http://%s/api/v1/plc-current", options.GtServerIp)
+	ctlUrl = fmt.Sprintf("http://%s/api/v1/plc/set-var-values", options.GtServerIp)
+
+	if options.Cache != nil {
+		cache = options.Cache
+	}
+}
+
+func (m MultiEnvItem) GetProjectId() int64 {
+	for _, item := range m {
+		return item.ProjectId
+	}
+	return 0
+}
+
+func (m MultiEnvItem) getItemNames() []string {
+	items := make([]string, 0)
+	for _, item := range m {
+		items = append(items, item.Item)
+	}
+	return items
+}
+
+func (m MultiEnvItem) FillCurrentValue() error {
+	datas, err := m.getCurrentData()
+	if err != nil {
+		return err
+	}
+	// 先做一个item -> key的映射
+	ikm := make(map[string]string)
+	for s, item := range m {
+		ikm[item.Item] = s
+	}
+
+	for _, data := range datas {
+		if k, ok := ikm[data.ItemName]; ok {
+			m[k].Value = data.Val
+			m[k].Htime = data.HTime
+			_ = m[k].setPrevValue()
+		}
+	}
+	return nil
+}
+
+func (m MultiEnvItem) GetItemFloat64Value(key string) float64 {
+	if envItem, ok := m[key]; ok {
+		return envItem.GetItemFloat64Val()
+	}
+	return 0
+}
+
+func (m MultiEnvItem) GetItemInt64Value(key string) int64 {
+	if envItem, ok := m[key]; ok {
+		return envItem.GetItemInt64Val()
+	}
+	return 0
+}
+
+func (m MultiEnvItem) GetItemStringValue(key string) string {
+	if envItem, ok := m[key]; ok {
+		return envItem.GetItemStringVal()
+	}
+	return ""
+}
+
+func (m MultiEnvItem) GetItemHtime(key string) *time.Time {
+	if envItem, ok := m[key]; ok {
+		return envItem.GetItemHtime()
+	}
+	return nil
+}
+
+func (m MultiEnvItem) FindString() map[string]string {
+	a := make(map[string]string)
+	for _, item := range m {
+		a[item.Item] = item.Value.(string)
+	}
+
+	return a
+}
+
+func (m MultiEnvItem) FindPrevString() map[string]string {
+	a := make(map[string]string)
+	for _, item := range m {
+		a[item.Item] = item.GetItemPrevStringVal()
+	}
+
+	return a
+}
+
+func (m MultiEnvItem) getCurrentData() ([]*ItemValueResp, error) {
+	req := httplib.Post(snapUrl)
+	data := make([]*ItemValueReq, 1)
+
+	data[0] = &ItemValueReq{
+		DeviceItems: strings.Join(m.getItemNames(), ","),
+		ProjectId:   m.GetProjectId(),
+	}
+
+	jsonBytes, err := json.Marshal(data)
+	if err != nil {
+		return nil, err
+	}
+	req.Body(jsonBytes)
+	req.SetTimeout(time.Millisecond * 2000)
+
+	r, err := req.Response()
+	if err != nil {
+		return nil, err
+	}
+	defer r.Body.Close()
+
+	if r.StatusCode == 200 {
+		resp, err := req.Bytes()
+		if err != nil {
+			return nil, err
+		}
+
+		res := &ItemValueResps{}
+		err = json.Unmarshal(resp, res)
+		if err != nil {
+			return nil, err
+		}
+
+		if len(res.Data) == 0 {
+			return nil, errors.New("not found envitem's value")
+		}
+
+		return res.Data, nil
+	}
+
+	return nil, errors.New(fmt.Sprintf("request statusCode: %d", r.StatusCode))
+}
+
+func (e *EnvItem) getCurrentData() (*ItemValueResp, error) {
+	req := httplib.Post(snapUrl)
+	data := make([]*ItemValueReq, 1)
+
+	data[0] = &ItemValueReq{
+		DeviceItems: e.Item,
+		ProjectId:   e.ProjectId,
+	}
+
+	jsonBytes, err := json.Marshal(data)
+	if err != nil {
+		return nil, err
+	}
+	req.Body(jsonBytes)
+	req.SetTimeout(time.Millisecond * 2000)
+
+	r, err := req.Response()
+	if err != nil {
+		return nil, err
+	}
+	defer r.Body.Close()
+
+	if r.StatusCode == 200 {
+		resp, err := req.Bytes()
+		if err != nil {
+			return nil, err
+		}
+
+		res := &ItemValueResps{}
+		err = json.Unmarshal(resp, res)
+		if err != nil {
+			return nil, err
+		}
+
+		if len(res.Data) == 0 {
+			return nil, errors.New("not found envitem's value")
+		}
+
+		return res.Data[0], nil
+	}
+
+	return nil, errors.New(fmt.Sprintf("request statusCode: %d", r.StatusCode))
+}
+
+func (e *EnvItem) getCurrentValue() (string, string, error) {
+	resp, err := e.getCurrentData()
+	if err != nil {
+		return "", "", err
+	}
+
+	e.Value = resp.Val
+	e.Htime = resp.HTime
+	_ = e.setPrevValue()
+
+	return resp.Val, resp.HTime, nil
+}
+
+func (e *EnvItem) getPrevValue() (string, string, error) {
+	if cache == nil {
+		return "", "", errors.New("not cache")
+	}
+	key := fmt.Sprintf(CACHE_PREV_VALUE_KEY, e.ProjectId, e.Item)
+	if cmd := cache.Get(context.Background(), key); cmd != nil {
+		n := strings.Split(cmd.Val(), "|")
+		if len(n) != 2 {
+			return "", "", errors.New("getPrevValue cache length error")
+		}
+		return n[0], n[1], nil
+	} else {
+		return "", "", cmd.Err()
+	}
+}
+
+func (e *EnvItem) setPrevValue() error {
+	if cache == nil {
+		return errors.New("not cache")
+	}
+	key := fmt.Sprintf(CACHE_PREV_VALUE_KEY, e.ProjectId, e.Item)
+	value := fmt.Sprintf("%s|%s", e.Value, e.Htime)
+	if statusCmd := cache.Set(context.Background(), key, value, CACHE_PREV_VALUE_KEY_EXPIRE); statusCmd != nil {
+		return nil
+	} else {
+		return errors.New("setPrevValue error")
+	}
+}
+
+func (e *EnvItem) GetItemFloat64Val() float64 {
+	if e.Value == nil {
+		e.getCurrentValue()
+	}
+
+	switch e.Value.(type) {
+	case string:
+		if v, e := strconv.ParseFloat(e.Value.(string), 64); e == nil {
+			return v
+		}
+	}
+
+	return 0
+}
+
+func (e *EnvItem) GetItemInt64Val() int64 {
+	if e.Value == nil {
+		e.getCurrentValue()
+	}
+
+	switch e.Value.(type) {
+	case string:
+		if v, e := strconv.ParseInt(e.Value.(string), 10, 64); e == nil {
+			return v
+		}
+	}
+
+	return 0
+}
+
+func (e *EnvItem) GetItemStringVal() string {
+	if e.Value == nil {
+		e.getCurrentValue()
+	}
+
+	if v, ok := e.Value.(string); ok {
+		return v
+	}
+
+	return ""
+}
+
+func (e *EnvItem) GetItemHtime() *time.Time {
+	if e.Value == nil {
+		e.getCurrentValue()
+	}
+
+	if ht, err := time.ParseInLocation("2006-01-02 15:04:05", e.Htime, time.Local); err == nil {
+		return &ht
+	}
+	return nil
+}
+
+func (e *EnvItem) GetItemPrevFloat64Val() float64 {
+	ov, _, err := e.getPrevValue()
+	if err != nil {
+		return 0
+	}
+
+	if v, err := strconv.ParseFloat(ov, 64); err == nil {
+		return v
+	}
+
+	return 0
+}
+
+func (e *EnvItem) GetItemPrevInt64Val() int64 {
+	ov, _, err := e.getPrevValue()
+	if err != nil {
+		return 0
+	}
+
+	if v, err := strconv.ParseInt(ov, 10, 64); err == nil {
+		return v
+	}
+
+	return 0
+}
+
+func (e *EnvItem) GetItemPrevStringVal() string {
+	ov, _, _ := e.getPrevValue()
+	return ov
+}
+
+func (e *EnvItem) GetItemPrevHtime() *time.Time {
+	_, ht, _ := e.getPrevValue()
+	if t, err := time.ParseInLocation("2006-01-02 15:04:05", ht, time.Local); err == nil {
+		return &t
+	}
+	return nil
+}
+
+// Scan 实现方法
+func (d *MultiEnvItem) Scan(input interface{}) error {
+	_ = json.Unmarshal(input.([]byte), &d)
+	return nil
+}
+
+func (d MultiEnvItem) Value() (driver.Value, error) {
+	return json.Marshal(d)
+}

+ 78 - 0
envitem/func_test.go

@@ -0,0 +1,78 @@
+package envitem
+
+import (
+	"encoding/json"
+	"testing"
+	"time"
+)
+
+func TestEnvItem_GetCurrentData(t *testing.T) {
+	SetOptions(Options{GtServerIp: "47.96.12.136:8788"})
+	e := EnvItem{
+		ProjectId: 92,
+		Item:      "C.M.LT_CIP@out,C.M.RO1_DB@time_CS_display",
+	}
+
+	v, ht, err := e.getCurrentValue()
+
+	t.Log(v, ht, err)
+
+}
+
+func TestMultiEnvItem_FillCurrentValue(t *testing.T) {
+	SetOptions(Options{GtServerIp: "47.96.12.136:8788"})
+	m := make(MultiEnvItem, 2)
+	m["C.M.LT_CIP@out"] = &EnvItem{
+		ProjectId: 92,
+		Item:      "C.M.LT_CIP@out",
+	}
+	m["C.M.RO1_DB@time_CS_display"] = &EnvItem{
+		ProjectId: 92,
+		Item:      "C.M.RO1_DB@time_CS_display",
+	}
+
+	err := m.FillCurrentValue()
+	t.Log(err)
+
+	for s, item := range m {
+		t.Logf("item: %s value: %s htime: %s", s, item.Value, item.Htime)
+	}
+}
+
+func TestMultiEnvItem_FillCurrentValue2(t *testing.T) {
+	SetOptions(Options{GtServerIp: "47.96.12.136:8788"})
+	js := `{"tmp":{"project_id":92,"device_code":"UF-4001A","plc_device_id":"0","item":"C.M.UF1_DB@press_PV","default_val":0},"feed_flow":{"project_id":92,"device_code":"UF-4001A","plc_device_id":"0","item":"C.M.UF1_FT_JS@out","default_val":0},"feed_pressure":{"project_id":92,"device_code":"UF-4001A","plc_device_id":"0","item":"C.M.UF1_PT_JS@out","default_val":0},"product_pressure":{"project_id":92,"device_code":"UF-4001A","plc_device_id":"0","item":"C.M.UF1_PT_CS@out","default_val":0},"feed_wq_turbidity":{"project_id":92,"device_code":"AIT-94061","plc_device_id":"0","item":"C.M.UF_Tur_ZJS@out","default_val":0},"water_temperature":{"project_id":92,"device_code":"TIT-34061","plc_device_id":"0","item":"C.M.RO_TT_ZJS@out","default_val":0},"product_wq_ph":{"project_id":92,"device_code":"AIT-95065b","plc_device_id":"0","item":"C.M.UF_PH_ZCS@out","default_val":0},"step":{"project_id":92,"device_code":"HB","plc_device_id":"0","item":"C.M.UF1_DB@word_control","default_val":0}}`
+	var multiEnvItems MultiEnvItem
+
+	_ = json.Unmarshal([]byte(js), &multiEnvItems)
+
+	t.Log(multiEnvItems)
+
+	for {
+		_ = multiEnvItems.FillCurrentValue()
+		time.Sleep(2 * time.Second)
+
+		//ms := multiEnvItems.FindString()
+
+		t.Logf("%+v", multiEnvItems)
+
+		t.Logf("step: %d", multiEnvItems.GetItemInt64Value("step"))
+		//early := checkEarly(multiEnvItems.GetItemFloat64Value("Display_Time"), multiEnvItems.GetItemFloat64Value("Filter_Time_Set"), multiEnvItems.GetItemStringValue("Step"))
+		//advanced := checkAdvanced(multiEnvItems.GetItemFloat64Value("Display_Time"), multiEnvItems.GetItemFloat64Value("Filter_Time_Set"), multiEnvItems.GetItemStringValue("Step"))
+		//
+		//t.Logf("early: %v, advanced: %v, step: %s filterNumber: %s Display_Time: %s Filter_Time_Set: %s", early, advanced, multiEnvItems.GetItemStringValue("Step"), multiEnvItems.GetItemStringValue("Filter_Number"), multiEnvItems.GetItemStringValue("Display_Time"), multiEnvItems.GetItemStringValue("Filter_Time_Set"))
+		//t.Log(err)
+		//for s, item := range multiEnvItems {
+		//	t.Logf("item: %s value: %s htime: %s", s, item.Value, item.Htime)
+		//}
+	}
+
+}
+
+func checkEarly(ft, fst float64, step string) bool {
+	return step == "26" && ft >= 360 && ft <= 660
+}
+
+func checkAdvanced(ft, fst float64, step string) bool {
+	return step == "26" && ft+360 >= fst && ft+60 <= fst
+}

+ 48 - 0
envitem/types.go

@@ -0,0 +1,48 @@
+package envitem
+
+import "github.com/go-redis/redis/v8"
+
+type (
+	Options struct {
+		GtServerIp string
+		Cache      *redis.Client
+	}
+
+	EnvItem struct {
+		ProjectId   int64       `json:"project_id"`
+		DeviceCode  string      `json:"device_code"`
+		PlcDeviceId string      `json:"plc_device_id"`
+		Item        string      `json:"item"`
+		DefaultVal  interface{} `json:"default_val"`
+		Value       interface{} `json:"value"`
+		Htime       string      `json:"htime"`
+	}
+
+	MultiEnvItem map[string]*EnvItem
+
+	ItemValueResp struct {
+		Alias        string `json:"alias"`
+		DataAddress  string `json:"dataAddress"`
+		DataType     string `json:"datatype"`
+		DevName      string `json:"devName"`
+		DevID        string `json:"devid"`
+		HTime        string `json:"htime"`
+		ItemID       string `json:"itemid"`
+		ItemName     string `json:"itemname"`
+		Quality      string `json:"quality"`
+		ReadOnly     bool   `json:"readOnly"`
+		SpecificType string `json:"specificType"`
+		Val          string `json:"val"`
+	}
+
+	ItemValueResps struct {
+		Code int              `json:"code"`
+		Data []*ItemValueResp `json:"data"`
+	}
+
+	ItemValueReq struct {
+		DeviceId    string `json:"deviceId"`
+		DeviceItems string `json:"deviceItems"`
+		ProjectId   int64  `json:"project_id"`
+	}
+)

+ 17 - 0
envitem/vars.go

@@ -0,0 +1,17 @@
+package envitem
+
+import (
+	"github.com/go-redis/redis/v8"
+	"time"
+)
+
+const (
+	CACHE_PREV_VALUE_KEY        = "envitem:prev:value:%d:%s"
+	CACHE_PREV_VALUE_KEY_EXPIRE = 86400 * time.Second
+)
+
+var (
+	snapUrl = ""
+	ctlUrl  = ""
+	cache   *redis.Client
+)

+ 10 - 0
go.mod

@@ -0,0 +1,10 @@
+module Gt/common
+
+go 1.19
+
+require github.com/go-redis/redis/v8 v8.11.5
+
+require (
+	github.com/cespare/xxhash/v2 v2.1.2 // indirect
+	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
+)

+ 15 - 0
go.sum

@@ -0,0 +1,15 @@
+github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
+github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
+github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
+github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=

+ 576 - 0
httplib/httplib.go

@@ -0,0 +1,576 @@
+// Copyright 2014 beego Author. All Rights Reserved.
+//
+// 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.
+
+// copy & modify from github.com/astaxie/beego/tree/master/httplib
+
+package httplib
+
+import (
+	"bytes"
+	"compress/gzip"
+	"crypto/tls"
+	"encoding/json"
+	"encoding/xml"
+	"io"
+	"io/ioutil"
+	"log"
+	"mime/multipart"
+	"net"
+	"net/http"
+	"net/http/cookiejar"
+	"net/http/httputil"
+	"net/url"
+	"os"
+	"strings"
+	"sync"
+	"time"
+)
+
+var defaultSetting = HTTPSettings{
+	//UserAgent:      "smart-push",
+	Gzip:           true,
+	DumpBody:       true,
+	ConnectTimeout: time.Second * 30,
+	KeepAlive:      time.Second * 60,
+	Transport: &http.Transport{
+		DialContext: (&net.Dialer{
+			Timeout:   time.Second * 30,
+			KeepAlive: time.Second * 60,
+		}).DialContext,
+		MaxIdleConnsPerHost: 3000,
+		MaxIdleConns:        30000,
+	},
+}
+
+var defaultCookieJar http.CookieJar
+var settingMutex sync.Mutex
+
+// createDefaultCookie creates a global cookiejar to store cookies.
+func createDefaultCookie() {
+	settingMutex.Lock()
+	defer settingMutex.Unlock()
+	defaultCookieJar, _ = cookiejar.New(nil)
+}
+
+// SetDefaultSetting Overwrite default settings
+func SetDefaultSetting(setting HTTPSettings) {
+	settingMutex.Lock()
+	defer settingMutex.Unlock()
+	defaultSetting = setting
+}
+
+// NewBeegoRequest return *HTTPRequest with specific method
+func NewHTTPRequest(rawurl, method string) *HTTPRequest {
+	var resp http.Response
+	u, err := url.Parse(rawurl)
+	if err != nil {
+		log.Println("Httplib:", err)
+	}
+	req := http.Request{
+		URL:        u,
+		Method:     method,
+		Header:     make(http.Header),
+		Proto:      "HTTP/1.1",
+		ProtoMajor: 1,
+		ProtoMinor: 1,
+	}
+	return &HTTPRequest{
+		url:     rawurl,
+		req:     &req,
+		params:  map[string][]string{},
+		files:   map[string]string{},
+		setting: defaultSetting,
+		resp:    &resp,
+	}
+}
+
+// Get returns *HTTPRequest with GET method.
+func Get(url string) *HTTPRequest {
+	return NewHTTPRequest(url, "GET")
+}
+
+// Post returns *HTTPRequest with POST method.
+func Post(url string) *HTTPRequest {
+	return NewHTTPRequest(url, "POST")
+}
+
+// Put returns *HTTPRequest with PUT method.
+func Put(url string) *HTTPRequest {
+	return NewHTTPRequest(url, "PUT")
+}
+
+// Delete returns *HTTPRequest DELETE method.
+func Delete(url string) *HTTPRequest {
+	return NewHTTPRequest(url, "DELETE")
+}
+
+// Head returns *HTTPRequest with HEAD method.
+func Head(url string) *HTTPRequest {
+	return NewHTTPRequest(url, "HEAD")
+}
+
+// HTTPSettings is the http.Client setting
+type HTTPSettings struct {
+	ShowDebug       bool
+	UserAgent       string
+	TLSClientConfig *tls.Config
+	Proxy           func(*http.Request) (*url.URL, error)
+	Transport       http.RoundTripper
+	CheckRedirect   func(req *http.Request, via []*http.Request) error
+	EnableCookie    bool
+	Gzip            bool
+	DumpBody        bool
+	Retries         int // if set to -1 means will retry forever
+	ConnectTimeout  time.Duration
+	KeepAlive       time.Duration
+	Timeout         time.Duration
+}
+
+// HTTPRequest provides more useful methods for requesting one url than http.Request.
+type HTTPRequest struct {
+	url     string
+	req     *http.Request
+	params  map[string][]string
+	files   map[string]string
+	setting HTTPSettings
+	resp    *http.Response
+	body    []byte
+	dump    []byte
+
+	client *http.Client
+}
+
+// GetRequest return the request object
+func (b *HTTPRequest) GetRequest() *http.Request {
+	return b.req
+}
+
+// Setting Change request settings
+func (b *HTTPRequest) Setting(setting HTTPSettings) *HTTPRequest {
+	b.setting = setting
+	return b
+}
+
+// SetBasicAuth sets the request's Authorization header to use HTTP Basic Authentication with the provided username and password.
+func (b *HTTPRequest) SetBasicAuth(username, password string) *HTTPRequest {
+	b.req.SetBasicAuth(username, password)
+	return b
+}
+
+// SetEnableCookie sets enable/disable cookiejar
+func (b *HTTPRequest) SetEnableCookie(enable bool) *HTTPRequest {
+	b.setting.EnableCookie = enable
+	return b
+}
+
+// SetUserAgent sets User-Agent header field
+func (b *HTTPRequest) SetUserAgent(useragent string) *HTTPRequest {
+	b.setting.UserAgent = useragent
+	return b
+}
+
+// Debug sets show debug or not when executing request.
+func (b *HTTPRequest) Debug(isdebug bool) *HTTPRequest {
+	b.setting.ShowDebug = isdebug
+	return b
+}
+
+// Retries sets Retries times.
+// default is 0 means no retried.
+// -1 means retried forever.
+// others means retried times.
+func (b *HTTPRequest) Retries(times int) *HTTPRequest {
+	b.setting.Retries = times
+	return b
+}
+
+// DumpBody setting whether need to Dump the Body.
+func (b *HTTPRequest) DumpBody(isdump bool) *HTTPRequest {
+	b.setting.DumpBody = isdump
+	return b
+}
+
+// DumpRequest return the DumpRequest
+func (b *HTTPRequest) DumpRequest() []byte {
+	return b.dump
+}
+
+// SetTimeout sets connect time out and read-write time out for BeegoRequest.
+func (b *HTTPRequest) SetTimeout(timeout time.Duration) *HTTPRequest {
+	b.setting.Timeout = timeout
+	return b
+}
+
+// SetTLSClientConfig sets tls connection configurations if visiting https url.
+func (b *HTTPRequest) SetTLSClientConfig(config *tls.Config) *HTTPRequest {
+	b.setting.TLSClientConfig = config
+	return b
+}
+
+// Header add header item string in request.
+func (b *HTTPRequest) Header(key, value string) *HTTPRequest {
+	b.req.Header.Set(key, value)
+	return b
+}
+
+// SetHost set the request host
+func (b *HTTPRequest) SetHost(host string) *HTTPRequest {
+	b.req.Host = host
+	return b
+}
+
+// SetProtocolVersion Set the protocol version for incoming requests.
+// Client requests always use HTTP/1.1.
+func (b *HTTPRequest) SetProtocolVersion(vers string) *HTTPRequest {
+	if len(vers) == 0 {
+		vers = "HTTP/1.1"
+	}
+
+	major, minor, ok := http.ParseHTTPVersion(vers)
+	if ok {
+		b.req.Proto = vers
+		b.req.ProtoMajor = major
+		b.req.ProtoMinor = minor
+	}
+
+	return b
+}
+
+// SetCookie add cookie into request.
+func (b *HTTPRequest) SetCookie(cookie *http.Cookie) *HTTPRequest {
+	b.req.Header.Add("Cookie", cookie.String())
+	return b
+}
+
+// SetTransport set the setting transport
+func (b *HTTPRequest) SetTransport(transport http.RoundTripper) *HTTPRequest {
+	b.setting.Transport = transport
+	return b
+}
+
+// SetProxy set the http proxy
+// example:
+//
+//	func(req *http.Request) (*url.URL, error) {
+//		u, _ := url.ParseRequestURI("http://127.0.0.1:8118")
+//		return u, nil
+//	}
+func (b *HTTPRequest) SetProxy(proxy func(*http.Request) (*url.URL, error)) *HTTPRequest {
+	b.setting.Proxy = proxy
+	return b
+}
+
+// SetCheckRedirect specifies the policy for handling redirects.
+//
+// If CheckRedirect is nil, the Client uses its default policy,
+// which is to stop after 10 consecutive requests.
+func (b *HTTPRequest) SetCheckRedirect(redirect func(req *http.Request, via []*http.Request) error) *HTTPRequest {
+	b.setting.CheckRedirect = redirect
+	return b
+}
+
+// Param adds query param in to request.
+// params build query string as ?key1=value1&key2=value2...
+func (b *HTTPRequest) Param(key, value string) *HTTPRequest {
+	if param, ok := b.params[key]; ok {
+		b.params[key] = append(param, value)
+	} else {
+		b.params[key] = []string{value}
+	}
+	return b
+}
+
+// PostFile add a post file to the request
+func (b *HTTPRequest) PostFile(formname, filename string) *HTTPRequest {
+	b.files[formname] = filename
+	return b
+}
+
+// Body adds request raw body.
+// it supports string and []byte.
+func (b *HTTPRequest) Body(data interface{}) *HTTPRequest {
+	switch t := data.(type) {
+	case string:
+		bf := bytes.NewBufferString(t)
+		b.req.Body = ioutil.NopCloser(bf)
+		b.req.ContentLength = int64(len(t))
+	case []byte:
+		bf := bytes.NewBuffer(t)
+		b.req.Body = ioutil.NopCloser(bf)
+		b.req.ContentLength = int64(len(t))
+	}
+	return b
+}
+
+// JSONBody adds request raw body encoding by JSON.
+func (b *HTTPRequest) JSONBody(obj interface{}) (*HTTPRequest, error) {
+	if b.req.Body == nil && obj != nil {
+		byts, err := json.Marshal(obj)
+		if err != nil {
+			return b, err
+		}
+		b.req.Body = ioutil.NopCloser(bytes.NewReader(byts))
+		b.req.ContentLength = int64(len(byts))
+		b.req.Header.Set("Content-Type", "application/json")
+	}
+	return b, nil
+}
+
+func (b *HTTPRequest) buildURL(paramBody string) {
+	// build GET url with query string
+	if b.req.Method == "GET" && len(paramBody) > 0 {
+		if strings.Contains(b.url, "?") {
+			b.url += "&" + paramBody
+		} else {
+			b.url = b.url + "?" + paramBody
+		}
+		return
+	}
+
+	// build POST/PUT/PATCH url and body
+	if (b.req.Method == "POST" || b.req.Method == "PUT" || b.req.Method == "PATCH" || b.req.Method == "DELETE") && b.req.Body == nil {
+		// with files
+		if len(b.files) > 0 {
+			pr, pw := io.Pipe()
+			bodyWriter := multipart.NewWriter(pw)
+			go func() {
+				for formname, filename := range b.files {
+					fileWriter, err := bodyWriter.CreateFormFile(formname, filename)
+					if err != nil {
+						log.Println("Httplib:", err)
+					}
+					fh, err := os.Open(filename)
+					if err != nil {
+						log.Println("Httplib:", err)
+					}
+					//iocopy
+					_, err = io.Copy(fileWriter, fh)
+					fh.Close()
+					if err != nil {
+						log.Println("Httplib:", err)
+					}
+				}
+				for k, v := range b.params {
+					for _, vv := range v {
+						bodyWriter.WriteField(k, vv)
+					}
+				}
+				bodyWriter.Close()
+				pw.Close()
+			}()
+			b.Header("Content-Type", bodyWriter.FormDataContentType())
+			b.req.Body = ioutil.NopCloser(pr)
+			return
+		}
+
+		// with params
+		if len(paramBody) > 0 {
+			b.Header("Content-Type", "application/x-www-form-urlencoded")
+			b.Body(paramBody)
+		}
+	}
+}
+
+func (b *HTTPRequest) getResponse() (*http.Response, error) {
+	if b.resp.StatusCode != 0 {
+		return b.resp, nil
+	}
+	resp, err := b.DoRequest()
+	if err != nil {
+		return nil, err
+	}
+	b.resp = resp
+	return resp, nil
+}
+
+// DoRequest will do the client.Do
+func (b *HTTPRequest) DoRequest() (resp *http.Response, err error) {
+	var paramBody string
+	if len(b.params) > 0 {
+		var buf bytes.Buffer
+		for k, v := range b.params {
+			for _, vv := range v {
+				buf.WriteString(url.QueryEscape(k))
+				buf.WriteByte('=')
+				buf.WriteString(url.QueryEscape(vv))
+				buf.WriteByte('&')
+			}
+		}
+		paramBody = buf.String()
+		paramBody = paramBody[0 : len(paramBody)-1]
+	}
+
+	b.buildURL(paramBody)
+	url, err := url.Parse(b.url)
+	if err != nil {
+		return nil, err
+	}
+
+	b.req.URL = url
+
+	trans := b.setting.Transport
+
+	if trans == nil {
+		// create default transport
+		trans = &http.Transport{
+			TLSClientConfig: b.setting.TLSClientConfig,
+			Proxy:           b.setting.Proxy,
+			DialContext: (&net.Dialer{
+				Timeout:   b.setting.ConnectTimeout,
+				KeepAlive: b.setting.KeepAlive,
+			}).DialContext,
+			MaxIdleConnsPerHost: -1,
+		}
+	} else {
+		// if b.transport is *http.Transport then set the settings.
+		if t, ok := trans.(*http.Transport); ok {
+			if t.TLSClientConfig == nil {
+				t.TLSClientConfig = b.setting.TLSClientConfig
+			}
+			if t.Proxy == nil {
+				t.Proxy = b.setting.Proxy
+			}
+			if t.DialContext == nil {
+				t.DialContext = (&net.Dialer{
+					Timeout:   b.setting.ConnectTimeout,
+					KeepAlive: b.setting.KeepAlive,
+				}).DialContext
+			}
+		}
+	}
+
+	var jar http.CookieJar
+	if b.setting.EnableCookie {
+		if defaultCookieJar == nil {
+			createDefaultCookie()
+		}
+		jar = defaultCookieJar
+	}
+
+	client := &http.Client{
+		Transport: trans,
+		Jar:       jar,
+	}
+
+	client.Timeout = b.setting.Timeout
+
+	if b.setting.UserAgent != "" && b.req.Header.Get("User-Agent") == "" {
+		b.req.Header.Set("User-Agent", b.setting.UserAgent)
+	}
+
+	if b.setting.CheckRedirect != nil {
+		client.CheckRedirect = b.setting.CheckRedirect
+	}
+
+	if b.setting.ShowDebug {
+		dump, err := httputil.DumpRequest(b.req, b.setting.DumpBody)
+		if err != nil {
+			log.Println(err.Error())
+		}
+		b.dump = dump
+	}
+	// retries default value is 0, it will run once.
+	// retries equal to -1, it will run forever until success
+	// retries is setted, it will retries fixed times.
+	for i := 0; b.setting.Retries == -1 || i <= b.setting.Retries; i++ {
+		resp, err = client.Do(b.req)
+		if err == nil {
+			break
+		}
+	}
+	return resp, err
+}
+
+// String returns the body string in response.
+// it calls Response inner.
+func (b *HTTPRequest) String() (string, error) {
+	data, err := b.Bytes()
+	if err != nil {
+		return "", err
+	}
+
+	return string(data), nil
+}
+
+// Bytes returns the body []byte in response.
+// it calls Response inner.
+func (b *HTTPRequest) Bytes() ([]byte, error) {
+	if b.body != nil {
+		return b.body, nil
+	}
+	resp, err := b.getResponse()
+	if err != nil {
+		return nil, err
+	}
+	if resp.Body == nil {
+		return nil, nil
+	}
+	defer resp.Body.Close()
+	if b.setting.Gzip && resp.Header.Get("Content-Encoding") == "gzip" {
+		reader, err := gzip.NewReader(resp.Body)
+		if err != nil {
+			return nil, err
+		}
+		b.body, err = ioutil.ReadAll(reader)
+		return b.body, err
+	}
+	b.body, err = ioutil.ReadAll(resp.Body)
+	return b.body, err
+}
+
+// ToFile saves the body data in response to one file.
+// it calls Response inner.
+func (b *HTTPRequest) ToFile(filename string) error {
+	f, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+
+	resp, err := b.getResponse()
+	if err != nil {
+		return err
+	}
+	if resp.Body == nil {
+		return nil
+	}
+	defer resp.Body.Close()
+	_, err = io.Copy(f, resp.Body)
+	return err
+}
+
+// ToJSON returns the map that marshals from the body bytes as json in response .
+// it calls Response inner.
+func (b *HTTPRequest) ToJSON(v interface{}) error {
+	data, err := b.Bytes()
+	if err != nil {
+		return err
+	}
+	return json.Unmarshal(data, v)
+}
+
+// ToXML returns the map that marshals from the body bytes as xml in response .
+// it calls Response inner.
+func (b *HTTPRequest) ToXML(v interface{}) error {
+	data, err := b.Bytes()
+	if err != nil {
+		return err
+	}
+	return xml.Unmarshal(data, v)
+}
+
+// Response executes request client gets response mannually.
+func (b *HTTPRequest) Response() (*http.Response, error) {
+	return b.getResponse()
+}