Compare commits
81 Commits
Author | SHA1 | Date |
---|---|---|
|
e868a001ec | |
|
8bad3fed0f | |
|
6d3e89ff89 | |
|
ead2368c2f | |
|
eb3adf0f0a | |
|
2bc352f538 | |
|
a0fc325190 | |
|
5758f57b6b | |
|
310a82873f | |
|
f1545e0403 | |
|
741b6adca7 | |
|
98686b0b0a | |
|
9df154169b | |
|
476a2c4fa0 | |
|
3bbe1db11e | |
|
c925bcf60d | |
|
6f5bdc4cb6 | |
|
2f0372c760 | |
|
b098c04ffb | |
|
7c3b1dca16 | |
|
25436c0fcf | |
|
707bd574c7 | |
|
c3c6011815 | |
|
a0c848a550 | |
|
b2c297e409 | |
|
61ecaa8163 | |
|
083c02f5a6 | |
|
006f55d6e1 | |
|
2e0eb3c25e | |
|
7d85b858b4 | |
|
163ee14e36 | |
|
6763a4e271 | |
|
6f9348ae4c | |
|
169486a47a | |
|
690bd7beb7 | |
|
6dd8997f7a | |
|
389f6b6dbd | |
|
89c5ab6a74 | |
|
7178ed341c | |
|
81bf7d5a0f | |
|
8677a56468 | |
|
65e2c9d5e8 | |
|
5fedf574d9 | |
|
355c2fd062 | |
|
d934e30359 | |
|
28188c7967 | |
|
03026b7e01 | |
|
79bf755989 | |
|
4ac57745c5 | |
|
9b9ff77177 | |
|
6930f82f09 | |
|
4eb055946d | |
|
f657a269e7 | |
|
e4312deb60 | |
|
9653ddea22 | |
|
b51d87d10b | |
|
d4949e187b | |
|
bb9e2ce276 | |
|
b8f432f437 | |
|
6e50fb9d8d | |
|
626117a7ec | |
|
0d34e0a237 | |
|
e4f8b4e8a1 | |
|
90174c2023 | |
|
16975cb816 | |
|
a23dd577d8 | |
|
f113a815be | |
|
dfbe390d78 | |
|
c11cbcc5ca | |
|
e25bc91bb0 | |
|
43cf5aeb30 | |
|
859cdce5a7 | |
|
03bd50fb6e | |
|
73c4f3632d | |
|
802920dd32 | |
|
82a862a9a4 | |
|
e190e290f5 | |
|
8c02e5d388 | |
|
2f8d81c152 | |
|
4cddffb74f | |
|
63f4c7b8aa |
|
@ -14,7 +14,7 @@ jobs:
|
|||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- go_version: 1.15
|
||||
- go_version: 1.21
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.x
|
||||
|
|
|
@ -1,467 +1,233 @@
|
|||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: nacos_grpc_service.proto
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.7
|
||||
// protoc v5.29.3
|
||||
// source: api/proto/nacos_grpc_service.proto
|
||||
|
||||
package grpc
|
||||
package auto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
any "github.com/golang/protobuf/ptypes/any"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
anypb "google.golang.org/protobuf/types/known/anypb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Metadata struct {
|
||||
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
|
||||
ClientIp string `protobuf:"bytes,8,opt,name=clientIp,proto3" json:"clientIp,omitempty"`
|
||||
Headers map[string]string `protobuf:"bytes,7,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
|
||||
ClientIp string `protobuf:"bytes,8,opt,name=clientIp,proto3" json:"clientIp,omitempty"`
|
||||
Headers map[string]string `protobuf:"bytes,7,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (m *Metadata) Reset() { *m = Metadata{} }
|
||||
func (m *Metadata) String() string { return proto.CompactTextString(m) }
|
||||
func (*Metadata) ProtoMessage() {}
|
||||
func (x *Metadata) Reset() {
|
||||
*x = Metadata{}
|
||||
mi := &file_api_proto_nacos_grpc_service_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Metadata) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Metadata) ProtoMessage() {}
|
||||
|
||||
func (x *Metadata) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_proto_nacos_grpc_service_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Metadata.ProtoReflect.Descriptor instead.
|
||||
func (*Metadata) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f908b146bdb05ce9, []int{0}
|
||||
return file_api_proto_nacos_grpc_service_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (m *Metadata) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Metadata.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Metadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Metadata.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Metadata) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Metadata.Merge(m, src)
|
||||
}
|
||||
func (m *Metadata) XXX_Size() int {
|
||||
return xxx_messageInfo_Metadata.Size(m)
|
||||
}
|
||||
func (m *Metadata) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Metadata.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Metadata proto.InternalMessageInfo
|
||||
|
||||
func (m *Metadata) GetType() string {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
func (x *Metadata) GetType() string {
|
||||
if x != nil {
|
||||
return x.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Metadata) GetClientIp() string {
|
||||
if m != nil {
|
||||
return m.ClientIp
|
||||
func (x *Metadata) GetClientIp() string {
|
||||
if x != nil {
|
||||
return x.ClientIp
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Metadata) GetHeaders() map[string]string {
|
||||
if m != nil {
|
||||
return m.Headers
|
||||
func (x *Metadata) GetHeaders() map[string]string {
|
||||
if x != nil {
|
||||
return x.Headers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Payload struct {
|
||||
Metadata *Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"`
|
||||
Body *any.Any `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Metadata *Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"`
|
||||
Body *anypb.Any `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (m *Payload) Reset() { *m = Payload{} }
|
||||
func (m *Payload) String() string { return proto.CompactTextString(m) }
|
||||
func (*Payload) ProtoMessage() {}
|
||||
func (x *Payload) Reset() {
|
||||
*x = Payload{}
|
||||
mi := &file_api_proto_nacos_grpc_service_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Payload) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Payload) ProtoMessage() {}
|
||||
|
||||
func (x *Payload) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_api_proto_nacos_grpc_service_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Payload.ProtoReflect.Descriptor instead.
|
||||
func (*Payload) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f908b146bdb05ce9, []int{1}
|
||||
return file_api_proto_nacos_grpc_service_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (m *Payload) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Payload.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Payload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Payload.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Payload) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Payload.Merge(m, src)
|
||||
}
|
||||
func (m *Payload) XXX_Size() int {
|
||||
return xxx_messageInfo_Payload.Size(m)
|
||||
}
|
||||
func (m *Payload) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Payload.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Payload proto.InternalMessageInfo
|
||||
|
||||
func (m *Payload) GetMetadata() *Metadata {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
func (x *Payload) GetMetadata() *Metadata {
|
||||
if x != nil {
|
||||
return x.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Payload) GetBody() *any.Any {
|
||||
if m != nil {
|
||||
return m.Body
|
||||
func (x *Payload) GetBody() *anypb.Any {
|
||||
if x != nil {
|
||||
return x.Body
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Metadata)(nil), "Metadata")
|
||||
proto.RegisterMapType((map[string]string)(nil), "Metadata.HeadersEntry")
|
||||
proto.RegisterType((*Payload)(nil), "Payload")
|
||||
var File_api_proto_nacos_grpc_service_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_api_proto_nacos_grpc_service_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\"api/proto/nacos_grpc_service.proto\x1a\x19google/protobuf/any.proto\"\xa8\x01\n" +
|
||||
"\bMetadata\x12\x12\n" +
|
||||
"\x04type\x18\x03 \x01(\tR\x04type\x12\x1a\n" +
|
||||
"\bclientIp\x18\b \x01(\tR\bclientIp\x120\n" +
|
||||
"\aheaders\x18\a \x03(\v2\x16.Metadata.HeadersEntryR\aheaders\x1a:\n" +
|
||||
"\fHeadersEntry\x12\x10\n" +
|
||||
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"Z\n" +
|
||||
"\aPayload\x12%\n" +
|
||||
"\bmetadata\x18\x02 \x01(\v2\t.MetadataR\bmetadata\x12(\n" +
|
||||
"\x04body\x18\x03 \x01(\v2\x14.google.protobuf.AnyR\x04body28\n" +
|
||||
"\rRequestStream\x12'\n" +
|
||||
"\rrequestStream\x12\b.Payload\x1a\b.Payload\"\x000\x012*\n" +
|
||||
"\aRequest\x12\x1f\n" +
|
||||
"\arequest\x12\b.Payload\x1a\b.Payload\"\x002>\n" +
|
||||
"\x0fBiRequestStream\x12+\n" +
|
||||
"\x0frequestBiStream\x12\b.Payload\x1a\b.Payload\"\x00(\x010\x01B^\n" +
|
||||
"\x1fcom.alibaba.nacos.api.grpc.autoP\x01Z9github.com/nacos-group/nacos-sdk-go/v2/api/grpc/auto;autob\x06proto3"
|
||||
|
||||
var (
|
||||
file_api_proto_nacos_grpc_service_proto_rawDescOnce sync.Once
|
||||
file_api_proto_nacos_grpc_service_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_api_proto_nacos_grpc_service_proto_rawDescGZIP() []byte {
|
||||
file_api_proto_nacos_grpc_service_proto_rawDescOnce.Do(func() {
|
||||
file_api_proto_nacos_grpc_service_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_api_proto_nacos_grpc_service_proto_rawDesc), len(file_api_proto_nacos_grpc_service_proto_rawDesc)))
|
||||
})
|
||||
return file_api_proto_nacos_grpc_service_proto_rawDescData
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("nacos_grpc_service.proto", fileDescriptor_f908b146bdb05ce9) }
|
||||
|
||||
var fileDescriptor_f908b146bdb05ce9 = []byte{
|
||||
// 333 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x51, 0x4f, 0x4b, 0xeb, 0x40,
|
||||
0x10, 0x7f, 0xdb, 0xf6, 0xbd, 0xa4, 0xd3, 0x57, 0x2a, 0x4b, 0x91, 0x98, 0x4b, 0x4b, 0x45, 0x0c,
|
||||
0x0a, 0xdb, 0x12, 0x2f, 0xa5, 0x07, 0xc1, 0x82, 0xa0, 0x07, 0xa1, 0xc4, 0x9b, 0x97, 0x32, 0x49,
|
||||
0xd6, 0x1a, 0x4c, 0xb3, 0x71, 0xb3, 0x29, 0xec, 0x37, 0xf2, 0x63, 0x4a, 0x37, 0x69, 0xb0, 0x20,
|
||||
0xde, 0x66, 0x7e, 0x7f, 0xe6, 0xc7, 0xcc, 0x80, 0x93, 0x61, 0x24, 0x8a, 0xf5, 0x46, 0xe6, 0xd1,
|
||||
0xba, 0xe0, 0x72, 0x97, 0x44, 0x9c, 0xe5, 0x52, 0x28, 0xe1, 0x9e, 0x6d, 0x84, 0xd8, 0xa4, 0x7c,
|
||||
0x6a, 0xba, 0xb0, 0x7c, 0x9d, 0x62, 0xa6, 0x2b, 0x6a, 0xf2, 0x49, 0xc0, 0x7e, 0xe2, 0x0a, 0x63,
|
||||
0x54, 0x48, 0x29, 0x74, 0x94, 0xce, 0xb9, 0xd3, 0x1e, 0x13, 0xaf, 0x1b, 0x98, 0x9a, 0xba, 0x60,
|
||||
0x47, 0x69, 0xc2, 0x33, 0xf5, 0x98, 0x3b, 0xb6, 0xc1, 0x9b, 0x9e, 0xce, 0xc0, 0x7a, 0xe3, 0x18,
|
||||
0x73, 0x59, 0x38, 0xd6, 0xb8, 0xed, 0xf5, 0xfc, 0x53, 0x76, 0x98, 0xc5, 0x1e, 0x2a, 0xe2, 0x3e,
|
||||
0x53, 0x52, 0x07, 0x07, 0x99, 0xbb, 0x80, 0xff, 0xdf, 0x09, 0x7a, 0x02, 0xed, 0x77, 0xae, 0x1d,
|
||||
0x62, 0x06, 0xef, 0x4b, 0x3a, 0x84, 0xbf, 0x3b, 0x4c, 0x4b, 0xee, 0xb4, 0x0c, 0x56, 0x35, 0x8b,
|
||||
0xd6, 0x9c, 0x4c, 0x5e, 0xc0, 0x5a, 0xa1, 0x4e, 0x05, 0xc6, 0xf4, 0x02, 0xec, 0x6d, 0x1d, 0x64,
|
||||
0x74, 0x3d, 0xbf, 0xdb, 0x24, 0x07, 0x0d, 0x45, 0x3d, 0xe8, 0x84, 0x22, 0xd6, 0x66, 0x9f, 0x9e,
|
||||
0x3f, 0x64, 0xd5, 0x19, 0xd8, 0xe1, 0x0c, 0xec, 0x2e, 0xd3, 0x81, 0x51, 0xf8, 0x73, 0xe8, 0x07,
|
||||
0xfc, 0xa3, 0xe4, 0x85, 0x7a, 0x56, 0x92, 0xe3, 0x96, 0x5e, 0x42, 0x5f, 0x1e, 0x01, 0x36, 0xab,
|
||||
0xc3, 0xdd, 0xa6, 0x9a, 0xfc, 0x99, 0x11, 0xff, 0x0a, 0xac, 0xda, 0x49, 0x47, 0x60, 0xd5, 0x9e,
|
||||
0x9f, 0xd5, 0xfe, 0x2d, 0x0c, 0x96, 0xc9, 0x71, 0xce, 0x35, 0x0c, 0x6a, 0xcf, 0x32, 0xf9, 0x2d,
|
||||
0xc9, 0x23, 0x33, 0xb2, 0x3c, 0x87, 0x51, 0x24, 0xb6, 0x0c, 0xd3, 0x24, 0xc4, 0x10, 0x99, 0xf9,
|
||||
0x37, 0xc3, 0x3c, 0x61, 0xfb, 0x9f, 0x33, 0x2c, 0x95, 0x58, 0x91, 0xf0, 0x9f, 0x59, 0xef, 0xe6,
|
||||
0x2b, 0x00, 0x00, 0xff, 0xff, 0x0f, 0x9e, 0xc7, 0x2d, 0x0f, 0x02, 0x00, 0x00,
|
||||
var file_api_proto_nacos_grpc_service_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_api_proto_nacos_grpc_service_proto_goTypes = []any{
|
||||
(*Metadata)(nil), // 0: Metadata
|
||||
(*Payload)(nil), // 1: Payload
|
||||
nil, // 2: Metadata.HeadersEntry
|
||||
(*anypb.Any)(nil), // 3: google.protobuf.Any
|
||||
}
|
||||
var file_api_proto_nacos_grpc_service_proto_depIdxs = []int32{
|
||||
2, // 0: Metadata.headers:type_name -> Metadata.HeadersEntry
|
||||
0, // 1: Payload.metadata:type_name -> Metadata
|
||||
3, // 2: Payload.body:type_name -> google.protobuf.Any
|
||||
1, // 3: RequestStream.requestStream:input_type -> Payload
|
||||
1, // 4: Request.request:input_type -> Payload
|
||||
1, // 5: BiRequestStream.requestBiStream:input_type -> Payload
|
||||
1, // 6: RequestStream.requestStream:output_type -> Payload
|
||||
1, // 7: Request.request:output_type -> Payload
|
||||
1, // 8: BiRequestStream.requestBiStream:output_type -> Payload
|
||||
6, // [6:9] is the sub-list for method output_type
|
||||
3, // [3:6] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// RequestStreamClient is the client API for RequestStream service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type RequestStreamClient interface {
|
||||
// build a streamRequest
|
||||
RequestStream(ctx context.Context, in *Payload, opts ...grpc.CallOption) (RequestStream_RequestStreamClient, error)
|
||||
}
|
||||
|
||||
type requestStreamClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewRequestStreamClient(cc *grpc.ClientConn) RequestStreamClient {
|
||||
return &requestStreamClient{cc}
|
||||
}
|
||||
|
||||
func (c *requestStreamClient) RequestStream(ctx context.Context, in *Payload, opts ...grpc.CallOption) (RequestStream_RequestStreamClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_RequestStream_serviceDesc.Streams[0], "/RequestStream/requestStream", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func init() { file_api_proto_nacos_grpc_service_proto_init() }
|
||||
func file_api_proto_nacos_grpc_service_proto_init() {
|
||||
if File_api_proto_nacos_grpc_service_proto != nil {
|
||||
return
|
||||
}
|
||||
x := &requestStreamRequestStreamClient{stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type RequestStream_RequestStreamClient interface {
|
||||
Recv() (*Payload, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type requestStreamRequestStreamClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *requestStreamRequestStreamClient) Recv() (*Payload, error) {
|
||||
m := new(Payload)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// RequestStreamServer is the server API for RequestStream service.
|
||||
type RequestStreamServer interface {
|
||||
// build a streamRequest
|
||||
RequestStream(*Payload, RequestStream_RequestStreamServer) error
|
||||
}
|
||||
|
||||
// UnimplementedRequestStreamServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedRequestStreamServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedRequestStreamServer) RequestStream(req *Payload, srv RequestStream_RequestStreamServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method RequestStream not implemented")
|
||||
}
|
||||
|
||||
func RegisterRequestStreamServer(s *grpc.Server, srv RequestStreamServer) {
|
||||
s.RegisterService(&_RequestStream_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _RequestStream_RequestStream_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(Payload)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(RequestStreamServer).RequestStream(m, &requestStreamRequestStreamServer{stream})
|
||||
}
|
||||
|
||||
type RequestStream_RequestStreamServer interface {
|
||||
Send(*Payload) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type requestStreamRequestStreamServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *requestStreamRequestStreamServer) Send(m *Payload) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
var _RequestStream_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "RequestStream",
|
||||
HandlerType: (*RequestStreamServer)(nil),
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "requestStream",
|
||||
Handler: _RequestStream_RequestStream_Handler,
|
||||
ServerStreams: true,
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_api_proto_nacos_grpc_service_proto_rawDesc), len(file_api_proto_nacos_grpc_service_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 3,
|
||||
},
|
||||
},
|
||||
Metadata: "nacos_grpc_service.proto",
|
||||
}
|
||||
|
||||
// RequestClient is the client API for Request service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type RequestClient interface {
|
||||
// Sends a commonRequest
|
||||
Request(ctx context.Context, in *Payload, opts ...grpc.CallOption) (*Payload, error)
|
||||
}
|
||||
|
||||
type requestClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewRequestClient(cc *grpc.ClientConn) RequestClient {
|
||||
return &requestClient{cc}
|
||||
}
|
||||
|
||||
func (c *requestClient) Request(ctx context.Context, in *Payload, opts ...grpc.CallOption) (*Payload, error) {
|
||||
out := new(Payload)
|
||||
err := c.cc.Invoke(ctx, "/Request/request", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// RequestServer is the server API for Request service.
|
||||
type RequestServer interface {
|
||||
// Sends a commonRequest
|
||||
Request(context.Context, *Payload) (*Payload, error)
|
||||
}
|
||||
|
||||
// UnimplementedRequestServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedRequestServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedRequestServer) Request(ctx context.Context, req *Payload) (*Payload, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Request not implemented")
|
||||
}
|
||||
|
||||
func RegisterRequestServer(s *grpc.Server, srv RequestServer) {
|
||||
s.RegisterService(&_Request_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Request_Request_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Payload)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RequestServer).Request(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/Request/Request",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RequestServer).Request(ctx, req.(*Payload))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Request_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "Request",
|
||||
HandlerType: (*RequestServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "request",
|
||||
Handler: _Request_Request_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "nacos_grpc_service.proto",
|
||||
}
|
||||
|
||||
// BiRequestStreamClient is the client API for BiRequestStream service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type BiRequestStreamClient interface {
|
||||
// Sends a commonRequest
|
||||
RequestBiStream(ctx context.Context, opts ...grpc.CallOption) (BiRequestStream_RequestBiStreamClient, error)
|
||||
}
|
||||
|
||||
type biRequestStreamClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewBiRequestStreamClient(cc *grpc.ClientConn) BiRequestStreamClient {
|
||||
return &biRequestStreamClient{cc}
|
||||
}
|
||||
|
||||
func (c *biRequestStreamClient) RequestBiStream(ctx context.Context, opts ...grpc.CallOption) (BiRequestStream_RequestBiStreamClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_BiRequestStream_serviceDesc.Streams[0], "/BiRequestStream/requestBiStream", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &biRequestStreamRequestBiStreamClient{stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type BiRequestStream_RequestBiStreamClient interface {
|
||||
Send(*Payload) error
|
||||
Recv() (*Payload, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type biRequestStreamRequestBiStreamClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *biRequestStreamRequestBiStreamClient) Send(m *Payload) error {
|
||||
return x.ClientStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *biRequestStreamRequestBiStreamClient) Recv() (*Payload, error) {
|
||||
m := new(Payload)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// BiRequestStreamServer is the server API for BiRequestStream service.
|
||||
type BiRequestStreamServer interface {
|
||||
// Sends a commonRequest
|
||||
RequestBiStream(BiRequestStream_RequestBiStreamServer) error
|
||||
}
|
||||
|
||||
// UnimplementedBiRequestStreamServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedBiRequestStreamServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedBiRequestStreamServer) RequestBiStream(srv BiRequestStream_RequestBiStreamServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method RequestBiStream not implemented")
|
||||
}
|
||||
|
||||
func RegisterBiRequestStreamServer(s *grpc.Server, srv BiRequestStreamServer) {
|
||||
s.RegisterService(&_BiRequestStream_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _BiRequestStream_RequestBiStream_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(BiRequestStreamServer).RequestBiStream(&biRequestStreamRequestBiStreamServer{stream})
|
||||
}
|
||||
|
||||
type BiRequestStream_RequestBiStreamServer interface {
|
||||
Send(*Payload) error
|
||||
Recv() (*Payload, error)
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type biRequestStreamRequestBiStreamServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *biRequestStreamRequestBiStreamServer) Send(m *Payload) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *biRequestStreamRequestBiStreamServer) Recv() (*Payload, error) {
|
||||
m := new(Payload)
|
||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
var _BiRequestStream_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "BiRequestStream",
|
||||
HandlerType: (*BiRequestStreamServer)(nil),
|
||||
Methods: []grpc.MethodDesc{},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "requestBiStream",
|
||||
Handler: _BiRequestStream_RequestBiStream_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "nacos_grpc_service.proto",
|
||||
GoTypes: file_api_proto_nacos_grpc_service_proto_goTypes,
|
||||
DependencyIndexes: file_api_proto_nacos_grpc_service_proto_depIdxs,
|
||||
MessageInfos: file_api_proto_nacos_grpc_service_proto_msgTypes,
|
||||
}.Build()
|
||||
File_api_proto_nacos_grpc_service_proto = out.File
|
||||
file_api_proto_nacos_grpc_service_proto_goTypes = nil
|
||||
file_api_proto_nacos_grpc_service_proto_depIdxs = nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,343 @@
|
|||
//
|
||||
// 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",
|
||||
}
|
|
@ -21,6 +21,8 @@ import "google/protobuf/any.proto";
|
|||
|
||||
option java_multiple_files = true;
|
||||
option java_package = "com.alibaba.nacos.api.grpc.auto";
|
||||
option go_package = "github.com/nacos-group/nacos-sdk-go/v2/api/grpc/auto;auto";
|
||||
|
||||
|
||||
message Metadata {
|
||||
string type = 3;
|
||||
|
|
|
@ -296,7 +296,7 @@ func (m ConcurrentMap) Keys() []string {
|
|||
return keys
|
||||
}
|
||||
|
||||
//Reviles ConcurrentMap "private" variables to json marshal.
|
||||
// Reviles ConcurrentMap "private" variables to json marshal.
|
||||
func (m ConcurrentMap) MarshalJSON() ([]byte, error) {
|
||||
// Create a temporary map, which will hold all item spread across shards.
|
||||
tmp := make(map[string]interface{})
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
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"
|
||||
)
|
|
@ -19,11 +19,11 @@ package cache
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/file"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
|
@ -31,10 +31,30 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func GetFileName(cacheKey string, cacheDir string) string {
|
||||
var (
|
||||
fileNotExistError = errors.New("file not exist")
|
||||
)
|
||||
|
||||
func GetFileName(cacheKey, cacheDir string) string {
|
||||
return cacheDir + string(os.PathSeparator) + cacheKey
|
||||
}
|
||||
|
||||
func GetEncryptedDataKeyDir(cacheDir string) string {
|
||||
return cacheDir + string(os.PathSeparator) + ENCRYPTED_DATA_KEY_FILE_NAME
|
||||
}
|
||||
|
||||
func GetConfigEncryptedDataKeyFileName(cacheKey, cacheDir string) string {
|
||||
return GetEncryptedDataKeyDir(cacheDir) + string(os.PathSeparator) + cacheKey
|
||||
}
|
||||
|
||||
func GetConfigFailOverContentFileName(cacheKey, cacheDir string) string {
|
||||
return GetFileName(cacheKey, cacheDir) + FAILOVER_FILE_SUFFIX
|
||||
}
|
||||
|
||||
func GetConfigFailOverEncryptedDataKeyFileName(cacheKey, cacheDir string) string {
|
||||
return GetConfigEncryptedDataKeyFileName(cacheKey, cacheDir) + FAILOVER_FILE_SUFFIX
|
||||
}
|
||||
|
||||
func WriteServicesToFile(service *model.Service, cacheKey, cacheDir string) {
|
||||
err := file.MkdirIfNecessary(cacheDir)
|
||||
if err != nil {
|
||||
|
@ -43,14 +63,14 @@ func WriteServicesToFile(service *model.Service, cacheKey, cacheDir string) {
|
|||
}
|
||||
bytes, _ := json.Marshal(service)
|
||||
domFileName := GetFileName(cacheKey, cacheDir)
|
||||
err = ioutil.WriteFile(domFileName, bytes, 0666)
|
||||
err = os.WriteFile(domFileName, bytes, 0666)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to write name cache:%s ,value:%s ,err:%v", domFileName, string(bytes), err)
|
||||
}
|
||||
}
|
||||
|
||||
func ReadServicesFromFile(cacheDir string) map[string]model.Service {
|
||||
files, err := ioutil.ReadDir(cacheDir)
|
||||
files, err := os.ReadDir(cacheDir)
|
||||
if err != nil {
|
||||
logger.Errorf("read cacheDir:%s failed!err:%+v", cacheDir, err)
|
||||
return nil
|
||||
|
@ -58,9 +78,9 @@ func ReadServicesFromFile(cacheDir string) map[string]model.Service {
|
|||
serviceMap := map[string]model.Service{}
|
||||
for _, f := range files {
|
||||
fileName := GetFileName(f.Name(), cacheDir)
|
||||
b, err := ioutil.ReadFile(fileName)
|
||||
b, err := os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to read name cache file:%s,err:%+v ", fileName, err)
|
||||
logger.Errorf("failed to read name cache file:%s,err:%v ", fileName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -78,42 +98,105 @@ func ReadServicesFromFile(cacheDir string) map[string]model.Service {
|
|||
return serviceMap
|
||||
}
|
||||
|
||||
func WriteConfigToFile(cacheKey string, cacheDir string, content string) {
|
||||
file.MkdirIfNecessary(cacheDir)
|
||||
fileName := GetFileName(cacheKey, cacheDir)
|
||||
if len(content) == 0 {
|
||||
func WriteConfigToFile(cacheKey string, cacheDir string, content string) error {
|
||||
err := file.MkdirIfNecessary(cacheDir)
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("make dir failed, dir path %s, err: %v.", cacheDir, err)
|
||||
logger.Error(errMsg)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
err = writeConfigToFile(GetFileName(cacheKey, cacheDir), content, ConfigContent)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteEncryptedDataKeyToFile(cacheKey string, cacheDir string, content string) error {
|
||||
err := file.MkdirIfNecessary(GetEncryptedDataKeyDir(cacheDir))
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("make dir failed, dir path %s, err: %v.", cacheDir, err)
|
||||
logger.Error(errMsg)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
err = writeConfigToFile(GetConfigEncryptedDataKeyFileName(cacheKey, cacheDir), content, ConfigEncryptedDataKey)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeConfigToFile(fileName string, content string, fileType ConfigCachedFileType) error {
|
||||
if len(strings.TrimSpace(content)) == 0 {
|
||||
// delete config snapshot
|
||||
if err := os.Remove(fileName); err != nil {
|
||||
logger.Errorf("failed to delete config file,cache:%s ,value:%s ,err:%+v", fileName, content, err)
|
||||
if err != syscall.ENOENT {
|
||||
logger.Debug(fmt.Sprintf("no need to delete %s cache file, file path %s, file doesn't exist.", fileType, fileName))
|
||||
return nil
|
||||
}
|
||||
errMsg := fmt.Sprintf("failed to delete %s cache file, file path %s, err:%v", fileType, fileName, err)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
return
|
||||
}
|
||||
err := ioutil.WriteFile(fileName, []byte(content), 0666)
|
||||
err := os.WriteFile(fileName, []byte(content), 0666)
|
||||
if err != nil {
|
||||
logger.Errorf("failed to write config cache:%s ,value:%s ,err:%+v", fileName, content, err)
|
||||
errMsg := fmt.Sprintf("failed to write %s cache file, file name: %s, value: %s, err:%v", fileType, 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) {
|
||||
fileName := GetFileName(cacheKey, cacheDir)
|
||||
b, err := ioutil.ReadFile(fileName)
|
||||
return readConfigFromFile(GetFileName(cacheKey, cacheDir), ConfigEncryptedDataKey)
|
||||
}
|
||||
|
||||
func readConfigFromFile(fileName string, fileType ConfigCachedFileType) (string, error) {
|
||||
if !file.IsExistFile(fileName) {
|
||||
errMsg := fmt.Sprintf("read cache file %s failed. cause file doesn't exist, file path: %s.", fileType, fileName)
|
||||
return "", errors.Wrap(fileNotExistError, errMsg)
|
||||
}
|
||||
b, err := os.ReadFile(fileName)
|
||||
if err != nil {
|
||||
return "", errors.New(fmt.Sprintf("failed to read config cache file:%s,err:%+v ", fileName, err))
|
||||
errMsg := fmt.Sprintf("get %s from cache failed, filePath:%s, error:%v ", fileType, fileName, err)
|
||||
return "", errors.New(errMsg)
|
||||
}
|
||||
return string(b), nil
|
||||
}
|
||||
|
||||
// GetFailover , get failover content
|
||||
func GetFailover(key, dir string) string {
|
||||
filePath := dir + string(os.PathSeparator) + key + constant.FAILOVER_FILE_SUFFIX
|
||||
filePath := GetConfigFailOverContentFileName(key, dir)
|
||||
return getFailOverConfig(filePath, ConfigContent)
|
||||
}
|
||||
|
||||
func GetFailoverEncryptedDataKey(key, dir string) string {
|
||||
filePath := GetConfigFailOverEncryptedDataKeyFileName(key, dir)
|
||||
return getFailOverConfig(filePath, ConfigEncryptedDataKey)
|
||||
}
|
||||
|
||||
func getFailOverConfig(filePath string, fileType ConfigCachedFileType) string {
|
||||
if !file.IsExistFile(filePath) {
|
||||
errMsg := fmt.Sprintf("read %s failed. cause file doesn't exist, file path: %s.", fileType, filePath)
|
||||
logger.Warn(errMsg)
|
||||
return ""
|
||||
}
|
||||
logger.GetLogger().Warn(fmt.Sprintf("reading failover content from path:%s", filePath))
|
||||
fileContent, err := ioutil.ReadFile(filePath)
|
||||
logger.Warnf("reading failover %s from path:%s", fileType, filePath)
|
||||
fileContent, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
logger.GetLogger().Error(fmt.Sprintf("fail to read failover content from %s", filePath))
|
||||
logger.Errorf("fail to read failover %s from %s", fileType, filePath)
|
||||
return ""
|
||||
}
|
||||
return string(fileContent)
|
||||
|
|
|
@ -2,8 +2,10 @@ package cache
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -11,9 +13,96 @@ import (
|
|||
"github.com/nacos-group/nacos-sdk-go/v2/common/file"
|
||||
)
|
||||
|
||||
var (
|
||||
dir = file.GetCurrentPath()
|
||||
group = "FILE_GROUP"
|
||||
ns = "chasu"
|
||||
)
|
||||
|
||||
func TestWriteAndGetConfigToFile(t *testing.T) {
|
||||
dataIdSuffix := strconv.Itoa(rand.Intn(1000))
|
||||
t.Run("write and get config content", func(t *testing.T) {
|
||||
dataId := "config_content" + dataIdSuffix
|
||||
cacheKey := util.GetConfigCacheKey(dataId, group, ns)
|
||||
configContent := "config content"
|
||||
|
||||
err := WriteConfigToFile(cacheKey, dir, "")
|
||||
assert.Nil(t, err)
|
||||
|
||||
configFromFile, err := ReadConfigFromFile(cacheKey, dir)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, configFromFile, "")
|
||||
|
||||
err = WriteConfigToFile(cacheKey, dir, configContent)
|
||||
assert.Nil(t, err)
|
||||
|
||||
fromFile, err := ReadConfigFromFile(cacheKey, dir)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, fromFile, configContent)
|
||||
|
||||
err = WriteConfigToFile(cacheKey, dir, "")
|
||||
assert.Nil(t, err)
|
||||
|
||||
configFromFile, err = ReadConfigFromFile(cacheKey, dir)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, configFromFile, "")
|
||||
})
|
||||
|
||||
t.Run("write and get config encryptedDataKey", func(t *testing.T) {
|
||||
dataId := "config_encryptedDataKey" + dataIdSuffix
|
||||
cacheKey := util.GetConfigCacheKey(dataId, group, ns)
|
||||
configContent := "config encrypted data key"
|
||||
|
||||
err := WriteEncryptedDataKeyToFile(cacheKey, dir, "")
|
||||
assert.Nil(t, err)
|
||||
|
||||
configFromFile, err := ReadEncryptedDataKeyFromFile(cacheKey, dir)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, configFromFile, "")
|
||||
|
||||
err = WriteEncryptedDataKeyToFile(cacheKey, dir, configContent)
|
||||
assert.Nil(t, err)
|
||||
|
||||
fromFile, err := ReadEncryptedDataKeyFromFile(cacheKey, dir)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, fromFile, configContent)
|
||||
|
||||
err = WriteEncryptedDataKeyToFile(cacheKey, dir, "")
|
||||
assert.Nil(t, err)
|
||||
|
||||
configFromFile, err = ReadEncryptedDataKeyFromFile(cacheKey, dir)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, configFromFile, "")
|
||||
})
|
||||
t.Run("double write config file", func(t *testing.T) {
|
||||
dataId := "config_encryptedDataKey" + dataIdSuffix
|
||||
cacheKey := util.GetConfigCacheKey(dataId, group, ns)
|
||||
configContent := "config encrypted data key"
|
||||
|
||||
err := WriteConfigToFile(cacheKey, dir, configContent)
|
||||
assert.Nil(t, err)
|
||||
|
||||
err = WriteConfigToFile(cacheKey, dir, configContent)
|
||||
assert.Nil(t, err)
|
||||
|
||||
fromFile, err := ReadConfigFromFile(cacheKey, dir)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, fromFile, configContent)
|
||||
})
|
||||
t.Run("read doesn't existed config file", func(t *testing.T) {
|
||||
dataId := "config_encryptedDataKey" + dataIdSuffix + strconv.Itoa(rand.Intn(1000))
|
||||
cacheKey := util.GetConfigCacheKey(dataId, group, ns)
|
||||
|
||||
_, err := ReadConfigFromFile(cacheKey, dir)
|
||||
assert.NotNil(t, err)
|
||||
|
||||
_, err = ReadEncryptedDataKeyFromFile(cacheKey, dir)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetFailover(t *testing.T) {
|
||||
cacheKey := "test_failOver"
|
||||
dir := file.GetCurrentPath()
|
||||
fileContent := "test_failover"
|
||||
t.Run("writeContent", func(t *testing.T) {
|
||||
filepath := dir + string(os.PathSeparator) + cacheKey + "_failover"
|
||||
|
@ -34,5 +123,5 @@ func TestGetFailover(t *testing.T) {
|
|||
|
||||
// write file content
|
||||
func writeFileContent(filepath, content string) error {
|
||||
return ioutil.WriteFile(filepath, []byte(content), 0666)
|
||||
return os.WriteFile(filepath, []byte(content), 0666)
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ func CreateConfigClient(properties map[string]interface{}) (iClient config_clien
|
|||
return NewConfigClient(param)
|
||||
}
|
||||
|
||||
//CreateNamingClient use to create a nacos naming client
|
||||
// CreateNamingClient use to create a nacos naming client
|
||||
func CreateNamingClient(properties map[string]interface{}) (iClient naming_client.INamingClient, err error) {
|
||||
param := getConfigParam(properties)
|
||||
return NewNamingClient(param)
|
||||
|
@ -45,7 +45,7 @@ func NewConfigClient(param vo.NacosClientParam) (iClient config_client.IConfigCl
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
config, err := config_client.NewConfigClient(nacosClient)
|
||||
config, err := config_client.NewConfigClientWithRamCredentialProvider(nacosClient, param.RamCredentialProvider)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ func NewNamingClient(param vo.NacosClientParam) (iClient naming_client.INamingCl
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
naming, err := naming_client.NewNamingClient(nacosClient)
|
||||
naming, err := naming_client.NewNamingClientWithRamCredentialProvider(nacosClient, param.RamCredentialProvider)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -104,6 +104,14 @@ func setConfig(param vo.NacosClientParam) (iClient nacos_client.INacosClient, er
|
|||
}
|
||||
_ = client.SetServerConfig(nil)
|
||||
} else {
|
||||
for i := range param.ServerConfigs {
|
||||
if param.ServerConfigs[i].Port == 0 {
|
||||
param.ServerConfigs[i].Port = 8848
|
||||
}
|
||||
if param.ServerConfigs[i].GrpcPort == 0 {
|
||||
param.ServerConfigs[i].GrpcPort = param.ServerConfigs[i].Port + constant.RpcPortOffset
|
||||
}
|
||||
}
|
||||
err = client.SetServerConfig(param.ServerConfigs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -19,21 +19,19 @@ package config_client
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/monitor"
|
||||
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/kms"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
nacos_inner_encryption "github.com/nacos-group/nacos-sdk-go/v2/common/encryption"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/filter"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/monitor"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/nacos_error"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
|
||||
|
@ -41,6 +39,7 @@ import (
|
|||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -52,15 +51,16 @@ type ConfigClient struct {
|
|||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
nacos_client.INacosClient
|
||||
kmsClient *kms.Client
|
||||
localConfigs []vo.ConfigParam
|
||||
mutex sync.Mutex
|
||||
configProxy IConfigProxy
|
||||
configCacheDir string
|
||||
lastAllSyncTime time.Time
|
||||
cacheMap cache.ConcurrentMap
|
||||
uid string
|
||||
listenExecute chan struct{}
|
||||
configFilterChainManager filter.IConfigFilterChain
|
||||
localConfigs []vo.ConfigParam
|
||||
mutex sync.Mutex
|
||||
configProxy IConfigProxy
|
||||
configCacheDir string
|
||||
lastAllSyncTime time.Time
|
||||
cacheMap cache.ConcurrentMap
|
||||
uid string
|
||||
listenExecute chan struct{}
|
||||
isClosed bool
|
||||
}
|
||||
|
||||
type cacheData struct {
|
||||
|
@ -69,6 +69,7 @@ type cacheData struct {
|
|||
group string
|
||||
content string
|
||||
contentType string
|
||||
encryptedDataKey string
|
||||
tenant string
|
||||
cacheDataListener *cacheDataListener
|
||||
md5 string
|
||||
|
@ -85,17 +86,24 @@ type cacheDataListener struct {
|
|||
|
||||
func (cacheData *cacheData) executeListener() {
|
||||
cacheData.cacheDataListener.lastMd5 = cacheData.md5
|
||||
cacheData.configClient.cacheMap.Set(util.GetConfigCacheKey(cacheData.dataId, cacheData.group, cacheData.tenant), *cacheData)
|
||||
|
||||
decryptedContent, err := cacheData.configClient.decrypt(cacheData.dataId, cacheData.content)
|
||||
if err != nil {
|
||||
logger.Errorf("decrypt content fail ,dataId=%s,group=%s,tenant=%s,err:%+v ", cacheData.dataId,
|
||||
param := &vo.ConfigParam{
|
||||
DataId: cacheData.dataId,
|
||||
Content: cacheData.content,
|
||||
EncryptedDataKey: cacheData.encryptedDataKey,
|
||||
UsageType: vo.ResponseType,
|
||||
}
|
||||
if err := cacheData.configClient.configFilterChainManager.DoFilters(param); err != nil {
|
||||
logger.Errorf("do filters failed ,dataId=%s,group=%s,tenant=%s,err:%+v ", cacheData.dataId,
|
||||
cacheData.group, cacheData.tenant, err)
|
||||
return
|
||||
}
|
||||
decryptedContent := param.Content
|
||||
go cacheData.cacheDataListener.listener(cacheData.tenant, cacheData.group, cacheData.dataId, decryptedContent)
|
||||
}
|
||||
|
||||
func NewConfigClient(nc nacos_client.INacosClient) (*ConfigClient, error) {
|
||||
func NewConfigClientWithRamCredentialProvider(nc nacos_client.INacosClient, provider security.RamCredentialProvider) (*ConfigClient, error) {
|
||||
config := &ConfigClient{}
|
||||
config.ctx, config.cancel = context.WithCancel(context.Background())
|
||||
config.INacosClient = nc
|
||||
|
@ -118,84 +126,62 @@ func NewConfigClient(nc nacos_client.INacosClient) (*ConfigClient, error) {
|
|||
clientConfig.CacheDir = clientConfig.CacheDir + string(os.PathSeparator) + "config"
|
||||
config.configCacheDir = clientConfig.CacheDir
|
||||
|
||||
if config.configProxy, err = NewConfigProxy(config.ctx, serverConfig, clientConfig, httpAgent); err != nil {
|
||||
if config.configProxy, err = NewConfigProxyWithRamCredentialProvider(config.ctx, serverConfig, clientConfig, httpAgent, provider); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.configFilterChainManager = filter.NewConfigFilterChainManager()
|
||||
|
||||
if clientConfig.OpenKMS {
|
||||
kmsClient, err := kms.NewClientWithAccessKey(clientConfig.RegionId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
kmsEncryptionHandler := nacos_inner_encryption.NewKmsHandler()
|
||||
nacos_inner_encryption.RegisterConfigEncryptionKmsPlugins(kmsEncryptionHandler, clientConfig)
|
||||
encryptionFilter := filter.NewDefaultConfigEncryptionFilter(kmsEncryptionHandler)
|
||||
err := filter.RegisterConfigFilterToChain(config.configFilterChainManager, encryptionFilter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
logger.Error(err)
|
||||
}
|
||||
config.kmsClient = kmsClient
|
||||
}
|
||||
|
||||
uid, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.uid = uid.String()
|
||||
|
||||
config.cacheMap = cache.NewConcurrentMap()
|
||||
// maximum buffered queue to prevent chan deadlocks during frequent configuration file updates
|
||||
config.listenExecute = make(chan struct{}, math.MaxInt64)
|
||||
|
||||
config.listenExecute = make(chan struct{})
|
||||
config.startInternal()
|
||||
|
||||
return config, err
|
||||
}
|
||||
|
||||
func NewConfigClient(nc nacos_client.INacosClient) (*ConfigClient, error) {
|
||||
return NewConfigClientWithRamCredentialProvider(nc, nil)
|
||||
}
|
||||
|
||||
func initLogger(clientConfig constant.ClientConfig) error {
|
||||
return logger.InitLogger(logger.BuildLoggerConfig(clientConfig))
|
||||
}
|
||||
|
||||
func (client *ConfigClient) GetConfig(param vo.ConfigParam) (content string, err error) {
|
||||
content, err = client.getConfigInner(param)
|
||||
|
||||
content, encryptedDataKey, err := client.getConfigInner(param)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return client.decrypt(param.DataId, content)
|
||||
}
|
||||
|
||||
func (client *ConfigClient) decrypt(dataId, content string) (string, error) {
|
||||
if client.kmsClient != nil && strings.HasPrefix(dataId, "cipher-") {
|
||||
request := kms.CreateDecryptRequest()
|
||||
request.Method = "POST"
|
||||
request.Scheme = "https"
|
||||
request.AcceptFormat = "json"
|
||||
request.CiphertextBlob = content
|
||||
response, err := client.kmsClient.Decrypt(request)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("kms decrypt failed: %v", err)
|
||||
}
|
||||
content = response.Plaintext
|
||||
deepCopyParam := param.DeepCopy()
|
||||
deepCopyParam.EncryptedDataKey = encryptedDataKey
|
||||
deepCopyParam.Content = content
|
||||
deepCopyParam.UsageType = vo.ResponseType
|
||||
if err = client.configFilterChainManager.DoFilters(deepCopyParam); err != nil {
|
||||
return "", err
|
||||
}
|
||||
content = deepCopyParam.Content
|
||||
return content, nil
|
||||
}
|
||||
|
||||
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) {
|
||||
func (client *ConfigClient) getConfigInner(param vo.ConfigParam) (content, encryptedDataKey string, err error) {
|
||||
if len(param.DataId) <= 0 {
|
||||
err = errors.New("[client.GetConfig] param.dataId can not be empty")
|
||||
return "", err
|
||||
return "", "", err
|
||||
}
|
||||
if len(param.Group) <= 0 {
|
||||
param.Group = constant.DEFAULT_GROUP
|
||||
|
@ -205,21 +191,44 @@ func (client *ConfigClient) getConfigInner(param vo.ConfigParam) (content string
|
|||
cacheKey := util.GetConfigCacheKey(param.DataId, param.Group, clientConfig.NamespaceId)
|
||||
content = cache.GetFailover(cacheKey, client.configCacheDir)
|
||||
if len(content) > 0 {
|
||||
logger.GetLogger().Warn(fmt.Sprintf("%s %s %s is using failover content!", clientConfig.NamespaceId, param.Group, param.DataId))
|
||||
return content, nil
|
||||
logger.Warnf("%s %s %s is using failover content!", clientConfig.NamespaceId, param.Group, param.DataId)
|
||||
encryptedDataKey = cache.GetFailoverEncryptedDataKey(cacheKey, client.configCacheDir)
|
||||
return content, encryptedDataKey, nil
|
||||
}
|
||||
response, err := client.configProxy.queryConfig(param.DataId, param.Group, clientConfig.NamespaceId,
|
||||
clientConfig.TimeoutMs, false, client)
|
||||
if err != nil {
|
||||
logger.Infof("get config from server error:%+v ", err)
|
||||
content, err = cache.ReadConfigFromFile(cacheKey, client.configCacheDir)
|
||||
if err != nil {
|
||||
logger.Errorf("get config from cache error:%+v ", err)
|
||||
return "", errors.New("read config from both server and cache fail")
|
||||
logger.Errorf("get config from server error:%v, dataId=%s, group=%s, namespaceId=%s", err,
|
||||
param.DataId, param.Group, clientConfig.NamespaceId)
|
||||
|
||||
if clientConfig.DisableUseSnapShot {
|
||||
return "", "", errors.Errorf("get config from remote nacos server fail, and is not allowed to read local file, err:%v", err)
|
||||
}
|
||||
return content, nil
|
||||
|
||||
cacheContent, cacheErr := cache.ReadConfigFromFile(cacheKey, client.configCacheDir)
|
||||
if cacheErr != nil {
|
||||
return "", "", errors.Errorf("read config from both server and cache fail, err=%v,dataId=%s, group=%s, namespaceId=%s",
|
||||
cacheErr, param.DataId, param.Group, clientConfig.NamespaceId)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(param.DataId, nacos_inner_encryption.CipherPrefix) {
|
||||
return cacheContent, "", nil
|
||||
}
|
||||
encryptedDataKey, cacheErr = cache.ReadEncryptedDataKeyFromFile(cacheKey, client.configCacheDir)
|
||||
if cacheErr != nil {
|
||||
return "", "", errors.Errorf("read encryptedDataKey from server and cache fail, err=%v,dataId=%s, group=%s, namespaceId=%s",
|
||||
cacheErr, param.DataId, param.Group, clientConfig.NamespaceId)
|
||||
}
|
||||
|
||||
logger.Warnf("read config from cache success, dataId=%s, group=%s, namespaceId=%s", param.DataId, param.Group, clientConfig.NamespaceId)
|
||||
return cacheContent, encryptedDataKey, nil
|
||||
}
|
||||
return response.Content, nil
|
||||
if response != nil && response.Response != nil && !response.IsSuccess() {
|
||||
return response.Content, response.EncryptedDataKey, errors.New(response.GetMessage())
|
||||
}
|
||||
encryptedDataKey = response.EncryptedDataKey
|
||||
content = response.Content
|
||||
return content, encryptedDataKey, nil
|
||||
}
|
||||
|
||||
func (client *ConfigClient) PublishConfig(param vo.ConfigParam) (published bool, err error) {
|
||||
|
@ -235,21 +244,28 @@ func (client *ConfigClient) PublishConfig(param vo.ConfigParam) (published bool,
|
|||
if len(param.Group) <= 0 {
|
||||
param.Group = constant.DEFAULT_GROUP
|
||||
}
|
||||
if param.Content, err = client.encrypt(param.DataId, param.Content); err != nil {
|
||||
return
|
||||
|
||||
param.UsageType = vo.RequestType
|
||||
if err = client.configFilterChainManager.DoFilters(¶m); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
clientConfig, _ := client.GetClientConfig()
|
||||
request := rpc_request.NewConfigPublishRequest(param.Group, param.DataId, clientConfig.NamespaceId, param.Content, param.CasMd5)
|
||||
request.AdditionMap["tag"] = param.Tag
|
||||
request.AdditionMap["config_tags"] = param.ConfigTags
|
||||
request.AdditionMap["appName"] = param.AppName
|
||||
request.AdditionMap["betaIps"] = param.BetaIps
|
||||
request.AdditionMap["type"] = param.Type
|
||||
request.AdditionMap["src_user"] = param.SrcUser
|
||||
request.AdditionMap["encryptedDataKey"] = param.EncryptedDataKey
|
||||
rpcClient := client.configProxy.getRpcClient(client)
|
||||
response, err := client.configProxy.requestProxy(rpcClient, request, constant.DEFAULT_TIMEOUT_MILLS)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if response != nil {
|
||||
return response.IsSuccess(), err
|
||||
return client.buildResponse(response)
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
@ -268,8 +284,11 @@ func (client *ConfigClient) DeleteConfig(param vo.ConfigParam) (deleted bool, er
|
|||
request := rpc_request.NewConfigRemoveRequest(param.Group, param.DataId, clientConfig.NamespaceId)
|
||||
rpcClient := client.configProxy.getRpcClient(client)
|
||||
response, err := client.configProxy.requestProxy(rpcClient, request, constant.DEFAULT_TIMEOUT_MILLS)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if response != nil {
|
||||
return response.IsSuccess(), err
|
||||
return client.buildResponse(response)
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
@ -302,16 +321,20 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
|
|||
}
|
||||
|
||||
key := util.GetConfigCacheKey(param.DataId, param.Group, clientConfig.NamespaceId)
|
||||
var cData *cacheData
|
||||
var cData cacheData
|
||||
if v, ok := client.cacheMap.Get(key); ok {
|
||||
cData = v.(*cacheData)
|
||||
cData = v.(cacheData)
|
||||
cData.isInitializing = true
|
||||
} else {
|
||||
var (
|
||||
content string
|
||||
md5Str string
|
||||
content string
|
||||
md5Str string
|
||||
innerErr error
|
||||
)
|
||||
content, _ = cache.ReadConfigFromFile(key, client.configCacheDir)
|
||||
if content, innerErr = cache.ReadConfigFromFile(key, client.configCacheDir); innerErr != nil {
|
||||
logger.Warn(innerErr)
|
||||
}
|
||||
encryptedDataKey, _ := cache.ReadEncryptedDataKeyFromFile(key, client.configCacheDir)
|
||||
if len(content) > 0 {
|
||||
md5Str = util.Md5(content)
|
||||
}
|
||||
|
@ -320,7 +343,7 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
|
|||
lastMd5: md5Str,
|
||||
}
|
||||
|
||||
cData = &cacheData{
|
||||
cData = cacheData{
|
||||
isInitializing: true,
|
||||
dataId: param.DataId,
|
||||
group: param.Group,
|
||||
|
@ -328,6 +351,7 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
|
|||
content: content,
|
||||
md5: md5Str,
|
||||
cacheDataListener: listener,
|
||||
encryptedDataKey: encryptedDataKey,
|
||||
taskId: client.cacheMap.Count() / perTaskConfigSize,
|
||||
configClient: client,
|
||||
}
|
||||
|
@ -341,8 +365,15 @@ func (client *ConfigClient) SearchConfig(param vo.SearchConfigParam) (*model.Con
|
|||
}
|
||||
|
||||
func (client *ConfigClient) CloseClient() {
|
||||
client.mutex.Lock()
|
||||
defer client.mutex.Unlock()
|
||||
|
||||
if client.isClosed {
|
||||
return
|
||||
}
|
||||
client.configProxy.getRpcClient(client).Shutdown()
|
||||
client.cancel()
|
||||
client.isClosed = true
|
||||
}
|
||||
|
||||
func (client *ConfigClient) searchConfigInner(param vo.SearchConfigParam) (*model.ConfigPage, error) {
|
||||
|
@ -392,78 +423,74 @@ func (client *ConfigClient) startInternal() {
|
|||
}
|
||||
|
||||
func (client *ConfigClient) executeConfigListen() {
|
||||
listenCachesMap := make(map[int][]*cacheData, 16)
|
||||
needAllSync := time.Since(client.lastAllSyncTime) >= constant.ALL_SYNC_INTERNAL
|
||||
for _, v := range client.cacheMap.Items() {
|
||||
cache, ok := v.(*cacheData)
|
||||
var (
|
||||
needAllSync = time.Since(client.lastAllSyncTime) >= constant.ALL_SYNC_INTERNAL
|
||||
hasChangedKeys = false
|
||||
)
|
||||
|
||||
listenTaskMap := client.buildListenTask(needAllSync)
|
||||
if len(listenTaskMap) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for taskId, caches := range listenTaskMap {
|
||||
request := buildConfigBatchListenRequest(caches)
|
||||
rpcClient := client.configProxy.createRpcClient(client.ctx, fmt.Sprintf("%d", taskId), client)
|
||||
iResponse, err := client.configProxy.requestProxy(rpcClient, request, 3000)
|
||||
if err != nil {
|
||||
logger.Warnf("ConfigBatchListenRequest failure, err:%v", err)
|
||||
continue
|
||||
}
|
||||
if iResponse == nil {
|
||||
logger.Warnf("ConfigBatchListenRequest failure, response is nil")
|
||||
continue
|
||||
}
|
||||
if !iResponse.IsSuccess() {
|
||||
logger.Warnf("ConfigBatchListenRequest failure, error code:%d", iResponse.GetErrorCode())
|
||||
continue
|
||||
}
|
||||
response, ok := iResponse.(*rpc_response.ConfigChangeBatchListenResponse)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if cache.isSyncWithServer {
|
||||
if cache.md5 != cache.cacheDataListener.lastMd5 {
|
||||
cache.executeListener()
|
||||
}
|
||||
if !needAllSync {
|
||||
continue
|
||||
if len(response.ChangedConfigs) > 0 {
|
||||
hasChangedKeys = true
|
||||
}
|
||||
changeKeys := make(map[string]struct{}, len(response.ChangedConfigs))
|
||||
for _, v := range response.ChangedConfigs {
|
||||
changeKey := util.GetConfigCacheKey(v.DataId, v.Group, v.Tenant)
|
||||
changeKeys[changeKey] = struct{}{}
|
||||
if value, ok := client.cacheMap.Get(changeKey); ok {
|
||||
cData := value.(cacheData)
|
||||
client.refreshContentAndCheck(cData, !cData.isInitializing)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
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
|
||||
}
|
||||
if iResponse == nil && !iResponse.IsSuccess() {
|
||||
continue
|
||||
}
|
||||
changeKeys := make(map[string]struct{})
|
||||
if response, ok := iResponse.(*rpc_response.ConfigChangeBatchListenResponse); ok {
|
||||
if len(response.ChangedConfigs) > 0 {
|
||||
hasChangedKeys = true
|
||||
for _, v := range response.ChangedConfigs {
|
||||
changeKey := util.GetConfigCacheKey(v.DataId, v.Group, v.Tenant)
|
||||
changeKeys[changeKey] = struct{}{}
|
||||
if cache, ok := client.cacheMap.Get(changeKey); !ok {
|
||||
continue
|
||||
} else {
|
||||
cacheData := cache.(*cacheData)
|
||||
client.refreshContentAndCheck(cacheData, !cacheData.isInitializing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range listenCaches {
|
||||
changeKey := util.GetConfigCacheKey(v.dataId, v.group, v.tenant)
|
||||
if _, ok := changeKeys[changeKey]; !ok {
|
||||
v.isSyncWithServer = true
|
||||
continue
|
||||
}
|
||||
v.isInitializing = true
|
||||
}
|
||||
}
|
||||
data.isInitializing = true
|
||||
client.cacheMap.Set(changeKey, data)
|
||||
}
|
||||
|
||||
}
|
||||
if needAllSync {
|
||||
client.lastAllSyncTime = time.Now()
|
||||
}
|
||||
|
||||
if hasChangedKeys {
|
||||
client.notifyListenConfig()
|
||||
client.asyncNotifyListenConfig()
|
||||
}
|
||||
monitor.GetListenConfigCountMonitor().Set(float64(client.cacheMap.Count()))
|
||||
}
|
||||
|
||||
func buildConfigBatchListenRequest(caches []*cacheData) *rpc_request.ConfigBatchListenRequest {
|
||||
func buildConfigBatchListenRequest(caches []cacheData) *rpc_request.ConfigBatchListenRequest {
|
||||
request := rpc_request.NewConfigBatchListenRequest(len(caches))
|
||||
for _, cache := range caches {
|
||||
request.ConfigListenContexts = append(request.ConfigListenContexts,
|
||||
|
@ -472,7 +499,7 @@ func buildConfigBatchListenRequest(caches []*cacheData) *rpc_request.ConfigBatch
|
|||
return request
|
||||
}
|
||||
|
||||
func (client *ConfigClient) refreshContentAndCheck(cacheData *cacheData, notify bool) {
|
||||
func (client *ConfigClient) refreshContentAndCheck(cacheData cacheData, notify bool) {
|
||||
configQueryResponse, err := client.configProxy.queryConfig(cacheData.dataId, cacheData.group, cacheData.tenant,
|
||||
constant.DEFAULT_TIMEOUT_MILLS, notify, client)
|
||||
if err != nil {
|
||||
|
@ -480,8 +507,14 @@ func (client *ConfigClient) refreshContentAndCheck(cacheData *cacheData, notify
|
|||
cacheData.group, cacheData.tenant)
|
||||
return
|
||||
}
|
||||
if configQueryResponse != nil && configQueryResponse.Response != nil && !configQueryResponse.IsSuccess() {
|
||||
logger.Errorf("refresh cached config from server error:%v, dataId=%s, group=%s", configQueryResponse.GetMessage(),
|
||||
cacheData.dataId, cacheData.group)
|
||||
return
|
||||
}
|
||||
cacheData.content = configQueryResponse.Content
|
||||
cacheData.contentType = configQueryResponse.ContentType
|
||||
cacheData.encryptedDataKey = configQueryResponse.EncryptedDataKey
|
||||
if notify {
|
||||
logger.Infof("[config_rpc_client] [data-received] dataId=%s, group=%s, tenant=%s, md5=%s, content=%s, type=%s",
|
||||
cacheData.dataId, cacheData.group, cacheData.tenant, cacheData.md5,
|
||||
|
@ -489,12 +522,42 @@ func (client *ConfigClient) refreshContentAndCheck(cacheData *cacheData, notify
|
|||
}
|
||||
cacheData.md5 = util.Md5(cacheData.content)
|
||||
if cacheData.md5 != cacheData.cacheDataListener.lastMd5 {
|
||||
client.cacheMap.Set(util.GetConfigCacheKey(cacheData.dataId, cacheData.group, cacheData.tenant), cacheData)
|
||||
|
||||
cacheData.executeListener()
|
||||
cacheDataPtr := &cacheData
|
||||
cacheDataPtr.executeListener()
|
||||
}
|
||||
}
|
||||
|
||||
func (client *ConfigClient) notifyListenConfig() {
|
||||
client.listenExecute <- struct{}{}
|
||||
func (client *ConfigClient) buildListenTask(needAllSync bool) map[int][]cacheData {
|
||||
listenTaskMap := make(map[int][]cacheData, 8)
|
||||
|
||||
for _, v := range client.cacheMap.Items() {
|
||||
data, ok := v.(cacheData)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if data.isSyncWithServer {
|
||||
if data.md5 != data.cacheDataListener.lastMd5 {
|
||||
data.executeListener()
|
||||
}
|
||||
if !needAllSync {
|
||||
continue
|
||||
}
|
||||
}
|
||||
listenTaskMap[data.taskId] = append(listenTaskMap[data.taskId], data)
|
||||
}
|
||||
return listenTaskMap
|
||||
}
|
||||
|
||||
func (client *ConfigClient) asyncNotifyListenConfig() {
|
||||
go func() {
|
||||
client.listenExecute <- struct{}{}
|
||||
}()
|
||||
}
|
||||
|
||||
func (client *ConfigClient) buildResponse(response rpc_response.IResponse) (bool, error) {
|
||||
if response.IsSuccess() {
|
||||
return response.IsSuccess(), nil
|
||||
}
|
||||
return false, errors.New(response.GetMessage())
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@ package config_client
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
"testing"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
|
||||
|
@ -35,12 +35,29 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var serverConfigWithOptions = constant.NewServerConfig("127.0.0.1", 80, constant.WithContextPath("/nacos"))
|
||||
var serverConfigWithOptions = constant.NewServerConfig("127.0.0.1", 8848)
|
||||
|
||||
var clientConfigWithOptions = constant.NewClientConfig(
|
||||
constant.WithTimeoutMs(10*1000),
|
||||
constant.WithBeatInterval(2*1000),
|
||||
constant.WithNotLoadCacheAtStart(true),
|
||||
constant.WithAccessKey("LTAxxx"),
|
||||
constant.WithSecretKey("EdPxxx"),
|
||||
constant.WithOpenKMS(true),
|
||||
constant.WithKMSVersion(constant.KMSv1),
|
||||
constant.WithRegionId("cn-hangzhou"),
|
||||
)
|
||||
|
||||
var clientTLsConfigWithOptions = constant.NewClientConfig(
|
||||
constant.WithTimeoutMs(10*1000),
|
||||
constant.WithBeatInterval(2*1000),
|
||||
constant.WithNotLoadCacheAtStart(true),
|
||||
|
||||
/*constant.WithTLS(constant.TLSConfig{
|
||||
Enable: true,
|
||||
TrustAll: false,
|
||||
CaFile: "mse-nacos-ca.cer",
|
||||
}),*/
|
||||
)
|
||||
|
||||
var localConfigTest = vo.ConfigParam{
|
||||
|
@ -59,6 +76,44 @@ func createConfigClientTest() *ConfigClient {
|
|||
return client
|
||||
}
|
||||
|
||||
func createConfigClientTestTls() *ConfigClient {
|
||||
nc := nacos_client.NacosClient{}
|
||||
_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
|
||||
_ = nc.SetClientConfig(*clientTLsConfigWithOptions)
|
||||
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewConfigClient(&nc)
|
||||
client.configProxy = &MockConfigProxy{}
|
||||
return client
|
||||
}
|
||||
|
||||
func createConfigClientCommon() *ConfigClient {
|
||||
nc := nacos_client.NacosClient{}
|
||||
_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
|
||||
_ = nc.SetClientConfig(*clientConfigWithOptions)
|
||||
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewConfigClient(&nc)
|
||||
client.configProxy = &MockConfigProxy{}
|
||||
return client
|
||||
}
|
||||
|
||||
func createConfigClientForKms() *ConfigClient {
|
||||
nc := nacos_client.NacosClient{}
|
||||
_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
|
||||
_ = nc.SetClientConfig(*clientConfigWithOptions)
|
||||
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewConfigClient(&nc)
|
||||
client.configProxy = &MockConfigProxyForUsingLocalDiskCache{}
|
||||
return client
|
||||
}
|
||||
|
||||
type MockConfigProxyForUsingLocalDiskCache struct {
|
||||
MockConfigProxy
|
||||
}
|
||||
|
||||
func (m *MockConfigProxyForUsingLocalDiskCache) queryConfig(dataId, group, tenant string, timeout uint64, notify bool, client *ConfigClient) (*rpc_response.ConfigQueryResponse, error) {
|
||||
return nil, errors.New("mock err for using localCache")
|
||||
}
|
||||
|
||||
type MockConfigProxy struct {
|
||||
}
|
||||
|
||||
|
@ -67,7 +122,7 @@ func (m *MockConfigProxy) queryConfig(dataId, group, tenant string, timeout uint
|
|||
if IsLimited(cacheKey) {
|
||||
return nil, errors.New("request is limited")
|
||||
}
|
||||
return &rpc_response.ConfigQueryResponse{Content: "hello world"}, nil
|
||||
return &rpc_response.ConfigQueryResponse{Content: "hello world", Response: &rpc_response.Response{Success: true}}, nil
|
||||
}
|
||||
func (m *MockConfigProxy) searchConfigProxy(param vo.SearchConfigParam, tenant, accessKey, secretKey string) (*model.ConfigPage, error) {
|
||||
return &model.ConfigPage{TotalCount: 1}, nil
|
||||
|
@ -94,7 +149,7 @@ func Test_GetConfig(t *testing.T) {
|
|||
|
||||
content, err := client.GetConfig(vo.ConfigParam{
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "group"})
|
||||
Group: localConfigTest.Group})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "hello world", content)
|
||||
|
@ -117,6 +172,74 @@ func Test_SearchConfig(t *testing.T) {
|
|||
assert.NotEmpty(t, configPage)
|
||||
}
|
||||
|
||||
func Test_GetConfigTls(t *testing.T) {
|
||||
client := createConfigClientTestTls()
|
||||
_, _ = client.PublishConfig(vo.ConfigParam{
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "DEFAULT_GROUP",
|
||||
Content: "hello world"})
|
||||
configPage, err := client.SearchConfig(vo.SearchConfigParam{
|
||||
Search: "accurate",
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "DEFAULT_GROUP",
|
||||
PageNo: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
assert.NotEmpty(t, configPage)
|
||||
|
||||
}
|
||||
|
||||
// only using by ak sk for cipher config of aliyun kms
|
||||
/*
|
||||
func TestPublishAndGetConfigByUsingLocalCache(t *testing.T) {
|
||||
param := vo.ConfigParam{
|
||||
DataId: "cipher-kms-aes-256-usingCache" + strconv.Itoa(rand.Int()),
|
||||
Group: "DEFAULT",
|
||||
Content: "content加密&&" + strconv.Itoa(rand.Int()),
|
||||
}
|
||||
t.Run("PublishAndGetConfigByUsingLocalCache", func(t *testing.T) {
|
||||
commonClient := createConfigClientCommon()
|
||||
_, err := commonClient.PublishConfig(param)
|
||||
assert.Nil(t, err)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
configQueryContent, err := commonClient.GetConfig(param)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, param.Content, configQueryContent)
|
||||
|
||||
usingKmsCacheClient := createConfigClientForKms()
|
||||
configQueryContentByUsingCache, err := usingKmsCacheClient.GetConfig(param)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, param.Content, configQueryContentByUsingCache)
|
||||
|
||||
newCipherContent := param.Content + "new"
|
||||
param.Content = newCipherContent
|
||||
err = commonClient.ListenConfig(vo.ConfigParam{
|
||||
DataId: param.DataId,
|
||||
Group: param.Group,
|
||||
OnChange: func(namespace, group, dataId, data string) {
|
||||
t.Log("origin data: " + newCipherContent + "; new data: " + data)
|
||||
assert.Equal(t, newCipherContent, data)
|
||||
},
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
|
||||
result, err := commonClient.PublishConfig(param)
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, result)
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
newContentCommon, err := commonClient.GetConfig(param)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, param.Content, newContentCommon)
|
||||
newContentKms, err := usingKmsCacheClient.GetConfig(param)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, param.Content, newContentKms)
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
// PublishConfig
|
||||
func Test_PublishConfigWithoutDataId(t *testing.T) {
|
||||
client := createConfigClientTest()
|
||||
|
@ -145,6 +268,7 @@ func Test_PublishConfig(t *testing.T) {
|
|||
success, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "group",
|
||||
SrcUser: "nacos-client-go",
|
||||
Content: "hello world"})
|
||||
|
||||
assert.Nil(t, err)
|
||||
|
@ -233,3 +357,55 @@ func TestCancelListenConfig(t *testing.T) {
|
|||
assert.Nil(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
type MockAccessKeyCredentialProvider struct {
|
||||
accessKey string
|
||||
secretKey string
|
||||
signatureRegionId string
|
||||
}
|
||||
|
||||
func (provider *MockAccessKeyCredentialProvider) MatchProvider() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (provider *MockAccessKeyCredentialProvider) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (provider *MockAccessKeyCredentialProvider) GetCredentialsForNacosClient() security.RamContext {
|
||||
ramContext := security.RamContext{
|
||||
AccessKey: provider.accessKey,
|
||||
SecretKey: provider.secretKey,
|
||||
SignatureRegionId: "",
|
||||
}
|
||||
return ramContext
|
||||
}
|
||||
|
||||
func Test_ConfigClientWithProvider(t *testing.T) {
|
||||
nc := nacos_client.NacosClient{}
|
||||
_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
|
||||
clientConfigWithOptions.AccessKey = ""
|
||||
clientConfigWithOptions.SecretKey = ""
|
||||
_ = nc.SetClientConfig(*clientConfigWithOptions)
|
||||
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
provider := &MockAccessKeyCredentialProvider{
|
||||
accessKey: "LTAxxx",
|
||||
secretKey: "EdPxxx",
|
||||
}
|
||||
client, _ := NewConfigClientWithRamCredentialProvider(&nc, provider)
|
||||
client.configProxy = &MockConfigProxy{}
|
||||
success, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: localConfigTest.Group,
|
||||
Content: "hello world"})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, success)
|
||||
|
||||
content, err := client.GetConfig(vo.ConfigParam{
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: localConfigTest.Group})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "hello world", content)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
* 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")
|
||||
}
|
|
@ -23,22 +23,20 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/monitor"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/monitor"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/nacos_server"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type ConfigProxy struct {
|
||||
|
@ -47,20 +45,21 @@ type ConfigProxy struct {
|
|||
}
|
||||
|
||||
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{}
|
||||
var err error
|
||||
proxy.nacosServer, err = nacos_server.NewNacosServer(ctx, serverConfig, clientConfig, httpAgent, clientConfig.TimeoutMs, clientConfig.Endpoint)
|
||||
proxy.nacosServer, err = nacos_server.NewNacosServerWithRamCredentialProvider(ctx, serverConfig, clientConfig, httpAgent, clientConfig.TimeoutMs, clientConfig.Endpoint, nil, provider)
|
||||
proxy.clientConfig = clientConfig
|
||||
return &proxy, err
|
||||
}
|
||||
|
||||
func (cp *ConfigProxy) requestProxy(rpcClient *rpc.RpcClient, request rpc_request.IRequest, timeoutMills uint64) (rpc_response.IResponse, error) {
|
||||
start := time.Now()
|
||||
cp.nacosServer.InjectSecurityInfo(request.GetHeaders())
|
||||
cp.nacosServer.InjectSecurityInfo(request.GetHeaders(), security.BuildConfigResourceByRequest(request))
|
||||
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))
|
||||
monitor.GetConfigRequestMonitor(constant.GRPC, request.GetRequestType(), rpc_response.GetGrpcResponseStatusCode(response)).Observe(float64(time.Now().Nanosecond() - start.Nanosecond()))
|
||||
return response, err
|
||||
|
@ -87,14 +86,27 @@ func (cp *ConfigProxy) searchConfigProxy(param vo.SearchConfigParam, tenant, acc
|
|||
params["dataId"] = ""
|
||||
}
|
||||
var headers = map[string]string{}
|
||||
headers["accessKey"] = accessKey
|
||||
headers["secretKey"] = secretKey
|
||||
var version = "v2"
|
||||
result, err := cp.nacosServer.ReqConfigApi(constant.CONFIG_PATH, params, headers, http.MethodGet, cp.clientConfig.TimeoutMs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(tenant) > 0 {
|
||||
params["namespaceId"] = params["tenant"]
|
||||
}
|
||||
params["groupName"] = params["group"]
|
||||
result, err = cp.nacosServer.ReqConfigApi("/v3/admin/cs/config/list", params, headers, http.MethodGet, cp.clientConfig.TimeoutMs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
version = "v3"
|
||||
}
|
||||
var configPage model.ConfigPage
|
||||
err = json.Unmarshal([]byte(result), &configPage)
|
||||
if version == "v2" {
|
||||
err = json.Unmarshal([]byte(result), &configPage)
|
||||
} else {
|
||||
var configPageResult model.ConfigPageResult
|
||||
err = json.Unmarshal([]byte(result), &configPageResult)
|
||||
configPage = configPageResult.Data
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -122,9 +134,8 @@ func (cp *ConfigProxy) queryConfig(dataId, group, tenant string, timeout uint64,
|
|||
return nil, errors.New("ConfigQueryRequest returns type error")
|
||||
}
|
||||
if response.IsSuccess() {
|
||||
//todo LocalConfigInfoProcessor.saveSnapshot
|
||||
cache.WriteConfigToFile(cacheKey, cp.clientConfig.CacheDir, response.Content)
|
||||
//todo LocalConfigInfoProcessor.saveEncryptDataKeySnapshot
|
||||
cache.WriteEncryptedDataKeyToFile(cacheKey, cp.clientConfig.CacheDir, response.EncryptedDataKey)
|
||||
if response.ContentType == "" {
|
||||
response.ContentType = "text"
|
||||
}
|
||||
|
@ -132,9 +143,9 @@ func (cp *ConfigProxy) queryConfig(dataId, group, tenant string, timeout uint64,
|
|||
}
|
||||
|
||||
if response.GetErrorCode() == 300 {
|
||||
//todo LocalConfigInfoProcessor.saveSnapshot
|
||||
cache.WriteConfigToFile(cacheKey, cp.clientConfig.CacheDir, "")
|
||||
//todo LocalConfigInfoProcessor.saveEncryptDataKeySnapshot
|
||||
cache.WriteEncryptedDataKeyToFile(cacheKey, cp.clientConfig.CacheDir, "")
|
||||
response.SetSuccess(true)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
|
@ -152,20 +163,33 @@ func (cp *ConfigProxy) queryConfig(dataId, group, tenant string, timeout uint64,
|
|||
return response, nil
|
||||
}
|
||||
|
||||
func appName(client *ConfigClient) string {
|
||||
if clientConfig, err := client.GetClientConfig(); err == nil {
|
||||
appName := clientConfig.AppName
|
||||
return appName
|
||||
}
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
func (cp *ConfigProxy) createRpcClient(ctx context.Context, taskId string, client *ConfigClient) *rpc.RpcClient {
|
||||
labels := map[string]string{
|
||||
constant.LABEL_SOURCE: constant.LABEL_SOURCE_SDK,
|
||||
constant.LABEL_MODULE: constant.LABEL_MODULE_CONFIG,
|
||||
"taskId": taskId,
|
||||
constant.LABEL_SOURCE: constant.LABEL_SOURCE_SDK,
|
||||
constant.LABEL_MODULE: constant.LABEL_MODULE_CONFIG,
|
||||
constant.APPNAME_HEADER: appName(client),
|
||||
"taskId": taskId,
|
||||
}
|
||||
|
||||
iRpcClient, _ := rpc.CreateClient(ctx, "config-"+taskId+"-"+client.uid, rpc.GRPC, labels, cp.nacosServer)
|
||||
iRpcClient, _ := rpc.CreateClient(ctx, "config-"+taskId+"-"+client.uid, rpc.GRPC, labels, cp.nacosServer, &cp.clientConfig.TLSCfg, cp.clientConfig.AppConnLabels)
|
||||
rpcClient := iRpcClient.GetRpcClient()
|
||||
if rpcClient.IsInitialized() {
|
||||
rpcClient.RegisterServerRequestHandler(func() rpc_request.IRequest {
|
||||
// TODO fix the group/dataId empty problem
|
||||
return rpc_request.NewConfigChangeNotifyRequest("", "", "")
|
||||
}, &ConfigChangeNotifyRequestHandler{client: client})
|
||||
|
||||
configListener := NewConfigConnectionEventListener(client, taskId)
|
||||
rpcClient.RegisterConnectionListener(configListener)
|
||||
|
||||
rpcClient.Tenant = cp.clientConfig.NamespaceId
|
||||
rpcClient.Start()
|
||||
}
|
||||
|
@ -186,22 +210,23 @@ func (c *ConfigChangeNotifyRequestHandler) Name() string {
|
|||
|
||||
func (c *ConfigChangeNotifyRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *rpc.RpcClient) rpc_response.IResponse {
|
||||
configChangeNotifyRequest, ok := request.(*rpc_request.ConfigChangeNotifyRequest)
|
||||
if ok {
|
||||
logger.Infof("%s [server-push] config changed. dataId=%s, group=%s,tenant=%s", rpcClient.Name(),
|
||||
configChangeNotifyRequest.DataId, configChangeNotifyRequest.Group, configChangeNotifyRequest.Tenant)
|
||||
|
||||
cacheKey := util.GetConfigCacheKey(configChangeNotifyRequest.DataId, configChangeNotifyRequest.Group,
|
||||
configChangeNotifyRequest.Tenant)
|
||||
data, ok := c.client.cacheMap.Get(cacheKey)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
cData := data.(*cacheData)
|
||||
cData.isSyncWithServer = false
|
||||
c.client.notifyListenConfig()
|
||||
return &rpc_response.NotifySubscriberResponse{
|
||||
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS},
|
||||
}
|
||||
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)
|
||||
|
||||
cacheKey := util.GetConfigCacheKey(configChangeNotifyRequest.DataId, configChangeNotifyRequest.Group,
|
||||
configChangeNotifyRequest.Tenant)
|
||||
data, ok := c.client.cacheMap.Get(cacheKey)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
cData := data.(cacheData)
|
||||
cData.isSyncWithServer = false
|
||||
c.client.cacheMap.Set(cacheKey, cData)
|
||||
c.client.asyncNotifyListenConfig()
|
||||
return &rpc_response.NotifySubscriberResponse{
|
||||
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS},
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package nacos_client
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
|
@ -36,7 +35,7 @@ type NacosClient struct {
|
|||
serverConfigs []constant.ServerConfig
|
||||
}
|
||||
|
||||
//SetClientConfig is use to set nacos client Config
|
||||
// SetClientConfig is use to set nacos client Config
|
||||
func (client *NacosClient) SetClientConfig(config constant.ClientConfig) (err error) {
|
||||
if config.TimeoutMs <= 0 {
|
||||
config.TimeoutMs = 10 * 1000
|
||||
|
@ -61,14 +60,14 @@ func (client *NacosClient) SetClientConfig(config constant.ClientConfig) (err er
|
|||
if config.LogDir == "" {
|
||||
config.LogDir = file.GetCurrentPath() + string(os.PathSeparator) + "log"
|
||||
}
|
||||
log.Printf("[INFO] logDir:<%s> cacheDir:<%s>", config.LogDir, config.CacheDir)
|
||||
|
||||
client.clientConfig = config
|
||||
client.clientConfigValid = true
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//SetServerConfig is use to set nacos server config
|
||||
// SetServerConfig is use to set nacos server config
|
||||
func (client *NacosClient) SetServerConfig(configs []constant.ServerConfig) (err error) {
|
||||
if len(configs) <= 0 {
|
||||
//it's may be use endpoint to get nacos server address
|
||||
|
@ -93,7 +92,7 @@ func (client *NacosClient) SetServerConfig(configs []constant.ServerConfig) (err
|
|||
return
|
||||
}
|
||||
|
||||
//GetClientConfig use to get client config
|
||||
// GetClientConfig use to get client config
|
||||
func (client *NacosClient) GetClientConfig() (config constant.ClientConfig, err error) {
|
||||
config = client.clientConfig
|
||||
if !client.clientConfigValid {
|
||||
|
@ -102,7 +101,7 @@ func (client *NacosClient) GetClientConfig() (config constant.ClientConfig, err
|
|||
return
|
||||
}
|
||||
|
||||
//GetServerConfig use to get server config
|
||||
// GetServerConfig use to get server config
|
||||
func (client *NacosClient) GetServerConfig() (configs []constant.ServerConfig, err error) {
|
||||
configs = client.serverConfigs
|
||||
if !client.serverConfigsValid {
|
||||
|
@ -111,7 +110,7 @@ func (client *NacosClient) GetServerConfig() (configs []constant.ServerConfig, e
|
|||
return
|
||||
}
|
||||
|
||||
//SetHttpAgent use to set http agent
|
||||
// SetHttpAgent use to set http agent
|
||||
func (client *NacosClient) SetHttpAgent(agent http_agent.IHttpAgent) (err error) {
|
||||
if agent == nil {
|
||||
err = errors.New("[client.SetHttpAgent] http agent can not be nil")
|
||||
|
@ -121,7 +120,7 @@ func (client *NacosClient) SetHttpAgent(agent http_agent.IHttpAgent) (err error)
|
|||
return
|
||||
}
|
||||
|
||||
//GetHttpAgent use to get http agent
|
||||
// GetHttpAgent use to get http agent
|
||||
func (client *NacosClient) GetHttpAgent() (agent http_agent.IHttpAgent, err error) {
|
||||
if client.agent == nil {
|
||||
err = errors.New("[client.GetHttpAgent] invalid http agent")
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package naming_cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
@ -116,12 +115,12 @@ func (s *ServiceInfoHolder) GetServiceInfo(serviceName, groupName, clusters stri
|
|||
return model.Service{}, ok
|
||||
}
|
||||
|
||||
func (s *ServiceInfoHolder) RegisterCallback(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
|
||||
s.subCallback.AddCallbackFunc(serviceName, clusters, callbackFunc)
|
||||
func (s *ServiceInfoHolder) RegisterCallback(serviceName string, clusters string, callbackWrapper *SubscribeCallbackFuncWrapper) {
|
||||
s.subCallback.AddCallbackFunc(serviceName, clusters, callbackWrapper)
|
||||
}
|
||||
|
||||
func (s *ServiceInfoHolder) DeregisterCallback(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
|
||||
s.subCallback.RemoveCallbackFunc(serviceName, clusters, callbackFunc)
|
||||
func (s *ServiceInfoHolder) DeregisterCallback(serviceName string, clusters string, callbackWrapper *SubscribeCallbackFuncWrapper) {
|
||||
s.subCallback.RemoveCallbackFunc(serviceName, clusters, callbackWrapper)
|
||||
}
|
||||
|
||||
func (s *ServiceInfoHolder) StopUpdateIfContain(serviceName, clusters string) {
|
||||
|
@ -152,7 +151,7 @@ func isServiceInstanceChanged(oldService, newService model.Service) bool {
|
|||
oldRefTime := oldService.LastRefTime
|
||||
newRefTime := newService.LastRefTime
|
||||
if oldRefTime > newRefTime {
|
||||
logger.Warn(fmt.Sprintf("out of date data received, old-t: %v , new-t: %v", oldRefTime, newRefTime))
|
||||
logger.Warnf("out of date data received, old-t: %v , new-t: %v", oldRefTime, newRefTime)
|
||||
return false
|
||||
}
|
||||
// sort instance list
|
||||
|
|
|
@ -19,8 +19,6 @@ package naming_cache
|
|||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
|
@ -38,31 +36,34 @@ func NewSubscribeCallback() *SubscribeCallback {
|
|||
|
||||
func (ed *SubscribeCallback) IsSubscribed(serviceName, clusters string) bool {
|
||||
key := util.GetServiceCacheKey(serviceName, clusters)
|
||||
_, ok := ed.callbackFuncMap.Get(key)
|
||||
return ok
|
||||
funcs, ok := ed.callbackFuncMap.Get(key)
|
||||
if ok {
|
||||
return len(funcs.([]*SubscribeCallbackFuncWrapper)) > 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (ed *SubscribeCallback) AddCallbackFunc(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
|
||||
func (ed *SubscribeCallback) AddCallbackFunc(serviceName string, clusters string, callbackWrapper *SubscribeCallbackFuncWrapper) {
|
||||
key := util.GetServiceCacheKey(serviceName, clusters)
|
||||
defer ed.mux.Unlock()
|
||||
ed.mux.Lock()
|
||||
var funcSlice []*func(services []model.Instance, err error)
|
||||
defer ed.mux.Unlock()
|
||||
var funcSlice []*SubscribeCallbackFuncWrapper
|
||||
old, ok := ed.callbackFuncMap.Get(key)
|
||||
if ok {
|
||||
funcSlice = append(funcSlice, old.([]*func(services []model.Instance, err error))...)
|
||||
funcSlice = append(funcSlice, old.([]*SubscribeCallbackFuncWrapper)...)
|
||||
}
|
||||
funcSlice = append(funcSlice, callbackFunc)
|
||||
funcSlice = append(funcSlice, callbackWrapper)
|
||||
ed.callbackFuncMap.Set(key, funcSlice)
|
||||
}
|
||||
|
||||
func (ed *SubscribeCallback) RemoveCallbackFunc(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
|
||||
func (ed *SubscribeCallback) RemoveCallbackFunc(serviceName string, clusters string, callbackWrapper *SubscribeCallbackFuncWrapper) {
|
||||
logger.Info("removing " + serviceName + " with " + clusters + " to listener map")
|
||||
key := util.GetServiceCacheKey(serviceName, clusters)
|
||||
funcs, ok := ed.callbackFuncMap.Get(key)
|
||||
if ok && funcs != nil {
|
||||
var newFuncs []*func(services []model.Instance, err error)
|
||||
for _, funcItem := range funcs.([]*func(services []model.Instance, err error)) {
|
||||
if funcItem != callbackFunc {
|
||||
var newFuncs []*SubscribeCallbackFuncWrapper
|
||||
for _, funcItem := range funcs.([]*SubscribeCallbackFuncWrapper) {
|
||||
if funcItem.CallbackFunc != callbackWrapper.CallbackFunc || !funcItem.Selector.Equals(callbackWrapper.Selector) {
|
||||
newFuncs = append(newFuncs, funcItem)
|
||||
}
|
||||
}
|
||||
|
@ -74,12 +75,8 @@ func (ed *SubscribeCallback) RemoveCallbackFunc(serviceName string, clusters str
|
|||
func (ed *SubscribeCallback) ServiceChanged(cacheKey string, service *model.Service) {
|
||||
funcs, ok := ed.callbackFuncMap.Get(cacheKey)
|
||||
if ok {
|
||||
for _, funcItem := range funcs.([]*func(services []model.Instance, err error)) {
|
||||
if len(service.Hosts) == 0 {
|
||||
(*funcItem)(service.Hosts, errors.New("[client.Subscribe] subscribe failed,hosts is empty"))
|
||||
continue
|
||||
}
|
||||
(*funcItem)(service.Hosts, nil)
|
||||
for _, funcItem := range funcs.([]*SubscribeCallbackFuncWrapper) {
|
||||
funcItem.notifyListener(service)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,13 +58,15 @@ func TestEventDispatcher_AddCallbackFuncs(t *testing.T) {
|
|||
fmt.Println(util.ToJsonString(ed.callbackFuncMap))
|
||||
},
|
||||
}
|
||||
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
clusterSelector := NewClusterSelector(param.Clusters)
|
||||
callbackWrapper := NewSubscribeCallbackFuncWrapper(clusterSelector, ¶m.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, ","))
|
||||
for k, v := range ed.callbackFuncMap.Items() {
|
||||
assert.Equal(t, key, k, "key should be equal!")
|
||||
funcs := v.([]*func(services []model.Instance, err error))
|
||||
funcs := v.([]*SubscribeCallbackFuncWrapper)
|
||||
assert.Equal(t, len(funcs), 1)
|
||||
assert.Equal(t, funcs[0], ¶m.SubscribeCallback, "callback function must be equal!")
|
||||
assert.Equal(t, funcs[0].CallbackFunc, ¶m.SubscribeCallback, "callback function must be equal!")
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +100,9 @@ func TestEventDispatcher_RemoveCallbackFuncs(t *testing.T) {
|
|||
fmt.Printf("func1:%s \n", util.ToJsonString(services))
|
||||
},
|
||||
}
|
||||
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
clusterSelector := NewClusterSelector(param.Clusters)
|
||||
callbackWrapper := NewSubscribeCallbackFuncWrapper(clusterSelector, ¶m.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")
|
||||
|
||||
param2 := vo.SubscribeParam{
|
||||
|
@ -109,21 +113,23 @@ func TestEventDispatcher_RemoveCallbackFuncs(t *testing.T) {
|
|||
fmt.Printf("func2:%s \n", util.ToJsonString(services))
|
||||
},
|
||||
}
|
||||
ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), ¶m2.SubscribeCallback)
|
||||
clusterSelector2 := NewClusterSelector(param2.Clusters)
|
||||
callbackWrapper2 := NewSubscribeCallbackFuncWrapper(clusterSelector2, ¶m2.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")
|
||||
|
||||
for k, v := range ed.callbackFuncMap.Items() {
|
||||
log.Printf("key:%s,%d", k, len(v.([]*func(services []model.Instance, err error))))
|
||||
log.Printf("key:%s,%d", k, len(v.([]*SubscribeCallbackFuncWrapper)))
|
||||
}
|
||||
|
||||
ed.RemoveCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), ¶m2.SubscribeCallback)
|
||||
ed.RemoveCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), callbackWrapper2)
|
||||
|
||||
key := util.GetServiceCacheKey(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
|
||||
for k, v := range ed.callbackFuncMap.Items() {
|
||||
assert.Equal(t, key, k, "key should be equal!")
|
||||
funcs := v.([]*func(services []model.Instance, err error))
|
||||
funcs := v.([]*SubscribeCallbackFuncWrapper)
|
||||
assert.Equal(t, len(funcs), 1)
|
||||
assert.Equal(t, funcs[0], ¶m.SubscribeCallback, "callback function must be equal!")
|
||||
assert.Equal(t, funcs[0].CallbackFunc, ¶m.SubscribeCallback, "callback function must be equal!")
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +164,9 @@ func TestSubscribeCallback_ServiceChanged(t *testing.T) {
|
|||
log.Printf("func1:%s \n", util.ToJsonString(services))
|
||||
},
|
||||
}
|
||||
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
clusterSelector := NewClusterSelector(param.Clusters)
|
||||
callbackWrapper := NewSubscribeCallbackFuncWrapper(clusterSelector, ¶m.SubscribeCallback)
|
||||
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), callbackWrapper)
|
||||
|
||||
param2 := vo.SubscribeParam{
|
||||
ServiceName: "Test",
|
||||
|
@ -169,7 +177,54 @@ func TestSubscribeCallback_ServiceChanged(t *testing.T) {
|
|||
|
||||
},
|
||||
}
|
||||
ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), ¶m2.SubscribeCallback)
|
||||
clusterSelector2 := NewClusterSelector(param2.Clusters)
|
||||
callbackWrapper2 := NewSubscribeCallbackFuncWrapper(clusterSelector2, ¶m2.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)
|
||||
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))
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
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, ",")
|
||||
}
|
|
@ -21,8 +21,11 @@ import (
|
|||
"math"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client"
|
||||
|
@ -42,10 +45,17 @@ type NamingClient struct {
|
|||
cancel context.CancelFunc
|
||||
serviceProxy naming_proxy.INamingProxy
|
||||
serviceInfoHolder *naming_cache.ServiceInfoHolder
|
||||
isClosed bool
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// NewNamingClient ...
|
||||
func NewNamingClient(nc nacos_client.INacosClient) (*NamingClient, error) {
|
||||
return NewNamingClientWithRamCredentialProvider(nc, nil)
|
||||
}
|
||||
|
||||
// NewNamingClientWithRamCredentialProvider ...
|
||||
func NewNamingClientWithRamCredentialProvider(nc nacos_client.INacosClient, provider security.RamCredentialProvider) (*NamingClient, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
naming := &NamingClient{INacosClient: nc, ctx: ctx, cancel: cancel}
|
||||
|
@ -75,9 +85,11 @@ func NewNamingClient(nc nacos_client.INacosClient) (*NamingClient, error) {
|
|||
naming.serviceInfoHolder = naming_cache.NewServiceInfoHolder(clientConfig.NamespaceId, clientConfig.CacheDir,
|
||||
clientConfig.UpdateCacheWhenEmpty, clientConfig.NotLoadCacheAtStart)
|
||||
|
||||
naming.serviceProxy, err = NewNamingProxyDelegate(ctx, clientConfig, serverConfig, httpAgent, naming.serviceInfoHolder)
|
||||
naming.serviceProxy, err = NewNamingProxyDelegateWithRamCredentialProvider(ctx, clientConfig, serverConfig, httpAgent, naming.serviceInfoHolder, provider)
|
||||
|
||||
go NewServiceInfoUpdater(ctx, naming.serviceInfoHolder, clientConfig.UpdateThreadNum, naming.serviceProxy).asyncUpdateService()
|
||||
if clientConfig.AsyncUpdateService {
|
||||
go NewServiceInfoUpdater(ctx, naming.serviceInfoHolder, clientConfig.UpdateThreadNum, naming.serviceProxy).asyncUpdateService()
|
||||
}
|
||||
if err != nil {
|
||||
return naming, err
|
||||
}
|
||||
|
@ -110,9 +122,37 @@ func (sc *NamingClient) RegisterInstance(param vo.RegisterInstanceParam) (bool,
|
|||
Weight: param.Weight,
|
||||
Ephemeral: param.Ephemeral,
|
||||
}
|
||||
|
||||
return sc.serviceProxy.RegisterInstance(param.ServiceName, param.GroupName, instance)
|
||||
}
|
||||
|
||||
func (sc *NamingClient) BatchRegisterInstance(param vo.BatchRegisterInstanceParam) (bool, error) {
|
||||
if param.ServiceName == "" {
|
||||
return false, errors.New("serviceName cannot be empty!")
|
||||
}
|
||||
if len(param.GroupName) == 0 {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
if len(param.Instances) == 0 {
|
||||
return false, errors.New("instances cannot be empty!")
|
||||
}
|
||||
var modelInstances []model.Instance
|
||||
for _, param := range param.Instances {
|
||||
if !param.Ephemeral {
|
||||
return false, errors.Errorf("Batch registration does not allow persistent instance registration! instance:%+v", param)
|
||||
}
|
||||
modelInstances = append(modelInstances, model.Instance{
|
||||
Ip: param.Ip,
|
||||
Port: param.Port,
|
||||
Metadata: param.Metadata,
|
||||
ClusterName: param.ClusterName,
|
||||
Healthy: param.Healthy,
|
||||
Enable: param.Enable,
|
||||
Weight: param.Weight,
|
||||
Ephemeral: param.Ephemeral,
|
||||
})
|
||||
}
|
||||
|
||||
return sc.serviceProxy.BatchRegisterInstance(param.ServiceName, param.GroupName, modelInstances)
|
||||
}
|
||||
|
||||
// DeregisterInstance ...
|
||||
|
@ -161,11 +201,14 @@ func (sc *NamingClient) GetService(param vo.GetServiceParam) (service model.Serv
|
|||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
var ok bool
|
||||
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, "")
|
||||
if !ok {
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
|
||||
}
|
||||
service.Clusters = clusters
|
||||
service.Hosts = clusterSelector.SelectInstance(&service)
|
||||
return service, err
|
||||
}
|
||||
|
||||
|
@ -191,21 +234,24 @@ func (sc *NamingClient) SelectAllInstances(param vo.SelectAllInstancesParam) ([]
|
|||
if len(param.GroupName) == 0 {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
var (
|
||||
service model.Service
|
||||
ok bool
|
||||
err error
|
||||
)
|
||||
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
|
||||
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, "")
|
||||
if !ok {
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
|
||||
}
|
||||
if err != nil || service.Hosts == nil || len(service.Hosts) == 0 {
|
||||
if err != nil {
|
||||
return []model.Instance{}, err
|
||||
}
|
||||
return service.Hosts, err
|
||||
instances := clusterSelector.SelectInstance(&service)
|
||||
if instances == nil || len(instances) == 0 {
|
||||
return []model.Instance{}, err
|
||||
}
|
||||
return instances, err
|
||||
}
|
||||
|
||||
// SelectInstances Get all instance by DataId, Group and Health
|
||||
|
@ -218,14 +264,15 @@ func (sc *NamingClient) SelectInstances(param vo.SelectInstancesParam) ([]model.
|
|||
ok bool
|
||||
err error
|
||||
)
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
|
||||
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, "")
|
||||
if !ok {
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
service.Hosts = clusterSelector.SelectInstance(&service)
|
||||
return sc.selectInstances(service, param.HealthyOnly)
|
||||
}
|
||||
|
||||
|
@ -235,6 +282,7 @@ func (sc *NamingClient) selectInstances(service model.Service, healthy bool) ([]
|
|||
}
|
||||
hosts := service.Hosts
|
||||
var result []model.Instance
|
||||
logger.Infof("select instances with options: [healthy:<%t>], with service:<%s>", healthy, util.GetGroupName(service.Name, service.GroupName))
|
||||
for _, host := range hosts {
|
||||
if host.Healthy == healthy && host.Enable && host.Weight > 0 {
|
||||
result = append(result, host)
|
||||
|
@ -253,15 +301,15 @@ func (sc *NamingClient) SelectOneHealthyInstance(param vo.SelectOneHealthInstanc
|
|||
ok bool
|
||||
err error
|
||||
)
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
|
||||
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, "")
|
||||
if !ok {
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
service.Hosts = clusterSelector.SelectInstance(&service)
|
||||
return sc.selectOneHealthyInstances(service)
|
||||
}
|
||||
|
||||
|
@ -294,26 +342,40 @@ func (sc *NamingClient) Subscribe(param *vo.SubscribeParam) error {
|
|||
if len(param.GroupName) == 0 {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
sc.serviceInfoHolder.RegisterCallback(util.GetGroupName(param.ServiceName, param.GroupName), clusters, ¶m.SubscribeCallback)
|
||||
_, err := sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
|
||||
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
|
||||
callbackWrapper := naming_cache.NewSubscribeCallbackFuncWrapper(clusterSelector, ¶m.SubscribeCallback)
|
||||
sc.serviceInfoHolder.RegisterCallback(util.GetGroupName(param.ServiceName, param.GroupName), "", callbackWrapper)
|
||||
_, err := sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, "")
|
||||
return err
|
||||
}
|
||||
|
||||
// Unsubscribe ...
|
||||
func (sc *NamingClient) Unsubscribe(param *vo.SubscribeParam) (err error) {
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
clusterSelector := naming_cache.NewClusterSelector(param.Clusters)
|
||||
callbackWrapper := naming_cache.NewSubscribeCallbackFuncWrapper(clusterSelector, ¶m.SubscribeCallback)
|
||||
serviceFullName := util.GetGroupName(param.ServiceName, param.GroupName)
|
||||
sc.serviceInfoHolder.DeregisterCallback(serviceFullName, clusters, ¶m.SubscribeCallback)
|
||||
if sc.serviceInfoHolder.IsSubscribed(serviceFullName, clusters) {
|
||||
err = sc.serviceProxy.Unsubscribe(param.ServiceName, param.GroupName, clusters)
|
||||
sc.serviceInfoHolder.DeregisterCallback(serviceFullName, "", callbackWrapper)
|
||||
if !sc.serviceInfoHolder.IsSubscribed(serviceFullName, "") {
|
||||
err = sc.serviceProxy.Unsubscribe(param.ServiceName, param.GroupName, "")
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// ServerHealthy ...
|
||||
func (sc *NamingClient) ServerHealthy() bool {
|
||||
return sc.serviceProxy.ServerHealthy()
|
||||
}
|
||||
|
||||
// CloseClient ...
|
||||
func (sc *NamingClient) CloseClient() {
|
||||
sc.mutex.Lock()
|
||||
defer sc.mutex.Unlock()
|
||||
|
||||
if sc.isClosed {
|
||||
return
|
||||
}
|
||||
sc.serviceProxy.CloseClient()
|
||||
sc.cancel()
|
||||
sc.isClosed = true
|
||||
}
|
||||
|
|
|
@ -39,6 +39,13 @@ type INamingClient interface {
|
|||
// Ephemeral optional
|
||||
RegisterInstance(param vo.RegisterInstanceParam) (bool, error)
|
||||
|
||||
// BatchRegisterInstance use to batch register instance
|
||||
// ClusterName optional,default:DEFAULT
|
||||
// ServiceName require
|
||||
// GroupName optional,default:DEFAULT_GROUP
|
||||
// Instances require,batch register instance list (serviceName, groupName in instances do not need to be set)
|
||||
BatchRegisterInstance(param vo.BatchRegisterInstanceParam) (bool, error)
|
||||
|
||||
// DeregisterInstance use to deregister instance
|
||||
// Ip required
|
||||
// Port required
|
||||
|
@ -105,6 +112,9 @@ type INamingClient interface {
|
|||
// GetAllServicesInfo use to get all service info by page
|
||||
GetAllServicesInfo(param vo.GetAllServiceInfoParam) (model.ServiceList, error)
|
||||
|
||||
// ServerHealthy use to check the connectivity to server
|
||||
ServerHealthy() bool
|
||||
|
||||
//CloseClient close the GRPC client
|
||||
CloseClient()
|
||||
}
|
||||
|
|
|
@ -37,12 +37,18 @@ var clientConfigTest = *constant.NewClientConfig(
|
|||
var serverConfigTest = *constant.NewServerConfig("127.0.0.1", 80, constant.WithContextPath("/nacos"))
|
||||
|
||||
type MockNamingProxy struct {
|
||||
unsubscribeCalled bool
|
||||
unsubscribeParams []string // 记录调用参数
|
||||
}
|
||||
|
||||
func (m *MockNamingProxy) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m *MockNamingProxy) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m *MockNamingProxy) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
@ -64,6 +70,8 @@ func (m *MockNamingProxy) Subscribe(serviceName, groupName, clusters string) (mo
|
|||
}
|
||||
|
||||
func (m *MockNamingProxy) Unsubscribe(serviceName, groupName, clusters string) error {
|
||||
m.unsubscribeCalled = true
|
||||
m.unsubscribeParams = []string{serviceName, groupName, clusters}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -448,3 +456,108 @@ 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)
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package naming_grpc
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_proxy"
|
||||
|
@ -53,6 +52,11 @@ func (c *ConnectionEventListener) OnDisConnect() {
|
|||
}
|
||||
|
||||
func (c *ConnectionEventListener) redoSubscribe() {
|
||||
grpcProxy, ok := c.clientProxy.(*NamingGrpcProxy)
|
||||
if !ok {
|
||||
logger.Error("redo subscribe clientProxy type error")
|
||||
return
|
||||
}
|
||||
for _, key := range c.subscribes.Keys() {
|
||||
info := strings.Split(key, constant.SERVICE_INFO_SPLITER)
|
||||
var err error
|
||||
|
@ -62,15 +66,9 @@ func (c *ConnectionEventListener) redoSubscribe() {
|
|||
} else {
|
||||
service, err = c.clientProxy.Subscribe(info[1], info[0], "")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.Warnf("redo subscribe service:%s faild:%+v", info[1], err)
|
||||
return
|
||||
}
|
||||
|
||||
grpcProxy, ok := c.clientProxy.(*NamingGrpcProxy)
|
||||
if !ok {
|
||||
return
|
||||
continue
|
||||
}
|
||||
grpcProxy.serviceInfoHolder.ProcessService(&service)
|
||||
}
|
||||
|
@ -81,27 +79,31 @@ func (c *ConnectionEventListener) redoRegisterEachService() {
|
|||
info := strings.Split(k, constant.SERVICE_INFO_SPLITER)
|
||||
serviceName := info[1]
|
||||
groupName := info[0]
|
||||
instance, ok := v.(model.Instance)
|
||||
if !ok {
|
||||
logger.Warnf("redo register service:%s faild,instances type not is model.instance", info[1])
|
||||
return
|
||||
if instance, ok := v.(model.Instance); ok {
|
||||
if _, err := c.clientProxy.RegisterInstance(serviceName, groupName, instance); err != nil {
|
||||
logger.Warnf("redo register service:%s groupName:%s faild:%s", info[1], info[0], err.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
_, err := c.clientProxy.RegisterInstance(serviceName, groupName, instance)
|
||||
if err != nil {
|
||||
logger.Warnf("redo register service:%s groupName:%s faild:%s", info[1], info[0], err.Error())
|
||||
if instances, ok := v.([]model.Instance); ok {
|
||||
if _, err := c.clientProxy.BatchRegisterInstance(serviceName, groupName, instances); err != nil {
|
||||
logger.Warnf("redo batch register service:%s groupName:%s faild:%s", info[1], info[0], err.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) CacheInstanceForRedo(serviceName, groupName string, instance model.Instance) {
|
||||
key := util.GetGroupName(serviceName, groupName)
|
||||
getInstance, _ := c.registeredInstanceCached.Get(key)
|
||||
if getInstance != nil && reflect.DeepEqual(getInstance.(model.Instance), instance) {
|
||||
return
|
||||
}
|
||||
c.registeredInstanceCached.Set(key, instance)
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) CacheInstancesForRedo(serviceName, groupName string, instances []model.Instance) {
|
||||
key := util.GetGroupName(serviceName, groupName)
|
||||
c.registeredInstanceCached.Set(key, instances)
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) RemoveInstanceForRedo(serviceName, groupName string, instance model.Instance) {
|
||||
key := util.GetGroupName(serviceName, groupName)
|
||||
_, ok := c.registeredInstanceCached.Get(key)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package naming_grpc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_proxy"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRedoSubscribe(t *testing.T) {
|
||||
t.Skip("Skipping test,It failed due to a previous commit and is difficult to modify because of the use of struct type assertions in the code.")
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/inner/uuid"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
|
@ -61,7 +62,7 @@ func NewNamingGrpcProxy(ctx context.Context, clientCfg constant.ClientConfig, na
|
|||
constant.LABEL_MODULE: constant.LABEL_MODULE_NAMING,
|
||||
}
|
||||
|
||||
iRpcClient, err := rpc.CreateClient(ctx, uid.String(), rpc.GRPC, labels, srvProxy.nacosServer)
|
||||
iRpcClient, err := rpc.CreateClient(ctx, uid.String(), rpc.GRPC, labels, srvProxy.nacosServer, &clientCfg.TLSCfg, clientCfg.AppConnLabels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -83,20 +84,32 @@ func NewNamingGrpcProxy(ctx context.Context, clientCfg constant.ClientConfig, na
|
|||
|
||||
func (proxy *NamingGrpcProxy) requestToServer(request rpc_request.IRequest) (rpc_response.IResponse, error) {
|
||||
start := time.Now()
|
||||
proxy.nacosServer.InjectSign(request, request.GetHeaders(), proxy.clientConfig)
|
||||
proxy.nacosServer.InjectSecurityInfo(request.GetHeaders())
|
||||
proxy.nacosServer.InjectSecurityInfo(request.GetHeaders(), security.BuildNamingResourceByRequest(request))
|
||||
response, err := proxy.rpcClient.GetRpcClient().Request(request, int64(proxy.clientConfig.TimeoutMs))
|
||||
monitor.GetConfigRequestMonitor(constant.GRPC, request.GetRequestType(), rpc_response.GetGrpcResponseStatusCode(response)).Observe(float64(time.Now().Nanosecond() - start.Nanosecond()))
|
||||
monitor.GetNamingRequestMonitor(constant.GRPC, request.GetRequestType(), rpc_response.GetGrpcResponseStatusCode(response)).Observe(float64(time.Now().Nanosecond() - start.Nanosecond()))
|
||||
return response, err
|
||||
}
|
||||
|
||||
// RegisterInstance ...
|
||||
func (proxy *NamingGrpcProxy) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
logger.Infof("instance namespaceId:<%s>,serviceName:<%s> with instance:<%s>",
|
||||
logger.Infof("register instance namespaceId:<%s>,serviceName:<%s> with instance:<%s>",
|
||||
proxy.clientConfig.NamespaceId, serviceName, util.ToJsonString(instance))
|
||||
proxy.eventListener.CacheInstanceForRedo(serviceName, groupName, instance)
|
||||
instanceRequest := rpc_request.NewInstanceRequest(proxy.clientConfig.NamespaceId, serviceName, groupName, "registerInstance", instance)
|
||||
response, err := proxy.requestToServer(instanceRequest)
|
||||
proxy.eventListener.CacheInstanceForRedo(serviceName, groupName, instance)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return response.IsSuccess(), err
|
||||
}
|
||||
|
||||
// BatchRegisterInstance ...
|
||||
func (proxy *NamingGrpcProxy) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) {
|
||||
logger.Infof("batch register instance namespaceId:<%s>,serviceName:<%s> with instance:<%s>",
|
||||
proxy.clientConfig.NamespaceId, serviceName, util.ToJsonString(instances))
|
||||
proxy.eventListener.CacheInstancesForRedo(serviceName, groupName, instances)
|
||||
batchInstanceRequest := rpc_request.NewBatchInstanceRequest(proxy.clientConfig.NamespaceId, serviceName, groupName, "batchRegisterInstance", instances)
|
||||
response, err := proxy.requestToServer(batchInstanceRequest)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -145,8 +158,8 @@ func (proxy *NamingGrpcProxy) ServerHealthy() bool {
|
|||
}
|
||||
|
||||
// QueryInstancesOfService ...
|
||||
func (proxy *NamingGrpcProxy) QueryInstancesOfService(serviceName, groupName, clusters string, udpPort int, healthyOnly bool) (*model.Service, error) {
|
||||
response, err := proxy.requestToServer(rpc_request.NewServiceQueryRequest(proxy.clientConfig.NamespaceId, serviceName, groupName, clusters,
|
||||
func (proxy *NamingGrpcProxy) QueryInstancesOfService(serviceName, groupName, cluster string, udpPort int, healthyOnly bool) (*model.Service, error) {
|
||||
response, err := proxy.requestToServer(rpc_request.NewServiceQueryRequest(proxy.clientConfig.NamespaceId, serviceName, groupName, cluster,
|
||||
healthyOnly, udpPort))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -161,6 +174,8 @@ func (proxy *NamingGrpcProxy) IsSubscribed(serviceName, groupName string, cluste
|
|||
|
||||
// Subscribe ...
|
||||
func (proxy *NamingGrpcProxy) Subscribe(serviceName, groupName string, clusters string) (model.Service, error) {
|
||||
logger.Infof("Subscribe Service namespaceId:<%s>, serviceName:<%s>, groupName:<%s>, clusters:<%s>",
|
||||
proxy.clientConfig.NamespaceId, serviceName, groupName, clusters)
|
||||
proxy.eventListener.CacheSubscriberForRedo(util.GetGroupName(serviceName, groupName), clusters)
|
||||
request := rpc_request.NewSubscribeServiceRequest(proxy.clientConfig.NamespaceId, serviceName,
|
||||
groupName, clusters, true)
|
||||
|
@ -175,6 +190,8 @@ func (proxy *NamingGrpcProxy) Subscribe(serviceName, groupName string, clusters
|
|||
|
||||
// Unsubscribe ...
|
||||
func (proxy *NamingGrpcProxy) Unsubscribe(serviceName, groupName, clusters string) error {
|
||||
logger.Infof("Unsubscribe Service namespaceId:<%s>, serviceName:<%s>, groupName:<%s>, clusters:<%s>",
|
||||
proxy.clientConfig.NamespaceId, serviceName, groupName, clusters)
|
||||
proxy.eventListener.RemoveSubscriberForRedo(util.GetGroupName(serviceName, groupName), clusters)
|
||||
_, err := proxy.requestToServer(rpc_request.NewSubscribeServiceRequest(proxy.clientConfig.NamespaceId, serviceName, groupName,
|
||||
clusters, false))
|
||||
|
@ -182,5 +199,6 @@ func (proxy *NamingGrpcProxy) Unsubscribe(serviceName, groupName, clusters strin
|
|||
}
|
||||
|
||||
func (proxy *NamingGrpcProxy) CloseClient() {
|
||||
logger.Info("Close Nacos Go SDK Client...")
|
||||
proxy.rpcClient.GetRpcClient().Shutdown()
|
||||
}
|
||||
|
|
|
@ -9,6 +9,10 @@ func (m *MockNamingGrpc) RegisterInstance(serviceName string, groupName string,
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (m *MockNamingGrpc) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m *MockNamingGrpc) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
@ -29,4 +33,8 @@ func (m *MockNamingGrpc) Subscribe(serviceName, groupName, clusters string) (mod
|
|||
return model.Service{}, nil
|
||||
}
|
||||
|
||||
func (m *MockNamingGrpc) Unsubscribe(serviceName, groupName, clusters string) {}
|
||||
func (m *MockNamingGrpc) Unsubscribe(serviceName, groupName, clusters string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *MockNamingGrpc) CloseClient() {}
|
||||
|
|
|
@ -18,7 +18,6 @@ package naming_http
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
@ -97,6 +96,10 @@ func (proxy *NamingHttpProxy) RegisterInstance(serviceName string, groupName str
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingHttpProxy) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// DeregisterInstance ...
|
||||
func (proxy *NamingHttpProxy) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
serviceName = util.GetGroupName(serviceName, groupName)
|
||||
|
@ -148,14 +151,14 @@ func (proxy *NamingHttpProxy) GetServiceList(pageNo uint32, pageSize uint32, gro
|
|||
|
||||
count, err := jsonparser.GetInt([]byte(result), "count")
|
||||
if err != nil {
|
||||
return serviceList, errors.New(fmt.Sprintf("namespaceId:<%s> get service list pageNo:<%d> pageSize:<%d> selector:<%s> from <%s> get 'count' from <%s> error:<%+v>", namespaceId, pageNo, pageSize, util.ToJsonString(selector), groupName, result, err))
|
||||
return serviceList, errors.Errorf("namespaceId:<%s> get service list pageNo:<%d> pageSize:<%d> selector:<%s> from <%s> get 'count' from <%s> error:<%+v>", namespaceId, pageNo, pageSize, util.ToJsonString(selector), groupName, result, err)
|
||||
}
|
||||
var doms []string
|
||||
_, err = jsonparser.ArrayEach([]byte(result), func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
|
||||
doms = append(doms, string(value))
|
||||
}, "doms")
|
||||
if err != nil {
|
||||
return serviceList, errors.New(fmt.Sprintf("namespaceId:<%s> get service list pageNo:<%d> pageSize:<%d> selector:<%s> from <%s> get 'doms' from <%s> error:<%+v> ", namespaceId, pageNo, pageSize, util.ToJsonString(selector), groupName, result, err))
|
||||
return serviceList, errors.Errorf("namespaceId:<%s> get service list pageNo:<%d> pageSize:<%d> selector:<%s> from <%s> get 'doms' from <%s> error:<%+v> ", namespaceId, pageNo, pageSize, util.ToJsonString(selector), groupName, result, err)
|
||||
}
|
||||
serviceList.Count = count
|
||||
serviceList.Doms = doms
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
"compress/gzip"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net"
|
||||
"strconv"
|
||||
|
@ -168,7 +168,7 @@ func TryDecompressData(data []byte) string {
|
|||
}
|
||||
|
||||
defer reader.Close()
|
||||
bs, err := ioutil.ReadAll(reader)
|
||||
bs, err := io.ReadAll(reader)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("failed to decompress gzip data,err:%+v", err)
|
||||
|
|
|
@ -24,6 +24,8 @@ import (
|
|||
type INamingProxy interface {
|
||||
RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error)
|
||||
|
||||
BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error)
|
||||
|
||||
DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error)
|
||||
|
||||
GetServiceList(pageNo uint32, pageSize uint32, groupName, namespaceId string, selector *model.ExpressionSelector) (model.ServiceList, error)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: proxy_interface.go
|
||||
// Source: clients/naming_client/naming_proxy/proxy_interface.go
|
||||
|
||||
// Package naming_proxy is a generated GoMock package.
|
||||
package naming_proxy
|
||||
|
@ -34,6 +34,21 @@ func (m *MockINamingProxy) EXPECT() *MockINamingProxyMockRecorder {
|
|||
return m.recorder
|
||||
}
|
||||
|
||||
// BatchRegisterInstance mocks base method.
|
||||
func (m *MockINamingProxy) BatchRegisterInstance(serviceName, groupName string, instances []model.Instance) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BatchRegisterInstance", serviceName, groupName, instances)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// BatchRegisterInstance indicates an expected call of BatchRegisterInstance.
|
||||
func (mr *MockINamingProxyMockRecorder) BatchRegisterInstance(serviceName, groupName, instances interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BatchRegisterInstance", reflect.TypeOf((*MockINamingProxy)(nil).BatchRegisterInstance), serviceName, groupName, instances)
|
||||
}
|
||||
|
||||
// CloseClient mocks base method.
|
||||
func (m *MockINamingProxy) CloseClient() {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -64,7 +79,7 @@ func (mr *MockINamingProxyMockRecorder) DeregisterInstance(serviceName, groupNam
|
|||
// GetServiceList mocks base method.
|
||||
func (m *MockINamingProxy) GetServiceList(pageNo, pageSize uint32, groupName, namespaceId string, selector *model.ExpressionSelector) (model.ServiceList, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetServiceList", pageNo, pageSize, groupName, selector)
|
||||
ret := m.ctrl.Call(m, "GetServiceList", pageNo, pageSize, groupName, namespaceId, selector)
|
||||
ret0, _ := ret[0].(model.ServiceList)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
|
@ -73,7 +88,7 @@ func (m *MockINamingProxy) GetServiceList(pageNo, pageSize uint32, groupName, na
|
|||
// GetServiceList indicates an expected call of GetServiceList.
|
||||
func (mr *MockINamingProxyMockRecorder) GetServiceList(pageNo, pageSize, groupName, namespaceId, selector interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceList", reflect.TypeOf((*MockINamingProxy)(nil).GetServiceList), pageNo, pageSize, groupName, selector)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServiceList", reflect.TypeOf((*MockINamingProxy)(nil).GetServiceList), pageNo, pageSize, groupName, namespaceId, selector)
|
||||
}
|
||||
|
||||
// QueryInstancesOfService mocks base method.
|
||||
|
|
|
@ -18,6 +18,8 @@ package naming_client
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/inner/uuid"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_grpc"
|
||||
|
@ -39,8 +41,23 @@ type NamingProxyDelegate struct {
|
|||
|
||||
func NewNamingProxyDelegate(ctx context.Context, clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig,
|
||||
httpAgent http_agent.IHttpAgent, serviceInfoHolder *naming_cache.ServiceInfoHolder) (naming_proxy.INamingProxy, error) {
|
||||
return NewNamingProxyDelegateWithRamCredentialProvider(ctx, clientCfg, serverCfgs, httpAgent, serviceInfoHolder, nil)
|
||||
}
|
||||
|
||||
nacosServer, err := nacos_server.NewNacosServer(ctx, serverCfgs, clientCfg, httpAgent, clientCfg.TimeoutMs, clientCfg.Endpoint)
|
||||
func NewNamingProxyDelegateWithRamCredentialProvider(ctx context.Context, clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig,
|
||||
httpAgent http_agent.IHttpAgent, serviceInfoHolder *naming_cache.ServiceInfoHolder, provider security.RamCredentialProvider) (naming_proxy.INamingProxy, error) {
|
||||
|
||||
uid, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
namingHeader := map[string][]string{
|
||||
"Client-Version": {constant.CLIENT_VERSION},
|
||||
"User-Agent": {constant.CLIENT_VERSION},
|
||||
"RequestId": {uid.String()},
|
||||
"Request-Module": {"Naming"},
|
||||
}
|
||||
nacosServer, err := nacos_server.NewNacosServerWithRamCredentialProvider(ctx, serverCfgs, clientCfg, httpAgent, clientCfg.TimeoutMs, clientCfg.Endpoint, namingHeader, provider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -75,6 +92,10 @@ func (proxy *NamingProxyDelegate) RegisterInstance(serviceName string, groupName
|
|||
return proxy.getExecuteClientProxy(instance).RegisterInstance(serviceName, groupName, instance)
|
||||
}
|
||||
|
||||
func (proxy *NamingProxyDelegate) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) {
|
||||
return proxy.grpcClientProxy.BatchRegisterInstance(serviceName, groupName, instances)
|
||||
}
|
||||
|
||||
func (proxy *NamingProxyDelegate) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
return proxy.getExecuteClientProxy(instance).DeregisterInstance(serviceName, groupName, instance)
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ func (s *ServiceInfoUpdater) updateServiceNow(serviceName, groupName, clusters s
|
|||
result, err := s.namingProxy.QueryInstancesOfService(serviceName, groupName, clusters, 0, false)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("QueryList return error!serviceName:%s cluster:%s err:%+v", serviceName, clusters, err)
|
||||
logger.Errorf("QueryInstances error, serviceName:%s, cluster:%s, err:%v", serviceName, clusters, err)
|
||||
return
|
||||
}
|
||||
s.serviceInfoHolder.ProcessService(result)
|
||||
|
|
|
@ -81,6 +81,27 @@ func WithEndpoint(endpoint string) ClientOption {
|
|||
}
|
||||
}
|
||||
|
||||
// WithEndpointContextPath ...
|
||||
func WithEndpointContextPath(endpointContextPath string) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
config.EndpointContextPath = endpointContextPath
|
||||
}
|
||||
}
|
||||
|
||||
// WithEndpointQueryParams ...
|
||||
func WithEndpointQueryParams(endpointQueryPrams string) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
config.EndpointQueryParams = endpointQueryPrams
|
||||
}
|
||||
}
|
||||
|
||||
// WithClusterName ...
|
||||
func WithClusterName(clusterName string) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
config.ClusterName = clusterName
|
||||
}
|
||||
}
|
||||
|
||||
// WithRegionId ...
|
||||
func WithRegionId(regionId string) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
|
@ -102,6 +123,12 @@ func WithSecretKey(secretKey string) ClientOption {
|
|||
}
|
||||
}
|
||||
|
||||
func WithRamConfig(ramConfig *RamConfig) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
config.RamConfig = ramConfig
|
||||
}
|
||||
}
|
||||
|
||||
// WithOpenKMS ...
|
||||
func WithOpenKMS(openKMS bool) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
|
@ -109,6 +136,25 @@ func WithOpenKMS(openKMS bool) ClientOption {
|
|||
}
|
||||
}
|
||||
|
||||
// WithOpenKMS ...
|
||||
func WithKMSVersion(kmsVersion KMSVersion) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
config.KMSVersion = kmsVersion
|
||||
}
|
||||
}
|
||||
|
||||
func WithKMSv3Config(kmsv3Config *KMSv3Config) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
config.KMSv3Config = kmsv3Config
|
||||
}
|
||||
}
|
||||
|
||||
func WithKMSConfig(kmsConfig *KMSConfig) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
config.KMSConfig = kmsConfig
|
||||
}
|
||||
}
|
||||
|
||||
// WithCacheDir ...
|
||||
func WithCacheDir(cacheDir string) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
|
@ -116,6 +162,13 @@ func WithCacheDir(cacheDir string) ClientOption {
|
|||
}
|
||||
}
|
||||
|
||||
// WithDisableUseSnapShot ...
|
||||
func WithDisableUseSnapShot(disableUseSnapShot bool) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
config.DisableUseSnapShot = disableUseSnapShot
|
||||
}
|
||||
}
|
||||
|
||||
// WithUpdateThreadNum ...
|
||||
func WithUpdateThreadNum(updateThreadNum int) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
|
@ -181,6 +234,13 @@ func WithLogRollingConfig(rollingConfig *ClientLogRollingConfig) ClientOption {
|
|||
|
||||
func WithTLS(tlsCfg TLSConfig) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
tlsCfg.Appointed = true
|
||||
config.TLSCfg = tlsCfg
|
||||
}
|
||||
}
|
||||
|
||||
func WithAppConnLabels(appConnLabels map[string]string) ClientOption {
|
||||
return func(config *ClientConfig) {
|
||||
config.AppConnLabels = appConnLabels
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,18 +27,23 @@ type ServerConfig struct {
|
|||
}
|
||||
|
||||
type ClientConfig struct {
|
||||
TimeoutMs uint64 // timeout for requesting Nacos server, default value is 10000ms
|
||||
ListenInterval uint64 // Deprecated
|
||||
BeatInterval int64 // the time interval for sending beat to server,default value is 5000ms
|
||||
NamespaceId string // the namespaceId of Nacos.When namespace is public, fill in the blank string here.
|
||||
AppName string // the appName
|
||||
AppKey string // the client identity information
|
||||
Endpoint string // the endpoint for get Nacos server addresses
|
||||
RegionId string // the regionId for kms
|
||||
AccessKey string // the AccessKey for kms
|
||||
SecretKey string // the SecretKey for kms
|
||||
OpenKMS bool // it's to open kms,default is false. https://help.aliyun.com/product/28933.html
|
||||
TimeoutMs uint64 // timeout for requesting Nacos server, default value is 10000ms
|
||||
ListenInterval uint64 // Deprecated
|
||||
BeatInterval int64 // the time interval for sending beat to server,default value is 5000ms
|
||||
NamespaceId string // the namespaceId of Nacos.When namespace is public, fill in the blank string here.
|
||||
AppName string // the appName
|
||||
AppKey string // the client identity information
|
||||
Endpoint string // the endpoint for get Nacos server addresses
|
||||
RegionId string // the regionId for kms
|
||||
AccessKey string // the AccessKey for kms
|
||||
SecretKey string // the SecretKey for kms
|
||||
RamConfig *RamConfig
|
||||
OpenKMS bool // it's to open kms, default is false. https://help.aliyun.com/product/28933.html
|
||||
KMSVersion KMSVersion // kms client version. https://help.aliyun.com/document_detail/380927.html
|
||||
KMSv3Config *KMSv3Config //KMSv3 configuration. https://help.aliyun.com/document_detail/601596.html
|
||||
KMSConfig *KMSConfig
|
||||
CacheDir string // the directory for persist nacos service info,default value is current path
|
||||
DisableUseSnapShot bool // It's a switch, default is false, means that when get remote config fail, use local cache file instead
|
||||
UpdateThreadNum int // the number of goroutine for update nacos service info,default value is 20
|
||||
NotLoadCacheAtStart bool // not to load persistent nacos service info in CacheDir at start time
|
||||
UpdateCacheWhenEmpty bool // update cache when get empty service instance from server
|
||||
|
@ -51,6 +56,11 @@ type ClientConfig struct {
|
|||
LogSampling *ClientLogSamplingConfig // the sampling config of log
|
||||
LogRollingConfig *ClientLogRollingConfig // log rolling config
|
||||
TLSCfg TLSConfig // tls Config
|
||||
AsyncUpdateService bool // open async update service by query
|
||||
EndpointContextPath string // the address server endpoint contextPath
|
||||
EndpointQueryParams string // the address server endpoint query params
|
||||
ClusterName string // the address server clusterName
|
||||
AppConnLabels map[string]string // app conn labels
|
||||
}
|
||||
|
||||
type ClientLogSamplingConfig struct {
|
||||
|
@ -87,9 +97,38 @@ type ClientLogRollingConfig struct {
|
|||
}
|
||||
|
||||
type TLSConfig struct {
|
||||
Appointed bool // Appointed or not ,if false,will get from env.
|
||||
Enable bool // enable tls
|
||||
TrustAll bool // trust all server
|
||||
CaFile string // clients use when verifying server certificates
|
||||
CertFile string // server use when verifying client certificates
|
||||
KeyFile string // server use when verifying client certificates
|
||||
ServerNameOverride string // serverNameOverride is for testing only
|
||||
}
|
||||
|
||||
type KMSv3Config struct {
|
||||
ClientKeyContent string
|
||||
Password string
|
||||
Endpoint string
|
||||
CaContent string
|
||||
}
|
||||
|
||||
type KMSConfig struct {
|
||||
Endpoint string
|
||||
OpenSSL string
|
||||
CaContent string
|
||||
}
|
||||
|
||||
type RamConfig struct {
|
||||
SecurityToken string
|
||||
SignatureRegionId string
|
||||
RamRoleName string
|
||||
RoleArn string
|
||||
Policy string
|
||||
RoleSessionName string
|
||||
RoleSessionExpiration int
|
||||
OIDCProviderArn string
|
||||
OIDCTokenFilePath string
|
||||
CredentialsURI string
|
||||
SecretName string
|
||||
}
|
||||
|
|
|
@ -18,83 +18,104 @@ package constant
|
|||
|
||||
import "time"
|
||||
|
||||
type KMSVersion string
|
||||
|
||||
const (
|
||||
KEY_USERNAME = "username"
|
||||
KEY_PASSWORD = "password"
|
||||
KEY_ENDPOINT = "endpoint"
|
||||
KEY_NAME_SPACE = "namespace"
|
||||
KEY_ACCESS_KEY = "accessKey"
|
||||
KEY_SECRET_KEY = "secretKey"
|
||||
KEY_SERVER_ADDR = "serverAddr"
|
||||
KEY_CONTEXT_PATH = "contextPath"
|
||||
KEY_ENCODE = "encode"
|
||||
KEY_DATA_ID = "dataId"
|
||||
KEY_GROUP = "group"
|
||||
KEY_TENANT = "tenant"
|
||||
KEY_DESC = "desc"
|
||||
KEY_APP_NAME = "appName"
|
||||
KEY_CONTENT = "content"
|
||||
KEY_TIMEOUT_MS = "timeoutMs"
|
||||
KEY_LISTEN_INTERVAL = "listenInterval"
|
||||
KEY_SERVER_CONFIGS = "serverConfigs"
|
||||
KEY_CLIENT_CONFIG = "clientConfig"
|
||||
KEY_TOKEN = "token"
|
||||
KEY_ACCESS_TOKEN = "accessToken"
|
||||
KEY_TOKEN_TTL = "tokenTtl"
|
||||
KEY_GLOBAL_ADMIN = "globalAdmin"
|
||||
KEY_TOKEN_REFRESH_WINDOW = "tokenRefreshWindow"
|
||||
WEB_CONTEXT = "/nacos"
|
||||
CONFIG_BASE_PATH = "/v1/cs"
|
||||
CONFIG_PATH = CONFIG_BASE_PATH + "/configs"
|
||||
CONFIG_AGG_PATH = "/datum.do"
|
||||
CONFIG_LISTEN_PATH = CONFIG_BASE_PATH + "/configs/listener"
|
||||
SERVICE_BASE_PATH = "/v1/ns"
|
||||
SERVICE_PATH = SERVICE_BASE_PATH + "/instance"
|
||||
SERVICE_INFO_PATH = SERVICE_BASE_PATH + "/service"
|
||||
SERVICE_SUBSCRIBE_PATH = SERVICE_PATH + "/list"
|
||||
NAMESPACE_PATH = "/v1/console/namespaces"
|
||||
SPLIT_CONFIG = string(rune(1))
|
||||
SPLIT_CONFIG_INNER = string(rune(2))
|
||||
KEY_LISTEN_CONFIGS = "Listening-Configs"
|
||||
KEY_SERVICE_NAME = "serviceName"
|
||||
KEY_IP = "ip"
|
||||
KEY_PORT = "port"
|
||||
KEY_WEIGHT = "weight"
|
||||
KEY_ENABLE = "enable"
|
||||
KEY_HEALTHY = "healthy"
|
||||
KEY_METADATA = "metadata"
|
||||
KEY_CLUSTER_NAME = "clusterName"
|
||||
KEY_CLUSTER = "cluster"
|
||||
KEY_BEAT = "beat"
|
||||
KEY_DOM = "dom"
|
||||
DEFAULT_CONTEXT_PATH = "/nacos"
|
||||
CLIENT_VERSION = "Nacos-Go-Client:v2.1.3"
|
||||
REQUEST_DOMAIN_RETRY_TIME = 3
|
||||
SERVICE_INFO_SPLITER = "@@"
|
||||
CONFIG_INFO_SPLITER = "@@"
|
||||
DEFAULT_NAMESPACE_ID = "public"
|
||||
DEFAULT_GROUP = "DEFAULT_GROUP"
|
||||
NAMING_INSTANCE_ID_SPLITTER = "#"
|
||||
DefaultClientErrorCode = "SDK.NacosError"
|
||||
DEFAULT_SERVER_SCHEME = "http"
|
||||
HTTPS_SERVER_SCHEME = "https"
|
||||
LABEL_SOURCE = "source"
|
||||
LABEL_SOURCE_SDK = "sdk"
|
||||
LABEL_MODULE = "module"
|
||||
LABEL_MODULE_CONFIG = "config"
|
||||
LABEL_MODULE_NAMING = "naming"
|
||||
RESPONSE_CODE_SUCCESS = 200
|
||||
UN_REGISTER = 301
|
||||
KEEP_ALIVE_TIME = 5
|
||||
DEFAULT_TIMEOUT_MILLS = 3000
|
||||
ALL_SYNC_INTERNAL = 5 * time.Minute
|
||||
CLIENT_APPNAME_HEADER = "Client-AppName"
|
||||
CLIENT_REQUEST_TS_HEADER = "Client-RequestTS"
|
||||
CLIENT_REQUEST_TOKEN_HEADER = "Client-RequestToken"
|
||||
EX_CONFIG_INFO = "exConfigInfo"
|
||||
CHARSET_KEY = "charset"
|
||||
LOG_FILE_NAME = "nacos-sdk.log"
|
||||
HTTPS_SERVER_PORT = 443
|
||||
GRPC = "grpc"
|
||||
FAILOVER_FILE_SUFFIX = "_failover"
|
||||
KMSv1 KMSVersion = "KMSv1"
|
||||
KMSv3 KMSVersion = "KMSv3"
|
||||
DEFAULT_KMS_VERSION KMSVersion = "" //to fit original version
|
||||
UNKNOWN_KMS_VERSION KMSVersion = "UNKNOWN_KMS_VERSION"
|
||||
)
|
||||
const (
|
||||
KEY_USERNAME = "username"
|
||||
KEY_PASSWORD = "password"
|
||||
KEY_ENDPOINT = "endpoint"
|
||||
KEY_NAME_SPACE = "namespace"
|
||||
KEY_ACCESS_KEY = "accessKey"
|
||||
KEY_SECRET_KEY = "secretKey"
|
||||
KEY_SERVER_ADDR = "serverAddr"
|
||||
KEY_CONTEXT_PATH = "contextPath"
|
||||
KEY_ENCODE = "encode"
|
||||
KEY_DATA_ID = "dataId"
|
||||
KEY_GROUP = "group"
|
||||
KEY_TENANT = "tenant"
|
||||
KEY_DESC = "desc"
|
||||
KEY_APP_NAME = "appName"
|
||||
KEY_CONTENT = "content"
|
||||
KEY_TIMEOUT_MS = "timeoutMs"
|
||||
KEY_LISTEN_INTERVAL = "listenInterval"
|
||||
KEY_SERVER_CONFIGS = "serverConfigs"
|
||||
KEY_CLIENT_CONFIG = "clientConfig"
|
||||
KEY_TOKEN = "token"
|
||||
KEY_ACCESS_TOKEN = "accessToken"
|
||||
KEY_TOKEN_TTL = "tokenTtl"
|
||||
KEY_GLOBAL_ADMIN = "globalAdmin"
|
||||
KEY_TOKEN_REFRESH_WINDOW = "tokenRefreshWindow"
|
||||
WEB_CONTEXT = "/nacos"
|
||||
CONFIG_BASE_PATH = "/v1/cs"
|
||||
CONFIG_PATH = CONFIG_BASE_PATH + "/configs"
|
||||
CONFIG_AGG_PATH = "/datum.do"
|
||||
CONFIG_LISTEN_PATH = CONFIG_BASE_PATH + "/configs/listener"
|
||||
SERVICE_BASE_PATH = "/v1/ns"
|
||||
SERVICE_PATH = SERVICE_BASE_PATH + "/instance"
|
||||
SERVICE_INFO_PATH = SERVICE_BASE_PATH + "/service"
|
||||
SERVICE_SUBSCRIBE_PATH = SERVICE_PATH + "/list"
|
||||
NAMESPACE_PATH = "/v1/console/namespaces"
|
||||
SPLIT_CONFIG = string(rune(1))
|
||||
SPLIT_CONFIG_INNER = string(rune(2))
|
||||
KEY_LISTEN_CONFIGS = "Listening-Configs"
|
||||
KEY_SERVICE_NAME = "serviceName"
|
||||
KEY_IP = "ip"
|
||||
KEY_PORT = "port"
|
||||
KEY_WEIGHT = "weight"
|
||||
KEY_ENABLE = "enable"
|
||||
KEY_HEALTHY = "healthy"
|
||||
KEY_METADATA = "metadata"
|
||||
KEY_CLUSTER_NAME = "clusterName"
|
||||
KEY_CLUSTER = "cluster"
|
||||
KEY_BEAT = "beat"
|
||||
KEY_DOM = "dom"
|
||||
DEFAULT_CONTEXT_PATH = "/nacos"
|
||||
CLIENT_VERSION = "Nacos-Go-Client:v2.3.3"
|
||||
REQUEST_DOMAIN_RETRY_TIME = 3
|
||||
SERVICE_INFO_SPLITER = "@@"
|
||||
CONFIG_INFO_SPLITER = "@@"
|
||||
DEFAULT_NAMESPACE_ID = "public"
|
||||
DEFAULT_GROUP = "DEFAULT_GROUP"
|
||||
NAMING_INSTANCE_ID_SPLITTER = "#"
|
||||
DefaultClientErrorCode = "SDK.NacosError"
|
||||
DEFAULT_SERVER_SCHEME = "http"
|
||||
HTTPS_SERVER_SCHEME = "https"
|
||||
LABEL_SOURCE = "source"
|
||||
LABEL_SOURCE_SDK = "sdk"
|
||||
LABEL_MODULE = "module"
|
||||
LABEL_MODULE_CONFIG = "config"
|
||||
LABEL_MODULE_NAMING = "naming"
|
||||
RESPONSE_CODE_SUCCESS = 200
|
||||
UN_REGISTER = 301
|
||||
KEEP_ALIVE_TIME = 5
|
||||
DEFAULT_TIMEOUT_MILLS = 3000
|
||||
ALL_SYNC_INTERNAL = 5 * time.Minute
|
||||
CLIENT_APPNAME_HEADER = "Client-AppName"
|
||||
APPNAME_HEADER = "AppName"
|
||||
CLIENT_REQUEST_TS_HEADER = "Client-RequestTS"
|
||||
CLIENT_REQUEST_TOKEN_HEADER = "Client-RequestToken"
|
||||
EX_CONFIG_INFO = "exConfigInfo"
|
||||
CHARSET_KEY = "charset"
|
||||
LOG_FILE_NAME = "nacos-sdk.log"
|
||||
HTTPS_SERVER_PORT = 443
|
||||
GRPC = "grpc"
|
||||
RpcPortOffset = 1000
|
||||
MSE_KMSv1_DEFAULT_KEY_ID = "alias/acs/mse"
|
||||
CONFIG_PUBLISH_REQUEST_NAME = "ConfigPublishRequest"
|
||||
CONFIG_QUERY_REQUEST_NAME = "ConfigQueryRequest"
|
||||
CONFIG_REMOVE_REQUEST_NAME = "ConfigRemoveRequest"
|
||||
INSTANCE_REQUEST_NAME = "InstanceRequest"
|
||||
BATCH_INSTANCE_REQUEST_NAME = "BatchInstanceRequest"
|
||||
SERVICE_LIST_REQUEST_NAME = "ServiceListRequest"
|
||||
SERVICE_QUERY_REQUEST_NAME = "ServiceQueryRequest"
|
||||
SUBSCRIBE_SERVICE_REQUEST_NAME = "SubscribeServiceRequest"
|
||||
NOTIFY_SUBSCRIBE_REQUEST_NAME = "NotifySubscriberRequest"
|
||||
CONFIG_BATCH_LISTEN_REQUEST_NAME = "ConfigBatchListenRequest"
|
||||
CONFIG_CHANGE_NOTIFY_REQUEST_NAME = "ConfigChangeNotifyRequest"
|
||||
)
|
||||
|
|
|
@ -34,35 +34,35 @@ func NewServerConfig(ipAddr string, port uint64, opts ...ServerOption) *ServerCo
|
|||
// ServerOption ...
|
||||
type ServerOption func(*ServerConfig)
|
||||
|
||||
//WithScheme set Scheme for server
|
||||
// WithScheme set Scheme for server
|
||||
func WithScheme(scheme string) ServerOption {
|
||||
return func(config *ServerConfig) {
|
||||
config.Scheme = scheme
|
||||
}
|
||||
}
|
||||
|
||||
//WithContextPath set contextPath for server
|
||||
// WithContextPath set contextPath for server
|
||||
func WithContextPath(contextPath string) ServerOption {
|
||||
return func(config *ServerConfig) {
|
||||
config.ContextPath = contextPath
|
||||
}
|
||||
}
|
||||
|
||||
//WithIpAddr set ip address for server
|
||||
// WithIpAddr set ip address for server
|
||||
func WithIpAddr(ipAddr string) ServerOption {
|
||||
return func(config *ServerConfig) {
|
||||
config.IpAddr = ipAddr
|
||||
}
|
||||
}
|
||||
|
||||
//WithPort set port for server
|
||||
// WithPort set port for server
|
||||
func WithPort(port uint64) ServerOption {
|
||||
return func(config *ServerConfig) {
|
||||
config.Port = port
|
||||
}
|
||||
}
|
||||
|
||||
//WithGrpcPort set grpc port for server
|
||||
// WithGrpcPort set grpc port for server
|
||||
func WithGrpcPort(port uint64) ServerOption {
|
||||
return func(config *ServerConfig) {
|
||||
config.GrpcPort = port
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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")
|
||||
)
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* 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)
|
||||
}
|
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* 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
|
||||
}
|
|
@ -18,19 +18,22 @@ package http_agent
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func delete(client *http.Client, path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) {
|
||||
if !strings.HasSuffix(path, "?") {
|
||||
path = path + "?"
|
||||
}
|
||||
for key, value := range params {
|
||||
path = path + key + "=" + value + "&"
|
||||
}
|
||||
if strings.HasSuffix(path, "&") {
|
||||
path = path[:len(path)-1]
|
||||
if len(params) > 0 {
|
||||
if !strings.HasSuffix(path, "?") {
|
||||
path = path + "?"
|
||||
}
|
||||
for key, value := range params {
|
||||
path = path + key + "=" + url.QueryEscape(value) + "&"
|
||||
}
|
||||
if strings.HasSuffix(path, "&") {
|
||||
path = path[:len(path)-1]
|
||||
}
|
||||
}
|
||||
client.Timeout = time.Millisecond * time.Duration(timeoutMs)
|
||||
request, errNew := http.NewRequest(http.MethodDelete, path, nil)
|
||||
|
|
|
@ -18,17 +18,21 @@ package http_agent
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func get(client *http.Client, path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) {
|
||||
if !strings.HasSuffix(path, "?") {
|
||||
if !strings.Contains(path, "?") {
|
||||
path = path + "?"
|
||||
}
|
||||
|
||||
for key, value := range params {
|
||||
path = path + key + "=" + value + "&"
|
||||
if !strings.HasSuffix(path, "&") {
|
||||
path = path + "&"
|
||||
}
|
||||
path = path + key + "=" + url.QueryEscape(value) + "&"
|
||||
}
|
||||
if strings.HasSuffix(path, "&") {
|
||||
path = path[:len(path)-1]
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package http_agent
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
|
@ -68,7 +68,7 @@ func (agent *HttpAgent) RequestOnlyResult(method string, path string, header htt
|
|||
logger.Errorf("request method[%s],request path[%s],header:[%s],params:[%s],status code error:%d", method, path, util.ToJsonString(header), util.ToJsonString(params), response.StatusCode)
|
||||
return ""
|
||||
}
|
||||
bytes, errRead := ioutil.ReadAll(response.Body)
|
||||
bytes, errRead := io.ReadAll(response.Body)
|
||||
defer response.Body.Close()
|
||||
if errRead != nil {
|
||||
logger.Errorf("request method[%s],request path[%s],header:[%s],params:[%s],read error:%+v", method, path, util.ToJsonString(header), util.ToJsonString(params), errRead)
|
||||
|
|
|
@ -110,6 +110,12 @@ func BuildLoggerConfig(clientConfig constant.ClientConfig) Config {
|
|||
loggerConfig.LogRollingConfig.MaxBackups = logRollingConfig.MaxBackups
|
||||
loggerConfig.LogRollingConfig.LocalTime = logRollingConfig.LocalTime
|
||||
loggerConfig.LogRollingConfig.Compress = logRollingConfig.Compress
|
||||
} else {
|
||||
loggerConfig.LogRollingConfig.MaxSize = 100
|
||||
loggerConfig.LogRollingConfig.MaxAge = 30
|
||||
loggerConfig.LogRollingConfig.MaxBackups = 5
|
||||
loggerConfig.LogRollingConfig.LocalTime = true
|
||||
loggerConfig.LogRollingConfig.Compress = false
|
||||
}
|
||||
return loggerConfig
|
||||
}
|
||||
|
@ -157,7 +163,7 @@ func getEncoder() zapcore.EncoderConfig {
|
|||
}
|
||||
}
|
||||
|
||||
//SetLogger sets logger for sdk
|
||||
// SetLogger sets logger for sdk
|
||||
func SetLogger(log Logger) {
|
||||
logLock.Lock()
|
||||
defer logLock.Unlock()
|
||||
|
|
|
@ -40,18 +40,13 @@ func TestGetLogger(t *testing.T) {
|
|||
// not yet init get default log
|
||||
log := GetLogger()
|
||||
config := Config{
|
||||
Level: "degug",
|
||||
Level: "debug",
|
||||
}
|
||||
_ = InitLogger(config)
|
||||
// after init logger
|
||||
log2 := GetLogger()
|
||||
assert.NotEqual(t, log, log2)
|
||||
|
||||
// the secend init logger
|
||||
config.Level = "info"
|
||||
_ = InitLogger(config)
|
||||
log3 := GetLogger()
|
||||
assert.NotEqual(t, log2, log3)
|
||||
reset()
|
||||
}
|
||||
|
||||
|
@ -66,13 +61,6 @@ func TestSetLogger(t *testing.T) {
|
|||
assert.NotEqual(t, log, log2)
|
||||
assert.Equal(t, log1, log2)
|
||||
|
||||
config := Config{
|
||||
Level: "degug",
|
||||
}
|
||||
_ = InitLogger(config)
|
||||
// after init logger
|
||||
log3 := GetLogger()
|
||||
assert.NotEqual(t, log2, log3)
|
||||
reset()
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,7 @@ package nacos_server
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
@ -34,8 +30,6 @@ import (
|
|||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/monitor"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
|
@ -49,7 +43,7 @@ import (
|
|||
|
||||
type NacosServer struct {
|
||||
sync.RWMutex
|
||||
securityLogin security.AuthClient
|
||||
securityLogin security.SecurityProxy
|
||||
serverList []constant.ServerConfig
|
||||
httpAgent http_agent.IHttpAgent
|
||||
timeoutMs uint64
|
||||
|
@ -57,17 +51,25 @@ type NacosServer struct {
|
|||
lastSrvRefTime int64
|
||||
vipSrvRefInterMills int64
|
||||
contextPath string
|
||||
endpointContextPath string
|
||||
endpointQueryParams string
|
||||
endpointQueryHeader map[string][]string
|
||||
clusterName string
|
||||
currentIndex int32
|
||||
ServerSrcChangeSignal chan struct{}
|
||||
}
|
||||
|
||||
func NewNacosServer(ctx context.Context, serverList []constant.ServerConfig, clientCfg constant.ClientConfig, httpAgent http_agent.IHttpAgent, timeoutMs uint64, endpoint string) (*NacosServer, error) {
|
||||
func NewNacosServer(ctx context.Context, serverList []constant.ServerConfig, clientCfg constant.ClientConfig, httpAgent http_agent.IHttpAgent, timeoutMs uint64, endpoint string, endpointQueryHeader map[string][]string) (*NacosServer, error) {
|
||||
return NewNacosServerWithRamCredentialProvider(ctx, serverList, clientCfg, httpAgent, timeoutMs, endpoint, endpointQueryHeader, nil)
|
||||
}
|
||||
|
||||
func NewNacosServerWithRamCredentialProvider(ctx context.Context, serverList []constant.ServerConfig, clientCfg constant.ClientConfig, httpAgent http_agent.IHttpAgent, timeoutMs uint64, endpoint string, endpointQueryHeader map[string][]string, provider security.RamCredentialProvider) (*NacosServer, error) {
|
||||
severLen := len(serverList)
|
||||
if severLen == 0 && endpoint == "" {
|
||||
return &NacosServer{}, errors.New("both serverlist and endpoint are empty")
|
||||
}
|
||||
|
||||
securityLogin := security.NewAuthClient(clientCfg, serverList, httpAgent)
|
||||
securityLogin := security.NewSecurityProxyWithRamCredentialProvider(clientCfg, serverList, httpAgent, provider)
|
||||
|
||||
ns := NacosServer{
|
||||
serverList: serverList,
|
||||
|
@ -76,21 +78,21 @@ func NewNacosServer(ctx context.Context, serverList []constant.ServerConfig, cli
|
|||
timeoutMs: timeoutMs,
|
||||
endpoint: endpoint,
|
||||
vipSrvRefInterMills: 10000,
|
||||
endpointContextPath: clientCfg.EndpointContextPath,
|
||||
endpointQueryParams: clientCfg.EndpointQueryParams,
|
||||
endpointQueryHeader: endpointQueryHeader,
|
||||
clusterName: clientCfg.ClusterName,
|
||||
contextPath: clientCfg.ContextPath,
|
||||
ServerSrcChangeSignal: make(chan struct{}, 1),
|
||||
}
|
||||
if severLen > 0 {
|
||||
ns.currentIndex = rand.Int31n(int32(severLen))
|
||||
} else {
|
||||
ns.initRefreshSrvIfNeed(ctx)
|
||||
}
|
||||
|
||||
ns.initRefreshSrvIfNeed(ctx)
|
||||
_, err := securityLogin.Login()
|
||||
|
||||
if err != nil {
|
||||
return &ns, err
|
||||
}
|
||||
|
||||
securityLogin.AutoRefresh(ctx)
|
||||
ns.securityLogin.Login()
|
||||
ns.securityLogin.AutoRefresh(ctx)
|
||||
return &ns, nil
|
||||
}
|
||||
|
||||
|
@ -101,8 +103,6 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
|
|||
contextPath = constant.WEB_CONTEXT
|
||||
}
|
||||
|
||||
signHeaders := GetSignHeaders(params, newHeaders["secretKey"])
|
||||
|
||||
url := curServer + contextPath + api
|
||||
|
||||
headers := map[string][]string{}
|
||||
|
@ -122,10 +122,6 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
|
|||
}
|
||||
headers["RequestId"] = []string{uid.String()}
|
||||
headers["Content-Type"] = []string{"application/x-www-form-urlencoded;charset=utf-8"}
|
||||
headers["Spas-AccessKey"] = []string{newHeaders["accessKey"]}
|
||||
headers["Timestamp"] = []string{signHeaders["Timestamp"]}
|
||||
headers["Spas-Signature"] = []string{signHeaders["Spas-Signature"]}
|
||||
server.InjectSecurityInfo(params)
|
||||
|
||||
var response *http.Response
|
||||
response, err = server.httpAgent.Request(method, url, headers, timeoutMS, params)
|
||||
|
@ -134,7 +130,7 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
|
|||
return
|
||||
}
|
||||
var bytes []byte
|
||||
bytes, err = ioutil.ReadAll(response.Body)
|
||||
bytes, err = io.ReadAll(response.Body)
|
||||
defer response.Body.Close()
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -169,15 +165,13 @@ func (server *NacosServer) callServer(api string, params map[string]string, meth
|
|||
headers["Request-Module"] = []string{"Naming"}
|
||||
headers["Content-Type"] = []string{"application/x-www-form-urlencoded;charset=utf-8"}
|
||||
|
||||
server.InjectSecurityInfo(params)
|
||||
|
||||
var response *http.Response
|
||||
response, err = server.httpAgent.Request(method, url, headers, server.timeoutMs, params)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var bytes []byte
|
||||
bytes, err = ioutil.ReadAll(response.Body)
|
||||
bytes, err = io.ReadAll(response.Body)
|
||||
defer response.Body.Close()
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -187,7 +181,7 @@ func (server *NacosServer) callServer(api string, params map[string]string, meth
|
|||
if response.StatusCode == constant.RESPONSE_CODE_SUCCESS {
|
||||
return
|
||||
} else {
|
||||
err = errors.New(fmt.Sprintf("request return error code %d", response.StatusCode))
|
||||
err = errors.Errorf("request return error code %d", response.StatusCode)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -198,7 +192,7 @@ func (server *NacosServer) ReqConfigApi(api string, params map[string]string, he
|
|||
return "", errors.New("server list is empty")
|
||||
}
|
||||
|
||||
server.InjectSecurityInfo(params)
|
||||
server.InjectSecurityInfo(params, security.BuildConfigResource(params["tenant"], params["group"], params["dataId"]))
|
||||
|
||||
//only one server,retry request when error
|
||||
var err error
|
||||
|
@ -232,8 +226,7 @@ func (server *NacosServer) ReqApi(api string, params map[string]string, method s
|
|||
return "", errors.New("server list is empty")
|
||||
}
|
||||
|
||||
server.InjectSecurityInfo(params)
|
||||
server.InjectSignForNamingHttp(params, config)
|
||||
server.InjectSecurityInfo(params, security.BuildNamingResource(params["namespaceId"], params["serviceName"], params["groupName"]))
|
||||
|
||||
//only one server,retry request when error
|
||||
var err error
|
||||
|
@ -265,31 +258,44 @@ func (server *NacosServer) initRefreshSrvIfNeed(ctx context.Context) {
|
|||
if server.endpoint == "" {
|
||||
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() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
default:
|
||||
time.Sleep(time.Duration(1) * time.Second)
|
||||
server.refreshServerSrvIfNeed()
|
||||
time.Sleep(time.Duration(10) * time.Second)
|
||||
server.refreshServerSrvIfNeed(urlString, server.endpointQueryHeader)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
func (server *NacosServer) refreshServerSrvIfNeed() {
|
||||
func (server *NacosServer) refreshServerSrvIfNeed(urlString string, header map[string][]string) {
|
||||
if util.CurrentMillis()-server.lastSrvRefTime < server.vipSrvRefInterMills && len(server.serverList) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var list []string
|
||||
urlString := "http://" + server.endpoint + "/nacos/serverlist"
|
||||
result := server.httpAgent.RequestOnlyResult(http.MethodGet, urlString, nil, server.timeoutMs, nil)
|
||||
|
||||
result := server.httpAgent.RequestOnlyResult(http.MethodGet, urlString, header, server.timeoutMs, nil)
|
||||
list = strings.Split(result, "\n")
|
||||
logger.Infof("http nacos server list: <%s>", result)
|
||||
|
||||
var servers []constant.ServerConfig
|
||||
contextPath := server.contextPath
|
||||
|
@ -315,10 +321,15 @@ func (server *NacosServer) refreshServerSrvIfNeed() {
|
|||
if len(servers) > 0 {
|
||||
if !reflect.DeepEqual(server.serverList, servers) {
|
||||
server.Lock()
|
||||
logger.Infof("server list is updated, old: <%v>,new:<%v>", server.serverList, servers)
|
||||
var serverPrev = server.serverList
|
||||
logger.Infof("server list is updated, old: <%v>,new:<%v>", serverPrev, servers)
|
||||
|
||||
server.serverList = servers
|
||||
server.ServerSrcChangeSignal <- struct{}{}
|
||||
if serverPrev != nil {
|
||||
server.ServerSrcChangeSignal <- struct{}{}
|
||||
}
|
||||
server.lastSrvRefTime = util.CurrentMillis()
|
||||
server.securityLogin.UpdateServerList(servers)
|
||||
server.Unlock()
|
||||
}
|
||||
|
||||
|
@ -330,47 +341,13 @@ func (server *NacosServer) GetServerList() []constant.ServerConfig {
|
|||
return server.serverList
|
||||
}
|
||||
|
||||
func (server *NacosServer) InjectSecurityInfo(param map[string]string) {
|
||||
accessToken := server.securityLogin.GetAccessToken()
|
||||
if accessToken != "" {
|
||||
param[constant.KEY_ACCESS_TOKEN] = accessToken
|
||||
func (server *NacosServer) InjectSecurityInfo(param map[string]string, resource security.RequestResource) {
|
||||
securityInfo := server.securityLogin.GetSecurityInfo(resource)
|
||||
for k, v := range securityInfo {
|
||||
param[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (server *NacosServer) 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 {
|
||||
if strings.Index(cfg.IpAddr, "http://") >= 0 || strings.Index(cfg.IpAddr, "https://") >= 0 {
|
||||
return cfg.IpAddr + ":" + strconv.Itoa(int(cfg.Port))
|
||||
|
@ -378,69 +355,6 @@ func getAddress(cfg constant.ServerConfig) string {
|
|||
return cfg.Scheme + "://" + cfg.IpAddr + ":" + strconv.Itoa(int(cfg.Port))
|
||||
}
|
||||
|
||||
func GetSignHeadersFromRequest(cr rpc_request.IConfigRequest, secretKey string) map[string]string {
|
||||
resource := ""
|
||||
|
||||
if len(cr.GetGroup()) != 0 {
|
||||
resource = cr.GetTenant() + "+" + cr.GetGroup()
|
||||
} else {
|
||||
resource = cr.GetGroup()
|
||||
}
|
||||
|
||||
headers := map[string]string{}
|
||||
|
||||
timeStamp := strconv.FormatInt(util.CurrentMillis(), 10)
|
||||
headers["Timestamp"] = timeStamp
|
||||
|
||||
signature := ""
|
||||
|
||||
if resource == "" {
|
||||
signature = signWithhmacSHA1Encrypt(timeStamp, secretKey)
|
||||
} else {
|
||||
signature = signWithhmacSHA1Encrypt(resource+"+"+timeStamp, secretKey)
|
||||
}
|
||||
|
||||
headers["Spas-Signature"] = signature
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
func GetSignHeaders(params map[string]string, secretKey string) map[string]string {
|
||||
resource := ""
|
||||
|
||||
if len(params["tenant"]) != 0 {
|
||||
resource = params["tenant"] + "+" + params["group"]
|
||||
} else {
|
||||
resource = params["group"]
|
||||
}
|
||||
|
||||
headers := map[string]string{}
|
||||
|
||||
timeStamp := strconv.FormatInt(util.CurrentMillis(), 10)
|
||||
headers["Timestamp"] = timeStamp
|
||||
|
||||
signature := ""
|
||||
|
||||
if resource == "" {
|
||||
signature = signWithhmacSHA1Encrypt(timeStamp, secretKey)
|
||||
} else {
|
||||
signature = signWithhmacSHA1Encrypt(resource+"+"+timeStamp, secretKey)
|
||||
}
|
||||
|
||||
headers["Spas-Signature"] = signature
|
||||
|
||||
return headers
|
||||
}
|
||||
|
||||
func signWithhmacSHA1Encrypt(encryptText, encryptKey string) string {
|
||||
//hmac ,use sha1
|
||||
key := []byte(encryptKey)
|
||||
mac := hmac.New(sha1.New, key)
|
||||
mac.Write([]byte(encryptText))
|
||||
|
||||
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
|
||||
}
|
||||
|
||||
func (server *NacosServer) GetNextServer() (constant.ServerConfig, error) {
|
||||
serverLen := len(server.GetServerList())
|
||||
if serverLen == 0 {
|
||||
|
@ -449,9 +363,3 @@ func (server *NacosServer) GetNextServer() (constant.ServerConfig, error) {
|
|||
index := atomic.AddInt32(&server.currentIndex, 1) % int32(serverLen)
|
||||
return server.GetServerList()[index], nil
|
||||
}
|
||||
|
||||
func (server *NacosServer) InjectSkAk(params map[string]string, clientConfig constant.ClientConfig) {
|
||||
if clientConfig.AccessKey != "" {
|
||||
params["Spas-AccessKey"] = clientConfig.AccessKey
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,11 @@ package nacos_server
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
|
||||
"testing"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -55,23 +57,24 @@ func buildNacosServer(clientConfig constant.ClientConfig) (*NacosServer, error)
|
|||
clientConfig,
|
||||
&http_agent.HttpAgent{},
|
||||
1000,
|
||||
"")
|
||||
"",
|
||||
nil)
|
||||
}
|
||||
|
||||
func TestNacosServer_InjectSignForNamingHttp_NoAk(t *testing.T) {
|
||||
clientConfig := constant.ClientConfig{
|
||||
AccessKey: "123",
|
||||
SecretKey: "321",
|
||||
AccessKey: "",
|
||||
SecretKey: "",
|
||||
}
|
||||
server, err := buildNacosServer(clientConfig)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
param := make(map[string]string)
|
||||
param := make(map[string]string, 4)
|
||||
param["serviceName"] = "s-0"
|
||||
param["groupName"] = "g-0"
|
||||
server.InjectSignForNamingHttp(param, constant.ClientConfig{})
|
||||
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"]))
|
||||
assert.Empty(t, param["ak"])
|
||||
assert.Empty(t, param["data"])
|
||||
assert.Empty(t, param["signature"])
|
||||
|
@ -87,10 +90,10 @@ func TestNacosServer_InjectSignForNamingHttp_WithGroup(t *testing.T) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
param := make(map[string]string)
|
||||
param := make(map[string]string, 4)
|
||||
param["serviceName"] = "s-0"
|
||||
param["groupName"] = "g-0"
|
||||
server.InjectSignForNamingHttp(param, clientConfig)
|
||||
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"]))
|
||||
assert.Equal(t, "123", param["ak"])
|
||||
assert.Contains(t, param["data"], "@@g-0@@s-0")
|
||||
_, has := param["signature"]
|
||||
|
@ -107,9 +110,9 @@ func TestNacosServer_InjectSignForNamingHttp_WithoutGroup(t *testing.T) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
param := make(map[string]string)
|
||||
param := make(map[string]string, 4)
|
||||
param["serviceName"] = "s-0"
|
||||
server.InjectSignForNamingHttp(param, clientConfig)
|
||||
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"]))
|
||||
assert.Equal(t, "123", param["ak"])
|
||||
assert.NotContains(t, param["data"], "@@g-0@@s-0")
|
||||
assert.Contains(t, param["data"], "@@s-0")
|
||||
|
@ -127,11 +130,11 @@ func TestNacosServer_InjectSignForNamingHttp_WithoutServiceName(t *testing.T) {
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
param := make(map[string]string)
|
||||
param := make(map[string]string, 4)
|
||||
param["groupName"] = "g-0"
|
||||
server.InjectSignForNamingHttp(param, clientConfig)
|
||||
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["groupName"], param["serviceName"]))
|
||||
assert.Equal(t, "123", param["ak"])
|
||||
assert.NotContains(t, param["data"], "@@")
|
||||
assert.Contains(t, param["data"], "@@")
|
||||
assert.Regexp(t, "\\d+", param["data"])
|
||||
_, has := param["signature"]
|
||||
assert.True(t, has)
|
||||
|
@ -147,11 +150,38 @@ func TestNacosServer_InjectSignForNamingHttp_WithoutServiceNameAndGroup(t *testi
|
|||
t.FailNow()
|
||||
}
|
||||
|
||||
param := make(map[string]string)
|
||||
server.InjectSignForNamingHttp(param, clientConfig)
|
||||
param := make(map[string]string, 4)
|
||||
server.InjectSecurityInfo(param, security.BuildNamingResource(param["namespaceId"], param["serviceName"], param["groupName"]))
|
||||
assert.Equal(t, "123", param["ak"])
|
||||
assert.NotContains(t, param["data"], "@@")
|
||||
assert.Regexp(t, "\\d+", param["data"])
|
||||
_, has := param["signature"]
|
||||
assert.True(t, has)
|
||||
}
|
||||
|
||||
func TestNacosServer_UpdateServerListForSecurityLogin(t *testing.T) {
|
||||
endpoint := "console.nacos.io:80"
|
||||
clientConfig := constant.ClientConfig{
|
||||
Username: "nacos",
|
||||
Password: "nacos",
|
||||
NamespaceId: "namespace_1",
|
||||
Endpoint: endpoint,
|
||||
EndpointContextPath: "nacos",
|
||||
ClusterName: "serverlist",
|
||||
AppendToStdout: true,
|
||||
}
|
||||
server, err := NewNacosServer(context.Background(),
|
||||
nil,
|
||||
clientConfig,
|
||||
&http_agent.HttpAgent{},
|
||||
1000,
|
||||
endpoint,
|
||||
nil)
|
||||
if err != nil {
|
||||
t.FailNow()
|
||||
}
|
||||
nacosAuthClient := server.securityLogin.Clients[0]
|
||||
client, ok := nacosAuthClient.(*security.NacosAuthClient)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, server.GetServerList(), client.GetServerList())
|
||||
}
|
||||
|
|
|
@ -55,5 +55,5 @@ func (c *Connection) getAbandon() bool {
|
|||
}
|
||||
|
||||
func (c *Connection) close() {
|
||||
c.conn.Close()
|
||||
_ = c.conn.Close()
|
||||
}
|
||||
|
|
|
@ -18,8 +18,13 @@ package rpc
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
|
@ -41,21 +46,21 @@ import (
|
|||
|
||||
type GrpcClient struct {
|
||||
*RpcClient
|
||||
*constant.TLSConfig
|
||||
}
|
||||
|
||||
func NewGrpcClient(ctx context.Context, clientName string, nacosServer *nacos_server.NacosServer) *GrpcClient {
|
||||
func NewGrpcClient(ctx context.Context, clientName string, nacosServer *nacos_server.NacosServer, tlsConfig *constant.TLSConfig) *GrpcClient {
|
||||
rpcClient := &GrpcClient{
|
||||
&RpcClient{
|
||||
ctx: ctx,
|
||||
name: clientName,
|
||||
labels: make(map[string]string, 8),
|
||||
rpcClientStatus: INITIALIZED,
|
||||
eventChan: make(chan ConnectionEvent),
|
||||
reconnectionChan: make(chan ReconnectContext),
|
||||
nacosServer: nacosServer,
|
||||
serverRequestHandlerMapping: make(map[string]ServerRequestHandlerMapping, 8),
|
||||
mux: new(sync.Mutex),
|
||||
},
|
||||
ctx: ctx,
|
||||
name: clientName,
|
||||
labels: make(map[string]string, 8),
|
||||
rpcClientStatus: INITIALIZED,
|
||||
eventChan: make(chan ConnectionEvent, 1),
|
||||
reconnectionChan: make(chan ReconnectContext, 1),
|
||||
nacosServer: nacosServer,
|
||||
mux: new(sync.Mutex),
|
||||
}, tlsConfig,
|
||||
}
|
||||
rpcClient.RpcClient.lastActiveTimestamp.Store(time.Now())
|
||||
rpcClient.executeClient = rpcClient
|
||||
|
@ -88,6 +93,41 @@ func getInitialConnWindowSize() int32 {
|
|||
return int32(initialConnWindowSize)
|
||||
}
|
||||
|
||||
func getTLSCredentials(tlsConfig *constant.TLSConfig, serverInfo ServerInfo) credentials.TransportCredentials {
|
||||
|
||||
logger.Infof("build tls config for connecting to server %s,tlsConfig = %s", serverInfo.serverIp, tlsConfig)
|
||||
|
||||
certPool, err := x509.SystemCertPool()
|
||||
if err != nil {
|
||||
log.Fatalf("load root cert pool fail : %v", err)
|
||||
}
|
||||
if len(tlsConfig.CaFile) != 0 {
|
||||
cert, err := os.ReadFile(tlsConfig.CaFile)
|
||||
if err != nil {
|
||||
fmt.Errorf("err, %v", err)
|
||||
}
|
||||
if ok := certPool.AppendCertsFromPEM(cert); !ok {
|
||||
fmt.Errorf("failed to append ca certs")
|
||||
}
|
||||
}
|
||||
|
||||
config := tls.Config{
|
||||
InsecureSkipVerify: tlsConfig.TrustAll,
|
||||
RootCAs: certPool,
|
||||
Certificates: []tls.Certificate{},
|
||||
}
|
||||
if len(tlsConfig.CertFile) != 0 && len(tlsConfig.KeyFile) != 0 {
|
||||
cert, err := tls.LoadX509KeyPair(tlsConfig.CertFile, tlsConfig.KeyFile)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("load cert fail : %v", err)
|
||||
}
|
||||
config.Certificates = append(config.Certificates, cert)
|
||||
}
|
||||
credentials := credentials.NewTLS(&config)
|
||||
return credentials
|
||||
}
|
||||
|
||||
func getInitialGrpcTimeout() int32 {
|
||||
initialGrpcTimeout, err := strconv.Atoi(os.Getenv("nacos.remote.client.grpc.timeout"))
|
||||
if err != nil {
|
||||
|
@ -118,6 +158,11 @@ func (c *GrpcClient) createNewConnection(serverInfo ServerInfo) (*grpc.ClientCon
|
|||
opts = append(opts, grpc.WithInsecure())
|
||||
opts = append(opts, grpc.WithInitialWindowSize(getInitialWindowSize()))
|
||||
opts = append(opts, grpc.WithInitialConnWindowSize(getInitialConnWindowSize()))
|
||||
c.getEnvTLSConfig(c.TLSConfig)
|
||||
if c.TLSConfig.Enable {
|
||||
logger.Infof(" tls enable ,trying to connection to server %s with tls config %s", serverInfo.serverIp, c.TLSConfig)
|
||||
opts = append(opts, grpc.WithTransportCredentials(getTLSCredentials(c.TLSConfig, serverInfo)))
|
||||
}
|
||||
rpcPort := serverInfo.serverGrpcPort
|
||||
if rpcPort == 0 {
|
||||
rpcPort = serverInfo.serverPort + c.rpcPortOffset()
|
||||
|
@ -126,30 +171,62 @@ func (c *GrpcClient) createNewConnection(serverInfo ServerInfo) (*grpc.ClientCon
|
|||
|
||||
}
|
||||
|
||||
func (c *GrpcClient) getEnvTLSConfig(config *constant.TLSConfig) {
|
||||
logger.Infof("check tls config ", config)
|
||||
|
||||
if config.Appointed == true {
|
||||
return
|
||||
}
|
||||
logger.Infof("try to get tls config from env")
|
||||
|
||||
enableTls, err := strconv.ParseBool(os.Getenv("nacos_remote_client_rpc_tls_enable"))
|
||||
if err == nil {
|
||||
config.Enable = enableTls
|
||||
logger.Infof("get tls config from env ,key = enableTls value = %s", enableTls)
|
||||
}
|
||||
|
||||
if enableTls != true {
|
||||
logger.Infof(" tls config from env is not enable")
|
||||
return
|
||||
}
|
||||
trustAll, err := strconv.ParseBool(os.Getenv("nacos_remote_client_rpc_tls_trustAll"))
|
||||
if err == nil {
|
||||
config.TrustAll = trustAll
|
||||
logger.Infof("get tls config from env ,key = trustAll value = %s", trustAll)
|
||||
}
|
||||
|
||||
config.CaFile = os.Getenv("nacos_remote_client_rpc_tls_trustCollectionChainPath")
|
||||
logger.Infof("get tls config from env ,key = trustCollectionChainPath value = %s", config.CaFile)
|
||||
config.CertFile = os.Getenv("nacos_remote_client_rpc_tls_certChainFile")
|
||||
logger.Infof("get tls config from env ,key = certChainFile value = %s", config.CertFile)
|
||||
config.KeyFile = os.Getenv("nacos_remote_client_rpc_tls_certPrivateKey")
|
||||
logger.Infof("get tls config from env ,key = certPrivateKey value = %s", config.KeyFile)
|
||||
|
||||
}
|
||||
|
||||
func (c *GrpcClient) connectToServer(serverInfo ServerInfo) (IConnection, error) {
|
||||
var client nacos_grpc_service.RequestClient
|
||||
var biStreamClient nacos_grpc_service.BiRequestStreamClient
|
||||
|
||||
conn, err := c.createNewConnection(serverInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Errorf("grpc create new connection failed , err:%v", err)
|
||||
}
|
||||
|
||||
client = nacos_grpc_service.NewRequestClient(conn)
|
||||
response, err := serverCheck(client)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
_ = conn.Close()
|
||||
return nil, errors.Errorf("server check request failed , err:%v", err)
|
||||
}
|
||||
|
||||
biStreamClient = nacos_grpc_service.NewBiRequestStreamClient(conn)
|
||||
|
||||
serverCheckResponse := response.(*rpc_response.ServerCheckResponse)
|
||||
|
||||
biStreamClient = nacos_grpc_service.NewBiRequestStreamClient(conn)
|
||||
biStreamRequestClient, err := biStreamClient.RequestBiStream(context.Background())
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("create biStreamRequestClient failed , err:%v", err)
|
||||
}
|
||||
grpcConn := NewGrpcConnection(serverInfo, serverCheckResponse.ConnectionId, conn, client, biStreamRequestClient)
|
||||
|
||||
c.bindBiRequestStream(biStreamRequestClient, grpcConn)
|
||||
err = c.sendConnectionSetupRequest(grpcConn)
|
||||
return grpcConn, err
|
||||
|
@ -163,7 +240,7 @@ func (c *GrpcClient) sendConnectionSetupRequest(grpcConn *GrpcConnection) error
|
|||
csr.ClientAbilities = c.clientAbilities
|
||||
err := grpcConn.biStreamSend(convertRequest(csr))
|
||||
if err != nil {
|
||||
logger.Warnf("Send ConnectionSetupRequest error:%+v", err)
|
||||
logger.Warnf("send connectionSetupRequest error:%v", err)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return err
|
||||
|
@ -174,7 +251,7 @@ func (c *GrpcClient) getConnectionType() ConnectionType {
|
|||
}
|
||||
|
||||
func (c *GrpcClient) rpcPortOffset() uint64 {
|
||||
return 1000
|
||||
return constant.RpcPortOffset
|
||||
}
|
||||
|
||||
func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiRequestStream_RequestBiStreamClient, grpcConn *GrpcConnection) {
|
||||
|
@ -182,6 +259,7 @@ func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiReque
|
|||
for {
|
||||
select {
|
||||
case <-streamClient.Context().Done():
|
||||
logger.Warnf("connectionId %s stream client close", grpcConn.getConnectionId())
|
||||
return
|
||||
default:
|
||||
payload, err := streamClient.Recv()
|
||||
|
@ -190,16 +268,16 @@ func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiReque
|
|||
abandon := grpcConn.getAbandon()
|
||||
if c.IsRunning() && !abandon {
|
||||
if err == io.EOF {
|
||||
logger.Infof("%s Request stream onCompleted, switch server", grpcConn.getConnectionId())
|
||||
logger.Infof("connectionId %s request stream onCompleted, switch server", grpcConn.getConnectionId())
|
||||
} else {
|
||||
logger.Errorf("%s Request stream error, switch server, error=%+v", grpcConn.getConnectionId(), err)
|
||||
logger.Errorf("connectionId %s request stream error, switch server, error=%v", grpcConn.getConnectionId(), err)
|
||||
}
|
||||
if atomic.CompareAndSwapInt32((*int32)(&c.rpcClientStatus), int32(RUNNING), int32(UNHEALTHY)) {
|
||||
c.switchServerAsync(ServerInfo{}, false)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
logger.Infof("%s received error event, isRunning:%v, isAbandon=%v, error=%+v", grpcConn.getConnectionId(), running, abandon, err)
|
||||
logger.Errorf("connectionId %s received error event, isRunning:%v, isAbandon=%v, error=%v", grpcConn.getConnectionId(), running, abandon, err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
|
@ -241,12 +319,14 @@ func (c *GrpcClient) handleServerRequest(p *nacos_grpc_service.Payload, grpcConn
|
|||
client := c.GetRpcClient()
|
||||
payLoadType := p.GetMetadata().GetType()
|
||||
|
||||
mapping, ok := client.serverRequestHandlerMapping[payLoadType]
|
||||
handlerMapping, ok := client.serverRequestHandlerMapping.Load(payLoadType)
|
||||
if !ok {
|
||||
logger.Errorf("%s Unsupported payload type", grpcConn.getConnectionId())
|
||||
return
|
||||
}
|
||||
|
||||
mapping := handlerMapping.(ServerRequestHandlerMapping)
|
||||
|
||||
serverRequest := mapping.serverRequest()
|
||||
err := json.Unmarshal(p.GetBody().Value, serverRequest)
|
||||
if err != nil {
|
||||
|
|
|
@ -18,16 +18,16 @@ package rpc
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/any"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
|
||||
nacos_grpc_service "github.com/nacos-group/nacos-sdk-go/v2/api/grpc"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
"github.com/pkg/errors"
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
@ -57,18 +57,18 @@ func (g *GrpcConnection) request(request rpc_request.IRequest, timeoutMills int6
|
|||
defer cancel()
|
||||
responsePayload, err := g.client.Request(ctx, p)
|
||||
if err != nil {
|
||||
logger.Debugf("%s grpc request nacos server failed, request=%+v, err=%v ", g.getConnectionId(), p, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responseFunc, ok := rpc_response.ClientResponseMapping[responsePayload.Metadata.GetType()]
|
||||
|
||||
if !ok {
|
||||
return nil, errors.New(fmt.Sprintf("request:%s,unsupported response type:%s", request.GetRequestType(),
|
||||
responsePayload.Metadata.GetType()))
|
||||
return nil, errors.Errorf("request:%s,unsupported response type:%s", request.GetRequestType(),
|
||||
responsePayload.Metadata.GetType())
|
||||
}
|
||||
response := responseFunc()
|
||||
err = json.Unmarshal(responsePayload.GetBody().Value, response)
|
||||
return response, err
|
||||
|
||||
logger.Debugf("%s grpc request nacos server success, request=%+v, response=%s", g.getConnectionId(), p, string(responsePayload.GetBody().Value))
|
||||
return rpc_response.InnerResponseJsonUnmarshal(responsePayload.GetBody().Value, responseFunc)
|
||||
}
|
||||
|
||||
func (g *GrpcConnection) close() {
|
||||
|
@ -87,7 +87,7 @@ func convertRequest(r rpc_request.IRequest) *nacos_grpc_service.Payload {
|
|||
}
|
||||
return &nacos_grpc_service.Payload{
|
||||
Metadata: &Metadata,
|
||||
Body: &any.Any{Value: []byte(r.GetBody(r))},
|
||||
Body: &anypb.Any{Value: []byte(r.GetBody(r))},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,6 @@ func convertResponse(r rpc_response.IResponse) *nacos_grpc_service.Payload {
|
|||
}
|
||||
return &nacos_grpc_service.Payload{
|
||||
Metadata: &Metadata,
|
||||
Body: &any.Any{Value: []byte(r.GetBody())},
|
||||
Body: &anypb.Any{Value: []byte(r.GetBody())},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,11 @@ package rpc
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
@ -105,7 +108,7 @@ type RpcClient struct {
|
|||
lastActiveTimestamp atomic.Value
|
||||
executeClient IRpcClient
|
||||
nacosServer *nacos_server.NacosServer
|
||||
serverRequestHandlerMapping map[string]ServerRequestHandlerMapping
|
||||
serverRequestHandlerMapping sync.Map
|
||||
mux *sync.Mutex
|
||||
clientAbilities rpc_request.ClientAbilities
|
||||
Tenant string
|
||||
|
@ -147,17 +150,31 @@ func getClient(clientName string) IRpcClient {
|
|||
return clientMap[clientName]
|
||||
}
|
||||
|
||||
func CreateClient(ctx context.Context, clientName string, connectionType ConnectionType, labels map[string]string, nacosServer *nacos_server.NacosServer) (IRpcClient, error) {
|
||||
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) {
|
||||
cMux.Lock()
|
||||
defer cMux.Unlock()
|
||||
if _, ok := clientMap[clientName]; !ok {
|
||||
logger.Infof("init rpc client for name ", clientName)
|
||||
var rpcClient IRpcClient
|
||||
if GRPC == connectionType {
|
||||
rpcClient = NewGrpcClient(ctx, clientName, nacosServer)
|
||||
rpcClient = NewGrpcClient(ctx, clientName, nacosServer, tlsConfig)
|
||||
}
|
||||
if rpcClient == nil {
|
||||
return nil, errors.New("unsupported connection type")
|
||||
}
|
||||
|
||||
logger.Infof("get app conn labels from client config %v ", appConnLabels)
|
||||
appConnLabelsEnv := getAppLabelsFromEnv()
|
||||
logger.Infof("get app conn labels from env %v ", appConnLabelsEnv)
|
||||
|
||||
appConnLabelsFinal := mergerAppLabels(appConnLabels, appConnLabelsEnv)
|
||||
logger.Infof("final app conn labels : %v ", appConnLabelsFinal)
|
||||
|
||||
appConnLabelsFinal = addPrefixForEachKey(appConnLabelsFinal, "app_")
|
||||
if len(appConnLabelsFinal) != 0 {
|
||||
rpcClient.putAllLabels(appConnLabelsFinal)
|
||||
}
|
||||
|
||||
rpcClient.putAllLabels(labels)
|
||||
clientMap[clientName] = rpcClient
|
||||
return rpcClient, nil
|
||||
|
@ -165,6 +182,92 @@ func CreateClient(ctx context.Context, clientName string, connectionType Connect
|
|||
return clientMap[clientName], nil
|
||||
}
|
||||
|
||||
func mergerAppLabels(appLabelsAppointed map[string]string, appLabelsEnv map[string]string) map[string]string {
|
||||
preferred := strings.ToLower(os.Getenv("nacos_app_conn_labels_preferred"))
|
||||
|
||||
var preferFirst bool
|
||||
if preferred != "env" {
|
||||
preferFirst = true
|
||||
} else {
|
||||
preferFirst = false
|
||||
}
|
||||
return mergeMaps(appLabelsAppointed, appLabelsEnv, preferFirst)
|
||||
}
|
||||
|
||||
func mergeMaps(map1, map2 map[string]string, preferFirst bool) map[string]string {
|
||||
result := make(map[string]string, 8)
|
||||
|
||||
for k, v := range map1 {
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
for k, v := range map2 {
|
||||
_, ok := map1[k]
|
||||
if preferFirst && ok {
|
||||
continue
|
||||
}
|
||||
result[k] = v
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func getAppLabelsFromEnv() map[string]string {
|
||||
configMap := make(map[string]string, 8)
|
||||
|
||||
// nacos_config_gray_label
|
||||
grayLabel := os.Getenv("nacos_config_gray_label")
|
||||
if grayLabel != "" {
|
||||
configMap["nacos_config_gray_label"] = grayLabel
|
||||
}
|
||||
|
||||
// nacos_app_conn_labels
|
||||
connLabels := os.Getenv("nacos_app_conn_labels")
|
||||
if connLabels != "" {
|
||||
labelsMap := parseLabels(connLabels)
|
||||
for k, v := range labelsMap {
|
||||
configMap[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return configMap
|
||||
}
|
||||
|
||||
func parseLabels(rawLabels string) map[string]string {
|
||||
if strings.TrimSpace(rawLabels) == "" {
|
||||
return make(map[string]string, 2)
|
||||
}
|
||||
|
||||
resultMap := make(map[string]string, 2)
|
||||
labels := strings.Split(rawLabels, ",")
|
||||
for _, label := range labels {
|
||||
if strings.TrimSpace(label) != "" {
|
||||
kv := strings.Split(label, "=")
|
||||
if len(kv) == 2 {
|
||||
resultMap[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
|
||||
} else {
|
||||
fmt.Println("unknown label format:", label)
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultMap
|
||||
}
|
||||
|
||||
func addPrefixForEachKey(m map[string]string, prefix string) map[string]string {
|
||||
if len(m) == 0 {
|
||||
return m
|
||||
}
|
||||
|
||||
newMap := make(map[string]string, len(m))
|
||||
for k, v := range m {
|
||||
if strings.TrimSpace(k) != "" {
|
||||
newKey := prefix + k
|
||||
newMap[newKey] = v
|
||||
}
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
func (r *RpcClient) Start() {
|
||||
if ok := atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(INITIALIZED), (int32)(STARTING)); !ok {
|
||||
return
|
||||
|
@ -218,7 +321,7 @@ func (r *RpcClient) Start() {
|
|||
startUpRetryTimes--
|
||||
serverInfo, err := r.nextRpcServer()
|
||||
if err != nil {
|
||||
logger.Errorf("[RpcClient.nextRpcServer],err:%+v", err)
|
||||
logger.Errorf("[RpcClient.nextRpcServer],err:%v", err)
|
||||
break
|
||||
}
|
||||
logger.Infof("[RpcClient.Start] %s try to connect to server on start up, server: %+v", r.name, serverInfo)
|
||||
|
@ -235,12 +338,16 @@ func (r *RpcClient) Start() {
|
|||
currentConnection.getServerInfo(), currentConnection.getConnectionId())
|
||||
r.currentConnection = currentConnection
|
||||
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
|
||||
r.eventChan <- ConnectionEvent{eventType: CONNECTED}
|
||||
r.notifyConnectionChange(CONNECTED)
|
||||
} else {
|
||||
r.switchServerAsync(ServerInfo{}, false)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RpcClient) notifyConnectionChange(eventType ConnectionStatus) {
|
||||
r.eventChan <- ConnectionEvent{eventType: eventType}
|
||||
}
|
||||
|
||||
func (r *RpcClient) notifyServerSrvChange() {
|
||||
if r.currentConnection == nil {
|
||||
r.switchServerAsync(ServerInfo{}, false)
|
||||
|
@ -284,10 +391,10 @@ func (r *RpcClient) RegisterServerRequestHandler(request func() rpc_request.IReq
|
|||
return
|
||||
}
|
||||
logger.Debugf("%s register server push request:%s handler:%+v", r.name, requestType, handler.Name())
|
||||
r.serverRequestHandlerMapping[requestType] = ServerRequestHandlerMapping{
|
||||
r.serverRequestHandlerMapping.Store(requestType, ServerRequestHandlerMapping{
|
||||
serverRequest: request,
|
||||
handler: handler,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (r *RpcClient) RegisterConnectionListener(listener IConnectionEventListener) {
|
||||
|
@ -306,6 +413,7 @@ func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
|
|||
if onRequestFail && r.sendHealthCheck() {
|
||||
logger.Infof("%s server check success, currentServer is %+v", r.name, r.currentConnection.getServerInfo())
|
||||
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
|
||||
r.notifyConnectionChange(CONNECTED)
|
||||
return
|
||||
}
|
||||
var (
|
||||
|
@ -339,7 +447,7 @@ func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
|
|||
}
|
||||
r.currentConnection = connectionNew
|
||||
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
|
||||
r.eventChan <- ConnectionEvent{eventType: CONNECTED}
|
||||
r.notifyConnectionChange(CONNECTED)
|
||||
return
|
||||
}
|
||||
if r.isShutdown() {
|
||||
|
@ -365,7 +473,7 @@ func (r *RpcClient) reconnect(serverInfo ServerInfo, onRequestFail bool) {
|
|||
func (r *RpcClient) closeConnection() {
|
||||
if r.currentConnection != nil {
|
||||
r.currentConnection.close()
|
||||
r.eventChan <- ConnectionEvent{eventType: DISCONNECTED}
|
||||
r.notifyConnectionChange(DISCONNECTED)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -375,7 +483,7 @@ func (r *RpcClient) notifyConnectionEvent(event ConnectionEvent) {
|
|||
if len(listeners) == 0 {
|
||||
return
|
||||
}
|
||||
logger.Infof("%s notify %s event to listeners.", r.name, event.toString())
|
||||
logger.Infof("%s notify %s event to listeners , connectionId=%s", r.name, event.toString(), r.currentConnection.getConnectionId())
|
||||
for _, v := range listeners {
|
||||
if event.isConnected() {
|
||||
v.OnConnected()
|
||||
|
@ -488,17 +596,22 @@ func (r *RpcClient) Request(request rpc_request.IRequest, timeoutMills int64) (r
|
|||
currentErr = waitReconnect(timeoutMills, &retryTimes, request, err)
|
||||
continue
|
||||
}
|
||||
if resp, ok := response.(*rpc_response.ErrorResponse); ok && resp.GetErrorCode() == constant.UN_REGISTER {
|
||||
r.mux.Lock()
|
||||
if atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING), (int32)(UNHEALTHY)) {
|
||||
logger.Infof("Connection is unregistered, switch server, connectionId=%s, request=%s",
|
||||
r.currentConnection.getConnectionId(), request.GetRequestType())
|
||||
r.switchServerAsync(ServerInfo{}, false)
|
||||
if resp, ok := response.(*rpc_response.ErrorResponse); ok {
|
||||
if resp.GetErrorCode() == constant.UN_REGISTER {
|
||||
r.mux.Lock()
|
||||
if atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING), (int32)(UNHEALTHY)) {
|
||||
logger.Infof("Connection is unregistered, switch server, connectionId=%s, request=%s",
|
||||
r.currentConnection.getConnectionId(), request.GetRequestType())
|
||||
r.switchServerAsync(ServerInfo{}, false)
|
||||
}
|
||||
r.mux.Unlock()
|
||||
}
|
||||
r.mux.Unlock()
|
||||
currentErr = waitReconnect(timeoutMills, &retryTimes, request, errors.New(response.GetMessage()))
|
||||
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())
|
||||
return response, nil
|
||||
}
|
||||
|
|
|
@ -16,7 +16,10 @@
|
|||
|
||||
package rpc_request
|
||||
|
||||
import "github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
)
|
||||
|
||||
type ConfigRequest struct {
|
||||
*Request
|
||||
|
@ -51,7 +54,7 @@ func (r *ConfigRequest) GetTenant() string {
|
|||
return r.Tenant
|
||||
}
|
||||
|
||||
//request of listening a batch of configs.
|
||||
// request of listening a batch of configs.
|
||||
type ConfigBatchListenRequest struct {
|
||||
*ConfigRequest
|
||||
Listen bool `json:"listen"`
|
||||
|
@ -67,7 +70,7 @@ func NewConfigBatchListenRequest(cacheLen int) *ConfigBatchListenRequest {
|
|||
}
|
||||
|
||||
func (r *ConfigBatchListenRequest) GetRequestType() string {
|
||||
return "ConfigBatchListenRequest"
|
||||
return constant.CONFIG_BATCH_LISTEN_REQUEST_NAME
|
||||
}
|
||||
|
||||
type ConfigChangeNotifyRequest struct {
|
||||
|
@ -79,7 +82,7 @@ func NewConfigChangeNotifyRequest(group, dataId, tenant string) *ConfigChangeNot
|
|||
}
|
||||
|
||||
func (r *ConfigChangeNotifyRequest) GetRequestType() string {
|
||||
return "ConfigChangeNotifyRequest"
|
||||
return constant.CONFIG_CHANGE_NOTIFY_REQUEST_NAME
|
||||
}
|
||||
|
||||
type ConfigQueryRequest struct {
|
||||
|
@ -92,7 +95,7 @@ func NewConfigQueryRequest(group, dataId, tenant string) *ConfigQueryRequest {
|
|||
}
|
||||
|
||||
func (r *ConfigQueryRequest) GetRequestType() string {
|
||||
return "ConfigQueryRequest"
|
||||
return constant.CONFIG_QUERY_REQUEST_NAME
|
||||
}
|
||||
|
||||
type ConfigPublishRequest struct {
|
||||
|
@ -108,7 +111,7 @@ func NewConfigPublishRequest(group, dataId, tenant, content, casMd5 string) *Con
|
|||
}
|
||||
|
||||
func (r *ConfigPublishRequest) GetRequestType() string {
|
||||
return "ConfigPublishRequest"
|
||||
return constant.CONFIG_PUBLISH_REQUEST_NAME
|
||||
}
|
||||
|
||||
type ConfigRemoveRequest struct {
|
||||
|
@ -120,5 +123,5 @@ func NewConfigRemoveRequest(group, dataId, tenant string) *ConfigRemoveRequest {
|
|||
}
|
||||
|
||||
func (r *ConfigRemoveRequest) GetRequestType() string {
|
||||
return "ConfigRemoveRequest"
|
||||
return constant.CONFIG_REMOVE_REQUEST_NAME
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
)
|
||||
|
||||
|
@ -32,12 +33,6 @@ type NamingRequest struct {
|
|||
Module string `json:"module"`
|
||||
}
|
||||
|
||||
type InstanceRequest struct {
|
||||
*NamingRequest
|
||||
Type string `json:"type"`
|
||||
Instance model.Instance `json:"instance"`
|
||||
}
|
||||
|
||||
func NewNamingRequest(namespace, serviceName, groupName string) *NamingRequest {
|
||||
request := Request{
|
||||
Headers: make(map[string]string, 8),
|
||||
|
@ -59,6 +54,12 @@ func (r *NamingRequest) GetStringToSign() string {
|
|||
return data
|
||||
}
|
||||
|
||||
type InstanceRequest struct {
|
||||
*NamingRequest
|
||||
Type string `json:"type"`
|
||||
Instance model.Instance `json:"instance"`
|
||||
}
|
||||
|
||||
func NewInstanceRequest(namespace, serviceName, groupName, Type string, instance model.Instance) *InstanceRequest {
|
||||
return &InstanceRequest{
|
||||
NamingRequest: NewNamingRequest(namespace, serviceName, groupName),
|
||||
|
@ -68,7 +69,25 @@ func NewInstanceRequest(namespace, serviceName, groupName, Type string, instance
|
|||
}
|
||||
|
||||
func (r *InstanceRequest) GetRequestType() string {
|
||||
return "InstanceRequest"
|
||||
return constant.INSTANCE_REQUEST_NAME
|
||||
}
|
||||
|
||||
type BatchInstanceRequest struct {
|
||||
*NamingRequest
|
||||
Type string `json:"type"`
|
||||
Instances []model.Instance `json:"instances"`
|
||||
}
|
||||
|
||||
func NewBatchInstanceRequest(namespace, serviceName, groupName, Type string, instances []model.Instance) *BatchInstanceRequest {
|
||||
return &BatchInstanceRequest{
|
||||
NamingRequest: NewNamingRequest(namespace, serviceName, groupName),
|
||||
Type: Type,
|
||||
Instances: instances,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *BatchInstanceRequest) GetRequestType() string {
|
||||
return constant.BATCH_INSTANCE_REQUEST_NAME
|
||||
}
|
||||
|
||||
type NotifySubscriberRequest struct {
|
||||
|
@ -77,7 +96,7 @@ type NotifySubscriberRequest struct {
|
|||
}
|
||||
|
||||
func (r *NotifySubscriberRequest) GetRequestType() string {
|
||||
return "NotifySubscriberRequest"
|
||||
return constant.NOTIFY_SUBSCRIBE_REQUEST_NAME
|
||||
}
|
||||
|
||||
type ServiceListRequest struct {
|
||||
|
@ -97,7 +116,7 @@ func NewServiceListRequest(namespace, serviceName, groupName string, pageNo, pag
|
|||
}
|
||||
|
||||
func (r *ServiceListRequest) GetRequestType() string {
|
||||
return "ServiceListRequest"
|
||||
return constant.SERVICE_LIST_REQUEST_NAME
|
||||
}
|
||||
|
||||
type SubscribeServiceRequest struct {
|
||||
|
@ -115,25 +134,25 @@ func NewSubscribeServiceRequest(namespace, serviceName, groupName, clusters stri
|
|||
}
|
||||
|
||||
func (r *SubscribeServiceRequest) GetRequestType() string {
|
||||
return "SubscribeServiceRequest"
|
||||
return constant.SUBSCRIBE_SERVICE_REQUEST_NAME
|
||||
}
|
||||
|
||||
type ServiceQueryRequest struct {
|
||||
*NamingRequest
|
||||
Clusters string `json:"clusters"`
|
||||
Cluster string `json:"cluster"`
|
||||
HealthyOnly bool `json:"healthyOnly"`
|
||||
UdpPort int `json:"udpPort"`
|
||||
}
|
||||
|
||||
func NewServiceQueryRequest(namespace, serviceName, groupName, clusters string, healthyOnly bool, udpPort int) *ServiceQueryRequest {
|
||||
func NewServiceQueryRequest(namespace, serviceName, groupName, cluster string, healthyOnly bool, udpPort int) *ServiceQueryRequest {
|
||||
return &ServiceQueryRequest{
|
||||
NamingRequest: NewNamingRequest(namespace, serviceName, groupName),
|
||||
Clusters: clusters,
|
||||
Cluster: cluster,
|
||||
HealthyOnly: healthyOnly,
|
||||
UdpPort: udpPort,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ServiceQueryRequest) GetRequestType() string {
|
||||
return "ServiceQueryRequest"
|
||||
return constant.SERVICE_QUERY_REQUEST_NAME
|
||||
}
|
||||
|
|
|
@ -39,6 +39,9 @@ type IConfigRequest interface {
|
|||
}
|
||||
|
||||
func (r *Request) PutAllHeaders(headers map[string]string) {
|
||||
if r.Headers == nil {
|
||||
r.Headers = make(map[string]string)
|
||||
}
|
||||
for k, v := range headers {
|
||||
r.Headers[k] = v
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package rpc_response
|
||||
|
||||
type ResponseCode int
|
||||
|
||||
const (
|
||||
ResponseSuccessCode ResponseCode = 200
|
||||
ResponseFailCode ResponseCode = 500
|
||||
|
||||
ResponseSuccessField = "success"
|
||||
)
|
|
@ -53,6 +53,14 @@ func (c *InstanceResponse) GetResponseType() string {
|
|||
return "InstanceResponse"
|
||||
}
|
||||
|
||||
type BatchInstanceResponse struct {
|
||||
*Response
|
||||
}
|
||||
|
||||
func (c *BatchInstanceResponse) GetResponseType() string {
|
||||
return "BatchInstanceResponse"
|
||||
}
|
||||
|
||||
type QueryServiceResponse struct {
|
||||
*Response
|
||||
ServiceInfo model.Service `json:"serviceInfo"`
|
||||
|
|
|
@ -36,6 +36,7 @@ type IResponse interface {
|
|||
GetBody() string
|
||||
GetErrorCode() int
|
||||
IsSuccess() bool
|
||||
SetSuccess(bool)
|
||||
GetResultCode() int
|
||||
GetMessage() string
|
||||
}
|
||||
|
@ -60,6 +61,10 @@ func (r *Response) IsSuccess() bool {
|
|||
return r.Success
|
||||
}
|
||||
|
||||
func (r *Response) SetSuccess(successResult bool) {
|
||||
r.Success = successResult
|
||||
}
|
||||
|
||||
func (r *Response) GetErrorCode() int {
|
||||
return r.ErrorCode
|
||||
}
|
||||
|
@ -87,6 +92,11 @@ func registerClientResponses() {
|
|||
return &InstanceResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
// register BatchInstanceResponse.
|
||||
registerClientResponse(func() IResponse {
|
||||
return &BatchInstanceResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
// register QueryServiceResponse.
|
||||
registerClientResponse(func() IResponse {
|
||||
return &QueryServiceResponse{Response: &Response{}}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
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")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
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
|
||||
|
||||
}
|
|
@ -69,7 +69,7 @@ func (c *ClientDetectionRequestHandler) Name() string {
|
|||
return "ClientDetectionRequestHandler"
|
||||
}
|
||||
|
||||
func (c *ClientDetectionRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *RpcClient) rpc_response.IResponse {
|
||||
func (c *ClientDetectionRequestHandler) RequestReply(request rpc_request.IRequest, _ *RpcClient) rpc_response.IResponse {
|
||||
_, ok := request.(*rpc_request.ClientDetectionRequest)
|
||||
if ok {
|
||||
return &rpc_response.ClientDetectionResponse{
|
||||
|
@ -87,12 +87,14 @@ func (*NamingPushRequestHandler) Name() string {
|
|||
return "NamingPushRequestHandler"
|
||||
}
|
||||
|
||||
func (c *NamingPushRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *RpcClient) rpc_response.IResponse {
|
||||
func (c *NamingPushRequestHandler) RequestReply(request rpc_request.IRequest, client *RpcClient) rpc_response.IResponse {
|
||||
notifySubscriberRequest, ok := request.(*rpc_request.NotifySubscriberRequest)
|
||||
if ok {
|
||||
c.ServiceInfoHolder.ProcessService(¬ifySubscriberRequest.ServiceInfo)
|
||||
logger.Debugf("%s naming push response success ackId->%s", client.currentConnection.getConnectionId(),
|
||||
request.GetRequestId())
|
||||
return &rpc_response.NotifySubscriberResponse{
|
||||
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS},
|
||||
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS, Success: true},
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
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
|
||||
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
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())
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
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
|
||||
}
|
|
@ -0,0 +1,380 @@
|
|||
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,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
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
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
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+")
|
||||
})
|
||||
}
|
|
@ -18,73 +18,135 @@ package security
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request"
|
||||
)
|
||||
|
||||
type AuthClient struct {
|
||||
username string
|
||||
password string
|
||||
accessToken *atomic.Value
|
||||
tokenTtl int64
|
||||
lastRefreshTime int64
|
||||
tokenRefreshWindow int64
|
||||
agent http_agent.IHttpAgent
|
||||
clientCfg constant.ClientConfig
|
||||
serverCfgs []constant.ServerConfig
|
||||
type RequestResource struct {
|
||||
requestType string
|
||||
namespace string
|
||||
group string
|
||||
resource string
|
||||
}
|
||||
|
||||
func NewAuthClient(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, agent http_agent.IHttpAgent) AuthClient {
|
||||
client := AuthClient{
|
||||
username: clientCfg.Username,
|
||||
password: clientCfg.Password,
|
||||
serverCfgs: serverCfgs,
|
||||
clientCfg: clientCfg,
|
||||
agent: agent,
|
||||
accessToken: &atomic.Value{},
|
||||
}
|
||||
const (
|
||||
REQUEST_TYPE_CONFIG = "config"
|
||||
REQUEST_TYPE_NAMING = "naming"
|
||||
)
|
||||
|
||||
return client
|
||||
func BuildConfigResourceByRequest(request rpc_request.IRequest) RequestResource {
|
||||
if request.GetRequestType() == constant.CONFIG_QUERY_REQUEST_NAME {
|
||||
configQueryRequest := request.(*rpc_request.ConfigQueryRequest)
|
||||
return BuildConfigResource(configQueryRequest.Tenant, configQueryRequest.Group, configQueryRequest.DataId)
|
||||
}
|
||||
if request.GetRequestType() == constant.CONFIG_PUBLISH_REQUEST_NAME {
|
||||
configPublishRequest := request.(*rpc_request.ConfigPublishRequest)
|
||||
return BuildConfigResource(configPublishRequest.Tenant, configPublishRequest.Group, configPublishRequest.DataId)
|
||||
}
|
||||
if request.GetRequestType() == "ConfigRemoveRequest" {
|
||||
configRemoveRequest := request.(*rpc_request.ConfigRemoveRequest)
|
||||
return BuildConfigResource(configRemoveRequest.Tenant, configRemoveRequest.Group, configRemoveRequest.DataId)
|
||||
}
|
||||
return RequestResource{
|
||||
requestType: REQUEST_TYPE_CONFIG,
|
||||
}
|
||||
}
|
||||
|
||||
func (ac *AuthClient) GetAccessToken() string {
|
||||
v := ac.accessToken.Load()
|
||||
if v == nil {
|
||||
return ""
|
||||
func BuildNamingResourceByRequest(request rpc_request.IRequest) RequestResource {
|
||||
if request.GetRequestType() == constant.INSTANCE_REQUEST_NAME {
|
||||
instanceRequest := request.(*rpc_request.InstanceRequest)
|
||||
return BuildNamingResource(instanceRequest.Namespace, instanceRequest.GroupName, instanceRequest.ServiceName)
|
||||
}
|
||||
if request.GetRequestType() == constant.BATCH_INSTANCE_REQUEST_NAME {
|
||||
batchInstanceRequest := request.(*rpc_request.BatchInstanceRequest)
|
||||
return BuildNamingResource(batchInstanceRequest.Namespace, batchInstanceRequest.GroupName, batchInstanceRequest.ServiceName)
|
||||
}
|
||||
if request.GetRequestType() == constant.SERVICE_LIST_REQUEST_NAME {
|
||||
serviceListRequest := request.(*rpc_request.ServiceListRequest)
|
||||
return BuildNamingResource(serviceListRequest.Namespace, serviceListRequest.GroupName, serviceListRequest.ServiceName)
|
||||
}
|
||||
if request.GetRequestType() == constant.SERVICE_QUERY_REQUEST_NAME {
|
||||
serviceQueryRequest := request.(*rpc_request.ServiceQueryRequest)
|
||||
return BuildNamingResource(serviceQueryRequest.Namespace, serviceQueryRequest.GroupName, serviceQueryRequest.ServiceName)
|
||||
}
|
||||
if request.GetRequestType() == constant.SUBSCRIBE_SERVICE_REQUEST_NAME {
|
||||
subscribeServiceRequest := request.(*rpc_request.SubscribeServiceRequest)
|
||||
return BuildNamingResource(subscribeServiceRequest.Namespace, subscribeServiceRequest.GroupName, subscribeServiceRequest.ServiceName)
|
||||
}
|
||||
return RequestResource{
|
||||
requestType: REQUEST_TYPE_NAMING,
|
||||
}
|
||||
return v.(string)
|
||||
}
|
||||
|
||||
func (ac *AuthClient) AutoRefresh(ctx context.Context) {
|
||||
|
||||
// If the username is not set, the automatic refresh Token is not enabled
|
||||
|
||||
if ac.username == "" {
|
||||
return
|
||||
func BuildConfigResource(tenant, group, dataId string) RequestResource {
|
||||
return RequestResource{
|
||||
requestType: REQUEST_TYPE_CONFIG,
|
||||
namespace: tenant,
|
||||
group: group,
|
||||
resource: dataId,
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
timer := time.NewTimer(time.Second * time.Duration(ac.tokenTtl-ac.tokenRefreshWindow))
|
||||
var 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(ac.tokenTtl-ac.tokenRefreshWindow))
|
||||
sp.Login()
|
||||
timer.Reset(time.Second * time.Duration(5))
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
|
@ -92,74 +154,20 @@ func (ac *AuthClient) AutoRefresh(ctx context.Context) {
|
|||
}()
|
||||
}
|
||||
|
||||
func (ac *AuthClient) Login() (bool, error) {
|
||||
var throwable error = nil
|
||||
for i := 0; i < len(ac.serverCfgs); i++ {
|
||||
result, err := ac.login(ac.serverCfgs[i])
|
||||
throwable = err
|
||||
if result {
|
||||
return true, nil
|
||||
}
|
||||
func NewSecurityProxy(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, agent http_agent.IHttpAgent) SecurityProxy {
|
||||
var securityProxy = SecurityProxy{}
|
||||
securityProxy.Clients = []AuthClient{
|
||||
NewNacosAuthClient(clientCfg, serverCfgs, agent),
|
||||
NewRamAuthClient(clientCfg),
|
||||
}
|
||||
return false, throwable
|
||||
return securityProxy
|
||||
}
|
||||
|
||||
func (ac *AuthClient) login(server constant.ServerConfig) (bool, error) {
|
||||
if ac.username != "" {
|
||||
contextPath := server.ContextPath
|
||||
|
||||
if !strings.HasPrefix(contextPath, "/") {
|
||||
contextPath = "/" + contextPath
|
||||
}
|
||||
|
||||
if strings.HasSuffix(contextPath, "/") {
|
||||
contextPath = contextPath[0 : len(contextPath)-1]
|
||||
}
|
||||
|
||||
if server.Scheme == "" {
|
||||
server.Scheme = "http"
|
||||
}
|
||||
|
||||
reqUrl := server.Scheme + "://" + server.IpAddr + ":" + strconv.FormatInt(int64(server.Port), 10) + contextPath + "/v1/auth/users/login"
|
||||
|
||||
header := http.Header{
|
||||
"content-type": []string{"application/x-www-form-urlencoded"},
|
||||
}
|
||||
resp, err := ac.agent.Post(reqUrl, header, ac.clientCfg.TimeoutMs, map[string]string{
|
||||
"username": ac.username,
|
||||
"password": ac.password,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var bytes []byte
|
||||
bytes, err = ioutil.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != constant.RESPONSE_CODE_SUCCESS {
|
||||
errMsg := string(bytes)
|
||||
return false, errors.New(errMsg)
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
|
||||
err = json.Unmarshal(bytes, &result)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if val, ok := result[constant.KEY_ACCESS_TOKEN]; ok {
|
||||
ac.accessToken.Store(val)
|
||||
ac.tokenTtl = int64(result[constant.KEY_TOKEN_TTL].(float64))
|
||||
ac.tokenRefreshWindow = ac.tokenTtl / 10
|
||||
}
|
||||
func NewSecurityProxyWithRamCredentialProvider(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, agent http_agent.IHttpAgent, provider RamCredentialProvider) SecurityProxy {
|
||||
var securityProxy = SecurityProxy{}
|
||||
securityProxy.Clients = []AuthClient{
|
||||
NewNacosAuthClient(clientCfg, serverCfgs, agent),
|
||||
NewRamAuthClientWithProvider(clientCfg, provider),
|
||||
}
|
||||
return true, nil
|
||||
|
||||
return securityProxy
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
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
|
||||
}
|
|
@ -20,7 +20,7 @@ import (
|
|||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
)
|
||||
|
@ -48,7 +48,7 @@ func NewTLS(c constant.TLSConfig) (tc *tls.Config, err error) {
|
|||
}
|
||||
|
||||
func rootCert(caFile string) (*x509.CertPool, error) {
|
||||
b, err := ioutil.ReadFile(caFile)
|
||||
b, err := os.ReadFile(caFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
package tls
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
@ -93,16 +92,16 @@ q9K53Jum9GDmkbUODa77sWR1zQsdrqSKywcjP/6FYXU9RMDqKUpm
|
|||
)
|
||||
|
||||
func Test_NewTLS(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "tls-test")
|
||||
dir, err := os.MkdirTemp("", "tls-test")
|
||||
if err != nil {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
caPath, crtPath, keyPath := filepath.Join(dir, "ca.crt"), filepath.Join(dir, "client.crt"), filepath.Join(dir, "client.key")
|
||||
ioutil.WriteFile(caPath, testCaCrt, 0666)
|
||||
ioutil.WriteFile(crtPath, testClientCrt, 0666)
|
||||
ioutil.WriteFile(keyPath, testClientKey, 0666)
|
||||
os.WriteFile(caPath, testCaCrt, 0666)
|
||||
os.WriteFile(crtPath, testClientCrt, 0666)
|
||||
os.WriteFile(keyPath, testClientKey, 0666)
|
||||
|
||||
t.Run("TestNoAuth", func(t *testing.T) {
|
||||
cfg, err := NewTLS(constant.SkipVerifyConfig)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
LTAIxxxxxxxxxxxBHS21E6
|
|
@ -18,67 +18,123 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients"
|
||||
"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/vo"
|
||||
"time"
|
||||
)
|
||||
|
||||
var localServerConfigWithOptions = constant.NewServerConfig(
|
||||
"mse-d12e6112-p.nacos-ans.mse.aliyuncs.com",
|
||||
8848,
|
||||
)
|
||||
|
||||
var localClientConfigWithOptions = constant.NewClientConfig(
|
||||
constant.WithTimeoutMs(10*1000),
|
||||
constant.WithBeatInterval(2*1000),
|
||||
constant.WithNotLoadCacheAtStart(true),
|
||||
//constant.WithAccessKey(getFileContent(path.Join(getWDR(), "ak"))),
|
||||
//constant.WithSecretKey(getFileContent(path.Join(getWDR(), "sk"))),
|
||||
constant.WithAccessKey("LTAxxxgQL"),
|
||||
constant.WithSecretKey("iG4xxxV6C"),
|
||||
constant.WithOpenKMS(true),
|
||||
constant.WithKMSVersion(constant.KMSv1),
|
||||
constant.WithRegionId("cn-beijing"),
|
||||
)
|
||||
|
||||
var localConfigList = []vo.ConfigParam{
|
||||
{
|
||||
DataId: "common-config",
|
||||
Group: "default",
|
||||
Content: "common",
|
||||
},
|
||||
{
|
||||
DataId: "cipher-crypt",
|
||||
Group: "default",
|
||||
Content: "cipher",
|
||||
},
|
||||
{
|
||||
DataId: "cipher-kms-aes-128-crypt",
|
||||
Group: "default",
|
||||
Content: "cipher-aes-128",
|
||||
},
|
||||
{
|
||||
DataId: "cipher-kms-aes-256-crypt",
|
||||
Group: "default",
|
||||
Content: "cipher-aes-256",
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
cc := constant.ClientConfig{
|
||||
Endpoint: "acm.aliyun.com:8080",
|
||||
NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468",
|
||||
RegionId: "cn-shanghai",
|
||||
AccessKey: "LTAI4G8KxxxxxxxxxxxxxbwZLBr",
|
||||
SecretKey: "n5jTL9YxxxxxxxxxxxxaxmPLZV9",
|
||||
OpenKMS: true,
|
||||
TimeoutMs: 5000,
|
||||
}
|
||||
|
||||
// a more graceful way to create config client
|
||||
client, err := clients.NewConfigClient(
|
||||
vo.NacosClientParam{
|
||||
ClientConfig: &cc,
|
||||
},
|
||||
)
|
||||
|
||||
client, err := createConfigClient()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// to enable encrypt/decrypt, DataId should be start with "cipher-"
|
||||
_, err = client.PublishConfig(vo.ConfigParam{
|
||||
DataId: "cipher-dataId-1",
|
||||
Group: "test-group",
|
||||
Content: "hello world!",
|
||||
})
|
||||
for _, localConfig := range localConfigList {
|
||||
// to enable encrypt/decrypt, DataId should be start with "cipher-"
|
||||
configParam := vo.ConfigParam{
|
||||
DataId: localConfig.DataId,
|
||||
Group: localConfig.Group,
|
||||
Content: localConfig.Content,
|
||||
OnChange: func(namespace, group, dataId, data string) {
|
||||
fmt.Printf("successfully receive changed config: \n"+
|
||||
"group[%s], dataId[%s], data[%s]\n", group, dataId, data)
|
||||
},
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("PublishConfig err: %v\n", err)
|
||||
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)
|
||||
}
|
||||
|
||||
//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)
|
||||
}
|
||||
|
||||
func createConfigClient() (*config_client.ConfigClient, error) {
|
||||
nc := nacos_client.NacosClient{}
|
||||
_ = nc.SetServerConfig([]constant.ServerConfig{*localServerConfigWithOptions})
|
||||
_ = nc.SetClientConfig(*localClientConfigWithOptions)
|
||||
fmt.Println("ak: " + localClientConfigWithOptions.AccessKey)
|
||||
fmt.Println("sk: " + localClientConfigWithOptions.SecretKey)
|
||||
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, err := config_client.NewConfigClient(&nc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
kr6JxxxxxxxxxxxxxY8nHnsD6
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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)
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
LTAxxxxgQL
|
|
@ -0,0 +1,3 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
xxx
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"KeyId": "KAAxxxxe74",
|
||||
"PrivateKeyData": "MIIxxxA=="
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
kst-bjj64f82f41yjrs66eygc.cryptoservice.kms.aliyuncs.com
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* 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)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
19axxxxx213
|
|
@ -0,0 +1 @@
|
|||
iG48xxxV6C
|
|
@ -111,12 +111,6 @@ func main() {
|
|||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
//cancel config change
|
||||
err = client.CancelListenConfig(vo.ConfigParam{
|
||||
DataId: "test-data",
|
||||
Group: "test-group",
|
||||
})
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
_, err = client.DeleteConfig(vo.ConfigParam{
|
||||
DataId: "test-data",
|
||||
|
@ -124,6 +118,12 @@ func main() {
|
|||
})
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
//cancel config change
|
||||
err = client.CancelListenConfig(vo.ConfigParam{
|
||||
DataId: "test-data",
|
||||
Group: "test-group",
|
||||
})
|
||||
|
||||
searchPage, _ := client.SearchConfig(vo.SearchConfigParam{
|
||||
Search: "blur",
|
||||
DataId: "",
|
||||
|
|
|
@ -56,7 +56,7 @@ func main() {
|
|||
}
|
||||
|
||||
//Register
|
||||
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
|
||||
registerServiceInstance(client, vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.10",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
|
@ -70,7 +70,7 @@ func main() {
|
|||
})
|
||||
|
||||
//DeRegister
|
||||
ExampleServiceClient_DeRegisterServiceInstance(client, vo.DeregisterInstanceParam{
|
||||
deRegisterServiceInstance(client, vo.DeregisterInstanceParam{
|
||||
Ip: "10.0.0.10",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
|
@ -79,24 +79,37 @@ func main() {
|
|||
Ephemeral: true, //it must be true
|
||||
})
|
||||
|
||||
//Register
|
||||
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.10",
|
||||
Port: 8848,
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
//BatchRegister
|
||||
batchRegisterServiceInstance(client, vo.BatchRegisterInstanceParam{
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
ClusterName: "cluster-a",
|
||||
Weight: 10,
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
Metadata: map[string]string{"idc": "shanghai"},
|
||||
Instances: []vo.RegisterInstanceParam{{
|
||||
Ip: "10.0.0.10",
|
||||
Port: 8848,
|
||||
Weight: 10,
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
ClusterName: "cluster-a",
|
||||
Metadata: map[string]string{"idc": "shanghai"},
|
||||
}, {
|
||||
Ip: "10.0.0.12",
|
||||
Port: 8848,
|
||||
Weight: 7,
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
ClusterName: "cluster-a",
|
||||
Metadata: map[string]string{"idc": "shanghai"},
|
||||
}},
|
||||
})
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
//Get service with serviceName, groupName , clusters
|
||||
ExampleServiceClient_GetService(client, vo.GetServiceParam{
|
||||
getService(client, vo.GetServiceParam{
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
Clusters: []string{"cluster-a"},
|
||||
|
@ -104,7 +117,7 @@ func main() {
|
|||
|
||||
//SelectAllInstance
|
||||
//GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_SelectAllInstances(client, vo.SelectAllInstancesParam{
|
||||
selectAllInstances(client, vo.SelectAllInstancesParam{
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
Clusters: []string{"cluster-a"},
|
||||
|
@ -112,16 +125,17 @@ func main() {
|
|||
|
||||
//SelectInstances only return the instances of healthy=${HealthyOnly},enable=true and weight>0
|
||||
//ClusterName=DEFAULT,GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_SelectInstances(client, vo.SelectInstancesParam{
|
||||
selectInstances(client, vo.SelectInstancesParam{
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
Clusters: []string{"cluster-a"},
|
||||
HealthyOnly: true,
|
||||
})
|
||||
|
||||
//SelectOneHealthyInstance return one instance by WRR strategy for load balance
|
||||
//And the instance should be health=true,enable=true and weight>0
|
||||
//ClusterName=DEFAULT,GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_SelectOneHealthyInstance(client, vo.SelectOneHealthInstanceParam{
|
||||
selectOneHealthyInstance(client, vo.SelectOneHealthInstanceParam{
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
Clusters: []string{"cluster-a"},
|
||||
|
@ -129,31 +143,19 @@ func main() {
|
|||
|
||||
//Subscribe key=serviceName+groupName+cluster
|
||||
//Note:We call add multiple SubscribeCallback with the same key.
|
||||
param := &vo.SubscribeParam{
|
||||
subscribeParam := &vo.SubscribeParam{
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
SubscribeCallback: func(services []model.Instance, err error) {
|
||||
fmt.Printf("callback return services:%s \n\n", util.ToJsonString(services))
|
||||
},
|
||||
}
|
||||
ExampleServiceClient_Subscribe(client, param)
|
||||
subscribe(client, subscribeParam)
|
||||
|
||||
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.10",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
ClusterName: "cluster-a",
|
||||
Weight: 10,
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
Metadata: map[string]string{"idc": "beijing"},
|
||||
})
|
||||
//wait for client pull change from server
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
ExampleServiceClient_UpdateServiceInstance(client, vo.UpdateInstanceParam{
|
||||
updateServiceInstance(client, vo.UpdateInstanceParam{
|
||||
Ip: "10.0.0.11", //update ip
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
|
@ -168,24 +170,15 @@ func main() {
|
|||
|
||||
//wait for client pull change from server
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
//Now we just unsubscribe callback1, and callback2 will still receive change event
|
||||
ExampleServiceClient_UnSubscribe(client, param)
|
||||
ExampleServiceClient_DeRegisterServiceInstance(client, vo.DeregisterInstanceParam{
|
||||
Ip: "10.0.0.112",
|
||||
Ephemeral: true,
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
Cluster: "cluster-b",
|
||||
})
|
||||
//wait for client pull change from server
|
||||
time.Sleep(3 * time.Second)
|
||||
// UnSubscribe
|
||||
unSubscribe(client, subscribeParam)
|
||||
|
||||
//GeAllService will get the list of service name
|
||||
//NameSpace default value is public.If the client set the namespaceId, NameSpace will use it.
|
||||
//GroupName default value is DEFAULT_GROUP
|
||||
ExampleServiceClient_GetAllService(client, vo.GetAllServiceInfoParam{
|
||||
PageNo: 1,
|
||||
PageSize: 10,
|
||||
getAllService(client, vo.GetAllServiceInfoParam{
|
||||
GroupName: "group-a",
|
||||
PageNo: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
)
|
||||
|
||||
func ExampleServiceClient_RegisterServiceInstance(client naming_client.INamingClient, param vo.RegisterInstanceParam) {
|
||||
func registerServiceInstance(client naming_client.INamingClient, param vo.RegisterInstanceParam) {
|
||||
success, err := client.RegisterInstance(param)
|
||||
if !success || err != nil {
|
||||
panic("RegisterServiceInstance failed!" + err.Error())
|
||||
|
@ -32,47 +32,55 @@ func ExampleServiceClient_RegisterServiceInstance(client naming_client.INamingCl
|
|||
fmt.Printf("RegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
|
||||
}
|
||||
|
||||
func ExampleServiceClient_DeRegisterServiceInstance(client naming_client.INamingClient, param vo.DeregisterInstanceParam) {
|
||||
func batchRegisterServiceInstance(client naming_client.INamingClient, param vo.BatchRegisterInstanceParam) {
|
||||
success, err := client.BatchRegisterInstance(param)
|
||||
if !success || err != nil {
|
||||
panic("BatchRegisterServiceInstance failed!" + err.Error())
|
||||
}
|
||||
fmt.Printf("BatchRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
|
||||
}
|
||||
|
||||
func deRegisterServiceInstance(client naming_client.INamingClient, param vo.DeregisterInstanceParam) {
|
||||
success, err := client.DeregisterInstance(param)
|
||||
if !success || err != nil {
|
||||
panic("DeRegisterServiceInstance failed!")
|
||||
panic("DeRegisterServiceInstance failed!" + err.Error())
|
||||
}
|
||||
fmt.Printf("DeRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success)
|
||||
}
|
||||
|
||||
func ExampleServiceClient_UpdateServiceInstance(client naming_client.INamingClient, param vo.UpdateInstanceParam) {
|
||||
func updateServiceInstance(client naming_client.INamingClient, param vo.UpdateInstanceParam) {
|
||||
success, err := client.UpdateInstance(param)
|
||||
if !success || err != nil {
|
||||
panic("UpdateInstance failed!")
|
||||
panic("UpdateInstance failed!" + err.Error())
|
||||
}
|
||||
fmt.Printf("UpdateServiceInstance,param:%+v,result:%+v \n\n", param, success)
|
||||
}
|
||||
|
||||
func ExampleServiceClient_GetService(client naming_client.INamingClient, param vo.GetServiceParam) {
|
||||
func getService(client naming_client.INamingClient, param vo.GetServiceParam) {
|
||||
service, err := client.GetService(param)
|
||||
if err != nil {
|
||||
panic("GetService failed!")
|
||||
panic("GetService failed!" + err.Error())
|
||||
}
|
||||
fmt.Printf("GetService,param:%+v, result:%+v \n\n", param, service)
|
||||
}
|
||||
|
||||
func ExampleServiceClient_SelectAllInstances(client naming_client.INamingClient, param vo.SelectAllInstancesParam) {
|
||||
func selectAllInstances(client naming_client.INamingClient, param vo.SelectAllInstancesParam) {
|
||||
instances, err := client.SelectAllInstances(param)
|
||||
if err != nil {
|
||||
panic("SelectAllInstances failed!")
|
||||
panic("SelectAllInstances failed!" + err.Error())
|
||||
}
|
||||
fmt.Printf("SelectAllInstance,param:%+v, result:%+v \n\n", param, instances)
|
||||
}
|
||||
|
||||
func ExampleServiceClient_SelectInstances(client naming_client.INamingClient, param vo.SelectInstancesParam) {
|
||||
func selectInstances(client naming_client.INamingClient, param vo.SelectInstancesParam) {
|
||||
instances, err := client.SelectInstances(param)
|
||||
if err != nil {
|
||||
panic("SelectInstances failed!")
|
||||
panic("SelectInstances failed!" + err.Error())
|
||||
}
|
||||
fmt.Printf("SelectInstances,param:%+v, result:%+v \n\n", param, instances)
|
||||
}
|
||||
|
||||
func ExampleServiceClient_SelectOneHealthyInstance(client naming_client.INamingClient, param vo.SelectOneHealthInstanceParam) {
|
||||
func selectOneHealthyInstance(client naming_client.INamingClient, param vo.SelectOneHealthInstanceParam) {
|
||||
instances, err := client.SelectOneHealthyInstance(param)
|
||||
if err != nil {
|
||||
panic("SelectOneHealthyInstance failed!")
|
||||
|
@ -80,15 +88,15 @@ func ExampleServiceClient_SelectOneHealthyInstance(client naming_client.INamingC
|
|||
fmt.Printf("SelectOneHealthyInstance,param:%+v, result:%+v \n\n", param, instances)
|
||||
}
|
||||
|
||||
func ExampleServiceClient_Subscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
|
||||
func subscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
|
||||
client.Subscribe(param)
|
||||
}
|
||||
|
||||
func ExampleServiceClient_UnSubscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
|
||||
func unSubscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
|
||||
client.Unsubscribe(param)
|
||||
}
|
||||
|
||||
func ExampleServiceClient_GetAllService(client naming_client.INamingClient, param vo.GetAllServiceInfoParam) {
|
||||
func getAllService(client naming_client.INamingClient, param vo.GetAllServiceInfoParam) {
|
||||
service, err := client.GetAllServicesInfo(param)
|
||||
if err != nil {
|
||||
panic("GetAllService failed!")
|
||||
|
|
69
go.mod
69
go.mod
|
@ -1,19 +1,72 @@
|
|||
module github.com/nacos-group/nacos-sdk-go/v2
|
||||
|
||||
go 1.15
|
||||
// v2.2.9 is deprecated due to a critical bug. Use v2.3.0 or later
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10
|
||||
github.com/alibabacloud-go/kms-20160120/v3 v3.2.3
|
||||
github.com/alibabacloud-go/tea v1.2.2
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800
|
||||
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1
|
||||
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8
|
||||
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5
|
||||
github.com/aliyun/credentials-go v1.4.3
|
||||
github.com/buger/jsonparser v1.1.1
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.12.2
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
go.uber.org/zap v1.21.0
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9
|
||||
google.golang.org/grpc v1.48.0
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
|
||||
golang.org/x/sync v0.10.0
|
||||
golang.org/x/time v0.1.0
|
||||
google.golang.org/grpc v1.67.3
|
||||
google.golang.org/protobuf v1.36.5
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f
|
||||
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
216
go.sum
|
@ -39,9 +39,67 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
|
|||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 h1:PpfENOj/vPfhhy9N2OFRjpue0hjM5XqAp2thFmkXXIk=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 h1:eIf+iGJxdU4U9ypaUfbtOWCsZSbTb8AUHvyPrxu6mAA=
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6/go.mod h1:4EUIoxs/do24zMOGGqYVWgw0s9NtiylnJglOeEB5UJo=
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 h1:zE8vH9C7JiZLNJJQ5OwjU9mSi4T9ef9u3BURT6LCLC8=
|
||||
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5/go.mod h1:tWnyE9AjF8J8qqLk645oUmVUnFybApTQWklQmi5tY6g=
|
||||
github.com/alibabacloud-go/darabonba-array v0.1.0 h1:vR8s7b1fWAQIjEjWnuF0JiKsCvclSRTfDzZHTYqfufY=
|
||||
github.com/alibabacloud-go/darabonba-array v0.1.0/go.mod h1:BLKxr0brnggqOJPqT09DFJ8g3fsDshapUD3C3aOEFaI=
|
||||
github.com/alibabacloud-go/darabonba-encode-util v0.0.2 h1:1uJGrbsGEVqWcWxrS9MyC2NG0Ax+GpOM5gtupki31XE=
|
||||
github.com/alibabacloud-go/darabonba-encode-util v0.0.2/go.mod h1:JiW9higWHYXm7F4PKuMgEUETNZasrDM6vqVr/Can7H8=
|
||||
github.com/alibabacloud-go/darabonba-map v0.0.2 h1:qvPnGB4+dJbJIxOOfawxzF3hzMnIpjmafa0qOTp6udc=
|
||||
github.com/alibabacloud-go/darabonba-map v0.0.2/go.mod h1:28AJaX8FOE/ym8OUFWga+MtEzBunJwQGceGQlvaPGPc=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.9/go.mod h1:bb+Io8Sn2RuM3/Rpme6ll86jMyFSrD1bxeV/+v61KeU=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 h1:GEYkMApgpKEVDn6z12DcH1EGYpDYRB8JxsazM4Rywak=
|
||||
github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10/go.mod h1:26a14FGhZVELuz2cc2AolvW4RHmIO3/HRwsdHhaIPDE=
|
||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7 h1:UzCnKvsjPFzApvODDNEYqBHMFt1w98wC7FOo0InLyxg=
|
||||
github.com/alibabacloud-go/darabonba-signature-util v0.0.7/go.mod h1:oUzCYV2fcCH797xKdL6BDH8ADIHlzrtKVjeRtunBNTQ=
|
||||
github.com/alibabacloud-go/darabonba-string v1.0.2 h1:E714wms5ibdzCqGeYJ9JCFywE5nDyvIXIIQbZVFkkqo=
|
||||
github.com/alibabacloud-go/darabonba-string v1.0.2/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA=
|
||||
github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
|
||||
github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
||||
github.com/alibabacloud-go/debug v1.0.1 h1:MsW9SmUtbb1Fnt3ieC6NNZi6aEwrXfDksD4QA6GSbPg=
|
||||
github.com/alibabacloud-go/debug v1.0.1/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc=
|
||||
github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
|
||||
github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
|
||||
github.com/alibabacloud-go/kms-20160120/v3 v3.2.3 h1:vamGcYQFwXVqR6RWcrVTTqlIXZVsYjaA7pZbx+Xw6zw=
|
||||
github.com/alibabacloud-go/kms-20160120/v3 v3.2.3/go.mod h1:3rIyughsFDLie1ut9gQJXkWkMg/NfXBCk+OtXnPu3lw=
|
||||
github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=
|
||||
github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
|
||||
github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg=
|
||||
github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||
github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||
github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4=
|
||||
github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.1.20/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
|
||||
github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA=
|
||||
github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU=
|
||||
github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk=
|
||||
github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.4 h1:lxCDvNCdTo9FaXKKq45+4vGETQUKNOW/qKTcX9Sk53o=
|
||||
github.com/alibabacloud-go/tea-utils v1.4.4/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw=
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.3/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ=
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4=
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.6/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7 h1:WDx5qW3Xa5ZgJ1c8NfqJkF6w+AU5wB8835UdhPr6Ax0=
|
||||
github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/TTs3E+U9MJpd001iWQ9I=
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0=
|
||||
github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 h1:ie/8RxBOfKZWcrbYSJi2Z8uX8TcOlSMwPlEJh83OeOw=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
|
||||
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 h1:nJYyoFP+aqGKgPs9JeZgS1rWQ4NndNR0Zfhh161ZltU=
|
||||
github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1/go.mod h1:WzGOmFFTlUzXM03CJnHWMQ85UN6QGpOXZocCjwkiyOg=
|
||||
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 h1:QeUdR7JF7iNCvO/81EhxEr3wDwxk4YBoYZOq6E0AjHI=
|
||||
github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8/go.mod h1:xP0KIZry6i7oGPF24vhAPr1Q8vLZRcMcxtft5xDKwCU=
|
||||
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 h1:8S0mtD101RDYa0LXwdoqgN0RxdMmmJYjq8g2mk7/lQ4=
|
||||
github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5/go.mod h1:M19fxYz3gpm0ETnoKweYyYtqrtnVtrpKFpwsghbw+cQ=
|
||||
github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
|
||||
github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0=
|
||||
github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM=
|
||||
github.com/aliyun/credentials-go v1.3.10/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||
github.com/aliyun/credentials-go v1.4.3 h1:N3iHyvHRMyOwY1+0qBLSf3hb5JFiOujVSVuEpgeGttY=
|
||||
github.com/aliyun/credentials-go v1.4.3/go.mod h1:Jm6d+xIgwJVLVWT561vy67ZRP4lPTQxMbEYRuT2Ti1U=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
|
@ -52,28 +110,25 @@ github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMU
|
|||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
|
||||
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ=
|
||||
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
|
@ -114,8 +169,9 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
|
@ -127,8 +183,8 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
|
@ -140,10 +196,10 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf
|
|||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
|
@ -158,13 +214,13 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
|||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
|
@ -180,6 +236,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc h1:Ak86L+yDSOzKFa7WM5bf5itSOo1e3Xh8bm5YCMUXIjQ=
|
||||
github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
|
@ -208,29 +268,41 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
|
|||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
|
@ -244,7 +316,18 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
@ -266,7 +349,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
|
|||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
|
@ -276,8 +358,9 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -306,10 +389,21 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
|
|||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -326,8 +420,10 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -353,6 +449,7 @@ golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -361,33 +458,59 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
|
||||
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
||||
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
|
@ -416,6 +539,7 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs
|
|||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
|
@ -423,12 +547,12 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
|
|||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
|
@ -475,14 +599,14 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
|
|||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987 h1:PDIOdWxZ8eRizhKa1AAvY53xsvLB1cWorMjslvY3VA8=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
|
@ -495,10 +619,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
|
|||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
|
||||
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.67.3 h1:OgPcDAFKHnH8X3O4WcO4XUc8GRDeKsKReqbQtiCj7N8=
|
||||
google.golang.org/grpc v1.67.3/go.mod h1:YGaHCc6Oap+FzBJTZLBzkGSYt/cvGPFTPxkn7QfSU8s=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
@ -511,21 +633,24 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
|
|||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
|
||||
gopkg.in/ini.v1 v1.56.0/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/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -533,8 +658,9 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
|
|
@ -70,27 +70,30 @@ func (u UUID) MarshalText() (text []byte, err error) {
|
|||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// Following formats are supported:
|
||||
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
||||
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
|
||||
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
|
||||
// "6ba7b8109dad11d180b400c04fd430c8"
|
||||
//
|
||||
// "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
|
||||
// "{6ba7b810-9dad-11d1-80b4-00c04fd430c8}",
|
||||
// "urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8"
|
||||
// "6ba7b8109dad11d180b400c04fd430c8"
|
||||
//
|
||||
// ABNF for supported UUID text representation follows:
|
||||
// uuid := canonical | hashlike | braced | urn
|
||||
// plain := canonical | hashlike
|
||||
// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
|
||||
// hashlike := 12hexoct
|
||||
// braced := '{' plain '}'
|
||||
// urn := URN ':' UUID-NID ':' plain
|
||||
// URN := 'urn'
|
||||
// UUID-NID := 'uuid'
|
||||
// 12hexoct := 6hexoct 6hexoct
|
||||
// 6hexoct := 4hexoct 2hexoct
|
||||
// 4hexoct := 2hexoct 2hexoct
|
||||
// 2hexoct := hexoct hexoct
|
||||
// hexoct := hexdig hexdig
|
||||
// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
|
||||
// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
|
||||
// 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
|
||||
//
|
||||
// uuid := canonical | hashlike | braced | urn
|
||||
// plain := canonical | hashlike
|
||||
// canonical := 4hexoct '-' 2hexoct '-' 2hexoct '-' 6hexoct
|
||||
// hashlike := 12hexoct
|
||||
// braced := '{' plain '}'
|
||||
// urn := URN ':' UUID-NID ':' plain
|
||||
// URN := 'urn'
|
||||
// UUID-NID := 'uuid'
|
||||
// 12hexoct := 6hexoct 6hexoct
|
||||
// 6hexoct := 4hexoct 2hexoct
|
||||
// 4hexoct := 2hexoct 2hexoct
|
||||
// 2hexoct := hexoct hexoct
|
||||
// hexoct := hexdig hexdig
|
||||
// hexdig := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
|
||||
// 'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
|
||||
// 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
|
||||
func (u *UUID) UnmarshalText(text []byte) (err error) {
|
||||
switch len(text) {
|
||||
case 32:
|
||||
|
|
|
@ -152,6 +152,7 @@ func (u *UUID) SetVariant(v byte) {
|
|||
// Must is a helper that wraps a call to a function returning (UUID, error)
|
||||
// and panics if the error is non-nil. It is intended for use in variable
|
||||
// initializations such as
|
||||
//
|
||||
// var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000"));
|
||||
func Must(u UUID, err error) UUID {
|
||||
if err != nil {
|
||||
|
|
|
@ -46,3 +46,9 @@ type ConfigContext struct {
|
|||
DataId string `json:"dataId"`
|
||||
Tenant string `json:"tenant"`
|
||||
}
|
||||
|
||||
type ConfigPageResult struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Data ConfigPage `json:"data"`
|
||||
}
|
||||
|
|
|
@ -139,3 +139,12 @@ func DeepCopyMap(params map[string]string) map[string]string {
|
|||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func Contains(slice []string, item string) bool {
|
||||
for _, s := range slice {
|
||||
if s == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
package util
|
||||
|
||||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
|
@ -16,6 +14,8 @@ package util
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package util
|
||||
|
||||
const SHOW_CONTENT_SIZE = 100
|
||||
|
||||
func TruncateContent(content string) string {
|
||||
|
|
|
@ -13,11 +13,16 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package vo
|
||||
|
||||
import "github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/security"
|
||||
)
|
||||
|
||||
type NacosClientParam struct {
|
||||
ClientConfig *constant.ClientConfig // optional
|
||||
ServerConfigs []constant.ServerConfig // optional
|
||||
ClientConfig *constant.ClientConfig // optional
|
||||
ServerConfigs []constant.ServerConfig // optional
|
||||
RamCredentialProvider security.RamCredentialProvider // optinal
|
||||
}
|
||||
|
|
|
@ -19,18 +19,38 @@ package vo
|
|||
type Listener func(namespace, group, dataId, data string)
|
||||
|
||||
type ConfigParam struct {
|
||||
DataId string `param:"dataId"` //required
|
||||
Group string `param:"group"` //required
|
||||
Content string `param:"content"` //required
|
||||
Tag string `param:"tag"`
|
||||
AppName string `param:"appName"`
|
||||
BetaIps string `param:"betaIps"`
|
||||
CasMd5 string `param:"casMd5"`
|
||||
Type string `param:"type"`
|
||||
EncryptedDataKey string `param:"encryptedDataKey"`
|
||||
DataId string `param:"dataId"` //required
|
||||
Group string `param:"group"` //required
|
||||
Content string `param:"content"` //required
|
||||
Tag string `param:"tag"`
|
||||
ConfigTags string `param:"configTags"`
|
||||
AppName string `param:"appName"`
|
||||
BetaIps string `param:"betaIps"`
|
||||
CasMd5 string `param:"casMd5"`
|
||||
Type string `param:"type"`
|
||||
SrcUser string `param:"srcUser"`
|
||||
EncryptedDataKey string `param:"encryptedDataKey"`
|
||||
KmsKeyId string `param:"kmsKeyId"`
|
||||
UsageType UsageType `param:"usageType"`
|
||||
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 {
|
||||
Search string `param:"search"`
|
||||
DataId string `param:"dataId"`
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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, ¶m.OnChange, ¶mDeepCopied.OnChange)
|
||||
assert.NotEqual(t, ¶m, ¶mDeepCopied)
|
||||
})
|
||||
}
|
|
@ -25,16 +25,22 @@ type RegisterInstanceParam struct {
|
|||
Enable bool `param:"enabled"` //required,the instance can be access or not
|
||||
Healthy bool `param:"healthy"` //required,the instance is health or not
|
||||
Metadata map[string]string `param:"metadata"` //optional
|
||||
ClusterName string `param:"clusterName"` //optional,default:DEFAULT
|
||||
ClusterName string `param:"clusterName"` //optional
|
||||
ServiceName string `param:"serviceName"` //required
|
||||
GroupName string `param:"groupName"` //optional,default:DEFAULT_GROUP
|
||||
Ephemeral bool `param:"ephemeral"` //optional
|
||||
}
|
||||
|
||||
type BatchRegisterInstanceParam struct {
|
||||
ServiceName string `param:"serviceName"` //required
|
||||
GroupName string `param:"groupName"` //optional,default:DEFAULT_GROUP
|
||||
Instances []RegisterInstanceParam //required
|
||||
}
|
||||
|
||||
type DeregisterInstanceParam struct {
|
||||
Ip string `param:"ip"` //required
|
||||
Port uint64 `param:"port"` //required
|
||||
Cluster string `param:"cluster"` //optional,default:DEFAULT
|
||||
Cluster string `param:"cluster"` //optional
|
||||
ServiceName string `param:"serviceName"` //required
|
||||
GroupName string `param:"groupName"` //optional,default:DEFAULT_GROUP
|
||||
Ephemeral bool `param:"ephemeral"` //optional
|
||||
|
@ -47,14 +53,14 @@ type UpdateInstanceParam struct {
|
|||
Enable bool `param:"enabled"` //required,the instance can be access or not
|
||||
Healthy bool `param:"healthy"` //required,the instance is health or not
|
||||
Metadata map[string]string `param:"metadata"` //optional
|
||||
ClusterName string `param:"clusterName"` //optional,default:DEFAULT
|
||||
ClusterName string `param:"clusterName"` //optional
|
||||
ServiceName string `param:"serviceName"` //required
|
||||
GroupName string `param:"groupName"` //optional,default:DEFAULT_GROUP
|
||||
Ephemeral bool `param:"ephemeral"` //optional
|
||||
}
|
||||
|
||||
type GetServiceParam struct {
|
||||
Clusters []string `param:"clusters"` //optional,default:DEFAULT
|
||||
Clusters []string `param:"clusters"` //optional
|
||||
ServiceName string `param:"serviceName"` //required
|
||||
GroupName string `param:"groupName"` //optional,default:DEFAULT_GROUP
|
||||
}
|
||||
|
@ -68,26 +74,26 @@ type GetAllServiceInfoParam struct {
|
|||
|
||||
type SubscribeParam struct {
|
||||
ServiceName string `param:"serviceName"` //required
|
||||
Clusters []string `param:"clusters"` //optional,default:DEFAULT
|
||||
Clusters []string `param:"clusters"` //optional
|
||||
GroupName string `param:"groupName"` //optional,default:DEFAULT_GROUP
|
||||
SubscribeCallback func(services []model.Instance, err error) //required
|
||||
}
|
||||
|
||||
type SelectAllInstancesParam struct {
|
||||
Clusters []string `param:"clusters"` //optional,default:DEFAULT
|
||||
Clusters []string `param:"clusters"` //optional
|
||||
ServiceName string `param:"serviceName"` //required
|
||||
GroupName string `param:"groupName"` //optional,default:DEFAULT_GROUP
|
||||
}
|
||||
|
||||
type SelectInstancesParam struct {
|
||||
Clusters []string `param:"clusters"` //optional,default:DEFAULT
|
||||
Clusters []string `param:"clusters"` //optional
|
||||
ServiceName string `param:"serviceName"` //required
|
||||
GroupName string `param:"groupName"` //optional,default:DEFAULT_GROUP
|
||||
HealthyOnly bool `param:"healthyOnly"` //optional,return only healthy instance
|
||||
HealthyOnly bool `param:"healthyOnly"` //optional,value = true return only healthy instance, value = false return only unHealthy instance
|
||||
}
|
||||
|
||||
type SelectOneHealthInstanceParam struct {
|
||||
Clusters []string `param:"clusters"` //optional,default:DEFAULT
|
||||
Clusters []string `param:"clusters"` //optional
|
||||
ServiceName string `param:"serviceName"` //required
|
||||
GroupName string `param:"groupName"` //optional,default:DEFAULT_GROUP
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue