Compare commits

..

1 Commits

Author SHA1 Message Date
realJackSun 6d4d84eb86 rewrite the Id in ConfigItem 2022-08-23 20:26:22 +08:00
108 changed files with 1735 additions and 6751 deletions

View File

@ -14,7 +14,7 @@ jobs:
strategy:
matrix:
config:
- go_version: 1.21
- go_version: 1.15
steps:
- name: Set up Go 1.x
@ -23,9 +23,16 @@ jobs:
go-version: ${{ matrix.config.go_version }}
id: go
- name: Get dependencies
run: |
go get -v -t -d ./...
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Install goimports
run: go get golang.org/x/tools/cmd/goimports
- name: Test
run: |
diff -u <(echo -n) <(gofmt -d -s .)

393
README.md
View File

@ -27,42 +27,38 @@ $ go get -u github.com/nacos-group/nacos-sdk-go/v2
* ClientConfig
```go
constant.ClientConfig {
TimeoutMs uint64 // timeout for requesting Nacos server, default value is 10000ms
NamespaceId string // the namespaceId of Nacos
Endpoint string // the endpoint for ACM. https://help.aliyun.com/document_detail/130146.html
RegionId string // the regionId for ACM & KMS
AccessKey string // the AccessKey for ACM & KMS
SecretKey string // the SecretKey for ACM & KMS
OpenKMS bool // it's to open KMS, default is false. https://help.aliyun.com/product/28933.html
// , to enable encrypt/decrypt, DataId should be start with "cipher-"
CacheDir string // the directory for persist nacos service info,default value is current path
UpdateThreadNum int // the number of goroutine for update nacos service info,default value is 20
NotLoadCacheAtStart bool // not to load persistent nacos service info in CacheDir at start time
UpdateCacheWhenEmpty bool // update cache when get empty service instance from server
Username string // the username for nacos auth
Password string // the password for nacos auth
LogDir string // the directory for log, default is current path
RotateTime string // the rotate time for log, eg: 30m, 1h, 24h, default is 24h
MaxAge int64 // the max age of a log file, default value is 3
LogLevel string // the level of log, it's must be debug,info,warn,error, default value is info
constant.ClientConfig{
TimeoutMs uint64 // timeout for requesting Nacos server, default value is 10000ms
NamespaceId string // the namespaceId of Nacos
Endpoint string // the endpoint for ACM. https://help.aliyun.com/document_detail/130146.html
RegionId string // the regionId for ACM & KMS
AccessKey string // the AccessKey for ACM & KMS
SecretKey string // the SecretKey for ACM & KMS
OpenKMS bool // it's to open KMS, default is false. https://help.aliyun.com/product/28933.html
// , to enable encrypt/decrypt, DataId should be start with "cipher-"
CacheDir string // the directory for persist nacos service info,default value is current path
UpdateThreadNum int // the number of goroutine for update nacos service info,default value is 20
NotLoadCacheAtStart bool // not to load persistent nacos service info in CacheDir at start time
UpdateCacheWhenEmpty bool // update cache when get empty service instance from server
Username string // the username for nacos auth
Password string // the password for nacos auth
LogDir string // the directory for log, default is current path
RotateTime string // the rotate time for log, eg: 30m, 1h, 24h, default is 24h
MaxAge int64 // the max age of a log file, default value is 3
LogLevel string // the level of log, it's must be debug,info,warn,error, default value is info
}
```
* ServerConfig
```go
constant.ServerConfig{
Scheme string // the nacos server scheme,defaut=http,this is not required in 2.0
ContextPath string // the nacos server contextpath,defaut=/nacos,this is not required in 2.0
IpAddr string // the nacos server address
Port uint64 // nacos server port
GrpcPort uint64 // nacos server grpc port, default=server port + 1000, this is not required
Scheme string // the nacos server scheme,defaut=http,this is not required in 2.0
ContextPath string // the nacos server contextpath,defaut=/nacos,this is not required in 2.0
IpAddr string // the nacos server address
Port uint64 // nacos server port
GrpcPort uint64 // nacos server grpc port, default=server port + 1000, this is not required
}
```
<b>NoteWe can config multiple ServerConfig,the client will rotate request the servers</b>
@ -70,83 +66,83 @@ constant.ServerConfig{
### Create client
```go
//create clientConfig
clientConfig := constant.ClientConfig{
NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468", //we can create multiple clients with different namespaceId to support multiple namespace.When namespace is public, fill in the blank string here.
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
CacheDir: "/tmp/nacos/cache",
LogLevel: "debug",
}
//Another way of create clientConfig
clientConfig := *constant.NewClientConfig(
constant.WithNamespaceId("e525eafa-f7d7-4029-83d9-008937f9d468"), //When namespace is public, fill in the blank string here.
constant.WithTimeoutMs(5000),
constant.WithNotLoadCacheAtStart(true),
constant.WithLogDir("/tmp/nacos/log"),
constant.WithCacheDir("/tmp/nacos/cache"),
constant.WithLogLevel("debug"),
)
//create clientConfig
clientConfig := constant.ClientConfig{
NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468", //we can create multiple clients with different namespaceId to support multiple namespace.When namespace is public, fill in the blank string here.
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
CacheDir: "/tmp/nacos/cache",
LogLevel: "debug",
}
//Another way of create clientConfig
clientConfig := *constant.NewClientConfig(
constant.WithNamespaceId("e525eafa-f7d7-4029-83d9-008937f9d468"), //When namespace is public, fill in the blank string here.
constant.WithTimeoutMs(5000),
constant.WithNotLoadCacheAtStart(true),
constant.WithLogDir("/tmp/nacos/log"),
constant.WithCacheDir("/tmp/nacos/cache"),
constant.WithLogLevel("debug"),
)
// At least one ServerConfig
serverConfigs := []constant.ServerConfig{
{
IpAddr: "console1.nacos.io",
ContextPath: "/nacos",
Port: 80,
Scheme: "http",
},
{
IpAddr: "console2.nacos.io",
ContextPath: "/nacos",
Port: 80,
Scheme: "http",
},
}
//Another way of create serverConfigs
serverConfigs := []constant.ServerConfig{
*constant.NewServerConfig(
"console1.nacos.io",
80,
constant.WithScheme("http"),
constant.WithContextPath("/nacos")
),
*constant.NewServerConfig(
"console2.nacos.io",
80,
constant.WithScheme("http"),
constant.WithContextPath("/nacos")
),
}
// At least one ServerConfig
serverConfigs := []constant.ServerConfig{
{
IpAddr: "console1.nacos.io",
ContextPath: "/nacos",
Port: 80,
Scheme: "http",
},
{
IpAddr: "console2.nacos.io",
ContextPath: "/nacos",
Port: 80,
Scheme: "http",
},
}
//Another way of create serverConfigs
serverConfigs := []constant.ServerConfig{
*constant.NewServerConfig(
"console1.nacos.io",
80,
constant.WithScheme("http"),
constant.WithContextPath("/nacos")
),
*constant.NewServerConfig(
"console2.nacos.io",
80,
constant.WithScheme("http"),
constant.WithContextPath("/nacos")
),
}
// Create naming client for service discovery
_, _ := clients.CreateNamingClient(map[string]interface{}{
"serverConfigs": serverConfigs,
"clientConfig": clientConfig,
})
// Create naming client for service discovery
_, _ := clients.CreateNamingClient(map[string]interface{}{
"serverConfigs": serverConfigs,
"clientConfig": clientConfig,
})
// Create config client for dynamic configuration
_, _ := clients.CreateConfigClient(map[string]interface{}{
"serverConfigs": serverConfigs,
"clientConfig": clientConfig,
})
// Create config client for dynamic configuration
_, _ := clients.CreateConfigClient(map[string]interface{}{
"serverConfigs": serverConfigs,
"clientConfig": clientConfig,
})
// Another way of create naming client for service discovery (recommend)
namingClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &clientConfig,
ServerConfigs: serverConfigs,
},
)
// Another way of create naming client for service discovery (recommend)
namingClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &clientConfig,
ServerConfigs: serverConfigs,
},
)
// Another way of create config client for dynamic configuration (recommend)
configClient, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &clientConfig,
ServerConfigs: serverConfigs,
},
)
// Another way of create config client for dynamic configuration (recommend)
configClient, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &clientConfig,
ServerConfigs: serverConfigs,
},
)
```
@ -155,25 +151,23 @@ constant.ServerConfig{
https://help.aliyun.com/document_detail/130146.html
```go
cc := constant.ClientConfig{
Endpoint: "acm.aliyun.com:8080",
NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468",
RegionId: "cn-shanghai",
AccessKey: "LTAI4G8KxxxxxxxxxxxxxbwZLBr",
SecretKey: "n5jTL9YxxxxxxxxxxxxaxmPLZV9",
OpenKMS: true,
TimeoutMs: 5000,
LogLevel: "debug",
}
// a more graceful way to create config client
client, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
},
)
Endpoint: "acm.aliyun.com:8080",
NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468",
RegionId: "cn-shanghai",
AccessKey: "LTAI4G8KxxxxxxxxxxxxxbwZLBr",
SecretKey: "n5jTL9YxxxxxxxxxxxxaxmPLZV9",
OpenKMS: true,
TimeoutMs: 5000,
LogLevel: "debug",
}
// a more graceful way to create config client
client, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
},
)
```
### Service Discovery
@ -183,17 +177,17 @@ cc := constant.ClientConfig{
```go
success, err := namingClient.RegisterInstance(vo.RegisterInstanceParam{
Ip: "10.0.0.11",
Port: 8848,
ServiceName: "demo.go",
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
Metadata: map[string]string{"idc":"shanghai"},
ClusterName: "cluster-a", // default value is DEFAULT
GroupName: "group-a", // default value is DEFAULT_GROUP
})
Ip: "10.0.0.11",
Port: 8848,
ServiceName: "demo.go",
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
Metadata: map[string]string{"idc":"shanghai"},
ClusterName: "cluster-a", // default value is DEFAULT
GroupName: "group-a", // default value is DEFAULT_GROUP
})
```
@ -202,13 +196,13 @@ success, err := namingClient.RegisterInstance(vo.RegisterInstanceParam{
```go
success, err := namingClient.DeregisterInstance(vo.DeregisterInstanceParam{
Ip: "10.0.0.11",
Port: 8848,
ServiceName: "demo.go",
Ephemeral: true,
Cluster: "cluster-a", // default value is DEFAULT
GroupName: "group-a", // default value is DEFAULT_GROUP
})
Ip: "10.0.0.11",
Port: 8848,
ServiceName: "demo.go",
Ephemeral: true,
Cluster: "cluster-a", // default value is DEFAULT
GroupName: "group-a", // default value is DEFAULT_GROUP
})
```
@ -217,37 +211,35 @@ success, err := namingClient.DeregisterInstance(vo.DeregisterInstanceParam{
```go
services, err := namingClient.GetService(vo.GetServiceParam{
ServiceName: "demo.go",
Clusters: []string{"cluster-a"}, // default value is DEFAULT
GroupName: "group-a", // default value is DEFAULT_GROUP
})
ServiceName: "demo.go",
Clusters: []string{"cluster-a"}, // default value is DEFAULT
GroupName: "group-a", // default value is DEFAULT_GROUP
})
```
* Get all instancesSelectAllInstances
```go
// SelectAllInstance return all instances,include healthy=false,enable=false,weight<=0
instances, err := namingClient.SelectAllInstances(vo.SelectAllInstancesParam{
ServiceName: "demo.go",
GroupName: "group-a", // default value is DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // default value is DEFAULT
})
instances, err := namingClient.SelectAllInstances(vo.SelectAllInstancesParam{
ServiceName: "demo.go",
GroupName: "group-a", // default value is DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // default value is DEFAULT
})
```
* Get instances SelectInstances
```go
// SelectInstances only return the instances of healthy=${HealthyOnly},enable=true and weight>0
instances, err := namingClient.SelectInstances(vo.SelectInstancesParam{
ServiceName: "demo.go",
GroupName: "group-a", // default value is DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // default value is DEFAULT
HealthyOnly: true,
})
instances, err := namingClient.SelectInstances(vo.SelectInstancesParam{
ServiceName: "demo.go",
GroupName: "group-a", // default value is DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // default value is DEFAULT
HealthyOnly: true,
})
```
@ -255,12 +247,12 @@ services, err := namingClient.GetService(vo.GetServiceParam{
```go
// SelectOneHealthyInstance return one instance by WRR strategy for load balance
// And the instance should be health=true,enable=true and weight>0
instance, err := namingClient.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
ServiceName: "demo.go",
GroupName: "group-a", // default value is DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // default value is DEFAULT
})
// And the instance should be health=true,enable=true and weight>0
instance, err := namingClient.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
ServiceName: "demo.go",
GroupName: "group-a", // default value is DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // default value is DEFAULT
})
```
@ -269,15 +261,15 @@ services, err := namingClient.GetService(vo.GetServiceParam{
```go
// Subscribe key = serviceName+groupName+cluster
// Note: We call add multiple SubscribeCallback with the same key.
err := namingClient.Subscribe(vo.SubscribeParam{
ServiceName: "demo.go",
GroupName: "group-a", // default value is DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // default value is DEFAULT
SubscribeCallback: func (services []model.Instance, err error) {
log.Printf("\n\n callback return services:%s \n\n", utils.ToJsonString(services))
},
})
// Note: We call add multiple SubscribeCallback with the same key.
err := namingClient.Subscribe(vo.SubscribeParam{
ServiceName: "demo.go",
GroupName: "group-a", // default value is DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // default value is DEFAULT
SubscribeCallback: func (services []model.Instance, err error) {
log.Printf("\n\n callback return services:%s \n\n", utils.ToJsonString(services))
},
})
```
@ -286,13 +278,13 @@ services, err := namingClient.GetService(vo.GetServiceParam{
```go
err := namingClient.Unsubscribe(vo.SubscribeParam{
ServiceName: "demo.go",
GroupName: "group-a", // default value is DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // default value is DEFAULT
SubscribeCallback: func (services []model.Instance, err error) {
log.Printf("\n\n callback return services:%s \n\n", utils.ToJsonString(services))
},
})
ServiceName: "demo.go",
GroupName: "group-a", // default value is DEFAULT_GROUP
Clusters: []string{"cluster-a"}, // default value is DEFAULT
SubscribeCallback: func (services []model.Instance, err error) {
log.Printf("\n\n callback return services:%s \n\n", utils.ToJsonString(services))
},
})
```
@ -301,10 +293,10 @@ err := namingClient.Unsubscribe(vo.SubscribeParam{
```go
serviceInfos, err := namingClient.GetAllServicesInfo(vo.GetAllServiceInfoParam{
NameSpace: "0e83cc81-9d8c-4bb8-a28a-ff703187543f",
PageNo: 1,
PageSize: 10,
}),
NameSpace: "0e83cc81-9d8c-4bb8-a28a-ff703187543f",
PageNo: 1,
PageSize: 10,
}),
```
@ -315,9 +307,9 @@ serviceInfos, err := namingClient.GetAllServicesInfo(vo.GetAllServiceInfoParam{
```go
success, err := configClient.PublishConfig(vo.ConfigParam{
DataId: "dataId",
Group: "group",
Content: "hello world!222222"})
DataId: "dataId",
Group: "group",
Content: "hello world!222222"})
```
@ -326,8 +318,8 @@ success, err := configClient.PublishConfig(vo.ConfigParam{
```go
success, err = configClient.DeleteConfig(vo.ConfigParam{
DataId: "dataId",
Group: "group"})
DataId: "dataId",
Group: "group"})
```
@ -336,9 +328,8 @@ success, err = configClient.DeleteConfig(vo.ConfigParam{
```go
content, err := configClient.GetConfig(vo.ConfigParam{
DataId: "dataId",
Group: "group"})
DataId: "dataId",
Group: "group"})
```
@ -347,12 +338,12 @@ content, err := configClient.GetConfig(vo.ConfigParam{
```go
err := configClient.ListenConfig(vo.ConfigParam{
DataId: "dataId",
Group: "group",
OnChange: func (namespace, group, dataId, data string) {
fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
},
})
DataId: "dataId",
Group: "group",
OnChange: func (namespace, group, dataId, data string) {
fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
},
})
```
@ -361,9 +352,9 @@ err := configClient.ListenConfig(vo.ConfigParam{
```go
err := configClient.CancelListenConfig(vo.ConfigParam{
DataId: "dataId",
Group: "group",
})
DataId: "dataId",
Group: "group",
})
```
@ -371,12 +362,12 @@ err := configClient.CancelListenConfig(vo.ConfigParam{
```go
configPage, err := configClient.SearchConfig(vo.SearchConfigParam{
Search: "blur",
DataId: "",
Group: "",
PageNo: 1,
PageSize: 10,
})
Search: "blur",
DataId: "",
Group: "",
PageNo: 1,
PageSize: 10,
})
```
## Example

View File

@ -63,7 +63,7 @@ constant.ServerConfig{
```go
// 创建clientConfig
clientConfig := constant.ClientConfig{
NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468", // 如果需要支持多namespace我们可以创建多个client,它们有不同的NamespaceId。当namespace是public时此处填空字符串。
NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468", // 如果需要支持多namespace我们可以场景多个client,它们有不同的NamespaceId。当namespace是public时此处填空字符串。
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
@ -103,13 +103,13 @@ serverConfigs := []constant.ServerConfig{
"console1.nacos.io",
80,
constant.WithScheme("http"),
constant.WithContextPath("/nacos"),
constant.WithContextPath("/nacos")
),
*constant.NewServerConfig(
"console2.nacos.io",
80,
constant.WithScheme("http"),
constant.WithContextPath("/nacos"),
constant.WithContextPath("/nacos")
),
}

View File

@ -1,233 +1,467 @@
//
// Copyright 1999-2020 Alibaba Group Holding 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.
/*
* Copyright 1999-2020 Alibaba Group Holding 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.
*/
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.7
// protoc v5.29.3
// source: api/proto/nacos_grpc_service.proto
// source: nacos_grpc_service.proto
package auto
package grpc
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
anypb "google.golang.org/protobuf/types/known/anypb"
reflect "reflect"
sync "sync"
unsafe "unsafe"
context "context"
fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto"
any "github.com/golang/protobuf/ptypes/any"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Metadata struct {
state protoimpl.MessageState `protogen:"open.v1"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
ClientIp string `protobuf:"bytes,8,opt,name=clientIp,proto3" json:"clientIp,omitempty"`
Headers map[string]string `protobuf:"bytes,7,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
ClientIp string `protobuf:"bytes,8,opt,name=clientIp,proto3" json:"clientIp,omitempty"`
Headers map[string]string `protobuf:"bytes,7,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (x *Metadata) Reset() {
*x = Metadata{}
mi := &file_api_proto_nacos_grpc_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Metadata) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Metadata) ProtoMessage() {}
func (x *Metadata) ProtoReflect() protoreflect.Message {
mi := &file_api_proto_nacos_grpc_service_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Metadata.ProtoReflect.Descriptor instead.
func (m *Metadata) Reset() { *m = Metadata{} }
func (m *Metadata) String() string { return proto.CompactTextString(m) }
func (*Metadata) ProtoMessage() {}
func (*Metadata) Descriptor() ([]byte, []int) {
return file_api_proto_nacos_grpc_service_proto_rawDescGZIP(), []int{0}
return fileDescriptor_f908b146bdb05ce9, []int{0}
}
func (x *Metadata) GetType() string {
if x != nil {
return x.Type
func (m *Metadata) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Metadata.Unmarshal(m, b)
}
func (m *Metadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Metadata.Marshal(b, m, deterministic)
}
func (m *Metadata) XXX_Merge(src proto.Message) {
xxx_messageInfo_Metadata.Merge(m, src)
}
func (m *Metadata) XXX_Size() int {
return xxx_messageInfo_Metadata.Size(m)
}
func (m *Metadata) XXX_DiscardUnknown() {
xxx_messageInfo_Metadata.DiscardUnknown(m)
}
var xxx_messageInfo_Metadata proto.InternalMessageInfo
func (m *Metadata) GetType() string {
if m != nil {
return m.Type
}
return ""
}
func (x *Metadata) GetClientIp() string {
if x != nil {
return x.ClientIp
func (m *Metadata) GetClientIp() string {
if m != nil {
return m.ClientIp
}
return ""
}
func (x *Metadata) GetHeaders() map[string]string {
if x != nil {
return x.Headers
func (m *Metadata) GetHeaders() map[string]string {
if m != nil {
return m.Headers
}
return nil
}
type Payload struct {
state protoimpl.MessageState `protogen:"open.v1"`
Metadata *Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"`
Body *anypb.Any `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
Metadata *Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"`
Body *any.Any `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (x *Payload) Reset() {
*x = Payload{}
mi := &file_api_proto_nacos_grpc_service_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *Payload) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Payload) ProtoMessage() {}
func (x *Payload) ProtoReflect() protoreflect.Message {
mi := &file_api_proto_nacos_grpc_service_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Payload.ProtoReflect.Descriptor instead.
func (m *Payload) Reset() { *m = Payload{} }
func (m *Payload) String() string { return proto.CompactTextString(m) }
func (*Payload) ProtoMessage() {}
func (*Payload) Descriptor() ([]byte, []int) {
return file_api_proto_nacos_grpc_service_proto_rawDescGZIP(), []int{1}
return fileDescriptor_f908b146bdb05ce9, []int{1}
}
func (x *Payload) GetMetadata() *Metadata {
if x != nil {
return x.Metadata
func (m *Payload) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Payload.Unmarshal(m, b)
}
func (m *Payload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Payload.Marshal(b, m, deterministic)
}
func (m *Payload) XXX_Merge(src proto.Message) {
xxx_messageInfo_Payload.Merge(m, src)
}
func (m *Payload) XXX_Size() int {
return xxx_messageInfo_Payload.Size(m)
}
func (m *Payload) XXX_DiscardUnknown() {
xxx_messageInfo_Payload.DiscardUnknown(m)
}
var xxx_messageInfo_Payload proto.InternalMessageInfo
func (m *Payload) GetMetadata() *Metadata {
if m != nil {
return m.Metadata
}
return nil
}
func (x *Payload) GetBody() *anypb.Any {
if x != nil {
return x.Body
func (m *Payload) GetBody() *any.Any {
if m != nil {
return m.Body
}
return nil
}
var File_api_proto_nacos_grpc_service_proto protoreflect.FileDescriptor
const file_api_proto_nacos_grpc_service_proto_rawDesc = "" +
"\n" +
"\"api/proto/nacos_grpc_service.proto\x1a\x19google/protobuf/any.proto\"\xa8\x01\n" +
"\bMetadata\x12\x12\n" +
"\x04type\x18\x03 \x01(\tR\x04type\x12\x1a\n" +
"\bclientIp\x18\b \x01(\tR\bclientIp\x120\n" +
"\aheaders\x18\a \x03(\v2\x16.Metadata.HeadersEntryR\aheaders\x1a:\n" +
"\fHeadersEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"Z\n" +
"\aPayload\x12%\n" +
"\bmetadata\x18\x02 \x01(\v2\t.MetadataR\bmetadata\x12(\n" +
"\x04body\x18\x03 \x01(\v2\x14.google.protobuf.AnyR\x04body28\n" +
"\rRequestStream\x12'\n" +
"\rrequestStream\x12\b.Payload\x1a\b.Payload\"\x000\x012*\n" +
"\aRequest\x12\x1f\n" +
"\arequest\x12\b.Payload\x1a\b.Payload\"\x002>\n" +
"\x0fBiRequestStream\x12+\n" +
"\x0frequestBiStream\x12\b.Payload\x1a\b.Payload\"\x00(\x010\x01B^\n" +
"\x1fcom.alibaba.nacos.api.grpc.autoP\x01Z9github.com/nacos-group/nacos-sdk-go/v2/api/grpc/auto;autob\x06proto3"
var (
file_api_proto_nacos_grpc_service_proto_rawDescOnce sync.Once
file_api_proto_nacos_grpc_service_proto_rawDescData []byte
)
func file_api_proto_nacos_grpc_service_proto_rawDescGZIP() []byte {
file_api_proto_nacos_grpc_service_proto_rawDescOnce.Do(func() {
file_api_proto_nacos_grpc_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_api_proto_nacos_grpc_service_proto_rawDesc), len(file_api_proto_nacos_grpc_service_proto_rawDesc)))
})
return file_api_proto_nacos_grpc_service_proto_rawDescData
func init() {
proto.RegisterType((*Metadata)(nil), "Metadata")
proto.RegisterMapType((map[string]string)(nil), "Metadata.HeadersEntry")
proto.RegisterType((*Payload)(nil), "Payload")
}
var file_api_proto_nacos_grpc_service_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_api_proto_nacos_grpc_service_proto_goTypes = []any{
(*Metadata)(nil), // 0: Metadata
(*Payload)(nil), // 1: Payload
nil, // 2: Metadata.HeadersEntry
(*anypb.Any)(nil), // 3: google.protobuf.Any
}
var file_api_proto_nacos_grpc_service_proto_depIdxs = []int32{
2, // 0: Metadata.headers:type_name -> Metadata.HeadersEntry
0, // 1: Payload.metadata:type_name -> Metadata
3, // 2: Payload.body:type_name -> google.protobuf.Any
1, // 3: RequestStream.requestStream:input_type -> Payload
1, // 4: Request.request:input_type -> Payload
1, // 5: BiRequestStream.requestBiStream:input_type -> Payload
1, // 6: RequestStream.requestStream:output_type -> Payload
1, // 7: Request.request:output_type -> Payload
1, // 8: BiRequestStream.requestBiStream:output_type -> Payload
6, // [6:9] is the sub-list for method output_type
3, // [3:6] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
func init() { proto.RegisterFile("nacos_grpc_service.proto", fileDescriptor_f908b146bdb05ce9) }
var fileDescriptor_f908b146bdb05ce9 = []byte{
// 333 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0x4f, 0x4b, 0xeb, 0x40,
0x10, 0x7f, 0xdb, 0xf6, 0xbd, 0xa4, 0xd3, 0x57, 0x2a, 0x4b, 0x91, 0x98, 0x4b, 0x4b, 0x45, 0x0c,
0x0a, 0xdb, 0x12, 0x2f, 0xa5, 0x07, 0xc1, 0x82, 0xa0, 0x07, 0xa1, 0xc4, 0x9b, 0x97, 0x32, 0x49,
0xd6, 0x1a, 0x4c, 0xb3, 0x71, 0xb3, 0x29, 0xec, 0x37, 0xf2, 0x63, 0x4a, 0x37, 0x69, 0xb0, 0x20,
0xde, 0x66, 0x7e, 0x7f, 0xe6, 0xc7, 0xcc, 0x80, 0x93, 0x61, 0x24, 0x8a, 0xf5, 0x46, 0xe6, 0xd1,
0xba, 0xe0, 0x72, 0x97, 0x44, 0x9c, 0xe5, 0x52, 0x28, 0xe1, 0x9e, 0x6d, 0x84, 0xd8, 0xa4, 0x7c,
0x6a, 0xba, 0xb0, 0x7c, 0x9d, 0x62, 0xa6, 0x2b, 0x6a, 0xf2, 0x49, 0xc0, 0x7e, 0xe2, 0x0a, 0x63,
0x54, 0x48, 0x29, 0x74, 0x94, 0xce, 0xb9, 0xd3, 0x1e, 0x13, 0xaf, 0x1b, 0x98, 0x9a, 0xba, 0x60,
0x47, 0x69, 0xc2, 0x33, 0xf5, 0x98, 0x3b, 0xb6, 0xc1, 0x9b, 0x9e, 0xce, 0xc0, 0x7a, 0xe3, 0x18,
0x73, 0x59, 0x38, 0xd6, 0xb8, 0xed, 0xf5, 0xfc, 0x53, 0x76, 0x98, 0xc5, 0x1e, 0x2a, 0xe2, 0x3e,
0x53, 0x52, 0x07, 0x07, 0x99, 0xbb, 0x80, 0xff, 0xdf, 0x09, 0x7a, 0x02, 0xed, 0x77, 0xae, 0x1d,
0x62, 0x06, 0xef, 0x4b, 0x3a, 0x84, 0xbf, 0x3b, 0x4c, 0x4b, 0xee, 0xb4, 0x0c, 0x56, 0x35, 0x8b,
0xd6, 0x9c, 0x4c, 0x5e, 0xc0, 0x5a, 0xa1, 0x4e, 0x05, 0xc6, 0xf4, 0x02, 0xec, 0x6d, 0x1d, 0x64,
0x74, 0x3d, 0xbf, 0xdb, 0x24, 0x07, 0x0d, 0x45, 0x3d, 0xe8, 0x84, 0x22, 0xd6, 0x66, 0x9f, 0x9e,
0x3f, 0x64, 0xd5, 0x19, 0xd8, 0xe1, 0x0c, 0xec, 0x2e, 0xd3, 0x81, 0x51, 0xf8, 0x73, 0xe8, 0x07,
0xfc, 0xa3, 0xe4, 0x85, 0x7a, 0x56, 0x92, 0xe3, 0x96, 0x5e, 0x42, 0x5f, 0x1e, 0x01, 0x36, 0xab,
0xc3, 0xdd, 0xa6, 0x9a, 0xfc, 0x99, 0x11, 0xff, 0x0a, 0xac, 0xda, 0x49, 0x47, 0x60, 0xd5, 0x9e,
0x9f, 0xd5, 0xfe, 0x2d, 0x0c, 0x96, 0xc9, 0x71, 0xce, 0x35, 0x0c, 0x6a, 0xcf, 0x32, 0xf9, 0x2d,
0xc9, 0x23, 0x33, 0xb2, 0x3c, 0x87, 0x51, 0x24, 0xb6, 0x0c, 0xd3, 0x24, 0xc4, 0x10, 0x99, 0xf9,
0x37, 0xc3, 0x3c, 0x61, 0xfb, 0x9f, 0x33, 0x2c, 0x95, 0x58, 0x91, 0xf0, 0x9f, 0x59, 0xef, 0xe6,
0x2b, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x9e, 0xc7, 0x2d, 0x0f, 0x02, 0x00, 0x00,
}
func init() { file_api_proto_nacos_grpc_service_proto_init() }
func file_api_proto_nacos_grpc_service_proto_init() {
if File_api_proto_nacos_grpc_service_proto != nil {
return
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// RequestStreamClient is the client API for RequestStream service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type RequestStreamClient interface {
// build a streamRequest
RequestStream(ctx context.Context, in *Payload, opts ...grpc.CallOption) (RequestStream_RequestStreamClient, error)
}
type requestStreamClient struct {
cc *grpc.ClientConn
}
func NewRequestStreamClient(cc *grpc.ClientConn) RequestStreamClient {
return &requestStreamClient{cc}
}
func (c *requestStreamClient) RequestStream(ctx context.Context, in *Payload, opts ...grpc.CallOption) (RequestStream_RequestStreamClient, error) {
stream, err := c.cc.NewStream(ctx, &_RequestStream_serviceDesc.Streams[0], "/RequestStream/requestStream", opts...)
if err != nil {
return nil, err
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_proto_nacos_grpc_service_proto_rawDesc), len(file_api_proto_nacos_grpc_service_proto_rawDesc)),
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 3,
x := &requestStreamRequestStreamClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type RequestStream_RequestStreamClient interface {
Recv() (*Payload, error)
grpc.ClientStream
}
type requestStreamRequestStreamClient struct {
grpc.ClientStream
}
func (x *requestStreamRequestStreamClient) Recv() (*Payload, error) {
m := new(Payload)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// RequestStreamServer is the server API for RequestStream service.
type RequestStreamServer interface {
// build a streamRequest
RequestStream(*Payload, RequestStream_RequestStreamServer) error
}
// UnimplementedRequestStreamServer can be embedded to have forward compatible implementations.
type UnimplementedRequestStreamServer struct {
}
func (*UnimplementedRequestStreamServer) RequestStream(req *Payload, srv RequestStream_RequestStreamServer) error {
return status.Errorf(codes.Unimplemented, "method RequestStream not implemented")
}
func RegisterRequestStreamServer(s *grpc.Server, srv RequestStreamServer) {
s.RegisterService(&_RequestStream_serviceDesc, srv)
}
func _RequestStream_RequestStream_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(Payload)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(RequestStreamServer).RequestStream(m, &requestStreamRequestStreamServer{stream})
}
type RequestStream_RequestStreamServer interface {
Send(*Payload) error
grpc.ServerStream
}
type requestStreamRequestStreamServer struct {
grpc.ServerStream
}
func (x *requestStreamRequestStreamServer) Send(m *Payload) error {
return x.ServerStream.SendMsg(m)
}
var _RequestStream_serviceDesc = grpc.ServiceDesc{
ServiceName: "RequestStream",
HandlerType: (*RequestStreamServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "requestStream",
Handler: _RequestStream_RequestStream_Handler,
ServerStreams: true,
},
GoTypes: file_api_proto_nacos_grpc_service_proto_goTypes,
DependencyIndexes: file_api_proto_nacos_grpc_service_proto_depIdxs,
MessageInfos: file_api_proto_nacos_grpc_service_proto_msgTypes,
}.Build()
File_api_proto_nacos_grpc_service_proto = out.File
file_api_proto_nacos_grpc_service_proto_goTypes = nil
file_api_proto_nacos_grpc_service_proto_depIdxs = nil
},
Metadata: "nacos_grpc_service.proto",
}
// RequestClient is the client API for Request service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type RequestClient interface {
// Sends a commonRequest
Request(ctx context.Context, in *Payload, opts ...grpc.CallOption) (*Payload, error)
}
type requestClient struct {
cc *grpc.ClientConn
}
func NewRequestClient(cc *grpc.ClientConn) RequestClient {
return &requestClient{cc}
}
func (c *requestClient) Request(ctx context.Context, in *Payload, opts ...grpc.CallOption) (*Payload, error) {
out := new(Payload)
err := c.cc.Invoke(ctx, "/Request/request", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// RequestServer is the server API for Request service.
type RequestServer interface {
// Sends a commonRequest
Request(context.Context, *Payload) (*Payload, error)
}
// UnimplementedRequestServer can be embedded to have forward compatible implementations.
type UnimplementedRequestServer struct {
}
func (*UnimplementedRequestServer) Request(ctx context.Context, req *Payload) (*Payload, error) {
return nil, status.Errorf(codes.Unimplemented, "method Request not implemented")
}
func RegisterRequestServer(s *grpc.Server, srv RequestServer) {
s.RegisterService(&_Request_serviceDesc, srv)
}
func _Request_Request_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Payload)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RequestServer).Request(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/Request/Request",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RequestServer).Request(ctx, req.(*Payload))
}
return interceptor(ctx, in, info, handler)
}
var _Request_serviceDesc = grpc.ServiceDesc{
ServiceName: "Request",
HandlerType: (*RequestServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "request",
Handler: _Request_Request_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "nacos_grpc_service.proto",
}
// BiRequestStreamClient is the client API for BiRequestStream service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type BiRequestStreamClient interface {
// Sends a commonRequest
RequestBiStream(ctx context.Context, opts ...grpc.CallOption) (BiRequestStream_RequestBiStreamClient, error)
}
type biRequestStreamClient struct {
cc *grpc.ClientConn
}
func NewBiRequestStreamClient(cc *grpc.ClientConn) BiRequestStreamClient {
return &biRequestStreamClient{cc}
}
func (c *biRequestStreamClient) RequestBiStream(ctx context.Context, opts ...grpc.CallOption) (BiRequestStream_RequestBiStreamClient, error) {
stream, err := c.cc.NewStream(ctx, &_BiRequestStream_serviceDesc.Streams[0], "/BiRequestStream/requestBiStream", opts...)
if err != nil {
return nil, err
}
x := &biRequestStreamRequestBiStreamClient{stream}
return x, nil
}
type BiRequestStream_RequestBiStreamClient interface {
Send(*Payload) error
Recv() (*Payload, error)
grpc.ClientStream
}
type biRequestStreamRequestBiStreamClient struct {
grpc.ClientStream
}
func (x *biRequestStreamRequestBiStreamClient) Send(m *Payload) error {
return x.ClientStream.SendMsg(m)
}
func (x *biRequestStreamRequestBiStreamClient) Recv() (*Payload, error) {
m := new(Payload)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// BiRequestStreamServer is the server API for BiRequestStream service.
type BiRequestStreamServer interface {
// Sends a commonRequest
RequestBiStream(BiRequestStream_RequestBiStreamServer) error
}
// UnimplementedBiRequestStreamServer can be embedded to have forward compatible implementations.
type UnimplementedBiRequestStreamServer struct {
}
func (*UnimplementedBiRequestStreamServer) RequestBiStream(srv BiRequestStream_RequestBiStreamServer) error {
return status.Errorf(codes.Unimplemented, "method RequestBiStream not implemented")
}
func RegisterBiRequestStreamServer(s *grpc.Server, srv BiRequestStreamServer) {
s.RegisterService(&_BiRequestStream_serviceDesc, srv)
}
func _BiRequestStream_RequestBiStream_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(BiRequestStreamServer).RequestBiStream(&biRequestStreamRequestBiStreamServer{stream})
}
type BiRequestStream_RequestBiStreamServer interface {
Send(*Payload) error
Recv() (*Payload, error)
grpc.ServerStream
}
type biRequestStreamRequestBiStreamServer struct {
grpc.ServerStream
}
func (x *biRequestStreamRequestBiStreamServer) Send(m *Payload) error {
return x.ServerStream.SendMsg(m)
}
func (x *biRequestStreamRequestBiStreamServer) Recv() (*Payload, error) {
m := new(Payload)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
var _BiRequestStream_serviceDesc = grpc.ServiceDesc{
ServiceName: "BiRequestStream",
HandlerType: (*BiRequestStreamServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "requestBiStream",
Handler: _BiRequestStream_RequestBiStream_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "nacos_grpc_service.proto",
}

View File

@ -1,343 +0,0 @@
//
// Copyright 1999-2020 Alibaba Group Holding 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.
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.5.1
// - protoc v5.29.3
// source: api/proto/nacos_grpc_service.proto
package auto
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
RequestStream_RequestStream_FullMethodName = "/RequestStream/requestStream"
)
// RequestStreamClient is the client API for RequestStream service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type RequestStreamClient interface {
// build a streamRequest
RequestStream(ctx context.Context, in *Payload, opts ...grpc.CallOption) (grpc.ServerStreamingClient[Payload], error)
}
type requestStreamClient struct {
cc grpc.ClientConnInterface
}
func NewRequestStreamClient(cc grpc.ClientConnInterface) RequestStreamClient {
return &requestStreamClient{cc}
}
func (c *requestStreamClient) RequestStream(ctx context.Context, in *Payload, opts ...grpc.CallOption) (grpc.ServerStreamingClient[Payload], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &RequestStream_ServiceDesc.Streams[0], RequestStream_RequestStream_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[Payload, Payload]{ClientStream: stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type RequestStream_RequestStreamClient = grpc.ServerStreamingClient[Payload]
// RequestStreamServer is the server API for RequestStream service.
// All implementations must embed UnimplementedRequestStreamServer
// for forward compatibility.
type RequestStreamServer interface {
// build a streamRequest
RequestStream(*Payload, grpc.ServerStreamingServer[Payload]) error
mustEmbedUnimplementedRequestStreamServer()
}
// UnimplementedRequestStreamServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedRequestStreamServer struct{}
func (UnimplementedRequestStreamServer) RequestStream(*Payload, grpc.ServerStreamingServer[Payload]) error {
return status.Errorf(codes.Unimplemented, "method RequestStream not implemented")
}
func (UnimplementedRequestStreamServer) mustEmbedUnimplementedRequestStreamServer() {}
func (UnimplementedRequestStreamServer) testEmbeddedByValue() {}
// UnsafeRequestStreamServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to RequestStreamServer will
// result in compilation errors.
type UnsafeRequestStreamServer interface {
mustEmbedUnimplementedRequestStreamServer()
}
func RegisterRequestStreamServer(s grpc.ServiceRegistrar, srv RequestStreamServer) {
// If the following call pancis, it indicates UnimplementedRequestStreamServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&RequestStream_ServiceDesc, srv)
}
func _RequestStream_RequestStream_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(Payload)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(RequestStreamServer).RequestStream(m, &grpc.GenericServerStream[Payload, Payload]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type RequestStream_RequestStreamServer = grpc.ServerStreamingServer[Payload]
// RequestStream_ServiceDesc is the grpc.ServiceDesc for RequestStream service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var RequestStream_ServiceDesc = grpc.ServiceDesc{
ServiceName: "RequestStream",
HandlerType: (*RequestStreamServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "requestStream",
Handler: _RequestStream_RequestStream_Handler,
ServerStreams: true,
},
},
Metadata: "api/proto/nacos_grpc_service.proto",
}
const (
Request_Request_FullMethodName = "/Request/request"
)
// RequestClient is the client API for Request service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type RequestClient interface {
// Sends a commonRequest
Request(ctx context.Context, in *Payload, opts ...grpc.CallOption) (*Payload, error)
}
type requestClient struct {
cc grpc.ClientConnInterface
}
func NewRequestClient(cc grpc.ClientConnInterface) RequestClient {
return &requestClient{cc}
}
func (c *requestClient) Request(ctx context.Context, in *Payload, opts ...grpc.CallOption) (*Payload, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(Payload)
err := c.cc.Invoke(ctx, Request_Request_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// RequestServer is the server API for Request service.
// All implementations must embed UnimplementedRequestServer
// for forward compatibility.
type RequestServer interface {
// Sends a commonRequest
Request(context.Context, *Payload) (*Payload, error)
mustEmbedUnimplementedRequestServer()
}
// UnimplementedRequestServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedRequestServer struct{}
func (UnimplementedRequestServer) Request(context.Context, *Payload) (*Payload, error) {
return nil, status.Errorf(codes.Unimplemented, "method Request not implemented")
}
func (UnimplementedRequestServer) mustEmbedUnimplementedRequestServer() {}
func (UnimplementedRequestServer) testEmbeddedByValue() {}
// UnsafeRequestServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to RequestServer will
// result in compilation errors.
type UnsafeRequestServer interface {
mustEmbedUnimplementedRequestServer()
}
func RegisterRequestServer(s grpc.ServiceRegistrar, srv RequestServer) {
// If the following call pancis, it indicates UnimplementedRequestServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&Request_ServiceDesc, srv)
}
func _Request_Request_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Payload)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(RequestServer).Request(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: Request_Request_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(RequestServer).Request(ctx, req.(*Payload))
}
return interceptor(ctx, in, info, handler)
}
// Request_ServiceDesc is the grpc.ServiceDesc for Request service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Request_ServiceDesc = grpc.ServiceDesc{
ServiceName: "Request",
HandlerType: (*RequestServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "request",
Handler: _Request_Request_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "api/proto/nacos_grpc_service.proto",
}
const (
BiRequestStream_RequestBiStream_FullMethodName = "/BiRequestStream/requestBiStream"
)
// BiRequestStreamClient is the client API for BiRequestStream service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type BiRequestStreamClient interface {
// Sends a commonRequest
RequestBiStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[Payload, Payload], error)
}
type biRequestStreamClient struct {
cc grpc.ClientConnInterface
}
func NewBiRequestStreamClient(cc grpc.ClientConnInterface) BiRequestStreamClient {
return &biRequestStreamClient{cc}
}
func (c *biRequestStreamClient) RequestBiStream(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[Payload, Payload], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &BiRequestStream_ServiceDesc.Streams[0], BiRequestStream_RequestBiStream_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[Payload, Payload]{ClientStream: stream}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type BiRequestStream_RequestBiStreamClient = grpc.BidiStreamingClient[Payload, Payload]
// BiRequestStreamServer is the server API for BiRequestStream service.
// All implementations must embed UnimplementedBiRequestStreamServer
// for forward compatibility.
type BiRequestStreamServer interface {
// Sends a commonRequest
RequestBiStream(grpc.BidiStreamingServer[Payload, Payload]) error
mustEmbedUnimplementedBiRequestStreamServer()
}
// UnimplementedBiRequestStreamServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedBiRequestStreamServer struct{}
func (UnimplementedBiRequestStreamServer) RequestBiStream(grpc.BidiStreamingServer[Payload, Payload]) error {
return status.Errorf(codes.Unimplemented, "method RequestBiStream not implemented")
}
func (UnimplementedBiRequestStreamServer) mustEmbedUnimplementedBiRequestStreamServer() {}
func (UnimplementedBiRequestStreamServer) testEmbeddedByValue() {}
// UnsafeBiRequestStreamServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to BiRequestStreamServer will
// result in compilation errors.
type UnsafeBiRequestStreamServer interface {
mustEmbedUnimplementedBiRequestStreamServer()
}
func RegisterBiRequestStreamServer(s grpc.ServiceRegistrar, srv BiRequestStreamServer) {
// If the following call pancis, it indicates UnimplementedBiRequestStreamServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&BiRequestStream_ServiceDesc, srv)
}
func _BiRequestStream_RequestBiStream_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(BiRequestStreamServer).RequestBiStream(&grpc.GenericServerStream[Payload, Payload]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type BiRequestStream_RequestBiStreamServer = grpc.BidiStreamingServer[Payload, Payload]
// BiRequestStream_ServiceDesc is the grpc.ServiceDesc for BiRequestStream service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var BiRequestStream_ServiceDesc = grpc.ServiceDesc{
ServiceName: "BiRequestStream",
HandlerType: (*BiRequestStreamServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "requestBiStream",
Handler: _BiRequestStream_RequestBiStream_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "api/proto/nacos_grpc_service.proto",
}

View File

@ -21,8 +21,6 @@ import "google/protobuf/any.proto";
option java_multiple_files = true;
option java_package = "com.alibaba.nacos.api.grpc.auto";
option go_package = "github.com/nacos-group/nacos-sdk-go/v2/api/grpc/auto;auto";
message Metadata {
string type = 3;

View File

@ -296,7 +296,7 @@ func (m ConcurrentMap) Keys() []string {
return keys
}
// Reviles ConcurrentMap "private" variables to json marshal.
//Reviles ConcurrentMap "private" variables to json marshal.
func (m ConcurrentMap) MarshalJSON() ([]byte, error) {
// Create a temporary map, which will hold all item spread across shards.
tmp := make(map[string]interface{})

View File

@ -1,11 +0,0 @@
package cache
type ConfigCachedFileType string
const (
ConfigContent ConfigCachedFileType = "Config Content"
ConfigEncryptedDataKey ConfigCachedFileType = "Config Encrypted Data Key"
ENCRYPTED_DATA_KEY_FILE_NAME = "encrypted-data-key"
FAILOVER_FILE_SUFFIX = "_failover"
)

View File

@ -19,11 +19,11 @@ package cache
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
"syscall"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/file"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
"github.com/nacos-group/nacos-sdk-go/v2/model"
@ -31,30 +31,10 @@ import (
"github.com/pkg/errors"
)
var (
fileNotExistError = errors.New("file not exist")
)
func GetFileName(cacheKey, cacheDir string) string {
func GetFileName(cacheKey string, cacheDir string) string {
return cacheDir + string(os.PathSeparator) + cacheKey
}
func GetEncryptedDataKeyDir(cacheDir string) string {
return cacheDir + string(os.PathSeparator) + ENCRYPTED_DATA_KEY_FILE_NAME
}
func GetConfigEncryptedDataKeyFileName(cacheKey, cacheDir string) string {
return GetEncryptedDataKeyDir(cacheDir) + string(os.PathSeparator) + cacheKey
}
func GetConfigFailOverContentFileName(cacheKey, cacheDir string) string {
return GetFileName(cacheKey, cacheDir) + FAILOVER_FILE_SUFFIX
}
func GetConfigFailOverEncryptedDataKeyFileName(cacheKey, cacheDir string) string {
return GetConfigEncryptedDataKeyFileName(cacheKey, cacheDir) + FAILOVER_FILE_SUFFIX
}
func WriteServicesToFile(service *model.Service, cacheKey, cacheDir string) {
err := file.MkdirIfNecessary(cacheDir)
if err != nil {
@ -63,14 +43,14 @@ func WriteServicesToFile(service *model.Service, cacheKey, cacheDir string) {
}
bytes, _ := json.Marshal(service)
domFileName := GetFileName(cacheKey, cacheDir)
err = os.WriteFile(domFileName, bytes, 0666)
err = ioutil.WriteFile(domFileName, bytes, 0666)
if err != nil {
logger.Errorf("failed to write name cache:%s ,value:%s ,err:%v", domFileName, string(bytes), err)
}
}
func ReadServicesFromFile(cacheDir string) map[string]model.Service {
files, err := os.ReadDir(cacheDir)
files, err := ioutil.ReadDir(cacheDir)
if err != nil {
logger.Errorf("read cacheDir:%s failed!err:%+v", cacheDir, err)
return nil
@ -78,9 +58,9 @@ func ReadServicesFromFile(cacheDir string) map[string]model.Service {
serviceMap := map[string]model.Service{}
for _, f := range files {
fileName := GetFileName(f.Name(), cacheDir)
b, err := os.ReadFile(fileName)
b, err := ioutil.ReadFile(fileName)
if err != nil {
logger.Errorf("failed to read name cache file:%s,err:%v ", fileName, err)
logger.Errorf("failed to read name cache file:%s,err:%+v ", fileName, err)
continue
}
@ -98,105 +78,42 @@ func ReadServicesFromFile(cacheDir string) map[string]model.Service {
return serviceMap
}
func WriteConfigToFile(cacheKey string, cacheDir string, content string) error {
err := file.MkdirIfNecessary(cacheDir)
if err != nil {
errMsg := fmt.Sprintf("make dir failed, dir path %s, err: %v.", cacheDir, err)
logger.Error(errMsg)
return errors.New(errMsg)
}
err = writeConfigToFile(GetFileName(cacheKey, cacheDir), content, ConfigContent)
if err != nil {
logger.Error(err)
return err
}
return nil
}
func WriteEncryptedDataKeyToFile(cacheKey string, cacheDir string, content string) error {
err := file.MkdirIfNecessary(GetEncryptedDataKeyDir(cacheDir))
if err != nil {
errMsg := fmt.Sprintf("make dir failed, dir path %s, err: %v.", cacheDir, err)
logger.Error(errMsg)
return errors.New(errMsg)
}
err = writeConfigToFile(GetConfigEncryptedDataKeyFileName(cacheKey, cacheDir), content, ConfigEncryptedDataKey)
if err != nil {
logger.Error(err)
return err
}
return nil
}
func writeConfigToFile(fileName string, content string, fileType ConfigCachedFileType) error {
if len(strings.TrimSpace(content)) == 0 {
func WriteConfigToFile(cacheKey string, cacheDir string, content string) {
file.MkdirIfNecessary(cacheDir)
fileName := GetFileName(cacheKey, cacheDir)
if len(content) == 0 {
// delete config snapshot
if err := os.Remove(fileName); err != nil {
if err != syscall.ENOENT {
logger.Debug(fmt.Sprintf("no need to delete %s cache file, file path %s, file doesn't exist.", fileType, fileName))
return nil
}
errMsg := fmt.Sprintf("failed to delete %s cache file, file path %s, err:%v", fileType, fileName, err)
return errors.New(errMsg)
logger.Errorf("failed to delete config file,cache:%s ,value:%s ,err:%+v", fileName, content, err)
}
return
}
err := os.WriteFile(fileName, []byte(content), 0666)
err := ioutil.WriteFile(fileName, []byte(content), 0666)
if err != nil {
errMsg := fmt.Sprintf("failed to write %s cache file, file name: %s, value: %s, err:%v", fileType, fileName, content, err)
return errors.New(errMsg)
logger.Errorf("failed to write config cache:%s ,value:%s ,err:%+v", fileName, content, err)
}
return nil
}
func ReadEncryptedDataKeyFromFile(cacheKey string, cacheDir string) (string, error) {
content, err := readConfigFromFile(GetConfigEncryptedDataKeyFileName(cacheKey, cacheDir), ConfigEncryptedDataKey)
if err != nil {
if errors.Is(err, fileNotExistError) {
logger.Warn(err)
return "", nil
}
}
return content, nil
}
func ReadConfigFromFile(cacheKey string, cacheDir string) (string, error) {
return readConfigFromFile(GetFileName(cacheKey, cacheDir), ConfigEncryptedDataKey)
}
func readConfigFromFile(fileName string, fileType ConfigCachedFileType) (string, error) {
if !file.IsExistFile(fileName) {
errMsg := fmt.Sprintf("read cache file %s failed. cause file doesn't exist, file path: %s.", fileType, fileName)
return "", errors.Wrap(fileNotExistError, errMsg)
}
b, err := os.ReadFile(fileName)
fileName := GetFileName(cacheKey, cacheDir)
b, err := ioutil.ReadFile(fileName)
if err != nil {
errMsg := fmt.Sprintf("get %s from cache failed, filePath:%s, error:%v ", fileType, fileName, err)
return "", errors.New(errMsg)
return "", errors.New(fmt.Sprintf("failed to read config cache file:%s,err:%+v ", fileName, err))
}
return string(b), nil
}
// GetFailover , get failover content
func GetFailover(key, dir string) string {
filePath := GetConfigFailOverContentFileName(key, dir)
return getFailOverConfig(filePath, ConfigContent)
}
func GetFailoverEncryptedDataKey(key, dir string) string {
filePath := GetConfigFailOverEncryptedDataKeyFileName(key, dir)
return getFailOverConfig(filePath, ConfigEncryptedDataKey)
}
func getFailOverConfig(filePath string, fileType ConfigCachedFileType) string {
filePath := dir + string(os.PathSeparator) + key + constant.FAILOVER_FILE_SUFFIX
if !file.IsExistFile(filePath) {
errMsg := fmt.Sprintf("read %s failed. cause file doesn't exist, file path: %s.", fileType, filePath)
logger.Warn(errMsg)
return ""
}
logger.Warnf("reading failover %s from path:%s", fileType, filePath)
fileContent, err := os.ReadFile(filePath)
logger.GetLogger().Warn(fmt.Sprintf("reading failover content from path:%s", filePath))
fileContent, err := ioutil.ReadFile(filePath)
if err != nil {
logger.Errorf("fail to read failover %s from %s", fileType, filePath)
logger.GetLogger().Error(fmt.Sprintf("fail to read failover content from %s", filePath))
return ""
}
return string(fileContent)

View File

@ -2,10 +2,8 @@ package cache
import (
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"math/rand"
"io/ioutil"
"os"
"strconv"
"testing"
"github.com/stretchr/testify/assert"
@ -13,96 +11,9 @@ import (
"github.com/nacos-group/nacos-sdk-go/v2/common/file"
)
var (
dir = file.GetCurrentPath()
group = "FILE_GROUP"
ns = "chasu"
)
func TestWriteAndGetConfigToFile(t *testing.T) {
dataIdSuffix := strconv.Itoa(rand.Intn(1000))
t.Run("write and get config content", func(t *testing.T) {
dataId := "config_content" + dataIdSuffix
cacheKey := util.GetConfigCacheKey(dataId, group, ns)
configContent := "config content"
err := WriteConfigToFile(cacheKey, dir, "")
assert.Nil(t, err)
configFromFile, err := ReadConfigFromFile(cacheKey, dir)
assert.NotNil(t, err)
assert.Equal(t, configFromFile, "")
err = WriteConfigToFile(cacheKey, dir, configContent)
assert.Nil(t, err)
fromFile, err := ReadConfigFromFile(cacheKey, dir)
assert.Nil(t, err)
assert.Equal(t, fromFile, configContent)
err = WriteConfigToFile(cacheKey, dir, "")
assert.Nil(t, err)
configFromFile, err = ReadConfigFromFile(cacheKey, dir)
assert.Nil(t, err)
assert.Equal(t, configFromFile, "")
})
t.Run("write and get config encryptedDataKey", func(t *testing.T) {
dataId := "config_encryptedDataKey" + dataIdSuffix
cacheKey := util.GetConfigCacheKey(dataId, group, ns)
configContent := "config encrypted data key"
err := WriteEncryptedDataKeyToFile(cacheKey, dir, "")
assert.Nil(t, err)
configFromFile, err := ReadEncryptedDataKeyFromFile(cacheKey, dir)
assert.Nil(t, err)
assert.Equal(t, configFromFile, "")
err = WriteEncryptedDataKeyToFile(cacheKey, dir, configContent)
assert.Nil(t, err)
fromFile, err := ReadEncryptedDataKeyFromFile(cacheKey, dir)
assert.Nil(t, err)
assert.Equal(t, fromFile, configContent)
err = WriteEncryptedDataKeyToFile(cacheKey, dir, "")
assert.Nil(t, err)
configFromFile, err = ReadEncryptedDataKeyFromFile(cacheKey, dir)
assert.Nil(t, err)
assert.Equal(t, configFromFile, "")
})
t.Run("double write config file", func(t *testing.T) {
dataId := "config_encryptedDataKey" + dataIdSuffix
cacheKey := util.GetConfigCacheKey(dataId, group, ns)
configContent := "config encrypted data key"
err := WriteConfigToFile(cacheKey, dir, configContent)
assert.Nil(t, err)
err = WriteConfigToFile(cacheKey, dir, configContent)
assert.Nil(t, err)
fromFile, err := ReadConfigFromFile(cacheKey, dir)
assert.Nil(t, err)
assert.Equal(t, fromFile, configContent)
})
t.Run("read doesn't existed config file", func(t *testing.T) {
dataId := "config_encryptedDataKey" + dataIdSuffix + strconv.Itoa(rand.Intn(1000))
cacheKey := util.GetConfigCacheKey(dataId, group, ns)
_, err := ReadConfigFromFile(cacheKey, dir)
assert.NotNil(t, err)
_, err = ReadEncryptedDataKeyFromFile(cacheKey, dir)
assert.Nil(t, err)
})
}
func TestGetFailover(t *testing.T) {
cacheKey := "test_failOver"
dir := file.GetCurrentPath()
fileContent := "test_failover"
t.Run("writeContent", func(t *testing.T) {
filepath := dir + string(os.PathSeparator) + cacheKey + "_failover"
@ -123,5 +34,5 @@ func TestGetFailover(t *testing.T) {
// write file content
func writeFileContent(filepath, content string) error {
return os.WriteFile(filepath, []byte(content), 0666)
return ioutil.WriteFile(filepath, []byte(content), 0666)
}

View File

@ -34,7 +34,7 @@ func CreateConfigClient(properties map[string]interface{}) (iClient config_clien
return NewConfigClient(param)
}
// CreateNamingClient use to create a nacos naming client
//CreateNamingClient use to create a nacos naming client
func CreateNamingClient(properties map[string]interface{}) (iClient naming_client.INamingClient, err error) {
param := getConfigParam(properties)
return NewNamingClient(param)
@ -45,7 +45,7 @@ func NewConfigClient(param vo.NacosClientParam) (iClient config_client.IConfigCl
if err != nil {
return
}
config, err := config_client.NewConfigClientWithRamCredentialProvider(nacosClient, param.RamCredentialProvider)
config, err := config_client.NewConfigClient(nacosClient)
if err != nil {
return
}
@ -58,7 +58,7 @@ func NewNamingClient(param vo.NacosClientParam) (iClient naming_client.INamingCl
if err != nil {
return
}
naming, err := naming_client.NewNamingClientWithRamCredentialProvider(nacosClient, param.RamCredentialProvider)
naming, err := naming_client.NewNamingClient(nacosClient)
if err != nil {
return
}
@ -104,14 +104,6 @@ func setConfig(param vo.NacosClientParam) (iClient nacos_client.INacosClient, er
}
_ = client.SetServerConfig(nil)
} else {
for i := range param.ServerConfigs {
if param.ServerConfigs[i].Port == 0 {
param.ServerConfigs[i].Port = 8848
}
if param.ServerConfigs[i].GrpcPort == 0 {
param.ServerConfigs[i].GrpcPort = param.ServerConfigs[i].Port + constant.RpcPortOffset
}
}
err = client.SetServerConfig(param.ServerConfigs)
if err != nil {
return nil, err

View File

@ -17,21 +17,22 @@
package config_client
import (
"context"
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
"math"
"os"
"strings"
"sync"
"time"
"github.com/pkg/errors"
"github.com/nacos-group/nacos-sdk-go/v2/common/monitor"
"github.com/aliyun/alibaba-cloud-sdk-go/services/kms"
"github.com/nacos-group/nacos-sdk-go/v2/clients/cache"
"github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
nacos_inner_encryption "github.com/nacos-group/nacos-sdk-go/v2/common/encryption"
"github.com/nacos-group/nacos-sdk-go/v2/common/filter"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
"github.com/nacos-group/nacos-sdk-go/v2/common/monitor"
"github.com/nacos-group/nacos-sdk-go/v2/common/nacos_error"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
@ -39,7 +40,6 @@ import (
"github.com/nacos-group/nacos-sdk-go/v2/model"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
"github.com/pkg/errors"
)
const (
@ -48,19 +48,16 @@ const (
)
type ConfigClient struct {
ctx context.Context
cancel context.CancelFunc
nacos_client.INacosClient
configFilterChainManager filter.IConfigFilterChain
localConfigs []vo.ConfigParam
mutex sync.Mutex
configProxy IConfigProxy
configCacheDir string
lastAllSyncTime time.Time
cacheMap cache.ConcurrentMap
uid string
listenExecute chan struct{}
isClosed bool
kmsClient *kms.Client
localConfigs []vo.ConfigParam
mutex sync.Mutex
configProxy IConfigProxy
configCacheDir string
lastAllSyncTime time.Time
cacheMap cache.ConcurrentMap
uid string
listenExecute chan struct{}
}
type cacheData struct {
@ -69,7 +66,6 @@ type cacheData struct {
group string
content string
contentType string
encryptedDataKey string
tenant string
cacheDataListener *cacheDataListener
md5 string
@ -84,28 +80,8 @@ type cacheDataListener struct {
lastMd5 string
}
func (cacheData *cacheData) executeListener() {
cacheData.cacheDataListener.lastMd5 = cacheData.md5
cacheData.configClient.cacheMap.Set(util.GetConfigCacheKey(cacheData.dataId, cacheData.group, cacheData.tenant), *cacheData)
param := &vo.ConfigParam{
DataId: cacheData.dataId,
Content: cacheData.content,
EncryptedDataKey: cacheData.encryptedDataKey,
UsageType: vo.ResponseType,
}
if err := cacheData.configClient.configFilterChainManager.DoFilters(param); err != nil {
logger.Errorf("do filters failed ,dataId=%s,group=%s,tenant=%s,err:%+v ", cacheData.dataId,
cacheData.group, cacheData.tenant, err)
return
}
decryptedContent := param.Content
go cacheData.cacheDataListener.listener(cacheData.tenant, cacheData.group, cacheData.dataId, decryptedContent)
}
func NewConfigClientWithRamCredentialProvider(nc nacos_client.INacosClient, provider security.RamCredentialProvider) (*ConfigClient, error) {
func NewConfigClient(nc nacos_client.INacosClient) (*ConfigClient, error) {
config := &ConfigClient{}
config.ctx, config.cancel = context.WithCancel(context.Background())
config.INacosClient = nc
clientConfig, err := nc.GetClientConfig()
if err != nil {
@ -126,36 +102,31 @@ func NewConfigClientWithRamCredentialProvider(nc nacos_client.INacosClient, prov
clientConfig.CacheDir = clientConfig.CacheDir + string(os.PathSeparator) + "config"
config.configCacheDir = clientConfig.CacheDir
if config.configProxy, err = NewConfigProxyWithRamCredentialProvider(config.ctx, serverConfig, clientConfig, httpAgent, provider); err != nil {
if config.configProxy, err = NewConfigProxy(serverConfig, clientConfig, httpAgent); err != nil {
return nil, err
}
config.configFilterChainManager = filter.NewConfigFilterChainManager()
if clientConfig.OpenKMS {
kmsEncryptionHandler := nacos_inner_encryption.NewKmsHandler()
nacos_inner_encryption.RegisterConfigEncryptionKmsPlugins(kmsEncryptionHandler, clientConfig)
encryptionFilter := filter.NewDefaultConfigEncryptionFilter(kmsEncryptionHandler)
err := filter.RegisterConfigFilterToChain(config.configFilterChainManager, encryptionFilter)
kmsClient, err := kms.NewClientWithAccessKey(clientConfig.RegionId, clientConfig.AccessKey, clientConfig.SecretKey)
if err != nil {
logger.Error(err)
return nil, err
}
config.kmsClient = kmsClient
}
uid, err := uuid.NewV4()
if err != nil {
return nil, err
}
config.uid = uid.String()
config.cacheMap = cache.NewConcurrentMap()
config.listenExecute = make(chan struct{})
config.startInternal()
return config, err
}
func NewConfigClient(nc nacos_client.INacosClient) (*ConfigClient, error) {
return NewConfigClientWithRamCredentialProvider(nc, nil)
config.cacheMap = cache.NewConcurrentMap()
// maximum buffered queue to prevent chan deadlocks during frequent configuration file updates
config.listenExecute = make(chan struct{}, math.MaxInt64)
config.startInternal()
return config, err
}
func initLogger(clientConfig constant.ClientConfig) error {
@ -163,72 +134,77 @@ func initLogger(clientConfig constant.ClientConfig) error {
}
func (client *ConfigClient) GetConfig(param vo.ConfigParam) (content string, err error) {
content, encryptedDataKey, err := client.getConfigInner(param)
content, err = client.getConfigInner(param)
if err != nil {
return "", err
}
deepCopyParam := param.DeepCopy()
deepCopyParam.EncryptedDataKey = encryptedDataKey
deepCopyParam.Content = content
deepCopyParam.UsageType = vo.ResponseType
if err = client.configFilterChainManager.DoFilters(deepCopyParam); err != nil {
return "", err
return client.decrypt(param.DataId, content)
}
func (client *ConfigClient) decrypt(dataId, content string) (string, error) {
if client.kmsClient != nil && strings.HasPrefix(dataId, "cipher-") {
request := kms.CreateDecryptRequest()
request.Method = "POST"
request.Scheme = "https"
request.AcceptFormat = "json"
request.CiphertextBlob = content
response, err := client.kmsClient.Decrypt(request)
if err != nil {
return "", fmt.Errorf("kms decrypt failed: %v", err)
}
content = response.Plaintext
}
content = deepCopyParam.Content
return content, nil
}
func (client *ConfigClient) getConfigInner(param vo.ConfigParam) (content, encryptedDataKey string, err error) {
func (client *ConfigClient) encrypt(dataId, content string) (string, error) {
if client.kmsClient != nil && strings.HasPrefix(dataId, "cipher-") {
request := kms.CreateEncryptRequest()
request.Method = "POST"
request.Scheme = "https"
request.AcceptFormat = "json"
request.KeyId = "alias/acs/mse" // use default key
request.Plaintext = content
response, err := client.kmsClient.Encrypt(request)
if err != nil {
return "", fmt.Errorf("kms encrypt failed: %v", err)
}
content = response.CiphertextBlob
}
return content, nil
}
func (client *ConfigClient) getConfigInner(param vo.ConfigParam) (content string, err error) {
if len(param.DataId) <= 0 {
err = errors.New("[client.GetConfig] param.dataId can not be empty")
return "", "", err
return "", err
}
if len(param.Group) <= 0 {
param.Group = constant.DEFAULT_GROUP
}
//todo 获取容灾配置的 EncryptedDataKey LocalEncryptedDataKeyProcessor.getEncryptDataKeyFailover
clientConfig, _ := client.GetClientConfig()
cacheKey := util.GetConfigCacheKey(param.DataId, param.Group, clientConfig.NamespaceId)
content = cache.GetFailover(cacheKey, client.configCacheDir)
if len(content) > 0 {
logger.Warnf("%s %s %s is using failover content!", clientConfig.NamespaceId, param.Group, param.DataId)
encryptedDataKey = cache.GetFailoverEncryptedDataKey(cacheKey, client.configCacheDir)
return content, encryptedDataKey, nil
logger.GetLogger().Warn(fmt.Sprintf("%s %s %s is using failover content!", clientConfig.NamespaceId, param.Group, param.DataId))
return content, nil
}
response, err := client.configProxy.queryConfig(param.DataId, param.Group, clientConfig.NamespaceId,
clientConfig.TimeoutMs, false, client)
if err != nil {
logger.Errorf("get config from server error:%v, dataId=%s, group=%s, namespaceId=%s", err,
param.DataId, param.Group, clientConfig.NamespaceId)
if clientConfig.DisableUseSnapShot {
return "", "", errors.Errorf("get config from remote nacos server fail, and is not allowed to read local file, err:%v", err)
logger.Infof("get config from server error:%+v ", err)
content, err = cache.ReadConfigFromFile(cacheKey, client.configCacheDir)
if err != nil {
logger.Errorf("get config from cache error:%+v ", err)
return "", errors.New("read config from both server and cache fail")
}
cacheContent, cacheErr := cache.ReadConfigFromFile(cacheKey, client.configCacheDir)
if cacheErr != nil {
return "", "", errors.Errorf("read config from both server and cache fail, err=%vdataId=%s, group=%s, namespaceId=%s",
cacheErr, param.DataId, param.Group, clientConfig.NamespaceId)
}
if !strings.HasPrefix(param.DataId, nacos_inner_encryption.CipherPrefix) {
return cacheContent, "", nil
}
encryptedDataKey, cacheErr = cache.ReadEncryptedDataKeyFromFile(cacheKey, client.configCacheDir)
if cacheErr != nil {
return "", "", errors.Errorf("read encryptedDataKey from server and cache fail, err=%vdataId=%s, group=%s, namespaceId=%s",
cacheErr, param.DataId, param.Group, clientConfig.NamespaceId)
}
logger.Warnf("read config from cache success, dataId=%s, group=%s, namespaceId=%s", param.DataId, param.Group, clientConfig.NamespaceId)
return cacheContent, encryptedDataKey, nil
return content, nil
}
if response != nil && response.Response != nil && !response.IsSuccess() {
return response.Content, response.EncryptedDataKey, errors.New(response.GetMessage())
}
encryptedDataKey = response.EncryptedDataKey
content = response.Content
return content, encryptedDataKey, nil
return response.Content, nil
}
func (client *ConfigClient) PublishConfig(param vo.ConfigParam) (published bool, err error) {
@ -244,28 +220,21 @@ func (client *ConfigClient) PublishConfig(param vo.ConfigParam) (published bool,
if len(param.Group) <= 0 {
param.Group = constant.DEFAULT_GROUP
}
param.UsageType = vo.RequestType
if err = client.configFilterChainManager.DoFilters(&param); err != nil {
return false, err
if param.Content, err = client.encrypt(param.DataId, param.Content); err != nil {
return
}
clientConfig, _ := client.GetClientConfig()
request := rpc_request.NewConfigPublishRequest(param.Group, param.DataId, clientConfig.NamespaceId, param.Content, param.CasMd5)
request.AdditionMap["tag"] = param.Tag
request.AdditionMap["config_tags"] = param.ConfigTags
request.AdditionMap["appName"] = param.AppName
request.AdditionMap["betaIps"] = param.BetaIps
request.AdditionMap["type"] = param.Type
request.AdditionMap["src_user"] = param.SrcUser
request.AdditionMap["encryptedDataKey"] = param.EncryptedDataKey
rpcClient := client.configProxy.getRpcClient(client)
response, err := client.configProxy.requestProxy(rpcClient, request, constant.DEFAULT_TIMEOUT_MILLS)
if err != nil {
return false, err
}
if response != nil {
return client.buildResponse(response)
return response.IsSuccess(), err
}
return false, err
}
@ -284,16 +253,13 @@ func (client *ConfigClient) DeleteConfig(param vo.ConfigParam) (deleted bool, er
request := rpc_request.NewConfigRemoveRequest(param.Group, param.DataId, clientConfig.NamespaceId)
rpcClient := client.configProxy.getRpcClient(client)
response, err := client.configProxy.requestProxy(rpcClient, request, constant.DEFAULT_TIMEOUT_MILLS)
if err != nil {
return false, err
}
if response != nil {
return client.buildResponse(response)
return response.IsSuccess(), err
}
return false, err
}
// Cancel Listen Config
//Cancel Listen Config
func (client *ConfigClient) CancelListenConfig(param vo.ConfigParam) (err error) {
clientConfig, err := client.GetClientConfig()
if err != nil {
@ -321,20 +287,16 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
}
key := util.GetConfigCacheKey(param.DataId, param.Group, clientConfig.NamespaceId)
var cData cacheData
var cData *cacheData
if v, ok := client.cacheMap.Get(key); ok {
cData = v.(cacheData)
cData = v.(*cacheData)
cData.isInitializing = true
} else {
var (
content string
md5Str string
innerErr error
content string
md5Str string
)
if content, innerErr = cache.ReadConfigFromFile(key, client.configCacheDir); innerErr != nil {
logger.Warn(innerErr)
}
encryptedDataKey, _ := cache.ReadEncryptedDataKeyFromFile(key, client.configCacheDir)
content, _ = cache.ReadConfigFromFile(key, client.configCacheDir)
if len(content) > 0 {
md5Str = util.Md5(content)
}
@ -343,7 +305,7 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
lastMd5: md5Str,
}
cData = cacheData{
cData = &cacheData{
isInitializing: true,
dataId: param.DataId,
group: param.Group,
@ -351,7 +313,6 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
content: content,
md5: md5Str,
cacheDataListener: listener,
encryptedDataKey: encryptedDataKey,
taskId: client.cacheMap.Count() / perTaskConfigSize,
configClient: client,
}
@ -360,23 +321,15 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
return
}
func (client *ConfigClient) SearchConfig(param vo.SearchConfigParam) (*model.ConfigPage, error) {
func (client *ConfigClient) SearchConfig(param vo.SearchConfigParm) (*model.ConfigPage, error) {
return client.searchConfigInner(param)
}
func (client *ConfigClient) CloseClient() {
client.mutex.Lock()
defer client.mutex.Unlock()
if client.isClosed {
return
}
client.configProxy.getRpcClient(client).Shutdown()
client.cancel()
client.isClosed = true
}
func (client *ConfigClient) searchConfigInner(param vo.SearchConfigParam) (*model.ConfigPage, error) {
func (client *ConfigClient) searchConfigInner(param vo.SearchConfigParm) (*model.ConfigPage, error) {
if param.Search != "accurate" && param.Search != "blur" {
return nil, errors.New("[client.searchConfigInner] param.search must be accurate or blur")
}
@ -405,17 +358,14 @@ func (client *ConfigClient) searchConfigInner(param vo.SearchConfigParam) (*mode
}
func (client *ConfigClient) startInternal() {
timer := time.NewTimer(executorErrDelay)
go func() {
timer := time.NewTimer(executorErrDelay)
defer timer.Stop()
for {
select {
case <-client.listenExecute:
client.executeConfigListen()
case <-timer.C:
client.executeConfigListen()
case <-client.ctx.Done():
return
}
timer.Reset(executorErrDelay)
}
@ -423,74 +373,82 @@ func (client *ConfigClient) startInternal() {
}
func (client *ConfigClient) executeConfigListen() {
var (
needAllSync = time.Since(client.lastAllSyncTime) >= constant.ALL_SYNC_INTERNAL
hasChangedKeys = false
)
listenTaskMap := client.buildListenTask(needAllSync)
if len(listenTaskMap) == 0 {
return
}
for taskId, caches := range listenTaskMap {
request := buildConfigBatchListenRequest(caches)
rpcClient := client.configProxy.createRpcClient(client.ctx, fmt.Sprintf("%d", taskId), client)
iResponse, err := client.configProxy.requestProxy(rpcClient, request, 3000)
if err != nil {
logger.Warnf("ConfigBatchListenRequest failure, err:%v", err)
continue
}
if iResponse == nil {
logger.Warnf("ConfigBatchListenRequest failure, response is nil")
continue
}
if !iResponse.IsSuccess() {
logger.Warnf("ConfigBatchListenRequest failure, error code:%d", iResponse.GetErrorCode())
continue
}
response, ok := iResponse.(*rpc_response.ConfigChangeBatchListenResponse)
listenCachesMap := make(map[int][]*cacheData, 16)
needAllSync := time.Since(client.lastAllSyncTime) >= constant.ALL_SYNC_INTERNAL
for _, v := range client.cacheMap.Items() {
cache, ok := v.(*cacheData)
if !ok {
continue
}
if len(response.ChangedConfigs) > 0 {
hasChangedKeys = true
}
changeKeys := make(map[string]struct{}, len(response.ChangedConfigs))
for _, v := range response.ChangedConfigs {
changeKey := util.GetConfigCacheKey(v.DataId, v.Group, v.Tenant)
changeKeys[changeKey] = struct{}{}
if value, ok := client.cacheMap.Get(changeKey); ok {
cData := value.(cacheData)
client.refreshContentAndCheck(cData, !cData.isInitializing)
if cache.isSyncWithServer {
if cache.md5 != cache.cacheDataListener.lastMd5 {
go cache.cacheDataListener.listener(cache.tenant, cache.group, cache.dataId, cache.content)
cache.cacheDataListener.lastMd5 = cache.md5
}
}
for _, v := range client.cacheMap.Items() {
data := v.(cacheData)
changeKey := util.GetConfigCacheKey(data.dataId, data.group, data.tenant)
if _, ok := changeKeys[changeKey]; !ok {
data.isSyncWithServer = true
client.cacheMap.Set(changeKey, data)
if !needAllSync {
continue
}
data.isInitializing = true
client.cacheMap.Set(changeKey, data)
}
var cacheDatas []*cacheData
if cacheDatas, ok = listenCachesMap[cache.taskId]; ok {
cacheDatas = append(cacheDatas, cache)
} else {
cacheDatas = append(cacheDatas, cache)
}
listenCachesMap[cache.taskId] = cacheDatas
}
hasChangedKeys := false
if len(listenCachesMap) > 0 {
for taskId, listenCaches := range listenCachesMap {
request := buildConfigBatchListenRequest(listenCaches)
rpcClient := client.configProxy.createRpcClient(fmt.Sprintf("%d", taskId), client)
iResponse, err := client.configProxy.requestProxy(rpcClient, request, 3000)
if err != nil {
logger.Warnf("ConfigBatchListenRequest failure,err:%+v", err)
continue
}
if iResponse == nil && !iResponse.IsSuccess() {
continue
}
changeKeys := make(map[string]struct{})
if response, ok := iResponse.(*rpc_response.ConfigChangeBatchListenResponse); ok {
if len(response.ChangedConfigs) > 0 {
hasChangedKeys = true
for _, v := range response.ChangedConfigs {
changeKey := util.GetConfigCacheKey(v.DataId, v.Group, v.Tenant)
changeKeys[changeKey] = struct{}{}
if cache, ok := client.cacheMap.Get(changeKey); !ok {
continue
} else {
cacheData := cache.(*cacheData)
client.refreshContentAndCheck(cacheData, !cacheData.isInitializing)
}
}
}
for _, v := range listenCaches {
changeKey := util.GetConfigCacheKey(v.dataId, v.group, v.tenant)
if _, ok := changeKeys[changeKey]; !ok {
v.isSyncWithServer = true
continue
}
v.isInitializing = true
}
}
}
}
if needAllSync {
client.lastAllSyncTime = time.Now()
}
if hasChangedKeys {
client.asyncNotifyListenConfig()
client.notifyListenConfig()
}
monitor.GetListenConfigCountMonitor().Set(float64(client.cacheMap.Count()))
}
func buildConfigBatchListenRequest(caches []cacheData) *rpc_request.ConfigBatchListenRequest {
func buildConfigBatchListenRequest(caches []*cacheData) *rpc_request.ConfigBatchListenRequest {
request := rpc_request.NewConfigBatchListenRequest(len(caches))
for _, cache := range caches {
request.ConfigListenContexts = append(request.ConfigListenContexts,
@ -499,7 +457,7 @@ func buildConfigBatchListenRequest(caches []cacheData) *rpc_request.ConfigBatchL
return request
}
func (client *ConfigClient) refreshContentAndCheck(cacheData cacheData, notify bool) {
func (client *ConfigClient) refreshContentAndCheck(cacheData *cacheData, notify bool) {
configQueryResponse, err := client.configProxy.queryConfig(cacheData.dataId, cacheData.group, cacheData.tenant,
constant.DEFAULT_TIMEOUT_MILLS, notify, client)
if err != nil {
@ -507,14 +465,8 @@ func (client *ConfigClient) refreshContentAndCheck(cacheData cacheData, notify b
cacheData.group, cacheData.tenant)
return
}
if configQueryResponse != nil && configQueryResponse.Response != nil && !configQueryResponse.IsSuccess() {
logger.Errorf("refresh cached config from server error:%v, dataId=%s, group=%s", configQueryResponse.GetMessage(),
cacheData.dataId, cacheData.group)
return
}
cacheData.content = configQueryResponse.Content
cacheData.contentType = configQueryResponse.ContentType
cacheData.encryptedDataKey = configQueryResponse.EncryptedDataKey
if notify {
logger.Infof("[config_rpc_client] [data-received] dataId=%s, group=%s, tenant=%s, md5=%s, content=%s, type=%s",
cacheData.dataId, cacheData.group, cacheData.tenant, cacheData.md5,
@ -522,42 +474,12 @@ func (client *ConfigClient) refreshContentAndCheck(cacheData cacheData, notify b
}
cacheData.md5 = util.Md5(cacheData.content)
if cacheData.md5 != cacheData.cacheDataListener.lastMd5 {
cacheDataPtr := &cacheData
cacheDataPtr.executeListener()
go cacheData.cacheDataListener.listener(cacheData.tenant, cacheData.group, cacheData.dataId, cacheData.content)
cacheData.cacheDataListener.lastMd5 = cacheData.md5
client.cacheMap.Set(util.GetConfigCacheKey(cacheData.dataId, cacheData.group, cacheData.tenant), cacheData)
}
}
func (client *ConfigClient) buildListenTask(needAllSync bool) map[int][]cacheData {
listenTaskMap := make(map[int][]cacheData, 8)
for _, v := range client.cacheMap.Items() {
data, ok := v.(cacheData)
if !ok {
continue
}
if data.isSyncWithServer {
if data.md5 != data.cacheDataListener.lastMd5 {
data.executeListener()
}
if !needAllSync {
continue
}
}
listenTaskMap[data.taskId] = append(listenTaskMap[data.taskId], data)
}
return listenTaskMap
}
func (client *ConfigClient) asyncNotifyListenConfig() {
go func() {
client.listenExecute <- struct{}{}
}()
}
func (client *ConfigClient) buildResponse(response rpc_response.IResponse) (bool, error) {
if response.IsSuccess() {
return response.IsSuccess(), nil
}
return false, errors.New(response.GetMessage())
func (client *ConfigClient) notifyListenConfig() {
client.listenExecute <- struct{}{}
}

View File

@ -63,7 +63,7 @@ type IConfigClient interface {
// tenant ==>nacos.namespace optional
// pageNo option,default is 1
// pageSize option,default is 10
SearchConfig(param vo.SearchConfigParam) (*model.ConfigPage, error)
SearchConfig(param vo.SearchConfigParm) (*model.ConfigPage, error)
// CloseClient Close the GRPC client
CloseClient()

View File

@ -17,12 +17,11 @@
package config_client
import (
"context"
"errors"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"testing"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
@ -35,29 +34,12 @@ import (
"github.com/stretchr/testify/assert"
)
var serverConfigWithOptions = constant.NewServerConfig("127.0.0.1", 8848)
var serverConfigWithOptions = constant.NewServerConfig("127.0.0.1", 80, constant.WithContextPath("/nacos"))
var clientConfigWithOptions = constant.NewClientConfig(
constant.WithTimeoutMs(10*1000),
constant.WithBeatInterval(2*1000),
constant.WithNotLoadCacheAtStart(true),
constant.WithAccessKey("LTAxxx"),
constant.WithSecretKey("EdPxxx"),
constant.WithOpenKMS(true),
constant.WithKMSVersion(constant.KMSv1),
constant.WithRegionId("cn-hangzhou"),
)
var clientTLsConfigWithOptions = constant.NewClientConfig(
constant.WithTimeoutMs(10*1000),
constant.WithBeatInterval(2*1000),
constant.WithNotLoadCacheAtStart(true),
/*constant.WithTLS(constant.TLSConfig{
Enable: true,
TrustAll: false,
CaFile: "mse-nacos-ca.cer",
}),*/
)
var localConfigTest = vo.ConfigParam{
@ -76,44 +58,6 @@ func createConfigClientTest() *ConfigClient {
return client
}
func createConfigClientTestTls() *ConfigClient {
nc := nacos_client.NacosClient{}
_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
_ = nc.SetClientConfig(*clientTLsConfigWithOptions)
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
client, _ := NewConfigClient(&nc)
client.configProxy = &MockConfigProxy{}
return client
}
func createConfigClientCommon() *ConfigClient {
nc := nacos_client.NacosClient{}
_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
_ = nc.SetClientConfig(*clientConfigWithOptions)
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
client, _ := NewConfigClient(&nc)
client.configProxy = &MockConfigProxy{}
return client
}
func createConfigClientForKms() *ConfigClient {
nc := nacos_client.NacosClient{}
_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
_ = nc.SetClientConfig(*clientConfigWithOptions)
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
client, _ := NewConfigClient(&nc)
client.configProxy = &MockConfigProxyForUsingLocalDiskCache{}
return client
}
type MockConfigProxyForUsingLocalDiskCache struct {
MockConfigProxy
}
func (m *MockConfigProxyForUsingLocalDiskCache) queryConfig(dataId, group, tenant string, timeout uint64, notify bool, client *ConfigClient) (*rpc_response.ConfigQueryResponse, error) {
return nil, errors.New("mock err for using localCache")
}
type MockConfigProxy struct {
}
@ -122,15 +66,15 @@ func (m *MockConfigProxy) queryConfig(dataId, group, tenant string, timeout uint
if IsLimited(cacheKey) {
return nil, errors.New("request is limited")
}
return &rpc_response.ConfigQueryResponse{Content: "hello world", Response: &rpc_response.Response{Success: true}}, nil
return &rpc_response.ConfigQueryResponse{Content: "hello world"}, nil
}
func (m *MockConfigProxy) searchConfigProxy(param vo.SearchConfigParam, tenant, accessKey, secretKey string) (*model.ConfigPage, error) {
func (m *MockConfigProxy) searchConfigProxy(param vo.SearchConfigParm, tenant, accessKey, secretKey string) (*model.ConfigPage, error) {
return &model.ConfigPage{TotalCount: 1}, nil
}
func (m *MockConfigProxy) requestProxy(rpcClient *rpc.RpcClient, request rpc_request.IRequest, timeoutMills uint64) (rpc_response.IResponse, error) {
return &rpc_response.MockResponse{Response: &rpc_response.Response{Success: true}}, nil
}
func (m *MockConfigProxy) createRpcClient(ctx context.Context, taskId string, client *ConfigClient) *rpc.RpcClient {
func (m *MockConfigProxy) createRpcClient(taskId string, client *ConfigClient) *rpc.RpcClient {
return &rpc.RpcClient{}
}
func (m *MockConfigProxy) getRpcClient(client *ConfigClient) *rpc.RpcClient {
@ -149,7 +93,7 @@ func Test_GetConfig(t *testing.T) {
content, err := client.GetConfig(vo.ConfigParam{
DataId: localConfigTest.DataId,
Group: localConfigTest.Group})
Group: "group"})
assert.Nil(t, err)
assert.Equal(t, "hello world", content)
@ -161,7 +105,7 @@ func Test_SearchConfig(t *testing.T) {
DataId: localConfigTest.DataId,
Group: "DEFAULT_GROUP",
Content: "hello world"})
configPage, err := client.SearchConfig(vo.SearchConfigParam{
configPage, err := client.SearchConfig(vo.SearchConfigParm{
Search: "accurate",
DataId: localConfigTest.DataId,
Group: "DEFAULT_GROUP",
@ -172,74 +116,6 @@ func Test_SearchConfig(t *testing.T) {
assert.NotEmpty(t, configPage)
}
func Test_GetConfigTls(t *testing.T) {
client := createConfigClientTestTls()
_, _ = client.PublishConfig(vo.ConfigParam{
DataId: localConfigTest.DataId,
Group: "DEFAULT_GROUP",
Content: "hello world"})
configPage, err := client.SearchConfig(vo.SearchConfigParam{
Search: "accurate",
DataId: localConfigTest.DataId,
Group: "DEFAULT_GROUP",
PageNo: 1,
PageSize: 10,
})
assert.Nil(t, err)
assert.NotEmpty(t, configPage)
}
// only using by ak sk for cipher config of aliyun kms
/*
func TestPublishAndGetConfigByUsingLocalCache(t *testing.T) {
param := vo.ConfigParam{
DataId: "cipher-kms-aes-256-usingCache" + strconv.Itoa(rand.Int()),
Group: "DEFAULT",
Content: "content加密&&" + strconv.Itoa(rand.Int()),
}
t.Run("PublishAndGetConfigByUsingLocalCache", func(t *testing.T) {
commonClient := createConfigClientCommon()
_, err := commonClient.PublishConfig(param)
assert.Nil(t, err)
time.Sleep(2 * time.Second)
configQueryContent, err := commonClient.GetConfig(param)
assert.Nil(t, err)
assert.Equal(t, param.Content, configQueryContent)
usingKmsCacheClient := createConfigClientForKms()
configQueryContentByUsingCache, err := usingKmsCacheClient.GetConfig(param)
assert.Nil(t, err)
assert.Equal(t, param.Content, configQueryContentByUsingCache)
newCipherContent := param.Content + "new"
param.Content = newCipherContent
err = commonClient.ListenConfig(vo.ConfigParam{
DataId: param.DataId,
Group: param.Group,
OnChange: func(namespace, group, dataId, data string) {
t.Log("origin data: " + newCipherContent + "; new data: " + data)
assert.Equal(t, newCipherContent, data)
},
})
assert.Nil(t, err)
result, err := commonClient.PublishConfig(param)
assert.Nil(t, err)
assert.True(t, result)
time.Sleep(2 * time.Second)
newContentCommon, err := commonClient.GetConfig(param)
assert.Nil(t, err)
assert.Equal(t, param.Content, newContentCommon)
newContentKms, err := usingKmsCacheClient.GetConfig(param)
assert.Nil(t, err)
assert.Equal(t, param.Content, newContentKms)
})
}
*/
// PublishConfig
func Test_PublishConfigWithoutDataId(t *testing.T) {
client := createConfigClientTest()
@ -268,7 +144,6 @@ func Test_PublishConfig(t *testing.T) {
success, err := client.PublishConfig(vo.ConfigParam{
DataId: localConfigTest.DataId,
Group: "group",
SrcUser: "nacos-client-go",
Content: "hello world"})
assert.Nil(t, err)
@ -357,55 +232,3 @@ func TestCancelListenConfig(t *testing.T) {
assert.Nil(t, err)
})
}
type MockAccessKeyCredentialProvider struct {
accessKey string
secretKey string
signatureRegionId string
}
func (provider *MockAccessKeyCredentialProvider) MatchProvider() bool {
return true
}
func (provider *MockAccessKeyCredentialProvider) Init() error {
return nil
}
func (provider *MockAccessKeyCredentialProvider) GetCredentialsForNacosClient() security.RamContext {
ramContext := security.RamContext{
AccessKey: provider.accessKey,
SecretKey: provider.secretKey,
SignatureRegionId: "",
}
return ramContext
}
func Test_ConfigClientWithProvider(t *testing.T) {
nc := nacos_client.NacosClient{}
_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
clientConfigWithOptions.AccessKey = ""
clientConfigWithOptions.SecretKey = ""
_ = nc.SetClientConfig(*clientConfigWithOptions)
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
provider := &MockAccessKeyCredentialProvider{
accessKey: "LTAxxx",
secretKey: "EdPxxx",
}
client, _ := NewConfigClientWithRamCredentialProvider(&nc, provider)
client.configProxy = &MockConfigProxy{}
success, err := client.PublishConfig(vo.ConfigParam{
DataId: localConfigTest.DataId,
Group: localConfigTest.Group,
Content: "hello world"})
assert.Nil(t, err)
assert.True(t, success)
content, err := client.GetConfig(vo.ConfigParam{
DataId: localConfigTest.DataId,
Group: localConfigTest.Group})
assert.Nil(t, err)
assert.Equal(t, "hello world", content)
}

View File

@ -1,64 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 config_client
import (
"strconv"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
)
type ConfigConnectionEventListener struct {
client *ConfigClient
taskId string
}
func NewConfigConnectionEventListener(client *ConfigClient, taskId string) *ConfigConnectionEventListener {
return &ConfigConnectionEventListener{
client: client,
taskId: taskId,
}
}
func (c *ConfigConnectionEventListener) OnConnected() {
logger.Info("[ConfigConnectionEventListener] connect to config server for taskId: " + c.taskId)
if c.client != nil {
c.client.asyncNotifyListenConfig()
}
}
func (c *ConfigConnectionEventListener) OnDisConnect() {
logger.Info("[ConfigConnectionEventListener] disconnect from config server for taskId: " + c.taskId)
if c.client != nil {
taskIdInt, err := strconv.Atoi(c.taskId)
if err != nil {
logger.Errorf("[ConfigConnectionEventListener] parse taskId error: %v", err)
return
}
items := c.client.cacheMap.Items()
for key, v := range items {
if data, ok := v.(cacheData); ok {
if data.taskId == taskIdInt {
data.isSyncWithServer = false
c.client.cacheMap.Set(key, data)
}
}
}
}
}

View File

@ -1,192 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 config_client
import (
"context"
"testing"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/clients/cache"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
"github.com/nacos-group/nacos-sdk-go/v2/model"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"github.com/stretchr/testify/assert"
)
func TestNewConfigConnectionEventListener(t *testing.T) {
client := &ConfigClient{}
taskId := "123"
listener := NewConfigConnectionEventListener(client, taskId)
assert.Equal(t, client, listener.client)
assert.Equal(t, taskId, listener.taskId)
}
func TestOnDisConnectWithMock(t *testing.T) {
client := &ConfigClient{
cacheMap: cache.NewConcurrentMap(),
}
data1 := cacheData{
dataId: "dataId1",
group: "group1",
tenant: "",
taskId: 1,
isSyncWithServer: true,
}
data2 := cacheData{
dataId: "dataId2",
group: "group1",
tenant: "",
taskId: 1,
isSyncWithServer: true,
}
data3 := cacheData{
dataId: "dataId3",
group: "group2",
tenant: "",
taskId: 2,
isSyncWithServer: true,
}
key1 := util.GetConfigCacheKey(data1.dataId, data1.group, data1.tenant)
key2 := util.GetConfigCacheKey(data2.dataId, data2.group, data2.tenant)
key3 := util.GetConfigCacheKey(data3.dataId, data3.group, data3.tenant)
client.cacheMap.Set(key1, data1)
client.cacheMap.Set(key2, data2)
client.cacheMap.Set(key3, data3)
listener := NewConfigConnectionEventListener(client, "1")
listener.OnDisConnect()
item1, _ := client.cacheMap.Get(key1)
item2, _ := client.cacheMap.Get(key2)
item3, _ := client.cacheMap.Get(key3)
updatedData1 := item1.(cacheData)
updatedData2 := item2.(cacheData)
updatedData3 := item3.(cacheData)
assert.False(t, updatedData1.isSyncWithServer, "dataId1 should be marked as not sync")
assert.False(t, updatedData2.isSyncWithServer, "dataId2 should be marked as not sync")
assert.True(t, updatedData3.isSyncWithServer, "dataId3 should be marked as sync")
}
func TestOnConnectedWithMock(t *testing.T) {
listenChan := make(chan struct{}, 1)
client := &ConfigClient{
listenExecute: listenChan,
}
listener := NewConfigConnectionEventListener(client, "1")
listener.OnConnected()
time.Sleep(100 * time.Millisecond)
select {
case <-listenChan:
assert.True(t, true, "asyncNotifyListenConfig should be called")
default:
t.Fatalf("asyncNotifyListenConfig should be called but not")
}
}
type MockRpcClientForListener struct {
requestCalled rpc_request.IRequest
}
func (m *MockRpcClientForListener) Request(request rpc_request.IRequest) (rpc_response.IResponse, error) {
m.requestCalled = request
return &rpc_response.ConfigChangeBatchListenResponse{
Response: &rpc_response.Response{
ResultCode: 200,
},
ChangedConfigs: []model.ConfigContext{},
}, nil
}
func TestReconnectionFlow(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
mockRpc := &MockRpcClientForListener{}
listenChan := make(chan struct{}, 1)
client := &ConfigClient{
ctx: ctx,
configProxy: &MockConfigProxy{},
cacheMap: cache.NewConcurrentMap(),
listenExecute: listenChan,
}
done := make(chan bool)
go func() {
for {
select {
case <-listenChan:
mockRpc.Request(&rpc_request.ConfigBatchListenRequest{})
done <- true
case <-ctx.Done():
return
}
}
}()
data1 := cacheData{
dataId: "dataId1",
group: "group1",
tenant: "",
taskId: 1,
isSyncWithServer: true,
}
key1 := util.GetConfigCacheKey(data1.dataId, data1.group, data1.tenant)
client.cacheMap.Set(key1, data1)
listener := NewConfigConnectionEventListener(client, "1")
initialData, _ := client.cacheMap.Get(key1)
assert.True(t, initialData.(cacheData).isSyncWithServer, "initial data should be sync with server")
listener.OnDisConnect()
afterDisconnectData, _ := client.cacheMap.Get(key1)
assert.False(t, afterDisconnectData.(cacheData).isSyncWithServer, "disconnect should set isSyncWithServer to false")
listener.OnConnected()
select {
case <-done:
case <-time.After(1 * time.Second):
t.Fatalf("wait for done timeout")
}
assert.NotNil(t, mockRpc.requestCalled, "should call request")
_, ok := mockRpc.requestCalled.(*rpc_request.ConfigBatchListenRequest)
assert.True(t, ok, "should be a ConfigBatchListenRequest")
}

View File

@ -17,26 +17,27 @@
package config_client
import (
"context"
"encoding/json"
"net/http"
"strconv"
"time"
"github.com/pkg/errors"
"github.com/nacos-group/nacos-sdk-go/v2/common/monitor"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
"github.com/nacos-group/nacos-sdk-go/v2/clients/cache"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
"github.com/nacos-group/nacos-sdk-go/v2/common/monitor"
"github.com/nacos-group/nacos-sdk-go/v2/common/nacos_server"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
"github.com/nacos-group/nacos-sdk-go/v2/model"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
"github.com/pkg/errors"
)
type ConfigProxy struct {
@ -44,22 +45,22 @@ type ConfigProxy struct {
clientConfig constant.ClientConfig
}
func NewConfigProxy(ctx context.Context, serverConfig []constant.ServerConfig, clientConfig constant.ClientConfig, httpAgent http_agent.IHttpAgent) (IConfigProxy, error) {
return NewConfigProxyWithRamCredentialProvider(ctx, serverConfig, clientConfig, httpAgent, nil)
}
func NewConfigProxyWithRamCredentialProvider(ctx context.Context, serverConfig []constant.ServerConfig, clientConfig constant.ClientConfig, httpAgent http_agent.IHttpAgent, provider security.RamCredentialProvider) (IConfigProxy, error) {
func NewConfigProxy(serverConfig []constant.ServerConfig, clientConfig constant.ClientConfig, httpAgent http_agent.IHttpAgent) (IConfigProxy, error) {
proxy := ConfigProxy{}
var err error
proxy.nacosServer, err = nacos_server.NewNacosServerWithRamCredentialProvider(ctx, serverConfig, clientConfig, httpAgent, clientConfig.TimeoutMs, clientConfig.Endpoint, nil, provider)
proxy.nacosServer, err = nacos_server.NewNacosServer(serverConfig, clientConfig, httpAgent, clientConfig.TimeoutMs, clientConfig.Endpoint)
proxy.clientConfig = clientConfig
return &proxy, err
}
func (cp *ConfigProxy) requestProxy(rpcClient *rpc.RpcClient, request rpc_request.IRequest, timeoutMills uint64) (rpc_response.IResponse, error) {
start := time.Now()
cp.nacosServer.InjectSecurityInfo(request.GetHeaders(), security.BuildConfigResourceByRequest(request))
cp.nacosServer.InjectSecurityInfo(request.GetHeaders())
cp.injectCommHeader(request.GetHeaders())
cp.nacosServer.InjectSkAk(request.GetHeaders(), cp.clientConfig)
signHeaders := nacos_server.GetSignHeadersFromRequest(request.(rpc_request.IConfigRequest), cp.clientConfig.SecretKey)
request.PutAllHeaders(signHeaders)
//todo Config Limiter
response, err := rpcClient.Request(request, int64(timeoutMills))
monitor.GetConfigRequestMonitor(constant.GRPC, request.GetRequestType(), rpc_response.GetGrpcResponseStatusCode(response)).Observe(float64(time.Now().Nanosecond() - start.Nanosecond()))
return response, err
@ -74,7 +75,7 @@ func (cp *ConfigProxy) injectCommHeader(param map[string]string) {
param[constant.CHARSET_KEY] = "utf-8"
}
func (cp *ConfigProxy) searchConfigProxy(param vo.SearchConfigParam, tenant, accessKey, secretKey string) (*model.ConfigPage, error) {
func (cp *ConfigProxy) searchConfigProxy(param vo.SearchConfigParm, tenant, accessKey, secretKey string) (*model.ConfigPage, error) {
params := util.TransformObject2Param(param)
if len(tenant) > 0 {
params["tenant"] = tenant
@ -86,27 +87,14 @@ func (cp *ConfigProxy) searchConfigProxy(param vo.SearchConfigParam, tenant, acc
params["dataId"] = ""
}
var headers = map[string]string{}
var version = "v2"
headers["accessKey"] = accessKey
headers["secretKey"] = secretKey
result, err := cp.nacosServer.ReqConfigApi(constant.CONFIG_PATH, params, headers, http.MethodGet, cp.clientConfig.TimeoutMs)
if err != nil {
if len(tenant) > 0 {
params["namespaceId"] = params["tenant"]
}
params["groupName"] = params["group"]
result, err = cp.nacosServer.ReqConfigApi("/v3/admin/cs/config/list", params, headers, http.MethodGet, cp.clientConfig.TimeoutMs)
if err != nil {
return nil, err
}
version = "v3"
return nil, err
}
var configPage model.ConfigPage
if version == "v2" {
err = json.Unmarshal([]byte(result), &configPage)
} else {
var configPageResult model.ConfigPageResult
err = json.Unmarshal([]byte(result), &configPageResult)
configPage = configPageResult.Data
}
err = json.Unmarshal([]byte(result), &configPage)
if err != nil {
return nil, err
}
@ -134,8 +122,9 @@ func (cp *ConfigProxy) queryConfig(dataId, group, tenant string, timeout uint64,
return nil, errors.New("ConfigQueryRequest returns type error")
}
if response.IsSuccess() {
//todo LocalConfigInfoProcessor.saveSnapshot
cache.WriteConfigToFile(cacheKey, cp.clientConfig.CacheDir, response.Content)
cache.WriteEncryptedDataKeyToFile(cacheKey, cp.clientConfig.CacheDir, response.EncryptedDataKey)
//todo LocalConfigInfoProcessor.saveEncryptDataKeySnapshot
if response.ContentType == "" {
response.ContentType = "text"
}
@ -143,9 +132,9 @@ func (cp *ConfigProxy) queryConfig(dataId, group, tenant string, timeout uint64,
}
if response.GetErrorCode() == 300 {
//todo LocalConfigInfoProcessor.saveSnapshot
cache.WriteConfigToFile(cacheKey, cp.clientConfig.CacheDir, "")
cache.WriteEncryptedDataKeyToFile(cacheKey, cp.clientConfig.CacheDir, "")
response.SetSuccess(true)
//todo LocalConfigInfoProcessor.saveEncryptDataKeySnapshot
return response, nil
}
@ -163,33 +152,20 @@ func (cp *ConfigProxy) queryConfig(dataId, group, tenant string, timeout uint64,
return response, nil
}
func appName(client *ConfigClient) string {
if clientConfig, err := client.GetClientConfig(); err == nil {
appName := clientConfig.AppName
return appName
}
return "unknown"
}
func (cp *ConfigProxy) createRpcClient(ctx context.Context, taskId string, client *ConfigClient) *rpc.RpcClient {
func (cp *ConfigProxy) createRpcClient(taskId string, client *ConfigClient) *rpc.RpcClient {
labels := map[string]string{
constant.LABEL_SOURCE: constant.LABEL_SOURCE_SDK,
constant.LABEL_MODULE: constant.LABEL_MODULE_CONFIG,
constant.APPNAME_HEADER: appName(client),
"taskId": taskId,
constant.LABEL_SOURCE: constant.LABEL_SOURCE_SDK,
constant.LABEL_MODULE: constant.LABEL_MODULE_CONFIG,
"taskId": taskId,
}
iRpcClient, _ := rpc.CreateClient(ctx, "config-"+taskId+"-"+client.uid, rpc.GRPC, labels, cp.nacosServer, &cp.clientConfig.TLSCfg, cp.clientConfig.AppConnLabels)
iRpcClient, _ := rpc.CreateClient("config-"+taskId+"-"+client.uid, rpc.GRPC, labels, cp.nacosServer)
rpcClient := iRpcClient.GetRpcClient()
if rpcClient.IsInitialized() {
rpcClient.RegisterServerRequestHandler(func() rpc_request.IRequest {
// TODO fix the group/dataId empty problem
return rpc_request.NewConfigChangeNotifyRequest("", "", "")
}, &ConfigChangeNotifyRequestHandler{client: client})
configListener := NewConfigConnectionEventListener(client, taskId)
rpcClient.RegisterConnectionListener(configListener)
rpcClient.Tenant = cp.clientConfig.NamespaceId
rpcClient.Start()
}
@ -197,7 +173,7 @@ func (cp *ConfigProxy) createRpcClient(ctx context.Context, taskId string, clien
}
func (cp *ConfigProxy) getRpcClient(client *ConfigClient) *rpc.RpcClient {
return cp.createRpcClient(client.ctx, "0", client)
return cp.createRpcClient("0", client)
}
type ConfigChangeNotifyRequestHandler struct {
@ -210,23 +186,22 @@ func (c *ConfigChangeNotifyRequestHandler) Name() string {
func (c *ConfigChangeNotifyRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *rpc.RpcClient) rpc_response.IResponse {
configChangeNotifyRequest, ok := request.(*rpc_request.ConfigChangeNotifyRequest)
if !ok {
return nil
}
logger.Infof("%s [server-push] config changed. dataId=%s, group=%s,tenant=%s", rpcClient.Name(),
configChangeNotifyRequest.DataId, configChangeNotifyRequest.Group, configChangeNotifyRequest.Tenant)
if ok {
logger.Infof("%s [server-push] config changed. dataId=%s, group=%s,tenant=%s", rpcClient.Name,
configChangeNotifyRequest.DataId, configChangeNotifyRequest.Group, configChangeNotifyRequest.Tenant)
cacheKey := util.GetConfigCacheKey(configChangeNotifyRequest.DataId, configChangeNotifyRequest.Group,
configChangeNotifyRequest.Tenant)
data, ok := c.client.cacheMap.Get(cacheKey)
if !ok {
return nil
}
cData := data.(cacheData)
cData.isSyncWithServer = false
c.client.cacheMap.Set(cacheKey, cData)
c.client.asyncNotifyListenConfig()
return &rpc_response.NotifySubscriberResponse{
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS},
cacheKey := util.GetConfigCacheKey(configChangeNotifyRequest.DataId, configChangeNotifyRequest.Group,
configChangeNotifyRequest.Tenant)
data, ok := c.client.cacheMap.Get(cacheKey)
if !ok {
return nil
}
cData := data.(*cacheData)
cData.isSyncWithServer = false
c.client.notifyListenConfig()
return &rpc_response.NotifySubscriberResponse{
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS},
}
}
return nil
}

View File

@ -1,8 +1,6 @@
package config_client
import (
"context"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
@ -12,8 +10,8 @@ import (
type IConfigProxy interface {
queryConfig(dataId, group, tenant string, timeout uint64, notify bool, client *ConfigClient) (*rpc_response.ConfigQueryResponse, error)
searchConfigProxy(param vo.SearchConfigParam, tenant, accessKey, secretKey string) (*model.ConfigPage, error)
searchConfigProxy(param vo.SearchConfigParm, tenant, accessKey, secretKey string) (*model.ConfigPage, error)
requestProxy(rpcClient *rpc.RpcClient, request rpc_request.IRequest, timeoutMills uint64) (rpc_response.IResponse, error)
createRpcClient(ctx context.Context, taskId string, client *ConfigClient) *rpc.RpcClient
createRpcClient(taskId string, client *ConfigClient) *rpc.RpcClient
getRpcClient(client *ConfigClient) *rpc.RpcClient
}

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package config_client
import (

View File

@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package config_client
import (

View File

@ -17,6 +17,7 @@
package nacos_client
import (
"log"
"os"
"strconv"
@ -35,7 +36,7 @@ type NacosClient struct {
serverConfigs []constant.ServerConfig
}
// SetClientConfig is use to set nacos client Config
//SetClientConfig is use to set nacos client Config
func (client *NacosClient) SetClientConfig(config constant.ClientConfig) (err error) {
if config.TimeoutMs <= 0 {
config.TimeoutMs = 10 * 1000
@ -60,14 +61,14 @@ func (client *NacosClient) SetClientConfig(config constant.ClientConfig) (err er
if config.LogDir == "" {
config.LogDir = file.GetCurrentPath() + string(os.PathSeparator) + "log"
}
log.Printf("[INFO] logDir:<%s> cacheDir:<%s>", config.LogDir, config.CacheDir)
client.clientConfig = config
client.clientConfigValid = true
return
}
// SetServerConfig is use to set nacos server config
//SetServerConfig is use to set nacos server config
func (client *NacosClient) SetServerConfig(configs []constant.ServerConfig) (err error) {
if len(configs) <= 0 {
//it's may be use endpoint to get nacos server address
@ -92,7 +93,7 @@ func (client *NacosClient) SetServerConfig(configs []constant.ServerConfig) (err
return
}
// GetClientConfig use to get client config
//GetClientConfig use to get client config
func (client *NacosClient) GetClientConfig() (config constant.ClientConfig, err error) {
config = client.clientConfig
if !client.clientConfigValid {
@ -101,7 +102,7 @@ func (client *NacosClient) GetClientConfig() (config constant.ClientConfig, err
return
}
// GetServerConfig use to get server config
//GetServerConfig use to get server config
func (client *NacosClient) GetServerConfig() (configs []constant.ServerConfig, err error) {
configs = client.serverConfigs
if !client.serverConfigsValid {
@ -110,7 +111,7 @@ func (client *NacosClient) GetServerConfig() (configs []constant.ServerConfig, e
return
}
// SetHttpAgent use to set http agent
//SetHttpAgent use to set http agent
func (client *NacosClient) SetHttpAgent(agent http_agent.IHttpAgent) (err error) {
if agent == nil {
err = errors.New("[client.SetHttpAgent] http agent can not be nil")
@ -120,7 +121,7 @@ func (client *NacosClient) SetHttpAgent(agent http_agent.IHttpAgent) (err error)
return
}
// GetHttpAgent use to get http agent
//GetHttpAgent use to get http agent
func (client *NacosClient) GetHttpAgent() (agent http_agent.IHttpAgent, err error) {
if client.agent == nil {
err = errors.New("[client.GetHttpAgent] invalid http agent")

View File

@ -17,12 +17,12 @@
package naming_cache
import (
"fmt"
"os"
"reflect"
"sort"
"strconv"
"strings"
"sync"
"github.com/nacos-group/nacos-sdk-go/v2/clients/cache"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
@ -32,12 +32,12 @@ import (
)
type ServiceInfoHolder struct {
ServiceInfoMap sync.Map
ServiceInfoMap cache.ConcurrentMap
updateCacheWhenEmpty bool
cacheDir string
notLoadCacheAtStart bool
subCallback *SubscribeCallback
UpdateTimeMap sync.Map
UpdateTimeMap cache.ConcurrentMap
}
func NewServiceInfoHolder(namespace, cacheDir string, updateCacheWhenEmpty, notLoadCacheAtStart bool) *ServiceInfoHolder {
@ -47,8 +47,8 @@ func NewServiceInfoHolder(namespace, cacheDir string, updateCacheWhenEmpty, notL
notLoadCacheAtStart: notLoadCacheAtStart,
cacheDir: cacheDir,
subCallback: NewSubscribeCallback(),
UpdateTimeMap: sync.Map{},
ServiceInfoMap: sync.Map{},
UpdateTimeMap: cache.NewConcurrentMap(),
ServiceInfoMap: cache.NewConcurrentMap(),
}
if !notLoadCacheAtStart {
@ -63,7 +63,7 @@ func (s *ServiceInfoHolder) loadCacheFromDisk() {
return
}
for k, v := range serviceMap {
s.ServiceInfoMap.Store(k, v)
s.ServiceInfoMap.Set(k, v)
}
}
@ -84,48 +84,43 @@ func (s *ServiceInfoHolder) ProcessService(service *model.Service) {
}
cacheKey := util.GetServiceCacheKey(util.GetGroupName(service.Name, service.GroupName), service.Clusters)
oldDomain, ok := s.ServiceInfoMap.Load(cacheKey)
oldDomain, ok := s.ServiceInfoMap.Get(cacheKey)
if ok && oldDomain.(model.Service).LastRefTime >= service.LastRefTime {
logger.Warnf("out of date data received, old-t: %d, new-t: %d", oldDomain.(model.Service).LastRefTime, service.LastRefTime)
return
}
s.UpdateTimeMap.Store(cacheKey, uint64(util.CurrentMillis()))
s.ServiceInfoMap.Store(cacheKey, *service)
s.UpdateTimeMap.Set(cacheKey, uint64(util.CurrentMillis()))
s.ServiceInfoMap.Set(cacheKey, *service)
if !ok || checkInstanceChanged(oldDomain, *service) {
logger.Infof("service key:%s was updated to:%s", cacheKey, util.ToJsonString(service))
cache.WriteServicesToFile(service, cacheKey, s.cacheDir)
s.subCallback.ServiceChanged(cacheKey, service)
}
var count int
s.ServiceInfoMap.Range(func(key, value interface{}) bool {
count++
return true
})
monitor.GetServiceInfoMapSizeMonitor().Set(float64(count))
monitor.GetServiceInfoMapSizeMonitor().Set(float64(s.ServiceInfoMap.Count()))
}
func (s *ServiceInfoHolder) GetServiceInfo(serviceName, groupName, clusters string) (model.Service, bool) {
cacheKey := util.GetServiceCacheKey(util.GetGroupName(serviceName, groupName), clusters)
//todo FailoverReactor
service, ok := s.ServiceInfoMap.Load(cacheKey)
service, ok := s.ServiceInfoMap.Get(cacheKey)
if ok {
return service.(model.Service), ok
}
return model.Service{}, ok
}
func (s *ServiceInfoHolder) RegisterCallback(serviceName string, clusters string, callbackWrapper *SubscribeCallbackFuncWrapper) {
s.subCallback.AddCallbackFunc(serviceName, clusters, callbackWrapper)
func (s *ServiceInfoHolder) RegisterCallback(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
s.subCallback.AddCallbackFunc(serviceName, clusters, callbackFunc)
}
func (s *ServiceInfoHolder) DeregisterCallback(serviceName string, clusters string, callbackWrapper *SubscribeCallbackFuncWrapper) {
s.subCallback.RemoveCallbackFunc(serviceName, clusters, callbackWrapper)
func (s *ServiceInfoHolder) DeregisterCallback(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
s.subCallback.RemoveCallbackFunc(serviceName, clusters, callbackFunc)
}
func (s *ServiceInfoHolder) StopUpdateIfContain(serviceName, clusters string) {
cacheKey := util.GetServiceCacheKey(serviceName, clusters)
s.ServiceInfoMap.Delete(cacheKey)
s.ServiceInfoMap.Remove(cacheKey)
}
func (s *ServiceInfoHolder) IsSubscribed(serviceName, clusters string) bool {
@ -151,7 +146,7 @@ func isServiceInstanceChanged(oldService, newService model.Service) bool {
oldRefTime := oldService.LastRefTime
newRefTime := newService.LastRefTime
if oldRefTime > newRefTime {
logger.Warnf("out of date data received, old-t: %v , new-t: %v", oldRefTime, newRefTime)
logger.Warn(fmt.Sprintf("out of date data received, old-t: %v , new-t: %v", oldRefTime, newRefTime))
return false
}
// sort instance list

View File

@ -19,6 +19,8 @@ package naming_cache
import (
"sync"
"github.com/pkg/errors"
"github.com/nacos-group/nacos-sdk-go/v2/clients/cache"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
"github.com/nacos-group/nacos-sdk-go/v2/model"
@ -36,34 +38,31 @@ func NewSubscribeCallback() *SubscribeCallback {
func (ed *SubscribeCallback) IsSubscribed(serviceName, clusters string) bool {
key := util.GetServiceCacheKey(serviceName, clusters)
funcs, ok := ed.callbackFuncMap.Get(key)
if ok {
return len(funcs.([]*SubscribeCallbackFuncWrapper)) > 0
}
return false
_, ok := ed.callbackFuncMap.Get(key)
return ok
}
func (ed *SubscribeCallback) AddCallbackFunc(serviceName string, clusters string, callbackWrapper *SubscribeCallbackFuncWrapper) {
func (ed *SubscribeCallback) AddCallbackFunc(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
key := util.GetServiceCacheKey(serviceName, clusters)
ed.mux.Lock()
defer ed.mux.Unlock()
var funcSlice []*SubscribeCallbackFuncWrapper
ed.mux.Lock()
var funcSlice []*func(services []model.Instance, err error)
old, ok := ed.callbackFuncMap.Get(key)
if ok {
funcSlice = append(funcSlice, old.([]*SubscribeCallbackFuncWrapper)...)
funcSlice = append(funcSlice, old.([]*func(services []model.Instance, err error))...)
}
funcSlice = append(funcSlice, callbackWrapper)
funcSlice = append(funcSlice, callbackFunc)
ed.callbackFuncMap.Set(key, funcSlice)
}
func (ed *SubscribeCallback) RemoveCallbackFunc(serviceName string, clusters string, callbackWrapper *SubscribeCallbackFuncWrapper) {
func (ed *SubscribeCallback) RemoveCallbackFunc(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
logger.Info("removing " + serviceName + " with " + clusters + " to listener map")
key := util.GetServiceCacheKey(serviceName, clusters)
funcs, ok := ed.callbackFuncMap.Get(key)
if ok && funcs != nil {
var newFuncs []*SubscribeCallbackFuncWrapper
for _, funcItem := range funcs.([]*SubscribeCallbackFuncWrapper) {
if funcItem.CallbackFunc != callbackWrapper.CallbackFunc || !funcItem.Selector.Equals(callbackWrapper.Selector) {
var newFuncs []*func(services []model.Instance, err error)
for _, funcItem := range funcs.([]*func(services []model.Instance, err error)) {
if funcItem != callbackFunc {
newFuncs = append(newFuncs, funcItem)
}
}
@ -75,8 +74,12 @@ func (ed *SubscribeCallback) RemoveCallbackFunc(serviceName string, clusters str
func (ed *SubscribeCallback) ServiceChanged(cacheKey string, service *model.Service) {
funcs, ok := ed.callbackFuncMap.Get(cacheKey)
if ok {
for _, funcItem := range funcs.([]*SubscribeCallbackFuncWrapper) {
funcItem.notifyListener(service)
for _, funcItem := range funcs.([]*func(services []model.Instance, err error)) {
if len(service.Hosts) == 0 {
(*funcItem)(service.Hosts, errors.New("[client.Subscribe] subscribe failed,hosts is empty"))
continue
}
(*funcItem)(service.Hosts, nil)
}
}
}

View File

@ -58,15 +58,13 @@ func TestEventDispatcher_AddCallbackFuncs(t *testing.T) {
fmt.Println(util.ToJsonString(ed.callbackFuncMap))
},
}
clusterSelector := NewClusterSelector(param.Clusters)
callbackWrapper := NewSubscribeCallbackFuncWrapper(clusterSelector, &param.SubscribeCallback)
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), callbackWrapper)
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), &param.SubscribeCallback)
key := util.GetServiceCacheKey(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
for k, v := range ed.callbackFuncMap.Items() {
assert.Equal(t, key, k, "key should be equal!")
funcs := v.([]*SubscribeCallbackFuncWrapper)
funcs := v.([]*func(services []model.Instance, err error))
assert.Equal(t, len(funcs), 1)
assert.Equal(t, funcs[0].CallbackFunc, &param.SubscribeCallback, "callback function must be equal!")
assert.Equal(t, funcs[0], &param.SubscribeCallback, "callback function must be equal!")
}
}
@ -100,9 +98,7 @@ func TestEventDispatcher_RemoveCallbackFuncs(t *testing.T) {
fmt.Printf("func1:%s \n", util.ToJsonString(services))
},
}
clusterSelector := NewClusterSelector(param.Clusters)
callbackWrapper := NewSubscribeCallbackFuncWrapper(clusterSelector, &param.SubscribeCallback)
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), callbackWrapper)
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), &param.SubscribeCallback)
assert.Equal(t, len(ed.callbackFuncMap.Items()), 1, "callback funcs map length should be 1")
param2 := vo.SubscribeParam{
@ -113,23 +109,21 @@ func TestEventDispatcher_RemoveCallbackFuncs(t *testing.T) {
fmt.Printf("func2:%s \n", util.ToJsonString(services))
},
}
clusterSelector2 := NewClusterSelector(param2.Clusters)
callbackWrapper2 := NewSubscribeCallbackFuncWrapper(clusterSelector2, &param2.SubscribeCallback)
ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), callbackWrapper2)
ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), &param2.SubscribeCallback)
assert.Equal(t, len(ed.callbackFuncMap.Items()), 1, "callback funcs map length should be 2")
for k, v := range ed.callbackFuncMap.Items() {
log.Printf("key:%s,%d", k, len(v.([]*SubscribeCallbackFuncWrapper)))
log.Printf("key:%s,%d", k, len(v.([]*func(services []model.Instance, err error))))
}
ed.RemoveCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), callbackWrapper2)
ed.RemoveCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), &param2.SubscribeCallback)
key := util.GetServiceCacheKey(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
for k, v := range ed.callbackFuncMap.Items() {
assert.Equal(t, key, k, "key should be equal!")
funcs := v.([]*SubscribeCallbackFuncWrapper)
funcs := v.([]*func(services []model.Instance, err error))
assert.Equal(t, len(funcs), 1)
assert.Equal(t, funcs[0].CallbackFunc, &param.SubscribeCallback, "callback function must be equal!")
assert.Equal(t, funcs[0], &param.SubscribeCallback, "callback function must be equal!")
}
}
@ -164,9 +158,7 @@ func TestSubscribeCallback_ServiceChanged(t *testing.T) {
log.Printf("func1:%s \n", util.ToJsonString(services))
},
}
clusterSelector := NewClusterSelector(param.Clusters)
callbackWrapper := NewSubscribeCallbackFuncWrapper(clusterSelector, &param.SubscribeCallback)
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), callbackWrapper)
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), &param.SubscribeCallback)
param2 := vo.SubscribeParam{
ServiceName: "Test",
@ -177,54 +169,7 @@ func TestSubscribeCallback_ServiceChanged(t *testing.T) {
},
}
clusterSelector2 := NewClusterSelector(param2.Clusters)
callbackWrapper2 := NewSubscribeCallbackFuncWrapper(clusterSelector2, &param2.SubscribeCallback)
ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), callbackWrapper2)
ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), &param2.SubscribeCallback)
cacheKey := util.GetServiceCacheKey(util.GetGroupName(service.Name, service.GroupName), service.Clusters)
ed.ServiceChanged(cacheKey, &service)
}
func TestSubscribeCallback_RemoveCallbackFunc(t *testing.T) {
ed := NewSubscribeCallback()
serviceName := "Test"
clusters := "default"
groupName := "public"
callback1 := func(services []model.Instance, err error) {
log.Printf("callback1:%s \n", util.ToJsonString(services))
}
clusterSelector1 := NewClusterSelector([]string{clusters})
callbackWrapper1 := NewSubscribeCallbackFuncWrapper(clusterSelector1, &callback1)
callback2 := func(services []model.Instance, err error) {
log.Printf("callback2:%s \n", util.ToJsonString(services))
}
clusterSelector2 := NewClusterSelector([]string{clusters})
callbackWrapper2 := NewSubscribeCallbackFuncWrapper(clusterSelector2, &callback2)
// Add both callbacks
ed.AddCallbackFunc(util.GetGroupName(serviceName, groupName), clusters, callbackWrapper1)
ed.AddCallbackFunc(util.GetGroupName(serviceName, groupName), clusters, callbackWrapper2)
assert.True(t, ed.IsSubscribed(util.GetGroupName(serviceName, groupName), clusters))
// Remove the first callback
ed.RemoveCallbackFunc(util.GetGroupName(serviceName, groupName), clusters, callbackWrapper1)
// Check if only the second callback remains
cacheKey := util.GetServiceCacheKey(util.GetGroupName(serviceName, groupName), clusters)
funcs, ok := ed.callbackFuncMap.Get(cacheKey)
if !ok || len(funcs.([]*SubscribeCallbackFuncWrapper)) != 1 {
t.Errorf("Expected 1 callback function, got %d", len(funcs.([]*SubscribeCallbackFuncWrapper)))
}
assert.True(t, ed.IsSubscribed(util.GetGroupName(serviceName, groupName), clusters))
// Remove the second callback
ed.RemoveCallbackFunc(util.GetGroupName(serviceName, groupName), clusters, callbackWrapper2)
// Check if no callbacks remain
funcs, ok = ed.callbackFuncMap.Get(cacheKey)
if ok && len(funcs.([]*SubscribeCallbackFuncWrapper)) != 0 {
t.Errorf("Expected 0 callback functions, got %d", len(funcs.([]*func(services []model.Instance, err error))))
}
assert.False(t, ed.IsSubscribed(util.GetGroupName(serviceName, groupName), clusters))
}

View File

@ -1,106 +0,0 @@
package naming_cache
import (
"sort"
"strings"
"github.com/nacos-group/nacos-sdk-go/v2/model"
"github.com/nacos-group/nacos-sdk-go/v2/util"
)
type Selector interface {
SelectInstance(service *model.Service) []model.Instance
Equals(o Selector) bool
}
type ClusterSelector struct {
ClusterNames string
Clusters []string
}
func NewClusterSelector(clusters []string) *ClusterSelector {
if len(clusters) == 0 {
return &ClusterSelector{
ClusterNames: "",
Clusters: []string{},
}
}
// 创建副本避免外部修改
clustersCopy := make([]string, len(clusters))
copy(clustersCopy, clusters)
return &ClusterSelector{
ClusterNames: joinCluster(clusters),
Clusters: clustersCopy,
}
}
func NewSubscribeCallbackFuncWrapper(selector Selector, callback *func(services []model.Instance, err error)) *SubscribeCallbackFuncWrapper {
if selector == nil {
panic("selector cannot be nil")
}
if callback == nil {
panic("callback cannot be nil")
}
return &SubscribeCallbackFuncWrapper{
Selector: selector,
CallbackFunc: callback,
}
}
type SubscribeCallbackFuncWrapper struct {
Selector Selector
CallbackFunc *func(services []model.Instance, err error)
}
func (ed *SubscribeCallbackFuncWrapper) notifyListener(service *model.Service) {
instances := ed.Selector.SelectInstance(service)
if ed.CallbackFunc != nil {
(*ed.CallbackFunc)(instances, nil)
}
}
func (cs *ClusterSelector) SelectInstance(service *model.Service) []model.Instance {
var instances []model.Instance
if cs.ClusterNames == "" {
return service.Hosts
}
for _, instance := range service.Hosts {
if util.Contains(cs.Clusters, instance.ClusterName) {
instances = append(instances, instance)
}
}
return instances
}
func (cs *ClusterSelector) Equals(o Selector) bool {
if o == nil {
return false
}
if o, ok := o.(*ClusterSelector); ok {
return cs.ClusterNames == o.ClusterNames
}
return false
}
func joinCluster(cluster []string) string {
// 使用map实现去重
uniqueSet := make(map[string]struct{})
for _, item := range cluster {
if item != "" { // 过滤空字符串类似Java中的isNotEmpty
uniqueSet[item] = struct{}{}
}
}
uniqueSlice := make([]string, 0, len(uniqueSet))
for item := range uniqueSet {
uniqueSlice = append(uniqueSlice, item)
}
sort.Strings(uniqueSlice)
// 使用逗号连接
return strings.Join(uniqueSlice, ",")
}

View File

@ -17,15 +17,11 @@
package naming_client
import (
"context"
"math"
"math/rand"
"strings"
"sync"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
"github.com/pkg/errors"
"github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client"
@ -41,24 +37,14 @@ import (
// NamingClient ...
type NamingClient struct {
nacos_client.INacosClient
ctx context.Context
cancel context.CancelFunc
serviceProxy naming_proxy.INamingProxy
serviceInfoHolder *naming_cache.ServiceInfoHolder
isClosed bool
mutex sync.Mutex
}
// NewNamingClient ...
func NewNamingClient(nc nacos_client.INacosClient) (*NamingClient, error) {
return NewNamingClientWithRamCredentialProvider(nc, nil)
}
// NewNamingClientWithRamCredentialProvider ...
func NewNamingClientWithRamCredentialProvider(nc nacos_client.INacosClient, provider security.RamCredentialProvider) (*NamingClient, error) {
ctx, cancel := context.WithCancel(context.Background())
rand.Seed(time.Now().UnixNano())
naming := &NamingClient{INacosClient: nc, ctx: ctx, cancel: cancel}
naming := &NamingClient{INacosClient: nc}
clientConfig, err := nc.GetClientConfig()
if err != nil {
return naming, err
@ -77,19 +63,15 @@ func NewNamingClientWithRamCredentialProvider(nc nacos_client.INacosClient, prov
if err = initLogger(clientConfig); err != nil {
return naming, err
}
if clientConfig.NamespaceId == "" {
clientConfig.NamespaceId = constant.DEFAULT_NAMESPACE_ID
}
naming.serviceInfoHolder = naming_cache.NewServiceInfoHolder(clientConfig.NamespaceId, clientConfig.CacheDir,
clientConfig.UpdateCacheWhenEmpty, clientConfig.NotLoadCacheAtStart)
naming.serviceProxy, err = NewNamingProxyDelegateWithRamCredentialProvider(ctx, clientConfig, serverConfig, httpAgent, naming.serviceInfoHolder, provider)
naming.serviceProxy, err = NewNamingProxyDelegate(clientConfig, serverConfig, httpAgent, naming.serviceInfoHolder)
if clientConfig.AsyncUpdateService {
go NewServiceInfoUpdater(ctx, naming.serviceInfoHolder, clientConfig.UpdateThreadNum, naming.serviceProxy).asyncUpdateService()
}
go NewServiceInfoUpdater(naming.serviceInfoHolder, clientConfig.UpdateThreadNum, naming.serviceProxy).asyncUpdateService()
if err != nil {
return naming, err
}
@ -122,37 +104,9 @@ func (sc *NamingClient) RegisterInstance(param vo.RegisterInstanceParam) (bool,
Weight: param.Weight,
Ephemeral: param.Ephemeral,
}
return sc.serviceProxy.RegisterInstance(param.ServiceName, param.GroupName, instance)
}
func (sc *NamingClient) BatchRegisterInstance(param vo.BatchRegisterInstanceParam) (bool, error) {
if param.ServiceName == "" {
return false, errors.New("serviceName cannot be empty!")
}
if len(param.GroupName) == 0 {
param.GroupName = constant.DEFAULT_GROUP
}
if len(param.Instances) == 0 {
return false, errors.New("instances cannot be empty!")
}
var modelInstances []model.Instance
for _, param := range param.Instances {
if !param.Ephemeral {
return false, errors.Errorf("Batch registration does not allow persistent instance registration! instance:%+v", param)
}
modelInstances = append(modelInstances, model.Instance{
Ip: param.Ip,
Port: param.Port,
Metadata: param.Metadata,
ClusterName: param.ClusterName,
Healthy: param.Healthy,
Enable: param.Enable,
Weight: param.Weight,
Ephemeral: param.Ephemeral,
})
}
return sc.serviceProxy.BatchRegisterInstance(param.ServiceName, param.GroupName, modelInstances)
}
// DeregisterInstance ...
@ -201,14 +155,11 @@ func (sc *NamingClient) GetService(param vo.GetServiceParam) (service model.Serv
param.GroupName = constant.DEFAULT_GROUP
}
var ok bool
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
clusters := strings.Join(param.Clusters, ",")
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, "")
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
if !ok {
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
}
service.Clusters = clusters
service.Hosts = clusterSelector.SelectInstance(&service)
return service, err
}
@ -234,24 +185,21 @@ func (sc *NamingClient) SelectAllInstances(param vo.SelectAllInstancesParam) ([]
if len(param.GroupName) == 0 {
param.GroupName = constant.DEFAULT_GROUP
}
clusters := strings.Join(param.Clusters, ",")
var (
service model.Service
ok bool
err error
)
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, "")
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
if !ok {
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
}
if err != nil {
if err != nil || service.Hosts == nil || len(service.Hosts) == 0 {
return []model.Instance{}, err
}
instances := clusterSelector.SelectInstance(&service)
if instances == nil || len(instances) == 0 {
return []model.Instance{}, err
}
return instances, err
return service.Hosts, err
}
// SelectInstances Get all instance by DataId, Group and Health
@ -264,15 +212,14 @@ func (sc *NamingClient) SelectInstances(param vo.SelectInstancesParam) ([]model.
ok bool
err error
)
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, "")
clusters := strings.Join(param.Clusters, ",")
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
if !ok {
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
if err != nil {
return nil, err
}
}
service.Hosts = clusterSelector.SelectInstance(&service)
return sc.selectInstances(service, param.HealthyOnly)
}
@ -282,7 +229,6 @@ func (sc *NamingClient) selectInstances(service model.Service, healthy bool) ([]
}
hosts := service.Hosts
var result []model.Instance
logger.Infof("select instances with options: [healthy:<%t>], with service:<%s>", healthy, util.GetGroupName(service.Name, service.GroupName))
for _, host := range hosts {
if host.Healthy == healthy && host.Enable && host.Weight > 0 {
result = append(result, host)
@ -301,15 +247,15 @@ func (sc *NamingClient) SelectOneHealthyInstance(param vo.SelectOneHealthInstanc
ok bool
err error
)
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, "")
clusters := strings.Join(param.Clusters, ",")
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
if !ok {
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
if err != nil {
return nil, err
}
}
service.Hosts = clusterSelector.SelectInstance(&service)
return sc.selectOneHealthyInstances(service)
}
@ -342,40 +288,25 @@ func (sc *NamingClient) Subscribe(param *vo.SubscribeParam) error {
if len(param.GroupName) == 0 {
param.GroupName = constant.DEFAULT_GROUP
}
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
callbackWrapper := naming_cache.NewSubscribeCallbackFuncWrapper(clusterSelector, &param.SubscribeCallback)
sc.serviceInfoHolder.RegisterCallback(util.GetGroupName(param.ServiceName, param.GroupName), "", callbackWrapper)
_, err := sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
clusters := strings.Join(param.Clusters, ",")
sc.serviceInfoHolder.RegisterCallback(util.GetGroupName(param.ServiceName, param.GroupName), clusters, &param.SubscribeCallback)
_, err := sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
return err
}
// Unsubscribe ...
func (sc *NamingClient) Unsubscribe(param *vo.SubscribeParam) (err error) {
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
callbackWrapper := naming_cache.NewSubscribeCallbackFuncWrapper(clusterSelector, &param.SubscribeCallback)
clusters := strings.Join(param.Clusters, ",")
serviceFullName := util.GetGroupName(param.ServiceName, param.GroupName)
sc.serviceInfoHolder.DeregisterCallback(serviceFullName, "", callbackWrapper)
if !sc.serviceInfoHolder.IsSubscribed(serviceFullName, "") {
err = sc.serviceProxy.Unsubscribe(param.ServiceName, param.GroupName, "")
sc.serviceInfoHolder.DeregisterCallback(serviceFullName, clusters, &param.SubscribeCallback)
if sc.serviceInfoHolder.IsSubscribed(serviceFullName, clusters) {
err = sc.serviceProxy.Unsubscribe(param.ServiceName, param.GroupName, clusters)
}
return err
}
// ServerHealthy ...
func (sc *NamingClient) ServerHealthy() bool {
return sc.serviceProxy.ServerHealthy()
}
// CloseClient ...
func (sc *NamingClient) CloseClient() {
sc.mutex.Lock()
defer sc.mutex.Unlock()
if sc.isClosed {
return
}
sc.serviceProxy.CloseClient()
sc.cancel()
sc.isClosed = true
}

View File

@ -39,13 +39,6 @@ type INamingClient interface {
// Ephemeral optional
RegisterInstance(param vo.RegisterInstanceParam) (bool, error)
// BatchRegisterInstance use to batch register instance
// ClusterName optional,default:DEFAULT
// ServiceName require
// GroupName optional,default:DEFAULT_GROUP
// Instances require,batch register instance list (serviceName, groupName in instances do not need to be set)
BatchRegisterInstance(param vo.BatchRegisterInstanceParam) (bool, error)
// DeregisterInstance use to deregister instance
// Ip required
// Port required
@ -112,9 +105,6 @@ type INamingClient interface {
// GetAllServicesInfo use to get all service info by page
GetAllServicesInfo(param vo.GetAllServiceInfoParam) (model.ServiceList, error)
// ServerHealthy use to check the connectivity to server
ServerHealthy() bool
//CloseClient close the GRPC client
CloseClient()
}

View File

@ -37,18 +37,12 @@ var clientConfigTest = *constant.NewClientConfig(
var serverConfigTest = *constant.NewServerConfig("127.0.0.1", 80, constant.WithContextPath("/nacos"))
type MockNamingProxy struct {
unsubscribeCalled bool
unsubscribeParams []string // 记录调用参数
}
func (m *MockNamingProxy) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
return true, nil
}
func (m *MockNamingProxy) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) {
return true, nil
}
func (m *MockNamingProxy) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
return true, nil
}
@ -70,8 +64,6 @@ func (m *MockNamingProxy) Subscribe(serviceName, groupName, clusters string) (mo
}
func (m *MockNamingProxy) Unsubscribe(serviceName, groupName, clusters string) error {
m.unsubscribeCalled = true
m.unsubscribeParams = []string{serviceName, groupName, clusters}
return nil
}
@ -456,108 +448,3 @@ func BenchmarkNamingClient_SelectOneHealthyInstances(b *testing.B) {
}
}
func TestNamingClient_Unsubscribe_WithCallback_ShouldNotCallServiceProxyUnsubscribe(t *testing.T) {
// 创建一个带有回调函数的订阅参数
callback := func(services []model.Instance, err error) {
// 空回调函数
}
param := &vo.SubscribeParam{
ServiceName: "test-service",
GroupName: "test-group",
Clusters: []string{"test-cluster"},
SubscribeCallback: callback,
}
// 创建测试客户端
client := NewTestNamingClient()
mockProxy := client.serviceProxy.(*MockNamingProxy)
// 执行 Unsubscribe
err := client.Unsubscribe(param)
// 验证没有错误
assert.Nil(t, err)
assert.True(t, mockProxy.unsubscribeCalled)
}
func TestNamingClient_Unsubscribe_WithoutCallback_ShouldCallServiceProxyUnsubscribe(t *testing.T) {
// 创建一个没有回调函数的订阅参数
param := &vo.SubscribeParam{
ServiceName: "test-service",
GroupName: "test-group",
Clusters: []string{"test-cluster"},
// SubscribeCallback 为 nil
}
// 创建测试客户端
client := NewTestNamingClient()
// 获取原始的 MockNamingProxy 来检查调用状态
mockProxy := client.serviceProxy.(*MockNamingProxy)
// 执行 Unsubscribe
err := client.Unsubscribe(param)
// 验证没有错误
assert.Nil(t, err)
assert.True(t, mockProxy.unsubscribeCalled)
}
// TestNamingClient_Unsubscribe_Integration_Test 集成测试,使用真实的 ServiceInfoHolder 来测试修复后的逻辑
func TestNamingClient_Unsubscribe_Integration_Test(t *testing.T) {
// 创建测试客户端
client := NewTestNamingClient()
// 获取原始的 MockNamingProxy 来检查调用状态
mockProxy := client.serviceProxy.(*MockNamingProxy)
// 创建回调函数
callback1 := func(services []model.Instance, err error) {
// 回调函数1
}
callback2 := func(services []model.Instance, err error) {
// 回调函数2
}
// 测试场景1先注册两个回调函数然后取消订阅第一个
// 这种情况下,取消订阅第一个回调函数后,还有其他回调函数,所以不应该调用 serviceProxy.Unsubscribe
// 注册第一个回调函数
param1 := &vo.SubscribeParam{
ServiceName: "test-service",
GroupName: "test-group",
Clusters: []string{"test-cluster"},
SubscribeCallback: callback1,
}
// 注册第二个回调函数
param2 := &vo.SubscribeParam{
ServiceName: "test-service",
GroupName: "test-group",
Clusters: []string{"test-cluster"},
SubscribeCallback: callback2,
}
// 先注册两个回调函数
err := client.Subscribe(param1)
assert.Nil(t, err)
err = client.Subscribe(param2)
assert.Nil(t, err)
// 重置 MockNamingProxy 的调用状态
mockProxy.unsubscribeCalled = false
mockProxy.unsubscribeParams = nil
// 取消订阅第一个回调函数
err = client.Unsubscribe(param1)
assert.Nil(t, err)
assert.False(t, mockProxy.unsubscribeCalled)
// 取消订阅第二个回调函数
err = client.Unsubscribe(param2)
assert.Nil(t, err)
assert.True(t, mockProxy.unsubscribeCalled)
}

View File

@ -17,6 +17,7 @@
package naming_grpc
import (
"reflect"
"strings"
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_proxy"
@ -52,11 +53,6 @@ func (c *ConnectionEventListener) OnDisConnect() {
}
func (c *ConnectionEventListener) redoSubscribe() {
grpcProxy, ok := c.clientProxy.(*NamingGrpcProxy)
if !ok {
logger.Error("redo subscribe clientProxy type error")
return
}
for _, key := range c.subscribes.Keys() {
info := strings.Split(key, constant.SERVICE_INFO_SPLITER)
var err error
@ -66,9 +62,15 @@ func (c *ConnectionEventListener) redoSubscribe() {
} else {
service, err = c.clientProxy.Subscribe(info[1], info[0], "")
}
if err != nil {
logger.Warnf("redo subscribe service:%s faild:%+v", info[1], err)
continue
return
}
grpcProxy, ok := c.clientProxy.(*NamingGrpcProxy)
if !ok {
return
}
grpcProxy.serviceInfoHolder.ProcessService(&service)
}
@ -79,31 +81,27 @@ func (c *ConnectionEventListener) redoRegisterEachService() {
info := strings.Split(k, constant.SERVICE_INFO_SPLITER)
serviceName := info[1]
groupName := info[0]
if instance, ok := v.(model.Instance); ok {
if _, err := c.clientProxy.RegisterInstance(serviceName, groupName, instance); err != nil {
logger.Warnf("redo register service:%s groupName:%s faild:%s", info[1], info[0], err.Error())
continue
}
instance, ok := v.(model.Instance)
if !ok {
logger.Warnf("redo register service:%s faild,instances type not is model.instance", info[1])
return
}
if instances, ok := v.([]model.Instance); ok {
if _, err := c.clientProxy.BatchRegisterInstance(serviceName, groupName, instances); err != nil {
logger.Warnf("redo batch register service:%s groupName:%s faild:%s", info[1], info[0], err.Error())
continue
}
_, err := c.clientProxy.RegisterInstance(serviceName, groupName, instance)
if err != nil {
logger.Warnf("redo register service:%s groupName:%s faild:%s", info[1], info[0], err.Error())
}
}
}
func (c *ConnectionEventListener) CacheInstanceForRedo(serviceName, groupName string, instance model.Instance) {
key := util.GetGroupName(serviceName, groupName)
getInstance, _ := c.registeredInstanceCached.Get(key)
if getInstance != nil && reflect.DeepEqual(getInstance.(model.Instance), instance) {
return
}
c.registeredInstanceCached.Set(key, instance)
}
func (c *ConnectionEventListener) CacheInstancesForRedo(serviceName, groupName string, instances []model.Instance) {
key := util.GetGroupName(serviceName, groupName)
c.registeredInstanceCached.Set(key, instances)
}
func (c *ConnectionEventListener) RemoveInstanceForRedo(serviceName, groupName string, instance model.Instance) {
key := util.GetGroupName(serviceName, groupName)
_, ok := c.registeredInstanceCached.Get(key)
@ -115,16 +113,11 @@ func (c *ConnectionEventListener) RemoveInstanceForRedo(serviceName, groupName s
func (c *ConnectionEventListener) CacheSubscriberForRedo(fullServiceName, clusters string) {
key := util.GetServiceCacheKey(fullServiceName, clusters)
if !c.IsSubscriberCached(key) {
if _, ok := c.subscribes.Get(key); !ok {
c.subscribes.Set(key, struct{}{})
}
}
func (c *ConnectionEventListener) IsSubscriberCached(key string) bool {
_, ok := c.subscribes.Get(key)
return ok
}
func (c *ConnectionEventListener) RemoveSubscriberForRedo(fullServiceName, clusters string) {
c.subscribes.Remove(util.GetServiceCacheKey(fullServiceName, clusters))
}

View File

@ -1,14 +1,14 @@
package naming_grpc
import (
"testing"
"github.com/golang/mock/gomock"
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_proxy"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"testing"
)
func TestRedoSubscribe(t *testing.T) {
t.Skip("Skipping test,It failed due to a previous commit and is difficult to modify because of the use of struct type assertions in the code.")
ctrl := gomock.NewController(t)
defer ctrl.Finish()

View File

@ -17,7 +17,6 @@
package naming_grpc
import (
"context"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache"
@ -28,7 +27,6 @@ import (
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
"github.com/nacos-group/nacos-sdk-go/v2/inner/uuid"
"github.com/nacos-group/nacos-sdk-go/v2/model"
"github.com/nacos-group/nacos-sdk-go/v2/util"
@ -44,7 +42,7 @@ type NamingGrpcProxy struct {
}
// NewNamingGrpcProxy create naming grpc proxy
func NewNamingGrpcProxy(ctx context.Context, clientCfg constant.ClientConfig, nacosServer *nacos_server.NacosServer,
func NewNamingGrpcProxy(clientCfg constant.ClientConfig, nacosServer *nacos_server.NacosServer,
serviceInfoHolder *naming_cache.ServiceInfoHolder) (*NamingGrpcProxy, error) {
srvProxy := NamingGrpcProxy{
clientConfig: clientCfg,
@ -62,7 +60,7 @@ func NewNamingGrpcProxy(ctx context.Context, clientCfg constant.ClientConfig, na
constant.LABEL_MODULE: constant.LABEL_MODULE_NAMING,
}
iRpcClient, err := rpc.CreateClient(ctx, uid.String(), rpc.GRPC, labels, srvProxy.nacosServer, &clientCfg.TLSCfg, clientCfg.AppConnLabels)
iRpcClient, err := rpc.CreateClient(uid.String(), rpc.GRPC, labels, srvProxy.nacosServer)
if err != nil {
return nil, err
}
@ -84,32 +82,20 @@ func NewNamingGrpcProxy(ctx context.Context, clientCfg constant.ClientConfig, na
func (proxy *NamingGrpcProxy) requestToServer(request rpc_request.IRequest) (rpc_response.IResponse, error) {
start := time.Now()
proxy.nacosServer.InjectSecurityInfo(request.GetHeaders(), security.BuildNamingResourceByRequest(request))
proxy.nacosServer.InjectSign(request, request.GetHeaders(), proxy.clientConfig)
proxy.nacosServer.InjectSecurityInfo(request.GetHeaders())
response, err := proxy.rpcClient.GetRpcClient().Request(request, int64(proxy.clientConfig.TimeoutMs))
monitor.GetNamingRequestMonitor(constant.GRPC, request.GetRequestType(), rpc_response.GetGrpcResponseStatusCode(response)).Observe(float64(time.Now().Nanosecond() - start.Nanosecond()))
monitor.GetConfigRequestMonitor(constant.GRPC, request.GetRequestType(), rpc_response.GetGrpcResponseStatusCode(response)).Observe(float64(time.Now().Nanosecond() - start.Nanosecond()))
return response, err
}
// RegisterInstance ...
func (proxy *NamingGrpcProxy) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
logger.Infof("register instance namespaceId:<%s>,serviceName:<%s> with instance:<%s>",
logger.Infof("instance namespaceId:<%s>,serviceName:<%s> with instance:<%s>",
proxy.clientConfig.NamespaceId, serviceName, util.ToJsonString(instance))
proxy.eventListener.CacheInstanceForRedo(serviceName, groupName, instance)
instanceRequest := rpc_request.NewInstanceRequest(proxy.clientConfig.NamespaceId, serviceName, groupName, "registerInstance", instance)
response, err := proxy.requestToServer(instanceRequest)
if err != nil {
return false, err
}
return response.IsSuccess(), err
}
// BatchRegisterInstance ...
func (proxy *NamingGrpcProxy) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) {
logger.Infof("batch register instance namespaceId:<%s>,serviceName:<%s> with instance:<%s>",
proxy.clientConfig.NamespaceId, serviceName, util.ToJsonString(instances))
proxy.eventListener.CacheInstancesForRedo(serviceName, groupName, instances)
batchInstanceRequest := rpc_request.NewBatchInstanceRequest(proxy.clientConfig.NamespaceId, serviceName, groupName, "batchRegisterInstance", instances)
response, err := proxy.requestToServer(batchInstanceRequest)
proxy.eventListener.CacheInstanceForRedo(serviceName, groupName, instance)
if err != nil {
return false, err
}
@ -158,8 +144,8 @@ func (proxy *NamingGrpcProxy) ServerHealthy() bool {
}
// QueryInstancesOfService ...
func (proxy *NamingGrpcProxy) QueryInstancesOfService(serviceName, groupName, cluster string, udpPort int, healthyOnly bool) (*model.Service, error) {
response, err := proxy.requestToServer(rpc_request.NewServiceQueryRequest(proxy.clientConfig.NamespaceId, serviceName, groupName, cluster,
func (proxy *NamingGrpcProxy) QueryInstancesOfService(serviceName, groupName, clusters string, udpPort int, healthyOnly bool) (*model.Service, error) {
response, err := proxy.requestToServer(rpc_request.NewServiceQueryRequest(proxy.clientConfig.NamespaceId, serviceName, groupName, clusters,
healthyOnly, udpPort))
if err != nil {
return nil, err
@ -168,14 +154,8 @@ func (proxy *NamingGrpcProxy) QueryInstancesOfService(serviceName, groupName, cl
return &queryServiceResponse.ServiceInfo, nil
}
func (proxy *NamingGrpcProxy) IsSubscribed(serviceName, groupName string, clusters string) bool {
return proxy.eventListener.IsSubscriberCached(util.GetServiceCacheKey(util.GetGroupName(serviceName, groupName), clusters))
}
// Subscribe ...
func (proxy *NamingGrpcProxy) Subscribe(serviceName, groupName string, clusters string) (model.Service, error) {
logger.Infof("Subscribe Service namespaceId:<%s>, serviceName:<%s>, groupName:<%s>, clusters:<%s>",
proxy.clientConfig.NamespaceId, serviceName, groupName, clusters)
proxy.eventListener.CacheSubscriberForRedo(util.GetGroupName(serviceName, groupName), clusters)
request := rpc_request.NewSubscribeServiceRequest(proxy.clientConfig.NamespaceId, serviceName,
groupName, clusters, true)
@ -190,8 +170,6 @@ func (proxy *NamingGrpcProxy) Subscribe(serviceName, groupName string, clusters
// Unsubscribe ...
func (proxy *NamingGrpcProxy) Unsubscribe(serviceName, groupName, clusters string) error {
logger.Infof("Unsubscribe Service namespaceId:<%s>, serviceName:<%s>, groupName:<%s>, clusters:<%s>",
proxy.clientConfig.NamespaceId, serviceName, groupName, clusters)
proxy.eventListener.RemoveSubscriberForRedo(util.GetGroupName(serviceName, groupName), clusters)
_, err := proxy.requestToServer(rpc_request.NewSubscribeServiceRequest(proxy.clientConfig.NamespaceId, serviceName, groupName,
clusters, false))
@ -199,6 +177,5 @@ func (proxy *NamingGrpcProxy) Unsubscribe(serviceName, groupName, clusters strin
}
func (proxy *NamingGrpcProxy) CloseClient() {
logger.Info("Close Nacos Go SDK Client...")
proxy.rpcClient.GetRpcClient().Shutdown()
}

View File

@ -9,10 +9,6 @@ func (m *MockNamingGrpc) RegisterInstance(serviceName string, groupName string,
return true, nil
}
func (m *MockNamingGrpc) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) {
return true, nil
}
func (m *MockNamingGrpc) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
return true, nil
}
@ -33,8 +29,4 @@ func (m *MockNamingGrpc) Subscribe(serviceName, groupName, clusters string) (mod
return model.Service{}, nil
}
func (m *MockNamingGrpc) Unsubscribe(serviceName, groupName, clusters string) error {
return nil
}
func (m *MockNamingGrpc) CloseClient() {}
func (m *MockNamingGrpc) Unsubscribe(serviceName, groupName, clusters string) {}

View File

@ -40,7 +40,6 @@ import (
)
type BeatReactor struct {
ctx context.Context
beatMap cache.ConcurrentMap
nacosServer *nacos_server.NacosServer
beatThreadCount int
@ -52,9 +51,10 @@ type BeatReactor struct {
const DefaultBeatThreadNum = 20
func NewBeatReactor(ctx context.Context, clientCfg constant.ClientConfig, nacosServer *nacos_server.NacosServer) BeatReactor {
var ctx = context.Background()
func NewBeatReactor(clientCfg constant.ClientConfig, nacosServer *nacos_server.NacosServer) BeatReactor {
br := BeatReactor{}
br.ctx = ctx
br.beatMap = cache.NewConcurrentMap()
br.nacosServer = nacosServer
br.clientCfg = clientCfg
@ -101,10 +101,8 @@ func (br *BeatReactor) RemoveBeatInfo(serviceName string, ip string, port uint64
}
func (br *BeatReactor) sendInstanceBeat(k string, beatInfo *model.BeatInfo) {
t := time.NewTimer(beatInfo.Period)
defer t.Stop()
for {
br.beatThreadSemaphore.Acquire(br.ctx, 1)
br.beatThreadSemaphore.Acquire(ctx, 1)
//如果当前实例注销,则进行停止心跳
if atomic.LoadInt32(&beatInfo.State) == int32(model.StateShutdown) {
logger.Infof("instance[%s] stop heartBeating", k)
@ -127,12 +125,9 @@ func (br *BeatReactor) sendInstanceBeat(k string, beatInfo *model.BeatInfo) {
br.beatRecordMap.Set(k, util.CurrentMillis())
br.beatThreadSemaphore.Release(1)
t.Reset(beatInfo.Period)
select {
case <-t.C:
case <-br.ctx.Done():
return
}
t := time.NewTimer(beatInfo.Period)
<-t.C
}
}
@ -144,7 +139,7 @@ func (br *BeatReactor) SendBeat(info *model.BeatInfo) (int64, error) {
params["serviceName"] = info.ServiceName
params["beat"] = util.ToJsonString(info)
api := constant.SERVICE_BASE_PATH + "/instance/beat"
result, err := br.nacosServer.ReqApi(api, params, http.MethodPut, br.clientCfg)
result, err := br.nacosServer.ReqApi(api, params, http.MethodPut)
if err != nil {
return 0, err
}

View File

@ -17,7 +17,6 @@
package naming_http
import (
"context"
"testing"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
@ -28,7 +27,7 @@ import (
)
func TestBeatReactor_AddBeatInfo(t *testing.T) {
br := NewBeatReactor(context.Background(), constant.ClientConfig{}, &nacos_server.NacosServer{})
br := NewBeatReactor(constant.ClientConfig{}, &nacos_server.NacosServer{})
serviceName := "Test"
groupName := "public"
beatInfo := &model.BeatInfo{
@ -47,7 +46,7 @@ func TestBeatReactor_AddBeatInfo(t *testing.T) {
}
func TestBeatReactor_RemoveBeatInfo(t *testing.T) {
br := NewBeatReactor(context.Background(), constant.ClientConfig{}, &nacos_server.NacosServer{})
br := NewBeatReactor(constant.ClientConfig{}, &nacos_server.NacosServer{})
serviceName := "Test"
groupName := "public"
beatInfo1 := &model.BeatInfo{

View File

@ -17,7 +17,7 @@
package naming_http
import (
"context"
"fmt"
"net/http"
"strconv"
"time"
@ -43,7 +43,7 @@ type NamingHttpProxy struct {
}
// NewNamingHttpProxy create naming http proxy
func NewNamingHttpProxy(ctx context.Context, clientCfg constant.ClientConfig, nacosServer *nacos_server.NacosServer,
func NewNamingHttpProxy(clientCfg constant.ClientConfig, nacosServer *nacos_server.NacosServer,
serviceInfoHolder *naming_cache.ServiceInfoHolder) (*NamingHttpProxy, error) {
srvProxy := NamingHttpProxy{
clientConfig: clientCfg,
@ -51,9 +51,9 @@ func NewNamingHttpProxy(ctx context.Context, clientCfg constant.ClientConfig, na
serviceInfoHolder: serviceInfoHolder,
}
srvProxy.beatReactor = NewBeatReactor(ctx, clientCfg, nacosServer)
srvProxy.beatReactor = NewBeatReactor(clientCfg, nacosServer)
NewPushReceiver(ctx, serviceInfoHolder).startServer()
NewPushReceiver(serviceInfoHolder).startServer()
return &srvProxy, nil
}
@ -76,7 +76,7 @@ func (proxy *NamingHttpProxy) RegisterInstance(serviceName string, groupName str
params["healthy"] = strconv.FormatBool(instance.Healthy)
params["metadata"] = util.ToJsonString(instance.Metadata)
params["ephemeral"] = strconv.FormatBool(instance.Ephemeral)
_, err := proxy.nacosServer.ReqApi(constant.SERVICE_PATH, params, http.MethodPost, proxy.clientConfig)
_, err := proxy.nacosServer.ReqApi(constant.SERVICE_PATH, params, http.MethodPost)
if err != nil {
return false, err
}
@ -96,10 +96,6 @@ func (proxy *NamingHttpProxy) RegisterInstance(serviceName string, groupName str
return true, nil
}
func (proxy *NamingHttpProxy) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) {
panic("implement me")
}
// DeregisterInstance ...
func (proxy *NamingHttpProxy) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
serviceName = util.GetGroupName(serviceName, groupName)
@ -113,7 +109,7 @@ func (proxy *NamingHttpProxy) DeregisterInstance(serviceName string, groupName s
params["ip"] = instance.Ip
params["port"] = strconv.Itoa(int(instance.Port))
params["ephemeral"] = strconv.FormatBool(instance.Ephemeral)
_, err := proxy.nacosServer.ReqApi(constant.SERVICE_PATH, params, http.MethodDelete, proxy.clientConfig)
_, err := proxy.nacosServer.ReqApi(constant.SERVICE_PATH, params, http.MethodDelete)
if err != nil {
return false, err
}
@ -141,7 +137,7 @@ func (proxy *NamingHttpProxy) GetServiceList(pageNo uint32, pageSize uint32, gro
serviceList := model.ServiceList{}
api := constant.SERVICE_BASE_PATH + "/service/list"
result, err := proxy.nacosServer.ReqApi(api, params, http.MethodGet, proxy.clientConfig)
result, err := proxy.nacosServer.ReqApi(api, params, http.MethodGet)
if err != nil {
return serviceList, err
}
@ -151,14 +147,14 @@ func (proxy *NamingHttpProxy) GetServiceList(pageNo uint32, pageSize uint32, gro
count, err := jsonparser.GetInt([]byte(result), "count")
if err != nil {
return serviceList, errors.Errorf("namespaceId:<%s> get service list pageNo:<%d> pageSize:<%d> selector:<%s> from <%s> get 'count' from <%s> error:<%+v>", namespaceId, pageNo, pageSize, util.ToJsonString(selector), groupName, result, err)
return serviceList, errors.New(fmt.Sprintf("namespaceId:<%s> get service list pageNo:<%d> pageSize:<%d> selector:<%s> from <%s> get 'count' from <%s> error:<%+v>", namespaceId, pageNo, pageSize, util.ToJsonString(selector), groupName, result, err))
}
var doms []string
_, err = jsonparser.ArrayEach([]byte(result), func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
doms = append(doms, string(value))
}, "doms")
if err != nil {
return serviceList, errors.Errorf("namespaceId:<%s> get service list pageNo:<%d> pageSize:<%d> selector:<%s> from <%s> get 'doms' from <%s> error:<%+v> ", namespaceId, pageNo, pageSize, util.ToJsonString(selector), groupName, result, err)
return serviceList, errors.New(fmt.Sprintf("namespaceId:<%s> get service list pageNo:<%d> pageSize:<%d> selector:<%s> from <%s> get 'doms' from <%s> error:<%+v> ", namespaceId, pageNo, pageSize, util.ToJsonString(selector), groupName, result, err))
}
serviceList.Count = count
serviceList.Doms = doms
@ -168,7 +164,7 @@ func (proxy *NamingHttpProxy) GetServiceList(pageNo uint32, pageSize uint32, gro
// ServerHealthy ...
func (proxy *NamingHttpProxy) ServerHealthy() bool {
api := constant.SERVICE_BASE_PATH + "/operator/metrics"
result, err := proxy.nacosServer.ReqApi(api, map[string]string{}, http.MethodGet, proxy.clientConfig)
result, err := proxy.nacosServer.ReqApi(api, map[string]string{}, http.MethodGet)
if err != nil {
logger.Errorf("namespaceId:[%s] sending server healthy failed!,result:%s error:%+v", proxy.clientConfig.NamespaceId, result, err)
return false
@ -195,7 +191,7 @@ func (proxy *NamingHttpProxy) QueryInstancesOfService(serviceName, groupName, cl
param["healthyOnly"] = strconv.FormatBool(healthyOnly)
param["clientIP"] = util.LocalIP()
api := constant.SERVICE_PATH + "/list"
result, err := proxy.nacosServer.ReqApi(api, param, http.MethodGet, proxy.clientConfig)
result, err := proxy.nacosServer.ReqApi(api, param, http.MethodGet)
if err != nil {
return nil, err
}

View File

@ -19,9 +19,8 @@ package naming_http
import (
"bytes"
"compress/gzip"
"context"
"encoding/json"
"io"
"io/ioutil"
"math/rand"
"net"
"strconv"
@ -33,7 +32,6 @@ import (
)
type PushReceiver struct {
ctx context.Context
port int
host string
serviceInfoHolder *naming_cache.ServiceInfoHolder
@ -49,9 +47,8 @@ var (
GZIP_MAGIC = []byte("\x1F\x8B")
)
func NewPushReceiver(ctx context.Context, serviceInfoHolder *naming_cache.ServiceInfoHolder) *PushReceiver {
func NewPushReceiver(serviceInfoHolder *naming_cache.ServiceInfoHolder) *PushReceiver {
pr := PushReceiver{
ctx: ctx,
serviceInfoHolder: serviceInfoHolder,
}
return &pr
@ -102,12 +99,7 @@ func (us *PushReceiver) startServer() {
go func() {
defer conn.Close()
for {
select {
case <-us.ctx.Done():
return
default:
us.handleClient(conn)
}
us.handleClient(conn)
}
}()
}
@ -168,7 +160,7 @@ func TryDecompressData(data []byte) string {
}
defer reader.Close()
bs, err := io.ReadAll(reader)
bs, err := ioutil.ReadAll(reader)
if err != nil {
logger.Errorf("failed to decompress gzip data,err:%+v", err)

View File

@ -24,8 +24,6 @@ import (
type INamingProxy interface {
RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error)
BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error)
DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error)
GetServiceList(pageNo uint32, pageSize uint32, groupName, namespaceId string, selector *model.ExpressionSelector) (model.ServiceList, error)

View File

@ -1,5 +1,5 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: clients/naming_client/naming_proxy/proxy_interface.go
// Source: proxy_interface.go
// Package naming_proxy is a generated GoMock package.
package naming_proxy
@ -34,21 +34,6 @@ func (m *MockINamingProxy) EXPECT() *MockINamingProxyMockRecorder {
return m.recorder
}
// BatchRegisterInstance mocks base method.
func (m *MockINamingProxy) BatchRegisterInstance(serviceName, groupName string, instances []model.Instance) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "BatchRegisterInstance", serviceName, groupName, instances)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BatchRegisterInstance indicates an expected call of BatchRegisterInstance.
func (mr *MockINamingProxyMockRecorder) BatchRegisterInstance(serviceName, groupName, instances interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BatchRegisterInstance", reflect.TypeOf((*MockINamingProxy)(nil).BatchRegisterInstance), serviceName, groupName, instances)
}
// CloseClient mocks base method.
func (m *MockINamingProxy) CloseClient() {
m.ctrl.T.Helper()
@ -79,7 +64,7 @@ func (mr *MockINamingProxyMockRecorder) DeregisterInstance(serviceName, groupNam
// GetServiceList mocks base method.
func (m *MockINamingProxy) GetServiceList(pageNo, pageSize uint32, groupName, namespaceId string, selector *model.ExpressionSelector) (model.ServiceList, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetServiceList", pageNo, pageSize, groupName, namespaceId, selector)
ret := m.ctrl.Call(m, "GetServiceList", pageNo, pageSize, groupName, selector)
ret0, _ := ret[0].(model.ServiceList)
ret1, _ := ret[1].(error)
return ret0, ret1
@ -88,7 +73,7 @@ func (m *MockINamingProxy) GetServiceList(pageNo, pageSize uint32, groupName, na
// GetServiceList indicates an expected call of GetServiceList.
func (mr *MockINamingProxyMockRecorder) GetServiceList(pageNo, pageSize, groupName, namespaceId, selector interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceList", reflect.TypeOf((*MockINamingProxy)(nil).GetServiceList), pageNo, pageSize, groupName, namespaceId, selector)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceList", reflect.TypeOf((*MockINamingProxy)(nil).GetServiceList), pageNo, pageSize, groupName, selector)
}
// QueryInstancesOfService mocks base method.

View File

@ -17,10 +17,6 @@
package naming_client
import (
"context"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
"github.com/nacos-group/nacos-sdk-go/v2/inner/uuid"
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache"
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_grpc"
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_http"
@ -39,35 +35,20 @@ type NamingProxyDelegate struct {
serviceInfoHolder *naming_cache.ServiceInfoHolder
}
func NewNamingProxyDelegate(ctx context.Context, clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig,
func NewNamingProxyDelegate(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig,
httpAgent http_agent.IHttpAgent, serviceInfoHolder *naming_cache.ServiceInfoHolder) (naming_proxy.INamingProxy, error) {
return NewNamingProxyDelegateWithRamCredentialProvider(ctx, clientCfg, serverCfgs, httpAgent, serviceInfoHolder, nil)
}
func NewNamingProxyDelegateWithRamCredentialProvider(ctx context.Context, clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig,
httpAgent http_agent.IHttpAgent, serviceInfoHolder *naming_cache.ServiceInfoHolder, provider security.RamCredentialProvider) (naming_proxy.INamingProxy, error) {
uid, err := uuid.NewV4()
if err != nil {
return nil, err
}
namingHeader := map[string][]string{
"Client-Version": {constant.CLIENT_VERSION},
"User-Agent": {constant.CLIENT_VERSION},
"RequestId": {uid.String()},
"Request-Module": {"Naming"},
}
nacosServer, err := nacos_server.NewNacosServerWithRamCredentialProvider(ctx, serverCfgs, clientCfg, httpAgent, clientCfg.TimeoutMs, clientCfg.Endpoint, namingHeader, provider)
nacosServer, err := nacos_server.NewNacosServer(serverCfgs, clientCfg, httpAgent, clientCfg.TimeoutMs, clientCfg.Endpoint)
if err != nil {
return nil, err
}
httpClientProxy, err := naming_http.NewNamingHttpProxy(ctx, clientCfg, nacosServer, serviceInfoHolder)
httpClientProxy, err := naming_http.NewNamingHttpProxy(clientCfg, nacosServer, serviceInfoHolder)
if err != nil {
return nil, err
}
grpcClientProxy, err := naming_grpc.NewNamingGrpcProxy(ctx, clientCfg, nacosServer, serviceInfoHolder)
grpcClientProxy, err := naming_grpc.NewNamingGrpcProxy(clientCfg, nacosServer, serviceInfoHolder)
if err != nil {
return nil, err
}
@ -92,10 +73,6 @@ func (proxy *NamingProxyDelegate) RegisterInstance(serviceName string, groupName
return proxy.getExecuteClientProxy(instance).RegisterInstance(serviceName, groupName, instance)
}
func (proxy *NamingProxyDelegate) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) {
return proxy.grpcClientProxy.BatchRegisterInstance(serviceName, groupName, instances)
}
func (proxy *NamingProxyDelegate) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
return proxy.getExecuteClientProxy(instance).DeregisterInstance(serviceName, groupName, instance)
}
@ -113,17 +90,15 @@ func (proxy *NamingProxyDelegate) QueryInstancesOfService(serviceName, groupName
}
func (proxy *NamingProxyDelegate) Subscribe(serviceName, groupName string, clusters string) (model.Service, error) {
var err error
isSubscribed := proxy.grpcClientProxy.IsSubscribed(serviceName, groupName, clusters)
serviceNameWithGroup := util.GetServiceCacheKey(util.GetGroupName(serviceName, groupName), clusters)
serviceInfo, ok := proxy.serviceInfoHolder.ServiceInfoMap.Load(serviceNameWithGroup)
if !isSubscribed || !ok {
serviceInfo, err = proxy.grpcClientProxy.Subscribe(serviceName, groupName, clusters)
serviceInfo, ok := proxy.serviceInfoHolder.ServiceInfoMap.Get(serviceNameWithGroup)
if !ok {
result, err := proxy.grpcClientProxy.Subscribe(serviceName, groupName, clusters)
if err != nil {
return model.Service{}, err
}
serviceInfo = result
}
service := serviceInfo.(model.Service)
proxy.serviceInfoHolder.ProcessService(&service)
return service, nil

View File

@ -17,7 +17,6 @@
package naming_client
import (
"context"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache"
@ -28,17 +27,15 @@ import (
)
type ServiceInfoUpdater struct {
ctx context.Context
serviceInfoHolder *naming_cache.ServiceInfoHolder
updateThreadNum int
namingProxy naming_proxy.INamingProxy
}
func NewServiceInfoUpdater(ctx context.Context, serviceInfoHolder *naming_cache.ServiceInfoHolder, updateThreadNum int,
func NewServiceInfoUpdater(serviceInfoHolder *naming_cache.ServiceInfoHolder, updateThreadNum int,
namingProxy naming_proxy.INamingProxy) *ServiceInfoUpdater {
return &ServiceInfoUpdater{
ctx: ctx,
serviceInfoHolder: serviceInfoHolder,
updateThreadNum: updateThreadNum,
namingProxy: namingProxy,
@ -48,28 +45,22 @@ func NewServiceInfoUpdater(ctx context.Context, serviceInfoHolder *naming_cache.
func (s *ServiceInfoUpdater) asyncUpdateService() {
sema := util.NewSemaphore(s.updateThreadNum)
for {
select {
case <-s.ctx.Done():
return
default:
s.serviceInfoHolder.ServiceInfoMap.Range(func(key, value interface{}) bool {
service := value.(model.Service)
lastRefTime, ok := s.serviceInfoHolder.UpdateTimeMap.Load(util.GetServiceCacheKey(util.GetGroupName(service.Name, service.GroupName),
service.Clusters))
if !ok {
lastRefTime = uint64(0)
}
if uint64(util.CurrentMillis())-lastRefTime.(uint64) > service.CacheMillis {
sema.Acquire()
go func() {
defer sema.Release()
s.updateServiceNow(service.Name, service.GroupName, service.Clusters)
}()
}
return true
})
time.Sleep(1 * time.Second)
for _, v := range s.serviceInfoHolder.ServiceInfoMap.Items() {
service := v.(model.Service)
lastRefTime, ok := s.serviceInfoHolder.UpdateTimeMap.Get(util.GetServiceCacheKey(util.GetGroupName(service.Name, service.GroupName),
service.Clusters))
if !ok {
lastRefTime = uint64(0)
}
if uint64(util.CurrentMillis())-lastRefTime.(uint64) > service.CacheMillis {
sema.Acquire()
go func() {
s.updateServiceNow(service.Name, service.GroupName, service.Clusters)
sema.Release()
}()
}
}
time.Sleep(1 * time.Second)
}
}
@ -77,7 +68,7 @@ func (s *ServiceInfoUpdater) updateServiceNow(serviceName, groupName, clusters s
result, err := s.namingProxy.QueryInstancesOfService(serviceName, groupName, clusters, 0, false)
if err != nil {
logger.Errorf("QueryInstances error, serviceName:%s, cluster:%s, err:%v", serviceName, clusters, err)
logger.Errorf("QueryList return error!serviceName:%s cluster:%s err:%+v", serviceName, clusters, err)
return
}
s.serviceInfoHolder.ProcessService(result)

View File

@ -81,27 +81,6 @@ func WithEndpoint(endpoint string) ClientOption {
}
}
// WithEndpointContextPath ...
func WithEndpointContextPath(endpointContextPath string) ClientOption {
return func(config *ClientConfig) {
config.EndpointContextPath = endpointContextPath
}
}
// WithEndpointQueryParams ...
func WithEndpointQueryParams(endpointQueryPrams string) ClientOption {
return func(config *ClientConfig) {
config.EndpointQueryParams = endpointQueryPrams
}
}
// WithClusterName ...
func WithClusterName(clusterName string) ClientOption {
return func(config *ClientConfig) {
config.ClusterName = clusterName
}
}
// WithRegionId ...
func WithRegionId(regionId string) ClientOption {
return func(config *ClientConfig) {
@ -123,12 +102,6 @@ func WithSecretKey(secretKey string) ClientOption {
}
}
func WithRamConfig(ramConfig *RamConfig) ClientOption {
return func(config *ClientConfig) {
config.RamConfig = ramConfig
}
}
// WithOpenKMS ...
func WithOpenKMS(openKMS bool) ClientOption {
return func(config *ClientConfig) {
@ -136,25 +109,6 @@ func WithOpenKMS(openKMS bool) ClientOption {
}
}
// WithOpenKMS ...
func WithKMSVersion(kmsVersion KMSVersion) ClientOption {
return func(config *ClientConfig) {
config.KMSVersion = kmsVersion
}
}
func WithKMSv3Config(kmsv3Config *KMSv3Config) ClientOption {
return func(config *ClientConfig) {
config.KMSv3Config = kmsv3Config
}
}
func WithKMSConfig(kmsConfig *KMSConfig) ClientOption {
return func(config *ClientConfig) {
config.KMSConfig = kmsConfig
}
}
// WithCacheDir ...
func WithCacheDir(cacheDir string) ClientOption {
return func(config *ClientConfig) {
@ -162,13 +116,6 @@ func WithCacheDir(cacheDir string) ClientOption {
}
}
// WithDisableUseSnapShot ...
func WithDisableUseSnapShot(disableUseSnapShot bool) ClientOption {
return func(config *ClientConfig) {
config.DisableUseSnapShot = disableUseSnapShot
}
}
// WithUpdateThreadNum ...
func WithUpdateThreadNum(updateThreadNum int) ClientOption {
return func(config *ClientConfig) {
@ -234,13 +181,6 @@ func WithLogRollingConfig(rollingConfig *ClientLogRollingConfig) ClientOption {
func WithTLS(tlsCfg TLSConfig) ClientOption {
return func(config *ClientConfig) {
tlsCfg.Appointed = true
config.TLSCfg = tlsCfg
}
}
func WithAppConnLabels(appConnLabels map[string]string) ClientOption {
return func(config *ClientConfig) {
config.AppConnLabels = appConnLabels
}
}

View File

@ -27,24 +27,19 @@ type ServerConfig struct {
}
type ClientConfig struct {
TimeoutMs uint64 // timeout for requesting Nacos server, default value is 10000ms
ListenInterval uint64 // Deprecated
BeatInterval int64 // the time interval for sending beat to server,default value is 5000ms
NamespaceId string // the namespaceId of Nacos.When namespace is public, fill in the blank string here.
AppName string // the appName
AppKey string // the client identity information
Endpoint string // the endpoint for get Nacos server addresses
RegionId string // the regionId for kms
AccessKey string // the AccessKey for kms
SecretKey string // the SecretKey for kms
RamConfig *RamConfig
OpenKMS bool // it's to open kms, default is false. https://help.aliyun.com/product/28933.html
KMSVersion KMSVersion // kms client version. https://help.aliyun.com/document_detail/380927.html
KMSv3Config *KMSv3Config //KMSv3 configuration. https://help.aliyun.com/document_detail/601596.html
KMSConfig *KMSConfig
TimeoutMs uint64 // timeout for requesting Nacos server, default value is 10000ms
ListenInterval uint64 // Deprecated
BeatInterval int64 // the time interval for sending beat to server,default value is 5000ms
NamespaceId string // the namespaceId of Nacos.When namespace is public, fill in the blank string here.
AppName string // the appName
AppKey string // the client identity information
Endpoint string // the endpoint for get Nacos server addresses
RegionId string // the regionId for kms
AccessKey string // the AccessKey for kms
SecretKey string // the SecretKey for kms
OpenKMS bool // it's to open kms,default is false. https://help.aliyun.com/product/28933.html
CacheDir string // the directory for persist nacos service info,default value is current path
DisableUseSnapShot bool // It's a switch, default is false, means that when get remote config fail, use local cache file instead
UpdateThreadNum int // the number of goroutine for update nacos service info,default value is 20
UpdateThreadNum int // the number of gorutine for update nacos service info,default value is 20
NotLoadCacheAtStart bool // not to load persistent nacos service info in CacheDir at start time
UpdateCacheWhenEmpty bool // update cache when get empty service instance from server
Username string // the username for nacos auth
@ -56,11 +51,6 @@ type ClientConfig struct {
LogSampling *ClientLogSamplingConfig // the sampling config of log
LogRollingConfig *ClientLogRollingConfig // log rolling config
TLSCfg TLSConfig // tls Config
AsyncUpdateService bool // open async update service by query
EndpointContextPath string // the address server endpoint contextPath
EndpointQueryParams string // the address server endpoint query params
ClusterName string // the address server clusterName
AppConnLabels map[string]string // app conn labels
}
type ClientLogSamplingConfig struct {
@ -97,38 +87,9 @@ type ClientLogRollingConfig struct {
}
type TLSConfig struct {
Appointed bool // Appointed or not ,if false,will get from env.
Enable bool // enable tls
TrustAll bool // trust all server
CaFile string // clients use when verifying server certificates
CertFile string // server use when verifying client certificates
KeyFile string // server use when verifying client certificates
ServerNameOverride string // serverNameOverride is for testing only
}
type KMSv3Config struct {
ClientKeyContent string
Password string
Endpoint string
CaContent string
}
type KMSConfig struct {
Endpoint string
OpenSSL string
CaContent string
}
type RamConfig struct {
SecurityToken string
SignatureRegionId string
RamRoleName string
RoleArn string
Policy string
RoleSessionName string
RoleSessionExpiration int
OIDCProviderArn string
OIDCTokenFilePath string
CredentialsURI string
SecretName string
}

View File

@ -18,104 +18,83 @@ package constant
import "time"
type KMSVersion string
const (
KMSv1 KMSVersion = "KMSv1"
KMSv3 KMSVersion = "KMSv3"
DEFAULT_KMS_VERSION KMSVersion = "" //to fit original version
UNKNOWN_KMS_VERSION KMSVersion = "UNKNOWN_KMS_VERSION"
)
const (
KEY_USERNAME = "username"
KEY_PASSWORD = "password"
KEY_ENDPOINT = "endpoint"
KEY_NAME_SPACE = "namespace"
KEY_ACCESS_KEY = "accessKey"
KEY_SECRET_KEY = "secretKey"
KEY_SERVER_ADDR = "serverAddr"
KEY_CONTEXT_PATH = "contextPath"
KEY_ENCODE = "encode"
KEY_DATA_ID = "dataId"
KEY_GROUP = "group"
KEY_TENANT = "tenant"
KEY_DESC = "desc"
KEY_APP_NAME = "appName"
KEY_CONTENT = "content"
KEY_TIMEOUT_MS = "timeoutMs"
KEY_LISTEN_INTERVAL = "listenInterval"
KEY_SERVER_CONFIGS = "serverConfigs"
KEY_CLIENT_CONFIG = "clientConfig"
KEY_TOKEN = "token"
KEY_ACCESS_TOKEN = "accessToken"
KEY_TOKEN_TTL = "tokenTtl"
KEY_GLOBAL_ADMIN = "globalAdmin"
KEY_TOKEN_REFRESH_WINDOW = "tokenRefreshWindow"
WEB_CONTEXT = "/nacos"
CONFIG_BASE_PATH = "/v1/cs"
CONFIG_PATH = CONFIG_BASE_PATH + "/configs"
CONFIG_AGG_PATH = "/datum.do"
CONFIG_LISTEN_PATH = CONFIG_BASE_PATH + "/configs/listener"
SERVICE_BASE_PATH = "/v1/ns"
SERVICE_PATH = SERVICE_BASE_PATH + "/instance"
SERVICE_INFO_PATH = SERVICE_BASE_PATH + "/service"
SERVICE_SUBSCRIBE_PATH = SERVICE_PATH + "/list"
NAMESPACE_PATH = "/v1/console/namespaces"
SPLIT_CONFIG = string(rune(1))
SPLIT_CONFIG_INNER = string(rune(2))
KEY_LISTEN_CONFIGS = "Listening-Configs"
KEY_SERVICE_NAME = "serviceName"
KEY_IP = "ip"
KEY_PORT = "port"
KEY_WEIGHT = "weight"
KEY_ENABLE = "enable"
KEY_HEALTHY = "healthy"
KEY_METADATA = "metadata"
KEY_CLUSTER_NAME = "clusterName"
KEY_CLUSTER = "cluster"
KEY_BEAT = "beat"
KEY_DOM = "dom"
DEFAULT_CONTEXT_PATH = "/nacos"
CLIENT_VERSION = "Nacos-Go-Client:v2.3.3"
REQUEST_DOMAIN_RETRY_TIME = 3
SERVICE_INFO_SPLITER = "@@"
CONFIG_INFO_SPLITER = "@@"
DEFAULT_NAMESPACE_ID = "public"
DEFAULT_GROUP = "DEFAULT_GROUP"
NAMING_INSTANCE_ID_SPLITTER = "#"
DefaultClientErrorCode = "SDK.NacosError"
DEFAULT_SERVER_SCHEME = "http"
HTTPS_SERVER_SCHEME = "https"
LABEL_SOURCE = "source"
LABEL_SOURCE_SDK = "sdk"
LABEL_MODULE = "module"
LABEL_MODULE_CONFIG = "config"
LABEL_MODULE_NAMING = "naming"
RESPONSE_CODE_SUCCESS = 200
UN_REGISTER = 301
KEEP_ALIVE_TIME = 5
DEFAULT_TIMEOUT_MILLS = 3000
ALL_SYNC_INTERNAL = 5 * time.Minute
CLIENT_APPNAME_HEADER = "Client-AppName"
APPNAME_HEADER = "AppName"
CLIENT_REQUEST_TS_HEADER = "Client-RequestTS"
CLIENT_REQUEST_TOKEN_HEADER = "Client-RequestToken"
EX_CONFIG_INFO = "exConfigInfo"
CHARSET_KEY = "charset"
LOG_FILE_NAME = "nacos-sdk.log"
HTTPS_SERVER_PORT = 443
GRPC = "grpc"
RpcPortOffset = 1000
MSE_KMSv1_DEFAULT_KEY_ID = "alias/acs/mse"
CONFIG_PUBLISH_REQUEST_NAME = "ConfigPublishRequest"
CONFIG_QUERY_REQUEST_NAME = "ConfigQueryRequest"
CONFIG_REMOVE_REQUEST_NAME = "ConfigRemoveRequest"
INSTANCE_REQUEST_NAME = "InstanceRequest"
BATCH_INSTANCE_REQUEST_NAME = "BatchInstanceRequest"
SERVICE_LIST_REQUEST_NAME = "ServiceListRequest"
SERVICE_QUERY_REQUEST_NAME = "ServiceQueryRequest"
SUBSCRIBE_SERVICE_REQUEST_NAME = "SubscribeServiceRequest"
NOTIFY_SUBSCRIBE_REQUEST_NAME = "NotifySubscriberRequest"
CONFIG_BATCH_LISTEN_REQUEST_NAME = "ConfigBatchListenRequest"
CONFIG_CHANGE_NOTIFY_REQUEST_NAME = "ConfigChangeNotifyRequest"
KEY_USERNAME = "username"
KEY_PASSWORD = "password"
KEY_ENDPOINT = "endpoint"
KEY_NAME_SPACE = "namespace"
KEY_ACCESS_KEY = "accessKey"
KEY_SECRET_KEY = "secretKey"
KEY_SERVER_ADDR = "serverAddr"
KEY_CONTEXT_PATH = "contextPath"
KEY_ENCODE = "encode"
KEY_DATA_ID = "dataId"
KEY_GROUP = "group"
KEY_TENANT = "tenant"
KEY_DESC = "desc"
KEY_APP_NAME = "appName"
KEY_CONTENT = "content"
KEY_TIMEOUT_MS = "timeoutMs"
KEY_LISTEN_INTERVAL = "listenInterval"
KEY_SERVER_CONFIGS = "serverConfigs"
KEY_CLIENT_CONFIG = "clientConfig"
KEY_TOKEN = "token"
KEY_ACCESS_TOKEN = "accessToken"
KEY_TOKEN_TTL = "tokenTtl"
KEY_GLOBAL_ADMIN = "globalAdmin"
KEY_TOKEN_REFRESH_WINDOW = "tokenRefreshWindow"
WEB_CONTEXT = "/nacos"
CONFIG_BASE_PATH = "/v1/cs"
CONFIG_PATH = CONFIG_BASE_PATH + "/configs"
CONFIG_AGG_PATH = "/datum.do"
CONFIG_LISTEN_PATH = CONFIG_BASE_PATH + "/configs/listener"
SERVICE_BASE_PATH = "/v1/ns"
SERVICE_PATH = SERVICE_BASE_PATH + "/instance"
SERVICE_INFO_PATH = SERVICE_BASE_PATH + "/service"
SERVICE_SUBSCRIBE_PATH = SERVICE_PATH + "/list"
NAMESPACE_PATH = "/v1/console/namespaces"
SPLIT_CONFIG = string(rune(1))
SPLIT_CONFIG_INNER = string(rune(2))
KEY_LISTEN_CONFIGS = "Listening-Configs"
KEY_SERVICE_NAME = "serviceName"
KEY_IP = "ip"
KEY_PORT = "port"
KEY_WEIGHT = "weight"
KEY_ENABLE = "enable"
KEY_HEALTHY = "healthy"
KEY_METADATA = "metadata"
KEY_CLUSTER_NAME = "clusterName"
KEY_CLUSTER = "cluster"
KEY_BEAT = "beat"
KEY_DOM = "dom"
DEFAULT_CONTEXT_PATH = "/nacos"
CLIENT_VERSION = "Nacos-Go-Client:v2.0.0"
REQUEST_DOMAIN_RETRY_TIME = 3
SERVICE_INFO_SPLITER = "@@"
CONFIG_INFO_SPLITER = "@@"
DEFAULT_NAMESPACE_ID = "public"
DEFAULT_GROUP = "DEFAULT_GROUP"
NAMING_INSTANCE_ID_SPLITTER = "#"
DefaultClientErrorCode = "SDK.NacosError"
DEFAULT_SERVER_SCHEME = "http"
HTTPS_SERVER_SCHEME = "https"
LABEL_SOURCE = "source"
LABEL_SOURCE_SDK = "sdk"
LABEL_MODULE = "module"
LABEL_MODULE_CONFIG = "config"
LABEL_MODULE_NAMING = "naming"
RESPONSE_CODE_SUCCESS = 200
UN_REGISTER = 301
KEEP_ALIVE_TIME = 5
DEFAULT_TIMEOUT_MILLS = 3000
ALL_SYNC_INTERNAL = 5 * time.Minute
CLIENT_APPNAME_HEADER = "Client-AppName"
CLIENT_REQUEST_TS_HEADER = "Client-RequestTS"
CLIENT_REQUEST_TOKEN_HEADER = "Client-RequestToken"
EX_CONFIG_INFO = "exConfigInfo"
CHARSET_KEY = "charset"
LOG_FILE_NAME = "nacos-sdk.log"
HTTPS_SERVER_PORT = 443
GRPC = "grpc"
FAILOVER_FILE_SUFFIX = "_failover"
)

View File

@ -34,35 +34,35 @@ func NewServerConfig(ipAddr string, port uint64, opts ...ServerOption) *ServerCo
// ServerOption ...
type ServerOption func(*ServerConfig)
// WithScheme set Scheme for server
//WithScheme set Scheme for server
func WithScheme(scheme string) ServerOption {
return func(config *ServerConfig) {
config.Scheme = scheme
}
}
// WithContextPath set contextPath for server
//WithContextPath set contextPath for server
func WithContextPath(contextPath string) ServerOption {
return func(config *ServerConfig) {
config.ContextPath = contextPath
}
}
// WithIpAddr set ip address for server
//WithIpAddr set ip address for server
func WithIpAddr(ipAddr string) ServerOption {
return func(config *ServerConfig) {
config.IpAddr = ipAddr
}
}
// WithPort set port for server
//WithPort set port for server
func WithPort(port uint64) ServerOption {
return func(config *ServerConfig) {
config.Port = port
}
}
// WithGrpcPort set grpc port for server
//WithGrpcPort set grpc port for server
func WithGrpcPort(port uint64) ServerOption {
return func(config *ServerConfig) {
config.GrpcPort = port

View File

@ -1,72 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 encoding
import (
"encoding/base64"
"unicode/utf8"
)
func DecodeString2Utf8Bytes(data string) []byte {
resBytes := make([]byte, 0, 8)
if len(data) == 0 {
return resBytes
}
bytesLen := 0
runes := []rune(data)
for _, r := range runes {
bytesLen += utf8.RuneLen(r)
}
resBytes = make([]byte, bytesLen)
pos := 0
for _, r := range runes {
pos += utf8.EncodeRune(resBytes[pos:], r)
}
return resBytes
}
func EncodeUtf8Bytes2String(bytes []byte) string {
if len(bytes) == 0 {
return ""
}
var startPos, endPos int
resRunes := make([]rune, 0, 8)
for endPos <= len(bytes) {
if utf8.FullRune(bytes[startPos:endPos]) {
decodedRune, _ := utf8.DecodeRune(bytes[startPos:endPos])
resRunes = append(resRunes, decodedRune)
startPos = endPos
}
endPos++
}
return string(resRunes)
}
func DecodeBase64(bytes []byte) ([]byte, error) {
dst := make([]byte, base64.StdEncoding.DecodedLen(len(bytes)))
n, err := base64.StdEncoding.Decode(dst, bytes)
if err != nil {
return nil, err
}
return dst[:n], nil
}
func EncodeBase64(bytes []byte) ([]byte, error) {
dst := make([]byte, base64.StdEncoding.EncodedLen(len(bytes)))
base64.StdEncoding.Encode(dst, bytes)
return dst[:], nil
}

View File

@ -1,88 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 encryption
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"fmt"
)
func AesEcbPkcs5PaddingEncrypt(plainContent, key []byte) (retBytes []byte, err error) {
if len(plainContent) == 0 {
return nil, nil
}
aesCipherBlock, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
pkcs5PaddingBytes := PKCS5Padding(plainContent, aesCipherBlock.BlockSize())
return BlockEncrypt(pkcs5PaddingBytes, aesCipherBlock)
}
func AesEcbPkcs5PaddingDecrypt(cipherContent, key []byte) (retBytes []byte, err error) {
if len(cipherContent) == 0 {
return nil, nil
}
aesCipherBlock, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
decryptBytes, err := BlockDecrypt(cipherContent, aesCipherBlock)
if err != nil {
return nil, err
}
retBytes = PKCS5UnPadding(decryptBytes)
return retBytes, nil
}
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS5UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
func BlockEncrypt(src []byte, b cipher.Block) (dst []byte, err error) {
if len(src)%b.BlockSize() != 0 {
return nil, fmt.Errorf("input not full blocks")
}
buf := make([]byte, b.BlockSize())
for i := 0; i < len(src); i += b.BlockSize() {
b.Encrypt(buf, src[i:i+b.BlockSize()])
dst = append(dst, buf...)
}
return
}
func BlockDecrypt(src []byte, b cipher.Block) (dst []byte, err error) {
if len(src)%b.BlockSize() != 0 {
return nil, fmt.Errorf("input not full blocks")
}
buf := make([]byte, b.BlockSize())
for i := 0; i < len(src); i += b.BlockSize() {
b.Decrypt(buf, src[i:i+b.BlockSize()])
dst = append(dst, buf...)
}
return
}

View File

@ -1,68 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 encryption
import "fmt"
const (
CipherPrefix = "cipher-"
KmsAes128AlgorithmName = "cipher-kms-aes-128"
KmsAes256AlgorithmName = "cipher-kms-aes-256"
KmsAlgorithmName = "cipher"
kmsAes128KeySpec = "AES_128"
kmsAes256KeySpec = "AES_256"
kmsScheme = "https"
kmsAcceptFormat = "XML"
kmsCipherAlgorithm = "AES/ECB/PKCS5Padding"
maskUnit8Width = 8
maskUnit32Width = 32
KmsHandlerName = "KmsHandler"
)
var (
DataIdParamCheckError = fmt.Errorf("dataId prefix should start with: %s", CipherPrefix)
ContentParamCheckError = fmt.Errorf("content need to encrypt is nil")
KeyIdParamCheckError = fmt.Errorf("keyId is nil, need to be set")
)
var (
PluginNotFoundError = fmt.Errorf("cannot find encryption plugin by dataId prefix")
)
var (
EmptyEncryptedDataKeyError = fmt.Errorf("empty encrypted data key error")
EmptyPlainDataKeyError = fmt.Errorf("empty plain data key error")
EmptyContentError = fmt.Errorf("encrypt empty content error")
)
var (
EmptyRegionKmsV1ClientInitError = fmt.Errorf("init kmsV1 client failed with empty region")
EmptyAkKmsV1ClientInitError = fmt.Errorf("init kmsV1 client failed with empty ak")
EmptySkKmsV1ClientInitError = fmt.Errorf("init kmsV1 client failed with empty sk")
EmptyEndpointKmsV3ClientInitError = fmt.Errorf("init kmsV3 client failed with empty endpoint")
EmptyPasswordKmsV3ClientInitError = fmt.Errorf("init kmsV3 client failed with empty password")
EmptyClientKeyContentKmsV3ClientInitError = fmt.Errorf("init kmsV3 client failed with empty client key content")
EmptyCaVerifyKmsV3ClientInitError = fmt.Errorf("init kmsV3 client failed with empty ca verify")
EmptyEndpointKmsRamClientInitError = fmt.Errorf("init kmsRam client failed with empty endpoint")
)

View File

@ -1,224 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 encryption
import (
"fmt"
"github.com/alibabacloud-go/tea/tea"
dkms_api "github.com/aliyun/alibabacloud-dkms-gcs-go-sdk/openapi"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
"github.com/pkg/errors"
"strings"
)
type HandlerParam struct {
DataId string `json:"dataId"` //required
Content string `json:"content"` //required
EncryptedDataKey string `json:"encryptedDataKey"`
PlainDataKey string `json:"plainDataKey"`
KeyId string `json:"keyId"`
}
type Plugin interface {
Encrypt(*HandlerParam) error
Decrypt(*HandlerParam) error
AlgorithmName() string
GenerateSecretKey(*HandlerParam) (string, error)
EncryptSecretKey(*HandlerParam) (string, error)
DecryptSecretKey(*HandlerParam) (string, error)
}
type Handler interface {
EncryptionHandler(*HandlerParam) error
DecryptionHandler(*HandlerParam) error
RegisterPlugin(Plugin) error
GetHandlerName() string
}
func NewKmsHandler() Handler {
return newKmsHandler()
}
func newKmsHandler() *KmsHandler {
kmsHandler := &KmsHandler{
encryptionPlugins: make(map[string]Plugin, 2),
}
logger.Debug("successfully create encryption KmsHandler")
return kmsHandler
}
func RegisterConfigEncryptionKmsPlugins(encryptionHandler Handler, clientConfig constant.ClientConfig) {
innerKmsClient, err := innerNewKmsClient(clientConfig)
if innerKmsClient == nil {
err = errors.New("create kms client failed.")
}
if err != nil && innerKmsClient == nil {
err = errors.New("create kms client failed.")
}
if err != nil {
logger.Error(err)
}
if err := encryptionHandler.RegisterPlugin(&KmsAes128Plugin{kmsPlugin{kmsClient: innerKmsClient}}); err != nil {
logger.Errorf("failed to register encryption plugin[%s] to %s", KmsAes128AlgorithmName, encryptionHandler.GetHandlerName())
} else {
logger.Debugf("successfully register encryption plugin[%s] to %s", KmsAes128AlgorithmName, encryptionHandler.GetHandlerName())
}
if err := encryptionHandler.RegisterPlugin(&KmsAes256Plugin{kmsPlugin{kmsClient: innerKmsClient}}); err != nil {
logger.Errorf("failed to register encryption plugin[%s] to %s", KmsAes256AlgorithmName, encryptionHandler.GetHandlerName())
} else {
logger.Debugf("successfully register encryption plugin[%s] to %s", KmsAes256AlgorithmName, encryptionHandler.GetHandlerName())
}
if err := encryptionHandler.RegisterPlugin(&KmsBasePlugin{kmsPlugin{kmsClient: innerKmsClient}}); err != nil {
logger.Errorf("failed to register encryption plugin[%s] to %s", KmsAlgorithmName, encryptionHandler.GetHandlerName())
} else {
logger.Debugf("successfully register encryption plugin[%s] to %s", KmsAlgorithmName, encryptionHandler.GetHandlerName())
}
}
type KmsHandler struct {
encryptionPlugins map[string]Plugin
}
func (d *KmsHandler) EncryptionHandler(param *HandlerParam) error {
if err := d.encryptionParamCheck(*param); err != nil {
return err
}
plugin, err := d.getPluginByDataIdPrefix(param.DataId)
if err != nil {
return err
}
plainSecretKey, err := plugin.GenerateSecretKey(param)
if err != nil {
return err
}
param.PlainDataKey = plainSecretKey
return plugin.Encrypt(param)
}
func (d *KmsHandler) DecryptionHandler(param *HandlerParam) error {
if err := d.decryptionParamCheck(*param); err != nil {
return err
}
plugin, err := d.getPluginByDataIdPrefix(param.DataId)
if err != nil {
return err
}
plainSecretkey, err := plugin.DecryptSecretKey(param)
if err != nil {
return err
}
param.PlainDataKey = plainSecretkey
return plugin.Decrypt(param)
}
func (d *KmsHandler) getPluginByDataIdPrefix(dataId string) (Plugin, error) {
var (
matchedCount int
matchedPlugin Plugin
)
for k, v := range d.encryptionPlugins {
if strings.Contains(dataId, k) {
if len(k) > matchedCount {
matchedCount = len(k)
matchedPlugin = v
}
}
}
if matchedPlugin == nil {
return matchedPlugin, PluginNotFoundError
}
return matchedPlugin, nil
}
func (d *KmsHandler) RegisterPlugin(plugin Plugin) error {
if _, v := d.encryptionPlugins[plugin.AlgorithmName()]; v {
logger.Warnf("encryption algorithm [%s] has already registered to defaultHandler, will be update", plugin.AlgorithmName())
} else {
logger.Debugf("register encryption algorithm [%s] to defaultHandler", plugin.AlgorithmName())
}
d.encryptionPlugins[plugin.AlgorithmName()] = plugin
return nil
}
func (d *KmsHandler) GetHandlerName() string {
return KmsHandlerName
}
func (d *KmsHandler) encryptionParamCheck(param HandlerParam) error {
if err := d.dataIdParamCheck(param.DataId); err != nil {
return DataIdParamCheckError
}
if err := d.contentParamCheck(param.Content); err != nil {
return ContentParamCheckError
}
return nil
}
func (d *KmsHandler) decryptionParamCheck(param HandlerParam) error {
return d.encryptionParamCheck(param)
}
func (d *KmsHandler) keyIdParamCheck(keyId string) error {
if len(keyId) == 0 {
return fmt.Errorf("cipher dataId using kmsService need to set keyId, but keyId is nil")
}
return nil
}
func (d *KmsHandler) dataIdParamCheck(dataId string) error {
if !strings.Contains(dataId, CipherPrefix) {
return fmt.Errorf("dataId prefix should start with: %s", CipherPrefix)
}
return nil
}
func (d *KmsHandler) contentParamCheck(content string) error {
if len(content) == 0 {
return fmt.Errorf("content need to encrypt is nil")
}
return nil
}
func innerNewKmsClient(clientConfig constant.ClientConfig) (kmsClient KmsClient, err error) {
switch clientConfig.KMSVersion {
case constant.KMSv1, constant.DEFAULT_KMS_VERSION:
kmsClient, err = newKmsRamClient(clientConfig)
case constant.KMSv3:
kmsClient, err = newKmsV3Client(clientConfig)
default:
err = fmt.Errorf("init kms client failed. unknown kms version:%s\n", clientConfig.KMSVersion)
}
return kmsClient, err
}
func newKmsV1Client(clientConfig constant.ClientConfig) (KmsClient, error) {
return NewKmsV1ClientWithAccessKey(clientConfig.RegionId, clientConfig.AccessKey, clientConfig.SecretKey)
}
func newKmsV3Client(clientConfig constant.ClientConfig) (KmsClient, error) {
return NewKmsV3ClientWithConfig(&dkms_api.Config{
Protocol: tea.String("https"),
Endpoint: tea.String(clientConfig.KMSv3Config.Endpoint),
ClientKeyContent: tea.String(clientConfig.KMSv3Config.ClientKeyContent),
Password: tea.String(clientConfig.KMSv3Config.Password),
}, clientConfig.KMSv3Config.CaContent)
}
func newKmsRamClient(clientConfig constant.ClientConfig) (KmsClient, error) {
return NewKmsRamClient(clientConfig.KMSConfig, clientConfig.RegionId, clientConfig.AccessKey, clientConfig.SecretKey)
}

View File

@ -1,303 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 encryption
import (
"fmt"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
kms20160120 "github.com/alibabacloud-go/kms-20160120/v3/client"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
"github.com/aliyun/alibaba-cloud-sdk-go/services/kms"
dkms_api "github.com/aliyun/alibabacloud-dkms-gcs-go-sdk/openapi"
dkms_transfer "github.com/aliyun/alibabacloud-dkms-transfer-go-sdk/sdk"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
"github.com/pkg/errors"
"net/http"
"strings"
)
type KmsClient interface {
Decrypt(cipherContent string) (string, error)
Encrypt(content string, keyId string) (string, error)
GenerateDataKey(keyId, keySpec string) (string, string, error)
GetKmsVersion() constant.KMSVersion
setKmsVersion(constant.KMSVersion)
}
type TransferKmsClient struct {
*dkms_transfer.KmsTransferClient
kmsVersion constant.KMSVersion
}
func NewKmsV1ClientWithAccessKey(regionId, ak, sk string) (*TransferKmsClient, error) {
var rErr error
if rErr = checkKmsV1InitParam(regionId, ak, sk); rErr != nil {
return nil, rErr
}
kmsClient, err := newKmsV1ClientWithAccessKey(regionId, ak, sk)
if err != nil {
rErr = errors.Wrap(err, "init kms v1 client with ak/sk failed")
} else {
kmsClient.setKmsVersion(constant.KMSv1)
}
return kmsClient, rErr
}
func checkKmsV1InitParam(regionId, ak, sk string) error {
if len(regionId) == 0 {
return EmptyRegionKmsV1ClientInitError
}
if len(ak) == 0 {
return EmptyAkKmsV1ClientInitError
}
if len(sk) == 0 {
return EmptySkKmsV1ClientInitError
}
return nil
}
func checkKmsRamInitParam(endpoint, ak, sk string) error {
if len(endpoint) == 0 {
return EmptyEndpointKmsRamClientInitError
}
if len(ak) == 0 {
return EmptyAkKmsV1ClientInitError
}
if len(sk) == 0 {
return EmptySkKmsV1ClientInitError
}
return nil
}
func NewKmsV3ClientWithConfig(config *dkms_api.Config, caVerify string) (*TransferKmsClient, error) {
var rErr error
if rErr = checkKmsV3InitParam(config, caVerify); rErr != nil {
return nil, rErr
}
kmsClient, err := newKmsV3ClientWithConfig(config)
if err != nil {
rErr = errors.Wrap(err, "init kms v3 client with config failed")
} else {
if len(strings.TrimSpace(caVerify)) != 0 {
logger.Debugf("set kms client Ca with content: %s\n", caVerify[:len(caVerify)/maskUnit32Width])
kmsClient.SetVerify(caVerify)
} else {
kmsClient.SetHTTPSInsecure(true)
}
kmsClient.setKmsVersion(constant.KMSv3)
}
return kmsClient, rErr
}
func checkKmsV3InitParam(config *dkms_api.Config, caVerify string) error {
if len(*config.Endpoint) == 0 {
return EmptyEndpointKmsV3ClientInitError
}
if len(*config.Password) == 0 {
return EmptyPasswordKmsV3ClientInitError
}
if len(*config.ClientKeyContent) == 0 {
return EmptyClientKeyContentKmsV3ClientInitError
}
if len(caVerify) == 0 {
return EmptyCaVerifyKmsV3ClientInitError
}
return nil
}
func newKmsV1ClientWithAccessKey(regionId, ak, sk string) (*TransferKmsClient, error) {
logger.Debugf("init kms client with region:[%s], ak:[%s]xxx, sk:[%s]xxx\n",
regionId, ak[:len(ak)/maskUnit8Width], sk[:len(sk)/maskUnit8Width])
return newKmsClient(regionId, ak, sk, nil)
}
func newKmsV3ClientWithConfig(config *dkms_api.Config) (*TransferKmsClient, error) {
logger.Debugf("init kms client with endpoint:[%s], clientKeyContent:[%s], password:[%s]\n",
config.Endpoint, (*config.ClientKeyContent)[:len(*config.ClientKeyContent)/maskUnit8Width],
(*config.Password)[:len(*config.Password)/maskUnit8Width])
return newKmsClient("", "", "", config)
}
func newKmsClient(regionId, ak, sk string, config *dkms_api.Config) (*TransferKmsClient, error) {
client, err := dkms_transfer.NewClientWithAccessKey(regionId, ak, sk, config)
if err != nil {
return nil, err
}
return &TransferKmsClient{
KmsTransferClient: client,
}, nil
}
func (kmsClient *TransferKmsClient) GetKmsVersion() constant.KMSVersion {
return kmsClient.kmsVersion
}
func (kmsClient *TransferKmsClient) setKmsVersion(kmsVersion constant.KMSVersion) {
logger.Debug("successfully set kms client version to " + kmsVersion)
kmsClient.kmsVersion = kmsVersion
}
func (kmsClient *TransferKmsClient) GenerateDataKey(keyId, keySpec string) (string, string, error) {
generateDataKeyRequest := kms.CreateGenerateDataKeyRequest()
generateDataKeyRequest.Scheme = kmsScheme
generateDataKeyRequest.AcceptFormat = kmsAcceptFormat
generateDataKeyRequest.KeyId = keyId
generateDataKeyRequest.KeySpec = keySpec
generateDataKeyResponse, err := kmsClient.KmsTransferClient.GenerateDataKey(generateDataKeyRequest)
if err != nil {
return "", "", err
}
return generateDataKeyResponse.Plaintext, generateDataKeyResponse.CiphertextBlob, nil
}
func (kmsClient *TransferKmsClient) Decrypt(cipherContent string) (string, error) {
request := kms.CreateDecryptRequest()
request.Method = http.MethodPost
request.Scheme = kmsScheme
request.AcceptFormat = kmsAcceptFormat
request.CiphertextBlob = cipherContent
response, err := kmsClient.KmsTransferClient.Decrypt(request)
if err != nil {
return "", fmt.Errorf("kms decrypt failed: %v", err)
}
return response.Plaintext, nil
}
func (kmsClient *TransferKmsClient) Encrypt(content, keyId string) (string, error) {
request := kms.CreateEncryptRequest()
request.Method = http.MethodPost
request.Scheme = kmsScheme
request.AcceptFormat = kmsAcceptFormat
request.Plaintext = content
request.KeyId = keyId
response, err := kmsClient.KmsTransferClient.Encrypt(request)
if err != nil {
return "", fmt.Errorf("kms encrypt failed: %v", err)
}
return response.CiphertextBlob, nil
}
func GetDefaultKMSv1KeyId() string {
return constant.MSE_KMSv1_DEFAULT_KEY_ID
}
type RamKmsClient struct {
*kms20160120.Client
kmsVersion constant.KMSVersion
runtime *util.RuntimeOptions
}
func NewKmsRamClient(kmsConfig *constant.KMSConfig, regionId, ak, sk string) (*RamKmsClient, error) {
if kmsConfig == nil || len(kmsConfig.Endpoint) == 0 {
if err := checkKmsV1InitParam(regionId, ak, sk); err != nil {
return nil, err
}
KmsV1Config := &openapi.Config{}
KmsV1Config.AccessKeyId = tea.String(ak)
KmsV1Config.AccessKeySecret = tea.String(sk)
KmsV1Config.RegionId = tea.String(regionId)
_result, _err := kms20160120.NewClient(KmsV1Config)
if _err != nil {
return nil, _err
}
_ramClient := &RamKmsClient{
Client: _result,
kmsVersion: constant.KMSv1,
runtime: &util.RuntimeOptions{},
}
return _ramClient, nil
}
if err := checkKmsRamInitParam(kmsConfig.Endpoint, ak, sk); err != nil {
return nil, err
}
config := &openapi.Config{}
config.AccessKeyId = tea.String(ak)
config.AccessKeySecret = tea.String(sk)
if len(regionId) != 0 {
config.RegionId = tea.String(regionId)
}
config.Endpoint = tea.String(kmsConfig.Endpoint)
config.Ca = tea.String(kmsConfig.CaContent)
runtimeOption := &util.RuntimeOptions{}
if len(kmsConfig.CaContent) == 0 {
runtimeOption.IgnoreSSL = tea.Bool(true)
}
if kmsConfig.OpenSSL == "true" {
runtimeOption.IgnoreSSL = tea.Bool(false)
} else if kmsConfig.OpenSSL == "false" {
runtimeOption.IgnoreSSL = tea.Bool(true)
}
_result, _err := kms20160120.NewClient(config)
if _err != nil {
return nil, _err
}
_ramClient := &RamKmsClient{
Client: _result,
kmsVersion: constant.KMSv3,
runtime: runtimeOption,
}
return _ramClient, nil
}
func (kmsClient *RamKmsClient) GetKmsVersion() constant.KMSVersion {
return kmsClient.kmsVersion
}
func (kmsClient *RamKmsClient) setKmsVersion(kmsVersion constant.KMSVersion) {
logger.Debug("successfully set kms client version to " + kmsVersion)
kmsClient.kmsVersion = kmsVersion
}
func (kmsClient *RamKmsClient) GenerateDataKey(keyId, keySpec string) (string, string, error) {
request := &kms20160120.GenerateDataKeyRequest{
KeyId: tea.String(keyId),
KeySpec: tea.String(keySpec),
}
_body, _err := kmsClient.Client.GenerateDataKeyWithOptions(request, kmsClient.runtime)
if _err != nil {
return "", "", _err
}
return *_body.Body.Plaintext, *_body.Body.CiphertextBlob, nil
}
func (kmsClient *RamKmsClient) Decrypt(cipherContent string) (string, error) {
request := &kms20160120.DecryptRequest{
CiphertextBlob: tea.String(cipherContent),
}
_body, _err := kmsClient.Client.DecryptWithOptions(request, kmsClient.runtime)
if _err != nil {
return "", _err
}
return *_body.Body.Plaintext, nil
}
func (kmsClient *RamKmsClient) Encrypt(content, keyId string) (string, error) {
request := &kms20160120.EncryptRequest{
Plaintext: tea.String(content),
KeyId: tea.String(keyId),
}
_body, _err := kmsClient.Client.EncryptWithOptions(request, kmsClient.runtime)
if _err != nil {
return "", _err
}
return *_body.Body.CiphertextBlob, nil
}

View File

@ -1,299 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 encryption
import (
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
inner_encoding "github.com/nacos-group/nacos-sdk-go/v2/common/encoding"
"strings"
)
type kmsPlugin struct {
kmsClient KmsClient
}
func (k *kmsPlugin) Encrypt(param *HandlerParam) error {
err := k.encryptionParamCheck(*param)
if err != nil {
return err
}
secretKeyBase64Decoded, err := inner_encoding.DecodeBase64(inner_encoding.DecodeString2Utf8Bytes(param.PlainDataKey))
if err != nil {
return err
}
contentUtf8Bytes := inner_encoding.DecodeString2Utf8Bytes(param.Content)
encryptedContent, err := AesEcbPkcs5PaddingEncrypt(contentUtf8Bytes, secretKeyBase64Decoded)
if err != nil {
return err
}
contentBase64Encoded, err := inner_encoding.EncodeBase64(encryptedContent)
if err != nil {
return err
}
param.Content = inner_encoding.EncodeUtf8Bytes2String(contentBase64Encoded)
return nil
}
func (k *kmsPlugin) Decrypt(param *HandlerParam) error {
err := k.decryptionParamCheck(*param)
if err != nil {
return err
}
secretKeyBase64Decoded, err := inner_encoding.DecodeBase64(inner_encoding.DecodeString2Utf8Bytes(param.PlainDataKey))
if err != nil {
return err
}
contentBase64Decoded, err := inner_encoding.DecodeBase64(inner_encoding.DecodeString2Utf8Bytes(param.Content))
if err != nil {
return err
}
decryptedContent, err := AesEcbPkcs5PaddingDecrypt(contentBase64Decoded, secretKeyBase64Decoded)
if err != nil {
return err
}
param.Content = inner_encoding.EncodeUtf8Bytes2String(decryptedContent)
return nil
}
func (k *kmsPlugin) AlgorithmName() string {
return ""
}
func (k *kmsPlugin) GenerateSecretKey(param *HandlerParam) (string, error) {
return "", nil
}
func (k *kmsPlugin) EncryptSecretKey(param *HandlerParam) (string, error) {
var keyId string
var err error
if keyId, err = k.keyIdParamCheck(param.KeyId); err != nil {
return "", err
}
if len(param.PlainDataKey) == 0 {
return "", EmptyPlainDataKeyError
}
encryptedDataKey, err := k.kmsClient.Encrypt(param.PlainDataKey, keyId)
if err != nil {
return "", err
}
if len(encryptedDataKey) == 0 {
return "", EmptyEncryptedDataKeyError
}
param.EncryptedDataKey = encryptedDataKey
return encryptedDataKey, nil
}
func (k *kmsPlugin) DecryptSecretKey(param *HandlerParam) (string, error) {
if len(param.EncryptedDataKey) == 0 {
return "", EmptyEncryptedDataKeyError
}
plainDataKey, err := k.kmsClient.Decrypt(param.EncryptedDataKey)
if err != nil {
return "", err
}
if len(plainDataKey) == 0 {
return "", EmptyPlainDataKeyError
}
param.PlainDataKey = plainDataKey
return plainDataKey, nil
}
func (k *kmsPlugin) encryptionParamCheck(param HandlerParam) error {
if err := k.plainDataKeyParamCheck(param.PlainDataKey); err != nil {
return KeyIdParamCheckError
}
if err := k.contentParamCheck(param.Content); err != nil {
return ContentParamCheckError
}
return nil
}
func (k *kmsPlugin) decryptionParamCheck(param HandlerParam) error {
return k.encryptionParamCheck(param)
}
func (k *kmsPlugin) plainDataKeyParamCheck(plainDataKey string) error {
if len(plainDataKey) == 0 {
return EmptyPlainDataKeyError
}
return nil
}
func (k *kmsPlugin) dataIdParamCheck(dataId string) error {
if !strings.Contains(dataId, CipherPrefix) {
return fmt.Errorf("dataId prefix should start with: %s", CipherPrefix)
}
return nil
}
func (k *kmsPlugin) keyIdParamCheck(keyId string) (string, error) {
if len(strings.TrimSpace(keyId)) == 0 {
if k.kmsClient.GetKmsVersion() == constant.KMSv1 {
return GetDefaultKMSv1KeyId(), nil
}
return "", KeyIdParamCheckError
}
return keyId, nil
}
func (k *kmsPlugin) contentParamCheck(content string) error {
if len(content) == 0 {
return fmt.Errorf("content need to encrypt is nil")
}
return nil
}
type KmsAes128Plugin struct {
kmsPlugin
}
func (k *KmsAes128Plugin) Encrypt(param *HandlerParam) error {
return k.kmsPlugin.Encrypt(param)
}
func (k *KmsAes128Plugin) Decrypt(param *HandlerParam) error {
return k.kmsPlugin.Decrypt(param)
}
func (k *KmsAes128Plugin) AlgorithmName() string {
return KmsAes128AlgorithmName
}
func (k *KmsAes128Plugin) GenerateSecretKey(param *HandlerParam) (string, error) {
var keyId string
var err error
if keyId, err = k.keyIdParamCheck(param.KeyId); err != nil {
return "", err
}
plainSecretKey, encryptedSecretKey, err := k.kmsClient.GenerateDataKey(keyId, kmsAes128KeySpec)
if err != nil {
return "", err
}
param.PlainDataKey = plainSecretKey
param.EncryptedDataKey = encryptedSecretKey
if len(param.PlainDataKey) == 0 {
return "", EmptyPlainDataKeyError
}
if len(param.EncryptedDataKey) == 0 {
return "", EmptyEncryptedDataKeyError
}
return plainSecretKey, nil
}
func (k *KmsAes128Plugin) EncryptSecretKey(param *HandlerParam) (string, error) {
return k.kmsPlugin.EncryptSecretKey(param)
}
func (k *KmsAes128Plugin) DecryptSecretKey(param *HandlerParam) (string, error) {
return k.kmsPlugin.DecryptSecretKey(param)
}
type KmsAes256Plugin struct {
kmsPlugin
}
func (k *KmsAes256Plugin) Encrypt(param *HandlerParam) error {
return k.kmsPlugin.Encrypt(param)
}
func (k *KmsAes256Plugin) Decrypt(param *HandlerParam) error {
return k.kmsPlugin.Decrypt(param)
}
func (k *KmsAes256Plugin) AlgorithmName() string {
return KmsAes256AlgorithmName
}
func (k *KmsAes256Plugin) GenerateSecretKey(param *HandlerParam) (string, error) {
var keyId string
var err error
if keyId, err = k.keyIdParamCheck(param.KeyId); err != nil {
return "", err
}
plainSecretKey, encryptedSecretKey, err := k.kmsClient.GenerateDataKey(keyId, kmsAes256KeySpec)
if err != nil {
return "", err
}
param.PlainDataKey = plainSecretKey
param.EncryptedDataKey = encryptedSecretKey
if len(param.PlainDataKey) == 0 {
return "", EmptyPlainDataKeyError
}
if len(param.EncryptedDataKey) == 0 {
return "", EmptyEncryptedDataKeyError
}
return plainSecretKey, nil
}
func (k *KmsAes256Plugin) EncryptSecretKey(param *HandlerParam) (string, error) {
return k.kmsPlugin.EncryptSecretKey(param)
}
func (k *KmsAes256Plugin) DecryptSecretKey(param *HandlerParam) (string, error) {
return k.kmsPlugin.DecryptSecretKey(param)
}
type KmsBasePlugin struct {
kmsPlugin
}
func (k *KmsBasePlugin) Encrypt(param *HandlerParam) error {
var keyId string
var err error
if keyId, err = k.keyIdParamCheck(param.KeyId); err != nil {
return err
}
if len(param.Content) == 0 {
return EmptyContentError
}
encryptedContent, err := k.kmsClient.Encrypt(param.Content, keyId)
if err != nil {
return err
}
param.Content = encryptedContent
return nil
}
func (k *KmsBasePlugin) Decrypt(param *HandlerParam) error {
if len(param.Content) == 0 {
return nil
}
plainContent, err := k.kmsClient.Decrypt(param.Content)
if err != nil {
return err
}
param.Content = plainContent
return nil
}
func (k *KmsBasePlugin) AlgorithmName() string {
return KmsAlgorithmName
}
func (k *KmsBasePlugin) GenerateSecretKey(param *HandlerParam) (string, error) {
return "", nil
}
func (k *KmsBasePlugin) EncryptSecretKey(param *HandlerParam) (string, error) {
return "", nil
}
func (k *KmsBasePlugin) DecryptSecretKey(param *HandlerParam) (string, error) {
return "", nil
}

View File

@ -1,87 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 filter
import (
nacos_inner_encryption "github.com/nacos-group/nacos-sdk-go/v2/common/encryption"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
"github.com/pkg/errors"
"strings"
)
const (
defaultConfigEncryptionFilterName = "defaultConfigEncryptionFilter"
)
var (
noNeedEncryptionError = errors.New("dataId doesn't need to encrypt/decrypt.")
)
type DefaultConfigEncryptionFilter struct {
handler nacos_inner_encryption.Handler
}
func NewDefaultConfigEncryptionFilter(handler nacos_inner_encryption.Handler) IConfigFilter {
return &DefaultConfigEncryptionFilter{handler}
}
func (d *DefaultConfigEncryptionFilter) DoFilter(param *vo.ConfigParam) error {
if err := d.paramCheck(*param); err != nil {
if errors.Is(err, noNeedEncryptionError) {
return nil
}
}
if param.UsageType == vo.RequestType {
encryptionParam := &nacos_inner_encryption.HandlerParam{
DataId: param.DataId,
Content: param.Content,
KeyId: param.KmsKeyId,
}
if err := d.handler.EncryptionHandler(encryptionParam); err != nil {
return err
}
param.Content = encryptionParam.Content
param.EncryptedDataKey = encryptionParam.EncryptedDataKey
} else if param.UsageType == vo.ResponseType {
decryptionParam := &nacos_inner_encryption.HandlerParam{
DataId: param.DataId,
Content: param.Content,
EncryptedDataKey: param.EncryptedDataKey,
}
if err := d.handler.DecryptionHandler(decryptionParam); err != nil {
return err
}
param.Content = decryptionParam.Content
}
return nil
}
func (d *DefaultConfigEncryptionFilter) GetOrder() int {
return 0
}
func (d *DefaultConfigEncryptionFilter) GetFilterName() string {
return defaultConfigEncryptionFilterName
}
func (d *DefaultConfigEncryptionFilter) paramCheck(param vo.ConfigParam) error {
if !strings.HasPrefix(param.DataId, nacos_inner_encryption.CipherPrefix) ||
len(strings.TrimSpace(param.Content)) == 0 {
return noNeedEncryptionError
}
return nil
}

View File

@ -1,104 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 filter
import (
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)
type IConfigFilterChain interface {
AddFilter(IConfigFilter) error
GetFilters() []IConfigFilter
DoFilters(*vo.ConfigParam) error
DoFilterByName(*vo.ConfigParam, string) error
}
type IConfigFilter interface {
DoFilter(*vo.ConfigParam) error
GetOrder() int
GetFilterName() string
}
func RegisterConfigFilterToChain(chain IConfigFilterChain, filter IConfigFilter) error {
return chain.AddFilter(filter)
}
func NewConfigFilterChainManager() IConfigFilterChain {
return newConfigFilterChainManager()
}
func newConfigFilterChainManager() *DefaultConfigFilterChainManager {
return &DefaultConfigFilterChainManager{
configFilterPriorityQueue: make([]IConfigFilter, 0, 2),
}
}
type DefaultConfigFilterChainManager struct {
configFilterPriorityQueue
}
func (m *DefaultConfigFilterChainManager) AddFilter(filter IConfigFilter) error {
return m.configFilterPriorityQueue.addFilter(filter)
}
func (m *DefaultConfigFilterChainManager) GetFilters() []IConfigFilter {
return m.configFilterPriorityQueue
}
func (m *DefaultConfigFilterChainManager) DoFilters(param *vo.ConfigParam) error {
for index := 0; index < len(m.GetFilters()); index++ {
if err := m.GetFilters()[index].DoFilter(param); err != nil {
return err
}
}
return nil
}
func (m *DefaultConfigFilterChainManager) DoFilterByName(param *vo.ConfigParam, name string) error {
for index := 0; index < len(m.GetFilters()); index++ {
if m.GetFilters()[index].GetFilterName() == name {
if err := m.GetFilters()[index].DoFilter(param); err != nil {
return err
}
return nil
}
}
return fmt.Errorf("cannot find the filter[%s]", name)
}
type configFilterPriorityQueue []IConfigFilter
func (c *configFilterPriorityQueue) addFilter(filter IConfigFilter) error {
var pos int = len(*c)
for i := 0; i < len(*c); i++ {
if filter.GetFilterName() == (*c)[i].GetFilterName() {
return nil
}
if filter.GetOrder() < (*c)[i].GetOrder() {
pos = i
break
}
}
if pos == len(*c) {
*c = append((*c)[:], filter)
} else {
temp := append((*c)[:pos], filter)
*c = append(temp[:], (*c)[pos:]...)
}
return nil
}

View File

@ -18,22 +18,19 @@ package http_agent
import (
"net/http"
"net/url"
"strings"
"time"
)
func delete(client *http.Client, path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) {
if len(params) > 0 {
if !strings.HasSuffix(path, "?") {
path = path + "?"
}
for key, value := range params {
path = path + key + "=" + url.QueryEscape(value) + "&"
}
if strings.HasSuffix(path, "&") {
path = path[:len(path)-1]
}
if !strings.HasSuffix(path, "?") {
path = path + "?"
}
for key, value := range params {
path = path + key + "=" + value + "&"
}
if strings.HasSuffix(path, "&") {
path = path[:len(path)-1]
}
client.Timeout = time.Millisecond * time.Duration(timeoutMs)
request, errNew := http.NewRequest(http.MethodDelete, path, nil)

View File

@ -18,21 +18,17 @@ package http_agent
import (
"net/http"
"net/url"
"strings"
"time"
)
func get(client *http.Client, path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) {
if !strings.Contains(path, "?") {
if !strings.HasSuffix(path, "?") {
path = path + "?"
}
for key, value := range params {
if !strings.HasSuffix(path, "&") {
path = path + "&"
}
path = path + key + "=" + url.QueryEscape(value) + "&"
path = path + key + "=" + value + "&"
}
if strings.HasSuffix(path, "&") {
path = path[:len(path)-1]

View File

@ -17,7 +17,7 @@
package http_agent
import (
"io"
"io/ioutil"
"net/http"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
@ -68,7 +68,7 @@ func (agent *HttpAgent) RequestOnlyResult(method string, path string, header htt
logger.Errorf("request method[%s],request path[%s],header:[%s],params:[%s],status code error:%d", method, path, util.ToJsonString(header), util.ToJsonString(params), response.StatusCode)
return ""
}
bytes, errRead := io.ReadAll(response.Body)
bytes, errRead := ioutil.ReadAll(response.Body)
defer response.Body.Close()
if errRead != nil {
logger.Errorf("request method[%s],request path[%s],header:[%s],params:[%s],read error:%+v", method, path, util.ToJsonString(header), util.ToJsonString(params), errRead)

View File

@ -110,12 +110,6 @@ func BuildLoggerConfig(clientConfig constant.ClientConfig) Config {
loggerConfig.LogRollingConfig.MaxBackups = logRollingConfig.MaxBackups
loggerConfig.LogRollingConfig.LocalTime = logRollingConfig.LocalTime
loggerConfig.LogRollingConfig.Compress = logRollingConfig.Compress
} else {
loggerConfig.LogRollingConfig.MaxSize = 100
loggerConfig.LogRollingConfig.MaxAge = 30
loggerConfig.LogRollingConfig.MaxBackups = 5
loggerConfig.LogRollingConfig.LocalTime = true
loggerConfig.LogRollingConfig.Compress = false
}
return loggerConfig
}
@ -163,7 +157,7 @@ func getEncoder() zapcore.EncoderConfig {
}
}
// SetLogger sets logger for sdk
//SetLogger sets logger for sdk
func SetLogger(log Logger) {
logLock.Lock()
defer logLock.Unlock()

View File

@ -40,13 +40,18 @@ func TestGetLogger(t *testing.T) {
// not yet init get default log
log := GetLogger()
config := Config{
Level: "debug",
Level: "degug",
}
_ = InitLogger(config)
// after init logger
log2 := GetLogger()
assert.NotEqual(t, log, log2)
// the secend init logger
config.Level = "info"
_ = InitLogger(config)
log3 := GetLogger()
assert.NotEqual(t, log2, log3)
reset()
}
@ -61,6 +66,13 @@ func TestSetLogger(t *testing.T) {
assert.NotEqual(t, log, log2)
assert.Equal(t, log1, log2)
config := Config{
Level: "degug",
}
_ = InitLogger(config)
// after init logger
log3 := GetLogger()
assert.NotEqual(t, log2, log3)
reset()
}

View File

@ -17,8 +17,11 @@
package nacos_server
import (
"context"
"io"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"fmt"
"io/ioutil"
"math/rand"
"net/http"
"reflect"
@ -30,6 +33,8 @@ import (
"github.com/pkg/errors"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/monitor"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
@ -43,7 +48,7 @@ import (
type NacosServer struct {
sync.RWMutex
securityLogin security.SecurityProxy
securityLogin security.AuthClient
serverList []constant.ServerConfig
httpAgent http_agent.IHttpAgent
timeoutMs uint64
@ -51,25 +56,17 @@ type NacosServer struct {
lastSrvRefTime int64
vipSrvRefInterMills int64
contextPath string
endpointContextPath string
endpointQueryParams string
endpointQueryHeader map[string][]string
clusterName string
currentIndex int32
ServerSrcChangeSignal chan struct{}
}
func NewNacosServer(ctx context.Context, serverList []constant.ServerConfig, clientCfg constant.ClientConfig, httpAgent http_agent.IHttpAgent, timeoutMs uint64, endpoint string, endpointQueryHeader map[string][]string) (*NacosServer, error) {
return NewNacosServerWithRamCredentialProvider(ctx, serverList, clientCfg, httpAgent, timeoutMs, endpoint, endpointQueryHeader, nil)
}
func NewNacosServerWithRamCredentialProvider(ctx context.Context, serverList []constant.ServerConfig, clientCfg constant.ClientConfig, httpAgent http_agent.IHttpAgent, timeoutMs uint64, endpoint string, endpointQueryHeader map[string][]string, provider security.RamCredentialProvider) (*NacosServer, error) {
func NewNacosServer(serverList []constant.ServerConfig, clientCfg constant.ClientConfig, httpAgent http_agent.IHttpAgent, timeoutMs uint64, endpoint string) (*NacosServer, error) {
severLen := len(serverList)
if severLen == 0 && endpoint == "" {
return &NacosServer{}, errors.New("both serverlist and endpoint are empty")
}
securityLogin := security.NewSecurityProxyWithRamCredentialProvider(clientCfg, serverList, httpAgent, provider)
securityLogin := security.NewAuthClient(clientCfg, serverList, httpAgent)
ns := NacosServer{
serverList: serverList,
@ -78,21 +75,21 @@ func NewNacosServerWithRamCredentialProvider(ctx context.Context, serverList []c
timeoutMs: timeoutMs,
endpoint: endpoint,
vipSrvRefInterMills: 10000,
endpointContextPath: clientCfg.EndpointContextPath,
endpointQueryParams: clientCfg.EndpointQueryParams,
endpointQueryHeader: endpointQueryHeader,
clusterName: clientCfg.ClusterName,
contextPath: clientCfg.ContextPath,
ServerSrcChangeSignal: make(chan struct{}, 1),
}
if severLen > 0 {
ns.currentIndex = rand.Int31n(int32(severLen))
} else {
ns.initRefreshSrvIfNeed(ctx)
}
ns.securityLogin.Login()
ns.securityLogin.AutoRefresh(ctx)
ns.initRefreshSrvIfNeed()
_, err := securityLogin.Login()
if err != nil {
return &ns, err
}
securityLogin.AutoRefresh()
return &ns, nil
}
@ -103,6 +100,8 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
contextPath = constant.WEB_CONTEXT
}
signHeaders := GetSignHeaders(params, newHeaders["secretKey"])
url := curServer + contextPath + api
headers := map[string][]string{}
@ -122,6 +121,10 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
}
headers["RequestId"] = []string{uid.String()}
headers["Content-Type"] = []string{"application/x-www-form-urlencoded;charset=utf-8"}
headers["Spas-AccessKey"] = []string{newHeaders["accessKey"]}
headers["Timestamp"] = []string{signHeaders["Timestamp"]}
headers["Spas-Signature"] = []string{signHeaders["Spas-Signature"]}
server.InjectSecurityInfo(params)
var response *http.Response
response, err = server.httpAgent.Request(method, url, headers, timeoutMS, params)
@ -130,7 +133,7 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
return
}
var bytes []byte
bytes, err = io.ReadAll(response.Body)
bytes, err = ioutil.ReadAll(response.Body)
defer response.Body.Close()
if err != nil {
return
@ -165,13 +168,15 @@ func (server *NacosServer) callServer(api string, params map[string]string, meth
headers["Request-Module"] = []string{"Naming"}
headers["Content-Type"] = []string{"application/x-www-form-urlencoded;charset=utf-8"}
server.InjectSecurityInfo(params)
var response *http.Response
response, err = server.httpAgent.Request(method, url, headers, server.timeoutMs, params)
if err != nil {
return
}
var bytes []byte
bytes, err = io.ReadAll(response.Body)
bytes, err = ioutil.ReadAll(response.Body)
defer response.Body.Close()
if err != nil {
return
@ -181,7 +186,7 @@ func (server *NacosServer) callServer(api string, params map[string]string, meth
if response.StatusCode == constant.RESPONSE_CODE_SUCCESS {
return
} else {
err = errors.Errorf("request return error code %d", response.StatusCode)
err = errors.New(fmt.Sprintf("request return error code %d", response.StatusCode))
return
}
}
@ -192,7 +197,7 @@ func (server *NacosServer) ReqConfigApi(api string, params map[string]string, he
return "", errors.New("server list is empty")
}
server.InjectSecurityInfo(params, security.BuildConfigResource(params["tenant"], params["group"], params["dataId"]))
server.InjectSecurityInfo(params)
//only one server,retry request when error
var err error
@ -220,13 +225,13 @@ func (server *NacosServer) ReqConfigApi(api string, params map[string]string, he
return "", errors.Wrapf(err, "retry %d times request failed!", constant.REQUEST_DOMAIN_RETRY_TIME)
}
func (server *NacosServer) ReqApi(api string, params map[string]string, method string, config constant.ClientConfig) (string, error) {
func (server *NacosServer) ReqApi(api string, params map[string]string, method string) (string, error) {
srvs := server.serverList
if srvs == nil || len(srvs) == 0 {
return "", errors.New("server list is empty")
}
server.InjectSecurityInfo(params, security.BuildNamingResource(params["namespaceId"], params["serviceName"], params["groupName"]))
server.InjectSecurityInfo(params)
//only one server,retry request when error
var err error
@ -254,48 +259,30 @@ func (server *NacosServer) ReqApi(api string, params map[string]string, method s
return "", errors.Wrapf(err, "retry %d times request failed!", constant.REQUEST_DOMAIN_RETRY_TIME)
}
func (server *NacosServer) initRefreshSrvIfNeed(ctx context.Context) {
func (server *NacosServer) initRefreshSrvIfNeed() {
if server.endpoint == "" {
return
}
if len(strings.TrimSpace(server.endpointContextPath)) == 0 {
server.endpointContextPath = "nacos"
}
if len(strings.TrimSpace(server.clusterName)) == 0 {
server.clusterName = "serverlist"
}
urlString := "http://" + server.endpoint + "/" + strings.TrimSpace(server.endpointContextPath) + "/" + strings.TrimSpace(server.clusterName)
if len(strings.TrimSpace(server.endpointQueryParams)) != 0 {
urlString += "?" + server.endpointQueryParams
}
logger.Infof("nacos address server url: <%s>", urlString)
server.refreshServerSrvIfNeed(urlString, server.endpointQueryHeader)
server.refreshServerSrvIfNeed()
go func() {
for {
select {
case <-ctx.Done():
return
default:
time.Sleep(time.Duration(10) * time.Second)
server.refreshServerSrvIfNeed(urlString, server.endpointQueryHeader)
}
time.Sleep(time.Duration(1) * time.Second)
server.refreshServerSrvIfNeed()
}
}()
}
func (server *NacosServer) refreshServerSrvIfNeed(urlString string, header map[string][]string) {
func (server *NacosServer) refreshServerSrvIfNeed() {
if util.CurrentMillis()-server.lastSrvRefTime < server.vipSrvRefInterMills && len(server.serverList) > 0 {
return
}
var list []string
result := server.httpAgent.RequestOnlyResult(http.MethodGet, urlString, header, server.timeoutMs, nil)
urlString := "http://" + server.endpoint + "/nacos/serverlist"
result := server.httpAgent.RequestOnlyResult(http.MethodGet, urlString, nil, server.timeoutMs, nil)
list = strings.Split(result, "\n")
logger.Infof("http nacos server list: <%s>", result)
var servers []constant.ServerConfig
contextPath := server.contextPath
@ -321,15 +308,10 @@ func (server *NacosServer) refreshServerSrvIfNeed(urlString string, header map[s
if len(servers) > 0 {
if !reflect.DeepEqual(server.serverList, servers) {
server.Lock()
var serverPrev = server.serverList
logger.Infof("server list is updated, old: <%v>,new:<%v>", serverPrev, servers)
logger.Infof("server list is updated, old: <%v>,new:<%v>", server.serverList, servers)
server.serverList = servers
if serverPrev != nil {
server.ServerSrcChangeSignal <- struct{}{}
}
server.ServerSrcChangeSignal <- struct{}{}
server.lastSrvRefTime = util.CurrentMillis()
server.securityLogin.UpdateServerList(servers)
server.Unlock()
}
@ -341,13 +323,27 @@ func (server *NacosServer) GetServerList() []constant.ServerConfig {
return server.serverList
}
func (server *NacosServer) InjectSecurityInfo(param map[string]string, resource security.RequestResource) {
securityInfo := server.securityLogin.GetSecurityInfo(resource)
for k, v := range securityInfo {
param[k] = v
func (server *NacosServer) InjectSecurityInfo(param map[string]string) {
accessToken := server.securityLogin.GetAccessToken()
if accessToken != "" {
param[constant.KEY_ACCESS_TOKEN] = accessToken
}
}
func (server *NacosServer) InjectSign(request rpc_request.IRequest, param map[string]string, clientConfig constant.ClientConfig) {
if clientConfig.AccessKey == "" || clientConfig.SecretKey == "" {
return
}
sts := request.GetStringToSign()
if sts == "" {
return
}
signature := signWithhmacSHA1Encrypt(sts, clientConfig.SecretKey)
param["data"] = sts
param["signature"] = signature
param["ak"] = clientConfig.AccessKey
}
func getAddress(cfg constant.ServerConfig) string {
if strings.Index(cfg.IpAddr, "http://") >= 0 || strings.Index(cfg.IpAddr, "https://") >= 0 {
return cfg.IpAddr + ":" + strconv.Itoa(int(cfg.Port))
@ -355,6 +351,69 @@ func getAddress(cfg constant.ServerConfig) string {
return cfg.Scheme + "://" + cfg.IpAddr + ":" + strconv.Itoa(int(cfg.Port))
}
func GetSignHeadersFromRequest(cr rpc_request.IConfigRequest, secretKey string) map[string]string {
resource := ""
if len(cr.GetGroup()) != 0 {
resource = cr.GetTenant() + "+" + cr.GetGroup()
} else {
resource = cr.GetGroup()
}
headers := map[string]string{}
timeStamp := strconv.FormatInt(util.CurrentMillis(), 10)
headers["Timestamp"] = timeStamp
signature := ""
if resource == "" {
signature = signWithhmacSHA1Encrypt(timeStamp, secretKey)
} else {
signature = signWithhmacSHA1Encrypt(resource+"+"+timeStamp, secretKey)
}
headers["Spas-Signature"] = signature
return headers
}
func GetSignHeaders(params map[string]string, secretKey string) map[string]string {
resource := ""
if len(params["tenant"]) != 0 {
resource = params["tenant"] + "+" + params["group"]
} else {
resource = params["group"]
}
headers := map[string]string{}
timeStamp := strconv.FormatInt(util.CurrentMillis(), 10)
headers["Timestamp"] = timeStamp
signature := ""
if resource == "" {
signature = signWithhmacSHA1Encrypt(timeStamp, secretKey)
} else {
signature = signWithhmacSHA1Encrypt(resource+"+"+timeStamp, secretKey)
}
headers["Spas-Signature"] = signature
return headers
}
func signWithhmacSHA1Encrypt(encryptText, encryptKey string) string {
//hmac ,use sha1
key := []byte(encryptKey)
mac := hmac.New(sha1.New, key)
mac.Write([]byte(encryptText))
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
}
func (server *NacosServer) GetNextServer() (constant.ServerConfig, error) {
serverLen := len(server.GetServerList())
if serverLen == 0 {
@ -363,3 +422,9 @@ func (server *NacosServer) GetNextServer() (constant.ServerConfig, error) {
index := atomic.AddInt32(&server.currentIndex, 1) % int32(serverLen)
return server.GetServerList()[index], nil
}
func (server *NacosServer) InjectSkAk(params map[string]string, clientConfig constant.ClientConfig) {
if clientConfig.AccessKey != "" {
params["Spas-AccessKey"] = clientConfig.AccessKey
}
}

View File

@ -17,12 +17,8 @@
package nacos_server
import (
"context"
"testing"
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/stretchr/testify/assert"
)
@ -50,138 +46,3 @@ func Test_getAddressWithoutScheme(t *testing.T) {
assert.Equal(t, "https://console.nacos.io:80", getAddress(serverConfigTest))
}
func buildNacosServer(clientConfig constant.ClientConfig) (*NacosServer, error) {
return NewNacosServer(context.Background(),
[]constant.ServerConfig{*constant.NewServerConfig("http://console.nacos.io", 80)},
clientConfig,
&http_agent.HttpAgent{},
1000,
"",
nil)
}
func TestNacosServer_InjectSignForNamingHttp_NoAk(t *testing.T) {
clientConfig := constant.ClientConfig{
AccessKey: "",
SecretKey: "",
}
server, err := buildNacosServer(clientConfig)
if err != nil {
t.FailNow()
}
param := make(map[string]string, 4)
param["serviceName"] = "s-0"
param["groupName"] = "g-0"
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"]))
assert.Empty(t, param["ak"])
assert.Empty(t, param["data"])
assert.Empty(t, param["signature"])
}
func TestNacosServer_InjectSignForNamingHttp_WithGroup(t *testing.T) {
clientConfig := constant.ClientConfig{
AccessKey: "123",
SecretKey: "321",
}
server, err := buildNacosServer(clientConfig)
if err != nil {
t.FailNow()
}
param := make(map[string]string, 4)
param["serviceName"] = "s-0"
param["groupName"] = "g-0"
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"]))
assert.Equal(t, "123", param["ak"])
assert.Contains(t, param["data"], "@@g-0@@s-0")
_, has := param["signature"]
assert.True(t, has)
}
func TestNacosServer_InjectSignForNamingHttp_WithoutGroup(t *testing.T) {
clientConfig := constant.ClientConfig{
AccessKey: "123",
SecretKey: "321",
}
server, err := buildNacosServer(clientConfig)
if err != nil {
t.FailNow()
}
param := make(map[string]string, 4)
param["serviceName"] = "s-0"
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"]))
assert.Equal(t, "123", param["ak"])
assert.NotContains(t, param["data"], "@@g-0@@s-0")
assert.Contains(t, param["data"], "@@s-0")
_, has := param["signature"]
assert.True(t, has)
}
func TestNacosServer_InjectSignForNamingHttp_WithoutServiceName(t *testing.T) {
clientConfig := constant.ClientConfig{
AccessKey: "123",
SecretKey: "321",
}
server, err := buildNacosServer(clientConfig)
if err != nil {
t.FailNow()
}
param := make(map[string]string, 4)
param["groupName"] = "g-0"
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"]))
assert.Equal(t, "123", param["ak"])
assert.Contains(t, param["data"], "@@")
assert.Regexp(t, "\\d+", param["data"])
_, has := param["signature"]
assert.True(t, has)
}
func TestNacosServer_InjectSignForNamingHttp_WithoutServiceNameAndGroup(t *testing.T) {
clientConfig := constant.ClientConfig{
AccessKey: "123",
SecretKey: "321",
}
server, err := buildNacosServer(clientConfig)
if err != nil {
t.FailNow()
}
param := make(map[string]string, 4)
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["serviceName"], param["groupName"]))
assert.Equal(t, "123", param["ak"])
assert.NotContains(t, param["data"], "@@")
assert.Regexp(t, "\\d+", param["data"])
_, has := param["signature"]
assert.True(t, has)
}
func TestNacosServer_UpdateServerListForSecurityLogin(t *testing.T) {
endpoint := "console.nacos.io:80"
clientConfig := constant.ClientConfig{
Username: "nacos",
Password: "nacos",
NamespaceId: "namespace_1",
Endpoint: endpoint,
EndpointContextPath: "nacos",
ClusterName: "serverlist",
AppendToStdout: true,
}
server, err := NewNacosServer(context.Background(),
nil,
clientConfig,
&http_agent.HttpAgent{},
1000,
endpoint,
nil)
if err != nil {
t.FailNow()
}
nacosAuthClient := server.securityLogin.Clients[0]
client, ok := nacosAuthClient.(*security.NacosAuthClient)
assert.True(t, ok)
assert.Equal(t, server.GetServerList(), client.GetServerList())
}

View File

@ -55,5 +55,5 @@ func (c *Connection) getAbandon() bool {
}
func (c *Connection) close() {
_ = c.conn.Close()
c.conn.Close()
}

View File

@ -18,13 +18,8 @@ package rpc
import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"google.golang.org/grpc/credentials"
"io"
"log"
"os"
"strconv"
"sync"
@ -46,21 +41,20 @@ import (
type GrpcClient struct {
*RpcClient
*constant.TLSConfig
}
func NewGrpcClient(ctx context.Context, clientName string, nacosServer *nacos_server.NacosServer, tlsConfig *constant.TLSConfig) *GrpcClient {
func NewGrpcClient(clientName string, nacosServer *nacos_server.NacosServer) *GrpcClient {
rpcClient := &GrpcClient{
&RpcClient{
ctx: ctx,
name: clientName,
labels: make(map[string]string, 8),
rpcClientStatus: INITIALIZED,
eventChan: make(chan ConnectionEvent, 1),
reconnectionChan: make(chan ReconnectContext, 1),
nacosServer: nacosServer,
mux: new(sync.Mutex),
}, tlsConfig,
Name: clientName,
labels: make(map[string]string, 8),
rpcClientStatus: INITIALIZED,
eventChan: make(chan ConnectionEvent),
reconnectionChan: make(chan ReconnectContext, 1),
nacosServer: nacosServer,
serverRequestHandlerMapping: make(map[string]ServerRequestHandlerMapping, 8),
mux: new(sync.Mutex),
},
}
rpcClient.RpcClient.lastActiveTimestamp.Store(time.Now())
rpcClient.executeClient = rpcClient
@ -93,49 +87,6 @@ func getInitialConnWindowSize() int32 {
return int32(initialConnWindowSize)
}
func getTLSCredentials(tlsConfig *constant.TLSConfig, serverInfo ServerInfo) credentials.TransportCredentials {
logger.Infof("build tls config for connecting to server %s,tlsConfig = %s", serverInfo.serverIp, tlsConfig)
certPool, err := x509.SystemCertPool()
if err != nil {
log.Fatalf("load root cert pool fail : %v", err)
}
if len(tlsConfig.CaFile) != 0 {
cert, err := os.ReadFile(tlsConfig.CaFile)
if err != nil {
fmt.Errorf("err, %v", err)
}
if ok := certPool.AppendCertsFromPEM(cert); !ok {
fmt.Errorf("failed to append ca certs")
}
}
config := tls.Config{
InsecureSkipVerify: tlsConfig.TrustAll,
RootCAs: certPool,
Certificates: []tls.Certificate{},
}
if len(tlsConfig.CertFile) != 0 && len(tlsConfig.KeyFile) != 0 {
cert, err := tls.LoadX509KeyPair(tlsConfig.CertFile, tlsConfig.KeyFile)
if err != nil {
log.Fatalf("load cert fail : %v", err)
}
config.Certificates = append(config.Certificates, cert)
}
credentials := credentials.NewTLS(&config)
return credentials
}
func getInitialGrpcTimeout() int32 {
initialGrpcTimeout, err := strconv.Atoi(os.Getenv("nacos.remote.client.grpc.timeout"))
if err != nil {
return constant.DEFAULT_TIMEOUT_MILLS
}
return int32(initialGrpcTimeout)
}
func getKeepAliveTimeMillis() keepalive.ClientParameters {
keepAliveTimeMillisInt, err := strconv.Atoi(os.Getenv("nacos.remote.grpc.keep.alive.millis"))
var keepAliveTime time.Duration
@ -158,11 +109,6 @@ func (c *GrpcClient) createNewConnection(serverInfo ServerInfo) (*grpc.ClientCon
opts = append(opts, grpc.WithInsecure())
opts = append(opts, grpc.WithInitialWindowSize(getInitialWindowSize()))
opts = append(opts, grpc.WithInitialConnWindowSize(getInitialConnWindowSize()))
c.getEnvTLSConfig(c.TLSConfig)
if c.TLSConfig.Enable {
logger.Infof(" tls enable ,trying to connection to server %s with tls config %s", serverInfo.serverIp, c.TLSConfig)
opts = append(opts, grpc.WithTransportCredentials(getTLSCredentials(c.TLSConfig, serverInfo)))
}
rpcPort := serverInfo.serverGrpcPort
if rpcPort == 0 {
rpcPort = serverInfo.serverPort + c.rpcPortOffset()
@ -171,62 +117,30 @@ func (c *GrpcClient) createNewConnection(serverInfo ServerInfo) (*grpc.ClientCon
}
func (c *GrpcClient) getEnvTLSConfig(config *constant.TLSConfig) {
logger.Infof("check tls config ", config)
if config.Appointed == true {
return
}
logger.Infof("try to get tls config from env")
enableTls, err := strconv.ParseBool(os.Getenv("nacos_remote_client_rpc_tls_enable"))
if err == nil {
config.Enable = enableTls
logger.Infof("get tls config from env key = enableTls value = %s", enableTls)
}
if enableTls != true {
logger.Infof(" tls config from env is not enable")
return
}
trustAll, err := strconv.ParseBool(os.Getenv("nacos_remote_client_rpc_tls_trustAll"))
if err == nil {
config.TrustAll = trustAll
logger.Infof("get tls config from env key = trustAll value = %s", trustAll)
}
config.CaFile = os.Getenv("nacos_remote_client_rpc_tls_trustCollectionChainPath")
logger.Infof("get tls config from env key = trustCollectionChainPath value = %s", config.CaFile)
config.CertFile = os.Getenv("nacos_remote_client_rpc_tls_certChainFile")
logger.Infof("get tls config from env key = certChainFile value = %s", config.CertFile)
config.KeyFile = os.Getenv("nacos_remote_client_rpc_tls_certPrivateKey")
logger.Infof("get tls config from env key = certPrivateKey value = %s", config.KeyFile)
}
func (c *GrpcClient) connectToServer(serverInfo ServerInfo) (IConnection, error) {
var client nacos_grpc_service.RequestClient
var biStreamClient nacos_grpc_service.BiRequestStreamClient
conn, err := c.createNewConnection(serverInfo)
if err != nil {
return nil, errors.Errorf("grpc create new connection failed , err:%v", err)
return nil, err
}
client = nacos_grpc_service.NewRequestClient(conn)
response, err := serverCheck(client)
if err != nil {
_ = conn.Close()
return nil, errors.Errorf("server check request failed , err:%v", err)
conn.Close()
return nil, err
}
serverCheckResponse := response.(*rpc_response.ServerCheckResponse)
biStreamClient = nacos_grpc_service.NewBiRequestStreamClient(conn)
serverCheckResponse := response.(*rpc_response.ServerCheckResponse)
biStreamRequestClient, err := biStreamClient.RequestBiStream(context.Background())
if err != nil {
return nil, errors.Errorf("create biStreamRequestClient failed , err:%v", err)
}
grpcConn := NewGrpcConnection(serverInfo, serverCheckResponse.ConnectionId, conn, client, biStreamRequestClient)
c.bindBiRequestStream(biStreamRequestClient, grpcConn)
err = c.sendConnectionSetupRequest(grpcConn)
return grpcConn, err
@ -240,7 +154,7 @@ func (c *GrpcClient) sendConnectionSetupRequest(grpcConn *GrpcConnection) error
csr.ClientAbilities = c.clientAbilities
err := grpcConn.biStreamSend(convertRequest(csr))
if err != nil {
logger.Warnf("send connectionSetupRequest error:%v", err)
logger.Warnf("Send ConnectionSetupRequest error:%+v", err)
}
time.Sleep(100 * time.Millisecond)
return err
@ -251,7 +165,7 @@ func (c *GrpcClient) getConnectionType() ConnectionType {
}
func (c *GrpcClient) rpcPortOffset() uint64 {
return constant.RpcPortOffset
return 1000
}
func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiRequestStream_RequestBiStreamClient, grpcConn *GrpcConnection) {
@ -259,7 +173,6 @@ func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiReque
for {
select {
case <-streamClient.Context().Done():
logger.Warnf("connectionId %s stream client close", grpcConn.getConnectionId())
return
default:
payload, err := streamClient.Recv()
@ -268,21 +181,22 @@ func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiReque
abandon := grpcConn.getAbandon()
if c.IsRunning() && !abandon {
if err == io.EOF {
logger.Infof("connectionId %s request stream onCompleted, switch server", grpcConn.getConnectionId())
logger.Infof("%s Request stream onCompleted, switch server", grpcConn.getConnectionId())
} else {
logger.Errorf("connectionId %s request stream error, switch server, error=%v", grpcConn.getConnectionId(), err)
logger.Errorf("%s Request stream error, switch server, error=%+v", grpcConn.getConnectionId(), err)
}
if atomic.CompareAndSwapInt32((*int32)(&c.rpcClientStatus), int32(RUNNING), int32(UNHEALTHY)) {
c.switchServerAsync(ServerInfo{}, false)
return
}
} else {
logger.Errorf("connectionId %s received error event, isRunning:%v, isAbandon=%v, error=%v", grpcConn.getConnectionId(), running, abandon, err)
logger.Infof("%s received error event, isRunning:%v, isAbandon=%v, error=%+v", grpcConn.getConnectionId(), running, abandon, err)
return
}
} else {
c.handleServerRequest(payload, grpcConn)
}
}
}
}()
@ -290,10 +204,8 @@ func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiReque
func serverCheck(client nacos_grpc_service.RequestClient) (rpc_response.IResponse, error) {
var response rpc_response.ServerCheckResponse
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(getInitialGrpcTimeout())*time.Millisecond)
defer cancel()
for i := 0; i <= 30; i++ {
payload, err := client.Request(ctx, convertRequest(rpc_request.NewServerCheckRequest()))
payload, err := client.Request(context.Background(), convertRequest(rpc_request.NewServerCheckRequest()))
if err != nil {
return nil, err
}
@ -319,14 +231,12 @@ func (c *GrpcClient) handleServerRequest(p *nacos_grpc_service.Payload, grpcConn
client := c.GetRpcClient()
payLoadType := p.GetMetadata().GetType()
handlerMapping, ok := client.serverRequestHandlerMapping.Load(payLoadType)
mapping, ok := client.serverRequestHandlerMapping[payLoadType]
if !ok {
logger.Errorf("%s Unsupported payload type", grpcConn.getConnectionId())
return
}
mapping := handlerMapping.(ServerRequestHandlerMapping)
serverRequest := mapping.serverRequest()
err := json.Unmarshal(p.GetBody().Value, serverRequest)
if err != nil {

View File

@ -18,17 +18,19 @@ package rpc
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
"github.com/pkg/errors"
nacos_grpc_service "github.com/nacos-group/nacos-sdk-go/v2/api/grpc"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"github.com/pkg/errors"
"google.golang.org/protobuf/types/known/anypb"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"github.com/golang/protobuf/ptypes/any"
nacos_grpc_service "github.com/nacos-group/nacos-sdk-go/v2/api/grpc"
"google.golang.org/grpc"
)
@ -57,18 +59,18 @@ func (g *GrpcConnection) request(request rpc_request.IRequest, timeoutMills int6
defer cancel()
responsePayload, err := g.client.Request(ctx, p)
if err != nil {
logger.Debugf("%s grpc request nacos server failed, request=%+v, err=%v ", g.getConnectionId(), p, err)
return nil, err
}
responseFunc, ok := rpc_response.ClientResponseMapping[responsePayload.Metadata.GetType()]
if !ok {
return nil, errors.Errorf("request:%s,unsupported response type:%s", request.GetRequestType(),
responsePayload.Metadata.GetType())
}
logger.Debugf("%s grpc request nacos server success, request=%+v, response=%s", g.getConnectionId(), p, string(responsePayload.GetBody().Value))
return rpc_response.InnerResponseJsonUnmarshal(responsePayload.GetBody().Value, responseFunc)
if !ok {
return nil, errors.New(fmt.Sprintf("request:%s,unsupported response type:%s", request.GetRequestType(),
responsePayload.Metadata.GetType()))
}
response := responseFunc()
err = json.Unmarshal(responsePayload.GetBody().Value, response)
return response, err
}
func (g *GrpcConnection) close() {
@ -87,7 +89,7 @@ func convertRequest(r rpc_request.IRequest) *nacos_grpc_service.Payload {
}
return &nacos_grpc_service.Payload{
Metadata: &Metadata,
Body: &anypb.Any{Value: []byte(r.GetBody(r))},
Body: &any.Any{Value: []byte(r.GetBody(r))},
}
}
@ -98,6 +100,6 @@ func convertResponse(r rpc_response.IResponse) *nacos_grpc_service.Payload {
}
return &nacos_grpc_service.Payload{
Metadata: &Metadata,
Body: &anypb.Any{Value: []byte(r.GetBody())},
Body: &any.Any{Value: []byte(r.GetBody())},
}
}

View File

@ -17,12 +17,8 @@
package rpc
import (
"context"
"fmt"
"math"
"os"
"reflect"
"strings"
"sync"
"sync/atomic"
"time"
@ -97,8 +93,7 @@ type ServerInfo struct {
}
type RpcClient struct {
ctx context.Context
name string
Name string
labels map[string]string
currentConnection IConnection
rpcClientStatus RpcClientStatus
@ -108,7 +103,7 @@ type RpcClient struct {
lastActiveTimestamp atomic.Value
executeClient IRpcClient
nacosServer *nacos_server.NacosServer
serverRequestHandlerMapping sync.Map
serverRequestHandlerMapping map[string]ServerRequestHandlerMapping
mux *sync.Mutex
clientAbilities rpc_request.ClientAbilities
Tenant string
@ -150,31 +145,17 @@ func getClient(clientName string) IRpcClient {
return clientMap[clientName]
}
func CreateClient(ctx context.Context, clientName string, connectionType ConnectionType, labels map[string]string, nacosServer *nacos_server.NacosServer, tlsConfig *constant.TLSConfig, appConnLabels map[string]string) (IRpcClient, error) {
func CreateClient(clientName string, connectionType ConnectionType, labels map[string]string, nacosServer *nacos_server.NacosServer) (IRpcClient, error) {
cMux.Lock()
defer cMux.Unlock()
if _, ok := clientMap[clientName]; !ok {
logger.Infof("init rpc client for name ", clientName)
var rpcClient IRpcClient
if GRPC == connectionType {
rpcClient = NewGrpcClient(ctx, clientName, nacosServer, tlsConfig)
rpcClient = NewGrpcClient(clientName, nacosServer)
}
if rpcClient == nil {
return nil, errors.New("unsupported connection type")
}
logger.Infof("get app conn labels from client config %v ", appConnLabels)
appConnLabelsEnv := getAppLabelsFromEnv()
logger.Infof("get app conn labels from env %v ", appConnLabelsEnv)
appConnLabelsFinal := mergerAppLabels(appConnLabels, appConnLabelsEnv)
logger.Infof("final app conn labels : %v ", appConnLabelsFinal)
appConnLabelsFinal = addPrefixForEachKey(appConnLabelsFinal, "app_")
if len(appConnLabelsFinal) != 0 {
rpcClient.putAllLabels(appConnLabelsFinal)
}
rpcClient.putAllLabels(labels)
clientMap[clientName] = rpcClient
return rpcClient, nil
@ -182,92 +163,6 @@ func CreateClient(ctx context.Context, clientName string, connectionType Connect
return clientMap[clientName], nil
}
func mergerAppLabels(appLabelsAppointed map[string]string, appLabelsEnv map[string]string) map[string]string {
preferred := strings.ToLower(os.Getenv("nacos_app_conn_labels_preferred"))
var preferFirst bool
if preferred != "env" {
preferFirst = true
} else {
preferFirst = false
}
return mergeMaps(appLabelsAppointed, appLabelsEnv, preferFirst)
}
func mergeMaps(map1, map2 map[string]string, preferFirst bool) map[string]string {
result := make(map[string]string, 8)
for k, v := range map1 {
result[k] = v
}
for k, v := range map2 {
_, ok := map1[k]
if preferFirst && ok {
continue
}
result[k] = v
}
return result
}
func getAppLabelsFromEnv() map[string]string {
configMap := make(map[string]string, 8)
// nacos_config_gray_label
grayLabel := os.Getenv("nacos_config_gray_label")
if grayLabel != "" {
configMap["nacos_config_gray_label"] = grayLabel
}
// nacos_app_conn_labels
connLabels := os.Getenv("nacos_app_conn_labels")
if connLabels != "" {
labelsMap := parseLabels(connLabels)
for k, v := range labelsMap {
configMap[k] = v
}
}
return configMap
}
func parseLabels(rawLabels string) map[string]string {
if strings.TrimSpace(rawLabels) == "" {
return make(map[string]string, 2)
}
resultMap := make(map[string]string, 2)
labels := strings.Split(rawLabels, ",")
for _, label := range labels {
if strings.TrimSpace(label) != "" {
kv := strings.Split(label, "=")
if len(kv) == 2 {
resultMap[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
} else {
fmt.Println("unknown label format:", label)
}
}
}
return resultMap
}
func addPrefixForEachKey(m map[string]string, prefix string) map[string]string {
if len(m) == 0 {
return m
}
newMap := make(map[string]string, len(m))
for k, v := range m {
if strings.TrimSpace(k) != "" {
newKey := prefix + k
newMap[newKey] = v
}
}
return newMap
}
func (r *RpcClient) Start() {
if ok := atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(INITIALIZED), (int32)(STARTING)); !ok {
return
@ -275,12 +170,8 @@ func (r *RpcClient) Start() {
r.registerServerRequestHandlers()
go func() {
for {
select {
case event := <-r.eventChan:
r.notifyConnectionEvent(event)
case <-r.ctx.Done():
return
}
event := <-r.eventChan
r.notifyConnectionEvent(event)
}
}()
@ -300,7 +191,7 @@ func (r *RpcClient) Start() {
}
}
if !serverExist {
logger.Infof("%s recommend server is not in server list, ignore recommend server %+v", r.name, rc.serverInfo)
logger.Infof("%s recommend server is not in server list, ignore recommend server %+v", r.Name, rc.serverInfo)
rc.serverInfo = ServerInfo{}
}
}
@ -309,8 +200,6 @@ func (r *RpcClient) Start() {
r.healthCheck(timer)
case <-r.nacosServer.ServerSrcChangeSignal:
r.notifyServerSrvChange()
case <-r.ctx.Done():
return
}
}
}()
@ -321,33 +210,29 @@ func (r *RpcClient) Start() {
startUpRetryTimes--
serverInfo, err := r.nextRpcServer()
if err != nil {
logger.Errorf("[RpcClient.nextRpcServer],err:%v", err)
logger.Errorf("[RpcClient.nextRpcServer],err:%+v", err)
break
}
logger.Infof("[RpcClient.Start] %s try to connect to server on start up, server: %+v", r.name, serverInfo)
logger.Infof("[RpcClient.Start] %s try to connect to server on start up, server: %+v", r.Name, serverInfo)
if connection, err := r.executeClient.connectToServer(serverInfo); err != nil {
logger.Warnf("[RpcClient.Start] %s fail to connect to server on start up, error message=%v, "+
"start up retry times left=%d", r.name, err.Error(), startUpRetryTimes)
"start up retry times left=%d", r.Name, err.Error(), startUpRetryTimes)
} else {
currentConnection = connection
break
}
}
if currentConnection != nil {
logger.Infof("%s success to connect to server %+v on start up, connectionId=%s", r.name,
logger.Infof("%s success to connect to server %+v on start up, connectionId=%s", r.Name,
currentConnection.getServerInfo(), currentConnection.getConnectionId())
r.currentConnection = currentConnection
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
r.notifyConnectionChange(CONNECTED)
r.eventChan <- ConnectionEvent{eventType: CONNECTED}
} else {
r.switchServerAsync(ServerInfo{}, false)
}
}
func (r *RpcClient) notifyConnectionChange(eventType ConnectionStatus) {
r.eventChan <- ConnectionEvent{eventType: eventType}
}
func (r *RpcClient) notifyServerSrvChange() {
if r.currentConnection == nil {
r.switchServerAsync(ServerInfo{}, false)
@ -387,18 +272,18 @@ func (r *RpcClient) RegisterServerRequestHandler(request func() rpc_request.IReq
requestType := request().GetRequestType()
if handler == nil || requestType == "" {
logger.Errorf("%s register server push request handler "+
"missing required parameters,request:%+v handler:%+v", r.name, requestType, handler.Name())
"missing required parameters,request:%+v handler:%+v", r.Name, requestType, handler.Name())
return
}
logger.Debugf("%s register server push request:%s handler:%+v", r.name, requestType, handler.Name())
r.serverRequestHandlerMapping.Store(requestType, ServerRequestHandlerMapping{
logger.Debugf("%s register server push request:%s handler:%+v", r.Name, requestType, handler.Name())
r.serverRequestHandlerMapping[requestType] = ServerRequestHandlerMapping{
serverRequest: request,
handler: handler,
})
}
}
func (r *RpcClient) RegisterConnectionListener(listener IConnectionEventListener) {
logger.Debugf("%s register connection listener [%+v] to current client", r.name, reflect.TypeOf(listener))
logger.Debugf("%s register connection listener [%+v] to current client", r.Name, reflect.TypeOf(listener))
listeners := r.connectionEventListeners.Load()
connectionEventListeners := listeners.([]IConnectionEventListener)
connectionEventListeners = append(connectionEventListeners, listener)
@ -411,9 +296,8 @@ func (r *RpcClient) switchServerAsync(recommendServerInfo ServerInfo, onRequestF
func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
if onRequestFail && r.sendHealthCheck() {
logger.Infof("%s server check success, currentServer is %+v", r.name, r.currentConnection.getServerInfo())
logger.Infof("%s server check success, currentServer is %+v", r.Name, r.currentConnection.getServerInfo())
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
r.notifyConnectionChange(CONNECTED)
return
}
var (
@ -423,7 +307,7 @@ func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
)
if (serverInfo == ServerInfo{}) {
serverInfoFlag = true
logger.Infof("%s try to re connect to a new server, server is not appointed, will choose a random server.", r.name)
logger.Infof("%s try to re connect to a new server, server is not appointed, will choose a random server.", r.Name)
}
for !r.isShutdown() {
@ -436,25 +320,25 @@ func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
}
connectionNew, err := r.executeClient.connectToServer(serverInfo)
if connectionNew != nil && err == nil {
logger.Infof("%s success to connect a server %+v, connectionId=%s", r.name, serverInfo,
logger.Infof("%s success to connect a server %+v, connectionId=%s", r.Name, serverInfo,
connectionNew.getConnectionId())
if r.currentConnection != nil {
logger.Infof("%s abandon prev connection, server is %+v, connectionId is %s", r.name, serverInfo,
logger.Infof("%s abandon prev connection, server is %+v, connectionId is %s", r.Name, serverInfo,
r.currentConnection.getConnectionId())
r.currentConnection.setAbandon(true)
r.closeConnection()
}
r.currentConnection = connectionNew
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
r.notifyConnectionChange(CONNECTED)
r.eventChan <- ConnectionEvent{eventType: CONNECTED}
return
}
if r.isShutdown() {
r.closeConnection()
}
if reConnectTimes > 0 && reConnectTimes%len(r.nacosServer.GetServerList()) == 0 {
logger.Warnf("%s fail to connect server, after trying %d times, last try server is %+v, error=%v", r.name,
logger.Warnf("%s fail to connect server, after trying %d times, last try server is %+v, error=%v", r.Name,
reConnectTimes, serverInfo, err)
if retryTurns < 50 {
retryTurns++
@ -466,14 +350,14 @@ func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
}
}
if r.isShutdown() {
logger.Warnf("%s client is shutdown, stop reconnect to server", r.name)
logger.Warnf("%s client is shutdown, stop reconnect to server", r.Name)
}
}
func (r *RpcClient) closeConnection() {
if r.currentConnection != nil {
r.currentConnection.close()
r.notifyConnectionChange(DISCONNECTED)
r.eventChan <- ConnectionEvent{eventType: DISCONNECTED}
}
}
@ -483,7 +367,7 @@ func (r *RpcClient) notifyConnectionEvent(event ConnectionEvent) {
if len(listeners) == 0 {
return
}
logger.Infof("%s notify %s event to listeners , connectionId=%s", r.name, event.toString(), r.currentConnection.getConnectionId())
logger.Infof("%s notify %s event to listeners.", r.Name, event.toString())
for _, v := range listeners {
if event.isConnected() {
v.OnConnected()
@ -505,10 +389,10 @@ func (r *RpcClient) healthCheck(timer *time.Timer) {
r.lastActiveTimestamp.Store(time.Now())
return
} else {
if r.currentConnection == nil || r.isShutdown() {
if r.currentConnection == nil {
return
}
logger.Infof("%s server healthy check fail, currentConnection=%s", r.name, r.currentConnection.getConnectionId())
logger.Infof("%s server healthy check fail, currentConnection=%s", r.Name, r.currentConnection.getConnectionId())
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(UNHEALTHY))
reconnectContext = ReconnectContext{onRequestFail: false}
}
@ -522,7 +406,6 @@ func (r *RpcClient) sendHealthCheck() bool {
response, err := r.currentConnection.request(rpc_request.NewHealthCheckRequest(),
constant.DEFAULT_TIMEOUT_MILLS, r)
if err != nil {
logger.Errorf("client sendHealthCheck failed,err=%v", err)
return false
}
if !response.IsSuccess() {
@ -557,12 +440,12 @@ func (c *ConnectionEvent) isDisConnected() bool {
return c.eventType == DISCONNECTED
}
// check is this client is shutdown.
//check is this client is shutdown.
func (r *RpcClient) isShutdown() bool {
return atomic.LoadInt32((*int32)(&r.rpcClientStatus)) == (int32)(SHUTDOWN)
}
// IsRunning check is this client is running.
//IsRunning check is this client is running.
func (r *RpcClient) IsRunning() bool {
return atomic.LoadInt32((*int32)(&r.rpcClientStatus)) == (int32)(RUNNING)
}
@ -592,28 +475,25 @@ func (r *RpcClient) Request(request rpc_request.IRequest, timeoutMills int64) (r
continue
}
response, err := r.currentConnection.request(request, timeoutMills, r)
if err != nil {
currentErr = waitReconnect(timeoutMills, &retryTimes, request, err)
continue
}
if resp, ok := response.(*rpc_response.ErrorResponse); ok {
if resp.GetErrorCode() == constant.UN_REGISTER {
r.mux.Lock()
if atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING), (int32)(UNHEALTHY)) {
logger.Infof("Connection is unregistered, switch server, connectionId=%s, request=%s",
r.currentConnection.getConnectionId(), request.GetRequestType())
r.switchServerAsync(ServerInfo{}, false)
if err == nil {
if response, ok := response.(*rpc_response.ErrorResponse); ok {
if response.GetErrorCode() == constant.UN_REGISTER {
r.mux.Lock()
if atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING), (int32)(UNHEALTHY)) {
logger.Infof("Connection is unregistered, switch server, connectionId=%s, request=%s",
r.currentConnection.getConnectionId(), request.GetRequestType())
r.switchServerAsync(ServerInfo{}, false)
}
r.mux.Unlock()
}
r.mux.Unlock()
currentErr = waitReconnect(timeoutMills, &retryTimes, request, errors.New(response.GetMessage()))
continue
}
currentErr = waitReconnect(timeoutMills, &retryTimes, request, errors.New(response.GetMessage()))
continue
r.lastActiveTimestamp.Store(time.Now())
return response, nil
} else {
currentErr = waitReconnect(timeoutMills, &retryTimes, request, err)
}
if response != nil && !response.IsSuccess() {
logger.Warnf("%s request received fail response, error code: %d, result code: %d, message: [%s]", request.GetRequestType(), response.GetErrorCode(), response.GetResultCode(), response.GetMessage())
}
r.lastActiveTimestamp.Store(time.Now())
return response, nil
}
if atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), int32(RUNNING), int32(UNHEALTHY)) {
@ -631,7 +511,3 @@ func waitReconnect(timeoutMills int64, retryTimes *int, request rpc_request.IReq
*retryTimes++
return err
}
func (r *RpcClient) Name() string {
return r.name
}

View File

@ -16,10 +16,7 @@
package rpc_request
import (
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/model"
)
import "github.com/nacos-group/nacos-sdk-go/v2/model"
type ConfigRequest struct {
*Request
@ -54,7 +51,7 @@ func (r *ConfigRequest) GetTenant() string {
return r.Tenant
}
// request of listening a batch of configs.
//request of listening a batch of configs.
type ConfigBatchListenRequest struct {
*ConfigRequest
Listen bool `json:"listen"`
@ -70,7 +67,7 @@ func NewConfigBatchListenRequest(cacheLen int) *ConfigBatchListenRequest {
}
func (r *ConfigBatchListenRequest) GetRequestType() string {
return constant.CONFIG_BATCH_LISTEN_REQUEST_NAME
return "ConfigBatchListenRequest"
}
type ConfigChangeNotifyRequest struct {
@ -82,7 +79,7 @@ func NewConfigChangeNotifyRequest(group, dataId, tenant string) *ConfigChangeNot
}
func (r *ConfigChangeNotifyRequest) GetRequestType() string {
return constant.CONFIG_CHANGE_NOTIFY_REQUEST_NAME
return "ConfigChangeNotifyRequest"
}
type ConfigQueryRequest struct {
@ -95,7 +92,7 @@ func NewConfigQueryRequest(group, dataId, tenant string) *ConfigQueryRequest {
}
func (r *ConfigQueryRequest) GetRequestType() string {
return constant.CONFIG_QUERY_REQUEST_NAME
return "ConfigQueryRequest"
}
type ConfigPublishRequest struct {
@ -111,7 +108,7 @@ func NewConfigPublishRequest(group, dataId, tenant, content, casMd5 string) *Con
}
func (r *ConfigPublishRequest) GetRequestType() string {
return constant.CONFIG_PUBLISH_REQUEST_NAME
return "ConfigPublishRequest"
}
type ConfigRemoveRequest struct {
@ -123,5 +120,5 @@ func NewConfigRemoveRequest(group, dataId, tenant string) *ConfigRemoveRequest {
}
func (r *ConfigRemoveRequest) GetRequestType() string {
return constant.CONFIG_REMOVE_REQUEST_NAME
return "ConfigRemoveRequest"
}

View File

@ -21,7 +21,6 @@ import (
"strconv"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/model"
)
@ -33,6 +32,12 @@ type NamingRequest struct {
Module string `json:"module"`
}
type InstanceRequest struct {
*NamingRequest
Type string `json:"type"`
Instance model.Instance `json:"instance"`
}
func NewNamingRequest(namespace, serviceName, groupName string) *NamingRequest {
request := Request{
Headers: make(map[string]string, 8),
@ -54,12 +59,6 @@ func (r *NamingRequest) GetStringToSign() string {
return data
}
type InstanceRequest struct {
*NamingRequest
Type string `json:"type"`
Instance model.Instance `json:"instance"`
}
func NewInstanceRequest(namespace, serviceName, groupName, Type string, instance model.Instance) *InstanceRequest {
return &InstanceRequest{
NamingRequest: NewNamingRequest(namespace, serviceName, groupName),
@ -69,25 +68,7 @@ func NewInstanceRequest(namespace, serviceName, groupName, Type string, instance
}
func (r *InstanceRequest) GetRequestType() string {
return constant.INSTANCE_REQUEST_NAME
}
type BatchInstanceRequest struct {
*NamingRequest
Type string `json:"type"`
Instances []model.Instance `json:"instances"`
}
func NewBatchInstanceRequest(namespace, serviceName, groupName, Type string, instances []model.Instance) *BatchInstanceRequest {
return &BatchInstanceRequest{
NamingRequest: NewNamingRequest(namespace, serviceName, groupName),
Type: Type,
Instances: instances,
}
}
func (r *BatchInstanceRequest) GetRequestType() string {
return constant.BATCH_INSTANCE_REQUEST_NAME
return "InstanceRequest"
}
type NotifySubscriberRequest struct {
@ -96,7 +77,7 @@ type NotifySubscriberRequest struct {
}
func (r *NotifySubscriberRequest) GetRequestType() string {
return constant.NOTIFY_SUBSCRIBE_REQUEST_NAME
return "NotifySubscriberRequest"
}
type ServiceListRequest struct {
@ -116,7 +97,7 @@ func NewServiceListRequest(namespace, serviceName, groupName string, pageNo, pag
}
func (r *ServiceListRequest) GetRequestType() string {
return constant.SERVICE_LIST_REQUEST_NAME
return "ServiceListRequest"
}
type SubscribeServiceRequest struct {
@ -134,25 +115,25 @@ func NewSubscribeServiceRequest(namespace, serviceName, groupName, clusters stri
}
func (r *SubscribeServiceRequest) GetRequestType() string {
return constant.SUBSCRIBE_SERVICE_REQUEST_NAME
return "SubscribeServiceRequest"
}
type ServiceQueryRequest struct {
*NamingRequest
Cluster string `json:"cluster"`
Clusters string `json:"clusters"`
HealthyOnly bool `json:"healthyOnly"`
UdpPort int `json:"udpPort"`
}
func NewServiceQueryRequest(namespace, serviceName, groupName, cluster string, healthyOnly bool, udpPort int) *ServiceQueryRequest {
func NewServiceQueryRequest(namespace, serviceName, groupName, clusters string, healthyOnly bool, udpPort int) *ServiceQueryRequest {
return &ServiceQueryRequest{
NamingRequest: NewNamingRequest(namespace, serviceName, groupName),
Cluster: cluster,
Clusters: clusters,
HealthyOnly: healthyOnly,
UdpPort: udpPort,
}
}
func (r *ServiceQueryRequest) GetRequestType() string {
return constant.SERVICE_QUERY_REQUEST_NAME
return "ServiceQueryRequest"
}

View File

@ -39,9 +39,6 @@ type IConfigRequest interface {
}
func (r *Request) PutAllHeaders(headers map[string]string) {
if r.Headers == nil {
r.Headers = make(map[string]string)
}
for k, v := range headers {
r.Headers[k] = v
}

View File

@ -1,10 +0,0 @@
package rpc_response
type ResponseCode int
const (
ResponseSuccessCode ResponseCode = 200
ResponseFailCode ResponseCode = 500
ResponseSuccessField = "success"
)

View File

@ -53,14 +53,6 @@ func (c *InstanceResponse) GetResponseType() string {
return "InstanceResponse"
}
type BatchInstanceResponse struct {
*Response
}
func (c *BatchInstanceResponse) GetResponseType() string {
return "BatchInstanceResponse"
}
type QueryServiceResponse struct {
*Response
ServiceInfo model.Service `json:"serviceInfo"`

View File

@ -36,7 +36,6 @@ type IResponse interface {
GetBody() string
GetErrorCode() int
IsSuccess() bool
SetSuccess(bool)
GetResultCode() int
GetMessage() string
}
@ -61,10 +60,6 @@ func (r *Response) IsSuccess() bool {
return r.Success
}
func (r *Response) SetSuccess(successResult bool) {
r.Success = successResult
}
func (r *Response) GetErrorCode() int {
return r.ErrorCode
}
@ -92,11 +87,6 @@ func registerClientResponses() {
return &InstanceResponse{Response: &Response{}}
})
// register BatchInstanceResponse.
registerClientResponse(func() IResponse {
return &BatchInstanceResponse{Response: &Response{}}
})
// register QueryServiceResponse.
registerClientResponse(func() IResponse {
return &QueryServiceResponse{Response: &Response{}}

View File

@ -1,40 +0,0 @@
package rpc_response
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestRpcResponseIsSuccess(t *testing.T) {
responseBody0 := `{"resultCode":200,"errorCode":0}`
responseBody1 := `{"resultCode":200,"errorCode":0,"success":true}`
responseBody2 := `{"resultCode":200,"errorCode":0,"success":"true"}`
responseBody3 := `{"resultCode":200,"errorCode":0,"success":false}`
responseBody4 := `{"resultCode":500,"errorCode":0,"success":true}`
responseBody5 := `{"resultCode":500,"errorCode":0,"success":false}`
responseBodyList := make([]string, 0)
responseBodyList = append(responseBodyList, responseBody0, responseBody1, responseBody2, responseBody3, responseBody4, responseBody5)
for k, v := range ClientResponseMapping {
t.Run("test "+k, func(t *testing.T) {
for index, responseBody := range responseBodyList {
response, err := InnerResponseJsonUnmarshal([]byte(responseBody), v)
switch index {
case 0, 1, 4:
assert.True(t, response.IsSuccess())
break
case 3, 5:
assert.False(t, response.IsSuccess())
break
case 2:
assert.Nil(t, response)
assert.NotNil(t, err)
t.Logf("handle %d failed with responseBody: %s", index, responseBody)
break
default:
panic("unknown index")
}
}
})
}
}

View File

@ -1,24 +0,0 @@
package rpc_response
import "encoding/json"
func InnerResponseJsonUnmarshal(responseBody []byte, responseFunc func() IResponse) (IResponse, error) {
response := responseFunc()
err := json.Unmarshal(responseBody, response)
if err != nil {
return nil, err
}
if !response.IsSuccess() {
tempFiledMap := make(map[string]interface{})
err = json.Unmarshal(responseBody, &tempFiledMap)
if err != nil {
return response, nil
}
if _, ok := tempFiledMap[ResponseSuccessField]; !ok {
response.SetSuccess(response.GetResultCode() == int(ResponseSuccessCode))
}
}
return response, err
}

View File

@ -26,7 +26,7 @@ import (
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
)
// IServerRequestHandler to process the request from server side.
//IServerRequestHandler to process the request from server side.
type IServerRequestHandler interface {
Name() string
//RequestReply Handle request from server.
@ -69,7 +69,7 @@ func (c *ClientDetectionRequestHandler) Name() string {
return "ClientDetectionRequestHandler"
}
func (c *ClientDetectionRequestHandler) RequestReply(request rpc_request.IRequest, _ *RpcClient) rpc_response.IResponse {
func (c *ClientDetectionRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *RpcClient) rpc_response.IResponse {
_, ok := request.(*rpc_request.ClientDetectionRequest)
if ok {
return &rpc_response.ClientDetectionResponse{
@ -87,14 +87,12 @@ func (*NamingPushRequestHandler) Name() string {
return "NamingPushRequestHandler"
}
func (c *NamingPushRequestHandler) RequestReply(request rpc_request.IRequest, client *RpcClient) rpc_response.IResponse {
func (c *NamingPushRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *RpcClient) rpc_response.IResponse {
notifySubscriberRequest, ok := request.(*rpc_request.NotifySubscriberRequest)
if ok {
c.ServiceInfoHolder.ProcessService(&notifySubscriberRequest.ServiceInfo)
logger.Debugf("%s naming push response success ackId->%s", client.currentConnection.getConnectionId(),
request.GetRequestId())
return &rpc_response.NotifySubscriberResponse{
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS, Success: true},
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS},
}
}
return nil

View File

@ -1,185 +0,0 @@
package security
import (
"context"
"encoding/json"
"io"
"net/http"
"strconv"
"strings"
"sync/atomic"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
"github.com/pkg/errors"
)
type NacosAuthClient struct {
username string
password string
accessToken *atomic.Value
tokenTtl int64
lastRefreshTime int64
tokenRefreshWindow int64
agent http_agent.IHttpAgent
clientCfg constant.ClientConfig
serverCfgs []constant.ServerConfig
}
func NewNacosAuthClient(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, agent http_agent.IHttpAgent) *NacosAuthClient {
client := &NacosAuthClient{
username: clientCfg.Username,
password: clientCfg.Password,
serverCfgs: serverCfgs,
clientCfg: clientCfg,
agent: agent,
accessToken: &atomic.Value{},
}
return client
}
func (ac *NacosAuthClient) GetAccessToken() string {
v := ac.accessToken.Load()
if v == nil {
return ""
}
return v.(string)
}
func (ac *NacosAuthClient) GetSecurityInfo(resource RequestResource) map[string]string {
var securityInfo = make(map[string]string, 4)
v := ac.accessToken.Load()
if v != nil {
securityInfo[constant.KEY_ACCESS_TOKEN] = v.(string)
}
return securityInfo
}
func (ac *NacosAuthClient) AutoRefresh(ctx context.Context) {
// If the username is not set, the automatic refresh Token is not enabled
if ac.username == "" {
return
}
go func() {
var timer *time.Timer
if lastLoginSuccess := ac.lastRefreshTime > 0 && ac.tokenTtl > 0 && ac.tokenRefreshWindow > 0; lastLoginSuccess {
timer = time.NewTimer(time.Second * time.Duration(ac.tokenTtl-ac.tokenRefreshWindow))
} else {
timer = time.NewTimer(time.Second * time.Duration(5))
}
defer timer.Stop()
for {
select {
case <-timer.C:
_, err := ac.Login()
if err != nil {
logger.Errorf("login has error %+v", err)
timer.Reset(time.Second * time.Duration(5))
} else {
logger.Infof("login success, tokenTtl: %+v seconds, tokenRefreshWindow: %+v seconds", ac.tokenTtl, ac.tokenRefreshWindow)
timer.Reset(time.Second * time.Duration(ac.tokenTtl-ac.tokenRefreshWindow))
}
case <-ctx.Done():
return
}
}
}()
}
func (ac *NacosAuthClient) Login() (bool, error) {
var throwable error = nil
for i := 0; i < len(ac.serverCfgs); i++ {
result, err := ac.login(ac.serverCfgs[i])
throwable = err
if result {
return true, nil
}
}
return false, throwable
}
func (ac *NacosAuthClient) UpdateServerList(serverList []constant.ServerConfig) {
ac.serverCfgs = serverList
}
func (ac *NacosAuthClient) GetServerList() []constant.ServerConfig {
return ac.serverCfgs
}
func (ac *NacosAuthClient) login(server constant.ServerConfig) (bool, error) {
if ac.lastRefreshTime > 0 && ac.tokenTtl > 0 {
// We refresh 2 windows before expiration to ensure continuous availability
tokenRefreshTime := ac.lastRefreshTime + ac.tokenTtl - 2*ac.tokenRefreshWindow
if time.Now().Unix() < tokenRefreshTime {
return true, nil
}
}
if ac.username == "" {
ac.lastRefreshTime = time.Now().Unix()
return true, nil
}
contextPath := server.ContextPath
if !strings.HasPrefix(contextPath, "/") {
contextPath = "/" + contextPath
}
if strings.HasSuffix(contextPath, "/") {
contextPath = contextPath[0 : len(contextPath)-1]
}
if server.Scheme == "" {
server.Scheme = "http"
}
reqUrl := server.Scheme + "://" + server.IpAddr + ":" + strconv.FormatInt(int64(server.Port), 10) + contextPath + "/v1/auth/users/login"
header := http.Header{
"content-type": []string{"application/x-www-form-urlencoded"},
}
resp, err := ac.agent.Post(reqUrl, header, ac.clientCfg.TimeoutMs, map[string]string{
"username": ac.username,
"password": ac.password,
})
if err != nil {
return false, err
}
var bytes []byte
bytes, err = io.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return false, err
}
if resp.StatusCode != constant.RESPONSE_CODE_SUCCESS {
errMsg := string(bytes)
return false, errors.New(errMsg)
}
var result map[string]interface{}
err = json.Unmarshal(bytes, &result)
if err != nil {
return false, err
}
if val, ok := result[constant.KEY_ACCESS_TOKEN]; ok {
ac.accessToken.Store(val)
ac.lastRefreshTime = time.Now().Unix()
ac.tokenTtl = int64(result[constant.KEY_TOKEN_TTL].(float64))
ac.tokenRefreshWindow = ac.tokenTtl / 10
}
return true, nil
}

View File

@ -1,289 +0,0 @@
package security
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"testing"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/stretchr/testify/assert"
)
// MockResponseBody creates a mock response body for testing
type MockResponseBody struct {
*bytes.Buffer
}
func (m *MockResponseBody) Close() error {
return nil
}
func NewMockResponseBody(data interface{}) io.ReadCloser {
var buf bytes.Buffer
if str, ok := data.(string); ok {
buf.WriteString(str)
} else {
enc := json.NewEncoder(&buf)
enc.SetEscapeHTML(false)
enc.Encode(data)
}
return &MockResponseBody{&buf}
}
// MockHttpAgent implements http_agent.IHttpAgent for testing
type MockHttpAgent struct {
PostFunc func(url string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error)
}
func (m *MockHttpAgent) Request(method string, url string, header http.Header, timeoutMs uint64, params map[string]string) (*http.Response, error) {
switch method {
case http.MethodPost:
return m.Post(url, header, timeoutMs, params)
default:
return &http.Response{
StatusCode: http.StatusMethodNotAllowed,
Body: NewMockResponseBody("method not allowed"),
}, nil
}
}
func (m *MockHttpAgent) RequestOnlyResult(method string, url string, header http.Header, timeoutMs uint64, params map[string]string) string {
resp, err := m.Request(method, url, header, timeoutMs, params)
if err != nil {
return ""
}
if resp.Body == nil {
return ""
}
defer resp.Body.Close()
data, err := io.ReadAll(resp.Body)
if err != nil {
return ""
}
return string(data)
}
func (m *MockHttpAgent) Get(url string, header http.Header, timeoutMs uint64, params map[string]string) (*http.Response, error) {
return m.Request(http.MethodGet, url, header, timeoutMs, params)
}
func (m *MockHttpAgent) Post(url string, header http.Header, timeoutMs uint64, params map[string]string) (*http.Response, error) {
if m.PostFunc != nil {
return m.PostFunc(url, header, timeoutMs, params)
}
return &http.Response{
StatusCode: http.StatusNotImplemented,
Body: NewMockResponseBody("not implemented"),
}, nil
}
func (m *MockHttpAgent) Delete(url string, header http.Header, timeoutMs uint64, params map[string]string) (*http.Response, error) {
return m.Request(http.MethodDelete, url, header, timeoutMs, params)
}
func (m *MockHttpAgent) Put(url string, header http.Header, timeoutMs uint64, params map[string]string) (*http.Response, error) {
return m.Request(http.MethodPut, url, header, timeoutMs, params)
}
func TestNacosAuthClient_Login_Success(t *testing.T) {
// Setup mock response
mockResp := &http.Response{
StatusCode: constant.RESPONSE_CODE_SUCCESS,
Body: NewMockResponseBody(map[string]interface{}{
constant.KEY_ACCESS_TOKEN: "test-token",
constant.KEY_TOKEN_TTL: float64(10),
}),
}
mockAgent := &MockHttpAgent{
PostFunc: func(url string, header http.Header, timeoutMs uint64, params map[string]string) (*http.Response, error) {
// Verify request parameters
assert.Equal(t, "test-user", params["username"])
assert.Equal(t, "test-pass", params["password"])
contentType := header["content-type"]
assert.Equal(t, []string{"application/x-www-form-urlencoded"}, contentType)
return mockResp, nil
},
}
// Create client config
clientConfig := constant.ClientConfig{
Username: "test-user",
Password: "test-pass",
TimeoutMs: 10000,
}
serverConfigs := []constant.ServerConfig{
{
IpAddr: "127.0.0.1",
Port: 8848,
ContextPath: "/nacos",
},
}
client := NewNacosAuthClient(clientConfig, serverConfigs, mockAgent)
// Test login
success, err := client.Login()
assert.NoError(t, err)
assert.True(t, success)
// Verify token is stored
assert.Equal(t, "test-token", client.GetAccessToken())
}
func TestNacosAuthClient_Login_NoAuth(t *testing.T) {
mockAgent := &MockHttpAgent{
PostFunc: func(url string, header http.Header, timeoutMs uint64, params map[string]string) (*http.Response, error) {
t.Fatal("Should not make HTTP call when no username is set")
return nil, nil
},
}
clientConfig := constant.ClientConfig{}
serverConfigs := []constant.ServerConfig{{}}
client := NewNacosAuthClient(clientConfig, serverConfigs, mockAgent)
success, err := client.Login()
assert.NoError(t, err)
assert.True(t, success)
assert.Empty(t, client.GetAccessToken())
}
func TestNacosAuthClient_TokenRefresh(t *testing.T) {
callCount := 0
mockAgent := &MockHttpAgent{
PostFunc: func(url string, header http.Header, timeoutMs uint64, params map[string]string) (*http.Response, error) {
callCount++
return &http.Response{
StatusCode: constant.RESPONSE_CODE_SUCCESS,
Body: NewMockResponseBody(map[string]interface{}{
constant.KEY_ACCESS_TOKEN: "token-" + fmt.Sprintf("%d", callCount),
constant.KEY_TOKEN_TTL: float64(1), // 1 second TTL for quick testing
}),
}, nil
},
}
clientConfig := constant.ClientConfig{
Username: "test-user",
Password: "test-pass",
}
client := NewNacosAuthClient(clientConfig, []constant.ServerConfig{{IpAddr: "localhost"}}, mockAgent)
// Initial login
success, err := client.Login()
assert.NoError(t, err)
assert.True(t, success)
assert.Equal(t, "token-1", client.GetAccessToken())
// Wait for token to require refresh (1 second TTL)
time.Sleep(time.Second * 2)
// Second login should get new token
success, err = client.Login()
assert.NoError(t, err)
assert.True(t, success)
assert.Equal(t, "token-2", client.GetAccessToken())
}
func TestNacosAuthClient_AutoRefresh(t *testing.T) {
callCount := 0
tokenChan := make(chan string, 2)
mockAgent := &MockHttpAgent{
PostFunc: func(url string, header http.Header, timeoutMs uint64, params map[string]string) (*http.Response, error) {
callCount++
token := fmt.Sprintf("auto-token-%d", callCount)
tokenChan <- token
t.Logf("Mock server received request #%d, returning token: %s", callCount, token)
return &http.Response{
StatusCode: constant.RESPONSE_CODE_SUCCESS,
Body: NewMockResponseBody(map[string]interface{}{
constant.KEY_ACCESS_TOKEN: token,
constant.KEY_TOKEN_TTL: float64(10), // 10 seconds TTL, resulting in 1s refresh window
}),
}, nil
},
}
clientConfig := constant.ClientConfig{
Username: "test-user",
Password: "test-pass",
}
client := NewNacosAuthClient(clientConfig, []constant.ServerConfig{{IpAddr: "localhost"}}, mockAgent)
// First do a manual login
t.Log("Performing initial manual login")
success, err := client.Login()
assert.NoError(t, err)
assert.True(t, success)
token1 := <-tokenChan // Get the token from the first login
t.Logf("Initial login successful, token: %s", token1)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel()
// Start auto refresh
t.Log("Starting auto refresh")
client.AutoRefresh(ctx)
// Wait for token refresh (should happen after TTL-2*refreshWindow seconds = 8 seconds)
// We'll wait a bit longer to account for any delays
t.Log("Waiting for token refresh")
var token2 string
select {
case token2 = <-tokenChan:
t.Logf("Received refreshed token: %s", token2)
case <-time.After(time.Second * 12):
t.Fatal("Timeout waiting for token refresh")
}
assert.NotEqual(t, token1, token2, "Token should have been refreshed")
assert.Equal(t, "auto-token-1", token1, "First token should be auto-token-1")
assert.Equal(t, "auto-token-2", token2, "Second token should be auto-token-2")
}
func TestNacosAuthClient_GetSecurityInfo(t *testing.T) {
client := NewNacosAuthClient(constant.ClientConfig{}, []constant.ServerConfig{}, nil)
// When no token
info := client.GetSecurityInfo(RequestResource{})
assert.Empty(t, info[constant.KEY_ACCESS_TOKEN])
// When token exists
mockToken := "test-security-token"
client.accessToken.Store(mockToken)
info = client.GetSecurityInfo(RequestResource{})
assert.Equal(t, mockToken, info[constant.KEY_ACCESS_TOKEN])
}
func TestNacosAuthClient_LoginFailure(t *testing.T) {
mockAgent := &MockHttpAgent{
PostFunc: func(url string, header http.Header, timeoutMs uint64, params map[string]string) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusUnauthorized,
Body: NewMockResponseBody("Invalid credentials"),
}, nil
},
}
client := NewNacosAuthClient(
constant.ClientConfig{Username: "wrong-user", Password: "wrong-pass"},
[]constant.ServerConfig{{IpAddr: "localhost"}},
mockAgent,
)
success, err := client.Login()
assert.Error(t, err)
assert.False(t, success)
assert.Empty(t, client.GetAccessToken())
}

View File

@ -1,95 +0,0 @@
package security
import (
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
)
type RamContext struct {
SignatureRegionId string
AccessKey string
SecretKey string
SecurityToken string
EphemeralAccessKeyId bool
}
type RamAuthClient struct {
clientConfig constant.ClientConfig
ramCredentialProviders []RamCredentialProvider
resourceInjector map[string]ResourceInjector
matchedProvider RamCredentialProvider
}
func NewRamAuthClient(clientCfg constant.ClientConfig) *RamAuthClient {
var providers = []RamCredentialProvider{
&RamRoleArnCredentialProvider{
clientConfig: clientCfg,
},
&EcsRamRoleCredentialProvider{
clientConfig: clientCfg,
},
&OIDCRoleArnCredentialProvider{
clientConfig: clientCfg,
},
&CredentialsURICredentialProvider{
clientConfig: clientCfg,
},
&AutoRotateCredentialProvider{
clientConfig: clientCfg,
},
&StsTokenCredentialProvider{
clientConfig: clientCfg,
},
&AccessKeyCredentialProvider{
clientConfig: clientCfg,
},
}
injectors := map[string]ResourceInjector{
REQUEST_TYPE_NAMING: &NamingResourceInjector{},
REQUEST_TYPE_CONFIG: &ConfigResourceInjector{},
}
return &RamAuthClient{
clientConfig: clientCfg,
ramCredentialProviders: providers,
resourceInjector: injectors,
}
}
func NewRamAuthClientWithProvider(clientCfg constant.ClientConfig, ramCredentialProvider RamCredentialProvider) *RamAuthClient {
ramAuthClient := NewRamAuthClient(clientCfg)
if ramCredentialProvider != nil {
ramAuthClient.ramCredentialProviders = append(ramAuthClient.ramCredentialProviders, ramCredentialProvider)
}
return ramAuthClient
}
func (rac *RamAuthClient) Login() (bool, error) {
for _, provider := range rac.ramCredentialProviders {
if provider.MatchProvider() {
rac.matchedProvider = provider
break
}
}
if rac.matchedProvider == nil {
return false, nil
}
err := rac.matchedProvider.Init()
if err != nil {
return false, err
}
return true, nil
}
func (rac *RamAuthClient) GetSecurityInfo(resource RequestResource) map[string]string {
var securityInfo = make(map[string]string, 4)
if rac.matchedProvider == nil {
return securityInfo
}
ramContext := rac.matchedProvider.GetCredentialsForNacosClient()
rac.resourceInjector[resource.requestType].doInject(resource, ramContext, securityInfo)
return securityInfo
}
func (rac *RamAuthClient) UpdateServerList(serverList []constant.ServerConfig) {
return
}

View File

@ -1,380 +0,0 @@
package security
import (
"encoding/json"
"os"
"strconv"
"github.com/aliyun/aliyun-secretsmanager-client-go/sdk"
"github.com/aliyun/credentials-go/credentials"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
)
const (
ENV_PREFIX string = "ALIBABA_CLOUD_"
ACCESS_KEY_ID_KEY string = ENV_PREFIX + "ACCESS_KEY_ID"
ACCESS_KEY_SECRET_KEY string = ENV_PREFIX + "ACCESS_KEY_SECRET"
SECURITY_TOKEN_KEY string = ENV_PREFIX + "SECURITY_TOKEN"
SIGNATURE_REGION_ID_KEY string = ENV_PREFIX + "SIGNATURE_REGION_ID"
RAM_ROLE_NAME_KEY string = ENV_PREFIX + "RAM_ROLE_NAME"
ROLE_ARN_KEY string = ENV_PREFIX + "ROLE_ARN"
ROLE_SESSION_NAME_KEY string = ENV_PREFIX + "ROLE_SESSION_NAME"
ROLE_SESSION_EXPIRATION_KEY string = ENV_PREFIX + "ROLE_SESSION_EXPIRATION"
POLICY_KEY string = ENV_PREFIX + "POLICY"
OIDC_PROVIDER_ARN_KEY string = ENV_PREFIX + "OIDC_PROVIDER_ARN"
OIDC_TOKEN_FILE_KEY string = ENV_PREFIX + "OIDC_TOKEN_FILE"
CREDENTIALS_URI_KEY string = ENV_PREFIX + "CREDENTIALS_URI"
SECRET_NAME_KEY string = ENV_PREFIX + "SECRET_NAME"
)
func GetNacosProperties(property string, envKey string) string {
if property != "" {
return property
} else {
return os.Getenv(envKey)
}
}
type RamCredentialProvider interface {
MatchProvider() bool
Init() error
GetCredentialsForNacosClient() RamContext
}
type AccessKeyCredentialProvider struct {
clientConfig constant.ClientConfig
accessKey string
secretKey string
signatureRegionId string
}
func (provider *AccessKeyCredentialProvider) MatchProvider() bool {
accessKey := GetNacosProperties(provider.clientConfig.AccessKey, ACCESS_KEY_ID_KEY)
secretKey := GetNacosProperties(provider.clientConfig.SecretKey, ACCESS_KEY_SECRET_KEY)
return accessKey != "" && secretKey != ""
}
func (provider *AccessKeyCredentialProvider) Init() error {
provider.accessKey = GetNacosProperties(provider.clientConfig.AccessKey, ACCESS_KEY_ID_KEY)
provider.secretKey = GetNacosProperties(provider.clientConfig.SecretKey, ACCESS_KEY_SECRET_KEY)
if provider.clientConfig.RamConfig != nil {
provider.signatureRegionId = GetNacosProperties(provider.clientConfig.RamConfig.SignatureRegionId, SIGNATURE_REGION_ID_KEY)
} else {
provider.signatureRegionId = ""
}
return nil
}
func (provider *AccessKeyCredentialProvider) GetCredentialsForNacosClient() RamContext {
ramContext := RamContext{
AccessKey: provider.accessKey,
SecretKey: provider.secretKey,
SignatureRegionId: provider.signatureRegionId,
}
return ramContext
}
type AutoRotateCredentialProvider struct {
clientConfig constant.ClientConfig
secretManagerCacheClient *sdk.SecretManagerCacheClient
secretName string
signatureRegionId string
}
func (provider *AutoRotateCredentialProvider) MatchProvider() bool {
if provider.clientConfig.RamConfig == nil {
return false
}
secretName := GetNacosProperties(provider.clientConfig.RamConfig.SecretName, SECRET_NAME_KEY)
return secretName != ""
}
func (provider *AutoRotateCredentialProvider) Init() error {
secretName := GetNacosProperties(provider.clientConfig.RamConfig.SecretName, SECRET_NAME_KEY)
client, err := sdk.NewClient()
if err != nil {
return err
}
provider.secretManagerCacheClient = client
provider.secretName = secretName
provider.signatureRegionId = GetNacosProperties(provider.clientConfig.RamConfig.SignatureRegionId, SIGNATURE_REGION_ID_KEY)
return nil
}
func (provider *AutoRotateCredentialProvider) GetCredentialsForNacosClient() RamContext {
if provider.secretManagerCacheClient == nil || provider.secretName == "" {
return RamContext{}
}
secretInfo, err := provider.secretManagerCacheClient.GetSecretInfo(provider.secretName)
if err != nil {
return RamContext{}
}
var m map[string]string
err = json.Unmarshal([]byte(secretInfo.SecretValue), &m)
if err != nil {
return RamContext{}
}
accessKeyId := m["AccessKeyId"]
accessKeySecret := m["AccessKeySecret"]
ramContext := RamContext{
AccessKey: accessKeyId,
SecretKey: accessKeySecret,
SignatureRegionId: provider.signatureRegionId,
EphemeralAccessKeyId: false,
}
return ramContext
}
type StsTokenCredentialProvider struct {
clientConfig constant.ClientConfig
accessKey string
secretKey string
securityToken string
signatureRegionId string
}
func (provider *StsTokenCredentialProvider) MatchProvider() bool {
accessKey := GetNacosProperties(provider.clientConfig.AccessKey, ACCESS_KEY_ID_KEY)
secretKey := GetNacosProperties(provider.clientConfig.SecretKey, ACCESS_KEY_SECRET_KEY)
if provider.clientConfig.RamConfig == nil {
return false
}
stsToken := GetNacosProperties(provider.clientConfig.RamConfig.SecurityToken, SECURITY_TOKEN_KEY)
return accessKey != "" && secretKey != "" && stsToken != ""
}
func (provider *StsTokenCredentialProvider) Init() error {
provider.accessKey = GetNacosProperties(provider.clientConfig.AccessKey, ACCESS_KEY_ID_KEY)
provider.secretKey = GetNacosProperties(provider.clientConfig.SecretKey, ACCESS_KEY_SECRET_KEY)
provider.securityToken = GetNacosProperties(provider.clientConfig.RamConfig.SecurityToken, SECURITY_TOKEN_KEY)
provider.signatureRegionId = GetNacosProperties(provider.clientConfig.RamConfig.SignatureRegionId, SIGNATURE_REGION_ID_KEY)
return nil
}
func (provider *StsTokenCredentialProvider) GetCredentialsForNacosClient() RamContext {
ramContext := RamContext{
AccessKey: provider.accessKey,
SecretKey: provider.secretKey,
SecurityToken: provider.securityToken,
SignatureRegionId: provider.signatureRegionId,
EphemeralAccessKeyId: true,
}
return ramContext
}
type EcsRamRoleCredentialProvider struct {
clientConfig constant.ClientConfig
credentialClient credentials.Credential
signatureRegionId string
}
func (provider *EcsRamRoleCredentialProvider) MatchProvider() bool {
if provider.clientConfig.RamConfig == nil {
return false
}
ramRoleName := GetNacosProperties(provider.clientConfig.RamConfig.RamRoleName, RAM_ROLE_NAME_KEY)
return ramRoleName != ""
}
func (provider *EcsRamRoleCredentialProvider) Init() error {
ramRoleName := GetNacosProperties(provider.clientConfig.RamConfig.RamRoleName, RAM_ROLE_NAME_KEY)
credentialsConfig := new(credentials.Config).SetType("ecs_ram_role").SetRoleName(ramRoleName)
credentialClient, err := credentials.NewCredential(credentialsConfig)
if err != nil {
return err
}
provider.credentialClient = credentialClient
provider.signatureRegionId = GetNacosProperties(provider.clientConfig.RamConfig.SignatureRegionId, SIGNATURE_REGION_ID_KEY)
return nil
}
func (provider *EcsRamRoleCredentialProvider) GetCredentialsForNacosClient() RamContext {
if provider.credentialClient == nil {
return RamContext{}
}
credential, err := provider.credentialClient.GetCredential()
if err != nil {
return RamContext{}
}
ramContext := RamContext{
AccessKey: *credential.AccessKeyId,
SecretKey: *credential.AccessKeySecret,
SecurityToken: *credential.SecurityToken,
SignatureRegionId: provider.signatureRegionId,
EphemeralAccessKeyId: true,
}
return ramContext
}
type RamRoleArnCredentialProvider struct {
clientConfig constant.ClientConfig
credentialClient credentials.Credential
signatureRegionId string
}
func (provider *RamRoleArnCredentialProvider) MatchProvider() bool {
if provider.clientConfig.RamConfig == nil {
return false
}
accessKey := GetNacosProperties(provider.clientConfig.AccessKey, ACCESS_KEY_ID_KEY)
secretKey := GetNacosProperties(provider.clientConfig.SecretKey, ACCESS_KEY_SECRET_KEY)
roleArn := GetNacosProperties(provider.clientConfig.RamConfig.RoleArn, ROLE_ARN_KEY)
roleSessionName := GetNacosProperties(provider.clientConfig.RamConfig.RoleSessionName, ROLE_SESSION_NAME_KEY)
oidcProviderArn := GetNacosProperties(provider.clientConfig.RamConfig.OIDCProviderArn, OIDC_PROVIDER_ARN_KEY)
return accessKey == "" && secretKey == "" && roleArn != "" && roleSessionName != "" && oidcProviderArn == ""
}
func (provider *RamRoleArnCredentialProvider) Init() error {
accessKey := GetNacosProperties(provider.clientConfig.AccessKey, ACCESS_KEY_ID_KEY)
secretKey := GetNacosProperties(provider.clientConfig.SecretKey, ACCESS_KEY_SECRET_KEY)
roleArn := GetNacosProperties(provider.clientConfig.RamConfig.RoleArn, ROLE_ARN_KEY)
roleSessionName := GetNacosProperties(provider.clientConfig.RamConfig.RoleSessionName, ROLE_SESSION_NAME_KEY)
credentialsConfig := new(credentials.Config).SetType("ram_role_arn").
SetAccessKeyId(accessKey).SetAccessKeySecret(secretKey).
SetRoleArn(roleArn).SetRoleSessionName(roleSessionName)
if roleSessionExpiration := GetNacosProperties(strconv.Itoa(provider.clientConfig.RamConfig.RoleSessionExpiration), ROLE_SESSION_EXPIRATION_KEY); roleSessionExpiration != "" {
if roleSessionExpirationTime, err := strconv.Atoi(roleSessionExpiration); err == nil {
if roleSessionExpirationTime == 0 {
roleSessionExpirationTime = 3600
}
credentialsConfig.SetRoleSessionExpiration(roleSessionExpirationTime)
}
}
policy := GetNacosProperties(provider.clientConfig.RamConfig.Policy, POLICY_KEY)
if policy != "" {
credentialsConfig.SetPolicy(policy)
}
credentialClient, err := credentials.NewCredential(credentialsConfig)
if err != nil {
return err
}
provider.credentialClient = credentialClient
provider.signatureRegionId = GetNacosProperties(provider.clientConfig.RamConfig.SignatureRegionId, SIGNATURE_REGION_ID_KEY)
return nil
}
func (provider *RamRoleArnCredentialProvider) GetCredentialsForNacosClient() RamContext {
if provider.credentialClient == nil {
return RamContext{}
}
credential, err := provider.credentialClient.GetCredential()
if err != nil {
return RamContext{}
}
return RamContext{
AccessKey: *credential.AccessKeyId,
SecretKey: *credential.AccessKeySecret,
SecurityToken: *credential.SecurityToken,
SignatureRegionId: provider.signatureRegionId,
EphemeralAccessKeyId: true,
}
}
type OIDCRoleArnCredentialProvider struct {
clientConfig constant.ClientConfig
credentialClient credentials.Credential
signatureRegionId string
}
func (provider *OIDCRoleArnCredentialProvider) MatchProvider() bool {
if provider.clientConfig.RamConfig == nil {
return false
}
roleArn := GetNacosProperties(provider.clientConfig.RamConfig.RoleArn, ROLE_ARN_KEY)
roleSessionName := GetNacosProperties(provider.clientConfig.RamConfig.RoleSessionName, ROLE_SESSION_NAME_KEY)
oidcProviderArn := GetNacosProperties(provider.clientConfig.RamConfig.OIDCProviderArn, OIDC_PROVIDER_ARN_KEY)
oidcTokenFile := GetNacosProperties(provider.clientConfig.RamConfig.OIDCTokenFilePath, OIDC_TOKEN_FILE_KEY)
return roleArn != "" && roleSessionName != "" && oidcProviderArn != "" && oidcTokenFile != ""
}
func (provider *OIDCRoleArnCredentialProvider) Init() error {
ramRoleArn := GetNacosProperties(provider.clientConfig.RamConfig.RoleArn, ROLE_ARN_KEY)
roleSessionName := GetNacosProperties(provider.clientConfig.RamConfig.RoleSessionName, ROLE_SESSION_NAME_KEY)
oidcProviderArn := GetNacosProperties(provider.clientConfig.RamConfig.OIDCProviderArn, OIDC_PROVIDER_ARN_KEY)
oidcTokenFilePath := GetNacosProperties(provider.clientConfig.RamConfig.OIDCTokenFilePath, OIDC_TOKEN_FILE_KEY)
credentialsConfig := new(credentials.Config).SetType("oidc_role_arn").
SetRoleArn(ramRoleArn).SetRoleSessionName(roleSessionName).
SetOIDCProviderArn(oidcProviderArn).SetOIDCTokenFilePath(oidcTokenFilePath)
if roleSessionExpiration := GetNacosProperties(strconv.Itoa(provider.clientConfig.RamConfig.RoleSessionExpiration), ROLE_SESSION_EXPIRATION_KEY); roleSessionExpiration != "" {
if roleSessionExpirationTime, err := strconv.Atoi(roleSessionExpiration); err == nil {
if roleSessionExpirationTime == 0 {
roleSessionExpirationTime = 3600
}
credentialsConfig.SetRoleSessionExpiration(roleSessionExpirationTime)
}
}
policy := GetNacosProperties(provider.clientConfig.RamConfig.Policy, POLICY_KEY)
if policy != "" {
credentialsConfig.SetPolicy(policy)
}
credentialClient, err := credentials.NewCredential(credentialsConfig)
if err != nil {
return err
}
provider.credentialClient = credentialClient
provider.signatureRegionId = GetNacosProperties(provider.clientConfig.RamConfig.SignatureRegionId, SIGNATURE_REGION_ID_KEY)
return nil
}
func (provider *OIDCRoleArnCredentialProvider) GetCredentialsForNacosClient() RamContext {
if provider.credentialClient == nil {
return RamContext{}
}
credential, err := provider.credentialClient.GetCredential()
if err != nil {
return RamContext{}
}
return RamContext{
AccessKey: *credential.AccessKeyId,
SecretKey: *credential.AccessKeySecret,
SecurityToken: *credential.SecurityToken,
SignatureRegionId: provider.signatureRegionId,
EphemeralAccessKeyId: true,
}
}
type CredentialsURICredentialProvider struct {
clientConfig constant.ClientConfig
credentialClient credentials.Credential
signatureRegionId string
}
func (provider *CredentialsURICredentialProvider) MatchProvider() bool {
if provider.clientConfig.RamConfig == nil {
return false
}
credentialsURI := GetNacosProperties(provider.clientConfig.RamConfig.CredentialsURI, CREDENTIALS_URI_KEY)
return credentialsURI != ""
}
func (provider *CredentialsURICredentialProvider) Init() error {
credentialsURI := GetNacosProperties(provider.clientConfig.RamConfig.CredentialsURI, CREDENTIALS_URI_KEY)
credentialsConfig := new(credentials.Config).SetType("credentials_uri").SetURLCredential(credentialsURI)
credentialClient, err := credentials.NewCredential(credentialsConfig)
if err != nil {
return err
}
provider.credentialClient = credentialClient
provider.signatureRegionId = GetNacosProperties(provider.clientConfig.RamConfig.SignatureRegionId, SIGNATURE_REGION_ID_KEY)
return nil
}
func (provider *CredentialsURICredentialProvider) GetCredentialsForNacosClient() RamContext {
if provider.credentialClient == nil {
return RamContext{}
}
if provider.credentialClient == nil {
return RamContext{}
}
credential, err := provider.credentialClient.GetCredential()
if err != nil {
return RamContext{}
}
return RamContext{
AccessKey: *credential.AccessKeyId,
SecretKey: *credential.AccessKeySecret,
SecurityToken: *credential.SecurityToken,
SignatureRegionId: provider.signatureRegionId,
EphemeralAccessKeyId: true,
}
}

View File

@ -1,127 +0,0 @@
package security
import (
"fmt"
"strings"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
)
type ResourceInjector interface {
doInject(resource RequestResource, ramContext RamContext, param map[string]string)
}
const (
CONFIG_AK_FILED string = "Spas-AccessKey"
NAMING_AK_FILED string = "ak"
SECURITY_TOKEN_HEADER string = "Spas-SecurityToken"
SIGNATURE_VERSION_HEADER string = "signatureVersion"
SIGNATURE_VERSION_V4 string = "v4"
SERVICE_INFO_SPLITER string = "@@"
TIMESTAMP_HEADER string = "Timestamp"
SIGNATURE_HEADER string = "Spas-Signature"
)
type NamingResourceInjector struct {
}
func (n *NamingResourceInjector) doInject(resource RequestResource, ramContext RamContext, param map[string]string) {
param[NAMING_AK_FILED] = ramContext.AccessKey
if ramContext.EphemeralAccessKeyId {
param[SECURITY_TOKEN_HEADER] = ramContext.SecurityToken
}
secretKey := trySignatureWithV4(ramContext, param)
signatures := n.calculateSignature(resource, secretKey, ramContext)
for k, v := range signatures {
param[k] = v
}
}
func (n *NamingResourceInjector) calculateSignature(resource RequestResource, secretKey string, ramContext RamContext) map[string]string {
var result = make(map[string]string, 4)
signData := n.getSignData(n.getGroupedServiceName(resource))
signature, err := Sign(signData, secretKey)
if err != nil {
logger.Errorf("get v4 signatrue error: %v", err)
return result
}
result["signature"] = signature
result["data"] = signData
return result
}
func (n *NamingResourceInjector) getGroupedServiceName(resource RequestResource) string {
if strings.Contains(resource.resource, SERVICE_INFO_SPLITER) || resource.group == "" {
return resource.resource
}
return resource.group + SERVICE_INFO_SPLITER + resource.resource
}
func (n *NamingResourceInjector) getSignData(serviceName string) string {
if serviceName != "" {
return fmt.Sprintf("%d%s%s", time.Now().UnixMilli(), SERVICE_INFO_SPLITER, serviceName)
}
return fmt.Sprintf("%d", time.Now().UnixMilli())
}
type ConfigResourceInjector struct {
}
func (c *ConfigResourceInjector) doInject(resource RequestResource, ramContext RamContext, param map[string]string) {
param[CONFIG_AK_FILED] = ramContext.AccessKey
if ramContext.EphemeralAccessKeyId {
param[SECURITY_TOKEN_HEADER] = ramContext.SecurityToken
}
secretKey := trySignatureWithV4(ramContext, param)
signatures := c.calculateSignature(resource, secretKey, ramContext)
for k, v := range signatures {
param[k] = v
}
}
func (c *ConfigResourceInjector) calculateSignature(resource RequestResource, secretKey string, ramContext RamContext) map[string]string {
var result = make(map[string]string, 4)
resourceName := c.getResourceName(resource)
signHeaders := c.getSignHeaders(resourceName, secretKey)
for k, v := range signHeaders {
result[k] = v
}
return result
}
func (c *ConfigResourceInjector) getResourceName(resource RequestResource) string {
if resource.namespace != "" {
return resource.namespace + "+" + resource.group
} else {
return resource.group
}
}
func (c *ConfigResourceInjector) getSignHeaders(resource, secretKey string) map[string]string {
header := make(map[string]string, 4)
timeStamp := fmt.Sprintf("%d", time.Now().UnixMilli())
header[TIMESTAMP_HEADER] = timeStamp
if secretKey != "" {
var signature string
if strings.TrimSpace(resource) == "" {
signature = signWithHmacSha1Encrypt(timeStamp, secretKey)
} else {
signature = signWithHmacSha1Encrypt(resource+"+"+timeStamp, secretKey)
}
header[SIGNATURE_HEADER] = signature
}
return header
}
func trySignatureWithV4(ramContext RamContext, param map[string]string) string {
if ramContext.SignatureRegionId == "" {
return ramContext.SecretKey
}
signatureV4, err := finalSigningKeyStringWithDefaultInfo(ramContext.SecretKey, ramContext.SignatureRegionId)
if err != nil {
logger.Errorf("get v4 signatrue error: %v", err)
return ramContext.SecretKey
}
param[SIGNATURE_VERSION_HEADER] = SIGNATURE_VERSION_V4
return signatureV4
}

View File

@ -1,98 +0,0 @@
package security
import (
"github.com/stretchr/testify/assert"
"testing"
)
func Test_NamingResourceInjector_doInject(t *testing.T) {
namingResourceInjector := NamingResourceInjector{}
resource := BuildNamingResource("testNamespace", "testGroup", "testServiceName")
t.Run("test_doInject_v4_sts", func(t *testing.T) {
ramContext := RamContext{
AccessKey: "testAccessKey",
SecretKey: "testSecretKey",
SecurityToken: "testSecurityToken",
EphemeralAccessKeyId: true,
SignatureRegionId: "testSignatureRegionId",
}
param := map[string]string{}
namingResourceInjector.doInject(resource, ramContext, param)
assert.Equal(t, param[NAMING_AK_FILED], ramContext.AccessKey)
assert.Equal(t, param[SECURITY_TOKEN_HEADER], ramContext.SecurityToken)
assert.Equal(t, param[SIGNATURE_VERSION_HEADER], SIGNATURE_VERSION_V4)
assert.NotEmpty(t, param["signature"])
})
t.Run("test_doInject", func(t *testing.T) {
ramContext := RamContext{
AccessKey: "testAccessKey",
SecretKey: "testSecretKey",
}
param := map[string]string{}
namingResourceInjector.doInject(resource, ramContext, param)
assert.Equal(t, param[NAMING_AK_FILED], ramContext.AccessKey)
assert.Empty(t, param[SECURITY_TOKEN_HEADER])
assert.Empty(t, param[SIGNATURE_VERSION_HEADER])
assert.NotEmpty(t, param["signature"])
})
}
func Test_NamingResourceInjector_getGroupedServiceName(t *testing.T) {
namingResourceInjector := NamingResourceInjector{}
t.Run("test_getGroupedServiceName", func(t *testing.T) {
resource := BuildNamingResource("testNamespace", "testGroup", "testServiceName")
assert.Equal(t, namingResourceInjector.getGroupedServiceName(resource), "testGroup@@testServiceName")
})
t.Run("test_getGroupedServiceName_without_group", func(t *testing.T) {
resource := BuildNamingResource("testNamespace", "", "testServiceName")
assert.Equal(t, namingResourceInjector.getGroupedServiceName(resource), "testServiceName")
})
}
func Test_ConfigResourceInjector_doInject(t *testing.T) {
configResourceInjector := ConfigResourceInjector{}
resource := BuildConfigResource("testTenant", "testGroup", "testDataId")
t.Run("test_doInject_v4_sts", func(t *testing.T) {
ramContext := RamContext{
AccessKey: "testAccessKey",
SecretKey: "testSecretKey",
SecurityToken: "testSecurityToken",
EphemeralAccessKeyId: true,
SignatureRegionId: "testSignatureRegionId",
}
param := map[string]string{}
configResourceInjector.doInject(resource, ramContext, param)
assert.Equal(t, param[CONFIG_AK_FILED], ramContext.AccessKey)
assert.Equal(t, param[SECURITY_TOKEN_HEADER], ramContext.SecurityToken)
assert.Equal(t, param[SIGNATURE_VERSION_HEADER], SIGNATURE_VERSION_V4)
assert.NotEmpty(t, param[SIGNATURE_HEADER])
assert.NotEmpty(t, param[TIMESTAMP_HEADER])
})
t.Run("test_doInject", func(t *testing.T) {
ramContext := RamContext{
AccessKey: "testAccessKey",
SecretKey: "testSecretKey",
}
param := map[string]string{}
configResourceInjector.doInject(resource, ramContext, param)
assert.Equal(t, param[CONFIG_AK_FILED], ramContext.AccessKey)
assert.Empty(t, param[SECURITY_TOKEN_HEADER])
assert.Empty(t, param[SIGNATURE_VERSION_HEADER])
assert.NotEmpty(t, param[SIGNATURE_HEADER])
assert.NotEmpty(t, param[TIMESTAMP_HEADER])
})
}
func Test_ConfigResourceInjector_getResourceName(t *testing.T) {
configResourceInjector := ConfigResourceInjector{}
t.Run("test_getGroupedServiceName", func(t *testing.T) {
resource := BuildConfigResource("testTenant", "testGroup", "testDataId")
assert.Equal(t, configResourceInjector.getResourceName(resource), "testTenant+testGroup")
})
t.Run("test_getGroupedServiceName_without_group", func(t *testing.T) {
resource := BuildConfigResource("testTenant", "", "testDataId")
assert.Equal(t, configResourceInjector.getResourceName(resource), "testTenant+")
})
}

View File

@ -17,157 +17,146 @@
package security
import (
"context"
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"strings"
"sync/atomic"
"time"
"github.com/pkg/errors"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
)
type RequestResource struct {
requestType string
namespace string
group string
resource string
type AuthClient struct {
username string
password string
accessToken *atomic.Value
tokenTtl int64
lastRefreshTime int64
tokenRefreshWindow int64
agent http_agent.IHttpAgent
clientCfg constant.ClientConfig
serverCfgs []constant.ServerConfig
}
const (
REQUEST_TYPE_CONFIG = "config"
REQUEST_TYPE_NAMING = "naming"
)
func NewAuthClient(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, agent http_agent.IHttpAgent) AuthClient {
client := AuthClient{
username: clientCfg.Username,
password: clientCfg.Password,
serverCfgs: serverCfgs,
clientCfg: clientCfg,
agent: agent,
accessToken: &atomic.Value{},
}
func BuildConfigResourceByRequest(request rpc_request.IRequest) RequestResource {
if request.GetRequestType() == constant.CONFIG_QUERY_REQUEST_NAME {
configQueryRequest := request.(*rpc_request.ConfigQueryRequest)
return BuildConfigResource(configQueryRequest.Tenant, configQueryRequest.Group, configQueryRequest.DataId)
}
if request.GetRequestType() == constant.CONFIG_PUBLISH_REQUEST_NAME {
configPublishRequest := request.(*rpc_request.ConfigPublishRequest)
return BuildConfigResource(configPublishRequest.Tenant, configPublishRequest.Group, configPublishRequest.DataId)
}
if request.GetRequestType() == "ConfigRemoveRequest" {
configRemoveRequest := request.(*rpc_request.ConfigRemoveRequest)
return BuildConfigResource(configRemoveRequest.Tenant, configRemoveRequest.Group, configRemoveRequest.DataId)
}
return RequestResource{
requestType: REQUEST_TYPE_CONFIG,
}
return client
}
func BuildNamingResourceByRequest(request rpc_request.IRequest) RequestResource {
if request.GetRequestType() == constant.INSTANCE_REQUEST_NAME {
instanceRequest := request.(*rpc_request.InstanceRequest)
return BuildNamingResource(instanceRequest.Namespace, instanceRequest.GroupName, instanceRequest.ServiceName)
}
if request.GetRequestType() == constant.BATCH_INSTANCE_REQUEST_NAME {
batchInstanceRequest := request.(*rpc_request.BatchInstanceRequest)
return BuildNamingResource(batchInstanceRequest.Namespace, batchInstanceRequest.GroupName, batchInstanceRequest.ServiceName)
}
if request.GetRequestType() == constant.SERVICE_LIST_REQUEST_NAME {
serviceListRequest := request.(*rpc_request.ServiceListRequest)
return BuildNamingResource(serviceListRequest.Namespace, serviceListRequest.GroupName, serviceListRequest.ServiceName)
}
if request.GetRequestType() == constant.SERVICE_QUERY_REQUEST_NAME {
serviceQueryRequest := request.(*rpc_request.ServiceQueryRequest)
return BuildNamingResource(serviceQueryRequest.Namespace, serviceQueryRequest.GroupName, serviceQueryRequest.ServiceName)
}
if request.GetRequestType() == constant.SUBSCRIBE_SERVICE_REQUEST_NAME {
subscribeServiceRequest := request.(*rpc_request.SubscribeServiceRequest)
return BuildNamingResource(subscribeServiceRequest.Namespace, subscribeServiceRequest.GroupName, subscribeServiceRequest.ServiceName)
}
return RequestResource{
requestType: REQUEST_TYPE_NAMING,
func (ac *AuthClient) GetAccessToken() string {
v := ac.accessToken.Load()
if v == nil {
return ""
}
return v.(string)
}
func BuildConfigResource(tenant, group, dataId string) RequestResource {
return RequestResource{
requestType: REQUEST_TYPE_CONFIG,
namespace: tenant,
group: group,
resource: dataId,
func (ac *AuthClient) AutoRefresh() {
// If the username is not set, the automatic refresh Token is not enabled
if ac.username == "" {
return
}
}
func BuildNamingResource(namespace, group, serviceName string) RequestResource {
return RequestResource{
requestType: REQUEST_TYPE_NAMING,
namespace: namespace,
group: group,
resource: serviceName,
}
}
type AuthClient interface {
Login() (bool, error)
GetSecurityInfo(resource RequestResource) map[string]string
UpdateServerList(serverList []constant.ServerConfig)
}
type SecurityProxy struct {
Clients []AuthClient
}
func (sp *SecurityProxy) Login() {
for _, client := range sp.Clients {
_, err := client.Login()
if err != nil {
logger.Errorf("login in err:%v", err)
}
}
}
func (sp *SecurityProxy) GetSecurityInfo(resource RequestResource) map[string]string {
var securityInfo = make(map[string]string, 4)
for _, client := range sp.Clients {
info := client.GetSecurityInfo(resource)
if info != nil {
for k, v := range info {
securityInfo[k] = v
}
}
}
return securityInfo
}
func (sp *SecurityProxy) UpdateServerList(serverList []constant.ServerConfig) {
for _, client := range sp.Clients {
client.UpdateServerList(serverList)
}
}
func (sp *SecurityProxy) AutoRefresh(ctx context.Context) {
go func() {
var timer = time.NewTimer(time.Second * time.Duration(5))
defer timer.Stop()
timer := time.NewTimer(time.Second * time.Duration(ac.tokenTtl-ac.tokenRefreshWindow))
for {
select {
case <-timer.C:
sp.Login()
timer.Reset(time.Second * time.Duration(5))
case <-ctx.Done():
return
_, err := ac.Login()
if err != nil {
logger.Errorf("login has error %+v", err)
}
timer.Reset(time.Second * time.Duration(ac.tokenTtl-ac.tokenRefreshWindow))
}
}
}()
}
func NewSecurityProxy(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, agent http_agent.IHttpAgent) SecurityProxy {
var securityProxy = SecurityProxy{}
securityProxy.Clients = []AuthClient{
NewNacosAuthClient(clientCfg, serverCfgs, agent),
NewRamAuthClient(clientCfg),
func (ac *AuthClient) Login() (bool, error) {
var throwable error = nil
for i := 0; i < len(ac.serverCfgs); i++ {
result, err := ac.login(ac.serverCfgs[i])
throwable = err
if result {
return true, nil
}
}
return securityProxy
return false, throwable
}
func NewSecurityProxyWithRamCredentialProvider(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, agent http_agent.IHttpAgent, provider RamCredentialProvider) SecurityProxy {
var securityProxy = SecurityProxy{}
securityProxy.Clients = []AuthClient{
NewNacosAuthClient(clientCfg, serverCfgs, agent),
NewRamAuthClientWithProvider(clientCfg, provider),
func (ac *AuthClient) login(server constant.ServerConfig) (bool, error) {
if ac.username != "" {
contextPath := server.ContextPath
if !strings.HasPrefix(contextPath, "/") {
contextPath = "/" + contextPath
}
if strings.HasSuffix(contextPath, "/") {
contextPath = contextPath[0 : len(contextPath)-1]
}
if server.Scheme == "" {
server.Scheme = "http"
}
reqUrl := server.Scheme + "://" + server.IpAddr + ":" + strconv.FormatInt(int64(server.Port), 10) + contextPath + "/v1/auth/users/login"
header := http.Header{
"content-type": []string{"application/x-www-form-urlencoded"},
}
resp, err := ac.agent.Post(reqUrl, header, ac.clientCfg.TimeoutMs, map[string]string{
"username": ac.username,
"password": ac.password,
})
if err != nil {
return false, err
}
var bytes []byte
bytes, err = ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if err != nil {
return false, err
}
if resp.StatusCode != constant.RESPONSE_CODE_SUCCESS {
errMsg := string(bytes)
return false, errors.New(errMsg)
}
var result map[string]interface{}
err = json.Unmarshal(bytes, &result)
if err != nil {
return false, err
}
if val, ok := result[constant.KEY_ACCESS_TOKEN]; ok {
ac.accessToken.Store(val)
ac.tokenTtl = int64(result[constant.KEY_TOKEN_TTL].(float64))
ac.tokenRefreshWindow = ac.tokenTtl / 10
}
}
return securityProxy
return true, nil
}

View File

@ -1,97 +0,0 @@
package security
import (
"crypto/hmac"
"crypto/sha1"
"crypto/sha256"
"encoding/base64"
"fmt"
"time"
)
const (
PREFIX = "aliyun_v4"
CONSTANT = "aliyun_v4_request"
V4_SIGN_DATE_FORMATTER = "20060102"
SIGNATURE_V4_PRODUCE = "mse"
)
func signWithHmacSha1Encrypt(encryptText, encryptKey string) string {
key := []byte(encryptKey)
mac := hmac.New(sha1.New, key)
mac.Write([]byte(encryptText))
expectedMAC := mac.Sum(nil)
return base64.StdEncoding.EncodeToString(expectedMAC)
}
func Sign(data, key string) (string, error) {
signature, err := sign([]byte(data), []byte(key))
if err != nil {
return "", fmt.Errorf("unable to calculate a request signature: %w", err)
}
return base64.StdEncoding.EncodeToString(signature), nil
}
// sign 方法用于生成签名字节数组
func sign(data, key []byte) ([]byte, error) {
mac := hmac.New(sha1.New, key)
if _, err := mac.Write(data); err != nil {
return nil, err
}
return mac.Sum(nil), nil
}
func finalSigningKeyStringWithDefaultInfo(secret, region string) (string, error) {
signDate := time.Now().UTC().Format(V4_SIGN_DATE_FORMATTER)
return finalSigningKeyString(secret, signDate, region, SIGNATURE_V4_PRODUCE)
}
func finalSigningKeyString(secret, date, region, productCode string) (string, error) {
finalKey, err := finalSigningKey(secret, date, region, productCode)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(finalKey), nil
}
func finalSigningKey(secret, date, region, productCode string) ([]byte, error) {
secondSignkey, err := regionSigningKey(secret, date, region)
if err != nil {
return nil, err
}
mac := hmac.New(sha256.New, secondSignkey)
_, err = mac.Write([]byte(productCode))
if err != nil {
return nil, err
}
thirdSigningKey := mac.Sum(nil)
mac = hmac.New(sha256.New, thirdSigningKey)
_, err = mac.Write([]byte(CONSTANT))
if err != nil {
return nil, err
}
return mac.Sum(nil), nil
}
func regionSigningKey(secret, date, region string) ([]byte, error) {
firstSignkey, err := firstSigningKey(secret, date)
if err != nil {
return nil, err
}
mac := hmac.New(sha256.New, firstSignkey)
_, err = mac.Write([]byte(region))
if err != nil {
return nil, err
}
return mac.Sum(nil), nil
}
func firstSigningKey(secret, date string) ([]byte, error) {
mac := hmac.New(sha256.New, []byte(PREFIX+secret))
_, err := mac.Write([]byte(date))
if err != nil {
return nil, err
}
return mac.Sum(nil), nil
}

View File

@ -20,7 +20,7 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
"os"
"io/ioutil"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
)
@ -48,7 +48,7 @@ func NewTLS(c constant.TLSConfig) (tc *tls.Config, err error) {
}
func rootCert(caFile string) (*x509.CertPool, error) {
b, err := os.ReadFile(caFile)
b, err := ioutil.ReadFile(caFile)
if err != nil {
return nil, err
}

View File

@ -17,6 +17,7 @@
package tls
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
@ -92,16 +93,16 @@ q9K53Jum9GDmkbUODa77sWR1zQsdrqSKywcjP/6FYXU9RMDqKUpm
)
func Test_NewTLS(t *testing.T) {
dir, err := os.MkdirTemp("", "tls-test")
dir, err := ioutil.TempDir("", "tls-test")
if err != nil {
t.Errorf(err.Error())
}
defer os.RemoveAll(dir)
caPath, crtPath, keyPath := filepath.Join(dir, "ca.crt"), filepath.Join(dir, "client.crt"), filepath.Join(dir, "client.key")
os.WriteFile(caPath, testCaCrt, 0666)
os.WriteFile(crtPath, testClientCrt, 0666)
os.WriteFile(keyPath, testClientKey, 0666)
ioutil.WriteFile(caPath, testCaCrt, 0666)
ioutil.WriteFile(crtPath, testClientCrt, 0666)
ioutil.WriteFile(keyPath, testClientKey, 0666)
t.Run("TestNoAuth", func(t *testing.T) {
cfg, err := NewTLS(constant.SkipVerifyConfig)

View File

@ -1 +0,0 @@
LTAIxxxxxxxxxxxBHS21E6

View File

@ -18,123 +18,67 @@ package main
import (
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
"github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
"time"
)
var localServerConfigWithOptions = constant.NewServerConfig(
"mse-d12e6112-p.nacos-ans.mse.aliyuncs.com",
8848,
)
var localClientConfigWithOptions = constant.NewClientConfig(
constant.WithTimeoutMs(10*1000),
constant.WithBeatInterval(2*1000),
constant.WithNotLoadCacheAtStart(true),
//constant.WithAccessKey(getFileContent(path.Join(getWDR(), "ak"))),
//constant.WithSecretKey(getFileContent(path.Join(getWDR(), "sk"))),
constant.WithAccessKey("LTAxxxgQL"),
constant.WithSecretKey("iG4xxxV6C"),
constant.WithOpenKMS(true),
constant.WithKMSVersion(constant.KMSv1),
constant.WithRegionId("cn-beijing"),
)
var localConfigList = []vo.ConfigParam{
{
DataId: "common-config",
Group: "default",
Content: "common",
},
{
DataId: "cipher-crypt",
Group: "default",
Content: "cipher",
},
{
DataId: "cipher-kms-aes-128-crypt",
Group: "default",
Content: "cipher-aes-128",
},
{
DataId: "cipher-kms-aes-256-crypt",
Group: "default",
Content: "cipher-aes-256",
},
}
func main() {
cc := constant.ClientConfig{
Endpoint: "acm.aliyun.com:8080",
NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468",
RegionId: "cn-shanghai",
AccessKey: "LTAI4G8KxxxxxxxxxxxxxbwZLBr",
SecretKey: "n5jTL9YxxxxxxxxxxxxaxmPLZV9",
OpenKMS: true,
TimeoutMs: 5000,
}
// a more graceful way to create config client
client, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
},
)
client, err := createConfigClient()
if err != nil {
panic(err)
}
for _, localConfig := range localConfigList {
// to enable encrypt/decrypt, DataId should be start with "cipher-"
configParam := vo.ConfigParam{
DataId: localConfig.DataId,
Group: localConfig.Group,
Content: localConfig.Content,
OnChange: func(namespace, group, dataId, data string) {
fmt.Printf("successfully receive changed config: \n"+
"group[%s], dataId[%s], data[%s]\n", group, dataId, data)
},
}
// to enable encrypt/decrypt, DataId should be start with "cipher-"
_, err = client.PublishConfig(vo.ConfigParam{
DataId: "cipher-dataId-1",
Group: "test-group",
Content: "hello world!",
})
err := client.ListenConfig(configParam)
if err != nil {
fmt.Printf("failed to listen: group[%s], dataId[%s] with error: %s\n",
configParam.Group, configParam.DataId, err)
} else {
fmt.Printf("successfully ListenConfig: group[%s], dataId[%s]\n", configParam.Group, configParam.DataId)
}
published, err := client.PublishConfig(configParam)
if published && err == nil {
fmt.Printf("successfully publish: group[%s], dataId[%s], data[%s]\n", configParam.Group, configParam.DataId, configParam.Content)
} else {
fmt.Printf("failed to publish: group[%s], dataId[%s], data[%s]\n with error: %s\n",
configParam.Group, configParam.DataId, configParam.Content, err)
}
//wait for config change callback to execute
time.Sleep(2 * time.Second)
//get config
content, err := client.GetConfig(configParam)
if err == nil {
fmt.Printf("successfully get config: group[%s], dataId[%s], data[%s]\n", configParam.Group, configParam.DataId, configParam.Content)
} else {
fmt.Printf("failed to get config: group[%s], dataId[%s], data[%s]\n with error: %s\n",
configParam.Group, configParam.DataId, configParam.Content, err)
}
if content != localConfig.Content {
panic("publish/get encrypted config failed.")
} else {
fmt.Println("publish/get encrypted config success.")
}
//wait for config change callback to execute
//time.Sleep(2 * time.Second)
}
}
func createConfigClient() (*config_client.ConfigClient, error) {
nc := nacos_client.NacosClient{}
_ = nc.SetServerConfig([]constant.ServerConfig{*localServerConfigWithOptions})
_ = nc.SetClientConfig(*localClientConfigWithOptions)
fmt.Println("ak: " + localClientConfigWithOptions.AccessKey)
fmt.Println("sk: " + localClientConfigWithOptions.SecretKey)
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
client, err := config_client.NewConfigClient(&nc)
if err != nil {
return nil, err
fmt.Printf("PublishConfig err: %v\n", err)
}
return client, nil
//get config
content, err := client.GetConfig(vo.ConfigParam{
DataId: "cipher-dataId-3",
Group: "test-group",
})
fmt.Printf("GetConfig, config: %s, error: %v\n", content, err)
// DataId is not start with "cipher-", content will not be encrypted.
_, err = client.PublishConfig(vo.ConfigParam{
DataId: "dataId-1",
Group: "test-group",
Content: "hello world!",
})
if err != nil {
fmt.Printf("PublishConfig err: %v\n", err)
}
//get config
content, err = client.GetConfig(vo.ConfigParam{
DataId: "dataId-1",
Group: "test-group",
})
fmt.Printf("GetConfig, config: %s, error: %v\n", content, err)
}

View File

@ -1 +0,0 @@
kr6JxxxxxxxxxxxxxY8nHnsD6

View File

@ -1,145 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 main
import (
"fmt"
"time"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)
func main() {
//create ClientConfig
cc := *constant.NewClientConfig(
constant.WithNamespaceId(""),
constant.WithTimeoutMs(5000),
constant.WithNotLoadCacheAtStart(true),
constant.WithLogDir("/tmp/nacos/log"),
constant.WithCacheDir("/tmp/nacos/cache"),
constant.WithLogLevel("debug"),
constant.WithAppName("yiyantest"),
constant.WithEndpoint("jmenv.tbsite.net:8080"),
constant.WithClusterName("serverlist"),
constant.WithEndpointQueryParams("nofix=1"),
constant.WithEndpointContextPath("nacos"),
)
// create config client
client, err := clients.NewConfigClient(
vo.NacosClientParam{
ClientConfig: &cc,
},
)
if err != nil {
panic(err)
}
//publish config
//config key=dataId+group+namespaceId
_, err = client.PublishConfig(vo.ConfigParam{
DataId: "test-data",
Group: "test-group",
Content: "hello world!",
})
_, err = client.PublishConfig(vo.ConfigParam{
DataId: "test-data-2",
Group: "test-group",
Content: "hello world!",
})
if err != nil {
fmt.Printf("PublishConfig err:%+v \n", err)
}
time.Sleep(1 * time.Second)
//get config
content, err := client.GetConfig(vo.ConfigParam{
DataId: "test-data",
Group: "test-group",
})
fmt.Println("GetConfig,config :" + content)
//Listen config change,key=dataId+group+namespaceId.
err = client.ListenConfig(vo.ConfigParam{
DataId: "test-data",
Group: "test-group",
OnChange: func(namespace, group, dataId, data string) {
fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data)
},
})
err = client.ListenConfig(vo.ConfigParam{
DataId: "test-data-2",
Group: "test-group",
OnChange: func(namespace, group, dataId, data string) {
fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data)
},
})
time.Sleep(1 * time.Second)
var content2 = "helo 130"
_, err = client.PublishConfig(vo.ConfigParam{
DataId: "test-data",
Group: "test-group",
Content: content2,
})
if err == nil {
fmt.Println("publish config success:" + "test-group" + ", dataId:" + "test-data" + ", content:" + content2)
} else {
fmt.Println("publish config fail :" + "test-group" + ", dataId:" + "test-data" + ", content:" + content2)
}
time.Sleep(1 * time.Second)
_, err = client.PublishConfig(vo.ConfigParam{
DataId: "test-data-2",
Group: "test-group",
Content: "test-listen",
})
time.Sleep(2 * time.Second)
time.Sleep(1 * time.Second)
_, err = client.DeleteConfig(vo.ConfigParam{
DataId: "test-data",
Group: "test-group",
})
fmt.Println("delete config success:" + "test-group" + ", dataId:" + "test-data")
time.Sleep(1 * time.Second)
/* //cancel config change
err = client.CancelListenConfig(vo.ConfigParam{
DataId: "test-data",
Group: "test-group",
})
*/
searchPage, _ := client.SearchConfig(vo.SearchConfigParam{
Search: "blur",
DataId: "test-data",
Group: "",
PageNo: 1,
PageSize: 10,
})
fmt.Printf("Search config:%+v \n", searchPage)
time.Sleep(1000 * time.Second)
}

View File

@ -1 +0,0 @@
LTAxxxxgQL

View File

@ -1,3 +0,0 @@
-----BEGIN CERTIFICATE-----
xxx
-----END CERTIFICATE-----

View File

@ -1,4 +0,0 @@
{
"KeyId": "KAAxxxxe74",
"PrivateKeyData": "MIIxxxA=="
}

View File

@ -1 +0,0 @@
kst-bjj64f82f41yjrs66eygc.cryptoservice.kms.aliyuncs.com

View File

@ -1,171 +0,0 @@
/*
* Copyright 1999-2020 Alibaba Group Holding 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 main
import (
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
"github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
"io/ioutil"
"os"
"path"
"time"
)
var localServerConfigWithOptions = constant.NewServerConfig(
"mse-cdf17f60-p.nacos-ans.mse.aliyuncs.com",
8848,
)
var localClientConfigWithOptions = constant.NewClientConfig(
constant.WithTimeoutMs(10*1000),
constant.WithBeatInterval(2*1000),
constant.WithNotLoadCacheAtStart(true),
constant.WithAccessKey(getFileContent(path.Join(getWDR(), "ak"))),
constant.WithSecretKey(getFileContent(path.Join(getWDR(), "sk"))),
//constant.WithNamespaceId("791fd262-3735-40df-a605-e3236f8ff495"),
constant.WithOpenKMS(true),
constant.WithKMSVersion(constant.KMSv3),
constant.WithKMSv3Config(&constant.KMSv3Config{
ClientKeyContent: getFileContent(path.Join(getWDR(), "client_key.json")),
Password: getFileContent(path.Join(getWDR(), "password")),
Endpoint: getFileContent(path.Join(getWDR(), "endpoint")),
CaContent: getFileContent(path.Join(getWDR(), "ca.pem")),
}),
constant.WithRegionId("cn-beijing"),
)
var localConfigList = []vo.ConfigParam{
{
DataId: "common-config",
Group: "default",
Content: "common普通&&",
},
{
DataId: "cipher-crypt",
Group: "default",
Content: "cipher加密&&",
KmsKeyId: "key-xxx", //可以识别
},
{
DataId: "cipher-kms-aes-128-crypt",
Group: "default",
Content: "cipher-aes-128加密&&",
KmsKeyId: "key-xxx", //可以识别
},
{
DataId: "cipher-kms-aes-256-crypt",
Group: "default",
Content: "cipher-aes-256加密&&",
KmsKeyId: "key-xxx", //可以识别
},
}
func main() {
usingKMSv3ClientAndStoredByNacos()
//onlyUsingFilters()
}
func usingKMSv3ClientAndStoredByNacos() {
client := createConfigClient()
if client == nil {
panic("init ConfigClient failed")
}
for _, localConfig := range localConfigList {
// to enable encrypt/decrypt, DataId should be start with "cipher-"
configParam := vo.ConfigParam{
DataId: localConfig.DataId,
Group: localConfig.Group,
Content: localConfig.Content,
KmsKeyId: localConfig.KmsKeyId,
OnChange: func(namespace, group, dataId, data string) {
fmt.Printf("successfully receive changed config: \n"+
"group[%s], dataId[%s], data[%s]\n", group, dataId, data)
},
}
err := client.ListenConfig(configParam)
if err != nil {
fmt.Printf("failed to listen: group[%s], dataId[%s] with error: %s\n",
configParam.Group, configParam.DataId, err)
} else {
fmt.Printf("successfully ListenConfig: group[%s], dataId[%s]\n", configParam.Group, configParam.DataId)
}
published, err := client.PublishConfig(configParam)
if published && err == nil {
fmt.Printf("successfully publish: group[%s], dataId[%s], data[%s]\n", configParam.Group, configParam.DataId, configParam.Content)
} else {
fmt.Printf("failed to publish: group[%s], dataId[%s], data[%s]\n with error: %s\n",
configParam.Group, configParam.DataId, configParam.Content, err)
}
//wait for config change callback to execute
time.Sleep(2 * time.Second)
//get config
content, err := client.GetConfig(configParam)
if err == nil {
fmt.Printf("successfully get config: group[%s], dataId[%s], data[%s]\n", configParam.Group, configParam.DataId, configParam.Content)
} else {
fmt.Printf("failed to get config: group[%s], dataId[%s], data[%s]\n with error: %s\n",
configParam.Group, configParam.DataId, configParam.Content, err)
}
if content != localConfig.Content {
panic("publish/get encrypted config failed.")
} else {
fmt.Println("publish/get encrypted config success.")
}
//wait for config change callback to execute
//time.Sleep(2 * time.Second)
}
}
func createConfigClient() *config_client.ConfigClient {
nc := nacos_client.NacosClient{}
_ = nc.SetServerConfig([]constant.ServerConfig{*localServerConfigWithOptions})
_ = nc.SetClientConfig(*localClientConfigWithOptions)
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
client, err := config_client.NewConfigClient(&nc)
if err != nil {
logger.Errorf("create config client failed: " + err.Error())
return nil
}
return client
}
func getWDR() string {
getwd, err := os.Getwd()
if err != nil {
return ""
}
return getwd
}
func getFileContent(filePath string) string {
file, err := ioutil.ReadFile(filePath)
if err != nil {
return ""
}
return string(file)
}

View File

@ -1 +0,0 @@
19axxxxx213

View File

@ -1 +0,0 @@
iG48xxxV6C

View File

@ -111,6 +111,12 @@ func main() {
time.Sleep(2 * time.Second)
//cancel config change
err = client.CancelListenConfig(vo.ConfigParam{
DataId: "test-data",
Group: "test-group",
})
time.Sleep(1 * time.Second)
_, err = client.DeleteConfig(vo.ConfigParam{
DataId: "test-data",
@ -118,13 +124,7 @@ func main() {
})
time.Sleep(1 * time.Second)
//cancel config change
err = client.CancelListenConfig(vo.ConfigParam{
DataId: "test-data",
Group: "test-group",
})
searchPage, _ := client.SearchConfig(vo.SearchConfigParam{
searchPage, _ := client.SearchConfig(vo.SearchConfigParm{
Search: "blur",
DataId: "",
Group: "",

View File

@ -56,7 +56,7 @@ func main() {
}
//Register
registerServiceInstance(client, vo.RegisterInstanceParam{
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
Ip: "10.0.0.10",
Port: 8848,
ServiceName: "demo.go",
@ -70,7 +70,7 @@ func main() {
})
//DeRegister
deRegisterServiceInstance(client, vo.DeregisterInstanceParam{
ExampleServiceClient_DeRegisterServiceInstance(client, vo.DeregisterInstanceParam{
Ip: "10.0.0.10",
Port: 8848,
ServiceName: "demo.go",
@ -79,37 +79,24 @@ func main() {
Ephemeral: true, //it must be true
})
time.Sleep(1 * time.Second)
//BatchRegister
batchRegisterServiceInstance(client, vo.BatchRegisterInstanceParam{
//Register
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
Ip: "10.0.0.10",
Port: 8848,
ServiceName: "demo.go",
GroupName: "group-a",
Instances: []vo.RegisterInstanceParam{{
Ip: "10.0.0.10",
Port: 8848,
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
ClusterName: "cluster-a",
Metadata: map[string]string{"idc": "shanghai"},
}, {
Ip: "10.0.0.12",
Port: 8848,
Weight: 7,
Enable: true,
Healthy: true,
Ephemeral: true,
ClusterName: "cluster-a",
Metadata: map[string]string{"idc": "shanghai"},
}},
ClusterName: "cluster-a",
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
Metadata: map[string]string{"idc": "shanghai"},
})
time.Sleep(1 * time.Second)
//Get service with serviceName, groupName , clusters
getService(client, vo.GetServiceParam{
ExampleServiceClient_GetService(client, vo.GetServiceParam{
ServiceName: "demo.go",
GroupName: "group-a",
Clusters: []string{"cluster-a"},
@ -117,7 +104,7 @@ func main() {
//SelectAllInstance
//GroupName=DEFAULT_GROUP
selectAllInstances(client, vo.SelectAllInstancesParam{
ExampleServiceClient_SelectAllInstances(client, vo.SelectAllInstancesParam{
ServiceName: "demo.go",
GroupName: "group-a",
Clusters: []string{"cluster-a"},
@ -125,17 +112,16 @@ func main() {
//SelectInstances only return the instances of healthy=${HealthyOnly},enable=true and weight>0
//ClusterName=DEFAULT,GroupName=DEFAULT_GROUP
selectInstances(client, vo.SelectInstancesParam{
ExampleServiceClient_SelectInstances(client, vo.SelectInstancesParam{
ServiceName: "demo.go",
GroupName: "group-a",
Clusters: []string{"cluster-a"},
HealthyOnly: true,
})
//SelectOneHealthyInstance return one instance by WRR strategy for load balance
//And the instance should be health=true,enable=true and weight>0
//ClusterName=DEFAULT,GroupName=DEFAULT_GROUP
selectOneHealthyInstance(client, vo.SelectOneHealthInstanceParam{
ExampleServiceClient_SelectOneHealthyInstance(client, vo.SelectOneHealthInstanceParam{
ServiceName: "demo.go",
GroupName: "group-a",
Clusters: []string{"cluster-a"},
@ -143,19 +129,31 @@ func main() {
//Subscribe key=serviceName+groupName+cluster
//Note:We call add multiple SubscribeCallback with the same key.
subscribeParam := &vo.SubscribeParam{
param := &vo.SubscribeParam{
ServiceName: "demo.go",
GroupName: "group-a",
SubscribeCallback: func(services []model.Instance, err error) {
fmt.Printf("callback return services:%s \n\n", util.ToJsonString(services))
},
}
subscribe(client, subscribeParam)
ExampleServiceClient_Subscribe(client, param)
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
Ip: "10.0.0.10",
Port: 8848,
ServiceName: "demo.go",
GroupName: "group-a",
ClusterName: "cluster-a",
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
Metadata: map[string]string{"idc": "beijing"},
})
//wait for client pull change from server
time.Sleep(3 * time.Second)
updateServiceInstance(client, vo.UpdateInstanceParam{
ExampleServiceClient_UpdateServiceInstance(client, vo.UpdateInstanceParam{
Ip: "10.0.0.11", //update ip
Port: 8848,
ServiceName: "demo.go",
@ -170,15 +168,24 @@ func main() {
//wait for client pull change from server
time.Sleep(3 * time.Second)
// UnSubscribe
unSubscribe(client, subscribeParam)
//Now we just unsubscribe callback1, and callback2 will still receive change event
ExampleServiceClient_UnSubscribe(client, param)
ExampleServiceClient_DeRegisterServiceInstance(client, vo.DeregisterInstanceParam{
Ip: "10.0.0.112",
Ephemeral: true,
Port: 8848,
ServiceName: "demo.go",
Cluster: "cluster-b",
})
//wait for client pull change from server
time.Sleep(3 * time.Second)
//GeAllService will get the list of service name
//NameSpace default value is public.If the client set the namespaceId, NameSpace will use it.
//GroupName default value is DEFAULT_GROUP
getAllService(client, vo.GetAllServiceInfoParam{
GroupName: "group-a",
PageNo: 1,
PageSize: 10,
ExampleServiceClient_GetAllService(client, vo.GetAllServiceInfoParam{
PageNo: 1,
PageSize: 10,
})
}

View File

@ -24,63 +24,55 @@ import (
"github.com/nacos-group/nacos-sdk-go/v2/vo"
)
func registerServiceInstance(client naming_client.INamingClient, param vo.RegisterInstanceParam) {
func ExampleServiceClient_RegisterServiceInstance(client naming_client.INamingClient, param vo.RegisterInstanceParam) {
success, err := client.RegisterInstance(param)
if !success || err != nil {
panic("RegisterServiceInstance failed!" + err.Error())
panic("RegisterServiceInstance failed!")
}
fmt.Printf("RegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}
func batchRegisterServiceInstance(client naming_client.INamingClient, param vo.BatchRegisterInstanceParam) {
success, err := client.BatchRegisterInstance(param)
if !success || err != nil {
panic("BatchRegisterServiceInstance failed!" + err.Error())
}
fmt.Printf("BatchRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}
func deRegisterServiceInstance(client naming_client.INamingClient, param vo.DeregisterInstanceParam) {
func ExampleServiceClient_DeRegisterServiceInstance(client naming_client.INamingClient, param vo.DeregisterInstanceParam) {
success, err := client.DeregisterInstance(param)
if !success || err != nil {
panic("DeRegisterServiceInstance failed!" + err.Error())
panic("DeRegisterServiceInstance failed!")
}
fmt.Printf("DeRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
}
func updateServiceInstance(client naming_client.INamingClient, param vo.UpdateInstanceParam) {
func ExampleServiceClient_UpdateServiceInstance(client naming_client.INamingClient, param vo.UpdateInstanceParam) {
success, err := client.UpdateInstance(param)
if !success || err != nil {
panic("UpdateInstance failed!" + err.Error())
panic("UpdateInstance failed!")
}
fmt.Printf("UpdateServiceInstance,param:%+v,result:%+v \n\n", param, success)
}
func getService(client naming_client.INamingClient, param vo.GetServiceParam) {
func ExampleServiceClient_GetService(client naming_client.INamingClient, param vo.GetServiceParam) {
service, err := client.GetService(param)
if err != nil {
panic("GetService failed!" + err.Error())
panic("GetService failed!")
}
fmt.Printf("GetService,param:%+v, result:%+v \n\n", param, service)
}
func selectAllInstances(client naming_client.INamingClient, param vo.SelectAllInstancesParam) {
func ExampleServiceClient_SelectAllInstances(client naming_client.INamingClient, param vo.SelectAllInstancesParam) {
instances, err := client.SelectAllInstances(param)
if err != nil {
panic("SelectAllInstances failed!" + err.Error())
panic("SelectAllInstances failed!")
}
fmt.Printf("SelectAllInstance,param:%+v, result:%+v \n\n", param, instances)
}
func selectInstances(client naming_client.INamingClient, param vo.SelectInstancesParam) {
func ExampleServiceClient_SelectInstances(client naming_client.INamingClient, param vo.SelectInstancesParam) {
instances, err := client.SelectInstances(param)
if err != nil {
panic("SelectInstances failed!" + err.Error())
panic("SelectInstances failed!")
}
fmt.Printf("SelectInstances,param:%+v, result:%+v \n\n", param, instances)
}
func selectOneHealthyInstance(client naming_client.INamingClient, param vo.SelectOneHealthInstanceParam) {
func ExampleServiceClient_SelectOneHealthyInstance(client naming_client.INamingClient, param vo.SelectOneHealthInstanceParam) {
instances, err := client.SelectOneHealthyInstance(param)
if err != nil {
panic("SelectOneHealthyInstance failed!")
@ -88,15 +80,15 @@ func selectOneHealthyInstance(client naming_client.INamingClient, param vo.Selec
fmt.Printf("SelectOneHealthyInstance,param:%+v, result:%+v \n\n", param, instances)
}
func subscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
func ExampleServiceClient_Subscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
client.Subscribe(param)
}
func unSubscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
func ExampleServiceClient_UnSubscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
client.Unsubscribe(param)
}
func getAllService(client naming_client.INamingClient, param vo.GetAllServiceInfoParam) {
func ExampleServiceClient_GetAllService(client naming_client.INamingClient, param vo.GetAllServiceInfoParam) {
service, err := client.GetAllServicesInfo(param)
if err != nil {
panic("GetAllService failed!")

69
go.mod
View File

@ -1,72 +1,19 @@
module github.com/nacos-group/nacos-sdk-go/v2
// v2.2.9 is deprecated due to a critical bug. Use v2.3.0 or later
go 1.21
go 1.15
require (
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10
github.com/alibabacloud-go/kms-20160120/v3 v3.2.3
github.com/alibabacloud-go/tea v1.2.2
github.com/alibabacloud-go/tea-utils/v2 v2.0.7
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5
github.com/aliyun/credentials-go v1.4.3
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704
github.com/buger/jsonparser v1.1.1
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.2
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.12.2
github.com/stretchr/testify v1.8.1
github.com/stretchr/testify v1.7.0
go.uber.org/zap v1.21.0
golang.org/x/sync v0.10.0
golang.org/x/time v0.1.0
google.golang.org/grpc v1.67.3
google.golang.org/protobuf v1.36.5
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
google.golang.org/grpc v1.48.0
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
gopkg.in/natefinch/lumberjack.v2 v2.0.0
)
require github.com/golang/protobuf v1.5.4 // indirect
require (
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
github.com/alibabacloud-go/darabonba-array v0.1.0 // indirect
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 // indirect
github.com/alibabacloud-go/darabonba-map v0.0.2 // indirect
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 // indirect
github.com/alibabacloud-go/darabonba-string v1.0.2 // indirect
github.com/alibabacloud-go/debug v1.0.1 // indirect
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
github.com/alibabacloud-go/openapi-util v0.1.0 // indirect
github.com/alibabacloud-go/tea-utils v1.4.4 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/clbanning/mxj/v2 v2.5.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/deckarep/golang-set v1.7.1 // indirect
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/text v0.1.0 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

216
go.sum
View File

@ -39,67 +39,9 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA=
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9/go.mod h1:bb+Io8Sn2RuM3/Rpme6ll86jMyFSrD1bxeV/+v61KeU=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak=
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
github.com/alibabacloud-go/kms-20160120/v3 v3.2.3 h1:vamGcYQFwXVqR6RWcrVTTqlIXZVsYjaA7pZbx+Xw6zw=
github.com/alibabacloud-go/kms-20160120/v3 v3.2.3/go.mod h1:3rIyughsFDLie1ut9gQJXkWkMg/NfXBCk+OtXnPu3lw=
github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=
github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=
github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA=
github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU=
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
github.com/alibabacloud-go/tea-utils v1.4.4 h1:lxCDvNCdTo9FaXKKq45+4vGETQUKNOW/qKTcX9Sk53o=
github.com/alibabacloud-go/tea-utils v1.4.4/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
github.com/alibabacloud-go/tea-utils/v2 v2.0.3/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ=
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0=
github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 h1:ie/8RxBOfKZWcrbYSJi2Z8uX8TcOlSMwPlEJh83OeOw=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 h1:nJYyoFP+aqGKgPs9JeZgS1rWQ4NndNR0Zfhh161ZltU=
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1/go.mod h1:WzGOmFFTlUzXM03CJnHWMQ85UN6QGpOXZocCjwkiyOg=
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 h1:QeUdR7JF7iNCvO/81EhxEr3wDwxk4YBoYZOq6E0AjHI=
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8/go.mod h1:xP0KIZry6i7oGPF24vhAPr1Q8vLZRcMcxtft5xDKwCU=
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 h1:8S0mtD101RDYa0LXwdoqgN0RxdMmmJYjq8g2mk7/lQ4=
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5/go.mod h1:M19fxYz3gpm0ETnoKweYyYtqrtnVtrpKFpwsghbw+cQ=
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
github.com/aliyun/credentials-go v1.4.3 h1:N3iHyvHRMyOwY1+0qBLSf3hb5JFiOujVSVuEpgeGttY=
github.com/aliyun/credentials-go v1.4.3/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 h1:PpfENOj/vPfhhy9N2OFRjpue0hjM5XqAp2thFmkXXIk=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@ -110,25 +52,28 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -169,9 +114,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -183,8 +127,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
@ -196,10 +140,10 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
@ -214,13 +158,13 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
@ -236,10 +180,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc h1:Ak86L+yDSOzKFa7WM5bf5itSOo1e3Xh8bm5YCMUXIjQ=
github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -268,41 +208,29 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
@ -316,18 +244,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -349,6 +266,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@ -358,9 +276,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -389,21 +306,10 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -420,10 +326,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -449,7 +353,6 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -458,59 +361,33 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@ -539,7 +416,6 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@ -547,12 +423,12 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@ -599,14 +475,14 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -619,8 +495,10 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8=
google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -633,24 +511,21 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@ -658,9 +533,8 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -70,30 +70,27 @@ func (u UUID) MarshalText() (text []byte, err error) {
// UnmarshalText implements the encoding.TextUnmarshaler interface.
// Following formats are supported:
//
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
// "6ba7b8109dad11d180b400c04fd430c8"
//
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
// "6ba7b8109dad11d180b400c04fd430c8"
// ABNF for supported UUID text representation follows:
//
// uuid := canonical | hashlike | braced | urn
// plain := canonical | hashlike
// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
// hashlike := 12hexoct
// braced := '{' plain '}'
// urn := URN ':' UUID-NID ':' plain
// URN := 'urn'
// UUID-NID := 'uuid'
// 12hexoct := 6hexoct 6hexoct
// 6hexoct := 4hexoct 2hexoct
// 4hexoct := 2hexoct 2hexoct
// 2hexoct := hexoct hexoct
// hexoct := hexdig hexdig
// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
// 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
// uuid := canonical | hashlike | braced | urn
// plain := canonical | hashlike
// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
// hashlike := 12hexoct
// braced := '{' plain '}'
// urn := URN ':' UUID-NID ':' plain
// URN := 'urn'
// UUID-NID := 'uuid'
// 12hexoct := 6hexoct 6hexoct
// 6hexoct := 4hexoct 2hexoct
// 4hexoct := 2hexoct 2hexoct
// 2hexoct := hexoct hexoct
// hexoct := hexdig hexdig
// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
// 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
func (u *UUID) UnmarshalText(text []byte) (err error) {
switch len(text) {
case 32:

View File

@ -152,7 +152,6 @@ func (u *UUID) SetVariant(v byte) {
// Must is a helper that wraps a call to a function returning (UUID, error)
// and panics if the error is non-nil. It is intended for use in variable
// initializations such as
//
// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"));
func Must(u UUID, err error) UUID {
if err != nil {

Some files were not shown because too many files have changed in this diff Show More