github.com/qiniu/go-sdk/v7@v7.27.0/sms/rpc/client.go (about)

     1  package rpc
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"net/http"
     9  	"net/url"
    10  	"strings"
    11  	"time"
    12  )
    13  
    14  var (
    15  	green   = string([]byte{27, 91, 57, 55, 59, 52, 50, 109})
    16  	white   = string([]byte{27, 91, 57, 48, 59, 52, 55, 109})
    17  	yellow  = string([]byte{27, 91, 57, 55, 59, 52, 51, 109})
    18  	red     = string([]byte{27, 91, 57, 55, 59, 52, 49, 109})
    19  	blue    = string([]byte{27, 91, 57, 55, 59, 52, 52, 109})
    20  	magenta = string([]byte{27, 91, 57, 55, 59, 52, 53, 109})
    21  	cyan    = string([]byte{27, 91, 57, 55, 59, 52, 54, 109})
    22  	reset   = string([]byte{27, 91, 48, 109})
    23  )
    24  
    25  // UserAgent user agent
    26  var UserAgent = "Golang qiniu/rpc package"
    27  
    28  // --------------------------------------------------------------------
    29  
    30  // Client a golang http client
    31  type Client struct {
    32  	*http.Client
    33  }
    34  
    35  // DefaultClient a golang default http client
    36  var DefaultClient = Client{&http.Client{Transport: DefaultTransport}}
    37  
    38  // NewClientTimeout return a golang http client
    39  func NewClientTimeout(dial, resp time.Duration) Client {
    40  	return Client{&http.Client{Transport: NewTransportTimeout(dial, resp)}}
    41  }
    42  
    43  // --------------------------------------------------------------------
    44  
    45  // Head send head method request
    46  func (r Client) Head(url string) (resp *http.Response, err error) {
    47  	req, err := http.NewRequest("HEAD", url, nil)
    48  	if err != nil {
    49  		return
    50  	}
    51  	return r.Do(req)
    52  }
    53  
    54  // Get send get method request
    55  func (r Client) Get(url string) (resp *http.Response, err error) {
    56  	req, err := http.NewRequest("GET", url, nil)
    57  	if err != nil {
    58  		return
    59  	}
    60  	return r.Do(req)
    61  }
    62  
    63  // Delete send delete method request
    64  func (r Client) Delete(url string) (resp *http.Response, err error) {
    65  	req, err := http.NewRequest("DELETE", url, nil)
    66  	if err != nil {
    67  		return
    68  	}
    69  	return r.Do(req)
    70  }
    71  
    72  // PostEx send post method request with url
    73  func (r Client) PostEx(url string) (resp *http.Response, err error) {
    74  	req, err := http.NewRequest("POST", url, nil)
    75  	if err != nil {
    76  		return
    77  	}
    78  	return r.Do(req)
    79  }
    80  
    81  // PostWith send post method request with url, bodyType, body and bodyLength
    82  func (r Client) PostWith(url1 string, bodyType string, body io.Reader, bodyLength int) (resp *http.Response, err error) {
    83  	req, err := http.NewRequest("POST", url1, body)
    84  	if err != nil {
    85  		return
    86  	}
    87  	req.Header.Set("Content-Type", bodyType)
    88  	req.ContentLength = int64(bodyLength)
    89  	return r.Do(req)
    90  }
    91  
    92  // PostWith64 send post method request with url, bodyType, body and bodyLength(64)
    93  func (r Client) PostWith64(url1 string, bodyType string, body io.Reader, bodyLength int64) (resp *http.Response, err error) {
    94  	req, err := http.NewRequest("POST", url1, body)
    95  	if err != nil {
    96  		return
    97  	}
    98  	req.Header.Set("Content-Type", bodyType)
    99  	req.ContentLength = bodyLength
   100  	return r.Do(req)
   101  }
   102  
   103  // PostWithForm send post method request with url and form data
   104  func (r Client) PostWithForm(url1 string, data map[string][]string) (resp *http.Response, err error) {
   105  	msg := url.Values(data).Encode()
   106  	return r.PostWith(url1, "application/x-www-form-urlencoded", strings.NewReader(msg), len(msg))
   107  }
   108  
   109  // PostWithJSON send post method request with url and application/json data
   110  func (r Client) PostWithJSON(url1 string, data interface{}) (resp *http.Response, err error) {
   111  	msg, err := json.Marshal(data)
   112  	if err != nil {
   113  		return
   114  	}
   115  	return r.PostWith(url1, "application/json", bytes.NewReader(msg), len(msg))
   116  }
   117  
   118  // PutEx send put request with url
   119  func (r Client) PutEx(url string) (resp *http.Response, err error) {
   120  	req, err := http.NewRequest("PUT", url, nil)
   121  	if err != nil {
   122  		return
   123  	}
   124  	return r.Do(req)
   125  }
   126  
   127  // PutWith send put method request with url, bodyType, body and bodyLength
   128  func (r Client) PutWith(url1 string, bodyType string, body io.Reader, bodyLength int) (resp *http.Response, err error) {
   129  	req, err := http.NewRequest("PUT", url1, body)
   130  	if err != nil {
   131  		return
   132  	}
   133  	req.Header.Set("Content-Type", bodyType)
   134  	req.ContentLength = int64(bodyLength)
   135  	return r.Do(req)
   136  }
   137  
   138  // PutWith64 send put method request with url, bodyType, body and bodyLength(64)
   139  func (r Client) PutWith64(url1 string, bodyType string, body io.Reader, bodyLength int64) (resp *http.Response, err error) {
   140  	req, err := http.NewRequest("PUT", url1, body)
   141  	if err != nil {
   142  		return
   143  	}
   144  	req.Header.Set("Content-Type", bodyType)
   145  	req.ContentLength = bodyLength
   146  	return r.Do(req)
   147  }
   148  
   149  // PutWithForm send put method request with url and form data
   150  func (r Client) PutWithForm(url1 string, data map[string][]string) (resp *http.Response, err error) {
   151  	msg := url.Values(data).Encode()
   152  	return r.PutWith(url1, "application/x-www-form-urlencoded", strings.NewReader(msg), len(msg))
   153  }
   154  
   155  // PutWithJSON send put method request with url and application/json data
   156  func (r Client) PutWithJSON(url1 string, data interface{}) (resp *http.Response, err error) {
   157  	msg, err := json.Marshal(data)
   158  	if err != nil {
   159  		return
   160  	}
   161  	return r.PutWith(url1, "application/json", bytes.NewReader(msg), len(msg))
   162  }
   163  
   164  // --------------------------------------------------------------------
   165  
   166  // Do 发送 HTTP Request, 并返回 HTTP Response
   167  func (r Client) Do(req *http.Request) (resp *http.Response, err error) {
   168  	// debug
   169  	start := time.Now()
   170  	defer func() {
   171  		end := time.Now()
   172  		latency := end.Sub(start)
   173  		if err != nil {
   174  		} else {
   175  			reqid := req.Header.Get("X-Reqid")
   176  			if rid := resp.Header.Get("X-Reqid"); len(rid) > 0 {
   177  				reqid = rid
   178  			}
   179  			method := req.Method
   180  			methodColor := colorForMethod(method)
   181  			statusCode := resp.StatusCode
   182  			statusColor := colorForStatus(statusCode)
   183  
   184  			fmt.Printf("[RPC] [%s] %v |%s %3d %s| %13v |%s %s %s|\t %s\n",
   185  				reqid,
   186  				start.Format("2006/01/02 - 15:04:05"),
   187  				statusColor, statusCode, reset,
   188  				latency,
   189  				methodColor, method, reset,
   190  				req.URL.String(),
   191  			)
   192  		}
   193  	}()
   194  
   195  	if req.Header.Get("User-Agent") == "" {
   196  		req.Header.Set("User-Agent", UserAgent)
   197  	}
   198  
   199  	resp, err = r.Client.Do(req)
   200  	return
   201  }
   202  
   203  // --------------------------------------------------------------------
   204  
   205  // ErrorInfo type
   206  type ErrorInfo struct {
   207  	Err       string `json:"error"`
   208  	RequestID string `json:"reqid"`
   209  	Message   string `json:"message"`
   210  	Code      int    `json:"code"`
   211  }
   212  
   213  // ErrorDetail return error detail
   214  func (r *ErrorInfo) ErrorDetail() string {
   215  	msg, _ := json.Marshal(r)
   216  	return string(msg)
   217  }
   218  
   219  // Error return error message
   220  func (r *ErrorInfo) Error() string {
   221  	if r.Err != "" {
   222  		return r.Err
   223  	}
   224  	return http.StatusText(r.Code)
   225  }
   226  
   227  // HTTPCode return rpc http StatusCode
   228  func (r *ErrorInfo) HTTPCode() int {
   229  	return r.Code
   230  }
   231  
   232  // --------------------------------------------------------------------
   233  
   234  type errorRet struct {
   235  	Error string `json:"error"`
   236  }
   237  
   238  // ResponseError return response error
   239  func ResponseError(resp *http.Response) (err error) {
   240  	e := &ErrorInfo{
   241  		RequestID: resp.Header.Get("X-Reqid"),
   242  		Code:      resp.StatusCode,
   243  	}
   244  	if resp.StatusCode > 299 {
   245  		if resp.ContentLength != 0 {
   246  			if ct := resp.Header.Get("Content-Type"); strings.TrimSpace(strings.SplitN(ct, ";", 2)[0]) == "application/json" {
   247  				var ret1 errorRet
   248  				json.NewDecoder(resp.Body).Decode(&ret1)
   249  				e.Err = ret1.Error
   250  			}
   251  		}
   252  	}
   253  	return e
   254  }
   255  
   256  // CallRet parse http response
   257  func CallRet(ret interface{}, resp *http.Response) (err error) {
   258  	return callRet(ret, resp)
   259  }
   260  
   261  // callRet parse http response
   262  func callRet(ret interface{}, resp *http.Response) (err error) {
   263  	defer func() {
   264  		io.Copy(io.Discard, resp.Body)
   265  		resp.Body.Close()
   266  	}()
   267  
   268  	if resp.StatusCode/100 == 2 || resp.StatusCode/100 == 3 {
   269  		if ret != nil && resp.ContentLength != 0 {
   270  			err = json.NewDecoder(resp.Body).Decode(ret)
   271  			if err != nil {
   272  				return
   273  			}
   274  		}
   275  		return nil
   276  	}
   277  	return ResponseError(resp)
   278  }
   279  
   280  // CallWithForm send post method request with url and form data then parse response
   281  func (r Client) CallWithForm(ret interface{}, url1 string, param map[string][]string) (err error) {
   282  	resp, err := r.PostWithForm(url1, param)
   283  	if err != nil {
   284  		return err
   285  	}
   286  	return callRet(ret, resp)
   287  }
   288  
   289  // CallWithJSON send post method request with url and application/json data then parse response
   290  func (r Client) CallWithJSON(ret interface{}, url1 string, param interface{}) (err error) {
   291  	resp, err := r.PostWithJSON(url1, param)
   292  	if err != nil {
   293  		return err
   294  	}
   295  	return callRet(ret, resp)
   296  }
   297  
   298  // CallWith send post method request with url, bodyType, body and bodyLength then parse response
   299  func (r Client) CallWith(ret interface{}, url1 string, bodyType string, body io.Reader, bodyLength int) (err error) {
   300  	resp, err := r.PostWith(url1, bodyType, body, bodyLength)
   301  	if err != nil {
   302  		return err
   303  	}
   304  	return callRet(ret, resp)
   305  }
   306  
   307  // CallWith64 send post method request with url, bodyType, body and bodyLength(64) then parse response
   308  func (r Client) CallWith64(ret interface{}, url1 string, bodyType string, body io.Reader, bodyLength int64) (err error) {
   309  	resp, err := r.PostWith64(url1, bodyType, body, bodyLength)
   310  	if err != nil {
   311  		return err
   312  	}
   313  	return callRet(ret, resp)
   314  }
   315  
   316  // Call send post method request with url then parse response
   317  func (r Client) Call(ret interface{}, url1 string) (err error) {
   318  	resp, err := r.PostWith(url1, "application/x-www-form-urlencoded", nil, 0)
   319  	if err != nil {
   320  		return err
   321  	}
   322  	return callRet(ret, resp)
   323  }
   324  
   325  // PutCallWithForm send put method request with url and param then parse response
   326  func (r Client) PutCallWithForm(ret interface{}, url1 string, param map[string][]string) (err error) {
   327  	resp, err := r.PutWithForm(url1, param)
   328  	if err != nil {
   329  		return err
   330  	}
   331  	return callRet(ret, resp)
   332  }
   333  
   334  // PutCallWithJSON send put method request with url and param then parse response
   335  func (r Client) PutCallWithJSON(ret interface{}, url1 string, param interface{}) (err error) {
   336  	resp, err := r.PutWithJSON(url1, param)
   337  	if err != nil {
   338  		return err
   339  	}
   340  	return callRet(ret, resp)
   341  }
   342  
   343  // PutCallWith send put method request with url, bodyType, body and bodyLength then parse response
   344  func (r Client) PutCallWith(ret interface{}, url1 string, bodyType string, body io.Reader, bodyLength int) (err error) {
   345  	resp, err := r.PutWith(url1, bodyType, body, bodyLength)
   346  	if err != nil {
   347  		return err
   348  	}
   349  	return callRet(ret, resp)
   350  }
   351  
   352  // PutCallWith64 send post method request with url, bodyType, body and bodyLength(64) then parse response
   353  func (r Client) PutCallWith64(ret interface{}, url1 string, bodyType string, body io.Reader, bodyLength int64) (err error) {
   354  	resp, err := r.PutWith64(url1, bodyType, body, bodyLength)
   355  	if err != nil {
   356  		return err
   357  	}
   358  	return callRet(ret, resp)
   359  }
   360  
   361  // PutCall send put method request with url then parse response
   362  func (r Client) PutCall(ret interface{}, url1 string) (err error) {
   363  	resp, err := r.PutWith(url1, "application/x-www-form-urlencoded", nil, 0)
   364  	if err != nil {
   365  		return err
   366  	}
   367  	return callRet(ret, resp)
   368  }
   369  
   370  // GetCall send get method request with url then parse response
   371  func (r Client) GetCall(ret interface{}, url1 string) (err error) {
   372  	resp, err := r.Get(url1)
   373  	if err != nil {
   374  		return err
   375  	}
   376  	return callRet(ret, resp)
   377  }
   378  
   379  // GetCallWithForm send get method request with url and param then parse response
   380  func (r Client) GetCallWithForm(ret interface{}, url1 string, param map[string][]string) (err error) {
   381  	payload := url.Values(param).Encode()
   382  	if strings.ContainsRune(url1, '?') {
   383  		url1 += "&"
   384  	} else {
   385  		url1 += "?"
   386  	}
   387  	url1 += payload
   388  	resp, err := r.Get(url1)
   389  	if err != nil {
   390  		return err
   391  	}
   392  	return callRet(ret, resp)
   393  }
   394  
   395  // DeleteCall send delete method request with url
   396  func (r Client) DeleteCall(ret interface{}, url string) (err error) {
   397  	resp, err := r.Delete(url)
   398  	if err != nil {
   399  		return err
   400  	}
   401  	return callRet(ret, resp)
   402  }
   403  
   404  // --------------------------------------------------------------------
   405  
   406  func colorForStatus(code int) string {
   407  	switch {
   408  	case code >= 200 && code < 300:
   409  		return green
   410  	case code >= 300 && code < 400:
   411  		return white
   412  	case code >= 400 && code < 500:
   413  		return yellow
   414  	default:
   415  		return red
   416  	}
   417  }
   418  
   419  func colorForMethod(method string) string {
   420  	switch method {
   421  	case "GET":
   422  		return blue
   423  	case "POST":
   424  		return cyan
   425  	case "PUT":
   426  		return yellow
   427  	case "DELETE":
   428  		return red
   429  	case "PATCH":
   430  		return green
   431  	case "HEAD":
   432  		return magenta
   433  	case "OPTIONS":
   434  		return white
   435  	default:
   436  		return reset
   437  	}
   438  }