增加vendor
This commit is contained in:
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (c) 2017-2018 Tencent Ltd.
|
||||
|
||||
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.
|
||||
Generated
Vendored
+259
@@ -0,0 +1,259 @@
|
||||
// a simple golang breaker according to https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589784(v=pandp.10)
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultBackupEndpoint = "ap-guangzhou.tencentcloudapi.com"
|
||||
defaultMaxFailNum = 5
|
||||
defaultMaxFailPercentage = 75
|
||||
defaultWindowLength = 1 * 60 * time.Second
|
||||
defaultTimeout = 60 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrOpenState is returned when the CB state is open
|
||||
errOpenState = errors.New("circuit breaker is open")
|
||||
)
|
||||
|
||||
// counter use atomic operations to ensure consistency
|
||||
// Atomic operations perform better than mutex
|
||||
type counter struct {
|
||||
failures int
|
||||
all int
|
||||
consecutiveSuccesses int
|
||||
consecutiveFailures int
|
||||
}
|
||||
|
||||
func newRegionCounter() counter {
|
||||
return counter{
|
||||
failures: 0,
|
||||
all: 0,
|
||||
consecutiveSuccesses: 0,
|
||||
consecutiveFailures: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *counter) onSuccess() {
|
||||
c.all++
|
||||
c.consecutiveSuccesses++
|
||||
c.consecutiveFailures = 0
|
||||
}
|
||||
|
||||
func (c *counter) onFailure() {
|
||||
c.all++
|
||||
c.failures++
|
||||
c.consecutiveSuccesses = 0
|
||||
c.consecutiveSuccesses = 0
|
||||
}
|
||||
|
||||
func (c *counter) clear() {
|
||||
c.all = 0
|
||||
c.failures = 0
|
||||
c.consecutiveSuccesses = 0
|
||||
}
|
||||
|
||||
// State is a type that represents a state of CircuitBreaker.
|
||||
type state int
|
||||
|
||||
// These constants are states of CircuitBreaker.
|
||||
const (
|
||||
StateClosed state = iota
|
||||
StateHalfOpen
|
||||
StateOpen
|
||||
)
|
||||
|
||||
type breakerSetting struct {
|
||||
// backupEndpoint
|
||||
// the default is "ap-guangzhou.tencentcloudapi.com"
|
||||
backupEndpoint string
|
||||
// max fail nums
|
||||
// the default is 5
|
||||
maxFailNum int
|
||||
// max fail percentage
|
||||
// the default is 75/100
|
||||
maxFailPercentage int
|
||||
// windowInterval decides when to reset counter if the state is StateClosed
|
||||
// the default is 5minutes
|
||||
windowInterval time.Duration
|
||||
// timeout decides when to turn StateOpen to StateHalfOpen
|
||||
// the default is 60s
|
||||
timeout time.Duration
|
||||
// maxRequests decides when to turn StateHalfOpen to StateClosed
|
||||
maxRequests int
|
||||
}
|
||||
|
||||
type circuitBreaker struct {
|
||||
// settings
|
||||
breakerSetting
|
||||
// read and write lock
|
||||
mu sync.Mutex
|
||||
// the breaker's state: closed, open, half-open
|
||||
state state
|
||||
// expiry time determines whether to enter the next generation
|
||||
// if in StateClosed, it will be now + windowInterval
|
||||
// if in StateOpen, it will be now + timeout
|
||||
// if in StateHalfOpen. it will be zero
|
||||
expiry time.Time
|
||||
// generation decide whether add the afterRequest's request to counter
|
||||
generation uint64
|
||||
// counter
|
||||
counter counter
|
||||
}
|
||||
|
||||
func newRegionBreaker(set breakerSetting) (re *circuitBreaker) {
|
||||
re = new(circuitBreaker)
|
||||
re.breakerSetting = set
|
||||
return
|
||||
}
|
||||
|
||||
func defaultRegionBreaker() *circuitBreaker {
|
||||
defaultSet := breakerSetting{
|
||||
backupEndpoint: defaultBackupEndpoint,
|
||||
maxFailNum: defaultMaxFailNum,
|
||||
maxFailPercentage: defaultMaxFailPercentage,
|
||||
windowInterval: defaultWindowLength,
|
||||
timeout: defaultTimeout,
|
||||
}
|
||||
return newRegionBreaker(defaultSet)
|
||||
}
|
||||
|
||||
// currentState return the current state.
|
||||
// if in StateClosed and now is over expiry time, it will turn to a new generation.
|
||||
// if in StateOpen and now is over expiry time, it will turn to StateHalfOpen
|
||||
func (s *circuitBreaker) currentState(now time.Time) (state, uint64) {
|
||||
switch s.state {
|
||||
case StateClosed:
|
||||
if s.expiry.Before(now) {
|
||||
s.toNewGeneration(now)
|
||||
}
|
||||
case StateOpen:
|
||||
if s.expiry.Before(now) {
|
||||
s.setState(StateHalfOpen, now)
|
||||
}
|
||||
}
|
||||
return s.state, s.generation
|
||||
}
|
||||
|
||||
// setState set the circuitBreaker's state to newState
|
||||
// and turn to new generation
|
||||
func (s *circuitBreaker) setState(newState state, now time.Time) {
|
||||
if s.state == newState {
|
||||
return
|
||||
}
|
||||
s.state = newState
|
||||
s.toNewGeneration(now)
|
||||
}
|
||||
|
||||
// toNewGeneration will increase the generation and clear the counter.
|
||||
// it also will reset the expiry
|
||||
func (s *circuitBreaker) toNewGeneration(now time.Time) {
|
||||
s.generation++
|
||||
s.counter.clear()
|
||||
var zero time.Time
|
||||
switch s.state {
|
||||
case StateClosed:
|
||||
s.expiry = now.Add(s.windowInterval)
|
||||
case StateOpen:
|
||||
s.expiry = now.Add(s.timeout)
|
||||
default: // StateHalfOpen
|
||||
s.expiry = zero
|
||||
}
|
||||
}
|
||||
|
||||
// beforeRequest return the current generation; if the breaker is in StateOpen, it will also return an errOpenState
|
||||
func (s *circuitBreaker) beforeRequest() (uint64, error) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
state, generation := s.currentState(now)
|
||||
//log.Println(s.counter)
|
||||
if state == StateOpen {
|
||||
return generation, errOpenState
|
||||
}
|
||||
return generation, nil
|
||||
}
|
||||
|
||||
func (s *circuitBreaker) afterRequest(before uint64, success bool) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
now := time.Now()
|
||||
state, generation := s.currentState(now)
|
||||
// the breaker has entered the next generation, the current results abandon.
|
||||
if generation != before {
|
||||
return
|
||||
}
|
||||
if success {
|
||||
s.onSuccess(state, now)
|
||||
} else {
|
||||
s.onFailure(state, now)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *circuitBreaker) onSuccess(state state, now time.Time) {
|
||||
switch state {
|
||||
case StateClosed:
|
||||
s.counter.onSuccess()
|
||||
case StateHalfOpen:
|
||||
s.counter.onSuccess()
|
||||
// The conditions for closing breaker are met
|
||||
if s.counter.all-s.counter.failures >= s.maxRequests {
|
||||
s.setState(StateClosed, now)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *circuitBreaker) readyToOpen(c counter) bool {
|
||||
failPre := float64(c.failures) / float64(c.all)
|
||||
return (c.failures >= s.maxFailNum && failPre >= float64(s.maxFailPercentage)/100.0) ||
|
||||
c.consecutiveFailures > 5
|
||||
}
|
||||
|
||||
func (s *circuitBreaker) onFailure(state state, now time.Time) {
|
||||
switch state {
|
||||
case StateClosed:
|
||||
s.counter.onFailure()
|
||||
if f := s.readyToOpen(s.counter); f {
|
||||
s.setState(StateOpen, now)
|
||||
}
|
||||
case StateHalfOpen:
|
||||
s.setState(StateOpen, now)
|
||||
}
|
||||
}
|
||||
|
||||
// checkEndpoint
|
||||
// valid: cvm.ap-shanghai.tencentcloudapi.com, cvm.ap-shenzhen-fs.tencentcloudapi.com,cvm.tencentcloudapi.com
|
||||
// invalid: cvm.tencentcloud.com
|
||||
func checkEndpoint(endpoint string) bool {
|
||||
ss := strings.Split(endpoint, ".")
|
||||
if len(ss) != 4 && len(ss) != 3 {
|
||||
return false
|
||||
}
|
||||
if ss[len(ss)-2] != "tencentcloudapi" {
|
||||
return false
|
||||
}
|
||||
// ap-beijing
|
||||
if len(ss) == 4 && len(strings.Split(ss[1], "-")) < 2 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func renewUrl(oldDomain, region string) string {
|
||||
ss := strings.Split(oldDomain, ".")
|
||||
if len(ss) == 3 {
|
||||
ss = append([]string{ss[0], region}, ss[1:]...)
|
||||
} else if len(ss) == 4 {
|
||||
ss[1] = region
|
||||
}
|
||||
newDomain := strings.Join(ss, ".")
|
||||
return newDomain
|
||||
}
|
||||
+412
@@ -0,0 +1,412 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||
)
|
||||
|
||||
const (
|
||||
octetStream = "application/octet-stream"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
region string
|
||||
httpClient *http.Client
|
||||
httpProfile *profile.HttpProfile
|
||||
profile *profile.ClientProfile
|
||||
credential CredentialIface
|
||||
signMethod string
|
||||
unsignedPayload bool
|
||||
debug bool
|
||||
rb *circuitBreaker
|
||||
}
|
||||
|
||||
func (c *Client) Send(request tchttp.Request, response tchttp.Response) (err error) {
|
||||
if request.GetScheme() == "" {
|
||||
request.SetScheme(c.httpProfile.Scheme)
|
||||
}
|
||||
|
||||
if request.GetRootDomain() == "" {
|
||||
request.SetRootDomain(c.httpProfile.RootDomain)
|
||||
}
|
||||
|
||||
if request.GetDomain() == "" {
|
||||
domain := c.httpProfile.Endpoint
|
||||
if domain == "" {
|
||||
domain = request.GetServiceDomain(request.GetService())
|
||||
}
|
||||
request.SetDomain(domain)
|
||||
}
|
||||
|
||||
if request.GetHttpMethod() == "" {
|
||||
request.SetHttpMethod(c.httpProfile.ReqMethod)
|
||||
}
|
||||
|
||||
tchttp.CompleteCommonParams(request, c.GetRegion())
|
||||
|
||||
// reflect to inject client if field ClientToken exists and retry feature is enabled
|
||||
if c.profile.NetworkFailureMaxRetries > 0 || c.profile.RateLimitExceededMaxRetries > 0 {
|
||||
safeInjectClientToken(request)
|
||||
}
|
||||
|
||||
if c.credential == nil {
|
||||
// Some APIs can skip signature.
|
||||
return c.sendWithoutSignature(request, response)
|
||||
} else if c.profile.DisableRegionBreaker == true || c.rb == nil {
|
||||
return c.sendWithSignature(request, response)
|
||||
} else {
|
||||
return c.sendWithRegionBreaker(request, response)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) sendWithRegionBreaker(request tchttp.Request, response tchttp.Response) (err error) {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if e != nil {
|
||||
msg := fmt.Sprintf("%s", e)
|
||||
err = tcerr.NewTencentCloudSDKError("ClientError.CircuitBreakerError", msg, "")
|
||||
}
|
||||
}()
|
||||
|
||||
ge, err := c.rb.beforeRequest()
|
||||
|
||||
if err == errOpenState {
|
||||
newEndpoint := request.GetService() + "." + c.rb.backupEndpoint
|
||||
request.SetDomain(newEndpoint)
|
||||
}
|
||||
err = c.sendWithSignature(request, response)
|
||||
isSuccess := false
|
||||
// Success is considered only when the server returns an effective response (have requestId and the code is not InternalError )
|
||||
if e, ok := err.(*tcerr.TencentCloudSDKError); ok {
|
||||
if e.GetRequestId() != "" && e.GetCode() != "InternalError" {
|
||||
isSuccess = true
|
||||
}
|
||||
}
|
||||
c.rb.afterRequest(ge, isSuccess)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) sendWithSignature(request tchttp.Request, response tchttp.Response) (err error) {
|
||||
if c.signMethod == "HmacSHA1" || c.signMethod == "HmacSHA256" {
|
||||
return c.sendWithSignatureV1(request, response)
|
||||
} else {
|
||||
return c.sendWithSignatureV3(request, response)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) sendWithoutSignature(request tchttp.Request, response tchttp.Response) error {
|
||||
httpRequest, err := http.NewRequestWithContext(request.GetContext(), request.GetHttpMethod(), request.GetUrl(), request.GetBodyReader())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if request.GetHttpMethod() == "POST" {
|
||||
httpRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
httpResponse, err := c.sendWithRateLimitRetry(httpRequest, isRetryable(request))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tchttp.ParseFromHttpResponse(httpResponse, response)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) sendWithSignatureV1(request tchttp.Request, response tchttp.Response) (err error) {
|
||||
// TODO: not an elegant way, it should be done in common params, but finally it need to refactor
|
||||
request.GetParams()["Language"] = c.profile.Language
|
||||
err = tchttp.ConstructParams(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = signRequest(request, c.credential, c.signMethod)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
httpRequest, err := http.NewRequestWithContext(request.GetContext(), request.GetHttpMethod(), request.GetUrl(), request.GetBodyReader())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if request.GetHttpMethod() == "POST" {
|
||||
httpRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
}
|
||||
httpResponse, err := c.sendWithRateLimitRetry(httpRequest, isRetryable(request))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tchttp.ParseFromHttpResponse(httpResponse, response)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) sendWithSignatureV3(request tchttp.Request, response tchttp.Response) (err error) {
|
||||
headers := map[string]string{
|
||||
"Host": request.GetDomain(),
|
||||
"X-TC-Action": request.GetAction(),
|
||||
"X-TC-Version": request.GetVersion(),
|
||||
"X-TC-Timestamp": request.GetParams()["Timestamp"],
|
||||
"X-TC-RequestClient": request.GetParams()["RequestClient"],
|
||||
"X-TC-Language": c.profile.Language,
|
||||
}
|
||||
if c.region != "" {
|
||||
headers["X-TC-Region"] = c.region
|
||||
}
|
||||
if c.credential.GetToken() != "" {
|
||||
headers["X-TC-Token"] = c.credential.GetToken()
|
||||
}
|
||||
if request.GetHttpMethod() == "GET" {
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
} else {
|
||||
headers["Content-Type"] = "application/json"
|
||||
}
|
||||
isOctetStream := false
|
||||
cr := &tchttp.CommonRequest{}
|
||||
ok := false
|
||||
var octetStreamBody []byte
|
||||
if cr, ok = request.(*tchttp.CommonRequest); ok {
|
||||
if cr.IsOctetStream() {
|
||||
isOctetStream = true
|
||||
// custom headers must contain Content-Type : application/octet-stream
|
||||
// todo:the custom header may overwrite headers
|
||||
for k, v := range cr.GetHeader() {
|
||||
headers[k] = v
|
||||
}
|
||||
octetStreamBody = cr.GetOctetStreamBody()
|
||||
}
|
||||
}
|
||||
|
||||
if !isOctetStream && request.GetContentType() == octetStream {
|
||||
isOctetStream = true
|
||||
b, _ := json.Marshal(request)
|
||||
var m map[string]string
|
||||
_ = json.Unmarshal(b, &m)
|
||||
for k, v := range m {
|
||||
key := "X-" + strings.ToUpper(request.GetService()) + "-" + k
|
||||
headers[key] = v
|
||||
}
|
||||
|
||||
headers["Content-Type"] = octetStream
|
||||
octetStreamBody = request.GetBody()
|
||||
}
|
||||
// start signature v3 process
|
||||
|
||||
// build canonical request string
|
||||
httpRequestMethod := request.GetHttpMethod()
|
||||
canonicalURI := "/"
|
||||
canonicalQueryString := ""
|
||||
if httpRequestMethod == "GET" {
|
||||
err = tchttp.ConstructParams(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := make(map[string]string)
|
||||
for key, value := range request.GetParams() {
|
||||
params[key] = value
|
||||
}
|
||||
delete(params, "Action")
|
||||
delete(params, "Version")
|
||||
delete(params, "Nonce")
|
||||
delete(params, "Region")
|
||||
delete(params, "RequestClient")
|
||||
delete(params, "Timestamp")
|
||||
canonicalQueryString = tchttp.GetUrlQueriesEncoded(params)
|
||||
}
|
||||
canonicalHeaders := fmt.Sprintf("content-type:%s\nhost:%s\n", headers["Content-Type"], headers["Host"])
|
||||
signedHeaders := "content-type;host"
|
||||
requestPayload := ""
|
||||
if httpRequestMethod == "POST" {
|
||||
if isOctetStream {
|
||||
// todo Conversion comparison between string and []byte affects performance much
|
||||
requestPayload = string(octetStreamBody)
|
||||
} else {
|
||||
b, err := json.Marshal(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
requestPayload = string(b)
|
||||
}
|
||||
}
|
||||
hashedRequestPayload := ""
|
||||
if c.unsignedPayload {
|
||||
hashedRequestPayload = sha256hex("UNSIGNED-PAYLOAD")
|
||||
headers["X-TC-Content-SHA256"] = "UNSIGNED-PAYLOAD"
|
||||
} else {
|
||||
hashedRequestPayload = sha256hex(requestPayload)
|
||||
}
|
||||
canonicalRequest := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n%s",
|
||||
httpRequestMethod,
|
||||
canonicalURI,
|
||||
canonicalQueryString,
|
||||
canonicalHeaders,
|
||||
signedHeaders,
|
||||
hashedRequestPayload)
|
||||
//log.Println("canonicalRequest:", canonicalRequest)
|
||||
|
||||
// build string to sign
|
||||
algorithm := "TC3-HMAC-SHA256"
|
||||
requestTimestamp := headers["X-TC-Timestamp"]
|
||||
timestamp, _ := strconv.ParseInt(requestTimestamp, 10, 64)
|
||||
t := time.Unix(timestamp, 0).UTC()
|
||||
// must be the format 2006-01-02, ref to package time for more info
|
||||
date := t.Format("2006-01-02")
|
||||
credentialScope := fmt.Sprintf("%s/%s/tc3_request", date, request.GetService())
|
||||
hashedCanonicalRequest := sha256hex(canonicalRequest)
|
||||
string2sign := fmt.Sprintf("%s\n%s\n%s\n%s",
|
||||
algorithm,
|
||||
requestTimestamp,
|
||||
credentialScope,
|
||||
hashedCanonicalRequest)
|
||||
//log.Println("string2sign", string2sign)
|
||||
|
||||
// sign string
|
||||
secretDate := hmacsha256(date, "TC3"+c.credential.GetSecretKey())
|
||||
secretService := hmacsha256(request.GetService(), secretDate)
|
||||
secretKey := hmacsha256("tc3_request", secretService)
|
||||
signature := hex.EncodeToString([]byte(hmacsha256(string2sign, secretKey)))
|
||||
//log.Println("signature", signature)
|
||||
|
||||
// build authorization
|
||||
authorization := fmt.Sprintf("%s Credential=%s/%s, SignedHeaders=%s, Signature=%s",
|
||||
algorithm,
|
||||
c.credential.GetSecretId(),
|
||||
credentialScope,
|
||||
signedHeaders,
|
||||
signature)
|
||||
//log.Println("authorization", authorization)
|
||||
|
||||
headers["Authorization"] = authorization
|
||||
url := request.GetScheme() + "://" + request.GetDomain() + request.GetPath()
|
||||
if canonicalQueryString != "" {
|
||||
url = url + "?" + canonicalQueryString
|
||||
}
|
||||
httpRequest, err := http.NewRequestWithContext(request.GetContext(), httpRequestMethod, url, strings.NewReader(requestPayload))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range headers {
|
||||
httpRequest.Header[k] = []string{v}
|
||||
}
|
||||
httpResponse, err := c.sendWithRateLimitRetry(httpRequest, isRetryable(request))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tchttp.ParseFromHttpResponse(httpResponse, response)
|
||||
return err
|
||||
}
|
||||
|
||||
// send http request
|
||||
func (c *Client) sendHttp(request *http.Request) (response *http.Response, err error) {
|
||||
if c.debug {
|
||||
outBytes, err := httputil.DumpRequest(request, true)
|
||||
if err != nil {
|
||||
log.Printf("[ERROR] dump request failed because %s", err)
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("[DEBUG] http request = %s", outBytes)
|
||||
}
|
||||
|
||||
response, err = c.httpClient.Do(request)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func (c *Client) GetRegion() string {
|
||||
return c.region
|
||||
}
|
||||
|
||||
func (c *Client) Init(region string) *Client {
|
||||
c.httpClient = &http.Client{}
|
||||
c.region = region
|
||||
c.signMethod = "TC3-HMAC-SHA256"
|
||||
c.debug = false
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) WithSecretId(secretId, secretKey string) *Client {
|
||||
c.credential = NewCredential(secretId, secretKey)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) WithCredential(cred CredentialIface) *Client {
|
||||
c.credential = cred
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) GetCredential() CredentialIface {
|
||||
return c.credential
|
||||
}
|
||||
|
||||
func (c *Client) WithProfile(clientProfile *profile.ClientProfile) *Client {
|
||||
c.profile = clientProfile
|
||||
if c.profile.DisableRegionBreaker == false {
|
||||
c.withRegionBreaker()
|
||||
}
|
||||
c.signMethod = clientProfile.SignMethod
|
||||
c.unsignedPayload = clientProfile.UnsignedPayload
|
||||
c.httpProfile = clientProfile.HttpProfile
|
||||
c.debug = clientProfile.Debug
|
||||
c.httpClient.Timeout = time.Duration(c.httpProfile.ReqTimeout) * time.Second
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) WithSignatureMethod(method string) *Client {
|
||||
c.signMethod = method
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) WithHttpTransport(transport http.RoundTripper) *Client {
|
||||
c.httpClient.Transport = transport
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) WithDebug(flag bool) *Client {
|
||||
c.debug = flag
|
||||
return c
|
||||
}
|
||||
|
||||
// WithProvider use specify provider to get a credential and use it to build a client
|
||||
func (c *Client) WithProvider(provider Provider) (*Client, error) {
|
||||
cred, err := provider.GetCredential()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.WithCredential(cred), nil
|
||||
}
|
||||
|
||||
func (c *Client) withRegionBreaker() *Client {
|
||||
rb := defaultRegionBreaker()
|
||||
if c.profile.BackupEndpoint != "" {
|
||||
rb.backupEndpoint = c.profile.BackupEndpoint
|
||||
} else if c.profile.BackupEndPoint != "" {
|
||||
rb.backupEndpoint = c.profile.BackupEndPoint
|
||||
}
|
||||
c.rb = rb
|
||||
return c
|
||||
}
|
||||
|
||||
func NewClientWithSecretId(secretId, secretKey, region string) (client *Client, err error) {
|
||||
client = &Client{}
|
||||
client.Init(region).WithSecretId(secretId, secretKey)
|
||||
return
|
||||
}
|
||||
|
||||
// NewClientWithProviders build client with your custom providers;
|
||||
// If you don't specify the providers, it will use the DefaultProviderChain to find credential
|
||||
func NewClientWithProviders(region string, providers ...Provider) (client *Client, err error) {
|
||||
client = (&Client{}).Init(region)
|
||||
var pc Provider
|
||||
if len(providers) == 0 {
|
||||
pc = DefaultProviderChain()
|
||||
} else {
|
||||
pc = NewProviderChain(providers)
|
||||
}
|
||||
return client.WithProvider(pc)
|
||||
}
|
||||
Generated
Vendored
+46
@@ -0,0 +1,46 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"crypto/rand"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const (
|
||||
fieldClientToken = "ClientToken"
|
||||
)
|
||||
|
||||
func safeInjectClientToken(obj interface{}) {
|
||||
// obj Must be struct ptr
|
||||
getType := reflect.TypeOf(obj)
|
||||
if getType.Kind() != reflect.Ptr || getType.Elem().Kind() != reflect.Struct {
|
||||
return
|
||||
}
|
||||
|
||||
// obj Must exist named field
|
||||
_, ok := getType.Elem().FieldByName(fieldClientToken)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
field := reflect.ValueOf(obj).Elem().FieldByName(fieldClientToken)
|
||||
|
||||
// field Must be string ptr
|
||||
if field.Kind() != reflect.Ptr {
|
||||
return
|
||||
}
|
||||
|
||||
// Set if ClientToken is nil or empty
|
||||
if field.IsNil() || (field.Elem().Kind() == reflect.String && field.Elem().Len() == 0) {
|
||||
uuidVal := randomClientToken()
|
||||
field.Set(reflect.ValueOf(&uuidVal))
|
||||
}
|
||||
}
|
||||
|
||||
// randomClientToken generate random string as ClientToken
|
||||
// ref: https://stackoverflow.com/questions/15130321/is-there-a-method-to-generate-a-uuid-with-go-language
|
||||
func randomClientToken() string {
|
||||
b := make([]byte, 16)
|
||||
_, _ = rand.Read(b)
|
||||
return fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
|
||||
}
|
||||
Generated
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||
)
|
||||
|
||||
func NewCommonClient(cred CredentialIface, region string, clientProfile *profile.ClientProfile) (c *Client) {
|
||||
return new(Client).Init(region).WithCredential(cred).WithProfile(clientProfile)
|
||||
}
|
||||
|
||||
// SendOctetStream Invoke API with application/octet-stream content-type.
|
||||
//
|
||||
// Note:
|
||||
// 1. only specific API can be invoked in such manner.
|
||||
// 2. only TC3-HMAC-SHA256 signature method can be specified.
|
||||
// 3. only POST request method can be specified
|
||||
// 4. the request Must be a CommonRequest and called SetOctetStreamParameters
|
||||
//
|
||||
func (c *Client) SendOctetStream(request tchttp.Request, response tchttp.Response) (err error) {
|
||||
if c.profile.SignMethod != "TC3-HMAC-SHA256" {
|
||||
return tcerr.NewTencentCloudSDKError("ClientError", "Invalid signature method.", "")
|
||||
}
|
||||
if c.profile.HttpProfile.ReqMethod != "POST" {
|
||||
return tcerr.NewTencentCloudSDKError("ClientError", "Invalid request method.", "")
|
||||
}
|
||||
//cr, ok := request.(*tchttp.CommonRequest)
|
||||
//if !ok {
|
||||
// return tcerr.NewTencentCloudSDKError("ClientError", "Invalid request, must be *CommonRequest!", "")
|
||||
//}
|
||||
//if !cr.IsOctetStream() {
|
||||
// return tcerr.NewTencentCloudSDKError("ClientError", "Invalid request, does not meet the conditions for sending OctetStream", "")
|
||||
//}
|
||||
return c.Send(request, response)
|
||||
}
|
||||
Generated
Vendored
+51
@@ -0,0 +1,51 @@
|
||||
package common
|
||||
|
||||
var creErr = "ClientError.CredentialError"
|
||||
|
||||
type CredentialIface interface {
|
||||
GetSecretId() string
|
||||
GetToken() string
|
||||
GetSecretKey() string
|
||||
// needRefresh() bool
|
||||
// refresh()
|
||||
}
|
||||
|
||||
type Credential struct {
|
||||
SecretId string
|
||||
SecretKey string
|
||||
Token string
|
||||
}
|
||||
|
||||
func (c *Credential) needRefresh() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Credential) refresh() {
|
||||
}
|
||||
|
||||
func NewCredential(secretId, secretKey string) *Credential {
|
||||
return &Credential{
|
||||
SecretId: secretId,
|
||||
SecretKey: secretKey,
|
||||
}
|
||||
}
|
||||
|
||||
func NewTokenCredential(secretId, secretKey, token string) *Credential {
|
||||
return &Credential{
|
||||
SecretId: secretId,
|
||||
SecretKey: secretKey,
|
||||
Token: token,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Credential) GetSecretKey() string {
|
||||
return c.SecretKey
|
||||
}
|
||||
|
||||
func (c *Credential) GetSecretId() string {
|
||||
return c.SecretId
|
||||
}
|
||||
|
||||
func (c *Credential) GetToken() string {
|
||||
return c.Token
|
||||
}
|
||||
Generated
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
const ExpiredTimeout = 300
|
||||
|
||||
type CvmRoleCredential struct {
|
||||
roleName string
|
||||
expiredTime int64
|
||||
tmpSecretId string
|
||||
tmpSecretKey string
|
||||
token string
|
||||
source *CvmRoleProvider
|
||||
}
|
||||
|
||||
func (c *CvmRoleCredential) GetSecretId() string {
|
||||
if c.needRefresh() {
|
||||
c.refresh()
|
||||
}
|
||||
return c.tmpSecretId
|
||||
}
|
||||
|
||||
func (c *CvmRoleCredential) GetToken() string {
|
||||
if c.needRefresh() {
|
||||
c.refresh()
|
||||
}
|
||||
return c.token
|
||||
}
|
||||
|
||||
func (c *CvmRoleCredential) GetSecretKey() string {
|
||||
if c.needRefresh() {
|
||||
c.refresh()
|
||||
}
|
||||
return c.tmpSecretKey
|
||||
}
|
||||
|
||||
func (c *CvmRoleCredential) needRefresh() bool {
|
||||
if c.tmpSecretId == "" || c.tmpSecretKey == "" || c.token == "" || c.expiredTime-ExpiredTimeout <= time.Now().Unix() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *CvmRoleCredential) refresh() {
|
||||
newCre, err := c.source.GetCredential()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
*c = *newCre.(*CvmRoleCredential)
|
||||
}
|
||||
Generated
Vendored
+96
@@ -0,0 +1,96 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
metaUrl = "http://metadata.tencentyun.com/latest/meta-data/"
|
||||
roleUrl = metaUrl + "cam/security-credentials/"
|
||||
)
|
||||
|
||||
var roleNotBound = errors.New("get cvm role name failed, Please confirm whether the role is bound")
|
||||
|
||||
type CvmRoleProvider struct {
|
||||
roleName string
|
||||
}
|
||||
|
||||
type roleRsp struct {
|
||||
TmpSecretId string `json:"TmpSecretId"`
|
||||
TmpSecretKey string `json:"TmpSecretKey"`
|
||||
ExpiredTime int64 `json:"ExpiredTime"`
|
||||
Expiration time.Time `json:"Expiration"`
|
||||
Token string `json:"Token"`
|
||||
Code string `json:"Code"`
|
||||
}
|
||||
|
||||
// NewCvmRoleProvider need you to specify the roleName of the cvm currently in use
|
||||
func NewCvmRoleProvider(roleName string) *CvmRoleProvider {
|
||||
return &CvmRoleProvider{roleName: roleName}
|
||||
}
|
||||
|
||||
// DefaultCvmRoleProvider will auto get the cvm role name by accessing the metadata api
|
||||
// more info please lookup: https://cloud.tencent.com/document/product/213/4934
|
||||
func DefaultCvmRoleProvider() *CvmRoleProvider {
|
||||
return NewCvmRoleProvider("")
|
||||
}
|
||||
|
||||
func get(url string) ([]byte, error) {
|
||||
rsp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rsp.StatusCode == http.StatusNotFound {
|
||||
return nil, roleNotBound
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(rsp.Body)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
func (r *CvmRoleProvider) getRoleName() (string, error) {
|
||||
if r.roleName != "" {
|
||||
return r.roleName, nil
|
||||
}
|
||||
rn, err := get(roleUrl)
|
||||
return string(rn), err
|
||||
}
|
||||
|
||||
func (r *CvmRoleProvider) GetCredential() (CredentialIface, error) {
|
||||
roleName, err := r.getRoleName()
|
||||
if err != nil {
|
||||
return nil, noCvmRole
|
||||
}
|
||||
// get the cvm role name by accessing the metadata api
|
||||
// https://cloud.tencent.com/document/product/213/4934
|
||||
body, err := get(roleUrl + roleName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rspSt := new(roleRsp)
|
||||
if err = json.Unmarshal(body, rspSt); err != nil {
|
||||
return nil, tcerr.NewTencentCloudSDKError(creErr, err.Error(), "")
|
||||
}
|
||||
if rspSt.Code != "Success" {
|
||||
return nil, tcerr.NewTencentCloudSDKError(creErr, "Get credential from metadata server by role name "+roleName+" failed, code="+rspSt.Code, "")
|
||||
}
|
||||
cre := &CvmRoleCredential{
|
||||
tmpSecretId: rspSt.TmpSecretId,
|
||||
tmpSecretKey: rspSt.TmpSecretKey,
|
||||
token: rspSt.Token,
|
||||
roleName: roleName,
|
||||
expiredTime: rspSt.ExpiredTime,
|
||||
source: r,
|
||||
}
|
||||
return cre, nil
|
||||
}
|
||||
Generated
Vendored
+40
@@ -0,0 +1,40 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
type EnvProvider struct {
|
||||
secretIdENV string
|
||||
secretKeyENV string
|
||||
}
|
||||
|
||||
// DefaultEnvProvider return a default provider
|
||||
// The default environment variable name are TENCENTCLOUD_SECRET_ID and TENCENTCLOUD_SECRET_KEY
|
||||
func DefaultEnvProvider() *EnvProvider {
|
||||
return &EnvProvider{
|
||||
secretIdENV: "TENCENTCLOUD_SECRET_ID",
|
||||
secretKeyENV: "TENCENTCLOUD_SECRET_KEY",
|
||||
}
|
||||
}
|
||||
|
||||
// NewEnvProvider uses the name of the environment variable you specified to get the credentials
|
||||
func NewEnvProvider(secretIdEnvName, secretKeyEnvName string) *EnvProvider {
|
||||
return &EnvProvider{
|
||||
secretIdENV: secretIdEnvName,
|
||||
secretKeyENV: secretKeyEnvName,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *EnvProvider) GetCredential() (CredentialIface, error) {
|
||||
secretId, ok1 := os.LookupEnv(p.secretIdENV)
|
||||
secretKey, ok2 := os.LookupEnv(p.secretKeyENV)
|
||||
if !ok1 || !ok2 {
|
||||
return nil, envNotSet
|
||||
}
|
||||
if secretId == "" || secretKey == "" {
|
||||
return nil, tcerr.NewTencentCloudSDKError(creErr, "Environmental variable ("+p.secretIdENV+" or "+p.secretKeyENV+") is empty", "")
|
||||
}
|
||||
return NewCredential(secretId, secretKey), nil
|
||||
}
|
||||
Generated
Vendored
+38
@@ -0,0 +1,38 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type TencentCloudSDKError struct {
|
||||
Code string
|
||||
Message string
|
||||
RequestId string
|
||||
}
|
||||
|
||||
func (e *TencentCloudSDKError) Error() string {
|
||||
if e.RequestId == "" {
|
||||
return fmt.Sprintf("[TencentCloudSDKError] Code=%s, Message=%s", e.Code, e.Message)
|
||||
}
|
||||
return fmt.Sprintf("[TencentCloudSDKError] Code=%s, Message=%s, RequestId=%s", e.Code, e.Message, e.RequestId)
|
||||
}
|
||||
|
||||
func NewTencentCloudSDKError(code, message, requestId string) error {
|
||||
return &TencentCloudSDKError{
|
||||
Code: code,
|
||||
Message: message,
|
||||
RequestId: requestId,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *TencentCloudSDKError) GetCode() string {
|
||||
return e.Code
|
||||
}
|
||||
|
||||
func (e *TencentCloudSDKError) GetMessage() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func (e *TencentCloudSDKError) GetRequestId() string {
|
||||
return e.RequestId
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
module github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common
|
||||
|
||||
go 1.14
|
||||
Generated
Vendored
+108
@@ -0,0 +1,108 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
octetStream = "application/octet-stream"
|
||||
)
|
||||
|
||||
type actionParameters map[string]interface{}
|
||||
|
||||
type CommonRequest struct {
|
||||
*BaseRequest
|
||||
// custom header, may be overwritten
|
||||
header map[string]string
|
||||
actionParameters
|
||||
}
|
||||
|
||||
func NewCommonRequest(service, version, action string) (request *CommonRequest) {
|
||||
request = &CommonRequest{
|
||||
BaseRequest: &BaseRequest{},
|
||||
actionParameters: actionParameters{},
|
||||
}
|
||||
request.Init().WithApiInfo(service, version, action)
|
||||
return
|
||||
}
|
||||
|
||||
// SetActionParameters set common request's actionParameters to your data.
|
||||
// note: your data Must be a json-formatted string or byte array or map[string]interface{}
|
||||
// note: you could not call SetActionParameters and SetOctetStreamParameters at once
|
||||
func (cr *CommonRequest) SetActionParameters(data interface{}) error {
|
||||
if data == nil {
|
||||
return nil
|
||||
}
|
||||
switch data.(type) {
|
||||
case []byte:
|
||||
if err := json.Unmarshal(data.([]byte), &cr.actionParameters); err != nil {
|
||||
msg := fmt.Sprintf("Fail to parse contenst %s to json,because: %s", data.([]byte), err)
|
||||
return tcerr.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
|
||||
}
|
||||
case string:
|
||||
if err := json.Unmarshal([]byte(data.(string)), &cr.actionParameters); err != nil {
|
||||
msg := fmt.Sprintf("Fail to parse contenst %s to json,because: %s", data.(string), err)
|
||||
return tcerr.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
|
||||
}
|
||||
case map[string]interface{}:
|
||||
cr.actionParameters = data.(map[string]interface{})
|
||||
default:
|
||||
msg := fmt.Sprintf("Invalid data type:%T, must be one of the following: []byte, string, map[string]interface{}", data)
|
||||
return tcerr.NewTencentCloudSDKError("ClientError.InvalidParameter", msg, "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr *CommonRequest) IsOctetStream() bool {
|
||||
v, ok := cr.header["Content-Type"]
|
||||
if !ok || v != octetStream {
|
||||
return false
|
||||
}
|
||||
value, ok := cr.actionParameters["OctetStreamBody"]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
_, ok = value.([]byte)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (cr *CommonRequest) SetHeader(header map[string]string) {
|
||||
if header == nil {
|
||||
return
|
||||
}
|
||||
cr.header = header
|
||||
}
|
||||
|
||||
func (cr *CommonRequest) GetHeader() map[string]string {
|
||||
return cr.header
|
||||
}
|
||||
|
||||
// SetOctetStreamParameters set request body to your data, and set head Content-Type to application/octet-stream
|
||||
// note: you could not call SetActionParameters and SetOctetStreamParameters on the same request
|
||||
func (cr *CommonRequest) SetOctetStreamParameters(header map[string]string, body []byte) {
|
||||
parameter := map[string]interface{}{}
|
||||
if header == nil {
|
||||
header = map[string]string{}
|
||||
}
|
||||
header["Content-Type"] = octetStream
|
||||
cr.header = header
|
||||
parameter["OctetStreamBody"] = body
|
||||
cr.actionParameters = parameter
|
||||
}
|
||||
|
||||
func (cr *CommonRequest) GetOctetStreamBody() []byte {
|
||||
if cr.IsOctetStream() {
|
||||
return cr.actionParameters["OctetStreamBody"].([]byte)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (cr *CommonRequest) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(cr.actionParameters)
|
||||
}
|
||||
Generated
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
package common
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type actionResult map[string]interface{}
|
||||
type CommonResponse struct {
|
||||
*BaseResponse
|
||||
*actionResult
|
||||
}
|
||||
|
||||
func NewCommonResponse() (response *CommonResponse) {
|
||||
response = &CommonResponse{
|
||||
BaseResponse: &BaseResponse{},
|
||||
actionResult: &actionResult{},
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (r *CommonResponse) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, r.actionResult)
|
||||
}
|
||||
|
||||
func (r *CommonResponse) GetBody() []byte {
|
||||
raw, _ := json.Marshal(r.actionResult)
|
||||
return raw
|
||||
}
|
||||
Generated
Vendored
+321
@@ -0,0 +1,321 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
//"log"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
POST = "POST"
|
||||
GET = "GET"
|
||||
|
||||
HTTP = "http"
|
||||
HTTPS = "https"
|
||||
|
||||
RootDomain = "tencentcloudapi.com"
|
||||
Path = "/"
|
||||
)
|
||||
|
||||
type Request interface {
|
||||
GetAction() string
|
||||
GetBodyReader() io.Reader
|
||||
GetScheme() string
|
||||
GetRootDomain() string
|
||||
GetServiceDomain(string) string
|
||||
GetDomain() string
|
||||
GetHttpMethod() string
|
||||
GetParams() map[string]string
|
||||
GetBody() []byte
|
||||
GetPath() string
|
||||
GetService() string
|
||||
GetUrl() string
|
||||
GetVersion() string
|
||||
GetContentType() string
|
||||
GetContext() context.Context
|
||||
SetScheme(string)
|
||||
SetRootDomain(string)
|
||||
SetDomain(string)
|
||||
SetHttpMethod(string)
|
||||
SetPath(string)
|
||||
SetContentType(string)
|
||||
SetBody([]byte)
|
||||
SetContext(context.Context)
|
||||
}
|
||||
|
||||
type BaseRequest struct {
|
||||
context context.Context
|
||||
httpMethod string
|
||||
scheme string
|
||||
rootDomain string
|
||||
domain string
|
||||
path string
|
||||
params map[string]string
|
||||
formParams map[string]string
|
||||
|
||||
service string
|
||||
version string
|
||||
action string
|
||||
|
||||
contentType string
|
||||
body []byte
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetAction() string {
|
||||
return r.action
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetHttpMethod() string {
|
||||
return r.httpMethod
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetParams() map[string]string {
|
||||
return r.params
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetPath() string {
|
||||
return r.path
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetDomain() string {
|
||||
return r.domain
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetScheme() string {
|
||||
return r.scheme
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetRootDomain() string {
|
||||
return r.rootDomain
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetServiceDomain(service string) (domain string) {
|
||||
rootDomain := r.rootDomain
|
||||
if rootDomain == "" {
|
||||
rootDomain = RootDomain
|
||||
}
|
||||
domain = service + "." + rootDomain
|
||||
return
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetBody() []byte {
|
||||
return r.body
|
||||
}
|
||||
|
||||
func (r *BaseRequest) SetBody(body []byte) {
|
||||
r.body = body
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetContentType() string {
|
||||
return r.contentType
|
||||
}
|
||||
|
||||
func (r *BaseRequest) SetContentType(contentType string) {
|
||||
r.contentType = contentType
|
||||
}
|
||||
|
||||
func (r *BaseRequest) SetDomain(domain string) {
|
||||
r.domain = domain
|
||||
}
|
||||
|
||||
func (r *BaseRequest) SetScheme(scheme string) {
|
||||
scheme = strings.ToLower(scheme)
|
||||
switch scheme {
|
||||
case HTTP:
|
||||
r.scheme = HTTP
|
||||
default:
|
||||
r.scheme = HTTPS
|
||||
}
|
||||
}
|
||||
|
||||
func (r *BaseRequest) SetRootDomain(rootDomain string) {
|
||||
r.rootDomain = rootDomain
|
||||
}
|
||||
|
||||
func (r *BaseRequest) SetHttpMethod(method string) {
|
||||
switch strings.ToUpper(method) {
|
||||
case POST:
|
||||
{
|
||||
r.httpMethod = POST
|
||||
}
|
||||
case GET:
|
||||
{
|
||||
r.httpMethod = GET
|
||||
}
|
||||
default:
|
||||
{
|
||||
r.httpMethod = GET
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *BaseRequest) SetPath(path string) {
|
||||
r.path = path
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetService() string {
|
||||
return r.service
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetUrl() string {
|
||||
if r.httpMethod == GET {
|
||||
return r.GetScheme() + "://" + r.domain + r.path + "?" + GetUrlQueriesEncoded(r.params)
|
||||
} else if r.httpMethod == POST {
|
||||
return r.GetScheme() + "://" + r.domain + r.path
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetVersion() string {
|
||||
return r.version
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetContext() context.Context {
|
||||
if r.context == nil {
|
||||
return context.Background()
|
||||
}
|
||||
return r.context
|
||||
}
|
||||
|
||||
func (r *BaseRequest) SetContext(ctx context.Context) {
|
||||
r.context = ctx
|
||||
}
|
||||
|
||||
func GetUrlQueriesEncoded(params map[string]string) string {
|
||||
values := url.Values{}
|
||||
for key, value := range params {
|
||||
values.Add(key, value)
|
||||
}
|
||||
return values.Encode()
|
||||
}
|
||||
|
||||
func (r *BaseRequest) GetBodyReader() io.Reader {
|
||||
if r.httpMethod == POST {
|
||||
s := GetUrlQueriesEncoded(r.params)
|
||||
return strings.NewReader(s)
|
||||
} else {
|
||||
return strings.NewReader("")
|
||||
}
|
||||
}
|
||||
|
||||
func (r *BaseRequest) Init() *BaseRequest {
|
||||
r.domain = ""
|
||||
r.path = Path
|
||||
r.params = make(map[string]string)
|
||||
r.formParams = make(map[string]string)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *BaseRequest) WithApiInfo(service, version, action string) *BaseRequest {
|
||||
r.service = service
|
||||
r.version = version
|
||||
r.action = action
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *BaseRequest) WithContentType(contentType string) *BaseRequest {
|
||||
r.contentType = contentType
|
||||
return r
|
||||
}
|
||||
|
||||
// Deprecated, use request.GetServiceDomain instead
|
||||
func GetServiceDomain(service string) (domain string) {
|
||||
domain = service + "." + RootDomain
|
||||
return
|
||||
}
|
||||
|
||||
func CompleteCommonParams(request Request, region string) {
|
||||
params := request.GetParams()
|
||||
params["Region"] = region
|
||||
if request.GetVersion() != "" {
|
||||
params["Version"] = request.GetVersion()
|
||||
}
|
||||
params["Action"] = request.GetAction()
|
||||
params["Timestamp"] = strconv.FormatInt(time.Now().Unix(), 10)
|
||||
params["Nonce"] = strconv.Itoa(rand.Int())
|
||||
params["RequestClient"] = "SDK_GO_1.0.364"
|
||||
}
|
||||
|
||||
func ConstructParams(req Request) (err error) {
|
||||
value := reflect.ValueOf(req).Elem()
|
||||
err = flatStructure(value, req, "")
|
||||
//log.Printf("[DEBUG] params=%s", req.GetParams())
|
||||
return
|
||||
}
|
||||
|
||||
func flatStructure(value reflect.Value, request Request, prefix string) (err error) {
|
||||
//log.Printf("[DEBUG] reflect value: %v", value.Type())
|
||||
valueType := value.Type()
|
||||
for i := 0; i < valueType.NumField(); i++ {
|
||||
tag := valueType.Field(i).Tag
|
||||
nameTag, hasNameTag := tag.Lookup("name")
|
||||
if !hasNameTag {
|
||||
continue
|
||||
}
|
||||
field := value.Field(i)
|
||||
kind := field.Kind()
|
||||
if kind == reflect.Ptr && field.IsNil() {
|
||||
continue
|
||||
}
|
||||
if kind == reflect.Ptr {
|
||||
field = field.Elem()
|
||||
kind = field.Kind()
|
||||
}
|
||||
key := prefix + nameTag
|
||||
if kind == reflect.String {
|
||||
s := field.String()
|
||||
if s != "" {
|
||||
request.GetParams()[key] = s
|
||||
}
|
||||
} else if kind == reflect.Bool {
|
||||
request.GetParams()[key] = strconv.FormatBool(field.Bool())
|
||||
} else if kind == reflect.Int || kind == reflect.Int64 {
|
||||
request.GetParams()[key] = strconv.FormatInt(field.Int(), 10)
|
||||
} else if kind == reflect.Uint || kind == reflect.Uint64 {
|
||||
request.GetParams()[key] = strconv.FormatUint(field.Uint(), 10)
|
||||
} else if kind == reflect.Float64 {
|
||||
request.GetParams()[key] = strconv.FormatFloat(field.Float(), 'f', -1, 64)
|
||||
} else if kind == reflect.Slice {
|
||||
list := value.Field(i)
|
||||
for j := 0; j < list.Len(); j++ {
|
||||
vj := list.Index(j)
|
||||
key := prefix + nameTag + "." + strconv.Itoa(j)
|
||||
kind = vj.Kind()
|
||||
if kind == reflect.Ptr && vj.IsNil() {
|
||||
continue
|
||||
}
|
||||
if kind == reflect.Ptr {
|
||||
vj = vj.Elem()
|
||||
kind = vj.Kind()
|
||||
}
|
||||
if kind == reflect.String {
|
||||
request.GetParams()[key] = vj.String()
|
||||
} else if kind == reflect.Bool {
|
||||
request.GetParams()[key] = strconv.FormatBool(vj.Bool())
|
||||
} else if kind == reflect.Int || kind == reflect.Int64 {
|
||||
request.GetParams()[key] = strconv.FormatInt(vj.Int(), 10)
|
||||
} else if kind == reflect.Uint || kind == reflect.Uint64 {
|
||||
request.GetParams()[key] = strconv.FormatUint(vj.Uint(), 10)
|
||||
} else if kind == reflect.Float64 {
|
||||
request.GetParams()[key] = strconv.FormatFloat(vj.Float(), 'f', -1, 64)
|
||||
} else {
|
||||
if err = flatStructure(vj, request, key+"."); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err = flatStructure(reflect.ValueOf(field.Interface()), request, prefix+nameTag+"."); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
Generated
Vendored
+104
@@ -0,0 +1,104 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
//"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
)
|
||||
|
||||
type Response interface {
|
||||
ParseErrorFromHTTPResponse(body []byte) error
|
||||
}
|
||||
|
||||
type BaseResponse struct {
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
Response struct {
|
||||
Error struct {
|
||||
Code string `json:"Code"`
|
||||
Message string `json:"Message"`
|
||||
} `json:"Error,omitempty"`
|
||||
RequestId string `json:"RequestId"`
|
||||
} `json:"Response"`
|
||||
}
|
||||
|
||||
type DeprecatedAPIErrorResponse struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
CodeDesc string `json:"codeDesc"`
|
||||
}
|
||||
|
||||
func (r *BaseResponse) ParseErrorFromHTTPResponse(body []byte) (err error) {
|
||||
resp := &ErrorResponse{}
|
||||
err = json.Unmarshal(body, resp)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
|
||||
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
|
||||
}
|
||||
if resp.Response.Error.Code != "" {
|
||||
return errors.NewTencentCloudSDKError(resp.Response.Error.Code, resp.Response.Error.Message, resp.Response.RequestId)
|
||||
}
|
||||
|
||||
deprecated := &DeprecatedAPIErrorResponse{}
|
||||
err = json.Unmarshal(body, deprecated)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
|
||||
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
|
||||
}
|
||||
if deprecated.Code != 0 {
|
||||
return errors.NewTencentCloudSDKError(deprecated.CodeDesc, deprecated.Message, "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseErrorFromHTTPResponse(body []byte) (err error) {
|
||||
resp := &ErrorResponse{}
|
||||
err = json.Unmarshal(body, resp)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
|
||||
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
|
||||
}
|
||||
if resp.Response.Error.Code != "" {
|
||||
return errors.NewTencentCloudSDKError(resp.Response.Error.Code, resp.Response.Error.Message, resp.Response.RequestId)
|
||||
}
|
||||
|
||||
deprecated := &DeprecatedAPIErrorResponse{}
|
||||
err = json.Unmarshal(body, deprecated)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
|
||||
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
|
||||
}
|
||||
if deprecated.Code != 0 {
|
||||
return errors.NewTencentCloudSDKError(deprecated.CodeDesc, deprecated.Message, "")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ParseFromHttpResponse(hr *http.Response, response Response) (err error) {
|
||||
defer hr.Body.Close()
|
||||
body, err := ioutil.ReadAll(hr.Body)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Fail to read response body because %s", err)
|
||||
return errors.NewTencentCloudSDKError("ClientError.IOError", msg, "")
|
||||
}
|
||||
if hr.StatusCode != 200 {
|
||||
msg := fmt.Sprintf("Request fail with http status code: %s, with body: %s", hr.Status, body)
|
||||
return errors.NewTencentCloudSDKError("ClientError.HttpStatusCodeError", msg, "")
|
||||
}
|
||||
//log.Printf("[DEBUG] Response Body=%s", body)
|
||||
err = response.ParseErrorFromHTTPResponse(body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(body, &response)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Fail to parse json content: %s, because: %s", body, err)
|
||||
return errors.NewTencentCloudSDKError("ClientError.ParseJsonError", msg, "")
|
||||
}
|
||||
return
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
|
||||
tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
globalSectionName = "____GLOBAL____"
|
||||
iniErr = "ClientError.INIError"
|
||||
)
|
||||
|
||||
func openFile(path string) (data []byte, err error) {
|
||||
data, err = ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
err = tcerr.NewTencentCloudSDKError(iniErr, err.Error(), "")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parse(path string) (*sections, error) {
|
||||
result := §ions{map[string]*section{}}
|
||||
buf, err := openFile(path)
|
||||
if err != nil {
|
||||
return §ions{}, err
|
||||
}
|
||||
content := string(buf)
|
||||
|
||||
lines := strings.Split(content, "\n")
|
||||
if len(lines) == 0 {
|
||||
msg := fmt.Sprintf("the result of reading the %s is empty", path)
|
||||
return §ions{}, tcerr.NewTencentCloudSDKError(iniErr, msg, "")
|
||||
}
|
||||
currentSectionName := globalSectionName
|
||||
currentSection := §ion{make(map[string]*value)}
|
||||
for i, line := range lines {
|
||||
line = strings.Replace(line, "\r", "", -1)
|
||||
line = strings.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
// comments
|
||||
if strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
|
||||
continue
|
||||
}
|
||||
// section name
|
||||
if strings.HasPrefix(line, "[") {
|
||||
if strings.HasSuffix(line, "]") {
|
||||
tempSection := line[1 : len(line)-1]
|
||||
if len(tempSection) == 0 {
|
||||
msg := fmt.Sprintf("INI file %s lien %d is not valid: wrong section", path, i)
|
||||
return result, tcerr.NewTencentCloudSDKError(iniErr, msg, "")
|
||||
}
|
||||
// Save the previous section
|
||||
result.contains[currentSectionName] = currentSection
|
||||
// new section
|
||||
currentSectionName = tempSection
|
||||
currentSection = §ion{make(map[string]*value, 0)}
|
||||
continue
|
||||
} else {
|
||||
msg := fmt.Sprintf("INI file %s lien %d is not valid: wrong section", path, i)
|
||||
return result, tcerr.NewTencentCloudSDKError(iniErr, msg, "")
|
||||
}
|
||||
}
|
||||
|
||||
pos := strings.Index(line, "=")
|
||||
if pos > 0 && pos < len(line)-1 {
|
||||
key := line[:pos]
|
||||
val := line[pos+1:]
|
||||
|
||||
key = strings.TrimSpace(key)
|
||||
val = strings.TrimSpace(val)
|
||||
|
||||
v := &value{raw: val}
|
||||
currentSection.content[key] = v
|
||||
}
|
||||
}
|
||||
|
||||
result.contains[currentSectionName] = currentSection
|
||||
return result, nil
|
||||
}
|
||||
Generated
Vendored
+83
@@ -0,0 +1,83 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||
)
|
||||
|
||||
const (
|
||||
tplNetworkFailureRetry = "[WARN] temporary network failure, retrying (%d/%d) in %f seconds: %s"
|
||||
)
|
||||
|
||||
func (c *Client) sendWithNetworkFailureRetry(req *http.Request, retryable bool) (resp *http.Response, err error) {
|
||||
// make sure maxRetries is more than or equal 0
|
||||
var maxRetries int
|
||||
if retryable {
|
||||
maxRetries = maxInt(c.profile.NetworkFailureMaxRetries, 0)
|
||||
}
|
||||
durationFunc := safeDurationFunc(c.profile.NetworkFailureRetryDuration)
|
||||
|
||||
for idx := 0; idx <= maxRetries; idx++ {
|
||||
resp, err = c.sendHttp(req)
|
||||
|
||||
// retry when error occurred and retryable and not the last retry
|
||||
// should not sleep on last retry even if it's retryable
|
||||
if err != nil && retryable && idx < maxRetries {
|
||||
if err, ok := err.(net.Error); ok && (err.Timeout() || err.Temporary()) {
|
||||
duration := durationFunc(idx)
|
||||
if c.debug {
|
||||
log.Printf(tplNetworkFailureRetry, idx, maxRetries, duration.Seconds(), err.Error())
|
||||
}
|
||||
|
||||
time.Sleep(duration)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Fail to get response because %s", err)
|
||||
err = errors.NewTencentCloudSDKError("ClientError.NetworkError", msg, "")
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func maxInt(a, b int) int {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func safeDurationFunc(durationFunc profile.DurationFunc) profile.DurationFunc {
|
||||
if durationFunc != nil {
|
||||
return durationFunc
|
||||
}
|
||||
return profile.ExponentialBackoff
|
||||
}
|
||||
|
||||
// isRetryable means if request is retryable or not,
|
||||
// depends on if request has a `ClientToken` field or not,
|
||||
// request with `ClientToken` means it's idempotent and retryable,
|
||||
// unretryable request SHOULDN'T retry for temporary network failure
|
||||
func isRetryable(obj interface{}) bool {
|
||||
// obj Must be struct ptr
|
||||
getType := reflect.TypeOf(obj)
|
||||
if getType.Kind() != reflect.Ptr || getType.Elem().Kind() != reflect.Struct {
|
||||
return false
|
||||
}
|
||||
|
||||
// obj Must exist named field
|
||||
_, ok := getType.Elem().FieldByName(fieldClientToken)
|
||||
return ok
|
||||
}
|
||||
Generated
Vendored
+57
@@ -0,0 +1,57 @@
|
||||
package profile
|
||||
|
||||
import (
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DurationFunc func(index int) time.Duration
|
||||
|
||||
func ConstantDurationFunc(duration time.Duration) DurationFunc {
|
||||
return func(int) time.Duration {
|
||||
return duration
|
||||
}
|
||||
}
|
||||
|
||||
func ExponentialBackoff(index int) time.Duration {
|
||||
seconds := math.Pow(2, float64(index))
|
||||
return time.Duration(seconds) * time.Second
|
||||
}
|
||||
|
||||
type ClientProfile struct {
|
||||
HttpProfile *HttpProfile
|
||||
// Valid choices: HmacSHA1, HmacSHA256, TC3-HMAC-SHA256.
|
||||
// Default value is TC3-HMAC-SHA256.
|
||||
SignMethod string
|
||||
UnsignedPayload bool
|
||||
// Valid choices: zh-CN, en-US.
|
||||
// Default value is zh-CN.
|
||||
Language string
|
||||
Debug bool
|
||||
// define Whether to enable Regional auto switch
|
||||
DisableRegionBreaker bool
|
||||
|
||||
// Deprecated. Use BackupEndpoint instead.
|
||||
BackupEndPoint string
|
||||
BackupEndpoint string
|
||||
|
||||
// define how to retry request
|
||||
NetworkFailureMaxRetries int
|
||||
NetworkFailureRetryDuration DurationFunc
|
||||
RateLimitExceededMaxRetries int
|
||||
RateLimitExceededRetryDuration DurationFunc
|
||||
}
|
||||
|
||||
func NewClientProfile() *ClientProfile {
|
||||
return &ClientProfile{
|
||||
HttpProfile: NewHttpProfile(),
|
||||
SignMethod: "TC3-HMAC-SHA256",
|
||||
UnsignedPayload: false,
|
||||
Language: "zh-CN",
|
||||
Debug: false,
|
||||
// now is true, will become to false in future
|
||||
DisableRegionBreaker: true,
|
||||
BackupEndPoint: "",
|
||||
BackupEndpoint: "",
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
package profile
|
||||
|
||||
type HttpProfile struct {
|
||||
ReqMethod string
|
||||
ReqTimeout int
|
||||
Scheme string
|
||||
RootDomain string
|
||||
Endpoint string
|
||||
// Deprecated, use Scheme instead
|
||||
Protocol string
|
||||
}
|
||||
|
||||
func NewHttpProfile() *HttpProfile {
|
||||
return &HttpProfile{
|
||||
ReqMethod: "POST",
|
||||
ReqTimeout: 60,
|
||||
Scheme: "HTTPS",
|
||||
RootDomain: "",
|
||||
Endpoint: "",
|
||||
}
|
||||
}
|
||||
Generated
Vendored
+96
@@ -0,0 +1,96 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
EnvCredentialFile = "TENCENTCLOUD_CREDENTIALS_FILE"
|
||||
)
|
||||
|
||||
type ProfileProvider struct {
|
||||
}
|
||||
|
||||
// DefaultProfileProvider return a default Profile provider
|
||||
// profile path :
|
||||
// 1. The value of the environment variable TENCENTCLOUD_CREDENTIALS_FILE
|
||||
// 2. linux: ~/.tencentcloud/credentials
|
||||
// windows: \c:\Users\NAME\.tencentcloud\credentials
|
||||
func DefaultProfileProvider() *ProfileProvider {
|
||||
return &ProfileProvider{}
|
||||
}
|
||||
|
||||
// getHomePath return home directory according to the system.
|
||||
// if the environmental variables does not exist, it will return empty string
|
||||
func getHomePath() string {
|
||||
// Windows
|
||||
if runtime.GOOS == "windows" {
|
||||
return os.Getenv("USERPROFILE")
|
||||
}
|
||||
// *nix
|
||||
return os.Getenv("HOME")
|
||||
}
|
||||
|
||||
func getCredentialsFilePath() string {
|
||||
homePath := getHomePath()
|
||||
if homePath == "" {
|
||||
return homePath
|
||||
}
|
||||
return filepath.Join(homePath, ".tencentcloud", "credentials")
|
||||
}
|
||||
|
||||
func checkDefaultFile() (path string, err error) {
|
||||
path = getCredentialsFilePath()
|
||||
if path == "" {
|
||||
return path, nil
|
||||
}
|
||||
_, err = os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return "", nil
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func (p *ProfileProvider) GetCredential() (CredentialIface, error) {
|
||||
path, ok := os.LookupEnv(EnvCredentialFile)
|
||||
// if not set custom file path, will use the default path
|
||||
if !ok {
|
||||
var err error
|
||||
path, err = checkDefaultFile()
|
||||
// only when the file exist but failed read it the err is not nil
|
||||
if err != nil {
|
||||
return nil, tcerr.NewTencentCloudSDKError(creErr, "Failed to find profile file,"+err.Error(), "")
|
||||
}
|
||||
// when the path is "" means the file dose not exist
|
||||
if path == "" {
|
||||
return nil, fileDoseNotExist
|
||||
}
|
||||
// if the EnvCredentialFile is set to "", will return an error
|
||||
} else if path == "" {
|
||||
return nil, tcerr.NewTencentCloudSDKError(creErr, "Environment variable '"+EnvCredentialFile+"' cannot be empty", "")
|
||||
}
|
||||
|
||||
cfg, err := parse(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sId := cfg.section("default").key("secret_id").string()
|
||||
sKey := cfg.section("default").key("secret_key").string()
|
||||
// if sId and sKey is "", but the credential file exist, means an error
|
||||
if sId == "" || sKey == "" {
|
||||
return nil, tcerr.NewTencentCloudSDKError(creErr, "Failed to parse profile file,please confirm whether it contains \"secret_id\" and \"secret_key\" in section: \"default\" ", "")
|
||||
}
|
||||
return &Credential{
|
||||
SecretId: sId,
|
||||
SecretKey: sKey,
|
||||
Token: "",
|
||||
}, nil
|
||||
}
|
||||
Generated
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
package common
|
||||
|
||||
import tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
|
||||
var (
|
||||
envNotSet = tcerr.NewTencentCloudSDKError(creErr, "could not find environmental variable", "")
|
||||
fileDoseNotExist = tcerr.NewTencentCloudSDKError(creErr, "could not find config file", "")
|
||||
noCvmRole = tcerr.NewTencentCloudSDKError(creErr, "get cvm role name failed, Please confirm whether the role is bound", "")
|
||||
)
|
||||
|
||||
// Provider provide credential to build client.
|
||||
//
|
||||
// Now there are four kinds provider:
|
||||
// EnvProvider : get credential from your Variable environment
|
||||
// ProfileProvider : get credential from your profile
|
||||
// CvmRoleProvider : get credential from your cvm role
|
||||
// RoleArnProvider : get credential from your role arn
|
||||
type Provider interface {
|
||||
// GetCredential get the credential interface
|
||||
GetCredential() (CredentialIface, error)
|
||||
}
|
||||
Generated
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
)
|
||||
|
||||
type ProviderChain struct {
|
||||
Providers []Provider
|
||||
}
|
||||
|
||||
// NewProviderChain returns a provider chain in your custom order
|
||||
func NewProviderChain(providers []Provider) Provider {
|
||||
return &ProviderChain{
|
||||
Providers: providers,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultProviderChain returns a default provider chain and try to get credentials in the following order:
|
||||
// 1. Environment variable
|
||||
// 2. Profile
|
||||
// 3. CvmRole
|
||||
// If you want to customize the search order, please use the function NewProviderChain
|
||||
func DefaultProviderChain() Provider {
|
||||
return NewProviderChain([]Provider{DefaultEnvProvider(), DefaultProfileProvider(), DefaultCvmRoleProvider()})
|
||||
}
|
||||
|
||||
func (c *ProviderChain) GetCredential() (CredentialIface, error) {
|
||||
for _, provider := range c.Providers {
|
||||
cred, err := provider.GetCredential()
|
||||
if err != nil {
|
||||
if err == envNotSet || err == fileDoseNotExist || err == noCvmRole {
|
||||
continue
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return cred, err
|
||||
}
|
||||
return nil, tcerr.NewTencentCloudSDKError(creErr, "no credential found in every providers", "")
|
||||
|
||||
}
|
||||
Generated
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
|
||||
)
|
||||
|
||||
const (
|
||||
codeLimitExceeded = "RequestLimitExceeded"
|
||||
tplRateLimitRetry = "[WARN] rate limit exceeded, retrying (%d/%d) in %f seconds: %s"
|
||||
)
|
||||
|
||||
func (c *Client) sendWithRateLimitRetry(req *http.Request, retryable bool) (resp *http.Response, err error) {
|
||||
// make sure maxRetries is more than 0
|
||||
maxRetries := maxInt(c.profile.RateLimitExceededMaxRetries, 0)
|
||||
durationFunc := safeDurationFunc(c.profile.RateLimitExceededRetryDuration)
|
||||
|
||||
var shadow []byte
|
||||
for idx := 0; idx <= maxRetries; idx++ {
|
||||
resp, err = c.sendWithNetworkFailureRetry(req, retryable)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
resp.Body, shadow = shadowRead(resp.Body)
|
||||
|
||||
err = tchttp.ParseErrorFromHTTPResponse(shadow)
|
||||
// should not sleep on last request
|
||||
if err, ok := err.(*errors.TencentCloudSDKError); ok && err.Code == codeLimitExceeded && idx < maxRetries {
|
||||
duration := durationFunc(idx)
|
||||
if c.debug {
|
||||
log.Printf(tplRateLimitRetry, idx, maxRetries, duration.Seconds(), err.Error())
|
||||
}
|
||||
|
||||
time.Sleep(duration)
|
||||
continue
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
return resp, err
|
||||
}
|
||||
|
||||
func shadowRead(reader io.ReadCloser) (io.ReadCloser, []byte) {
|
||||
val, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return reader, nil
|
||||
}
|
||||
return ioutil.NopCloser(bytes.NewBuffer(val)), val
|
||||
}
|
||||
Generated
Vendored
+62
@@ -0,0 +1,62 @@
|
||||
// Copyright (c) 2018 Tencent Ltd.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package regions
|
||||
|
||||
const (
|
||||
// 曼谷
|
||||
Bangkok = "ap-bangkok"
|
||||
// 北京
|
||||
Beijing = "ap-beijing"
|
||||
// 成都
|
||||
Chengdu = "ap-chengdu"
|
||||
// 重庆
|
||||
Chongqing = "ap-chongqing"
|
||||
// 广州
|
||||
Guangzhou = "ap-guangzhou"
|
||||
// 广州Open
|
||||
GuangzhouOpen = "ap-guangzhou-open"
|
||||
// 中国香港
|
||||
HongKong = "ap-hongkong"
|
||||
// 雅加达
|
||||
Jakarta = "ap-jakarta"
|
||||
// 孟买
|
||||
Mumbai = "ap-mumbai"
|
||||
// 首尔
|
||||
Seoul = "ap-seoul"
|
||||
// 上海
|
||||
Shanghai = "ap-shanghai"
|
||||
// 南京
|
||||
Nanjing = "ap-nanjing"
|
||||
// 上海金融
|
||||
ShanghaiFSI = "ap-shanghai-fsi"
|
||||
// 深圳金融
|
||||
ShenzhenFSI = "ap-shenzhen-fsi"
|
||||
// 新加坡
|
||||
Singapore = "ap-singapore"
|
||||
// 东京
|
||||
Tokyo = "ap-tokyo"
|
||||
// 法兰克福
|
||||
Frankfurt = "eu-frankfurt"
|
||||
// 莫斯科
|
||||
Moscow = "eu-moscow"
|
||||
// 阿什本
|
||||
Ashburn = "na-ashburn"
|
||||
// 硅谷
|
||||
SiliconValley = "na-siliconvalley"
|
||||
// 多伦多
|
||||
Toronto = "na-toronto"
|
||||
// 圣保罗
|
||||
SaoPaulo = "sa-saopaulo"
|
||||
)
|
||||
Generated
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RoleArnCredential struct {
|
||||
roleArn string
|
||||
roleSessionName string
|
||||
durationSeconds int64
|
||||
expiredTime int64
|
||||
token string
|
||||
tmpSecretId string
|
||||
tmpSecretKey string
|
||||
source *RoleArnProvider
|
||||
}
|
||||
|
||||
func (c *RoleArnCredential) GetSecretId() string {
|
||||
if c.needRefresh() {
|
||||
c.refresh()
|
||||
}
|
||||
return c.tmpSecretId
|
||||
}
|
||||
|
||||
func (c *RoleArnCredential) GetSecretKey() string {
|
||||
if c.needRefresh() {
|
||||
c.refresh()
|
||||
}
|
||||
return c.tmpSecretKey
|
||||
|
||||
}
|
||||
|
||||
func (c *RoleArnCredential) GetToken() string {
|
||||
if c.needRefresh() {
|
||||
c.refresh()
|
||||
}
|
||||
return c.token
|
||||
}
|
||||
|
||||
func (c *RoleArnCredential) needRefresh() bool {
|
||||
if c.tmpSecretKey == "" || c.tmpSecretId == "" || c.token == "" || c.expiredTime <= time.Now().Unix() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *RoleArnCredential) refresh() {
|
||||
newCre, err := c.source.GetCredential()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
*c = *newCre.(*RoleArnCredential)
|
||||
}
|
||||
Generated
Vendored
+105
@@ -0,0 +1,105 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
|
||||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/regions"
|
||||
)
|
||||
|
||||
const (
|
||||
endpoint = "sts.tencentcloudapi.com"
|
||||
service = "sts"
|
||||
version = "2018-08-13"
|
||||
region = regions.Guangzhou
|
||||
defaultSessionName = "tencentcloud-go-sdk-"
|
||||
action = "AssumeRole"
|
||||
defaultDurationSeconds = 7200
|
||||
)
|
||||
|
||||
type RoleArnProvider struct {
|
||||
longSecretId string
|
||||
longSecretKey string
|
||||
roleArn string
|
||||
roleSessionName string
|
||||
durationSeconds int64
|
||||
}
|
||||
|
||||
type stsRsp struct {
|
||||
Response struct {
|
||||
Credentials struct {
|
||||
Token string `json:"Token"`
|
||||
TmpSecretId string `json:"TmpSecretId"`
|
||||
TmpSecretKey string `json:"TmpSecretKey"`
|
||||
} `json:"Credentials"`
|
||||
ExpiredTime int `json:"ExpiredTime"`
|
||||
Expiration time.Time `json:"Expiration"`
|
||||
RequestId string `json:"RequestId"`
|
||||
} `json:"Response"`
|
||||
}
|
||||
|
||||
func NewRoleArnProvider(secretId, secretKey, roleArn, sessionName string, duration int64) *RoleArnProvider {
|
||||
return &RoleArnProvider{
|
||||
longSecretId: secretId,
|
||||
longSecretKey: secretKey,
|
||||
roleArn: roleArn,
|
||||
roleSessionName: sessionName,
|
||||
durationSeconds: duration,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultRoleArnProvider returns a RoleArnProvider that use some default options:
|
||||
// 1. roleSessionName will be "tencentcloud-go-sdk-" + timestamp
|
||||
// 2. durationSeconds will be 7200s
|
||||
func DefaultRoleArnProvider(secretId, secretKey, roleArn string) *RoleArnProvider {
|
||||
return NewRoleArnProvider(secretId, secretKey, roleArn, defaultSessionName+strconv.FormatInt(time.Now().UnixNano()/1000, 10), defaultDurationSeconds)
|
||||
}
|
||||
|
||||
func (r *RoleArnProvider) GetCredential() (CredentialIface, error) {
|
||||
if r.durationSeconds > 43200 || r.durationSeconds <= 0 {
|
||||
return nil, tcerr.NewTencentCloudSDKError(creErr, "Assume Role durationSeconds should be in the range of 0~43200s", "")
|
||||
}
|
||||
credential := NewCredential(r.longSecretId, r.longSecretKey)
|
||||
cpf := profile.NewClientProfile()
|
||||
cpf.HttpProfile.Endpoint = endpoint
|
||||
cpf.HttpProfile.ReqMethod = "POST"
|
||||
|
||||
client := NewCommonClient(credential, region, cpf)
|
||||
request := tchttp.NewCommonRequest(service, version, action)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"RoleArn": r.roleArn,
|
||||
"RoleSessionName": r.roleSessionName,
|
||||
"DurationSeconds": r.durationSeconds,
|
||||
}
|
||||
err := request.SetActionParameters(params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := tchttp.NewCommonResponse()
|
||||
err = client.Send(request, response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rspSt := new(stsRsp)
|
||||
|
||||
if err = json.Unmarshal(response.GetBody(), rspSt); err != nil {
|
||||
return nil, tcerr.NewTencentCloudSDKError(creErr, err.Error(), "")
|
||||
}
|
||||
|
||||
return &RoleArnCredential{
|
||||
roleArn: r.roleArn,
|
||||
roleSessionName: r.roleSessionName,
|
||||
durationSeconds: r.durationSeconds,
|
||||
expiredTime: int64(rspSt.Response.ExpiredTime) - r.durationSeconds/10*9, // credential's actual duration time is 1/10 of the original
|
||||
token: rspSt.Response.Credentials.Token,
|
||||
tmpSecretId: rspSt.Response.Credentials.TmpSecretId,
|
||||
tmpSecretKey: rspSt.Response.Credentials.TmpSecretKey,
|
||||
source: r,
|
||||
}, nil
|
||||
}
|
||||
Generated
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
package common
|
||||
|
||||
type sections struct {
|
||||
contains map[string]*section
|
||||
}
|
||||
|
||||
func (ss sections) section(name string) *section {
|
||||
s, ok := ss.contains[name]
|
||||
if !ok {
|
||||
s = new(section)
|
||||
ss.contains[name] = s
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type section struct {
|
||||
content map[string]*value
|
||||
}
|
||||
|
||||
func (s *section) key(name string) *value {
|
||||
v, ok := s.content[name]
|
||||
if !ok {
|
||||
v = new(value)
|
||||
s.content[name] = v
|
||||
}
|
||||
return v
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"sort"
|
||||
|
||||
tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http"
|
||||
)
|
||||
|
||||
const (
|
||||
SHA256 = "HmacSHA256"
|
||||
SHA1 = "HmacSHA1"
|
||||
)
|
||||
|
||||
func Sign(s, secretKey, method string) string {
|
||||
hashed := hmac.New(sha1.New, []byte(secretKey))
|
||||
if method == SHA256 {
|
||||
hashed = hmac.New(sha256.New, []byte(secretKey))
|
||||
}
|
||||
hashed.Write([]byte(s))
|
||||
|
||||
return base64.StdEncoding.EncodeToString(hashed.Sum(nil))
|
||||
}
|
||||
|
||||
func sha256hex(s string) string {
|
||||
b := sha256.Sum256([]byte(s))
|
||||
return hex.EncodeToString(b[:])
|
||||
}
|
||||
|
||||
func hmacsha256(s, key string) string {
|
||||
hashed := hmac.New(sha256.New, []byte(key))
|
||||
hashed.Write([]byte(s))
|
||||
return string(hashed.Sum(nil))
|
||||
}
|
||||
|
||||
func signRequest(request tchttp.Request, credential CredentialIface, method string) (err error) {
|
||||
if method != SHA256 {
|
||||
method = SHA1
|
||||
}
|
||||
checkAuthParams(request, credential, method)
|
||||
s := getStringToSign(request)
|
||||
signature := Sign(s, credential.GetSecretKey(), method)
|
||||
request.GetParams()["Signature"] = signature
|
||||
return
|
||||
}
|
||||
|
||||
func checkAuthParams(request tchttp.Request, credential CredentialIface, method string) {
|
||||
params := request.GetParams()
|
||||
params["SecretId"] = credential.GetSecretId()
|
||||
if token := credential.GetToken(); len(token) != 0 {
|
||||
params["Token"] = token
|
||||
}
|
||||
params["SignatureMethod"] = method
|
||||
delete(params, "Signature")
|
||||
}
|
||||
|
||||
func getStringToSign(request tchttp.Request) string {
|
||||
method := request.GetHttpMethod()
|
||||
domain := request.GetDomain()
|
||||
path := request.GetPath()
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(method)
|
||||
buf.WriteString(domain)
|
||||
buf.WriteString(path)
|
||||
buf.WriteString("?")
|
||||
|
||||
params := request.GetParams()
|
||||
// sort params
|
||||
keys := make([]string, 0, len(params))
|
||||
for k := range params {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for i := range keys {
|
||||
k := keys[i]
|
||||
buf.WriteString(k)
|
||||
buf.WriteString("=")
|
||||
buf.WriteString(params[k])
|
||||
buf.WriteString("&")
|
||||
}
|
||||
buf.Truncate(buf.Len() - 1)
|
||||
return buf.String()
|
||||
}
|
||||
Generated
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
# wrong section name
|
||||
[]
|
||||
invalidKey1 =
|
||||
;wrong section
|
||||
[default
|
||||
Generated
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
app=tencentcloud-sdk-go
|
||||
|
||||
# default
|
||||
[default]
|
||||
key1 = value1
|
||||
key2 = 2
|
||||
|
||||
;section 2
|
||||
[custom]
|
||||
customKey1 = 3.1415
|
||||
customKey2 = true
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
package common
|
||||
|
||||
func IntPtr(v int) *int {
|
||||
return &v
|
||||
}
|
||||
|
||||
func Int64Ptr(v int64) *int64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
func UintPtr(v uint) *uint {
|
||||
return &v
|
||||
}
|
||||
|
||||
func Uint64Ptr(v uint64) *uint64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
func Float64Ptr(v float64) *float64 {
|
||||
return &v
|
||||
}
|
||||
|
||||
func BoolPtr(v bool) *bool {
|
||||
return &v
|
||||
}
|
||||
|
||||
func StringPtr(v string) *string {
|
||||
return &v
|
||||
}
|
||||
|
||||
func StringValues(ptrs []*string) []string {
|
||||
values := make([]string, len(ptrs))
|
||||
for i := 0; i < len(ptrs); i++ {
|
||||
if ptrs[i] != nil {
|
||||
values[i] = *ptrs[i]
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func IntPtrs(vals []int) []*int {
|
||||
ptrs := make([]*int, len(vals))
|
||||
for i := 0; i < len(vals); i++ {
|
||||
ptrs[i] = &vals[i]
|
||||
}
|
||||
return ptrs
|
||||
}
|
||||
|
||||
func Int64Ptrs(vals []int64) []*int64 {
|
||||
ptrs := make([]*int64, len(vals))
|
||||
for i := 0; i < len(vals); i++ {
|
||||
ptrs[i] = &vals[i]
|
||||
}
|
||||
return ptrs
|
||||
}
|
||||
|
||||
func UintPtrs(vals []uint) []*uint {
|
||||
ptrs := make([]*uint, len(vals))
|
||||
for i := 0; i < len(vals); i++ {
|
||||
ptrs[i] = &vals[i]
|
||||
}
|
||||
return ptrs
|
||||
}
|
||||
|
||||
func Uint64Ptrs(vals []uint64) []*uint64 {
|
||||
ptrs := make([]*uint64, len(vals))
|
||||
for i := 0; i < len(vals); i++ {
|
||||
ptrs[i] = &vals[i]
|
||||
}
|
||||
return ptrs
|
||||
}
|
||||
|
||||
func Float64Ptrs(vals []float64) []*float64 {
|
||||
ptrs := make([]*float64, len(vals))
|
||||
for i := 0; i < len(vals); i++ {
|
||||
ptrs[i] = &vals[i]
|
||||
}
|
||||
return ptrs
|
||||
}
|
||||
|
||||
func BoolPtrs(vals []bool) []*bool {
|
||||
ptrs := make([]*bool, len(vals))
|
||||
for i := 0; i < len(vals); i++ {
|
||||
ptrs[i] = &vals[i]
|
||||
}
|
||||
return ptrs
|
||||
}
|
||||
|
||||
func StringPtrs(vals []string) []*string {
|
||||
ptrs := make([]*string, len(vals))
|
||||
for i := 0; i < len(vals); i++ {
|
||||
ptrs[i] = &vals[i]
|
||||
}
|
||||
return ptrs
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
tcerr "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors"
|
||||
)
|
||||
|
||||
type value struct {
|
||||
raw string
|
||||
}
|
||||
|
||||
func (v *value) int() (int, error) {
|
||||
i, e := strconv.Atoi(v.raw)
|
||||
if e != nil {
|
||||
msg := fmt.Sprintf("failed to parsing %s to int: %s", v.raw, e.Error())
|
||||
e = tcerr.NewTencentCloudSDKError(iniErr, msg, "")
|
||||
}
|
||||
return i, e
|
||||
}
|
||||
|
||||
func (v *value) int64() (int64, error) {
|
||||
i, e := strconv.ParseInt(v.raw, 10, 64)
|
||||
if e != nil {
|
||||
msg := fmt.Sprintf("failed to parsing %s to int64: %s", v.raw, e.Error())
|
||||
e = tcerr.NewTencentCloudSDKError(iniErr, msg, "")
|
||||
}
|
||||
return i, e
|
||||
}
|
||||
|
||||
func (v *value) string() string {
|
||||
return v.raw
|
||||
}
|
||||
|
||||
func (v *value) bool() (bool, error) {
|
||||
switch v.raw {
|
||||
case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "y", "ON", "on", "On":
|
||||
return true, nil
|
||||
case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "n", "OFF", "off", "Off":
|
||||
return false, nil
|
||||
}
|
||||
errorMsg := fmt.Sprintf("failed to parsing \"%s\" to Bool: invalid syntax", v.raw)
|
||||
return false, tcerr.NewTencentCloudSDKError(iniErr, errorMsg, "")
|
||||
}
|
||||
|
||||
func (v *value) float32() (float32, error) {
|
||||
f, e := strconv.ParseFloat(v.raw, 32)
|
||||
if e != nil {
|
||||
msg := fmt.Sprintf("failed to parse %s to Float32: %s", v.raw, e.Error())
|
||||
e = tcerr.NewTencentCloudSDKError(iniErr, msg, "")
|
||||
}
|
||||
return float32(f), e
|
||||
}
|
||||
func (v *value) float64() (float64, error) {
|
||||
f, e := strconv.ParseFloat(v.raw, 64)
|
||||
if e != nil {
|
||||
msg := fmt.Sprintf("failed to parse %s to Float64: %s", v.raw, e.Error())
|
||||
e = tcerr.NewTencentCloudSDKError(iniErr, msg, "")
|
||||
}
|
||||
|
||||
return f, e
|
||||
}
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (c) 2017-2018 Tencent Ltd.
|
||||
|
||||
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.
|
||||
Generated
Vendored
+5606
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+115
@@ -0,0 +1,115 @@
|
||||
// Copyright (c) 2017-2018 THL A29 Limited, a Tencent company. 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.
|
||||
|
||||
package v20181119
|
||||
|
||||
const (
|
||||
// 此产品的特有错误码
|
||||
|
||||
// 帐号已欠费。
|
||||
FAILEDOPERATION_ARREARSERROR = "FailedOperation.ArrearsError"
|
||||
|
||||
// 今日次数达到限制。
|
||||
FAILEDOPERATION_COUNTLIMITERROR = "FailedOperation.CountLimitError"
|
||||
|
||||
// 检测失败。
|
||||
FAILEDOPERATION_DETECTFAILED = "FailedOperation.DetectFailed"
|
||||
|
||||
// 文件下载失败。
|
||||
FAILEDOPERATION_DOWNLOADERROR = "FailedOperation.DownLoadError"
|
||||
|
||||
// 图片内容为空。
|
||||
FAILEDOPERATION_EMPTYIMAGEERROR = "FailedOperation.EmptyImageError"
|
||||
|
||||
// 引擎识别超时。
|
||||
FAILEDOPERATION_ENGINERECOGNIZETIMEOUT = "FailedOperation.EngineRecognizeTimeout"
|
||||
|
||||
// 身份证信息不合法(身份证号、姓名字段校验非法等)。
|
||||
FAILEDOPERATION_IDCARDINFOILLEGAL = "FailedOperation.IdCardInfoIllegal"
|
||||
|
||||
// 图片模糊。
|
||||
FAILEDOPERATION_IMAGEBLUR = "FailedOperation.ImageBlur"
|
||||
|
||||
// 图片解码失败。
|
||||
FAILEDOPERATION_IMAGEDECODEFAILED = "FailedOperation.ImageDecodeFailed"
|
||||
|
||||
// 照片未检测到名片。
|
||||
FAILEDOPERATION_IMAGENOBUSINESSCARD = "FailedOperation.ImageNoBusinessCard"
|
||||
|
||||
// 图片中未检测到身份证。
|
||||
FAILEDOPERATION_IMAGENOIDCARD = "FailedOperation.ImageNoIdCard"
|
||||
|
||||
// 图片中未检测到文本。
|
||||
FAILEDOPERATION_IMAGENOTEXT = "FailedOperation.ImageNoText"
|
||||
|
||||
// 图片尺寸过大,请参考输出参数中关于图片大小限制的说明。
|
||||
FAILEDOPERATION_IMAGESIZETOOLARGE = "FailedOperation.ImageSizeTooLarge"
|
||||
|
||||
// 发票数据不一致。
|
||||
FAILEDOPERATION_INVOICEMISMATCH = "FailedOperation.InvoiceMismatch"
|
||||
|
||||
// 输入的Language不支持。
|
||||
FAILEDOPERATION_LANGUAGENOTSUPPORT = "FailedOperation.LanguageNotSupport"
|
||||
|
||||
// 照片中存在多张卡。
|
||||
FAILEDOPERATION_MULTICARDERROR = "FailedOperation.MultiCardError"
|
||||
|
||||
// 非香港身份证。
|
||||
FAILEDOPERATION_NOHKIDCARD = "FailedOperation.NoHKIDCard"
|
||||
|
||||
// 非马来身份证。
|
||||
FAILEDOPERATION_NOMASIDCARD = "FailedOperation.NoMASIDCard"
|
||||
|
||||
// 非护照。
|
||||
FAILEDOPERATION_NOPASSPORT = "FailedOperation.NoPassport"
|
||||
|
||||
// OCR识别失败。
|
||||
FAILEDOPERATION_OCRFAILED = "FailedOperation.OcrFailed"
|
||||
|
||||
// 查询无记录。
|
||||
FAILEDOPERATION_QUERYNORECORD = "FailedOperation.QueryNoRecord"
|
||||
|
||||
// 未知错误。
|
||||
FAILEDOPERATION_UNKNOWERROR = "FailedOperation.UnKnowError"
|
||||
|
||||
// 服务未开通。
|
||||
FAILEDOPERATION_UNOPENERROR = "FailedOperation.UnOpenError"
|
||||
|
||||
// 内部错误。
|
||||
INTERNALERROR = "InternalError"
|
||||
|
||||
// Config不是有效的JSON格式。
|
||||
INVALIDPARAMETER_CONFIGFORMATERROR = "InvalidParameter.ConfigFormatError"
|
||||
|
||||
// 图片解码失败。
|
||||
INVALIDPARAMETER_ENGINEIMAGEDECODEFAILED = "InvalidParameter.EngineImageDecodeFailed"
|
||||
|
||||
// 无效的GTIN。
|
||||
INVALIDPARAMETER_INVALIDGTINERROR = "InvalidParameter.InvalidGTINError"
|
||||
|
||||
// 参数值错误。
|
||||
INVALIDPARAMETERVALUE_INVALIDPARAMETERVALUELIMIT = "InvalidParameterValue.InvalidParameterValueLimit"
|
||||
|
||||
// 文件内容太大。
|
||||
LIMITEXCEEDED_TOOLARGEFILEERROR = "LimitExceeded.TooLargeFileError"
|
||||
|
||||
// 发票不存在。
|
||||
RESOURCENOTFOUND_NOINVOICE = "ResourceNotFound.NoInvoice"
|
||||
|
||||
// 不支持当天发票查询。
|
||||
RESOURCENOTFOUND_NOTSUPPORTCURRENTINVOICEQUERY = "ResourceNotFound.NotSupportCurrentInvoiceQuery"
|
||||
|
||||
// 计费状态异常。
|
||||
RESOURCESSOLDOUT_CHARGESTATUSEXCEPTION = "ResourcesSoldOut.ChargeStatusException"
|
||||
)
|
||||
Generated
Vendored
+6850
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user