base_service_gateway.go 4.0 KB
package api

import (
	rawjson "encoding/json"
	"fmt"
	"github.com/linmadan/egglib-go/utils/json"
	"net/http"
	"strings"
	"time"

	"github.com/beego/beego/v2/client/httplib"
)

type MessageCode struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
}

// Response 统一消息返回格式
type Response struct {
	MessageCode
	Data rawjson.RawMessage `json:"data"`
}

type BaseServiceGateway struct {
	ConnectTimeout   time.Duration
	ReadWriteTimeout time.Duration
	host             string
	Interceptor      func(msg string)
	ServiceName      string
}

type Request struct {
	Url    string
	Method string
	Param  interface{}
}

func (gateway BaseServiceGateway) CreateRequest(url string, method string, options *RequestOptions) *httplib.BeegoHTTPRequest {
	var request *httplib.BeegoHTTPRequest
	method = strings.ToUpper(method)
	switch method {
	case http.MethodGet:
		request = httplib.Get(url)
	case http.MethodPost:
		request = httplib.Post(url)
	case http.MethodPut:
		request = httplib.Put(url)
	case http.MethodDelete:
		request = httplib.Delete(url)
	case http.MethodHead:
		request = httplib.Head(url)
	default:
		request = httplib.Get(url)
	}
	if len(options.Header) > 0 {
		for k, v := range options.Header {
			request.Header(k, strings.Join(v, ";"))
		}
	}
	for k, v := range options.FileMap {
		request.PostFile(k, v)
	}
	return request.SetTimeout(gateway.ConnectTimeout, gateway.ReadWriteTimeout)
}

func (gateway BaseServiceGateway) GetResponseData(result Response, data interface{}) error {
	err := json.Unmarshal(result.Data, data)
	if err != nil {
		return NewErrCodeMsg(gateway.ServiceName, JsonUnMarshError, err.Error())
	}
	return nil
}

func (gateway BaseServiceGateway) FastDoRequest(url, method string, param interface{}, data interface{}, options ...Option) error {
	begin := time.Now()
	var err error
	var result = "success"
	defer func() {
		jsonParam, _ := json.Marshal(param)
		jsonData, _ := json.Marshal(data)
		if err != nil {
			result = err.Error()
		}
		if gateway.Interceptor != nil {
			gateway.Interceptor(fmt.Sprintf("【网关】%v | %v | %v : %v \nRequest:%v \nResponse:%v", time.Since(begin), url, strings.ToUpper(method),
				result,
				string(jsonParam),
				string(jsonData),
			))
		}
	}()
	var requestOptions = &RequestOptions{}
	for _, option := range options {
		option(requestOptions)
	}
	err = gateway.DoRequest(Request{
		Url:    url,
		Method: method,
		Param:  param,
	}, &data, requestOptions)
	if err != nil {
		return err
	}
	return nil
}

func (gateway BaseServiceGateway) DoRequest(requestParam Request, val interface{}, options *RequestOptions) error {
	r := gateway.CreateRequest(requestParam.Url, requestParam.Method, options)
	var err error
	if len(options.FileMap) == 0 {
		r, err = r.JSONBody(requestParam.Param)
		if err != nil {
			return err
		}
	}
	byteResult, err := r.Bytes()
	if err != nil {
		gateway.InterceptSimple(requestParam.Url, string(byteResult), err)
		return err
	}
	var result Response
	err = json.Unmarshal(byteResult, &result)
	if err != nil {
		gateway.InterceptSimple(requestParam.Url, string(byteResult), err)
		return err
	}
	if result.Code != 0 && len(result.Msg) > 0 {
		return NewErrCodeMsg(gateway.ServiceName, result.Code, result.Msg)
	}
	return gateway.GetResponseData(result, val)
}

func (gateway BaseServiceGateway) InterceptSimple(url string, data string, err error) {
	if gateway.Interceptor != nil {
		errMsg := ""
		if err != nil {
			errMsg = err.Error()
		}
		gateway.Interceptor(fmt.Sprintf("【网关】 %v | %v  \nResponse:%v Error:%v", url,
			data, errMsg,
		))
	}
}

func (gateway BaseServiceGateway) Host() string {
	return gateway.host
}

func NewBaseServiceGateway(host string) BaseServiceGateway {
	return BaseServiceGateway{
		host: host,
	}
}

type RequestOptions struct {
	Header http.Header
	// key:form key value:path
	FileMap map[string]string
}

type Option func(o *RequestOptions)

func WithHeader(header http.Header) Option {
	return func(o *RequestOptions) {
		o.Header = header
	}
}

func WithFileMap(v map[string]string) Option {
	return func(o *RequestOptions) {
		o.FileMap = v
	}
}