| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- package base
- import (
- "context"
- "encoding/base64"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "os"
- "strings"
- "time"
- )
- const (
- accessKey = "VOLC_ACCESSKEY"
- secretKey = "VOLC_SECRETKEY"
- defaultScheme = "http"
- )
- var _GlobalClient *http.Client
- func init() {
- _GlobalClient = &http.Client{
- Transport: &http.Transport{
- MaxIdleConns: 1000,
- MaxIdleConnsPerHost: 100,
- IdleConnTimeout: 10 * time.Second,
- },
- }
- }
- // Client 基础客户端
- type Client struct {
- Client *http.Client
- SdkVersion string
- ServiceInfo *ServiceInfo
- ApiInfoList map[string]*ApiInfo
- }
- // NewClient 生成一个客户端
- func NewClient(info *ServiceInfo, apiInfoList map[string]*ApiInfo) *Client {
- client := &Client{Client: _GlobalClient, ServiceInfo: info.Clone(), ApiInfoList: apiInfoList}
- if client.ServiceInfo.Scheme == "" {
- client.ServiceInfo.Scheme = defaultScheme
- }
- if os.Getenv(accessKey) != "" && os.Getenv(secretKey) != "" {
- client.ServiceInfo.Credentials.AccessKeyID = os.Getenv(accessKey)
- client.ServiceInfo.Credentials.SecretAccessKey = os.Getenv(secretKey)
- } else if _, err := os.Stat(os.Getenv("HOME") + "/.volc/config"); err == nil {
- if content, err := ioutil.ReadFile(os.Getenv("HOME") + "/.volc/config"); err == nil {
- m := make(map[string]string)
- json.Unmarshal(content, &m)
- if accessKey, ok := m["ak"]; ok {
- client.ServiceInfo.Credentials.AccessKeyID = accessKey
- }
- if secretKey, ok := m["sk"]; ok {
- client.ServiceInfo.Credentials.SecretAccessKey = secretKey
- }
- }
- }
- content, err := ioutil.ReadFile("VERSION")
- if err == nil {
- client.SdkVersion = strings.TrimSpace(string(content))
- client.ServiceInfo.Header.Set("User-Agent", strings.Join([]string{"volc-sdk-golang", client.SdkVersion}, "/"))
- }
- return client
- }
- func (serviceInfo *ServiceInfo) Clone() *ServiceInfo {
- ret := new(ServiceInfo)
- //base info
- ret.Timeout = serviceInfo.Timeout
- ret.Host = serviceInfo.Host
- ret.Scheme = serviceInfo.Scheme
- //credential
- ret.Credentials = serviceInfo.Credentials.Clone()
- // header
- ret.Header = serviceInfo.Header.Clone()
- return ret
- }
- func (cred Credentials) Clone() Credentials {
- return Credentials{
- Service: cred.Service,
- Region: cred.Region,
- SecretAccessKey: cred.SecretAccessKey,
- AccessKeyID: cred.AccessKeyID,
- SessionToken: cred.SessionToken,
- }
- }
- // SetAccessKey 设置AK
- func (client *Client) SetAccessKey(ak string) {
- if ak != "" {
- client.ServiceInfo.Credentials.AccessKeyID = ak
- }
- }
- // SetSecretKey 设置SK
- func (client *Client) SetSecretKey(sk string) {
- if sk != "" {
- client.ServiceInfo.Credentials.SecretAccessKey = sk
- }
- }
- // SetSessionToken
- func (client *Client) SetSessionToken(token string) {
- if token != "" {
- client.ServiceInfo.Credentials.SessionToken = token
- }
- }
- // SetHost 设置Host
- func (client *Client) SetHost(host string) {
- if host != "" {
- client.ServiceInfo.Host = host
- }
- }
- func (client *Client) SetScheme(scheme string) {
- if scheme != "" {
- client.ServiceInfo.Scheme = scheme
- }
- }
- // SetCredential 设置Credentials
- func (client *Client) SetCredential(c Credentials) {
- if c.AccessKeyID != "" {
- client.ServiceInfo.Credentials.AccessKeyID = c.AccessKeyID
- }
- if c.SecretAccessKey != "" {
- client.ServiceInfo.Credentials.SecretAccessKey = c.SecretAccessKey
- }
- if c.Region != "" {
- client.ServiceInfo.Credentials.Region = c.Region
- }
- if c.SessionToken != "" {
- client.ServiceInfo.Credentials.SessionToken = c.SessionToken
- }
- }
- func (client *Client) SetTimeout(timeout time.Duration) {
- if timeout > 0 {
- client.ServiceInfo.Timeout = timeout
- }
- }
- // GetSignUrl 获取签名字符串
- func (client *Client) GetSignUrl(api string, query url.Values) (string, error) {
- apiInfo := client.ApiInfoList[api]
- if apiInfo == nil {
- return "", errors.New("相关api不存在")
- }
- query = mergeQuery(query, apiInfo.Query)
- u := url.URL{
- Scheme: client.ServiceInfo.Scheme,
- Host: client.ServiceInfo.Host,
- Path: apiInfo.Path,
- RawQuery: query.Encode(),
- }
- req, err := http.NewRequest(strings.ToUpper(apiInfo.Method), u.String(), nil)
- if err != nil {
- return "", errors.New("构建request失败")
- }
- return client.ServiceInfo.Credentials.SignUrl(req), nil
- }
- // SignSts2 生成sts信息
- func (client *Client) SignSts2(inlinePolicy *Policy, expire time.Duration) (*SecurityToken2, error) {
- var err error
- sts := new(SecurityToken2)
- if sts.AccessKeyID, sts.SecretAccessKey, err = createTempAKSK(); err != nil {
- return nil, err
- }
- if expire < time.Minute {
- expire = time.Minute
- }
- now := time.Now()
- expireTime := now.Add(expire)
- sts.CurrentTime = now.Format(time.RFC3339)
- sts.ExpiredTime = expireTime.Format(time.RFC3339)
- innerToken, err := createInnerToken(client.ServiceInfo.Credentials, sts, inlinePolicy, expireTime.Unix())
- if err != nil {
- return nil, err
- }
- b, _ := json.Marshal(innerToken)
- sts.SessionToken = "STS2" + base64.StdEncoding.EncodeToString(b)
- return sts, nil
- }
- // Query 发起Get的query请求
- func (client *Client) Query(api string, query url.Values) ([]byte, int, error) {
- return client.requestWithContentType(api, query, "", "")
- }
- // Json 发起Json的post请求
- func (client *Client) Json(api string, query url.Values, body string) ([]byte, int, error) {
- return client.requestWithContentType(api, query, body, "application/json")
- }
- // PostWithContentType 发起自定义 Content-Type 的 post 请求,Content-Type 不可以为空
- func (client *Client) PostWithContentType(api string, query url.Values, body string, ct string) ([]byte, int, error) {
- return client.requestWithContentType(api, query, body, ct)
- }
- func (client *Client) requestWithContentType(api string, query url.Values, body string, ct string) ([]byte, int, error) {
- apiInfo := client.ApiInfoList[api]
- if apiInfo == nil {
- return []byte(""), 500, errors.New("相关api不存在")
- }
- timeout := getTimeout(client.ServiceInfo.Timeout, apiInfo.Timeout)
- header := mergeHeader(client.ServiceInfo.Header, apiInfo.Header)
- query = mergeQuery(query, apiInfo.Query)
- u := url.URL{
- Scheme: client.ServiceInfo.Scheme,
- Host: client.ServiceInfo.Host,
- Path: apiInfo.Path,
- RawQuery: query.Encode(),
- }
- var requestBody io.Reader
- if body != "" {
- requestBody = strings.NewReader(body)
- }
- req, err := http.NewRequest(strings.ToUpper(apiInfo.Method), u.String(), requestBody)
- if err != nil {
- return []byte(""), 500, errors.New("构建request失败")
- }
- req.Header = header
- if ct != "" {
- req.Header.Set("Content-Type", ct)
- }
- return client.makeRequest(api, req, timeout)
- }
- // Post 发起Post请求
- func (client *Client) Post(api string, query url.Values, form url.Values) ([]byte, int, error) {
- apiInfo := client.ApiInfoList[api]
- form = mergeQuery(form, apiInfo.Form)
- return client.requestWithContentType(api, query, form.Encode(), "application/x-www-form-urlencoded")
- }
- func (client *Client) makeRequest(api string, req *http.Request, timeout time.Duration) ([]byte, int, error) {
- req = client.ServiceInfo.Credentials.Sign(req)
- ctx, cancel := context.WithTimeout(context.Background(), timeout)
- defer cancel()
- req = req.WithContext(ctx)
- resp, err := client.Client.Do(req)
- if err != nil {
- return []byte(""), 500, err
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return []byte(""), resp.StatusCode, err
- }
- if resp.StatusCode < 200 || resp.StatusCode > 299 {
- return body, resp.StatusCode, fmt.Errorf("api %s http code %d body %s", api, resp.StatusCode, string(body))
- }
- return body, resp.StatusCode, nil
- }
|