Skip to content

Commit f5e4153

Browse files
committed
release 0.0.5-beta source code for go
1 parent cbd3c5a commit f5e4153

File tree

15 files changed

+473
-198
lines changed

15 files changed

+473
-198
lines changed

CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
# 0.0.4-beta # 0.0.4-beta 2023-02-20
1+
# 0.0.5-beta 2023-04-14
2+
3+
### G42Cloud SDK Core
4+
5+
- _Features_
6+
- None
7+
- _Bug Fix_
8+
- None
9+
- _Change_
10+
- Optimize the code structure.
11+
12+
# 0.0.4-beta 2023-02-20
213

314
### G42Cloud SDK CBR
415

core/auth/signer/derived_signer.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package signer
2222
import (
2323
"crypto/sha256"
2424
"encoding/hex"
25+
"errors"
2526
"fmt"
2627
"github.com/g42cloud-sdk/g42cloud-sdk-go/core/request"
2728
"golang.org/x/crypto/hkdf"
@@ -62,8 +63,17 @@ func StringToSignDerived(canonicalRequest string, info string, t time.Time) (str
6263

6364
// SignDerived SignRequest set Authorization header
6465
func SignDerived(r *request.DefaultHttpRequest, ak string, sk string, derivedAuthServiceName string, regionId string) (map[string]string, error) {
65-
if derivedAuthServiceName == "" || regionId == "" {
66-
panic("DerivedAuthServiceName and RegionId in credential is required when using derived auth")
66+
if ak == "" {
67+
return nil, errors.New("AK is required in credentials")
68+
}
69+
if sk == "" {
70+
return nil, errors.New("SK is required in credentials")
71+
}
72+
if derivedAuthServiceName == "" {
73+
return nil, errors.New("DerivedAuthServiceName is required in credentials when using derived auth")
74+
}
75+
if regionId == "" {
76+
return nil, errors.New("RegionId is required in credentials when using derived auth")
6777
}
6878

6979
var err error

core/auth/signer/signer.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package signer
88
import (
99
"crypto/hmac"
1010
"crypto/sha256"
11+
"errors"
1112
"fmt"
1213
"net/url"
1314
"reflect"
@@ -213,6 +214,13 @@ func AuthHeaderValue(signature, accessKey string, signedHeaders []string) string
213214

214215
// SignRequest set Authorization header
215216
func Sign(r *request.DefaultHttpRequest, ak string, sk string) (map[string]string, error) {
217+
if ak == "" {
218+
return nil, errors.New("ak is required in credentials")
219+
}
220+
if sk == "" {
221+
return nil, errors.New("sk is required in credentials")
222+
}
223+
216224
var err error
217225
var t time.Time
218226
var headerParams = make(map[string]string)

core/converter/converters.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ func ConvertInterfaceToString(value interface{}) string {
6161
return strconv.FormatInt(value.(int64), 10)
6262
case uint64:
6363
return strconv.FormatUint(value.(uint64), 10)
64+
case bool:
65+
return strconv.FormatBool(value.(bool))
6466
case string:
6567
return value.(string)
6668
case []byte:

core/hc_http_client.go

Lines changed: 66 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,32 +34,37 @@ import (
3434
"github.com/g42cloud-sdk/g42cloud-sdk-go/core/response"
3535
"github.com/g42cloud-sdk/g42cloud-sdk-go/core/sdkerr"
3636
jsoniter "github.com/json-iterator/go"
37+
"go.mongodb.org/mongo-driver/bson"
3738
"io/ioutil"
39+
"net"
3840
"net/url"
3941
"reflect"
4042
"strings"
43+
"sync/atomic"
4144
)
4245

4346
const (
44-
userAgent = "User-Agent"
45-
xRequestId = "X-Request-Id"
46-
contentType = "Content-Type"
47-
applicationXml = "application/xml"
47+
userAgent = "User-Agent"
48+
xRequestId = "X-Request-Id"
49+
contentType = "Content-Type"
50+
applicationXml = "application/xml"
51+
applicationBson = "application/bson"
4852
)
4953

5054
type HcHttpClient struct {
51-
endpoint string
52-
credential auth.ICredential
53-
extraHeader map[string]string
54-
httpClient *impl.DefaultHttpClient
55+
endpoints []string
56+
endpointIndex int32
57+
credential auth.ICredential
58+
extraHeader map[string]string
59+
httpClient *impl.DefaultHttpClient
5560
}
5661

5762
func NewHcHttpClient(httpClient *impl.DefaultHttpClient) *HcHttpClient {
5863
return &HcHttpClient{httpClient: httpClient}
5964
}
6065

61-
func (hc *HcHttpClient) WithEndpoint(endpoint string) *HcHttpClient {
62-
hc.endpoint = endpoint
66+
func (hc *HcHttpClient) WithEndpoints(endpoints []string) *HcHttpClient {
67+
hc.endpoints = endpoints
6368
return hc
6469
}
6570

@@ -87,14 +92,23 @@ func (hc *HcHttpClient) Sync(req interface{}, reqDef *def.HttpRequestDef) (inter
8792

8893
func (hc *HcHttpClient) SyncInvoke(req interface{}, reqDef *def.HttpRequestDef,
8994
exchange *exchange.SdkExchange) (interface{}, error) {
90-
httpRequest, err := hc.buildRequest(req, reqDef)
91-
if err != nil {
92-
return nil, err
93-
}
95+
var resp *response.DefaultHttpResponse
96+
for {
97+
httpRequest, err := hc.buildRequest(req, reqDef)
98+
if err != nil {
99+
return nil, err
100+
}
94101

95-
resp, err := hc.httpClient.SyncInvokeHttpWithExchange(httpRequest, exchange)
96-
if err != nil {
97-
return nil, err
102+
resp, err = hc.httpClient.SyncInvokeHttpWithExchange(httpRequest, exchange)
103+
if err == nil {
104+
break
105+
}
106+
107+
if isNoSuchHostErr(err) && atomic.LoadInt32(&hc.endpointIndex) < int32(len(hc.endpoints)-1) {
108+
atomic.AddInt32(&hc.endpointIndex, 1)
109+
} else {
110+
return nil, err
111+
}
98112
}
99113

100114
return hc.extractResponse(resp, reqDef)
@@ -104,7 +118,7 @@ func (hc *HcHttpClient) extractEndpoint(req interface{}, reqDef *def.HttpRequest
104118
var endpoint string
105119
for _, v := range reqDef.RequestFields {
106120
if v.LocationType == def.Cname {
107-
u, err := url.Parse(hc.endpoint)
121+
u, err := url.Parse(hc.endpoints[atomic.LoadInt32(&hc.endpointIndex)])
108122
if err != nil {
109123
return "", err
110124
}
@@ -117,7 +131,7 @@ func (hc *HcHttpClient) extractEndpoint(req interface{}, reqDef *def.HttpRequest
117131
}
118132

119133
if endpoint == "" {
120-
endpoint = hc.endpoint
134+
endpoint = hc.endpoints[hc.endpointIndex]
121135
}
122136

123137
return endpoint, nil
@@ -342,14 +356,16 @@ func (hc *HcHttpClient) deserializeResponseFields(resp *response.DefaultHttpResp
342356

343357
bodyErr := hc.deserializeResponseBody(reqDef, data)
344358
if bodyErr != nil {
345-
return processError(err)
359+
return processError(bodyErr)
346360
}
347361
}
348362
}
349363

350364
if len(data) != 0 && !hasBody {
351365
if strings.Contains(resp.Response.Header.Get(contentType), applicationXml) {
352366
err = xml.Unmarshal(data, &reqDef.Response)
367+
} else if strings.Contains(resp.Response.Header.Get(contentType), applicationBson) {
368+
err = bson.Unmarshal(data, reqDef.Response)
353369
} else {
354370
err = jsoniter.Unmarshal(data, &reqDef.Response)
355371
}
@@ -387,8 +403,12 @@ func (hc *HcHttpClient) deserializeResponseBody(reqDef *def.HttpRequestDef, data
387403
} else {
388404
bodyIns = reflect.New(body.Type).Interface()
389405
}
390-
391-
err := json.Unmarshal(data, bodyIns)
406+
var err error
407+
if reqDef.ContentType == applicationBson {
408+
err = bson.Unmarshal(data, bodyIns)
409+
} else {
410+
err = json.Unmarshal(data, bodyIns)
411+
}
392412
if err != nil {
393413
return err
394414
}
@@ -451,3 +471,27 @@ func (hc *HcHttpClient) getFieldInfo(reqDef *def.HttpRequestDef, item *def.Field
451471

452472
return isPtr, fieldKind
453473
}
474+
475+
func isNoSuchHostErr(err error) bool {
476+
if err == nil {
477+
return false
478+
}
479+
var errInterface interface{} = err
480+
if innerErr, ok := errInterface.(*url.Error); !ok {
481+
return false
482+
} else {
483+
errInterface = innerErr.Err
484+
}
485+
486+
if innerErr, ok := errInterface.(*net.OpError); !ok {
487+
return false
488+
} else {
489+
errInterface = innerErr.Err
490+
}
491+
492+
if innerErr, ok := errInterface.(*net.DNSError); !ok {
493+
return false
494+
} else {
495+
return innerErr.Err == "no such host"
496+
}
497+
}

core/hc_http_client_builder.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ type HcHttpClientBuilder struct {
3434
CredentialsType []string
3535
derivedAuthServiceName string
3636
credentials auth.ICredential
37-
endpoint string
37+
endpoints []string
3838
httpConfig *config.HttpConfig
3939
region *region.Region
4040
}
@@ -56,8 +56,13 @@ func (builder *HcHttpClientBuilder) WithDerivedAuthServiceName(derivedAuthServic
5656
return builder
5757
}
5858

59+
// Deprecated: As of 0.1.27, because of the support of the multi-endpoint feature, use WithEndpoints instead
5960
func (builder *HcHttpClientBuilder) WithEndpoint(endpoint string) *HcHttpClientBuilder {
60-
builder.endpoint = endpoint
61+
return builder.WithEndpoints([]string{endpoint})
62+
}
63+
64+
func (builder *HcHttpClientBuilder) WithEndpoints(endpoints []string) *HcHttpClientBuilder {
65+
builder.endpoints = endpoints
6166
return builder
6267
}
6368

@@ -109,18 +114,20 @@ func (builder *HcHttpClientBuilder) Build() *HcHttpClient {
109114
}
110115

111116
if builder.region != nil {
112-
builder.endpoint = builder.region.Endpoint
117+
builder.endpoints = builder.region.Endpoints
113118
builder.credentials.ProcessAuthParams(defaultHttpClient, builder.region.Id)
114119

115120
if credential, ok := builder.credentials.(auth.IDerivedCredential); ok {
116121
credential.ProcessDerivedAuthParams(builder.derivedAuthServiceName, builder.region.Id)
117122
}
118123
}
119124

120-
if !strings.HasPrefix(builder.endpoint, "http") {
121-
builder.endpoint = "https://" + builder.endpoint
125+
for index, endpoint := range builder.endpoints {
126+
if !strings.HasPrefix(endpoint, "http") {
127+
builder.endpoints[index] = "https://" + endpoint
128+
}
122129
}
123130

124-
hcHttpClient := NewHcHttpClient(defaultHttpClient).WithEndpoint(builder.endpoint).WithCredential(builder.credentials)
131+
hcHttpClient := NewHcHttpClient(defaultHttpClient).WithEndpoints(builder.endpoints).WithCredential(builder.credentials)
125132
return hcHttpClient
126133
}

core/hc_http_client_builder_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,16 @@ func TestHcHttpClientBuilder_Build(t *testing.T) {
3030
err := recover()
3131
assert.NotNil(t, err)
3232
}()
33+
endpoints := []string{"endpoint"}
3334
err := os.Setenv("G42CLOUD_SDK_CREDENTIALS_FILE", "/cred")
3435
assert.Nil(t, err)
35-
client := NewHcHttpClientBuilder().WithEndpoint("endpoint").Build()
36+
client := NewHcHttpClientBuilder().WithEndpoints(endpoints).Build()
3637
assert.Nil(t, client.credential)
3738

3839
err = os.Setenv("G42CLOUD_SDK_AK", "ak")
3940
assert.Nil(t, err)
4041
err = os.Setenv("G42CLOUD_SDK_SK", "sk")
4142
assert.Nil(t, err)
42-
client = NewHcHttpClientBuilder().WithEndpoint("endpoint").Build()
43+
client = NewHcHttpClientBuilder().WithEndpoints(endpoints).Build()
4344
assert.NotNil(t, client.credential)
4445
}

core/region/region.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,23 @@
2020
package region
2121

2222
type Region struct {
23-
Id string
24-
Endpoint string
23+
Id string
24+
Endpoints []string
2525
}
2626

27-
func NewRegion(id string, endpoint string) *Region {
27+
func NewRegion(id string, endpoints ...string) *Region {
2828
return &Region{
29-
Id: id,
30-
Endpoint: endpoint,
29+
Id: id,
30+
Endpoints: endpoints,
3131
}
3232
}
3333

34+
// Deprecated: As of 0.1.27, because of the support of the multi-endpoint feature, use WithEndpointsOverride instead
3435
func (r *Region) WithEndpointOverride(endpoint string) *Region {
35-
r.Endpoint = endpoint
36+
return r.WithEndpointsOverride([]string{endpoint})
37+
}
38+
39+
func (r *Region) WithEndpointsOverride(endpoints []string) *Region {
40+
r.Endpoints = endpoints
3641
return r
3742
}

core/region/region_test.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@ var endpoint = fmt.Sprintf("https://%s.%s.myg42cloud.com", strings.ToLower(servi
3636
func TestNewRegion(t *testing.T) {
3737
reg := NewRegion(regionId, endpoint)
3838
assert.Equal(t, &Region{
39-
Id: regionId,
40-
Endpoint: endpoint,
39+
Id: regionId,
40+
Endpoints: []string{endpoint},
4141
}, reg)
4242
}
4343

44-
func TestRegion_WithEndpointOverride(t *testing.T) {
44+
func TestRegion_WithEndpointsOverride(t *testing.T) {
45+
testEndpoints := []string{"test"}
4546
reg := NewRegion(regionId, endpoint)
46-
assert.Equal(t, endpoint, reg.Endpoint)
47-
reg.WithEndpointOverride("test")
48-
assert.Equal(t, "test", reg.Endpoint)
47+
assert.Equal(t, endpoint, reg.Endpoints[0])
48+
reg.WithEndpointsOverride(testEndpoints)
49+
assert.Equal(t, testEndpoints, reg.Endpoints)
4950
}

core/request/default_http_request.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"errors"
2828
"fmt"
2929
"github.com/g42cloud-sdk/g42cloud-sdk-go/core/converter"
30+
"go.mongodb.org/mongo-driver/bson"
3031
"io"
3132
"mime/multipart"
3233
"net/http"
@@ -114,12 +115,17 @@ func (httpRequest *DefaultHttpRequest) GetBodyToBytes() (*bytes.Buffer, error) {
114115
if httpRequest.headerParams["Content-Type"] == "application/xml" {
115116
encoder := xml.NewEncoder(buf)
116117
err = encoder.Encode(httpRequest.body)
118+
} else if httpRequest.headerParams["Content-Type"] == "application/bson" {
119+
buffer, err := bson.Marshal(httpRequest.body)
120+
if err != nil {
121+
return nil, err
122+
}
123+
buf.Write(buffer)
117124
} else {
118125
encoder := json.NewEncoder(buf)
119126
encoder.SetEscapeHTML(false)
120127
err = encoder.Encode(httpRequest.body)
121128
}
122-
123129
if err != nil {
124130
return nil, err
125131
}

0 commit comments

Comments
 (0)