client/api/client.go (320 lines of code) (raw):
// Package client
/*
* YuanJing OpenAPI SDK for Go
*
*
*/
package api
import (
"bytes"
"crypto/md5"
"crypto/rand"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
"reflect"
"regexp"
"sort"
"strconv"
"strings"
"time"
"unicode/utf8"
)
const (
Trace_Id string = "Traceid"
Result_Status string = "Result-Status"
)
var (
jsonCheck = regexp.MustCompile("(?i:[application|text]/json)")
xmlCheck = regexp.MustCompile("(?i:[application|text]/xml)")
DefaultConfiguration = NewConfiguration()
)
// APIClient manages communication with the API
// In most cases there should be only one, shared, APIClient.
type APIClient struct {
cfg *Configuration
common service // Reuse a single struct instead of allocating one for each service on the heap.
// API Services
ConsoleAdminApi *ConsoleAdminApiService
DispatchApi *DispatchApiService
InteractiveApi *InteractiveApiService
LiveApi *LiveApiService
MultiplayApi *MultiplayApiService
TokenApi *TokenApiService
UsercontrollerApi *UsercontrollerApiService
}
type service struct {
client *APIClient
}
// NewAPIClient creates a new API client. Requires a userAgent string describing your application.
// optionally a custom http.Client to allow for advanced features such as caching.
func NewAPIClient(cfg *Configuration) *APIClient {
if cfg.HTTPClient == nil {
cfg.HTTPClient = http.DefaultClient
}
c := &APIClient{}
c.cfg = cfg
c.common.client = c
// API Services
c.ConsoleAdminApi = (*ConsoleAdminApiService)(&c.common)
c.DispatchApi = (*DispatchApiService)(&c.common)
c.InteractiveApi = (*InteractiveApiService)(&c.common)
c.LiveApi = (*LiveApiService)(&c.common)
c.MultiplayApi = (*MultiplayApiService)(&c.common)
c.TokenApi = (*TokenApiService)(&c.common)
c.UsercontrollerApi = (*UsercontrollerApiService)(&c.common)
return c
}
func atoi(in string) (int, error) {
return strconv.Atoi(in)
}
// selectHeaderContentType select a content type from the available list.
func selectHeaderContentType(contentTypes []string) string {
if len(contentTypes) == 0 {
return ""
}
if contains(contentTypes, "application/json") {
return "application/json"
}
return contentTypes[0] // use the first content type specified in 'consumes'
}
// selectHeaderAccept join all accept types and return
func selectHeaderAccept(accepts []string) string {
if len(accepts) == 0 {
return ""
}
if contains(accepts, "application/json") {
return "application/json"
}
return strings.Join(accepts, ",")
}
// contains is a case insenstive match, finding needle in a haystack
func contains(haystack []string, needle string) bool {
for _, a := range haystack {
if strings.ToLower(a) == strings.ToLower(needle) {
return true
}
}
return false
}
// Verify optional parameters are of the correct type.
func typeCheckParameter(obj interface{}, expected string, name string) error {
// Make sure there is an object.
if obj == nil {
return nil
}
// Check the type is as expected.
if reflect.TypeOf(obj).String() != expected {
return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String())
}
return nil
}
// parameterToString convert interface{} parameters to string, using a delimiter if format is provided.
func parameterToString(obj interface{}, collectionFormat string) string {
// var delimiter string
// switch collectionFormat {
// case "pipes":
// delimiter = "|"
// case "ssv":
// delimiter = " "
// case "tsv":
// delimiter = "\t"
// case "csv":
// delimiter = ","
// }
if reflect.TypeOf(obj).Kind() == reflect.Slice {
// return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]")
if marshal, err := json.Marshal(obj); err != nil {
return ""
} else {
return string(marshal)
}
}
if reflect.TypeOf(obj).Kind() == reflect.Struct {
if marshal, err := json.Marshal(obj); err != nil {
return ""
} else {
return string(marshal)
}
}
return fmt.Sprintf("%v", obj)
}
// callAPI do the request.
func (c *APIClient) callAPI(request *http.Request) (*http.Response, error) {
return c.cfg.HTTPClient.Do(request)
}
// prepareRequest build the request
func (c *APIClient) prepareRequest(
path string,
method string,
headerParams map[string]string,
queryParams url.Values,
formParams url.Values,
) (localVarRequest *http.Request, err error) {
var body *bytes.Buffer
// add form parameters
if strings.HasPrefix(headerParams["Content-Type"], "application/x-www-form-urlencoded") && len(formParams) > 0 {
body = &bytes.Buffer{}
body.WriteString(formParams.Encode())
// Set Content-Length
headerParams["Content-Length"] = fmt.Sprintf("%d", body.Len())
}
// Setup path and query parameters
url, err := url.Parse(path)
if err != nil {
return nil, err
}
// Adding Query Param
query := url.Query()
for k, v := range queryParams {
for _, iv := range v {
query.Add(k, iv)
}
}
// Encode the parameters.
url.RawQuery = query.Encode()
// Generate a new request
if body != nil {
localVarRequest, err = http.NewRequest(method, url.String(), body)
} else {
localVarRequest, err = http.NewRequest(method, url.String(), nil)
}
if err != nil {
return nil, err
}
// add header parameters, if any
if len(headerParams) > 0 {
headers := http.Header{}
for h, v := range headerParams {
headers.Set(h, v)
}
localVarRequest.Header = headers
}
// Override request host, if applicable
if c.cfg.Host != "" {
localVarRequest.Host = c.cfg.Host
}
// Add the user agent to the request.
localVarRequest.Header.Add("User-Agent", "cgw-client/1.0.0/go")
// prepare sign headers
prepareSignHeader(queryParams, formParams, localVarRequest, c.cfg)
for header, value := range c.cfg.DefaultHeader {
localVarRequest.Header.Add(header, value)
}
return localVarRequest, nil
}
func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err error) {
if strings.Contains(contentType, "application/json") {
if err = json.Unmarshal(b, v); err != nil {
return err
}
return nil
}
return errors.New("undefined response type")
}
// Prevent trying to import "fmt"
func reportError(format string, a ...interface{}) error {
return fmt.Errorf(format, a...)
}
// Ripped from https://github.com/gregjones/httpcache/blob/master/httpcache.go
type cacheControl map[string]string
func parseCacheControl(headers http.Header) cacheControl {
cc := cacheControl{}
ccHeader := headers.Get("Cache-Control")
for _, part := range strings.Split(ccHeader, ",") {
part = strings.Trim(part, " ")
if part == "" {
continue
}
if strings.ContainsRune(part, '=') {
keyval := strings.Split(part, "=")
cc[strings.Trim(keyval[0], " ")] = strings.Trim(keyval[1], ",")
} else {
cc[part] = ""
}
}
return cc
}
// CacheExpires helper function to determine remaining time before repeating a request.
func CacheExpires(r *http.Response) time.Time {
// Figure out when the cache expires.
var expires time.Time
now, err := time.Parse(time.RFC1123, r.Header.Get("date"))
if err != nil {
return time.Now()
}
respCacheControl := parseCacheControl(r.Header)
if maxAge, ok := respCacheControl["max-age"]; ok {
lifetime, err := time.ParseDuration(maxAge + "s")
if err != nil {
expires = now
}
expires = now.Add(lifetime)
} else {
expiresHeader := r.Header.Get("Expires")
if expiresHeader != "" {
expires, err = time.Parse(time.RFC1123, expiresHeader)
if err != nil {
expires = now
}
}
}
return expires
}
func strlen(s string) int {
return utf8.RuneCountInString(s)
}
func prepareSignHeader(queryParams url.Values, formParams url.Values, localVarRequest *http.Request, cfg *Configuration) {
accessKey := cfg.AccessKey
nonce := randNonce(16)
version := cfg.SignatureVersion
timestamp := time.Now().UTC().Format(time.RFC3339)
method := cfg.SignatureMethod
values := url.Values{}
values.Add("AccessKey", accessKey)
values.Add("SignatureNonce", nonce)
values.Add("SignatureVersion", version)
values.Add("SignatureMethod", method)
values.Add("Timestamp", timestamp)
if len(queryParams) > 0 {
for s, i := range queryParams {
for _, s2 := range i {
values.Add(s, s2)
}
}
}
if len(formParams) > 0 {
for s, i := range formParams {
for _, s2 := range i {
values.Add(s, s2)
}
}
}
sign := md5Hex([]byte(getSignRaw(values, localVarRequest.Method, cfg.SecretKey)))
localVarRequest.Header.Add("Signature", sign)
localVarRequest.Header.Add("Accesskey", accessKey)
localVarRequest.Header.Add("Signaturenonce", nonce)
localVarRequest.Header.Add("Signatureversion", version)
localVarRequest.Header.Add("Timestamp", timestamp)
localVarRequest.Header.Add("Signaturemethod", method)
}
func md5Hex(data []byte) string {
md5Sum := md5.Sum(data)
return hex.EncodeToString(md5Sum[:])
}
func getSignRaw(values url.Values, method string, secret string) string {
return secret + "&" + keySignInput(values, method)
}
func keySignInput(values url.Values, method string) string {
keys := make([]string, 0)
for s, _ := range values {
keys = append(keys, s)
}
sort.Strings(keys)
stringToSign := method + "&" + encodeURLComponent("/")
strs := make([]string, 0)
for _, k := range keys {
strs = append(strs, k+"="+encodeURLComponent(values.Get(k)))
}
return stringToSign + "&" + encodeURLComponent(strings.Join(strs, "&"))
}
func encodeURLComponent(str string) string {
escape := url.QueryEscape(str)
escape = strings.ReplaceAll(escape, "+", "%20")
escape = strings.ReplaceAll(escape, "*", "%2A")
escape = strings.ReplaceAll(escape, "%7E", "~")
return escape
}
func randNonce(n int) string {
b := make([]byte, n)
rand.Read(b)
return hex.EncodeToString(b)
}
// GenericError Provides access to the body, error and model on returned errors.
type GenericError struct {
body []byte
error string
model interface{}
}
// Error returns non-empty string if there was an error.
func (e GenericError) Error() string {
return e.error
}
// Body returns the raw bytes of the response
func (e GenericError) Body() []byte {
return e.body
}
// Model returns the unpacked model of the error
func (e GenericError) Model() interface{} {
return e.model
}
type Configuration struct {
Host string `json:"host"`
Scheme string `json:"scheme"`
DefaultHeader map[string]string `json:"defaultHeader,omitempty"`
AccessKey string `json:"accessKey"`
SecretKey string `json:"secretKey"`
SignatureVersion string `json:"signatureVersion"`
SignatureMethod string `json:"signatureMethod"`
HTTPClient *http.Client
}
func NewConfiguration() *Configuration {
return &Configuration{
Scheme: "https",
SignatureVersion: "1.0",
SignatureMethod: "MD5",
HTTPClient: http.DefaultClient,
}
}