Compare commits

..

No commits in common. "master" and "v2.2.1" have entirely different histories.

88 changed files with 1301 additions and 5912 deletions

View File

@ -14,7 +14,7 @@ jobs:
strategy: strategy:
matrix: matrix:
config: config:
- go_version: 1.21 - go_version: 1.15
steps: steps:
- name: Set up Go 1.x - name: Set up Go 1.x

View File

@ -1,233 +1,467 @@
// /*
// Copyright 1999-2020 Alibaba Group Holding Ltd. * Copyright 1999-2020 Alibaba Group Holding Ltd.
// *
// Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
// You may obtain a copy of the License at * You may obtain a copy of the License at
// *
// http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
// *
// Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
// limitations under the License. * limitations under the License.
*/
// Code generated by protoc-gen-go. DO NOT EDIT. // Code generated by protoc-gen-go. DO NOT EDIT.
// versions: // source: nacos_grpc_service.proto
// protoc-gen-go v1.36.7
// protoc v5.29.3
// source: api/proto/nacos_grpc_service.proto
package auto package grpc
import ( import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect" context "context"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" fmt "fmt"
anypb "google.golang.org/protobuf/types/known/anypb" math "math"
reflect "reflect"
sync "sync" proto "github.com/golang/protobuf/proto"
unsafe "unsafe" 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 ( // Reference imports to suppress errors if they are not otherwise used.
// Verify that this generated code is sufficiently up-to-date. var _ = proto.Marshal
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) var _ = fmt.Errorf
// Verify that runtime/protoimpl is sufficiently up-to-date. var _ = math.Inf
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
) // 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 { type Metadata struct {
state protoimpl.MessageState `protogen:"open.v1"` Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"` ClientIp string `protobuf:"bytes,8,opt,name=clientIp,proto3" json:"clientIp,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"`
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"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
unknownFields protoimpl.UnknownFields XXX_unrecognized []byte `json:"-"`
sizeCache protoimpl.SizeCache XXX_sizecache int32 `json:"-"`
} }
func (x *Metadata) Reset() { func (m *Metadata) Reset() { *m = Metadata{} }
*x = Metadata{} func (m *Metadata) String() string { return proto.CompactTextString(m) }
mi := &file_api_proto_nacos_grpc_service_proto_msgTypes[0] func (*Metadata) ProtoMessage() {}
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 (*Metadata) Descriptor() ([]byte, []int) { 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 { func (m *Metadata) XXX_Unmarshal(b []byte) error {
if x != nil { return xxx_messageInfo_Metadata.Unmarshal(m, b)
return x.Type }
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 "" return ""
} }
func (x *Metadata) GetClientIp() string { func (m *Metadata) GetClientIp() string {
if x != nil { if m != nil {
return x.ClientIp return m.ClientIp
} }
return "" return ""
} }
func (x *Metadata) GetHeaders() map[string]string { func (m *Metadata) GetHeaders() map[string]string {
if x != nil { if m != nil {
return x.Headers return m.Headers
} }
return nil return nil
} }
type Payload struct { type Payload struct {
state protoimpl.MessageState `protogen:"open.v1"` Metadata *Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"`
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"`
Body *anypb.Any `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
unknownFields protoimpl.UnknownFields XXX_unrecognized []byte `json:"-"`
sizeCache protoimpl.SizeCache XXX_sizecache int32 `json:"-"`
} }
func (x *Payload) Reset() { func (m *Payload) Reset() { *m = Payload{} }
*x = Payload{} func (m *Payload) String() string { return proto.CompactTextString(m) }
mi := &file_api_proto_nacos_grpc_service_proto_msgTypes[1] func (*Payload) ProtoMessage() {}
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 (*Payload) Descriptor() ([]byte, []int) { 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 { func (m *Payload) XXX_Unmarshal(b []byte) error {
if x != nil { return xxx_messageInfo_Payload.Unmarshal(m, b)
return x.Metadata }
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 return nil
} }
func (x *Payload) GetBody() *anypb.Any { func (m *Payload) GetBody() *any.Any {
if x != nil { if m != nil {
return x.Body return m.Body
} }
return nil return nil
} }
var File_api_proto_nacos_grpc_service_proto protoreflect.FileDescriptor func init() {
proto.RegisterType((*Metadata)(nil), "Metadata")
const file_api_proto_nacos_grpc_service_proto_rawDesc = "" + proto.RegisterMapType((map[string]string)(nil), "Metadata.HeadersEntry")
"\n" + proto.RegisterType((*Payload)(nil), "Payload")
"\"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
} }
var file_api_proto_nacos_grpc_service_proto_msgTypes = make([]protoimpl.MessageInfo, 3) func init() { proto.RegisterFile("nacos_grpc_service.proto", fileDescriptor_f908b146bdb05ce9) }
var file_api_proto_nacos_grpc_service_proto_goTypes = []any{
(*Metadata)(nil), // 0: Metadata var fileDescriptor_f908b146bdb05ce9 = []byte{
(*Payload)(nil), // 1: Payload // 333 bytes of a gzipped FileDescriptorProto
nil, // 2: Metadata.HeadersEntry 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0x4f, 0x4b, 0xeb, 0x40,
(*anypb.Any)(nil), // 3: google.protobuf.Any 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,
var file_api_proto_nacos_grpc_service_proto_depIdxs = []int32{ 0xd6, 0x1a, 0x4c, 0xb3, 0x71, 0xb3, 0x29, 0xec, 0x37, 0xf2, 0x63, 0x4a, 0x37, 0x69, 0xb0, 0x20,
2, // 0: Metadata.headers:type_name -> Metadata.HeadersEntry 0xde, 0x66, 0x7e, 0x7f, 0xe6, 0xc7, 0xcc, 0x80, 0x93, 0x61, 0x24, 0x8a, 0xf5, 0x46, 0xe6, 0xd1,
0, // 1: Payload.metadata:type_name -> Metadata 0xba, 0xe0, 0x72, 0x97, 0x44, 0x9c, 0xe5, 0x52, 0x28, 0xe1, 0x9e, 0x6d, 0x84, 0xd8, 0xa4, 0x7c,
3, // 2: Payload.body:type_name -> google.protobuf.Any 0x6a, 0xba, 0xb0, 0x7c, 0x9d, 0x62, 0xa6, 0x2b, 0x6a, 0xf2, 0x49, 0xc0, 0x7e, 0xe2, 0x0a, 0x63,
1, // 3: RequestStream.requestStream:input_type -> Payload 0x54, 0x48, 0x29, 0x74, 0x94, 0xce, 0xb9, 0xd3, 0x1e, 0x13, 0xaf, 0x1b, 0x98, 0x9a, 0xba, 0x60,
1, // 4: Request.request:input_type -> Payload 0x47, 0x69, 0xc2, 0x33, 0xf5, 0x98, 0x3b, 0xb6, 0xc1, 0x9b, 0x9e, 0xce, 0xc0, 0x7a, 0xe3, 0x18,
1, // 5: BiRequestStream.requestBiStream:input_type -> Payload 0x73, 0x59, 0x38, 0xd6, 0xb8, 0xed, 0xf5, 0xfc, 0x53, 0x76, 0x98, 0xc5, 0x1e, 0x2a, 0xe2, 0x3e,
1, // 6: RequestStream.requestStream:output_type -> Payload 0x53, 0x52, 0x07, 0x07, 0x99, 0xbb, 0x80, 0xff, 0xdf, 0x09, 0x7a, 0x02, 0xed, 0x77, 0xae, 0x1d,
1, // 7: Request.request:output_type -> Payload 0x62, 0x06, 0xef, 0x4b, 0x3a, 0x84, 0xbf, 0x3b, 0x4c, 0x4b, 0xee, 0xb4, 0x0c, 0x56, 0x35, 0x8b,
1, // 8: BiRequestStream.requestBiStream:output_type -> Payload 0xd6, 0x9c, 0x4c, 0x5e, 0xc0, 0x5a, 0xa1, 0x4e, 0x05, 0xc6, 0xf4, 0x02, 0xec, 0x6d, 0x1d, 0x64,
6, // [6:9] is the sub-list for method output_type 0x74, 0x3d, 0xbf, 0xdb, 0x24, 0x07, 0x0d, 0x45, 0x3d, 0xe8, 0x84, 0x22, 0xd6, 0x66, 0x9f, 0x9e,
3, // [3:6] is the sub-list for method input_type 0x3f, 0x64, 0xd5, 0x19, 0xd8, 0xe1, 0x0c, 0xec, 0x2e, 0xd3, 0x81, 0x51, 0xf8, 0x73, 0xe8, 0x07,
3, // [3:3] is the sub-list for extension type_name 0xfc, 0xa3, 0xe4, 0x85, 0x7a, 0x56, 0x92, 0xe3, 0x96, 0x5e, 0x42, 0x5f, 0x1e, 0x01, 0x36, 0xab,
3, // [3:3] is the sub-list for extension extendee 0xc3, 0xdd, 0xa6, 0x9a, 0xfc, 0x99, 0x11, 0xff, 0x0a, 0xac, 0xda, 0x49, 0x47, 0x60, 0xd5, 0x9e,
0, // [0:3] is the sub-list for field type_name 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() } // Reference imports to suppress errors if they are not otherwise used.
func file_api_proto_nacos_grpc_service_proto_init() { var _ context.Context
if File_api_proto_nacos_grpc_service_proto != nil { var _ grpc.ClientConn
return
// 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{} x := &requestStreamRequestStreamClient{stream}
out := protoimpl.TypeBuilder{ if err := x.ClientStream.SendMsg(in); err != nil {
File: protoimpl.DescBuilder{ return nil, err
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)), if err := x.ClientStream.CloseSend(); err != nil {
NumEnums: 0, return nil, err
NumMessages: 3, }
NumExtensions: 0, return x, nil
NumServices: 3, }
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, Metadata: "nacos_grpc_service.proto",
MessageInfos: file_api_proto_nacos_grpc_service_proto_msgTypes, }
}.Build()
File_api_proto_nacos_grpc_service_proto = out.File // RequestClient is the client API for Request service.
file_api_proto_nacos_grpc_service_proto_goTypes = nil //
file_api_proto_nacos_grpc_service_proto_depIdxs = nil // 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_multiple_files = true;
option java_package = "com.alibaba.nacos.api.grpc.auto"; 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 { message Metadata {
string type = 3; string type = 3;

View File

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

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

View File

@ -2,10 +2,8 @@ package cache
import ( import (
"fmt" "fmt"
"github.com/nacos-group/nacos-sdk-go/v2/util" "io/ioutil"
"math/rand"
"os" "os"
"strconv"
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -13,96 +11,9 @@ import (
"github.com/nacos-group/nacos-sdk-go/v2/common/file" "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) { func TestGetFailover(t *testing.T) {
cacheKey := "test_failOver" cacheKey := "test_failOver"
dir := file.GetCurrentPath()
fileContent := "test_failover" fileContent := "test_failover"
t.Run("writeContent", func(t *testing.T) { t.Run("writeContent", func(t *testing.T) {
filepath := dir + string(os.PathSeparator) + cacheKey + "_failover" filepath := dir + string(os.PathSeparator) + cacheKey + "_failover"
@ -123,5 +34,5 @@ func TestGetFailover(t *testing.T) {
// write file content // write file content
func writeFileContent(filepath, content string) error { func writeFileContent(filepath, content string) error {
return os.WriteFile(filepath, []byte(content), 0666) return ioutil.WriteFile(filepath, []byte(content), 0666)
} }

View File

@ -45,7 +45,7 @@ func NewConfigClient(param vo.NacosClientParam) (iClient config_client.IConfigCl
if err != nil { if err != nil {
return return
} }
config, err := config_client.NewConfigClientWithRamCredentialProvider(nacosClient, param.RamCredentialProvider) config, err := config_client.NewConfigClient(nacosClient)
if err != nil { if err != nil {
return return
} }
@ -58,7 +58,7 @@ func NewNamingClient(param vo.NacosClientParam) (iClient naming_client.INamingCl
if err != nil { if err != nil {
return return
} }
naming, err := naming_client.NewNamingClientWithRamCredentialProvider(nacosClient, param.RamCredentialProvider) naming, err := naming_client.NewNamingClient(nacosClient)
if err != nil { if err != nil {
return return
} }
@ -105,9 +105,6 @@ func setConfig(param vo.NacosClientParam) (iClient nacos_client.INacosClient, er
_ = client.SetServerConfig(nil) _ = client.SetServerConfig(nil)
} else { } else {
for i := range param.ServerConfigs { for i := range param.ServerConfigs {
if param.ServerConfigs[i].Port == 0 {
param.ServerConfigs[i].Port = 8848
}
if param.ServerConfigs[i].GrpcPort == 0 { if param.ServerConfigs[i].GrpcPort == 0 {
param.ServerConfigs[i].GrpcPort = param.ServerConfigs[i].Port + constant.RpcPortOffset param.ServerConfigs[i].GrpcPort = param.ServerConfigs[i].Port + constant.RpcPortOffset
} }

View File

@ -19,19 +19,20 @@ package config_client
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
"os" "os"
"strings" "strings"
"sync" "sync"
"time" "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/cache"
"github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_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/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/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/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_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response" "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/model"
"github.com/nacos-group/nacos-sdk-go/v2/util" "github.com/nacos-group/nacos-sdk-go/v2/util"
"github.com/nacos-group/nacos-sdk-go/v2/vo" "github.com/nacos-group/nacos-sdk-go/v2/vo"
"github.com/pkg/errors"
) )
const ( const (
@ -51,16 +51,15 @@ type ConfigClient struct {
ctx context.Context ctx context.Context
cancel context.CancelFunc cancel context.CancelFunc
nacos_client.INacosClient nacos_client.INacosClient
configFilterChainManager filter.IConfigFilterChain kmsClient *kms.Client
localConfigs []vo.ConfigParam localConfigs []vo.ConfigParam
mutex sync.Mutex mutex sync.Mutex
configProxy IConfigProxy configProxy IConfigProxy
configCacheDir string configCacheDir string
lastAllSyncTime time.Time lastAllSyncTime time.Time
cacheMap cache.ConcurrentMap cacheMap cache.ConcurrentMap
uid string uid string
listenExecute chan struct{} listenExecute chan struct{}
isClosed bool
} }
type cacheData struct { type cacheData struct {
@ -69,7 +68,6 @@ type cacheData struct {
group string group string
content string content string
contentType string contentType string
encryptedDataKey string
tenant string tenant string
cacheDataListener *cacheDataListener cacheDataListener *cacheDataListener
md5 string md5 string
@ -86,24 +84,17 @@ type cacheDataListener struct {
func (cacheData *cacheData) executeListener() { func (cacheData *cacheData) executeListener() {
cacheData.cacheDataListener.lastMd5 = cacheData.md5 cacheData.cacheDataListener.lastMd5 = cacheData.md5
cacheData.configClient.cacheMap.Set(util.GetConfigCacheKey(cacheData.dataId, cacheData.group, cacheData.tenant), *cacheData)
param := &vo.ConfigParam{ decryptedContent, err := cacheData.configClient.decrypt(cacheData.dataId, cacheData.content)
DataId: cacheData.dataId, if err != nil {
Content: cacheData.content, logger.Errorf("decrypt content fail ,dataId=%s,group=%s,tenant=%s,err:%+v ", cacheData.dataId,
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) cacheData.group, cacheData.tenant, err)
return return
} }
decryptedContent := param.Content
go cacheData.cacheDataListener.listener(cacheData.tenant, cacheData.group, cacheData.dataId, decryptedContent) 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 := &ConfigClient{}
config.ctx, config.cancel = context.WithCancel(context.Background()) config.ctx, config.cancel = context.WithCancel(context.Background())
config.INacosClient = nc config.INacosClient = nc
@ -126,20 +117,16 @@ func NewConfigClientWithRamCredentialProvider(nc nacos_client.INacosClient, prov
clientConfig.CacheDir = clientConfig.CacheDir + string(os.PathSeparator) + "config" clientConfig.CacheDir = clientConfig.CacheDir + string(os.PathSeparator) + "config"
config.configCacheDir = clientConfig.CacheDir config.configCacheDir = clientConfig.CacheDir
if config.configProxy, err = NewConfigProxyWithRamCredentialProvider(config.ctx, serverConfig, clientConfig, httpAgent, provider); err != nil { if config.configProxy, err = NewConfigProxy(config.ctx, serverConfig, clientConfig, httpAgent); err != nil {
return nil, err return nil, err
} }
config.configFilterChainManager = filter.NewConfigFilterChainManager()
if clientConfig.OpenKMS { if clientConfig.OpenKMS {
kmsEncryptionHandler := nacos_inner_encryption.NewKmsHandler() kmsClient, err := kms.NewClientWithAccessKey(clientConfig.RegionId, clientConfig.AccessKey, clientConfig.SecretKey)
nacos_inner_encryption.RegisterConfigEncryptionKmsPlugins(kmsEncryptionHandler, clientConfig)
encryptionFilter := filter.NewDefaultConfigEncryptionFilter(kmsEncryptionHandler)
err := filter.RegisterConfigFilterToChain(config.configFilterChainManager, encryptionFilter)
if err != nil { if err != nil {
logger.Error(err) return nil, err
} }
config.kmsClient = kmsClient
} }
uid, err := uuid.NewV4() uid, err := uuid.NewV4()
@ -154,34 +141,55 @@ func NewConfigClientWithRamCredentialProvider(nc nacos_client.INacosClient, prov
return config, err return config, err
} }
func NewConfigClient(nc nacos_client.INacosClient) (*ConfigClient, error) {
return NewConfigClientWithRamCredentialProvider(nc, nil)
}
func initLogger(clientConfig constant.ClientConfig) error { func initLogger(clientConfig constant.ClientConfig) error {
return logger.InitLogger(logger.BuildLoggerConfig(clientConfig)) return logger.InitLogger(logger.BuildLoggerConfig(clientConfig))
} }
func (client *ConfigClient) GetConfig(param vo.ConfigParam) (content string, err 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 { if err != nil {
return "", err return "", err
} }
deepCopyParam := param.DeepCopy() return client.decrypt(param.DataId, content)
deepCopyParam.EncryptedDataKey = encryptedDataKey }
deepCopyParam.Content = content
deepCopyParam.UsageType = vo.ResponseType func (client *ConfigClient) decrypt(dataId, content string) (string, error) {
if err = client.configFilterChainManager.DoFilters(deepCopyParam); err != nil { if client.kmsClient != nil && strings.HasPrefix(dataId, "cipher-") {
return "", err 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 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 { if len(param.DataId) <= 0 {
err = errors.New("[client.GetConfig] param.dataId can not be empty") err = errors.New("[client.GetConfig] param.dataId can not be empty")
return "", "", err return "", err
} }
if len(param.Group) <= 0 { if len(param.Group) <= 0 {
param.Group = constant.DEFAULT_GROUP param.Group = constant.DEFAULT_GROUP
@ -192,43 +200,22 @@ func (client *ConfigClient) getConfigInner(param vo.ConfigParam) (content, encry
content = cache.GetFailover(cacheKey, client.configCacheDir) content = cache.GetFailover(cacheKey, client.configCacheDir)
if len(content) > 0 { if len(content) > 0 {
logger.Warnf("%s %s %s is using failover content!", clientConfig.NamespaceId, param.Group, param.DataId) logger.Warnf("%s %s %s is using failover content!", clientConfig.NamespaceId, param.Group, param.DataId)
encryptedDataKey = cache.GetFailoverEncryptedDataKey(cacheKey, client.configCacheDir) return content, nil
return content, encryptedDataKey, nil
} }
response, err := client.configProxy.queryConfig(param.DataId, param.Group, clientConfig.NamespaceId, response, err := client.configProxy.queryConfig(param.DataId, param.Group, clientConfig.NamespaceId,
clientConfig.TimeoutMs, false, client) clientConfig.TimeoutMs, false, client)
if err != nil { if err != nil {
logger.Errorf("get config from server error:%v, dataId=%s, group=%s, namespaceId=%s", err, logger.Infof("get config from server error:%v ", err)
param.DataId, param.Group, clientConfig.NamespaceId)
if clientConfig.DisableUseSnapShot { if clientConfig.DisableUseSnapShot {
return "", "", errors.Errorf("get config from remote nacos server fail, and is not allowed to read local file, err:%v", err) return "", errors.Errorf("get config from remote nacos server fail, and is not allowed to read local file, err:%v", err)
} }
cacheContent, cacheErr := cache.ReadConfigFromFile(cacheKey, client.configCacheDir) cacheContent, cacheErr := cache.ReadConfigFromFile(cacheKey, client.configCacheDir)
if cacheErr != nil { if err != nil {
return "", "", errors.Errorf("read config from both server and cache fail, err=%vdataId=%s, group=%s, namespaceId=%s", return "", errors.Errorf("read config from both server and cache fail, err=%v", cacheErr)
cacheErr, param.DataId, param.Group, clientConfig.NamespaceId)
} }
return cacheContent, nil
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
} }
if response != nil && response.Response != nil && !response.IsSuccess() { return response.Content, nil
return response.Content, response.EncryptedDataKey, errors.New(response.GetMessage())
}
encryptedDataKey = response.EncryptedDataKey
content = response.Content
return content, encryptedDataKey, nil
} }
func (client *ConfigClient) PublishConfig(param vo.ConfigParam) (published bool, err error) { func (client *ConfigClient) PublishConfig(param vo.ConfigParam) (published bool, err error) {
@ -244,28 +231,21 @@ func (client *ConfigClient) PublishConfig(param vo.ConfigParam) (published bool,
if len(param.Group) <= 0 { if len(param.Group) <= 0 {
param.Group = constant.DEFAULT_GROUP param.Group = constant.DEFAULT_GROUP
} }
if param.Content, err = client.encrypt(param.DataId, param.Content); err != nil {
param.UsageType = vo.RequestType return
if err = client.configFilterChainManager.DoFilters(&param); err != nil {
return false, err
} }
clientConfig, _ := client.GetClientConfig() clientConfig, _ := client.GetClientConfig()
request := rpc_request.NewConfigPublishRequest(param.Group, param.DataId, clientConfig.NamespaceId, param.Content, param.CasMd5) request := rpc_request.NewConfigPublishRequest(param.Group, param.DataId, clientConfig.NamespaceId, param.Content, param.CasMd5)
request.AdditionMap["tag"] = param.Tag request.AdditionMap["tag"] = param.Tag
request.AdditionMap["config_tags"] = param.ConfigTags
request.AdditionMap["appName"] = param.AppName request.AdditionMap["appName"] = param.AppName
request.AdditionMap["betaIps"] = param.BetaIps request.AdditionMap["betaIps"] = param.BetaIps
request.AdditionMap["type"] = param.Type request.AdditionMap["type"] = param.Type
request.AdditionMap["src_user"] = param.SrcUser
request.AdditionMap["encryptedDataKey"] = param.EncryptedDataKey request.AdditionMap["encryptedDataKey"] = param.EncryptedDataKey
rpcClient := client.configProxy.getRpcClient(client) rpcClient := client.configProxy.getRpcClient(client)
response, err := client.configProxy.requestProxy(rpcClient, request, constant.DEFAULT_TIMEOUT_MILLS) response, err := client.configProxy.requestProxy(rpcClient, request, constant.DEFAULT_TIMEOUT_MILLS)
if err != nil {
return false, err
}
if response != nil { if response != nil {
return client.buildResponse(response) return response.IsSuccess(), err
} }
return false, err return false, err
} }
@ -284,11 +264,8 @@ func (client *ConfigClient) DeleteConfig(param vo.ConfigParam) (deleted bool, er
request := rpc_request.NewConfigRemoveRequest(param.Group, param.DataId, clientConfig.NamespaceId) request := rpc_request.NewConfigRemoveRequest(param.Group, param.DataId, clientConfig.NamespaceId)
rpcClient := client.configProxy.getRpcClient(client) rpcClient := client.configProxy.getRpcClient(client)
response, err := client.configProxy.requestProxy(rpcClient, request, constant.DEFAULT_TIMEOUT_MILLS) response, err := client.configProxy.requestProxy(rpcClient, request, constant.DEFAULT_TIMEOUT_MILLS)
if err != nil {
return false, err
}
if response != nil { if response != nil {
return client.buildResponse(response) return response.IsSuccess(), err
} }
return false, err return false, err
} }
@ -321,20 +298,16 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
} }
key := util.GetConfigCacheKey(param.DataId, param.Group, clientConfig.NamespaceId) key := util.GetConfigCacheKey(param.DataId, param.Group, clientConfig.NamespaceId)
var cData cacheData var cData *cacheData
if v, ok := client.cacheMap.Get(key); ok { if v, ok := client.cacheMap.Get(key); ok {
cData = v.(cacheData) cData = v.(*cacheData)
cData.isInitializing = true cData.isInitializing = true
} else { } else {
var ( var (
content string content string
md5Str string md5Str string
innerErr error
) )
if content, innerErr = cache.ReadConfigFromFile(key, client.configCacheDir); innerErr != nil { content, _ = cache.ReadConfigFromFile(key, client.configCacheDir)
logger.Warn(innerErr)
}
encryptedDataKey, _ := cache.ReadEncryptedDataKeyFromFile(key, client.configCacheDir)
if len(content) > 0 { if len(content) > 0 {
md5Str = util.Md5(content) md5Str = util.Md5(content)
} }
@ -343,7 +316,7 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
lastMd5: md5Str, lastMd5: md5Str,
} }
cData = cacheData{ cData = &cacheData{
isInitializing: true, isInitializing: true,
dataId: param.DataId, dataId: param.DataId,
group: param.Group, group: param.Group,
@ -351,7 +324,6 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
content: content, content: content,
md5: md5Str, md5: md5Str,
cacheDataListener: listener, cacheDataListener: listener,
encryptedDataKey: encryptedDataKey,
taskId: client.cacheMap.Count() / perTaskConfigSize, taskId: client.cacheMap.Count() / perTaskConfigSize,
configClient: client, configClient: client,
} }
@ -365,15 +337,8 @@ func (client *ConfigClient) SearchConfig(param vo.SearchConfigParam) (*model.Con
} }
func (client *ConfigClient) CloseClient() { func (client *ConfigClient) CloseClient() {
client.mutex.Lock()
defer client.mutex.Unlock()
if client.isClosed {
return
}
client.configProxy.getRpcClient(client).Shutdown() client.configProxy.getRpcClient(client).Shutdown()
client.cancel() client.cancel()
client.isClosed = true
} }
func (client *ConfigClient) searchConfigInner(param vo.SearchConfigParam) (*model.ConfigPage, error) { func (client *ConfigClient) searchConfigInner(param vo.SearchConfigParam) (*model.ConfigPage, error) {
@ -423,62 +388,71 @@ func (client *ConfigClient) startInternal() {
} }
func (client *ConfigClient) executeConfigListen() { func (client *ConfigClient) executeConfigListen() {
var ( listenCachesMap := make(map[int][]*cacheData, 16)
needAllSync = time.Since(client.lastAllSyncTime) >= constant.ALL_SYNC_INTERNAL needAllSync := time.Since(client.lastAllSyncTime) >= constant.ALL_SYNC_INTERNAL
hasChangedKeys = false for _, v := range client.cacheMap.Items() {
) cache, ok := v.(*cacheData)
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)
if !ok { if !ok {
continue continue
} }
if len(response.ChangedConfigs) > 0 { if cache.isSyncWithServer {
hasChangedKeys = true if cache.md5 != cache.cacheDataListener.lastMd5 {
} cache.executeListener()
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 !needAllSync {
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)
continue continue
} }
data.isInitializing = true
client.cacheMap.Set(changeKey, data)
} }
cacheDatas := listenCachesMap[cache.taskId]
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(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:%+v", iResponse.GetErrorCode())
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 { if needAllSync {
client.lastAllSyncTime = time.Now() client.lastAllSyncTime = time.Now()
@ -490,7 +464,7 @@ func (client *ConfigClient) executeConfigListen() {
monitor.GetListenConfigCountMonitor().Set(float64(client.cacheMap.Count())) 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)) request := rpc_request.NewConfigBatchListenRequest(len(caches))
for _, cache := range caches { for _, cache := range caches {
request.ConfigListenContexts = append(request.ConfigListenContexts, request.ConfigListenContexts = append(request.ConfigListenContexts,
@ -499,7 +473,7 @@ func buildConfigBatchListenRequest(caches []cacheData) *rpc_request.ConfigBatchL
return request 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, configQueryResponse, err := client.configProxy.queryConfig(cacheData.dataId, cacheData.group, cacheData.tenant,
constant.DEFAULT_TIMEOUT_MILLS, notify, client) constant.DEFAULT_TIMEOUT_MILLS, notify, client)
if err != nil { if err != nil {
@ -507,14 +481,8 @@ func (client *ConfigClient) refreshContentAndCheck(cacheData cacheData, notify b
cacheData.group, cacheData.tenant) cacheData.group, cacheData.tenant)
return 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.content = configQueryResponse.Content
cacheData.contentType = configQueryResponse.ContentType cacheData.contentType = configQueryResponse.ContentType
cacheData.encryptedDataKey = configQueryResponse.EncryptedDataKey
if notify { if notify {
logger.Infof("[config_rpc_client] [data-received] dataId=%s, group=%s, tenant=%s, md5=%s, content=%s, type=%s", 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, cacheData.dataId, cacheData.group, cacheData.tenant, cacheData.md5,
@ -522,42 +490,14 @@ func (client *ConfigClient) refreshContentAndCheck(cacheData cacheData, notify b
} }
cacheData.md5 = util.Md5(cacheData.content) cacheData.md5 = util.Md5(cacheData.content)
if cacheData.md5 != cacheData.cacheDataListener.lastMd5 { if cacheData.md5 != cacheData.cacheDataListener.lastMd5 {
cacheDataPtr := &cacheData client.cacheMap.Set(util.GetConfigCacheKey(cacheData.dataId, cacheData.group, cacheData.tenant), cacheData)
cacheDataPtr.executeListener()
cacheData.executeListener()
} }
} }
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() { func (client *ConfigClient) asyncNotifyListenConfig() {
go func() { go func() {
client.listenExecute <- struct{}{} 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())
}

View File

@ -19,10 +19,10 @@ package config_client
import ( import (
"context" "context"
"errors" "errors"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"testing" "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"
"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_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response" "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
@ -35,29 +35,12 @@ import (
"github.com/stretchr/testify/assert" "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( var clientConfigWithOptions = constant.NewClientConfig(
constant.WithTimeoutMs(10*1000), constant.WithTimeoutMs(10*1000),
constant.WithBeatInterval(2*1000), constant.WithBeatInterval(2*1000),
constant.WithNotLoadCacheAtStart(true), 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{ var localConfigTest = vo.ConfigParam{
@ -76,44 +59,6 @@ func createConfigClientTest() *ConfigClient {
return client 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 { type MockConfigProxy struct {
} }
@ -122,7 +67,7 @@ func (m *MockConfigProxy) queryConfig(dataId, group, tenant string, timeout uint
if IsLimited(cacheKey) { if IsLimited(cacheKey) {
return nil, errors.New("request is limited") 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.SearchConfigParam, tenant, accessKey, secretKey string) (*model.ConfigPage, error) {
return &model.ConfigPage{TotalCount: 1}, nil return &model.ConfigPage{TotalCount: 1}, nil
@ -149,7 +94,7 @@ func Test_GetConfig(t *testing.T) {
content, err := client.GetConfig(vo.ConfigParam{ content, err := client.GetConfig(vo.ConfigParam{
DataId: localConfigTest.DataId, DataId: localConfigTest.DataId,
Group: localConfigTest.Group}) Group: "group"})
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "hello world", content) assert.Equal(t, "hello world", content)
@ -172,74 +117,6 @@ func Test_SearchConfig(t *testing.T) {
assert.NotEmpty(t, configPage) 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 // PublishConfig
func Test_PublishConfigWithoutDataId(t *testing.T) { func Test_PublishConfigWithoutDataId(t *testing.T) {
client := createConfigClientTest() client := createConfigClientTest()
@ -268,7 +145,6 @@ func Test_PublishConfig(t *testing.T) {
success, err := client.PublishConfig(vo.ConfigParam{ success, err := client.PublishConfig(vo.ConfigParam{
DataId: localConfigTest.DataId, DataId: localConfigTest.DataId,
Group: "group", Group: "group",
SrcUser: "nacos-client-go",
Content: "hello world"}) Content: "hello world"})
assert.Nil(t, err) assert.Nil(t, err)
@ -357,55 +233,3 @@ func TestCancelListenConfig(t *testing.T) {
assert.Nil(t, err) 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

@ -23,20 +23,22 @@ import (
"strconv" "strconv"
"time" "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/clients/cache"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant" "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/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger" "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/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/model"
"github.com/nacos-group/nacos-sdk-go/v2/util" "github.com/nacos-group/nacos-sdk-go/v2/util"
"github.com/nacos-group/nacos-sdk-go/v2/vo" "github.com/nacos-group/nacos-sdk-go/v2/vo"
"github.com/pkg/errors"
) )
type ConfigProxy struct { type ConfigProxy struct {
@ -45,21 +47,20 @@ type ConfigProxy struct {
} }
func NewConfigProxy(ctx context.Context, serverConfig []constant.ServerConfig, clientConfig constant.ClientConfig, httpAgent http_agent.IHttpAgent) (IConfigProxy, error) { 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) {
proxy := ConfigProxy{} proxy := ConfigProxy{}
var err error 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(ctx, serverConfig, clientConfig, httpAgent, clientConfig.TimeoutMs, clientConfig.Endpoint)
proxy.clientConfig = clientConfig proxy.clientConfig = clientConfig
return &proxy, err return &proxy, err
} }
func (cp *ConfigProxy) requestProxy(rpcClient *rpc.RpcClient, request rpc_request.IRequest, timeoutMills uint64) (rpc_response.IResponse, error) { func (cp *ConfigProxy) requestProxy(rpcClient *rpc.RpcClient, request rpc_request.IRequest, timeoutMills uint64) (rpc_response.IResponse, error) {
start := time.Now() start := time.Now()
cp.nacosServer.InjectSecurityInfo(request.GetHeaders(), security.BuildConfigResourceByRequest(request)) cp.nacosServer.InjectSecurityInfo(request.GetHeaders())
cp.injectCommHeader(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)
response, err := rpcClient.Request(request, int64(timeoutMills)) response, err := rpcClient.Request(request, int64(timeoutMills))
monitor.GetConfigRequestMonitor(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 return response, err
@ -86,27 +87,14 @@ func (cp *ConfigProxy) searchConfigProxy(param vo.SearchConfigParam, tenant, acc
params["dataId"] = "" params["dataId"] = ""
} }
var headers = map[string]string{} 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) result, err := cp.nacosServer.ReqConfigApi(constant.CONFIG_PATH, params, headers, http.MethodGet, cp.clientConfig.TimeoutMs)
if err != nil { if err != nil {
if len(tenant) > 0 { return nil, err
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"
} }
var configPage model.ConfigPage var configPage model.ConfigPage
if version == "v2" { err = json.Unmarshal([]byte(result), &configPage)
err = json.Unmarshal([]byte(result), &configPage)
} else {
var configPageResult model.ConfigPageResult
err = json.Unmarshal([]byte(result), &configPageResult)
configPage = configPageResult.Data
}
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -135,7 +123,7 @@ func (cp *ConfigProxy) queryConfig(dataId, group, tenant string, timeout uint64,
} }
if response.IsSuccess() { if response.IsSuccess() {
cache.WriteConfigToFile(cacheKey, cp.clientConfig.CacheDir, response.Content) cache.WriteConfigToFile(cacheKey, cp.clientConfig.CacheDir, response.Content)
cache.WriteEncryptedDataKeyToFile(cacheKey, cp.clientConfig.CacheDir, response.EncryptedDataKey) //todo LocalConfigInfoProcessor.saveEncryptDataKeySnapshot
if response.ContentType == "" { if response.ContentType == "" {
response.ContentType = "text" response.ContentType = "text"
} }
@ -144,8 +132,7 @@ func (cp *ConfigProxy) queryConfig(dataId, group, tenant string, timeout uint64,
if response.GetErrorCode() == 300 { if response.GetErrorCode() == 300 {
cache.WriteConfigToFile(cacheKey, cp.clientConfig.CacheDir, "") cache.WriteConfigToFile(cacheKey, cp.clientConfig.CacheDir, "")
cache.WriteEncryptedDataKeyToFile(cacheKey, cp.clientConfig.CacheDir, "") //todo LocalConfigInfoProcessor.saveEncryptDataKeySnapshot
response.SetSuccess(true)
return response, nil return response, nil
} }
@ -179,17 +166,13 @@ func (cp *ConfigProxy) createRpcClient(ctx context.Context, taskId string, clien
"taskId": taskId, "taskId": taskId,
} }
iRpcClient, _ := rpc.CreateClient(ctx, "config-"+taskId+"-"+client.uid, rpc.GRPC, labels, cp.nacosServer, &cp.clientConfig.TLSCfg, cp.clientConfig.AppConnLabels) iRpcClient, _ := rpc.CreateClient(ctx, "config-"+taskId+"-"+client.uid, rpc.GRPC, labels, cp.nacosServer)
rpcClient := iRpcClient.GetRpcClient() rpcClient := iRpcClient.GetRpcClient()
if rpcClient.IsInitialized() { if rpcClient.IsInitialized() {
rpcClient.RegisterServerRequestHandler(func() rpc_request.IRequest { rpcClient.RegisterServerRequestHandler(func() rpc_request.IRequest {
// TODO fix the group/dataId empty problem // TODO fix the group/dataId empty problem
return rpc_request.NewConfigChangeNotifyRequest("", "", "") return rpc_request.NewConfigChangeNotifyRequest("", "", "")
}, &ConfigChangeNotifyRequestHandler{client: client}) }, &ConfigChangeNotifyRequestHandler{client: client})
configListener := NewConfigConnectionEventListener(client, taskId)
rpcClient.RegisterConnectionListener(configListener)
rpcClient.Tenant = cp.clientConfig.NamespaceId rpcClient.Tenant = cp.clientConfig.NamespaceId
rpcClient.Start() rpcClient.Start()
} }
@ -210,23 +193,22 @@ func (c *ConfigChangeNotifyRequestHandler) Name() string {
func (c *ConfigChangeNotifyRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *rpc.RpcClient) rpc_response.IResponse { func (c *ConfigChangeNotifyRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *rpc.RpcClient) rpc_response.IResponse {
configChangeNotifyRequest, ok := request.(*rpc_request.ConfigChangeNotifyRequest) configChangeNotifyRequest, ok := request.(*rpc_request.ConfigChangeNotifyRequest)
if !ok { 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)
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, cacheKey := util.GetConfigCacheKey(configChangeNotifyRequest.DataId, configChangeNotifyRequest.Group,
configChangeNotifyRequest.Tenant) configChangeNotifyRequest.Tenant)
data, ok := c.client.cacheMap.Get(cacheKey) data, ok := c.client.cacheMap.Get(cacheKey)
if !ok { if !ok {
return nil return nil
} }
cData := data.(cacheData) cData := data.(*cacheData)
cData.isSyncWithServer = false cData.isSyncWithServer = false
c.client.cacheMap.Set(cacheKey, cData) c.client.asyncNotifyListenConfig()
c.client.asyncNotifyListenConfig() return &rpc_response.NotifySubscriberResponse{
return &rpc_response.NotifySubscriberResponse{ Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS},
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS}, }
} }
return nil
} }

View File

@ -25,6 +25,7 @@ import (
"github.com/nacos-group/nacos-sdk-go/v2/common/constant" "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/file"
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent" "github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
) )
type NacosClient struct { type NacosClient struct {
@ -35,7 +36,7 @@ type NacosClient struct {
serverConfigs []constant.ServerConfig 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) { func (client *NacosClient) SetClientConfig(config constant.ClientConfig) (err error) {
if config.TimeoutMs <= 0 { if config.TimeoutMs <= 0 {
config.TimeoutMs = 10 * 1000 config.TimeoutMs = 10 * 1000
@ -61,13 +62,15 @@ func (client *NacosClient) SetClientConfig(config constant.ClientConfig) (err er
config.LogDir = file.GetCurrentPath() + string(os.PathSeparator) + "log" config.LogDir = file.GetCurrentPath() + string(os.PathSeparator) + "log"
} }
logger.Infof("logDir:<%s> cacheDir:<%s>", config.LogDir, config.CacheDir)
client.clientConfig = config client.clientConfig = config
client.clientConfigValid = true client.clientConfigValid = true
return 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) { func (client *NacosClient) SetServerConfig(configs []constant.ServerConfig) (err error) {
if len(configs) <= 0 { if len(configs) <= 0 {
//it's may be use endpoint to get nacos server address //it's may be use endpoint to get nacos server address
@ -92,7 +95,7 @@ func (client *NacosClient) SetServerConfig(configs []constant.ServerConfig) (err
return return
} }
// GetClientConfig use to get client config //GetClientConfig use to get client config
func (client *NacosClient) GetClientConfig() (config constant.ClientConfig, err error) { func (client *NacosClient) GetClientConfig() (config constant.ClientConfig, err error) {
config = client.clientConfig config = client.clientConfig
if !client.clientConfigValid { if !client.clientConfigValid {
@ -101,7 +104,7 @@ func (client *NacosClient) GetClientConfig() (config constant.ClientConfig, err
return return
} }
// GetServerConfig use to get server config //GetServerConfig use to get server config
func (client *NacosClient) GetServerConfig() (configs []constant.ServerConfig, err error) { func (client *NacosClient) GetServerConfig() (configs []constant.ServerConfig, err error) {
configs = client.serverConfigs configs = client.serverConfigs
if !client.serverConfigsValid { if !client.serverConfigsValid {
@ -110,7 +113,7 @@ func (client *NacosClient) GetServerConfig() (configs []constant.ServerConfig, e
return return
} }
// SetHttpAgent use to set http agent //SetHttpAgent use to set http agent
func (client *NacosClient) SetHttpAgent(agent http_agent.IHttpAgent) (err error) { func (client *NacosClient) SetHttpAgent(agent http_agent.IHttpAgent) (err error) {
if agent == nil { if agent == nil {
err = errors.New("[client.SetHttpAgent] http agent can not be nil") err = errors.New("[client.SetHttpAgent] http agent can not be nil")
@ -120,7 +123,7 @@ func (client *NacosClient) SetHttpAgent(agent http_agent.IHttpAgent) (err error)
return return
} }
// GetHttpAgent use to get http agent //GetHttpAgent use to get http agent
func (client *NacosClient) GetHttpAgent() (agent http_agent.IHttpAgent, err error) { func (client *NacosClient) GetHttpAgent() (agent http_agent.IHttpAgent, err error) {
if client.agent == nil { if client.agent == nil {
err = errors.New("[client.GetHttpAgent] invalid http agent") err = errors.New("[client.GetHttpAgent] invalid http agent")

View File

@ -115,12 +115,12 @@ func (s *ServiceInfoHolder) GetServiceInfo(serviceName, groupName, clusters stri
return model.Service{}, ok return model.Service{}, ok
} }
func (s *ServiceInfoHolder) RegisterCallback(serviceName string, clusters string, callbackWrapper *SubscribeCallbackFuncWrapper) { func (s *ServiceInfoHolder) RegisterCallback(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
s.subCallback.AddCallbackFunc(serviceName, clusters, callbackWrapper) s.subCallback.AddCallbackFunc(serviceName, clusters, callbackFunc)
} }
func (s *ServiceInfoHolder) DeregisterCallback(serviceName string, clusters string, callbackWrapper *SubscribeCallbackFuncWrapper) { func (s *ServiceInfoHolder) DeregisterCallback(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
s.subCallback.RemoveCallbackFunc(serviceName, clusters, callbackWrapper) s.subCallback.RemoveCallbackFunc(serviceName, clusters, callbackFunc)
} }
func (s *ServiceInfoHolder) StopUpdateIfContain(serviceName, clusters string) { func (s *ServiceInfoHolder) StopUpdateIfContain(serviceName, clusters string) {

View File

@ -19,6 +19,8 @@ package naming_cache
import ( import (
"sync" "sync"
"github.com/pkg/errors"
"github.com/nacos-group/nacos-sdk-go/v2/clients/cache" "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/common/logger"
"github.com/nacos-group/nacos-sdk-go/v2/model" "github.com/nacos-group/nacos-sdk-go/v2/model"
@ -36,34 +38,31 @@ func NewSubscribeCallback() *SubscribeCallback {
func (ed *SubscribeCallback) IsSubscribed(serviceName, clusters string) bool { func (ed *SubscribeCallback) IsSubscribed(serviceName, clusters string) bool {
key := util.GetServiceCacheKey(serviceName, clusters) key := util.GetServiceCacheKey(serviceName, clusters)
funcs, ok := ed.callbackFuncMap.Get(key) _, ok := ed.callbackFuncMap.Get(key)
if ok { return ok
return len(funcs.([]*SubscribeCallbackFuncWrapper)) > 0
}
return false
} }
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) key := util.GetServiceCacheKey(serviceName, clusters)
ed.mux.Lock()
defer ed.mux.Unlock() defer ed.mux.Unlock()
var funcSlice []*SubscribeCallbackFuncWrapper ed.mux.Lock()
var funcSlice []*func(services []model.Instance, err error)
old, ok := ed.callbackFuncMap.Get(key) old, ok := ed.callbackFuncMap.Get(key)
if ok { 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) 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") logger.Info("removing " + serviceName + " with " + clusters + " to listener map")
key := util.GetServiceCacheKey(serviceName, clusters) key := util.GetServiceCacheKey(serviceName, clusters)
funcs, ok := ed.callbackFuncMap.Get(key) funcs, ok := ed.callbackFuncMap.Get(key)
if ok && funcs != nil { if ok && funcs != nil {
var newFuncs []*SubscribeCallbackFuncWrapper var newFuncs []*func(services []model.Instance, err error)
for _, funcItem := range funcs.([]*SubscribeCallbackFuncWrapper) { for _, funcItem := range funcs.([]*func(services []model.Instance, err error)) {
if funcItem.CallbackFunc != callbackWrapper.CallbackFunc || !funcItem.Selector.Equals(callbackWrapper.Selector) { if funcItem != callbackFunc {
newFuncs = append(newFuncs, funcItem) 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) { func (ed *SubscribeCallback) ServiceChanged(cacheKey string, service *model.Service) {
funcs, ok := ed.callbackFuncMap.Get(cacheKey) funcs, ok := ed.callbackFuncMap.Get(cacheKey)
if ok { if ok {
for _, funcItem := range funcs.([]*SubscribeCallbackFuncWrapper) { for _, funcItem := range funcs.([]*func(services []model.Instance, err error)) {
funcItem.notifyListener(service) 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)) fmt.Println(util.ToJsonString(ed.callbackFuncMap))
}, },
} }
clusterSelector := NewClusterSelector(param.Clusters) ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), &param.SubscribeCallback)
callbackWrapper := NewSubscribeCallbackFuncWrapper(clusterSelector, &param.SubscribeCallback)
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), callbackWrapper)
key := util.GetServiceCacheKey(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ",")) key := util.GetServiceCacheKey(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
for k, v := range ed.callbackFuncMap.Items() { for k, v := range ed.callbackFuncMap.Items() {
assert.Equal(t, key, k, "key should be equal!") 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, 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)) fmt.Printf("func1:%s \n", util.ToJsonString(services))
}, },
} }
clusterSelector := NewClusterSelector(param.Clusters) ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), &param.SubscribeCallback)
callbackWrapper := NewSubscribeCallbackFuncWrapper(clusterSelector, &param.SubscribeCallback)
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), callbackWrapper)
assert.Equal(t, len(ed.callbackFuncMap.Items()), 1, "callback funcs map length should be 1") assert.Equal(t, len(ed.callbackFuncMap.Items()), 1, "callback funcs map length should be 1")
param2 := vo.SubscribeParam{ param2 := vo.SubscribeParam{
@ -113,23 +109,21 @@ func TestEventDispatcher_RemoveCallbackFuncs(t *testing.T) {
fmt.Printf("func2:%s \n", util.ToJsonString(services)) fmt.Printf("func2:%s \n", util.ToJsonString(services))
}, },
} }
clusterSelector2 := NewClusterSelector(param2.Clusters) ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), &param2.SubscribeCallback)
callbackWrapper2 := NewSubscribeCallbackFuncWrapper(clusterSelector2, &param2.SubscribeCallback)
ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), callbackWrapper2)
assert.Equal(t, len(ed.callbackFuncMap.Items()), 1, "callback funcs map length should be 2") assert.Equal(t, len(ed.callbackFuncMap.Items()), 1, "callback funcs map length should be 2")
for k, v := range ed.callbackFuncMap.Items() { 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, ",")) key := util.GetServiceCacheKey(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
for k, v := range ed.callbackFuncMap.Items() { for k, v := range ed.callbackFuncMap.Items() {
assert.Equal(t, key, k, "key should be equal!") 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, 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)) log.Printf("func1:%s \n", util.ToJsonString(services))
}, },
} }
clusterSelector := NewClusterSelector(param.Clusters) ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), &param.SubscribeCallback)
callbackWrapper := NewSubscribeCallbackFuncWrapper(clusterSelector, &param.SubscribeCallback)
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), callbackWrapper)
param2 := vo.SubscribeParam{ param2 := vo.SubscribeParam{
ServiceName: "Test", ServiceName: "Test",
@ -177,54 +169,7 @@ func TestSubscribeCallback_ServiceChanged(t *testing.T) {
}, },
} }
clusterSelector2 := NewClusterSelector(param2.Clusters) ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), &param2.SubscribeCallback)
callbackWrapper2 := NewSubscribeCallbackFuncWrapper(clusterSelector2, &param2.SubscribeCallback)
ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), callbackWrapper2)
cacheKey := util.GetServiceCacheKey(util.GetGroupName(service.Name, service.GroupName), service.Clusters) cacheKey := util.GetServiceCacheKey(util.GetGroupName(service.Name, service.GroupName), service.Clusters)
ed.ServiceChanged(cacheKey, &service) 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

@ -21,11 +21,8 @@ import (
"math" "math"
"math/rand" "math/rand"
"strings" "strings"
"sync"
"time" "time"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client" "github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client"
@ -45,17 +42,10 @@ type NamingClient struct {
cancel context.CancelFunc cancel context.CancelFunc
serviceProxy naming_proxy.INamingProxy serviceProxy naming_proxy.INamingProxy
serviceInfoHolder *naming_cache.ServiceInfoHolder serviceInfoHolder *naming_cache.ServiceInfoHolder
isClosed bool
mutex sync.Mutex
} }
// NewNamingClient ... // NewNamingClient ...
func NewNamingClient(nc nacos_client.INacosClient) (*NamingClient, error) { 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()) ctx, cancel := context.WithCancel(context.Background())
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
naming := &NamingClient{INacosClient: nc, ctx: ctx, cancel: cancel} naming := &NamingClient{INacosClient: nc, ctx: ctx, cancel: cancel}
@ -85,11 +75,9 @@ func NewNamingClientWithRamCredentialProvider(nc nacos_client.INacosClient, prov
naming.serviceInfoHolder = naming_cache.NewServiceInfoHolder(clientConfig.NamespaceId, clientConfig.CacheDir, naming.serviceInfoHolder = naming_cache.NewServiceInfoHolder(clientConfig.NamespaceId, clientConfig.CacheDir,
clientConfig.UpdateCacheWhenEmpty, clientConfig.NotLoadCacheAtStart) clientConfig.UpdateCacheWhenEmpty, clientConfig.NotLoadCacheAtStart)
naming.serviceProxy, err = NewNamingProxyDelegateWithRamCredentialProvider(ctx, clientConfig, serverConfig, httpAgent, naming.serviceInfoHolder, provider) naming.serviceProxy, err = NewNamingProxyDelegate(ctx, clientConfig, serverConfig, httpAgent, naming.serviceInfoHolder)
if clientConfig.AsyncUpdateService { go NewServiceInfoUpdater(ctx, naming.serviceInfoHolder, clientConfig.UpdateThreadNum, naming.serviceProxy).asyncUpdateService()
go NewServiceInfoUpdater(ctx, naming.serviceInfoHolder, clientConfig.UpdateThreadNum, naming.serviceProxy).asyncUpdateService()
}
if err != nil { if err != nil {
return naming, err return naming, err
} }
@ -201,14 +189,11 @@ func (sc *NamingClient) GetService(param vo.GetServiceParam) (service model.Serv
param.GroupName = constant.DEFAULT_GROUP param.GroupName = constant.DEFAULT_GROUP
} }
var ok bool var ok bool
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
clusters := strings.Join(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 { 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 return service, err
} }
@ -234,24 +219,21 @@ func (sc *NamingClient) SelectAllInstances(param vo.SelectAllInstancesParam) ([]
if len(param.GroupName) == 0 { if len(param.GroupName) == 0 {
param.GroupName = constant.DEFAULT_GROUP param.GroupName = constant.DEFAULT_GROUP
} }
clusters := strings.Join(param.Clusters, ",")
var ( var (
service model.Service service model.Service
ok bool ok bool
err error 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 { 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 return []model.Instance{}, err
} }
instances := clusterSelector.SelectInstance(&service) return service.Hosts, err
if instances == nil || len(instances) == 0 {
return []model.Instance{}, err
}
return instances, err
} }
// SelectInstances Get all instance by DataId, Group and Health // SelectInstances Get all instance by DataId, Group and Health
@ -264,15 +246,14 @@ func (sc *NamingClient) SelectInstances(param vo.SelectInstancesParam) ([]model.
ok bool ok bool
err error err error
) )
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 { 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 {
return nil, err return nil, err
} }
} }
service.Hosts = clusterSelector.SelectInstance(&service)
return sc.selectInstances(service, param.HealthyOnly) return sc.selectInstances(service, param.HealthyOnly)
} }
@ -282,7 +263,6 @@ func (sc *NamingClient) selectInstances(service model.Service, healthy bool) ([]
} }
hosts := service.Hosts hosts := service.Hosts
var result []model.Instance 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 { for _, host := range hosts {
if host.Healthy == healthy && host.Enable && host.Weight > 0 { if host.Healthy == healthy && host.Enable && host.Weight > 0 {
result = append(result, host) result = append(result, host)
@ -301,15 +281,15 @@ func (sc *NamingClient) SelectOneHealthyInstance(param vo.SelectOneHealthInstanc
ok bool ok bool
err error err error
) )
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 { 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 {
return nil, err return nil, err
} }
} }
service.Hosts = clusterSelector.SelectInstance(&service)
return sc.selectOneHealthyInstances(service) return sc.selectOneHealthyInstances(service)
} }
@ -342,40 +322,26 @@ func (sc *NamingClient) Subscribe(param *vo.SubscribeParam) error {
if len(param.GroupName) == 0 { if len(param.GroupName) == 0 {
param.GroupName = constant.DEFAULT_GROUP param.GroupName = constant.DEFAULT_GROUP
} }
clusterSelector := naming_cache.NewClusterSelector(param.Clusters) clusters := strings.Join(param.Clusters, ",")
callbackWrapper := naming_cache.NewSubscribeCallbackFuncWrapper(clusterSelector, &param.SubscribeCallback) sc.serviceInfoHolder.RegisterCallback(util.GetGroupName(param.ServiceName, param.GroupName), clusters, &param.SubscribeCallback)
sc.serviceInfoHolder.RegisterCallback(util.GetGroupName(param.ServiceName, param.GroupName), "", callbackWrapper) _, err := sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
_, err := sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
return err return err
} }
// Unsubscribe ... // Unsubscribe ...
func (sc *NamingClient) Unsubscribe(param *vo.SubscribeParam) (err error) { func (sc *NamingClient) Unsubscribe(param *vo.SubscribeParam) (err error) {
clusterSelector := naming_cache.NewClusterSelector(param.Clusters) clusters := strings.Join(param.Clusters, ",")
callbackWrapper := naming_cache.NewSubscribeCallbackFuncWrapper(clusterSelector, &param.SubscribeCallback)
serviceFullName := util.GetGroupName(param.ServiceName, param.GroupName) serviceFullName := util.GetGroupName(param.ServiceName, param.GroupName)
sc.serviceInfoHolder.DeregisterCallback(serviceFullName, "", callbackWrapper) sc.serviceInfoHolder.DeregisterCallback(serviceFullName, clusters, &param.SubscribeCallback)
if !sc.serviceInfoHolder.IsSubscribed(serviceFullName, "") { if sc.serviceInfoHolder.IsSubscribed(serviceFullName, clusters) {
err = sc.serviceProxy.Unsubscribe(param.ServiceName, param.GroupName, "") err = sc.serviceProxy.Unsubscribe(param.ServiceName, param.GroupName, clusters)
} }
return err return err
} }
// ServerHealthy ...
func (sc *NamingClient) ServerHealthy() bool {
return sc.serviceProxy.ServerHealthy()
}
// CloseClient ... // CloseClient ...
func (sc *NamingClient) CloseClient() { func (sc *NamingClient) CloseClient() {
sc.mutex.Lock()
defer sc.mutex.Unlock()
if sc.isClosed {
return
}
sc.serviceProxy.CloseClient() sc.serviceProxy.CloseClient()
sc.cancel() sc.cancel()
sc.isClosed = true
} }

View File

@ -112,9 +112,6 @@ type INamingClient interface {
// GetAllServicesInfo use to get all service info by page // GetAllServicesInfo use to get all service info by page
GetAllServicesInfo(param vo.GetAllServiceInfoParam) (model.ServiceList, error) GetAllServicesInfo(param vo.GetAllServiceInfoParam) (model.ServiceList, error)
// ServerHealthy use to check the connectivity to server
ServerHealthy() bool
//CloseClient close the GRPC client //CloseClient close the GRPC client
CloseClient() CloseClient()
} }

View File

@ -37,8 +37,6 @@ var clientConfigTest = *constant.NewClientConfig(
var serverConfigTest = *constant.NewServerConfig("127.0.0.1", 80, constant.WithContextPath("/nacos")) var serverConfigTest = *constant.NewServerConfig("127.0.0.1", 80, constant.WithContextPath("/nacos"))
type MockNamingProxy struct { type MockNamingProxy struct {
unsubscribeCalled bool
unsubscribeParams []string // 记录调用参数
} }
func (m *MockNamingProxy) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) { func (m *MockNamingProxy) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
@ -70,8 +68,6 @@ func (m *MockNamingProxy) Subscribe(serviceName, groupName, clusters string) (mo
} }
func (m *MockNamingProxy) Unsubscribe(serviceName, groupName, clusters string) error { func (m *MockNamingProxy) Unsubscribe(serviceName, groupName, clusters string) error {
m.unsubscribeCalled = true
m.unsubscribeParams = []string{serviceName, groupName, clusters}
return nil return nil
} }
@ -456,108 +452,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

@ -52,11 +52,6 @@ func (c *ConnectionEventListener) OnDisConnect() {
} }
func (c *ConnectionEventListener) redoSubscribe() { 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() { for _, key := range c.subscribes.Keys() {
info := strings.Split(key, constant.SERVICE_INFO_SPLITER) info := strings.Split(key, constant.SERVICE_INFO_SPLITER)
var err error var err error
@ -66,9 +61,15 @@ func (c *ConnectionEventListener) redoSubscribe() {
} else { } else {
service, err = c.clientProxy.Subscribe(info[1], info[0], "") service, err = c.clientProxy.Subscribe(info[1], info[0], "")
} }
if err != nil { if err != nil {
logger.Warnf("redo subscribe service:%s faild:%+v", info[1], err) 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) grpcProxy.serviceInfoHolder.ProcessService(&service)
} }

View File

@ -1,14 +1,14 @@
package naming_grpc package naming_grpc
import ( import (
"testing"
"github.com/golang/mock/gomock" "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/clients/naming_client/naming_proxy"
"github.com/nacos-group/nacos-sdk-go/v2/util" "github.com/nacos-group/nacos-sdk-go/v2/util"
"testing"
) )
func TestRedoSubscribe(t *testing.T) { 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) ctrl := gomock.NewController(t)
defer ctrl.Finish() defer ctrl.Finish()

View File

@ -28,7 +28,6 @@ import (
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc" "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_request"
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response" "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/inner/uuid"
"github.com/nacos-group/nacos-sdk-go/v2/model" "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/util"
@ -62,7 +61,7 @@ func NewNamingGrpcProxy(ctx context.Context, clientCfg constant.ClientConfig, na
constant.LABEL_MODULE: constant.LABEL_MODULE_NAMING, 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(ctx, uid.String(), rpc.GRPC, labels, srvProxy.nacosServer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -84,9 +83,10 @@ func NewNamingGrpcProxy(ctx context.Context, clientCfg constant.ClientConfig, na
func (proxy *NamingGrpcProxy) requestToServer(request rpc_request.IRequest) (rpc_response.IResponse, error) { func (proxy *NamingGrpcProxy) requestToServer(request rpc_request.IRequest) (rpc_response.IResponse, error) {
start := time.Now() 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)) 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 return response, err
} }

View File

@ -21,7 +21,7 @@ import (
"compress/gzip" "compress/gzip"
"context" "context"
"encoding/json" "encoding/json"
"io" "io/ioutil"
"math/rand" "math/rand"
"net" "net"
"strconv" "strconv"
@ -168,7 +168,7 @@ func TryDecompressData(data []byte) string {
} }
defer reader.Close() defer reader.Close()
bs, err := io.ReadAll(reader) bs, err := ioutil.ReadAll(reader)
if err != nil { if err != nil {
logger.Errorf("failed to decompress gzip data,err:%+v", err) logger.Errorf("failed to decompress gzip data,err:%+v", err)

View File

@ -18,8 +18,6 @@ package naming_client
import ( import (
"context" "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_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_grpc"
@ -41,23 +39,8 @@ type NamingProxyDelegate struct {
func NewNamingProxyDelegate(ctx context.Context, clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, func NewNamingProxyDelegate(ctx context.Context, clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig,
httpAgent http_agent.IHttpAgent, serviceInfoHolder *naming_cache.ServiceInfoHolder) (naming_proxy.INamingProxy, error) { 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, nacosServer, err := nacos_server.NewNacosServer(ctx, serverCfgs, clientCfg, httpAgent, clientCfg.TimeoutMs, clientCfg.Endpoint)
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)
if err != nil { if err != nil {
return nil, err return nil, err
} }

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 ... // WithRegionId ...
func WithRegionId(regionId string) ClientOption { func WithRegionId(regionId string) ClientOption {
return func(config *ClientConfig) { 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 ... // WithOpenKMS ...
func WithOpenKMS(openKMS bool) ClientOption { func WithOpenKMS(openKMS bool) ClientOption {
return func(config *ClientConfig) { 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 ... // WithCacheDir ...
func WithCacheDir(cacheDir string) ClientOption { func WithCacheDir(cacheDir string) ClientOption {
return func(config *ClientConfig) { return func(config *ClientConfig) {
@ -234,13 +188,6 @@ func WithLogRollingConfig(rollingConfig *ClientLogRollingConfig) ClientOption {
func WithTLS(tlsCfg TLSConfig) ClientOption { func WithTLS(tlsCfg TLSConfig) ClientOption {
return func(config *ClientConfig) { return func(config *ClientConfig) {
tlsCfg.Appointed = true
config.TLSCfg = tlsCfg config.TLSCfg = tlsCfg
} }
} }
func WithAppConnLabels(appConnLabels map[string]string) ClientOption {
return func(config *ClientConfig) {
config.AppConnLabels = appConnLabels
}
}

View File

@ -27,21 +27,17 @@ type ServerConfig struct {
} }
type ClientConfig struct { type ClientConfig struct {
TimeoutMs uint64 // timeout for requesting Nacos server, default value is 10000ms TimeoutMs uint64 // timeout for requesting Nacos server, default value is 10000ms
ListenInterval uint64 // Deprecated ListenInterval uint64 // Deprecated
BeatInterval int64 // the time interval for sending beat to server,default value is 5000ms 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. NamespaceId string // the namespaceId of Nacos.When namespace is public, fill in the blank string here.
AppName string // the appName AppName string // the appName
AppKey string // the client identity information AppKey string // the client identity information
Endpoint string // the endpoint for get Nacos server addresses Endpoint string // the endpoint for get Nacos server addresses
RegionId string // the regionId for kms RegionId string // the regionId for kms
AccessKey string // the AccessKey for kms AccessKey string // the AccessKey for kms
SecretKey string // the SecretKey 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
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
CacheDir string // the directory for persist nacos service info,default value is current path 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 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 goroutine for update nacos service info,default value is 20
@ -56,11 +52,6 @@ type ClientConfig struct {
LogSampling *ClientLogSamplingConfig // the sampling config of log LogSampling *ClientLogSamplingConfig // the sampling config of log
LogRollingConfig *ClientLogRollingConfig // log rolling config LogRollingConfig *ClientLogRollingConfig // log rolling config
TLSCfg TLSConfig // tls 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 { type ClientLogSamplingConfig struct {
@ -97,38 +88,9 @@ type ClientLogRollingConfig struct {
} }
type TLSConfig struct { type TLSConfig struct {
Appointed bool // Appointed or not ,if false,will get from env.
Enable bool // enable tls Enable bool // enable tls
TrustAll bool // trust all server
CaFile string // clients use when verifying server certificates CaFile string // clients use when verifying server certificates
CertFile string // server use when verifying client certificates CertFile string // server use when verifying client certificates
KeyFile string // server use when verifying client certificates KeyFile string // server use when verifying client certificates
ServerNameOverride string // serverNameOverride is for testing only 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,85 @@ package constant
import "time" import "time"
type KMSVersion string
const ( const (
KMSv1 KMSVersion = "KMSv1" KEY_USERNAME = "username"
KMSv3 KMSVersion = "KMSv3" KEY_PASSWORD = "password"
DEFAULT_KMS_VERSION KMSVersion = "" //to fit original version KEY_ENDPOINT = "endpoint"
UNKNOWN_KMS_VERSION KMSVersion = "UNKNOWN_KMS_VERSION" KEY_NAME_SPACE = "namespace"
) KEY_ACCESS_KEY = "accessKey"
const ( KEY_SECRET_KEY = "secretKey"
KEY_USERNAME = "username" KEY_SERVER_ADDR = "serverAddr"
KEY_PASSWORD = "password" KEY_CONTEXT_PATH = "contextPath"
KEY_ENDPOINT = "endpoint" KEY_ENCODE = "encode"
KEY_NAME_SPACE = "namespace" KEY_DATA_ID = "dataId"
KEY_ACCESS_KEY = "accessKey" KEY_GROUP = "group"
KEY_SECRET_KEY = "secretKey" KEY_TENANT = "tenant"
KEY_SERVER_ADDR = "serverAddr" KEY_DESC = "desc"
KEY_CONTEXT_PATH = "contextPath" KEY_APP_NAME = "appName"
KEY_ENCODE = "encode" KEY_CONTENT = "content"
KEY_DATA_ID = "dataId" KEY_TIMEOUT_MS = "timeoutMs"
KEY_GROUP = "group" KEY_LISTEN_INTERVAL = "listenInterval"
KEY_TENANT = "tenant" KEY_SERVER_CONFIGS = "serverConfigs"
KEY_DESC = "desc" KEY_CLIENT_CONFIG = "clientConfig"
KEY_APP_NAME = "appName" KEY_TOKEN = "token"
KEY_CONTENT = "content" KEY_ACCESS_TOKEN = "accessToken"
KEY_TIMEOUT_MS = "timeoutMs" KEY_TOKEN_TTL = "tokenTtl"
KEY_LISTEN_INTERVAL = "listenInterval" KEY_GLOBAL_ADMIN = "globalAdmin"
KEY_SERVER_CONFIGS = "serverConfigs" KEY_TOKEN_REFRESH_WINDOW = "tokenRefreshWindow"
KEY_CLIENT_CONFIG = "clientConfig" WEB_CONTEXT = "/nacos"
KEY_TOKEN = "token" CONFIG_BASE_PATH = "/v1/cs"
KEY_ACCESS_TOKEN = "accessToken" CONFIG_PATH = CONFIG_BASE_PATH + "/configs"
KEY_TOKEN_TTL = "tokenTtl" CONFIG_AGG_PATH = "/datum.do"
KEY_GLOBAL_ADMIN = "globalAdmin" CONFIG_LISTEN_PATH = CONFIG_BASE_PATH + "/configs/listener"
KEY_TOKEN_REFRESH_WINDOW = "tokenRefreshWindow" SERVICE_BASE_PATH = "/v1/ns"
WEB_CONTEXT = "/nacos" SERVICE_PATH = SERVICE_BASE_PATH + "/instance"
CONFIG_BASE_PATH = "/v1/cs" SERVICE_INFO_PATH = SERVICE_BASE_PATH + "/service"
CONFIG_PATH = CONFIG_BASE_PATH + "/configs" SERVICE_SUBSCRIBE_PATH = SERVICE_PATH + "/list"
CONFIG_AGG_PATH = "/datum.do" NAMESPACE_PATH = "/v1/console/namespaces"
CONFIG_LISTEN_PATH = CONFIG_BASE_PATH + "/configs/listener" SPLIT_CONFIG = string(rune(1))
SERVICE_BASE_PATH = "/v1/ns" SPLIT_CONFIG_INNER = string(rune(2))
SERVICE_PATH = SERVICE_BASE_PATH + "/instance" KEY_LISTEN_CONFIGS = "Listening-Configs"
SERVICE_INFO_PATH = SERVICE_BASE_PATH + "/service" KEY_SERVICE_NAME = "serviceName"
SERVICE_SUBSCRIBE_PATH = SERVICE_PATH + "/list" KEY_IP = "ip"
NAMESPACE_PATH = "/v1/console/namespaces" KEY_PORT = "port"
SPLIT_CONFIG = string(rune(1)) KEY_WEIGHT = "weight"
SPLIT_CONFIG_INNER = string(rune(2)) KEY_ENABLE = "enable"
KEY_LISTEN_CONFIGS = "Listening-Configs" KEY_HEALTHY = "healthy"
KEY_SERVICE_NAME = "serviceName" KEY_METADATA = "metadata"
KEY_IP = "ip" KEY_CLUSTER_NAME = "clusterName"
KEY_PORT = "port" KEY_CLUSTER = "cluster"
KEY_WEIGHT = "weight" KEY_BEAT = "beat"
KEY_ENABLE = "enable" KEY_DOM = "dom"
KEY_HEALTHY = "healthy" DEFAULT_CONTEXT_PATH = "/nacos"
KEY_METADATA = "metadata" CLIENT_VERSION = "Nacos-Go-Client:v2.2.1"
KEY_CLUSTER_NAME = "clusterName" REQUEST_DOMAIN_RETRY_TIME = 3
KEY_CLUSTER = "cluster" SERVICE_INFO_SPLITER = "@@"
KEY_BEAT = "beat" CONFIG_INFO_SPLITER = "@@"
KEY_DOM = "dom" DEFAULT_NAMESPACE_ID = "public"
DEFAULT_CONTEXT_PATH = "/nacos" DEFAULT_GROUP = "DEFAULT_GROUP"
CLIENT_VERSION = "Nacos-Go-Client:v2.3.3" NAMING_INSTANCE_ID_SPLITTER = "#"
REQUEST_DOMAIN_RETRY_TIME = 3 DefaultClientErrorCode = "SDK.NacosError"
SERVICE_INFO_SPLITER = "@@" DEFAULT_SERVER_SCHEME = "http"
CONFIG_INFO_SPLITER = "@@" HTTPS_SERVER_SCHEME = "https"
DEFAULT_NAMESPACE_ID = "public" LABEL_SOURCE = "source"
DEFAULT_GROUP = "DEFAULT_GROUP" LABEL_SOURCE_SDK = "sdk"
NAMING_INSTANCE_ID_SPLITTER = "#" LABEL_MODULE = "module"
DefaultClientErrorCode = "SDK.NacosError" LABEL_MODULE_CONFIG = "config"
DEFAULT_SERVER_SCHEME = "http" LABEL_MODULE_NAMING = "naming"
HTTPS_SERVER_SCHEME = "https" RESPONSE_CODE_SUCCESS = 200
LABEL_SOURCE = "source" UN_REGISTER = 301
LABEL_SOURCE_SDK = "sdk" KEEP_ALIVE_TIME = 5
LABEL_MODULE = "module" DEFAULT_TIMEOUT_MILLS = 3000
LABEL_MODULE_CONFIG = "config" ALL_SYNC_INTERNAL = 5 * time.Minute
LABEL_MODULE_NAMING = "naming" CLIENT_APPNAME_HEADER = "Client-AppName"
RESPONSE_CODE_SUCCESS = 200 APPNAME_HEADER = "AppName"
UN_REGISTER = 301 CLIENT_REQUEST_TS_HEADER = "Client-RequestTS"
KEEP_ALIVE_TIME = 5 CLIENT_REQUEST_TOKEN_HEADER = "Client-RequestToken"
DEFAULT_TIMEOUT_MILLS = 3000 EX_CONFIG_INFO = "exConfigInfo"
ALL_SYNC_INTERNAL = 5 * time.Minute CHARSET_KEY = "charset"
CLIENT_APPNAME_HEADER = "Client-AppName" LOG_FILE_NAME = "nacos-sdk.log"
APPNAME_HEADER = "AppName" HTTPS_SERVER_PORT = 443
CLIENT_REQUEST_TS_HEADER = "Client-RequestTS" GRPC = "grpc"
CLIENT_REQUEST_TOKEN_HEADER = "Client-RequestToken" FAILOVER_FILE_SUFFIX = "_failover"
EX_CONFIG_INFO = "exConfigInfo" RpcPortOffset = 1000
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"
) )

View File

@ -34,35 +34,35 @@ func NewServerConfig(ipAddr string, port uint64, opts ...ServerOption) *ServerCo
// ServerOption ... // ServerOption ...
type ServerOption func(*ServerConfig) type ServerOption func(*ServerConfig)
// WithScheme set Scheme for server //WithScheme set Scheme for server
func WithScheme(scheme string) ServerOption { func WithScheme(scheme string) ServerOption {
return func(config *ServerConfig) { return func(config *ServerConfig) {
config.Scheme = scheme config.Scheme = scheme
} }
} }
// WithContextPath set contextPath for server //WithContextPath set contextPath for server
func WithContextPath(contextPath string) ServerOption { func WithContextPath(contextPath string) ServerOption {
return func(config *ServerConfig) { return func(config *ServerConfig) {
config.ContextPath = contextPath config.ContextPath = contextPath
} }
} }
// WithIpAddr set ip address for server //WithIpAddr set ip address for server
func WithIpAddr(ipAddr string) ServerOption { func WithIpAddr(ipAddr string) ServerOption {
return func(config *ServerConfig) { return func(config *ServerConfig) {
config.IpAddr = ipAddr config.IpAddr = ipAddr
} }
} }
// WithPort set port for server //WithPort set port for server
func WithPort(port uint64) ServerOption { func WithPort(port uint64) ServerOption {
return func(config *ServerConfig) { return func(config *ServerConfig) {
config.Port = port config.Port = port
} }
} }
// WithGrpcPort set grpc port for server //WithGrpcPort set grpc port for server
func WithGrpcPort(port uint64) ServerOption { func WithGrpcPort(port uint64) ServerOption {
return func(config *ServerConfig) { return func(config *ServerConfig) {
config.GrpcPort = port 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 ( import (
"net/http" "net/http"
"net/url"
"strings" "strings"
"time" "time"
) )
func delete(client *http.Client, path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) { 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, "?") {
if !strings.HasSuffix(path, "?") { path = path + "?"
path = path + "?" }
} for key, value := range params {
for key, value := range params { path = path + key + "=" + value + "&"
path = path + key + "=" + url.QueryEscape(value) + "&" }
} if strings.HasSuffix(path, "&") {
if strings.HasSuffix(path, "&") { path = path[:len(path)-1]
path = path[:len(path)-1]
}
} }
client.Timeout = time.Millisecond * time.Duration(timeoutMs) client.Timeout = time.Millisecond * time.Duration(timeoutMs)
request, errNew := http.NewRequest(http.MethodDelete, path, nil) request, errNew := http.NewRequest(http.MethodDelete, path, nil)

View File

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

View File

@ -17,7 +17,7 @@
package http_agent package http_agent
import ( import (
"io" "io/ioutil"
"net/http" "net/http"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant" "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) 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 "" return ""
} }
bytes, errRead := io.ReadAll(response.Body) bytes, errRead := ioutil.ReadAll(response.Body)
defer response.Body.Close() defer response.Body.Close()
if errRead != nil { 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) 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.MaxBackups = logRollingConfig.MaxBackups
loggerConfig.LogRollingConfig.LocalTime = logRollingConfig.LocalTime loggerConfig.LogRollingConfig.LocalTime = logRollingConfig.LocalTime
loggerConfig.LogRollingConfig.Compress = logRollingConfig.Compress 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 return loggerConfig
} }
@ -163,7 +157,7 @@ func getEncoder() zapcore.EncoderConfig {
} }
} }
// SetLogger sets logger for sdk //SetLogger sets logger for sdk
func SetLogger(log Logger) { func SetLogger(log Logger) {
logLock.Lock() logLock.Lock()
defer logLock.Unlock() defer logLock.Unlock()

View File

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

View File

@ -18,7 +18,10 @@ package nacos_server
import ( import (
"context" "context"
"io" "crypto/hmac"
"crypto/sha1"
"encoding/base64"
"io/ioutil"
"math/rand" "math/rand"
"net/http" "net/http"
"reflect" "reflect"
@ -30,6 +33,8 @@ import (
"github.com/pkg/errors" "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/monitor"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant" "github.com/nacos-group/nacos-sdk-go/v2/common/constant"
@ -43,7 +48,7 @@ import (
type NacosServer struct { type NacosServer struct {
sync.RWMutex sync.RWMutex
securityLogin security.SecurityProxy securityLogin security.AuthClient
serverList []constant.ServerConfig serverList []constant.ServerConfig
httpAgent http_agent.IHttpAgent httpAgent http_agent.IHttpAgent
timeoutMs uint64 timeoutMs uint64
@ -51,25 +56,17 @@ type NacosServer struct {
lastSrvRefTime int64 lastSrvRefTime int64
vipSrvRefInterMills int64 vipSrvRefInterMills int64
contextPath string contextPath string
endpointContextPath string
endpointQueryParams string
endpointQueryHeader map[string][]string
clusterName string
currentIndex int32 currentIndex int32
ServerSrcChangeSignal chan struct{} 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) { func NewNacosServer(ctx context.Context, serverList []constant.ServerConfig, clientCfg constant.ClientConfig, httpAgent http_agent.IHttpAgent, timeoutMs uint64, endpoint 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) {
severLen := len(serverList) severLen := len(serverList)
if severLen == 0 && endpoint == "" { if severLen == 0 && endpoint == "" {
return &NacosServer{}, errors.New("both serverlist and endpoint are empty") 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{ ns := NacosServer{
serverList: serverList, serverList: serverList,
@ -78,21 +75,21 @@ func NewNacosServerWithRamCredentialProvider(ctx context.Context, serverList []c
timeoutMs: timeoutMs, timeoutMs: timeoutMs,
endpoint: endpoint, endpoint: endpoint,
vipSrvRefInterMills: 10000, vipSrvRefInterMills: 10000,
endpointContextPath: clientCfg.EndpointContextPath,
endpointQueryParams: clientCfg.EndpointQueryParams,
endpointQueryHeader: endpointQueryHeader,
clusterName: clientCfg.ClusterName,
contextPath: clientCfg.ContextPath, contextPath: clientCfg.ContextPath,
ServerSrcChangeSignal: make(chan struct{}, 1), ServerSrcChangeSignal: make(chan struct{}, 1),
} }
if severLen > 0 { if severLen > 0 {
ns.currentIndex = rand.Int31n(int32(severLen)) ns.currentIndex = rand.Int31n(int32(severLen))
} else {
ns.initRefreshSrvIfNeed(ctx)
} }
ns.securityLogin.Login() ns.initRefreshSrvIfNeed(ctx)
ns.securityLogin.AutoRefresh(ctx) _, err := securityLogin.Login()
if err != nil {
logger.Errorf("login in err:%v", err)
}
securityLogin.AutoRefresh(ctx)
return &ns, nil return &ns, nil
} }
@ -103,6 +100,8 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
contextPath = constant.WEB_CONTEXT contextPath = constant.WEB_CONTEXT
} }
signHeaders := GetSignHeaders(params, newHeaders["secretKey"])
url := curServer + contextPath + api url := curServer + contextPath + api
headers := map[string][]string{} headers := map[string][]string{}
@ -122,6 +121,10 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
} }
headers["RequestId"] = []string{uid.String()} headers["RequestId"] = []string{uid.String()}
headers["Content-Type"] = []string{"application/x-www-form-urlencoded;charset=utf-8"} 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 var response *http.Response
response, err = server.httpAgent.Request(method, url, headers, timeoutMS, params) 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 return
} }
var bytes []byte var bytes []byte
bytes, err = io.ReadAll(response.Body) bytes, err = ioutil.ReadAll(response.Body)
defer response.Body.Close() defer response.Body.Close()
if err != nil { if err != nil {
return return
@ -165,13 +168,15 @@ func (server *NacosServer) callServer(api string, params map[string]string, meth
headers["Request-Module"] = []string{"Naming"} headers["Request-Module"] = []string{"Naming"}
headers["Content-Type"] = []string{"application/x-www-form-urlencoded;charset=utf-8"} headers["Content-Type"] = []string{"application/x-www-form-urlencoded;charset=utf-8"}
server.InjectSecurityInfo(params)
var response *http.Response var response *http.Response
response, err = server.httpAgent.Request(method, url, headers, server.timeoutMs, params) response, err = server.httpAgent.Request(method, url, headers, server.timeoutMs, params)
if err != nil { if err != nil {
return return
} }
var bytes []byte var bytes []byte
bytes, err = io.ReadAll(response.Body) bytes, err = ioutil.ReadAll(response.Body)
defer response.Body.Close() defer response.Body.Close()
if err != nil { if err != nil {
return return
@ -192,7 +197,7 @@ func (server *NacosServer) ReqConfigApi(api string, params map[string]string, he
return "", errors.New("server list is empty") 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 //only one server,retry request when error
var err error var err error
@ -226,7 +231,8 @@ func (server *NacosServer) ReqApi(api string, params map[string]string, method s
return "", errors.New("server list is empty") return "", errors.New("server list is empty")
} }
server.InjectSecurityInfo(params, security.BuildNamingResource(params["namespaceId"], params["serviceName"], params["groupName"])) server.InjectSecurityInfo(params)
server.InjectSignForNamingHttp(params, config)
//only one server,retry request when error //only one server,retry request when error
var err error var err error
@ -258,44 +264,31 @@ func (server *NacosServer) initRefreshSrvIfNeed(ctx context.Context) {
if server.endpoint == "" { if server.endpoint == "" {
return return
} }
server.refreshServerSrvIfNeed()
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)
go func() { go func() {
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return
default: default:
time.Sleep(time.Duration(10) * time.Second) time.Sleep(time.Duration(1) * time.Second)
server.refreshServerSrvIfNeed(urlString, server.endpointQueryHeader) 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 { if util.CurrentMillis()-server.lastSrvRefTime < server.vipSrvRefInterMills && len(server.serverList) > 0 {
return return
} }
var list []string var list []string
urlString := "http://" + server.endpoint + "/nacos/serverlist"
result := server.httpAgent.RequestOnlyResult(http.MethodGet, urlString, header, server.timeoutMs, nil) result := server.httpAgent.RequestOnlyResult(http.MethodGet, urlString, nil, server.timeoutMs, nil)
list = strings.Split(result, "\n") list = strings.Split(result, "\n")
logger.Infof("http nacos server list: <%s>", result)
var servers []constant.ServerConfig var servers []constant.ServerConfig
contextPath := server.contextPath contextPath := server.contextPath
@ -321,15 +314,10 @@ func (server *NacosServer) refreshServerSrvIfNeed(urlString string, header map[s
if len(servers) > 0 { if len(servers) > 0 {
if !reflect.DeepEqual(server.serverList, servers) { if !reflect.DeepEqual(server.serverList, servers) {
server.Lock() server.Lock()
var serverPrev = server.serverList logger.Infof("server list is updated, old: <%v>,new:<%v>", server.serverList, servers)
logger.Infof("server list is updated, old: <%v>,new:<%v>", serverPrev, servers)
server.serverList = servers server.serverList = servers
if serverPrev != nil { server.ServerSrcChangeSignal <- struct{}{}
server.ServerSrcChangeSignal <- struct{}{}
}
server.lastSrvRefTime = util.CurrentMillis() server.lastSrvRefTime = util.CurrentMillis()
server.securityLogin.UpdateServerList(servers)
server.Unlock() server.Unlock()
} }
@ -341,13 +329,47 @@ func (server *NacosServer) GetServerList() []constant.ServerConfig {
return server.serverList return server.serverList
} }
func (server *NacosServer) InjectSecurityInfo(param map[string]string, resource security.RequestResource) { func (server *NacosServer) InjectSecurityInfo(param map[string]string) {
securityInfo := server.securityLogin.GetSecurityInfo(resource) accessToken := server.securityLogin.GetAccessToken()
for k, v := range securityInfo { if accessToken != "" {
param[k] = v param[constant.KEY_ACCESS_TOKEN] = accessToken
} }
} }
func (server *NacosServer) InjectSignForNamingHttp(param map[string]string, clientConfig constant.ClientConfig) {
if clientConfig.AccessKey == "" || clientConfig.SecretKey == "" {
return
}
var signData string
timeStamp := strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
if serviceName, hasServiceName := param["serviceName"]; hasServiceName {
if groupName, hasGroup := param["groupName"]; strings.Contains(serviceName, constant.SERVICE_INFO_SPLITER) || !hasGroup || groupName == "" {
signData = timeStamp + constant.SERVICE_INFO_SPLITER + serviceName
} else {
signData = timeStamp + constant.SERVICE_INFO_SPLITER + util.GetGroupName(serviceName, groupName)
}
} else {
signData = timeStamp
}
param["signature"] = signWithhmacSHA1Encrypt(signData, clientConfig.SecretKey)
param["ak"] = clientConfig.AccessKey
param["data"] = signData
}
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 { func getAddress(cfg constant.ServerConfig) string {
if strings.Index(cfg.IpAddr, "http://") >= 0 || strings.Index(cfg.IpAddr, "https://") >= 0 { if strings.Index(cfg.IpAddr, "http://") >= 0 || strings.Index(cfg.IpAddr, "https://") >= 0 {
return cfg.IpAddr + ":" + strconv.Itoa(int(cfg.Port)) return cfg.IpAddr + ":" + strconv.Itoa(int(cfg.Port))
@ -355,6 +377,69 @@ func getAddress(cfg constant.ServerConfig) string {
return cfg.Scheme + "://" + cfg.IpAddr + ":" + strconv.Itoa(int(cfg.Port)) 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) { func (server *NacosServer) GetNextServer() (constant.ServerConfig, error) {
serverLen := len(server.GetServerList()) serverLen := len(server.GetServerList())
if serverLen == 0 { if serverLen == 0 {
@ -363,3 +448,9 @@ func (server *NacosServer) GetNextServer() (constant.ServerConfig, error) {
index := atomic.AddInt32(&server.currentIndex, 1) % int32(serverLen) index := atomic.AddInt32(&server.currentIndex, 1) % int32(serverLen)
return server.GetServerList()[index], nil 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

@ -18,10 +18,8 @@ package nacos_server
import ( import (
"context" "context"
"testing"
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent" "github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/common/security" "testing"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant" "github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -57,24 +55,23 @@ func buildNacosServer(clientConfig constant.ClientConfig) (*NacosServer, error)
clientConfig, clientConfig,
&http_agent.HttpAgent{}, &http_agent.HttpAgent{},
1000, 1000,
"", "")
nil)
} }
func TestNacosServer_InjectSignForNamingHttp_NoAk(t *testing.T) { func TestNacosServer_InjectSignForNamingHttp_NoAk(t *testing.T) {
clientConfig := constant.ClientConfig{ clientConfig := constant.ClientConfig{
AccessKey: "", AccessKey: "123",
SecretKey: "", SecretKey: "321",
} }
server, err := buildNacosServer(clientConfig) server, err := buildNacosServer(clientConfig)
if err != nil { if err != nil {
t.FailNow() t.FailNow()
} }
param := make(map[string]string, 4) param := make(map[string]string)
param["serviceName"] = "s-0" param["serviceName"] = "s-0"
param["groupName"] = "g-0" param["groupName"] = "g-0"
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"])) server.InjectSignForNamingHttp(param, constant.ClientConfig{})
assert.Empty(t, param["ak"]) assert.Empty(t, param["ak"])
assert.Empty(t, param["data"]) assert.Empty(t, param["data"])
assert.Empty(t, param["signature"]) assert.Empty(t, param["signature"])
@ -90,10 +87,10 @@ func TestNacosServer_InjectSignForNamingHttp_WithGroup(t *testing.T) {
t.FailNow() t.FailNow()
} }
param := make(map[string]string, 4) param := make(map[string]string)
param["serviceName"] = "s-0" param["serviceName"] = "s-0"
param["groupName"] = "g-0" param["groupName"] = "g-0"
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"])) server.InjectSignForNamingHttp(param, clientConfig)
assert.Equal(t, "123", param["ak"]) assert.Equal(t, "123", param["ak"])
assert.Contains(t, param["data"], "@@g-0@@s-0") assert.Contains(t, param["data"], "@@g-0@@s-0")
_, has := param["signature"] _, has := param["signature"]
@ -110,9 +107,9 @@ func TestNacosServer_InjectSignForNamingHttp_WithoutGroup(t *testing.T) {
t.FailNow() t.FailNow()
} }
param := make(map[string]string, 4) param := make(map[string]string)
param["serviceName"] = "s-0" param["serviceName"] = "s-0"
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"])) server.InjectSignForNamingHttp(param, clientConfig)
assert.Equal(t, "123", param["ak"]) assert.Equal(t, "123", param["ak"])
assert.NotContains(t, param["data"], "@@g-0@@s-0") assert.NotContains(t, param["data"], "@@g-0@@s-0")
assert.Contains(t, param["data"], "@@s-0") assert.Contains(t, param["data"], "@@s-0")
@ -130,11 +127,11 @@ func TestNacosServer_InjectSignForNamingHttp_WithoutServiceName(t *testing.T) {
t.FailNow() t.FailNow()
} }
param := make(map[string]string, 4) param := make(map[string]string)
param["groupName"] = "g-0" param["groupName"] = "g-0"
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"])) server.InjectSignForNamingHttp(param, clientConfig)
assert.Equal(t, "123", param["ak"]) assert.Equal(t, "123", param["ak"])
assert.Contains(t, param["data"], "@@") assert.NotContains(t, param["data"], "@@")
assert.Regexp(t, "\\d+", param["data"]) assert.Regexp(t, "\\d+", param["data"])
_, has := param["signature"] _, has := param["signature"]
assert.True(t, has) assert.True(t, has)
@ -150,38 +147,11 @@ func TestNacosServer_InjectSignForNamingHttp_WithoutServiceNameAndGroup(t *testi
t.FailNow() t.FailNow()
} }
param := make(map[string]string, 4) param := make(map[string]string)
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["serviceName"], param["groupName"])) server.InjectSignForNamingHttp(param, clientConfig)
assert.Equal(t, "123", param["ak"]) assert.Equal(t, "123", param["ak"])
assert.NotContains(t, param["data"], "@@") assert.NotContains(t, param["data"], "@@")
assert.Regexp(t, "\\d+", param["data"]) assert.Regexp(t, "\\d+", param["data"])
_, has := param["signature"] _, has := param["signature"]
assert.True(t, has) 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

@ -18,13 +18,8 @@ package rpc
import ( import (
"context" "context"
"crypto/tls"
"crypto/x509"
"encoding/json" "encoding/json"
"fmt"
"google.golang.org/grpc/credentials"
"io" "io"
"log"
"os" "os"
"strconv" "strconv"
"sync" "sync"
@ -46,21 +41,20 @@ import (
type GrpcClient struct { type GrpcClient struct {
*RpcClient *RpcClient
*constant.TLSConfig
} }
func NewGrpcClient(ctx context.Context, clientName string, nacosServer *nacos_server.NacosServer, tlsConfig *constant.TLSConfig) *GrpcClient { func NewGrpcClient(ctx context.Context, clientName string, nacosServer *nacos_server.NacosServer) *GrpcClient {
rpcClient := &GrpcClient{ rpcClient := &GrpcClient{
&RpcClient{ &RpcClient{
ctx: ctx, ctx: ctx,
name: clientName, name: clientName,
labels: make(map[string]string, 8), labels: make(map[string]string, 8),
rpcClientStatus: INITIALIZED, rpcClientStatus: INITIALIZED,
eventChan: make(chan ConnectionEvent, 1), eventChan: make(chan ConnectionEvent),
reconnectionChan: make(chan ReconnectContext, 1), reconnectionChan: make(chan ReconnectContext),
nacosServer: nacosServer, nacosServer: nacosServer,
mux: new(sync.Mutex), mux: new(sync.Mutex),
}, tlsConfig, },
} }
rpcClient.RpcClient.lastActiveTimestamp.Store(time.Now()) rpcClient.RpcClient.lastActiveTimestamp.Store(time.Now())
rpcClient.executeClient = rpcClient rpcClient.executeClient = rpcClient
@ -93,41 +87,6 @@ func getInitialConnWindowSize() int32 {
return int32(initialConnWindowSize) 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 { func getInitialGrpcTimeout() int32 {
initialGrpcTimeout, err := strconv.Atoi(os.Getenv("nacos.remote.client.grpc.timeout")) initialGrpcTimeout, err := strconv.Atoi(os.Getenv("nacos.remote.client.grpc.timeout"))
if err != nil { if err != nil {
@ -158,11 +117,6 @@ func (c *GrpcClient) createNewConnection(serverInfo ServerInfo) (*grpc.ClientCon
opts = append(opts, grpc.WithInsecure()) opts = append(opts, grpc.WithInsecure())
opts = append(opts, grpc.WithInitialWindowSize(getInitialWindowSize())) opts = append(opts, grpc.WithInitialWindowSize(getInitialWindowSize()))
opts = append(opts, grpc.WithInitialConnWindowSize(getInitialConnWindowSize())) 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 rpcPort := serverInfo.serverGrpcPort
if rpcPort == 0 { if rpcPort == 0 {
rpcPort = serverInfo.serverPort + c.rpcPortOffset() rpcPort = serverInfo.serverPort + c.rpcPortOffset()
@ -171,39 +125,6 @@ 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) { func (c *GrpcClient) connectToServer(serverInfo ServerInfo) (IConnection, error) {
var client nacos_grpc_service.RequestClient var client nacos_grpc_service.RequestClient
var biStreamClient nacos_grpc_service.BiRequestStreamClient var biStreamClient nacos_grpc_service.BiRequestStreamClient
@ -240,7 +161,7 @@ func (c *GrpcClient) sendConnectionSetupRequest(grpcConn *GrpcConnection) error
csr.ClientAbilities = c.clientAbilities csr.ClientAbilities = c.clientAbilities
err := grpcConn.biStreamSend(convertRequest(csr)) err := grpcConn.biStreamSend(convertRequest(csr))
if err != nil { if err != nil {
logger.Warnf("send connectionSetupRequest error:%v", err) logger.Warnf("Send ConnectionSetupRequest error:%+v", err)
} }
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
return err return err
@ -259,7 +180,6 @@ func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiReque
for { for {
select { select {
case <-streamClient.Context().Done(): case <-streamClient.Context().Done():
logger.Warnf("connectionId %s stream client close", grpcConn.getConnectionId())
return return
default: default:
payload, err := streamClient.Recv() payload, err := streamClient.Recv()
@ -268,16 +188,16 @@ func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiReque
abandon := grpcConn.getAbandon() abandon := grpcConn.getAbandon()
if c.IsRunning() && !abandon { if c.IsRunning() && !abandon {
if err == io.EOF { 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 { } 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)) { if atomic.CompareAndSwapInt32((*int32)(&c.rpcClientStatus), int32(RUNNING), int32(UNHEALTHY)) {
c.switchServerAsync(ServerInfo{}, false) c.switchServerAsync(ServerInfo{}, false)
return return
} }
} else { } 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 return
} }
} else { } else {

View File

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

View File

@ -18,11 +18,8 @@ package rpc
import ( import (
"context" "context"
"fmt"
"math" "math"
"os"
"reflect" "reflect"
"strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -150,31 +147,17 @@ func getClient(clientName string) IRpcClient {
return clientMap[clientName] 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(ctx context.Context, clientName string, connectionType ConnectionType, labels map[string]string, nacosServer *nacos_server.NacosServer) (IRpcClient, error) {
cMux.Lock() cMux.Lock()
defer cMux.Unlock() defer cMux.Unlock()
if _, ok := clientMap[clientName]; !ok { if _, ok := clientMap[clientName]; !ok {
logger.Infof("init rpc client for name ", clientName)
var rpcClient IRpcClient var rpcClient IRpcClient
if GRPC == connectionType { if GRPC == connectionType {
rpcClient = NewGrpcClient(ctx, clientName, nacosServer, tlsConfig) rpcClient = NewGrpcClient(ctx, clientName, nacosServer)
} }
if rpcClient == nil { if rpcClient == nil {
return nil, errors.New("unsupported connection type") 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) rpcClient.putAllLabels(labels)
clientMap[clientName] = rpcClient clientMap[clientName] = rpcClient
return rpcClient, nil return rpcClient, nil
@ -182,92 +165,6 @@ func CreateClient(ctx context.Context, clientName string, connectionType Connect
return clientMap[clientName], nil 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() { func (r *RpcClient) Start() {
if ok := atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(INITIALIZED), (int32)(STARTING)); !ok { if ok := atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(INITIALIZED), (int32)(STARTING)); !ok {
return return
@ -321,7 +218,7 @@ func (r *RpcClient) Start() {
startUpRetryTimes-- startUpRetryTimes--
serverInfo, err := r.nextRpcServer() serverInfo, err := r.nextRpcServer()
if err != nil { if err != nil {
logger.Errorf("[RpcClient.nextRpcServer],err:%v", err) logger.Errorf("[RpcClient.nextRpcServer],err:%+v", err)
break 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)
@ -338,14 +235,16 @@ func (r *RpcClient) Start() {
currentConnection.getServerInfo(), currentConnection.getConnectionId()) currentConnection.getServerInfo(), currentConnection.getConnectionId())
r.currentConnection = currentConnection r.currentConnection = currentConnection
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING)) atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
r.notifyConnectionChange(CONNECTED) r.asyncNotifyConnectionChange(CONNECTED)
} else { } else {
r.switchServerAsync(ServerInfo{}, false) r.switchServerAsync(ServerInfo{}, false)
} }
} }
func (r *RpcClient) notifyConnectionChange(eventType ConnectionStatus) { func (r *RpcClient) asyncNotifyConnectionChange(eventType ConnectionStatus) {
r.eventChan <- ConnectionEvent{eventType: eventType} go func() {
r.eventChan <- ConnectionEvent{eventType: eventType}
}()
} }
func (r *RpcClient) notifyServerSrvChange() { func (r *RpcClient) notifyServerSrvChange() {
@ -413,7 +312,6 @@ func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
if onRequestFail && r.sendHealthCheck() { 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)) atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
r.notifyConnectionChange(CONNECTED)
return return
} }
var ( var (
@ -447,7 +345,7 @@ func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
} }
r.currentConnection = connectionNew r.currentConnection = connectionNew
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING)) atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
r.notifyConnectionChange(CONNECTED) r.asyncNotifyConnectionChange(CONNECTED)
return return
} }
if r.isShutdown() { if r.isShutdown() {
@ -473,7 +371,7 @@ func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
func (r *RpcClient) closeConnection() { func (r *RpcClient) closeConnection() {
if r.currentConnection != nil { if r.currentConnection != nil {
r.currentConnection.close() r.currentConnection.close()
r.notifyConnectionChange(DISCONNECTED) r.asyncNotifyConnectionChange(DISCONNECTED)
} }
} }
@ -483,7 +381,7 @@ func (r *RpcClient) notifyConnectionEvent(event ConnectionEvent) {
if len(listeners) == 0 { if len(listeners) == 0 {
return 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 { for _, v := range listeners {
if event.isConnected() { if event.isConnected() {
v.OnConnected() v.OnConnected()
@ -609,9 +507,6 @@ func (r *RpcClient) Request(request rpc_request.IRequest, timeoutMills int64) (r
currentErr = waitReconnect(timeoutMills, &retryTimes, request, errors.New(response.GetMessage())) currentErr = waitReconnect(timeoutMills, &retryTimes, request, errors.New(response.GetMessage()))
continue continue
} }
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()) r.lastActiveTimestamp.Store(time.Now())
return response, nil return response, nil
} }

View File

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

View File

@ -21,7 +21,6 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/model" "github.com/nacos-group/nacos-sdk-go/v2/model"
) )
@ -69,7 +68,7 @@ func NewInstanceRequest(namespace, serviceName, groupName, Type string, instance
} }
func (r *InstanceRequest) GetRequestType() string { func (r *InstanceRequest) GetRequestType() string {
return constant.INSTANCE_REQUEST_NAME return "InstanceRequest"
} }
type BatchInstanceRequest struct { type BatchInstanceRequest struct {
@ -87,7 +86,7 @@ func NewBatchInstanceRequest(namespace, serviceName, groupName, Type string, ins
} }
func (r *BatchInstanceRequest) GetRequestType() string { func (r *BatchInstanceRequest) GetRequestType() string {
return constant.BATCH_INSTANCE_REQUEST_NAME return "BatchInstanceRequest"
} }
type NotifySubscriberRequest struct { type NotifySubscriberRequest struct {
@ -96,7 +95,7 @@ type NotifySubscriberRequest struct {
} }
func (r *NotifySubscriberRequest) GetRequestType() string { func (r *NotifySubscriberRequest) GetRequestType() string {
return constant.NOTIFY_SUBSCRIBE_REQUEST_NAME return "NotifySubscriberRequest"
} }
type ServiceListRequest struct { type ServiceListRequest struct {
@ -116,7 +115,7 @@ func NewServiceListRequest(namespace, serviceName, groupName string, pageNo, pag
} }
func (r *ServiceListRequest) GetRequestType() string { func (r *ServiceListRequest) GetRequestType() string {
return constant.SERVICE_LIST_REQUEST_NAME return "ServiceListRequest"
} }
type SubscribeServiceRequest struct { type SubscribeServiceRequest struct {
@ -134,7 +133,7 @@ func NewSubscribeServiceRequest(namespace, serviceName, groupName, clusters stri
} }
func (r *SubscribeServiceRequest) GetRequestType() string { func (r *SubscribeServiceRequest) GetRequestType() string {
return constant.SUBSCRIBE_SERVICE_REQUEST_NAME return "SubscribeServiceRequest"
} }
type ServiceQueryRequest struct { type ServiceQueryRequest struct {
@ -154,5 +153,5 @@ func NewServiceQueryRequest(namespace, serviceName, groupName, cluster string, h
} }
func (r *ServiceQueryRequest) GetRequestType() string { 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) { func (r *Request) PutAllHeaders(headers map[string]string) {
if r.Headers == nil {
r.Headers = make(map[string]string)
}
for k, v := range headers { for k, v := range headers {
r.Headers[k] = v 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

@ -36,7 +36,6 @@ type IResponse interface {
GetBody() string GetBody() string
GetErrorCode() int GetErrorCode() int
IsSuccess() bool IsSuccess() bool
SetSuccess(bool)
GetResultCode() int GetResultCode() int
GetMessage() string GetMessage() string
} }
@ -61,10 +60,6 @@ func (r *Response) IsSuccess() bool {
return r.Success return r.Success
} }
func (r *Response) SetSuccess(successResult bool) {
r.Success = successResult
}
func (r *Response) GetErrorCode() int { func (r *Response) GetErrorCode() int {
return r.ErrorCode return r.ErrorCode
} }

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

@ -87,14 +87,12 @@ func (*NamingPushRequestHandler) Name() string {
return "NamingPushRequestHandler" return "NamingPushRequestHandler"
} }
func (c *NamingPushRequestHandler) RequestReply(request rpc_request.IRequest, client *RpcClient) rpc_response.IResponse { func (c *NamingPushRequestHandler) RequestReply(request rpc_request.IRequest, _ *RpcClient) rpc_response.IResponse {
notifySubscriberRequest, ok := request.(*rpc_request.NotifySubscriberRequest) notifySubscriberRequest, ok := request.(*rpc_request.NotifySubscriberRequest)
if ok { if ok {
c.ServiceInfoHolder.ProcessService(&notifySubscriberRequest.ServiceInfo) c.ServiceInfoHolder.ProcessService(&notifySubscriberRequest.ServiceInfo)
logger.Debugf("%s naming push response success ackId->%s", client.currentConnection.getConnectionId(),
request.GetRequestId())
return &rpc_response.NotifySubscriberResponse{ 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 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

@ -18,135 +18,81 @@ package security
import ( import (
"context" "context"
"encoding/json"
"io/ioutil"
"net/http"
"strconv"
"strings"
"sync/atomic"
"time" "time"
"github.com/pkg/errors"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant" "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/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/common/logger" "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 { type AuthClient struct {
requestType string username string
namespace string password string
group string accessToken *atomic.Value
resource string tokenTtl int64
lastRefreshTime int64
tokenRefreshWindow int64
agent http_agent.IHttpAgent
clientCfg constant.ClientConfig
serverCfgs []constant.ServerConfig
} }
const ( func NewAuthClient(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, agent http_agent.IHttpAgent) AuthClient {
REQUEST_TYPE_CONFIG = "config" client := AuthClient{
REQUEST_TYPE_NAMING = "naming" username: clientCfg.Username,
) password: clientCfg.Password,
serverCfgs: serverCfgs,
clientCfg: clientCfg,
agent: agent,
accessToken: &atomic.Value{},
}
func BuildConfigResourceByRequest(request rpc_request.IRequest) RequestResource { return client
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,
}
} }
func BuildNamingResourceByRequest(request rpc_request.IRequest) RequestResource { func (ac *AuthClient) GetAccessToken() string {
if request.GetRequestType() == constant.INSTANCE_REQUEST_NAME { v := ac.accessToken.Load()
instanceRequest := request.(*rpc_request.InstanceRequest) if v == nil {
return BuildNamingResource(instanceRequest.Namespace, instanceRequest.GroupName, instanceRequest.ServiceName) return ""
}
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,
} }
return v.(string)
} }
func BuildConfigResource(tenant, group, dataId string) RequestResource { func (ac *AuthClient) AutoRefresh(ctx context.Context) {
return RequestResource{
requestType: REQUEST_TYPE_CONFIG, // If the username is not set, the automatic refresh Token is not enabled
namespace: tenant,
group: group, if ac.username == "" {
resource: dataId, 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() { go func() {
var timer = time.NewTimer(time.Second * time.Duration(5)) 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() defer timer.Stop()
for { for {
select { select {
case <-timer.C: case <-timer.C:
sp.Login() _, err := ac.Login()
timer.Reset(time.Second * time.Duration(5)) 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(): case <-ctx.Done():
return return
} }
@ -154,20 +100,75 @@ func (sp *SecurityProxy) AutoRefresh(ctx context.Context) {
}() }()
} }
func NewSecurityProxy(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, agent http_agent.IHttpAgent) SecurityProxy { func (ac *AuthClient) Login() (bool, error) {
var securityProxy = SecurityProxy{} var throwable error = nil
securityProxy.Clients = []AuthClient{ for i := 0; i < len(ac.serverCfgs); i++ {
NewNacosAuthClient(clientCfg, serverCfgs, agent), result, err := ac.login(ac.serverCfgs[i])
NewRamAuthClient(clientCfg), 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 { func (ac *AuthClient) login(server constant.ServerConfig) (bool, error) {
var securityProxy = SecurityProxy{} if ac.username != "" {
securityProxy.Clients = []AuthClient{ contextPath := server.ContextPath
NewNacosAuthClient(clientCfg, serverCfgs, agent),
NewRamAuthClientWithProvider(clientCfg, provider), 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.lastRefreshTime = time.Now().Unix()
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/tls"
"crypto/x509" "crypto/x509"
"fmt" "fmt"
"os" "io/ioutil"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant" "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) { func rootCert(caFile string) (*x509.CertPool, error) {
b, err := os.ReadFile(caFile) b, err := ioutil.ReadFile(caFile)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

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

View File

@ -1 +0,0 @@
LTAIxxxxxxxxxxxBHS21E6

View File

@ -18,123 +18,67 @@ package main
import ( import (
"fmt" "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/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
"github.com/nacos-group/nacos-sdk-go/v2/vo" "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() { 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 { if err != nil {
panic(err) panic(err)
} }
for _, localConfig := range localConfigList { // to enable encrypt/decrypt, DataId should be start with "cipher-"
// to enable encrypt/decrypt, DataId should be start with "cipher-" _, err = client.PublishConfig(vo.ConfigParam{
configParam := vo.ConfigParam{ DataId: "cipher-dataId-1",
DataId: localConfig.DataId, Group: "test-group",
Group: localConfig.Group, Content: "hello world!",
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)
},
}
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 { 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) time.Sleep(2 * time.Second)
//cancel config change
err = client.CancelListenConfig(vo.ConfigParam{
DataId: "test-data",
Group: "test-group",
})
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
_, err = client.DeleteConfig(vo.ConfigParam{ _, err = client.DeleteConfig(vo.ConfigParam{
DataId: "test-data", DataId: "test-data",
@ -118,12 +124,6 @@ func main() {
}) })
time.Sleep(1 * time.Second) 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.SearchConfigParam{
Search: "blur", Search: "blur",
DataId: "", DataId: "",

69
go.mod
View File

@ -1,72 +1,19 @@
module github.com/nacos-group/nacos-sdk-go/v2 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.15
go 1.21
require ( require (
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704
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/buger/jsonparser v1.1.1 github.com/buger/jsonparser v1.1.1
github.com/golang/mock v1.6.0 github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.2
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.12.2 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 go.uber.org/zap v1.21.0
golang.org/x/sync v0.10.0 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
golang.org/x/time v0.1.0 golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
google.golang.org/grpc v1.67.3 google.golang.org/grpc v1.48.0
google.golang.org/protobuf v1.36.5 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f
gopkg.in/natefinch/lumberjack.v2 v2.0.0 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-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-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= 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/aliyun/alibaba-cloud-sdk-go v1.61.1704 h1:PpfENOj/vPfhhy9N2OFRjpue0hjM5XqAp2thFmkXXIk=
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
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/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 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= 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/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/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.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.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/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/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/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/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-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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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.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.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.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/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 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-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/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.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/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.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.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 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/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 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.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.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.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.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 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/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 v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= 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-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/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/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.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= 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/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 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/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= 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/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.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/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.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= 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/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.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/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/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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 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/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-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/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.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/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= 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.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 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= 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/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.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 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/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.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.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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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.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.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.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.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/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.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 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.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= 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.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/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.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 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= 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-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-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-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-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-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-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= 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-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-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-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/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-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= 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.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.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.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.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-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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/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-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-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-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-20201021035429-f5854403a974/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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 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-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-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-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/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-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-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-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.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-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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-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-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-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-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-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/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-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-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-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-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-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-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-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-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-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-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.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.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.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.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.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.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-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-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.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.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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-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-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-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-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-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-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-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-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/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-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-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-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-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-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/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-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/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.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.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-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-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-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= 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.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= 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-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-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-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-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-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-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-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-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 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.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= 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.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.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.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s= 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-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-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 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.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-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.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.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 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 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-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-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/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.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 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 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.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.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.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.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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-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.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-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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/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. // UnmarshalText implements the encoding.TextUnmarshaler interface.
// Following formats are supported: // Following formats are supported:
// // "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8", // "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}", // "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8" // "6ba7b8109dad11d180b400c04fd430c8"
// "6ba7b8109dad11d180b400c04fd430c8"
//
// ABNF for supported UUID text representation follows: // ABNF for supported UUID text representation follows:
// // uuid := canonical | hashlike | braced | urn
// uuid := canonical | hashlike | braced | urn // plain := canonical | hashlike
// plain := canonical | hashlike // canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct // hashlike := 12hexoct
// hashlike := 12hexoct // braced := '{' plain '}'
// braced := '{' plain '}' // urn := URN ':' UUID-NID ':' plain
// urn := URN ':' UUID-NID ':' plain // URN := 'urn'
// URN := 'urn' // UUID-NID := 'uuid'
// UUID-NID := 'uuid' // 12hexoct := 6hexoct 6hexoct
// 12hexoct := 6hexoct 6hexoct // 6hexoct := 4hexoct 2hexoct
// 6hexoct := 4hexoct 2hexoct // 4hexoct := 2hexoct 2hexoct
// 4hexoct := 2hexoct 2hexoct // 2hexoct := hexoct hexoct
// 2hexoct := hexoct hexoct // hexoct := hexdig hexdig
// hexoct := hexdig hexdig // hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | // 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | // 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
// 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
func (u *UUID) UnmarshalText(text []byte) (err error) { func (u *UUID) UnmarshalText(text []byte) (err error) {
switch len(text) { switch len(text) {
case 32: 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) // 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 // and panics if the error is non-nil. It is intended for use in variable
// initializations such as // initializations such as
//
// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000")); // var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"));
func Must(u UUID, err error) UUID { func Must(u UUID, err error) UUID {
if err != nil { if err != nil {

View File

@ -46,9 +46,3 @@ type ConfigContext struct {
DataId string `json:"dataId"` DataId string `json:"dataId"`
Tenant string `json:"tenant"` Tenant string `json:"tenant"`
} }
type ConfigPageResult struct {
Code int `json:"code"`
Message string `json:"message"`
Data ConfigPage `json:"data"`
}

View File

@ -139,12 +139,3 @@ func DeepCopyMap(params map[string]string) map[string]string {
} }
return result return result
} }
func Contains(slice []string, item string) bool {
for _, s := range slice {
if s == item {
return true
}
}
return false
}

View File

@ -16,13 +16,9 @@
package vo package vo
import ( import "github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
)
type NacosClientParam struct { type NacosClientParam struct {
ClientConfig *constant.ClientConfig // optional ClientConfig *constant.ClientConfig // optional
ServerConfigs []constant.ServerConfig // optional ServerConfigs []constant.ServerConfig // optional
RamCredentialProvider security.RamCredentialProvider // optinal
} }

View File

@ -19,38 +19,18 @@ package vo
type Listener func(namespace, group, dataId, data string) type Listener func(namespace, group, dataId, data string)
type ConfigParam struct { type ConfigParam struct {
DataId string `param:"dataId"` //required DataId string `param:"dataId"` //required
Group string `param:"group"` //required Group string `param:"group"` //required
Content string `param:"content"` //required Content string `param:"content"` //required
Tag string `param:"tag"` Tag string `param:"tag"`
ConfigTags string `param:"configTags"` AppName string `param:"appName"`
AppName string `param:"appName"` BetaIps string `param:"betaIps"`
BetaIps string `param:"betaIps"` CasMd5 string `param:"casMd5"`
CasMd5 string `param:"casMd5"` Type string `param:"type"`
Type string `param:"type"` EncryptedDataKey string `param:"encryptedDataKey"`
SrcUser string `param:"srcUser"`
EncryptedDataKey string `param:"encryptedDataKey"`
KmsKeyId string `param:"kmsKeyId"`
UsageType UsageType `param:"usageType"`
OnChange func(namespace, group, dataId, data string) OnChange func(namespace, group, dataId, data string)
} }
func (this *ConfigParam) DeepCopy() *ConfigParam {
if this == nil {
return nil
}
result := new(ConfigParam)
*result = *this
return result
}
type UsageType string
const (
RequestType UsageType = "RequestType"
ResponseType UsageType = "ResponseType"
)
type SearchConfigParam struct { type SearchConfigParam struct {
Search string `param:"search"` Search string `param:"search"`
DataId string `param:"dataId"` DataId string `param:"dataId"`

View File

@ -1,42 +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 vo
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestConfigParamDeepCopy(t *testing.T) {
t.Run("test configParam deep copy", func(t *testing.T) {
param := &ConfigParam{
DataId: "dataId",
Group: "",
Content: "common content",
UsageType: RequestType,
OnChange: func(namespace, group, dataId, data string) {
//do nothing
},
}
paramDeepCopied := param.DeepCopy()
assert.Equal(t, param.DataId, paramDeepCopied.DataId)
assert.Equal(t, param.Content, paramDeepCopied.Content)
assert.NotEqual(t, &param.OnChange, &paramDeepCopied.OnChange)
assert.NotEqual(t, &param, &paramDeepCopied)
})
}