Compare commits
6 Commits
master
...
v2.0.0-Alp
Author | SHA1 | Date |
---|---|---|
|
9eef0329a7 | |
|
fb490395ce | |
|
7a2d20f2bf | |
|
a42d35ad2c | |
|
b718836ea4 | |
|
8cb8d63e7e |
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: nacos_grpc_service.proto
|
||||
|
||||
package grpc
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type Metadata struct {
|
||||
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
|
||||
ClientIp string `protobuf:"bytes,8,opt,name=clientIp,proto3" json:"clientIp,omitempty"`
|
||||
Headers map[string]string `protobuf:"bytes,7,rep,name=headers,proto3" json:"headers,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Metadata) Reset() { *m = Metadata{} }
|
||||
func (m *Metadata) String() string { return proto.CompactTextString(m) }
|
||||
func (*Metadata) ProtoMessage() {}
|
||||
func (*Metadata) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f908b146bdb05ce9, []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
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Metadata) GetClientIp() string {
|
||||
if m != nil {
|
||||
return m.ClientIp
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Metadata) GetHeaders() map[string]string {
|
||||
if m != nil {
|
||||
return m.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:"-"`
|
||||
}
|
||||
|
||||
func (m *Payload) Reset() { *m = Payload{} }
|
||||
func (m *Payload) String() string { return proto.CompactTextString(m) }
|
||||
func (*Payload) ProtoMessage() {}
|
||||
func (*Payload) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f908b146bdb05ce9, []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
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Payload) GetBody() *any.Any {
|
||||
if m != nil {
|
||||
return m.Body
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Metadata)(nil), "Metadata")
|
||||
proto.RegisterMapType((map[string]string)(nil), "Metadata.HeadersEntry")
|
||||
proto.RegisterType((*Payload)(nil), "Payload")
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
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,
|
||||
},
|
||||
},
|
||||
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",
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
|
||||
option java_multiple_files = true;
|
||||
option java_package = "com.alibaba.nacos.api.grpc.auto";
|
||||
|
||||
message Metadata {
|
||||
string type = 3;
|
||||
string clientIp = 8;
|
||||
map<string, string> headers = 7;
|
||||
}
|
||||
|
||||
|
||||
message Payload {
|
||||
Metadata metadata = 2;
|
||||
google.protobuf.Any body = 3;
|
||||
}
|
||||
|
||||
service RequestStream {
|
||||
// build a streamRequest
|
||||
rpc requestStream (Payload) returns (stream Payload) {
|
||||
}
|
||||
}
|
||||
|
||||
service Request {
|
||||
// Sends a commonRequest
|
||||
rpc request (Payload) returns (Payload) {
|
||||
}
|
||||
}
|
||||
|
||||
service BiRequestStream {
|
||||
// Sends a commonRequest
|
||||
rpc requestBiStream (stream Payload) returns (stream Payload) {
|
||||
}
|
||||
}
|
|
@ -24,10 +24,10 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/file"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"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"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
func GetFileName(cacheKey string, cacheDir string) string {
|
||||
|
|
|
@ -19,12 +19,13 @@ package clients
|
|||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/config_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/nacos_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
// CreateConfigClient use to create config client
|
||||
|
@ -48,7 +49,7 @@ func NewConfigClient(param vo.NacosClientParam) (iClient config_client.IConfigCl
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
iClient = &config
|
||||
iClient = config
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -61,7 +62,7 @@ func NewNamingClient(param vo.NacosClientParam) (iClient naming_client.INamingCl
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
iClient = &naming
|
||||
iClient = naming
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
|
@ -19,23 +19,28 @@ package config_client
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/aliyun/alibaba-cloud-sdk-go/services/kms"
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/nacos_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/nacos_error"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"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"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"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"
|
||||
"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"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
)
|
||||
|
||||
const (
|
||||
perTaskConfigSize = 3000
|
||||
executorErrDelay = 5 * time.Second
|
||||
)
|
||||
|
||||
type ConfigClient struct {
|
||||
|
@ -43,32 +48,27 @@ type ConfigClient struct {
|
|||
kmsClient *kms.Client
|
||||
localConfigs []vo.ConfigParam
|
||||
mutex sync.Mutex
|
||||
configProxy ConfigProxy
|
||||
configProxy IConfigProxy
|
||||
configCacheDir string
|
||||
lastAllSyncTime time.Time
|
||||
cacheMap cache.ConcurrentMap
|
||||
uid string
|
||||
listenExecute chan struct{}
|
||||
}
|
||||
|
||||
const (
|
||||
perTaskConfigSize = 3000
|
||||
executorErrDelay = 5 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
currentTaskCount int
|
||||
cacheMap = cache.NewConcurrentMap()
|
||||
schedulerMap = cache.NewConcurrentMap()
|
||||
)
|
||||
|
||||
type cacheData struct {
|
||||
isInitializing bool
|
||||
dataId string
|
||||
group string
|
||||
content string
|
||||
contentType string
|
||||
tenant string
|
||||
cacheDataListener *cacheDataListener
|
||||
md5 string
|
||||
appName string
|
||||
taskId int
|
||||
configClient *ConfigClient
|
||||
isSyncWithServer bool
|
||||
}
|
||||
|
||||
type cacheDataListener struct {
|
||||
|
@ -76,65 +76,58 @@ type cacheDataListener struct {
|
|||
lastMd5 string
|
||||
}
|
||||
|
||||
func init() {
|
||||
schedulerMap.Set("root", true)
|
||||
go delayScheduler(time.NewTimer(1*time.Millisecond), 10*time.Millisecond, "root", listenConfigExecutor())
|
||||
}
|
||||
|
||||
func NewConfigClient(nc nacos_client.INacosClient) (ConfigClient, error) {
|
||||
config := ConfigClient{}
|
||||
func NewConfigClient(nc nacos_client.INacosClient) (*ConfigClient, error) {
|
||||
config := &ConfigClient{}
|
||||
config.INacosClient = nc
|
||||
clientConfig, err := nc.GetClientConfig()
|
||||
if err != nil {
|
||||
return config, err
|
||||
return nil, err
|
||||
}
|
||||
serverConfig, err := nc.GetServerConfig()
|
||||
if err != nil {
|
||||
return config, err
|
||||
return nil, err
|
||||
}
|
||||
httpAgent, err := nc.GetHttpAgent()
|
||||
if err != nil {
|
||||
return config, err
|
||||
return nil, err
|
||||
}
|
||||
err = logger.InitLogger(logger.Config{
|
||||
|
||||
if err = initLogger(clientConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.configCacheDir = clientConfig.CacheDir + string(os.PathSeparator) + "config"
|
||||
|
||||
config.configProxy, err = NewConfigProxy(serverConfig, clientConfig, httpAgent)
|
||||
if clientConfig.OpenKMS {
|
||||
kmsClient, err := kms.NewClientWithAccessKey(clientConfig.RegionId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.kmsClient = kmsClient
|
||||
}
|
||||
|
||||
uid, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
config.uid = uid.String()
|
||||
|
||||
config.cacheMap = cache.NewConcurrentMap()
|
||||
|
||||
config.listenExecute = make(chan struct{}, 1)
|
||||
|
||||
config.startInternal()
|
||||
|
||||
return config, err
|
||||
}
|
||||
|
||||
func initLogger(clientConfig constant.ClientConfig) error {
|
||||
return logger.InitLogger(logger.Config{
|
||||
Level: clientConfig.LogLevel,
|
||||
OutputPath: clientConfig.LogDir,
|
||||
RotationTime: clientConfig.RotateTime,
|
||||
MaxAge: clientConfig.MaxAge,
|
||||
})
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
config.configCacheDir = clientConfig.CacheDir + string(os.PathSeparator) + "config"
|
||||
config.configProxy, err = NewConfigProxy(serverConfig, clientConfig, httpAgent)
|
||||
if clientConfig.OpenKMS {
|
||||
kmsClient, err := kms.NewClientWithAccessKey(clientConfig.RegionId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
if err != nil {
|
||||
return config, err
|
||||
}
|
||||
config.kmsClient = kmsClient
|
||||
}
|
||||
return config, err
|
||||
}
|
||||
|
||||
func (client *ConfigClient) sync() (clientConfig constant.ClientConfig,
|
||||
serverConfigs []constant.ServerConfig, agent http_agent.IHttpAgent, err error) {
|
||||
clientConfig, err = client.GetClientConfig()
|
||||
if err != nil {
|
||||
logger.Errorf("getClientConfig catch error:%+v", err)
|
||||
return
|
||||
}
|
||||
serverConfigs, err = client.GetServerConfig()
|
||||
if err != nil {
|
||||
logger.Errorf("getServerConfig catch error:%+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
agent, err = client.GetHttpAgent()
|
||||
if err != nil {
|
||||
logger.Errorf("getHttpAgent catch error:%+v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (client *ConfigClient) GetConfig(param vo.ConfigParam) (content string, err error) {
|
||||
|
@ -186,55 +179,55 @@ func (client *ConfigClient) getConfigInner(param vo.ConfigParam) (content string
|
|||
return "", err
|
||||
}
|
||||
if len(param.Group) <= 0 {
|
||||
err = errors.New("[client.GetConfig] param.group can not be empty")
|
||||
return "", err
|
||||
param.Group = constant.DEFAULT_GROUP
|
||||
}
|
||||
//todo 优先使用本地配置
|
||||
//todo 获取容灾配置的 EncryptedDataKey LocalEncryptedDataKeyProcessor.getEncryptDataKeyFailover
|
||||
clientConfig, _ := client.GetClientConfig()
|
||||
cacheKey := util.GetConfigCacheKey(param.DataId, param.Group, clientConfig.NamespaceId)
|
||||
content, err = client.configProxy.GetConfigProxy(param, clientConfig.NamespaceId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
|
||||
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)
|
||||
if _, ok := err.(*nacos_error.NacosError); ok {
|
||||
nacosErr := err.(*nacos_error.NacosError)
|
||||
if nacosErr.ErrorCode() == "404" {
|
||||
cache.WriteConfigToFile(cacheKey, client.configCacheDir, "")
|
||||
return "", errors.New("config not found")
|
||||
}
|
||||
if nacosErr.ErrorCode() == "403" {
|
||||
return "", errors.New("get config forbidden")
|
||||
}
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
} else {
|
||||
cache.WriteConfigToFile(cacheKey, client.configCacheDir, content)
|
||||
}
|
||||
return content, nil
|
||||
}
|
||||
return response.Content, nil
|
||||
}
|
||||
|
||||
func (client *ConfigClient) PublishConfig(param vo.ConfigParam) (published bool,
|
||||
err error) {
|
||||
func (client *ConfigClient) PublishConfig(param vo.ConfigParam) (published bool, err error) {
|
||||
if len(param.DataId) <= 0 {
|
||||
err = errors.New("[client.PublishConfig] param.dataId can not be empty")
|
||||
}
|
||||
if len(param.Group) <= 0 {
|
||||
err = errors.New("[client.PublishConfig] param.group can not be empty")
|
||||
}
|
||||
if len(param.Content) <= 0 {
|
||||
err = errors.New("[client.PublishConfig] param.content can not be empty")
|
||||
}
|
||||
|
||||
if len(param.Group) <= 0 {
|
||||
param.Group = constant.DEFAULT_GROUP
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
param.Content, err = client.encrypt(param.DataId, param.Content)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
clientConfig, _ := client.GetClientConfig()
|
||||
return client.configProxy.PublishConfigProxy(param, clientConfig.NamespaceId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
request := rpc_request.NewConfigPublishRequest(param.Group, param.DataId, clientConfig.NamespaceId, param.Content, param.CasMd5)
|
||||
request.AdditionMap["tag"] = param.Tag
|
||||
request.AdditionMap["appName"] = param.AppName
|
||||
request.AdditionMap["betaIps"] = param.BetaIps
|
||||
request.AdditionMap["type"] = param.Type
|
||||
request.AdditionMap["encryptedDataKey"] = param.EncryptedDataKey
|
||||
rpcClient := client.configProxy.getRpcClient(client)
|
||||
response, err := client.configProxy.requestProxy(rpcClient, request, constant.DEFAULT_TIMEOUT_MILLS)
|
||||
return response.IsSuccess(), err
|
||||
}
|
||||
|
||||
func (client *ConfigClient) DeleteConfig(param vo.ConfigParam) (deleted bool, err error) {
|
||||
|
@ -242,11 +235,17 @@ func (client *ConfigClient) DeleteConfig(param vo.ConfigParam) (deleted bool, er
|
|||
err = errors.New("[client.DeleteConfig] param.dataId can not be empty")
|
||||
}
|
||||
if len(param.Group) <= 0 {
|
||||
err = errors.New("[client.DeleteConfig] param.group can not be empty")
|
||||
param.Group = constant.DEFAULT_GROUP
|
||||
}
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
clientConfig, _ := client.GetClientConfig()
|
||||
return client.configProxy.DeleteConfigProxy(param, clientConfig.NamespaceId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
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)
|
||||
return response.IsSuccess(), err
|
||||
|
||||
}
|
||||
|
||||
//Cancel Listen Config
|
||||
|
@ -256,33 +255,11 @@ func (client *ConfigClient) CancelListenConfig(param vo.ConfigParam) (err error)
|
|||
logger.Errorf("[checkConfigInfo.GetClientConfig] failed,err:%+v", err)
|
||||
return
|
||||
}
|
||||
cacheMap.Remove(util.GetConfigCacheKey(param.DataId, param.Group, clientConfig.NamespaceId))
|
||||
client.cacheMap.Remove(util.GetConfigCacheKey(param.DataId, param.Group, clientConfig.NamespaceId))
|
||||
logger.Infof("Cancel listen config DataId:%s Group:%s", param.DataId, param.Group)
|
||||
remakeId := int(math.Ceil(float64(cacheMap.Count()) / float64(perTaskConfigSize)))
|
||||
if remakeId < currentTaskCount {
|
||||
remakeCacheDataTaskId(remakeId)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//Remake cache data taskId
|
||||
func remakeCacheDataTaskId(remakeId int) {
|
||||
for i := 0; i < remakeId; i++ {
|
||||
count := 0
|
||||
for _, key := range cacheMap.Keys() {
|
||||
if count == perTaskConfigSize {
|
||||
break
|
||||
}
|
||||
if value, ok := cacheMap.Get(key); ok {
|
||||
cData := value.(cacheData)
|
||||
cData.taskId = i
|
||||
cacheMap.Set(key, cData)
|
||||
}
|
||||
count++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
|
||||
if len(param.DataId) <= 0 {
|
||||
err = errors.New("[client.ListenConfig] DataId can not be empty")
|
||||
|
@ -300,7 +277,7 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
|
|||
|
||||
key := util.GetConfigCacheKey(param.DataId, param.Group, clientConfig.NamespaceId)
|
||||
var cData cacheData
|
||||
if v, ok := cacheMap.Get(key); ok {
|
||||
if v, ok := client.cacheMap.Get(key); ok {
|
||||
cData = v.(cacheData)
|
||||
cData.isInitializing = true
|
||||
} else {
|
||||
|
@ -328,150 +305,11 @@ func (client *ConfigClient) ListenConfig(param vo.ConfigParam) (err error) {
|
|||
content: content,
|
||||
md5: md5Str,
|
||||
cacheDataListener: listener,
|
||||
taskId: cacheMap.Count() / perTaskConfigSize,
|
||||
taskId: client.cacheMap.Count() / perTaskConfigSize,
|
||||
configClient: client,
|
||||
}
|
||||
}
|
||||
cacheMap.Set(key, cData)
|
||||
return
|
||||
}
|
||||
|
||||
//Delay Scheduler
|
||||
//initialDelay the time to delay first execution
|
||||
//delay the delay between the termination of one execution and the commencement of the next
|
||||
func delayScheduler(t *time.Timer, delay time.Duration, taskId string, execute func() error) {
|
||||
for {
|
||||
if v, ok := schedulerMap.Get(taskId); ok {
|
||||
if !v.(bool) {
|
||||
return
|
||||
}
|
||||
}
|
||||
<-t.C
|
||||
d := delay
|
||||
if err := execute(); err != nil {
|
||||
d = executorErrDelay
|
||||
}
|
||||
t.Reset(d)
|
||||
}
|
||||
}
|
||||
|
||||
//Listen for the configuration executor
|
||||
func listenConfigExecutor() func() error {
|
||||
return func() error {
|
||||
listenerSize := cacheMap.Count()
|
||||
taskCount := int(math.Ceil(float64(listenerSize) / float64(perTaskConfigSize)))
|
||||
|
||||
if taskCount > currentTaskCount {
|
||||
for i := currentTaskCount; i < taskCount; i++ {
|
||||
schedulerMap.Set(strconv.Itoa(i), true)
|
||||
go delayScheduler(time.NewTimer(1*time.Millisecond), 10*time.Millisecond, strconv.Itoa(i), longPulling(i))
|
||||
}
|
||||
currentTaskCount = taskCount
|
||||
} else if taskCount < currentTaskCount {
|
||||
for i := taskCount; i < currentTaskCount; i++ {
|
||||
if _, ok := schedulerMap.Get(strconv.Itoa(i)); ok {
|
||||
schedulerMap.Set(strconv.Itoa(i), false)
|
||||
}
|
||||
}
|
||||
currentTaskCount = taskCount
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//Long polling listening configuration
|
||||
func longPulling(taskId int) func() error {
|
||||
return func() error {
|
||||
var listeningConfigs string
|
||||
var client *ConfigClient
|
||||
initializationList := make([]cacheData, 0)
|
||||
for _, key := range cacheMap.Keys() {
|
||||
if value, ok := cacheMap.Get(key); ok {
|
||||
cData := value.(cacheData)
|
||||
client = cData.configClient
|
||||
if cData.taskId == taskId {
|
||||
if cData.isInitializing {
|
||||
initializationList = append(initializationList, cData)
|
||||
}
|
||||
if len(cData.tenant) > 0 {
|
||||
listeningConfigs += cData.dataId + constant.SPLIT_CONFIG_INNER + cData.group + constant.SPLIT_CONFIG_INNER +
|
||||
cData.md5 + constant.SPLIT_CONFIG_INNER + cData.tenant + constant.SPLIT_CONFIG
|
||||
} else {
|
||||
listeningConfigs += cData.dataId + constant.SPLIT_CONFIG_INNER + cData.group + constant.SPLIT_CONFIG_INNER +
|
||||
cData.md5 + constant.SPLIT_CONFIG
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(listeningConfigs) > 0 {
|
||||
clientConfig, err := client.GetClientConfig()
|
||||
if err != nil {
|
||||
logger.Errorf("[checkConfigInfo.GetClientConfig] err: %+v", err)
|
||||
return err
|
||||
}
|
||||
// http get
|
||||
params := make(map[string]string)
|
||||
params[constant.KEY_LISTEN_CONFIGS] = listeningConfigs
|
||||
|
||||
var changed string
|
||||
changedTmp, err := client.configProxy.ListenConfig(params, len(initializationList) > 0, clientConfig.NamespaceId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
if err == nil {
|
||||
changed = changedTmp
|
||||
} else {
|
||||
if _, ok := err.(*nacos_error.NacosError); ok {
|
||||
changed = changedTmp
|
||||
} else {
|
||||
logger.Errorf("[client.ListenConfig] listen config error: %+v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
for _, v := range initializationList {
|
||||
v.isInitializing = false
|
||||
cacheMap.Set(util.GetConfigCacheKey(v.dataId, v.group, clientConfig.NamespaceId), v)
|
||||
}
|
||||
if len(strings.ToLower(strings.Trim(changed, " "))) == 0 {
|
||||
logger.Info("[client.ListenConfig] no change")
|
||||
} else {
|
||||
logger.Info("[client.ListenConfig] config changed:" + changed)
|
||||
client.callListener(changed, clientConfig.NamespaceId)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Execute the Listener callback func()
|
||||
func (client *ConfigClient) callListener(changed, tenant string) {
|
||||
changedConfigs := strings.Split(changed, "%01")
|
||||
for _, config := range changedConfigs {
|
||||
attrs := strings.Split(config, "%02")
|
||||
if len(attrs) >= 2 {
|
||||
if value, ok := cacheMap.Get(util.GetConfigCacheKey(attrs[0], attrs[1], tenant)); ok {
|
||||
cData := value.(cacheData)
|
||||
content, err := client.getConfigInner(vo.ConfigParam{
|
||||
DataId: cData.dataId,
|
||||
Group: cData.group,
|
||||
})
|
||||
if err != nil {
|
||||
logger.Errorf("[client.getConfigInner] DataId:[%s] Group:[%s] Error:[%+v]", cData.dataId, cData.group, err)
|
||||
continue
|
||||
}
|
||||
cData.content = content
|
||||
cData.md5 = util.Md5(content)
|
||||
if cData.md5 != cData.cacheDataListener.lastMd5 {
|
||||
go cData.cacheDataListener.listener(tenant, attrs[1], attrs[0], cData.content)
|
||||
cData.cacheDataListener.lastMd5 = cData.md5
|
||||
cacheMap.Set(util.GetConfigCacheKey(cData.dataId, cData.group, tenant), cData)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (client *ConfigClient) buildBasePath(serverConfig constant.ServerConfig) (basePath string) {
|
||||
basePath = "http://" + serverConfig.IpAddr + ":" +
|
||||
strconv.FormatUint(serverConfig.Port, 10) + serverConfig.ContextPath + constant.CONFIG_PATH
|
||||
client.cacheMap.Set(key, &cData)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -479,42 +317,6 @@ func (client *ConfigClient) SearchConfig(param vo.SearchConfigParm) (*model.Conf
|
|||
return client.searchConfigInner(param)
|
||||
}
|
||||
|
||||
func (client *ConfigClient) PublishAggr(param vo.ConfigParam) (published bool,
|
||||
err error) {
|
||||
if len(param.DataId) <= 0 {
|
||||
err = errors.New("[client.PublishAggr] param.dataId can not be empty")
|
||||
}
|
||||
if len(param.Group) <= 0 {
|
||||
err = errors.New("[client.PublishAggr] param.group can not be empty")
|
||||
}
|
||||
if len(param.Content) <= 0 {
|
||||
err = errors.New("[client.PublishAggr] param.content can not be empty")
|
||||
}
|
||||
if len(param.DatumId) <= 0 {
|
||||
err = errors.New("[client.PublishAggr] param.DatumId can not be empty")
|
||||
}
|
||||
clientConfig, _ := client.GetClientConfig()
|
||||
return client.configProxy.PublishAggProxy(param, clientConfig.NamespaceId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
}
|
||||
|
||||
func (client *ConfigClient) RemoveAggr(param vo.ConfigParam) (published bool,
|
||||
err error) {
|
||||
if len(param.DataId) <= 0 {
|
||||
err = errors.New("[client.DeleteAggr] param.dataId can not be empty")
|
||||
}
|
||||
if len(param.Group) <= 0 {
|
||||
err = errors.New("[client.DeleteAggr] param.group can not be empty")
|
||||
}
|
||||
if len(param.Content) <= 0 {
|
||||
err = errors.New("[client.DeleteAggr] param.content can not be empty")
|
||||
}
|
||||
if len(param.DatumId) <= 0 {
|
||||
err = errors.New("[client.DeleteAggr] param.DatumId can not be empty")
|
||||
}
|
||||
clientConfig, _ := client.GetClientConfig()
|
||||
return client.configProxy.DeleteAggProxy(param, clientConfig.NamespaceId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
}
|
||||
|
||||
func (client *ConfigClient) searchConfigInner(param vo.SearchConfigParm) (*model.ConfigPage, error) {
|
||||
if param.Search != "accurate" && param.Search != "blur" {
|
||||
return nil, errors.New("[client.searchConfigInner] param.search must be accurate or blur")
|
||||
|
@ -526,7 +328,7 @@ func (client *ConfigClient) searchConfigInner(param vo.SearchConfigParm) (*model
|
|||
param.PageSize = 10
|
||||
}
|
||||
clientConfig, _ := client.GetClientConfig()
|
||||
configItems, err := client.configProxy.SearchConfigProxy(param, clientConfig.NamespaceId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
configItems, err := client.configProxy.searchConfigProxy(param, clientConfig.NamespaceId, clientConfig.AccessKey, clientConfig.SecretKey)
|
||||
if err != nil {
|
||||
logger.Errorf("search config from server error:%+v ", err)
|
||||
if _, ok := err.(*nacos_error.NacosError); ok {
|
||||
|
@ -542,3 +344,130 @@ func (client *ConfigClient) searchConfigInner(param vo.SearchConfigParm) (*model
|
|||
}
|
||||
return configItems, nil
|
||||
}
|
||||
|
||||
func (client *ConfigClient) startInternal() {
|
||||
timer := time.NewTimer(executorErrDelay)
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-client.listenExecute:
|
||||
client.executeConfigListen()
|
||||
case <-timer.C:
|
||||
client.executeConfigListen()
|
||||
}
|
||||
timer.Reset(executorErrDelay)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (client *ConfigClient) executeConfigListen() {
|
||||
listenCachesMap := make(map[int][]*cacheData, 16)
|
||||
needAllSync := time.Now().Sub(client.lastAllSyncTime) >= constant.ALL_SYNC_INTERNAL
|
||||
for _, v := range client.cacheMap.Items() {
|
||||
cache, ok := v.(*cacheData)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if cache.isSyncWithServer {
|
||||
if cache.md5 != cache.cacheDataListener.lastMd5 {
|
||||
go cache.cacheDataListener.listener(cache.tenant, cache.group, cache.dataId, cache.content)
|
||||
cache.cacheDataListener.lastMd5 = cache.md5
|
||||
}
|
||||
if !needAllSync {
|
||||
continue
|
||||
}
|
||||
}
|
||||
var cacheDatas []*cacheData
|
||||
if cacheDatas, ok = listenCachesMap[cache.taskId]; ok {
|
||||
cacheDatas = append(cacheDatas, cache)
|
||||
} else {
|
||||
cacheDatas = append(cacheDatas, cache)
|
||||
}
|
||||
listenCachesMap[cache.taskId] = cacheDatas
|
||||
}
|
||||
hasChangedKeys := false
|
||||
if len(listenCachesMap) > 0 {
|
||||
for taskId, listenCaches := range listenCachesMap {
|
||||
request := buildConfigBatchListenRequest(listenCaches)
|
||||
rpcClient := client.configProxy.createRpcClient(string(taskId), client)
|
||||
iResponse, err := client.configProxy.requestProxy(rpcClient, request, 3000)
|
||||
if err != nil {
|
||||
logger.Warnf("ConfigBatchListenRequest failure,err:%+v", err)
|
||||
continue
|
||||
}
|
||||
if iResponse == nil && !iResponse.IsSuccess() {
|
||||
continue
|
||||
}
|
||||
changeKeys := make(map[string]struct{})
|
||||
if response, ok := iResponse.(*rpc_response.ConfigChangeBatchListenResponse); ok {
|
||||
if len(response.ChangedConfigs) > 0 {
|
||||
hasChangedKeys = true
|
||||
for _, v := range response.ChangedConfigs {
|
||||
changeKey := util.GetConfigCacheKey(v.DataId, v.Group, v.Tenant)
|
||||
changeKeys[changeKey] = struct{}{}
|
||||
if cache, ok := client.cacheMap.Get(changeKey); !ok {
|
||||
continue
|
||||
} else {
|
||||
cacheData := cache.(*cacheData)
|
||||
client.refreshContentAndCheck(cacheData, !cacheData.isInitializing)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range listenCaches {
|
||||
changeKey := util.GetConfigCacheKey(v.dataId, v.group, v.tenant)
|
||||
if _, ok := changeKeys[changeKey]; !ok {
|
||||
v.isSyncWithServer = true
|
||||
continue
|
||||
}
|
||||
v.isInitializing = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if needAllSync {
|
||||
client.lastAllSyncTime = time.Now()
|
||||
}
|
||||
|
||||
if hasChangedKeys {
|
||||
client.notifyListenConfig()
|
||||
}
|
||||
}
|
||||
|
||||
func buildConfigBatchListenRequest(caches []*cacheData) *rpc_request.ConfigBatchListenRequest {
|
||||
request := rpc_request.NewConfigBatchListenRequest(len(caches))
|
||||
for _, cache := range caches {
|
||||
request.ConfigListenContexts = append(request.ConfigListenContexts,
|
||||
model.ConfigListenContext{Group: cache.group, Md5: cache.md5, DataId: cache.dataId, Tenant: cache.tenant})
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
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 {
|
||||
logger.Errorf("refresh content and check md5 fail ,dataId=%s,group=%s,tenant=%s ", cacheData.dataId,
|
||||
cacheData.group, cacheData.tenant)
|
||||
return
|
||||
}
|
||||
cacheData.content = configQueryResponse.Content
|
||||
cacheData.contentType = configQueryResponse.ContentType
|
||||
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,
|
||||
util.TruncateContent(cacheData.content), cacheData.contentType)
|
||||
}
|
||||
cacheData.md5 = util.Md5(cacheData.content)
|
||||
if cacheData.md5 != cacheData.cacheDataListener.lastMd5 {
|
||||
go cacheData.cacheDataListener.listener(cacheData.tenant, cacheData.group, cacheData.dataId, cacheData.content)
|
||||
cacheData.cacheDataListener.lastMd5 = cacheData.md5
|
||||
client.cacheMap.Set(util.GetConfigCacheKey(cacheData.dataId, cacheData.group, cacheData.tenant), cacheData)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (client *ConfigClient) notifyListenConfig() {
|
||||
client.listenExecute <- struct{}{}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
package config_client
|
||||
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination ../../mock/mock_config_client_interface.go -package mock -source=./config_client_interface.go
|
||||
|
@ -64,6 +64,4 @@ type IConfigClient interface {
|
|||
// pageNo option,default is 1
|
||||
// pageSize option,default is 10
|
||||
SearchConfig(param vo.SearchConfigParm) (*model.ConfigPage, error)
|
||||
|
||||
PublishAggr(param vo.ConfigParam) (published bool, err error)
|
||||
}
|
||||
|
|
|
@ -17,47 +17,21 @@
|
|||
package config_client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/nacos_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/mock"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"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/model"
|
||||
|
||||
"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"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var goVersion = runtime.Version()
|
||||
|
||||
var clientConfigTest = constant.ClientConfig{
|
||||
TimeoutMs: 10000,
|
||||
ListenInterval: 20000,
|
||||
BeatInterval: 10000,
|
||||
}
|
||||
|
||||
var clientConfigTestWithTenant = constant.ClientConfig{
|
||||
TimeoutMs: 10000,
|
||||
ListenInterval: 20000,
|
||||
BeatInterval: 10000,
|
||||
NamespaceId: "tenant",
|
||||
}
|
||||
|
||||
var serverConfigTest = constant.ServerConfig{
|
||||
ContextPath: "/nacos",
|
||||
Port: 80,
|
||||
IpAddr: "console.nacos.io",
|
||||
}
|
||||
|
||||
var serverConfigWithOptions = constant.NewServerConfig("console.nacos.io", 80, constant.WithContextPath("/nacos"))
|
||||
var serverConfigWithOptions = constant.NewServerConfig("127.0.0.1", 80, constant.WithContextPath("/nacos"))
|
||||
|
||||
var clientConfigWithOptions = constant.NewClientConfig(
|
||||
constant.WithTimeoutMs(10*1000),
|
||||
|
@ -65,116 +39,69 @@ var clientConfigWithOptions = constant.NewClientConfig(
|
|||
constant.WithNotLoadCacheAtStart(true),
|
||||
)
|
||||
|
||||
var (
|
||||
dataIdKey = goVersion + "dataId"
|
||||
configNoChangeKey = goVersion + "ConfigNoChange"
|
||||
multipleClientsKey = goVersion + "MultipleClients"
|
||||
multipleClientsMultipleConfigsKey = goVersion + "MultipleClientsMultipleConfig"
|
||||
cancelOneKey = goVersion + "CancelOne"
|
||||
cancelOne1Key = goVersion + "CancelOne1"
|
||||
cancelListenConfigKey = goVersion + "cancel_listen_config"
|
||||
specialSymbolKey = goVersion + "special_symbol"
|
||||
)
|
||||
|
||||
var configParamMapTest = map[string]string{
|
||||
"dataId": dataIdKey,
|
||||
"group": "group",
|
||||
}
|
||||
|
||||
var configParamTest = vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
Group: "group",
|
||||
}
|
||||
|
||||
var localConfigTest = vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
DataId: "dataId",
|
||||
Group: "group",
|
||||
Content: "content",
|
||||
}
|
||||
|
||||
var localConfigMapTest = map[string]string{
|
||||
"dataId": dataIdKey,
|
||||
"group": "group",
|
||||
"content": "content",
|
||||
}
|
||||
|
||||
var headerTest = map[string][]string{
|
||||
"Content-Type": {"application/x-www-form-urlencoded"},
|
||||
}
|
||||
var headerListenerTest = map[string][]string{
|
||||
"Content-Type": {"application/x-www-form-urlencoded"},
|
||||
"Listening-Configs": {"30000"},
|
||||
}
|
||||
|
||||
var serverConfigsTest = []constant.ServerConfig{serverConfigTest}
|
||||
|
||||
var httpAgentTest = mock.MockIHttpAgent{}
|
||||
|
||||
func createConfigClientTest() ConfigClient {
|
||||
func createConfigClientTest() *ConfigClient {
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
|
||||
nc.SetClientConfig(*clientConfigWithOptions)
|
||||
nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
_ = nc.SetServerConfig([]constant.ServerConfig{*serverConfigWithOptions})
|
||||
_ = nc.SetClientConfig(*clientConfigWithOptions)
|
||||
_ = nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewConfigClient(&nc)
|
||||
client.configProxy = &MockConfigProxy{}
|
||||
return client
|
||||
}
|
||||
|
||||
func createConfigClientTestWithTenant() ConfigClient {
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTestWithTenant)
|
||||
nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewConfigClient(&nc)
|
||||
return client
|
||||
type MockConfigProxy struct {
|
||||
}
|
||||
|
||||
func createConfigClientHttpTest(mockHttpAgent http_agent.IHttpAgent) ConfigClient {
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockHttpAgent)
|
||||
client, _ := NewConfigClient(&nc)
|
||||
return client
|
||||
func (m *MockConfigProxy) queryConfig(dataId, group, tenant string, timeout uint64, notify bool, client *ConfigClient) (*rpc_response.ConfigQueryResponse, error) {
|
||||
return &rpc_response.ConfigQueryResponse{Content: "hello world"}, nil
|
||||
}
|
||||
|
||||
func createConfigClientHttpTestWithTenant(mockHttpAgent http_agent.IHttpAgent) ConfigClient {
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTestWithTenant)
|
||||
nc.SetHttpAgent(mockHttpAgent)
|
||||
client, _ := NewConfigClient(&nc)
|
||||
return client
|
||||
func (m *MockConfigProxy) searchConfigProxy(param vo.SearchConfigParm, tenant, accessKey, secretKey string) (*model.ConfigPage, error) {
|
||||
return &model.ConfigPage{TotalCount: 1}, nil
|
||||
}
|
||||
func (m *MockConfigProxy) requestProxy(rpcClient *rpc.RpcClient, request rpc_request.IRequest, timeoutMills uint64) (rpc_response.IResponse, error) {
|
||||
return &rpc_response.MockResponse{Response: &rpc_response.Response{Success: true}}, nil
|
||||
}
|
||||
func (m *MockConfigProxy) createRpcClient(taskId string, client *ConfigClient) *rpc.RpcClient {
|
||||
return &rpc.RpcClient{}
|
||||
}
|
||||
func (m *MockConfigProxy) getRpcClient(client *ConfigClient) *rpc.RpcClient {
|
||||
return &rpc.RpcClient{}
|
||||
}
|
||||
|
||||
func Test_GetConfig(t *testing.T) {
|
||||
|
||||
client := createConfigClientTest()
|
||||
success, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
Group: "group",
|
||||
Content: "hello world!222222"})
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: localConfigTest.Group,
|
||||
Content: "hello world"})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, success)
|
||||
|
||||
content, err := client.GetConfig(vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "group"})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "hello world!222222", content)
|
||||
assert.Equal(t, "hello world", content)
|
||||
}
|
||||
|
||||
func Test_SearchConfig(t *testing.T) {
|
||||
client := createConfigClientTest()
|
||||
client.PublishConfig(vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
Group: "groDEFAULT_GROUPup",
|
||||
Content: "hello world!222222"})
|
||||
_, _ = client.PublishConfig(vo.ConfigParam{
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "DEFAULT_GROUP",
|
||||
Content: "hello world"})
|
||||
configPage, err := client.SearchConfig(vo.SearchConfigParm{
|
||||
Search: "accurate",
|
||||
DataId: dataIdKey,
|
||||
Group: "groDEFAULT_GROUPup",
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "DEFAULT_GROUP",
|
||||
PageNo: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
|
@ -182,86 +109,7 @@ func Test_SearchConfig(t *testing.T) {
|
|||
assert.NotEmpty(t, configPage)
|
||||
}
|
||||
|
||||
func Test_GetConfigWithErrorResponse_401(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
mockHttpAgent := mock.NewMockIHttpAgent(controller)
|
||||
client := createConfigClientHttpTest(mockHttpAgent)
|
||||
mockHttpAgent.EXPECT().Request(gomock.Eq(http.MethodGet),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/cs/configs"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(clientConfigTest.TimeoutMs),
|
||||
gomock.Eq(configParamMapTest),
|
||||
).Times(3).Return(http_agent.FakeHttpResponse(401, "no security"), nil)
|
||||
result, err := client.GetConfig(configParamTest)
|
||||
assert.Nil(t, err)
|
||||
fmt.Printf("result:%s \n", result)
|
||||
}
|
||||
|
||||
func Test_GetConfigWithErrorResponse_404(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
mockHttpAgent := mock.NewMockIHttpAgent(controller)
|
||||
client := createConfigClientHttpTest(mockHttpAgent)
|
||||
mockHttpAgent.EXPECT().Request(gomock.Eq(http.MethodGet),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/cs/configs"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(clientConfigTest.TimeoutMs),
|
||||
gomock.Eq(configParamMapTest),
|
||||
).Times(3).Return(http_agent.FakeHttpResponse(404, ""), nil)
|
||||
reslut, err := client.GetConfig(configParamTest)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "", reslut)
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
func Test_GetConfigWithErrorResponse_403(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
mockHttpAgent := mock.NewMockIHttpAgent(controller)
|
||||
client := createConfigClientHttpTest(mockHttpAgent)
|
||||
mockHttpAgent.EXPECT().Request(gomock.Eq(http.MethodGet),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/cs/configs"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(clientConfigTest.TimeoutMs),
|
||||
gomock.Eq(configParamMapTest),
|
||||
).Times(3).Return(http_agent.FakeHttpResponse(403, ""), nil)
|
||||
reslut, err := client.GetConfig(configParamTest)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "", reslut)
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
func Test_GetConfigWithCache(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mockHttpAgent := mock.NewMockIHttpAgent(controller)
|
||||
client := createConfigClientHttpTest(mockHttpAgent)
|
||||
|
||||
mockHttpAgent.EXPECT().Request(gomock.Eq(http.MethodGet),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/cs/configs"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(clientConfigTest.TimeoutMs),
|
||||
gomock.Eq(configParamMapTest),
|
||||
).Times(1).Return(http_agent.FakeHttpResponse(200, "content"), nil)
|
||||
content, err := client.GetConfig(configParamTest)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "content", content)
|
||||
|
||||
mockHttpAgent.EXPECT().Request(gomock.Eq(http.MethodGet),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/cs/configs"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(clientConfigTest.TimeoutMs),
|
||||
gomock.Eq(configParamMapTest),
|
||||
).Times(3).Return(http_agent.FakeHttpResponse(401, "no security"), nil)
|
||||
content, err = client.GetConfig(configParamTest)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, "content", content)
|
||||
}
|
||||
|
||||
// PublishConfig
|
||||
|
||||
func Test_PublishConfigWithoutDataId(t *testing.T) {
|
||||
client := createConfigClientTest()
|
||||
_, err := client.PublishConfig(vo.ConfigParam{
|
||||
|
@ -272,20 +120,10 @@ func Test_PublishConfigWithoutDataId(t *testing.T) {
|
|||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func Test_PublishConfigWithoutGroup(t *testing.T) {
|
||||
client := createConfigClientTest()
|
||||
_, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
Group: "",
|
||||
Content: "content",
|
||||
})
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func Test_PublishConfigWithoutContent(t *testing.T) {
|
||||
client := createConfigClientTest()
|
||||
_, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "group",
|
||||
Content: "",
|
||||
})
|
||||
|
@ -297,56 +135,21 @@ func Test_PublishConfig(t *testing.T) {
|
|||
client := createConfigClientTest()
|
||||
|
||||
success, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "group",
|
||||
Content: "hello world2!"})
|
||||
Content: "hello world"})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, success)
|
||||
}
|
||||
|
||||
func Test_PublishConfigWithErrorResponse(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mockHttpAgent := mock.NewMockIHttpAgent(controller)
|
||||
client := createConfigClientHttpTest(mockHttpAgent)
|
||||
mockHttpAgent.EXPECT().Request(gomock.Eq(http.MethodPost),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/cs/configs"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(clientConfigTest.TimeoutMs),
|
||||
gomock.Eq(localConfigMapTest),
|
||||
).Times(3).Return(http_agent.FakeHttpResponse(401, "no security"), nil)
|
||||
success, err := client.PublishConfig(localConfigTest)
|
||||
assert.NotNil(t, err)
|
||||
assert.True(t, !success)
|
||||
}
|
||||
|
||||
func Test_PublishConfigWithErrorResponse_200(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mockHttpAgent := mock.NewMockIHttpAgent(controller)
|
||||
client := createConfigClientHttpTest(mockHttpAgent)
|
||||
mockHttpAgent.EXPECT().Request(gomock.Eq(http.MethodPost),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/cs/configs"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(clientConfigTest.TimeoutMs),
|
||||
gomock.Eq(localConfigMapTest),
|
||||
).Times(1).Return(http_agent.FakeHttpResponse(200, "false"), nil)
|
||||
success, err := client.PublishConfig(localConfigTest)
|
||||
assert.NotNil(t, err)
|
||||
assert.True(t, !success)
|
||||
}
|
||||
|
||||
// DeleteConfig
|
||||
|
||||
func Test_DeleteConfig(t *testing.T) {
|
||||
|
||||
client := createConfigClientTest()
|
||||
|
||||
success, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "group",
|
||||
Content: "hello world!"})
|
||||
|
||||
|
@ -354,49 +157,13 @@ func Test_DeleteConfig(t *testing.T) {
|
|||
assert.True(t, success)
|
||||
|
||||
success, err = client.DeleteConfig(vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: "group"})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, success)
|
||||
}
|
||||
|
||||
func Test_DeleteConfigWithErrorResponse_200(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mockHttpAgent := mock.NewMockIHttpAgent(controller)
|
||||
client := createConfigClientHttpTest(mockHttpAgent)
|
||||
|
||||
mockHttpAgent.EXPECT().Request(gomock.Eq(http.MethodDelete),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/cs/configs"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(clientConfigTest.TimeoutMs),
|
||||
gomock.Eq(configParamMapTest),
|
||||
).Times(1).Return(http_agent.FakeHttpResponse(200, "false"), nil)
|
||||
success, err := client.DeleteConfig(configParamTest)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, false, success)
|
||||
}
|
||||
|
||||
func Test_DeleteConfigWithErrorResponse_401(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
mockHttpAgent := mock.NewMockIHttpAgent(controller)
|
||||
client := createConfigClientHttpTest(mockHttpAgent)
|
||||
|
||||
mockHttpAgent.EXPECT().Request(gomock.Eq(http.MethodDelete),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/cs/configs"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(clientConfigTest.TimeoutMs),
|
||||
gomock.Eq(configParamMapTest),
|
||||
).Times(3).Return(http_agent.FakeHttpResponse(401, "no security"), nil)
|
||||
success, err := client.DeleteConfig(configParamTest)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, false, success)
|
||||
}
|
||||
|
||||
func Test_DeleteConfigWithoutDataId(t *testing.T) {
|
||||
client := createConfigClientTest()
|
||||
success, err := client.DeleteConfig(vo.ConfigParam{
|
||||
|
@ -407,59 +174,21 @@ func Test_DeleteConfigWithoutDataId(t *testing.T) {
|
|||
assert.Equal(t, false, success)
|
||||
}
|
||||
|
||||
func Test_DeleteConfigWithoutGroup(t *testing.T) {
|
||||
client := createConfigClientTest()
|
||||
success, err := client.DeleteConfig(vo.ConfigParam{
|
||||
DataId: dataIdKey,
|
||||
Group: "",
|
||||
})
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, false, success)
|
||||
}
|
||||
|
||||
// ListenConfig
|
||||
func TestListen(t *testing.T) {
|
||||
// ListenConfig
|
||||
t.Run("TestListenConfig", func(t *testing.T) {
|
||||
client := createConfigClientTest()
|
||||
key := util.GetConfigCacheKey(localConfigTest.DataId, localConfigTest.Group, clientConfigTest.NamespaceId)
|
||||
cache.WriteConfigToFile(key, client.configCacheDir, "")
|
||||
var err error
|
||||
var success bool
|
||||
ch := make(chan string)
|
||||
go func() {
|
||||
err = client.ListenConfig(vo.ConfigParam{
|
||||
err := client.ListenConfig(vo.ConfigParam{
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: localConfigTest.Group,
|
||||
OnChange: func(namespace, group, dataId, data string) {
|
||||
fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
|
||||
ch <- data
|
||||
},
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
}()
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
success, err = client.PublishConfig(vo.ConfigParam{
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: localConfigTest.Group,
|
||||
Content: localConfigTest.Content})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, success)
|
||||
select {
|
||||
case c := <-ch:
|
||||
assert.Equal(t, c, localConfigTest.Content)
|
||||
case <-time.After(10 * time.Second):
|
||||
fmt.Println("timeout")
|
||||
assert.Errorf(t, errors.New("timeout"), "timeout")
|
||||
}
|
||||
})
|
||||
// ListenConfig no dataId
|
||||
t.Run("TestListenConfigNoDataId", func(t *testing.T) {
|
||||
listenConfigParam := vo.ConfigParam{
|
||||
Group: "gateway",
|
||||
Group: localConfigTest.Group,
|
||||
OnChange: func(namespace, group, dataId, data string) {
|
||||
},
|
||||
}
|
||||
|
@ -467,107 +196,6 @@ func TestListen(t *testing.T) {
|
|||
err := client.ListenConfig(listenConfigParam)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
// ListenConfig no change
|
||||
t.Run("TestListenConfigNoChange", func(t *testing.T) {
|
||||
client := createConfigClientTest()
|
||||
key := util.GetConfigCacheKey(configNoChangeKey, localConfigTest.Group, clientConfigTest.NamespaceId)
|
||||
cache.WriteConfigToFile(key, client.configCacheDir, localConfigTest.Content)
|
||||
var err error
|
||||
var success bool
|
||||
var content string
|
||||
|
||||
go func() {
|
||||
err = client.ListenConfig(vo.ConfigParam{
|
||||
DataId: configNoChangeKey,
|
||||
Group: localConfigTest.Group,
|
||||
OnChange: func(namespace, group, dataId, data string) {
|
||||
content = "data"
|
||||
},
|
||||
})
|
||||
assert.Nil(t, err)
|
||||
}()
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
success, err = client.PublishConfig(vo.ConfigParam{
|
||||
DataId: configNoChangeKey,
|
||||
Group: localConfigTest.Group,
|
||||
Content: localConfigTest.Content})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, success)
|
||||
assert.Equal(t, content, "")
|
||||
})
|
||||
// Multiple clients listen to the same configuration file
|
||||
t.Run("TestListenConfigWithMultipleClients", func(t *testing.T) {
|
||||
ch := make(chan string)
|
||||
listenConfigParam := vo.ConfigParam{
|
||||
DataId: multipleClientsKey,
|
||||
Group: localConfigTest.Group,
|
||||
OnChange: func(namespace, group, dataId, data string) {
|
||||
fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
|
||||
ch <- data
|
||||
},
|
||||
}
|
||||
client := createConfigClientTest()
|
||||
key := util.GetConfigCacheKey(listenConfigParam.DataId, listenConfigParam.Group, clientConfigTest.NamespaceId)
|
||||
cache.WriteConfigToFile(key, client.configCacheDir, "")
|
||||
client.ListenConfig(listenConfigParam)
|
||||
|
||||
client1 := createConfigClientTest()
|
||||
client1.ListenConfig(listenConfigParam)
|
||||
|
||||
success, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: multipleClientsKey,
|
||||
Group: localConfigTest.Group,
|
||||
Content: localConfigTest.Content})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, success)
|
||||
select {
|
||||
case c := <-ch:
|
||||
assert.Equal(t, localConfigTest.Content, c)
|
||||
case <-time.After(10 * time.Second):
|
||||
fmt.Println("timeout")
|
||||
assert.Errorf(t, errors.New("timeout"), "timeout")
|
||||
}
|
||||
|
||||
})
|
||||
// Multiple clients listen to multiple configuration files
|
||||
t.Run("TestListenConfigWithMultipleClientsMultipleConfig", func(t *testing.T) {
|
||||
ch := make(chan string)
|
||||
listenConfigParam := vo.ConfigParam{
|
||||
DataId: multipleClientsMultipleConfigsKey,
|
||||
Group: localConfigTest.Group,
|
||||
OnChange: func(namespace, group, dataId, data string) {
|
||||
fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
|
||||
ch <- data
|
||||
},
|
||||
}
|
||||
client := createConfigClientTest()
|
||||
key := util.GetConfigCacheKey(listenConfigParam.DataId, listenConfigParam.Group, clientConfigTest.NamespaceId)
|
||||
cache.WriteConfigToFile(key, client.configCacheDir, "")
|
||||
client.ListenConfig(listenConfigParam)
|
||||
|
||||
client1 := createConfigClientTest()
|
||||
client1.ListenConfig(listenConfigParam)
|
||||
|
||||
success, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: multipleClientsMultipleConfigsKey,
|
||||
Group: localConfigTest.Group,
|
||||
Content: localConfigTest.Content})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, success)
|
||||
select {
|
||||
case c := <-ch:
|
||||
assert.Equal(t, localConfigTest.Content, c)
|
||||
case <-time.After(10 * time.Second):
|
||||
fmt.Println("timeout")
|
||||
assert.Errorf(t, errors.New("timeout"), "timeout")
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// CancelListenConfig
|
||||
|
@ -576,120 +204,24 @@ func TestCancelListenConfig(t *testing.T) {
|
|||
t.Run("TestMultipleListenersCancelOne", func(t *testing.T) {
|
||||
client := createConfigClientTest()
|
||||
var err error
|
||||
var success bool
|
||||
var context string
|
||||
listenConfigParam := vo.ConfigParam{
|
||||
DataId: cancelOneKey,
|
||||
Group: "group",
|
||||
DataId: localConfigTest.DataId,
|
||||
Group: localConfigTest.Group,
|
||||
OnChange: func(namespace, group, dataId, data string) {
|
||||
fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
|
||||
},
|
||||
}
|
||||
|
||||
listenConfigParam1 := vo.ConfigParam{
|
||||
DataId: cancelOne1Key,
|
||||
Group: "group1",
|
||||
OnChange: func(namespace, group, dataId, data string) {
|
||||
fmt.Println("group1:" + group + ", dataId1:" + dataId + ", data:" + data)
|
||||
context = data
|
||||
},
|
||||
}
|
||||
go func() {
|
||||
client.ListenConfig(listenConfigParam)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
client.ListenConfig(listenConfigParam1)
|
||||
}()
|
||||
|
||||
fmt.Println("Start listening")
|
||||
for i := 1; i <= 5; i++ {
|
||||
go func() {
|
||||
success, err = client.PublishConfig(vo.ConfigParam{
|
||||
DataId: cancelOneKey,
|
||||
Group: "group",
|
||||
Content: "abcd" + strconv.Itoa(i)})
|
||||
}()
|
||||
|
||||
go func() {
|
||||
success, err = client.PublishConfig(vo.ConfigParam{
|
||||
DataId: cancelOne1Key,
|
||||
Group: "group1",
|
||||
Content: "abcd" + strconv.Itoa(i)})
|
||||
}()
|
||||
|
||||
if i == 3 {
|
||||
client.CancelListenConfig(listenConfigParam)
|
||||
fmt.Println("Cancel listen config")
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, success)
|
||||
}
|
||||
assert.Equal(t, "abcd5", context)
|
||||
})
|
||||
t.Run("TestCancelListenConfig", func(t *testing.T) {
|
||||
var context string
|
||||
var err error
|
||||
ch := make(chan string)
|
||||
client := createConfigClientTest()
|
||||
//
|
||||
key := util.GetConfigCacheKey(localConfigTest.DataId, localConfigTest.Group, clientConfigTest.NamespaceId)
|
||||
cache.WriteConfigToFile(key, client.configCacheDir, "")
|
||||
listenConfigParam := vo.ConfigParam{
|
||||
DataId: cancelListenConfigKey,
|
||||
DataId: localConfigTest.DataId + "1",
|
||||
Group: localConfigTest.Group,
|
||||
OnChange: func(namespace, group, dataId, data string) {
|
||||
fmt.Println("group:" + group + ", dataId:" + dataId + ", data:" + data)
|
||||
context = data
|
||||
ch <- data
|
||||
},
|
||||
}
|
||||
go func() {
|
||||
err = client.ListenConfig(listenConfigParam)
|
||||
assert.Nil(t, err)
|
||||
}()
|
||||
success, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: cancelListenConfigKey,
|
||||
Group: localConfigTest.Group,
|
||||
Content: localConfigTest.Content})
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, success)
|
||||
_ = client.ListenConfig(listenConfigParam)
|
||||
|
||||
select {
|
||||
case c := <-ch:
|
||||
assert.Equal(t, c, localConfigTest.Content)
|
||||
}
|
||||
//Cancel listen config
|
||||
client.CancelListenConfig(listenConfigParam)
|
||||
_ = client.ListenConfig(listenConfigParam1)
|
||||
|
||||
success, err = client.PublishConfig(vo.ConfigParam{
|
||||
DataId: cancelListenConfigKey,
|
||||
Group: localConfigTest.Group,
|
||||
Content: "abcd"})
|
||||
err = client.CancelListenConfig(listenConfigParam)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, true, success)
|
||||
|
||||
assert.Equal(t, localConfigTest.Content, context)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetConfigWithSpecialSymbol(t *testing.T) {
|
||||
contentStr := "hello world!!@#$%^&&*()"
|
||||
|
||||
client := createConfigClientTest()
|
||||
success, err := client.PublishConfig(vo.ConfigParam{
|
||||
DataId: specialSymbolKey,
|
||||
Group: localConfigTest.Group,
|
||||
Content: contentStr})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, success)
|
||||
|
||||
content, err := client.GetConfig(vo.ConfigParam{
|
||||
DataId: specialSymbolKey,
|
||||
Group: localConfigTest.Group})
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, contentStr, content)
|
||||
}
|
||||
|
|
|
@ -21,15 +21,19 @@ import (
|
|||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/nacos_server"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"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/nacos_server"
|
||||
"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"
|
||||
)
|
||||
|
||||
type ConfigProxy struct {
|
||||
|
@ -37,34 +41,35 @@ type ConfigProxy struct {
|
|||
clientConfig constant.ClientConfig
|
||||
}
|
||||
|
||||
func NewConfigProxy(serverConfig []constant.ServerConfig, clientConfig constant.ClientConfig, httpAgent http_agent.IHttpAgent) (ConfigProxy, error) {
|
||||
func NewConfigProxy(serverConfig []constant.ServerConfig, clientConfig constant.ClientConfig, httpAgent http_agent.IHttpAgent) (IConfigProxy, error) {
|
||||
proxy := ConfigProxy{}
|
||||
var err error
|
||||
proxy.nacosServer, err = nacos_server.NewNacosServer(serverConfig, clientConfig, httpAgent, clientConfig.TimeoutMs, clientConfig.Endpoint)
|
||||
proxy.clientConfig = clientConfig
|
||||
return proxy, err
|
||||
return &proxy, err
|
||||
|
||||
}
|
||||
|
||||
func (cp *ConfigProxy) GetServerList() []constant.ServerConfig {
|
||||
return cp.nacosServer.GetServerList()
|
||||
func (cp *ConfigProxy) requestProxy(rpcClient *rpc.RpcClient, request rpc_request.IRequest, timeoutMills uint64) (rpc_response.IResponse, error) {
|
||||
cp.nacosServer.InjectSecurityInfo(request.GetHeaders())
|
||||
cp.injectCommHeader(request.GetHeaders())
|
||||
signHeaders := nacos_server.GetSignHeaders(request.GetHeaders(), cp.clientConfig.SecretKey)
|
||||
request.PutAllHeaders(signHeaders)
|
||||
//todo Spas-SecurityToken/Spas-AccessKey.
|
||||
//todo Config Limiter
|
||||
return rpcClient.Request(request, int64(timeoutMills))
|
||||
}
|
||||
|
||||
func (cp *ConfigProxy) GetConfigProxy(param vo.ConfigParam, tenant, accessKey, secretKey string) (string, error) {
|
||||
params := util.TransformObject2Param(param)
|
||||
if len(tenant) > 0 {
|
||||
params["tenant"] = tenant
|
||||
}
|
||||
|
||||
var headers = map[string]string{}
|
||||
headers["accessKey"] = accessKey
|
||||
headers["secretKey"] = secretKey
|
||||
|
||||
result, err := cp.nacosServer.ReqConfigApi(constant.CONFIG_PATH, params, headers, http.MethodGet, cp.clientConfig.TimeoutMs)
|
||||
return result, err
|
||||
func (cp *ConfigProxy) injectCommHeader(param map[string]string) {
|
||||
now := string(util.CurrentMillis())
|
||||
param[constant.CLIENT_APPNAME_HEADER] = cp.clientConfig.AppName
|
||||
param[constant.CLIENT_REQUEST_TS_HEADER] = now
|
||||
param[constant.CLIENT_REQUEST_TOKEN_HEADER] = util.Md5(now + cp.clientConfig.AppKey)
|
||||
param[constant.EX_CONFIG_INFO] = "true"
|
||||
param[constant.CHARSET_KEY] = "utf-8"
|
||||
}
|
||||
|
||||
func (cp *ConfigProxy) SearchConfigProxy(param vo.SearchConfigParm, tenant, accessKey, secretKey string) (*model.ConfigPage, error) {
|
||||
func (cp *ConfigProxy) searchConfigProxy(param vo.SearchConfigParm, tenant, accessKey, secretKey string) (*model.ConfigPage, error) {
|
||||
params := util.TransformObject2Param(param)
|
||||
if len(tenant) > 0 {
|
||||
params["tenant"] = tenant
|
||||
|
@ -89,98 +94,97 @@ func (cp *ConfigProxy) SearchConfigProxy(param vo.SearchConfigParm, tenant, acce
|
|||
}
|
||||
return &configPage, nil
|
||||
}
|
||||
func (cp *ConfigProxy) PublishConfigProxy(param vo.ConfigParam, tenant, accessKey, secretKey string) (bool, error) {
|
||||
params := util.TransformObject2Param(param)
|
||||
if len(tenant) > 0 {
|
||||
params["tenant"] = tenant
|
||||
}
|
||||
|
||||
var headers = map[string]string{}
|
||||
headers["accessKey"] = accessKey
|
||||
headers["secretKey"] = secretKey
|
||||
result, err := cp.nacosServer.ReqConfigApi(constant.CONFIG_PATH, params, headers, http.MethodPost, cp.clientConfig.TimeoutMs)
|
||||
func (cp *ConfigProxy) queryConfig(dataId, group, tenant string, timeout uint64, notify bool, client *ConfigClient) (*rpc_response.ConfigQueryResponse, error) {
|
||||
if group == "" {
|
||||
group = constant.DEFAULT_GROUP
|
||||
}
|
||||
configQueryRequest := rpc_request.NewConfigQueryRequest(group, dataId, tenant)
|
||||
configQueryRequest.Headers["notify"] = strconv.FormatBool(notify)
|
||||
iResponse, err := cp.requestProxy(cp.getRpcClient(client), configQueryRequest, timeout)
|
||||
if err != nil {
|
||||
return false, errors.New("[client.PublishConfig] publish config failed:" + err.Error())
|
||||
return nil, err
|
||||
}
|
||||
if strings.ToLower(strings.Trim(result, " ")) == "true" {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, errors.New("[client.PublishConfig] publish config failed:" + result)
|
||||
response, ok := iResponse.(*rpc_response.ConfigQueryResponse)
|
||||
if !ok {
|
||||
return nil, errors.New("ConfigQueryRequest returns type error")
|
||||
}
|
||||
if response.IsSuccess() {
|
||||
//todo LocalConfigInfoProcessor.saveSnapshot
|
||||
cacheKey := util.GetConfigCacheKey(dataId, group, tenant)
|
||||
cache.WriteConfigToFile(cacheKey, cp.clientConfig.CacheDir, response.Content)
|
||||
//todo LocalConfigInfoProcessor.saveEncryptDataKeySnapshot
|
||||
if response.ContentType == "" {
|
||||
response.ContentType = "text"
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
if response.GetErrorCode() == 300 {
|
||||
//todo LocalConfigInfoProcessor.saveSnapshot
|
||||
//todo LocalConfigInfoProcessor.saveEncryptDataKeySnapshot
|
||||
return response, nil
|
||||
}
|
||||
|
||||
if response.GetErrorCode() == 400 {
|
||||
logger.Errorf(
|
||||
"[config_rpc_client] [sub-server-error] get server config being modified concurrently, dataId=%s, group=%s, "+
|
||||
"tenant=%s", dataId, group, tenant)
|
||||
return nil, errors.New("data being modified, dataId=" + dataId + ",group=" + group + ",tenant=" + tenant)
|
||||
}
|
||||
|
||||
if response.GetErrorCode() > 0 {
|
||||
logger.Errorf("[config_rpc_client] [sub-server-error] dataId=%s, group=%s, tenant=%s, code=%v", dataId, group,
|
||||
tenant, response)
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (cp *ConfigProxy) PublishAggProxy(param vo.ConfigParam, tenant, accessKey, secretKey string) (bool, error) {
|
||||
params := util.TransformObject2Param(param)
|
||||
if len(tenant) > 0 {
|
||||
params["tenant"] = tenant
|
||||
func (cp *ConfigProxy) createRpcClient(taskId string, client *ConfigClient) *rpc.RpcClient {
|
||||
labels := map[string]string{
|
||||
constant.LABEL_SOURCE: constant.LABEL_SOURCE_SDK,
|
||||
constant.LABEL_MODULE: constant.LABEL_MODULE_CONFIG,
|
||||
"taskId": taskId,
|
||||
}
|
||||
params["method"] = "addDatum"
|
||||
var headers = map[string]string{}
|
||||
headers["accessKey"] = accessKey
|
||||
headers["secretKey"] = secretKey
|
||||
_, err := cp.nacosServer.ReqConfigApi(constant.CONFIG_AGG_PATH, params, headers, http.MethodPost, cp.clientConfig.TimeoutMs)
|
||||
if err != nil {
|
||||
return false, errors.New("[client.PublishAggProxy] publish agg failed:" + err.Error())
|
||||
|
||||
iRpcClient, _ := rpc.CreateClient("config-"+taskId+"-"+client.uid, rpc.GRPC, labels, cp.nacosServer)
|
||||
rpcClient := iRpcClient.GetRpcClient()
|
||||
if rpcClient.IsInitialized() {
|
||||
rpcClient.RegisterServerRequestHandler(func() rpc_request.IRequest {
|
||||
return &rpc_request.ConfigChangeNotifyRequest{ConfigRequest: rpc_request.NewConfigRequest()}
|
||||
}, &ConfigChangeNotifyRequestHandler{client: client})
|
||||
rpcClient.Tenant = cp.clientConfig.NamespaceId
|
||||
rpcClient.Start()
|
||||
}
|
||||
return true, nil
|
||||
return rpcClient
|
||||
}
|
||||
|
||||
func (cp *ConfigProxy) DeleteAggProxy(param vo.ConfigParam, tenant, accessKey, secretKey string) (bool, error) {
|
||||
params := util.TransformObject2Param(param)
|
||||
if len(tenant) > 0 {
|
||||
params["tenant"] = tenant
|
||||
}
|
||||
params["method"] = "deleteDatum"
|
||||
var headers = map[string]string{}
|
||||
headers["accessKey"] = accessKey
|
||||
headers["secretKey"] = secretKey
|
||||
_, err := cp.nacosServer.ReqConfigApi(constant.CONFIG_AGG_PATH, params, headers, http.MethodPost, cp.clientConfig.TimeoutMs)
|
||||
if err != nil {
|
||||
return false, errors.New("[client.DeleteAggProxy] delete agg failed:" + err.Error())
|
||||
}
|
||||
return true, nil
|
||||
func (cp *ConfigProxy) getRpcClient(client *ConfigClient) *rpc.RpcClient {
|
||||
return cp.createRpcClient("0", client)
|
||||
}
|
||||
|
||||
func (cp *ConfigProxy) DeleteConfigProxy(param vo.ConfigParam, tenant, accessKey, secretKey string) (bool, error) {
|
||||
params := util.TransformObject2Param(param)
|
||||
if len(tenant) > 0 {
|
||||
params["tenant"] = tenant
|
||||
}
|
||||
var headers = map[string]string{}
|
||||
headers["accessKey"] = accessKey
|
||||
headers["secretKey"] = secretKey
|
||||
result, err := cp.nacosServer.ReqConfigApi(constant.CONFIG_PATH, params, headers, http.MethodDelete, cp.clientConfig.TimeoutMs)
|
||||
if err != nil {
|
||||
return false, errors.New("[client.DeleteConfig] deleted config failed:" + err.Error())
|
||||
}
|
||||
if strings.ToLower(strings.Trim(result, " ")) == "true" {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, errors.New("[client.DeleteConfig] deleted config failed: " + string(result))
|
||||
}
|
||||
type ConfigChangeNotifyRequestHandler struct {
|
||||
client *ConfigClient
|
||||
}
|
||||
|
||||
func (cp *ConfigProxy) ListenConfig(params map[string]string, isInitializing bool, tenant, accessKey, secretKey string) (string, error) {
|
||||
//fixed at 30000ms,avoid frequent request on the server
|
||||
var listenInterval uint64 = 30000
|
||||
headers := map[string]string{
|
||||
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
|
||||
"Long-Pulling-Timeout": strconv.FormatUint(listenInterval, 10),
|
||||
}
|
||||
if isInitializing {
|
||||
headers["Long-Pulling-Timeout-No-Hangup"] = "true"
|
||||
}
|
||||
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)
|
||||
|
||||
headers["accessKey"] = accessKey
|
||||
headers["secretKey"] = secretKey
|
||||
|
||||
if len(tenant) > 0 {
|
||||
params["tenant"] = tenant
|
||||
cacheKey := util.GetConfigCacheKey(configChangeNotifyRequest.DataId, configChangeNotifyRequest.Group,
|
||||
configChangeNotifyRequest.Tenant)
|
||||
cache, ok := c.client.cacheMap.Get(cacheKey)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
logger.Infof("[client.ListenConfig] request params:%+v header:%+v \n", params, headers)
|
||||
// In order to prevent the server from handling the delay of the client's long task,
|
||||
// increase the client's read timeout to avoid this problem.
|
||||
timeout := listenInterval + listenInterval/10
|
||||
result, err := cp.nacosServer.ReqConfigApi(constant.CONFIG_LISTEN_PATH, params, headers, http.MethodPost, timeout)
|
||||
return result, err
|
||||
cacheData := cache.(*cacheData)
|
||||
cacheData.isSyncWithServer = false
|
||||
c.client.notifyListenConfig()
|
||||
return &rpc_response.NotifySubscriberResponse{
|
||||
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS},
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
package config_client
|
||||
|
||||
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/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
)
|
||||
|
||||
type IConfigProxy interface {
|
||||
queryConfig(dataId, group, tenant string, timeout uint64, notify bool, client *ConfigClient) (*rpc_response.ConfigQueryResponse, error)
|
||||
searchConfigProxy(param vo.SearchConfigParm, tenant, accessKey, secretKey string) (*model.ConfigPage, error)
|
||||
requestProxy(rpcClient *rpc.RpcClient, request rpc_request.IRequest, timeoutMills uint64) (rpc_response.IResponse, error)
|
||||
createRpcClient(taskId string, client *ConfigClient) *rpc.RpcClient
|
||||
getRpcClient(client *ConfigClient) *rpc.RpcClient
|
||||
}
|
|
@ -22,9 +22,9 @@ import (
|
|||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/file"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"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/http_agent"
|
||||
)
|
||||
|
||||
type NacosClient struct {
|
||||
|
@ -68,7 +68,6 @@ 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
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
package nacos_client
|
||||
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination mock_nacos_client_interface.go -package nacos_client -source=./nacos_client_interface.go
|
||||
|
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package naming_client
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/nacos_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestHostReactor_GetServiceInfo(t *testing.T) {
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewNamingClient(&nc)
|
||||
param := vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.11",
|
||||
Port: 8848,
|
||||
ServiceName: "test",
|
||||
Weight: 10,
|
||||
ClusterName: "test",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
}
|
||||
if param.GroupName == "" {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
param.ServiceName = util.GetGroupName(param.ServiceName, param.GroupName)
|
||||
client.RegisterInstance(param)
|
||||
_, err := client.hostReactor.GetServiceInfo(param.ServiceName, param.ClusterName)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestHostReactor_GetServiceInfoErr(t *testing.T) {
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewNamingClient(&nc)
|
||||
param := vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.11",
|
||||
Port: 8848,
|
||||
ServiceName: "test",
|
||||
Weight: 10,
|
||||
ClusterName: "test",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
}
|
||||
client.RegisterInstance(param)
|
||||
_, err := client.hostReactor.GetServiceInfo(param.ServiceName, param.ClusterName)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestHostReactor_GetServiceInfoConcurrent(t *testing.T) {
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewNamingClient(&nc)
|
||||
param := vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.11",
|
||||
Port: 8848,
|
||||
ServiceName: "test",
|
||||
Weight: 10,
|
||||
ClusterName: "test",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
}
|
||||
if param.GroupName == "" {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
param.ServiceName = util.GetGroupName(param.ServiceName, param.GroupName)
|
||||
client.RegisterInstance(param)
|
||||
for i := 0; i < 10000; i++ {
|
||||
go func() {
|
||||
_, err := client.hostReactor.GetServiceInfo(param.ServiceName, param.ClusterName)
|
||||
assert.Nil(t, err)
|
||||
}()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHostReactor_GetServiceInfoConcurrent(b *testing.B) {
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewNamingClient(&nc)
|
||||
param := vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.11",
|
||||
Port: 8848,
|
||||
ServiceName: "test",
|
||||
Weight: 10,
|
||||
ClusterName: "test",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
}
|
||||
if param.GroupName == "" {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
param.ServiceName = util.GetGroupName(param.ServiceName, param.GroupName)
|
||||
client.RegisterInstance(param)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
client.hostReactor.GetServiceInfo(param.ServiceName, param.ClusterName)
|
||||
}
|
||||
}
|
|
@ -1,173 +0,0 @@
|
|||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package naming_client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
)
|
||||
|
||||
type HostReactor struct {
|
||||
serviceInfoMap cache.ConcurrentMap
|
||||
cacheDir string
|
||||
updateThreadNum int
|
||||
serviceProxy NamingProxy
|
||||
pushReceiver PushReceiver
|
||||
subCallback SubscribeCallback
|
||||
updateTimeMap cache.ConcurrentMap
|
||||
updateCacheWhenEmpty bool
|
||||
}
|
||||
|
||||
const Default_Update_Thread_Num = 20
|
||||
|
||||
func NewHostReactor(serviceProxy NamingProxy, cacheDir string, updateThreadNum int, notLoadCacheAtStart bool, subCallback SubscribeCallback, updateCacheWhenEmpty bool) HostReactor {
|
||||
if updateThreadNum <= 0 {
|
||||
updateThreadNum = Default_Update_Thread_Num
|
||||
}
|
||||
hr := HostReactor{
|
||||
serviceProxy: serviceProxy,
|
||||
cacheDir: cacheDir,
|
||||
updateThreadNum: updateThreadNum,
|
||||
serviceInfoMap: cache.NewConcurrentMap(),
|
||||
subCallback: subCallback,
|
||||
updateTimeMap: cache.NewConcurrentMap(),
|
||||
updateCacheWhenEmpty: updateCacheWhenEmpty,
|
||||
}
|
||||
pr := NewPushReceiver(&hr)
|
||||
hr.pushReceiver = *pr
|
||||
if !notLoadCacheAtStart {
|
||||
hr.loadCacheFromDisk()
|
||||
}
|
||||
go hr.asyncUpdateService()
|
||||
return hr
|
||||
}
|
||||
|
||||
func (hr *HostReactor) loadCacheFromDisk() {
|
||||
serviceMap := cache.ReadServicesFromFile(hr.cacheDir)
|
||||
if serviceMap == nil || len(serviceMap) == 0 {
|
||||
return
|
||||
}
|
||||
for k, v := range serviceMap {
|
||||
hr.serviceInfoMap.Set(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func (hr *HostReactor) ProcessServiceJson(result string) {
|
||||
service := util.JsonToService(result)
|
||||
if service == nil {
|
||||
return
|
||||
}
|
||||
cacheKey := util.GetServiceCacheKey(service.Name, service.Clusters)
|
||||
|
||||
oldDomain, ok := hr.serviceInfoMap.Get(cacheKey)
|
||||
if ok && !hr.updateCacheWhenEmpty {
|
||||
//if instance list is empty,not to update cache
|
||||
if service.Hosts == nil || len(service.Hosts) == 0 {
|
||||
logger.Errorf("do not have useful host, ignore it, name:%s", service.Name)
|
||||
return
|
||||
}
|
||||
}
|
||||
hr.updateTimeMap.Set(cacheKey, uint64(util.CurrentMillis()))
|
||||
hr.serviceInfoMap.Set(cacheKey, *service)
|
||||
if !ok || ok && !reflect.DeepEqual(service.Hosts, oldDomain.(model.Service).Hosts) {
|
||||
if !ok {
|
||||
logger.Info("service not found in cache " + cacheKey)
|
||||
} else {
|
||||
logger.Info("service key:%s was updated to:%s", cacheKey, util.ToJsonString(service))
|
||||
}
|
||||
cache.WriteServicesToFile(*service, hr.cacheDir)
|
||||
hr.subCallback.ServiceChanged(service)
|
||||
}
|
||||
}
|
||||
|
||||
func (hr *HostReactor) GetServiceInfo(serviceName string, clusters string) (model.Service, error) {
|
||||
key := util.GetServiceCacheKey(serviceName, clusters)
|
||||
cacheService, ok := hr.serviceInfoMap.Get(key)
|
||||
if !ok {
|
||||
hr.updateServiceNow(serviceName, clusters)
|
||||
if cacheService, ok = hr.serviceInfoMap.Get(key); !ok {
|
||||
return model.Service{}, errors.New("get service info failed")
|
||||
}
|
||||
}
|
||||
|
||||
return cacheService.(model.Service), nil
|
||||
}
|
||||
|
||||
func (hr *HostReactor) GetAllServiceInfo(nameSpace, groupName string, pageNo, pageSize uint32) model.ServiceList {
|
||||
data := model.ServiceList{}
|
||||
result, err := hr.serviceProxy.GetAllServiceInfoList(nameSpace, groupName, pageNo, pageSize)
|
||||
if err != nil {
|
||||
logger.Errorf("GetAllServiceInfoList return error!nameSpace:%s groupName:%s pageNo:%d, pageSize:%d err:%+v",
|
||||
nameSpace, groupName, pageNo, pageSize, err)
|
||||
return data
|
||||
}
|
||||
if result == "" {
|
||||
logger.Errorf("GetAllServiceInfoList result is empty!nameSpace:%s groupName:%s pageNo:%d, pageSize:%d",
|
||||
nameSpace, groupName, pageNo, pageSize)
|
||||
return data
|
||||
}
|
||||
|
||||
err = json.Unmarshal([]byte(result), &data)
|
||||
if err != nil {
|
||||
logger.Errorf("GetAllServiceInfoList result json.Unmarshal error!nameSpace:%s groupName:%s pageNo:%d, pageSize:%d",
|
||||
nameSpace, groupName, pageNo, pageSize)
|
||||
return data
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (hr *HostReactor) updateServiceNow(serviceName, clusters string) {
|
||||
result, err := hr.serviceProxy.QueryList(serviceName, clusters, hr.pushReceiver.port, false)
|
||||
|
||||
if err != nil {
|
||||
logger.Errorf("QueryList return error!serviceName:%s cluster:%s err:%+v", serviceName, clusters, err)
|
||||
return
|
||||
}
|
||||
if result == "" {
|
||||
logger.Errorf("QueryList result is empty!serviceName:%s cluster:%s", serviceName, clusters)
|
||||
return
|
||||
}
|
||||
hr.ProcessServiceJson(result)
|
||||
}
|
||||
|
||||
func (hr *HostReactor) asyncUpdateService() {
|
||||
sema := util.NewSemaphore(hr.updateThreadNum)
|
||||
for {
|
||||
for _, v := range hr.serviceInfoMap.Items() {
|
||||
service := v.(model.Service)
|
||||
lastRefTime, ok := hr.updateTimeMap.Get(util.GetServiceCacheKey(service.Name, service.Clusters))
|
||||
if !ok {
|
||||
lastRefTime = uint64(0)
|
||||
}
|
||||
if uint64(util.CurrentMillis())-lastRefTime.(uint64) > service.CacheMillis {
|
||||
sema.Acquire()
|
||||
go func() {
|
||||
hr.updateServiceNow(service.Name, service.Clusters)
|
||||
sema.Release()
|
||||
}()
|
||||
}
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* 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 naming_cache
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"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"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
type ServiceInfoHolder struct {
|
||||
ServiceInfoMap cache.ConcurrentMap
|
||||
updateCacheWhenEmpty bool
|
||||
cacheDir string
|
||||
notLoadCacheAtStart bool
|
||||
subCallback *SubscribeCallback
|
||||
UpdateTimeMap cache.ConcurrentMap
|
||||
}
|
||||
|
||||
func NewServiceInfoHolder(namespace, cacheDir string, updateCacheWhenEmpty, notLoadCacheAtStart bool) *ServiceInfoHolder {
|
||||
cacheDir = cacheDir + string(os.PathSeparator) + "naming" + string(os.PathSeparator) + namespace
|
||||
serviceInfoHolder := &ServiceInfoHolder{
|
||||
updateCacheWhenEmpty: updateCacheWhenEmpty,
|
||||
notLoadCacheAtStart: notLoadCacheAtStart,
|
||||
cacheDir: cacheDir,
|
||||
subCallback: NewSubscribeCallback(),
|
||||
UpdateTimeMap: cache.NewConcurrentMap(),
|
||||
}
|
||||
if notLoadCacheAtStart {
|
||||
serviceInfoHolder.ServiceInfoMap = cache.NewConcurrentMap()
|
||||
} else {
|
||||
serviceInfoHolder.loadCacheFromDisk()
|
||||
}
|
||||
return serviceInfoHolder
|
||||
}
|
||||
|
||||
func (s *ServiceInfoHolder) loadCacheFromDisk() {
|
||||
serviceMap := cache.ReadServicesFromFile(s.cacheDir)
|
||||
if serviceMap == nil || len(serviceMap) == 0 {
|
||||
return
|
||||
}
|
||||
for k, v := range serviceMap {
|
||||
s.ServiceInfoMap.Set(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServiceInfoHolder) ProcessServiceJson(data string) {
|
||||
s.ProcessService(util.JsonToService(data))
|
||||
}
|
||||
|
||||
func (s *ServiceInfoHolder) ProcessService(service *model.Service) {
|
||||
if service == nil {
|
||||
return
|
||||
}
|
||||
cacheKey := util.GetServiceCacheKey(util.GetGroupName(service.Name, service.GroupName), service.Clusters)
|
||||
|
||||
oldDomain, ok := s.ServiceInfoMap.Get(cacheKey)
|
||||
if ok && !s.updateCacheWhenEmpty {
|
||||
//if instance list is empty,not to update cache
|
||||
if service.Hosts == nil || len(service.Hosts) == 0 {
|
||||
logger.Errorf("do not have useful host, ignore it, name:%s", service.Name)
|
||||
return
|
||||
}
|
||||
}
|
||||
s.UpdateTimeMap.Set(cacheKey, uint64(util.CurrentMillis()))
|
||||
s.ServiceInfoMap.Set(cacheKey, *service)
|
||||
if !ok || ok && !reflect.DeepEqual(service.Hosts, oldDomain.(model.Service).Hosts) {
|
||||
if !ok {
|
||||
logger.Info("service not found in cache " + cacheKey)
|
||||
} else {
|
||||
logger.Info("service key:%s was updated to:%s", cacheKey, util.ToJsonString(service))
|
||||
}
|
||||
cache.WriteServicesToFile(*service, s.cacheDir)
|
||||
s.subCallback.ServiceChanged(service)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServiceInfoHolder) GetServiceInfo(serviceName, groupName, clusters string) (model.Service, bool) {
|
||||
cacheKey := util.GetServiceCacheKey(util.GetGroupName(serviceName, groupName), clusters)
|
||||
//todo FailoverReactor
|
||||
service, ok := s.ServiceInfoMap.Get(cacheKey)
|
||||
if ok {
|
||||
return service.(model.Service), ok
|
||||
}
|
||||
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) DeregisterCallback(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
|
||||
s.subCallback.RemoveCallbackFunc(serviceName, clusters, callbackFunc)
|
||||
}
|
||||
|
||||
func (s *ServiceInfoHolder) StopUpdateIfContain(serviceName, clusters string) {
|
||||
cacheKey := util.GetServiceCacheKey(serviceName, clusters)
|
||||
s.ServiceInfoMap.Remove(cacheKey)
|
||||
}
|
||||
|
||||
func (s *ServiceInfoHolder) IsSubscribed(serviceName, clusters string) bool {
|
||||
return s.subCallback.IsSubscribed(serviceName, clusters)
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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 naming_cache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"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"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
type SubscribeCallback struct {
|
||||
callbackFuncMap cache.ConcurrentMap
|
||||
mux *sync.Mutex
|
||||
}
|
||||
|
||||
func NewSubscribeCallback() *SubscribeCallback {
|
||||
return &SubscribeCallback{callbackFuncMap: cache.NewConcurrentMap(), mux: new(sync.Mutex)}
|
||||
}
|
||||
|
||||
func (ed *SubscribeCallback) IsSubscribed(serviceName, clusters string) bool {
|
||||
key := util.GetServiceCacheKey(serviceName, clusters)
|
||||
_, ok := ed.callbackFuncMap.Get(key)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (ed *SubscribeCallback) AddCallbackFunc(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
|
||||
logger.Info("adding " + serviceName + " with " + clusters + " to listener map")
|
||||
key := util.GetServiceCacheKey(serviceName, clusters)
|
||||
defer ed.mux.Unlock()
|
||||
ed.mux.Lock()
|
||||
var funcSlice []*func(services []model.Instance, err error)
|
||||
old, ok := ed.callbackFuncMap.Get(key)
|
||||
if ok {
|
||||
funcSlice = append(funcSlice, old.([]*func(services []model.Instance, err error))...)
|
||||
}
|
||||
funcSlice = append(funcSlice, callbackFunc)
|
||||
ed.callbackFuncMap.Set(key, funcSlice)
|
||||
}
|
||||
|
||||
func (ed *SubscribeCallback) RemoveCallbackFunc(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) {
|
||||
logger.Info("removing " + serviceName + " with " + clusters + " to listener map")
|
||||
key := util.GetServiceCacheKey(serviceName, clusters)
|
||||
funcs, ok := ed.callbackFuncMap.Get(key)
|
||||
if ok && funcs != nil {
|
||||
var newFuncs []*func(services []model.Instance, err error)
|
||||
for _, funcItem := range funcs.([]*func(services []model.Instance, err error)) {
|
||||
if funcItem != callbackFunc {
|
||||
newFuncs = append(newFuncs, funcItem)
|
||||
}
|
||||
}
|
||||
ed.callbackFuncMap.Set(key, newFuncs)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (ed *SubscribeCallback) ServiceChanged(service *model.Service) {
|
||||
if service == nil || service.Name == "" {
|
||||
return
|
||||
}
|
||||
key := util.GetServiceCacheKey(util.GetGroupName(service.Name, service.GroupName), service.Clusters)
|
||||
funcs, ok := ed.callbackFuncMap.Get(key)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package naming_client
|
||||
package naming_cache
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -23,15 +23,14 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"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/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEventDispatcher_AddCallbackFuncs(t *testing.T) {
|
||||
service := model.Service{
|
||||
Dom: "public@@Test",
|
||||
Clusters: strings.Join([]string{"default"}, ","),
|
||||
CacheMillis: 10000,
|
||||
Checksum: "abcd",
|
||||
|
@ -39,7 +38,6 @@ func TestEventDispatcher_AddCallbackFuncs(t *testing.T) {
|
|||
}
|
||||
var hosts []model.Instance
|
||||
host := model.Instance{
|
||||
Valid: true,
|
||||
Enable: true,
|
||||
InstanceId: "123",
|
||||
Port: 8080,
|
||||
|
@ -56,15 +54,15 @@ func TestEventDispatcher_AddCallbackFuncs(t *testing.T) {
|
|||
ServiceName: "Test",
|
||||
Clusters: []string{"default"},
|
||||
GroupName: "public",
|
||||
SubscribeCallback: func(services []model.SubscribeService, err error) {
|
||||
fmt.Println(util.ToJsonString(ed.callbackFuncsMap))
|
||||
SubscribeCallback: func(services []model.Instance, err error) {
|
||||
fmt.Println(util.ToJsonString(ed.callbackFuncMap))
|
||||
},
|
||||
}
|
||||
ed.AddCallbackFuncs(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
key := util.GetServiceCacheKey(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
|
||||
for k, v := range ed.callbackFuncsMap.Items() {
|
||||
for k, v := range ed.callbackFuncMap.Items() {
|
||||
assert.Equal(t, key, k, "key should be equal!")
|
||||
funcs := v.([]*func(services []model.SubscribeService, err error))
|
||||
funcs := v.([]*func(services []model.Instance, err error))
|
||||
assert.Equal(t, len(funcs), 1)
|
||||
assert.Equal(t, funcs[0], ¶m.SubscribeCallback, "callback function must be equal!")
|
||||
|
||||
|
@ -73,7 +71,6 @@ func TestEventDispatcher_AddCallbackFuncs(t *testing.T) {
|
|||
|
||||
func TestEventDispatcher_RemoveCallbackFuncs(t *testing.T) {
|
||||
service := model.Service{
|
||||
Dom: "public@@Test",
|
||||
Clusters: strings.Join([]string{"default"}, ","),
|
||||
CacheMillis: 10000,
|
||||
Checksum: "abcd",
|
||||
|
@ -81,7 +78,6 @@ func TestEventDispatcher_RemoveCallbackFuncs(t *testing.T) {
|
|||
}
|
||||
var hosts []model.Instance
|
||||
host := model.Instance{
|
||||
Valid: true,
|
||||
Enable: true,
|
||||
InstanceId: "123",
|
||||
Port: 8080,
|
||||
|
@ -98,34 +94,34 @@ func TestEventDispatcher_RemoveCallbackFuncs(t *testing.T) {
|
|||
ServiceName: "Test",
|
||||
Clusters: []string{"default"},
|
||||
GroupName: "public",
|
||||
SubscribeCallback: func(services []model.SubscribeService, err error) {
|
||||
SubscribeCallback: func(services []model.Instance, err error) {
|
||||
fmt.Printf("func1:%s \n", util.ToJsonString(services))
|
||||
},
|
||||
}
|
||||
ed.AddCallbackFuncs(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
assert.Equal(t, len(ed.callbackFuncsMap.Items()), 1, "callback funcs map length should be 1")
|
||||
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
assert.Equal(t, len(ed.callbackFuncMap.Items()), 1, "callback funcs map length should be 1")
|
||||
|
||||
param2 := vo.SubscribeParam{
|
||||
ServiceName: "Test",
|
||||
Clusters: []string{"default"},
|
||||
GroupName: "public",
|
||||
SubscribeCallback: func(services []model.SubscribeService, err error) {
|
||||
SubscribeCallback: func(services []model.Instance, err error) {
|
||||
fmt.Printf("func2:%s \n", util.ToJsonString(services))
|
||||
},
|
||||
}
|
||||
ed.AddCallbackFuncs(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), ¶m2.SubscribeCallback)
|
||||
assert.Equal(t, len(ed.callbackFuncsMap.Items()), 1, "callback funcs map length should be 2")
|
||||
ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), ¶m2.SubscribeCallback)
|
||||
assert.Equal(t, len(ed.callbackFuncMap.Items()), 1, "callback funcs map length should be 2")
|
||||
|
||||
for k, v := range ed.callbackFuncsMap.Items() {
|
||||
log.Printf("key:%s,%d", k, len(v.([]*func(services []model.SubscribeService, err error))))
|
||||
for k, v := range ed.callbackFuncMap.Items() {
|
||||
log.Printf("key:%s,%d", k, len(v.([]*func(services []model.Instance, err error))))
|
||||
}
|
||||
|
||||
ed.RemoveCallbackFuncs(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), ¶m2.SubscribeCallback)
|
||||
ed.RemoveCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), ¶m2.SubscribeCallback)
|
||||
|
||||
key := util.GetServiceCacheKey(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
|
||||
for k, v := range ed.callbackFuncsMap.Items() {
|
||||
for k, v := range ed.callbackFuncMap.Items() {
|
||||
assert.Equal(t, key, k, "key should be equal!")
|
||||
funcs := v.([]*func(services []model.SubscribeService, err error))
|
||||
funcs := v.([]*func(services []model.Instance, err error))
|
||||
assert.Equal(t, len(funcs), 1)
|
||||
assert.Equal(t, funcs[0], ¶m.SubscribeCallback, "callback function must be equal!")
|
||||
|
||||
|
@ -142,7 +138,6 @@ func TestSubscribeCallback_ServiceChanged(t *testing.T) {
|
|||
}
|
||||
var hosts []model.Instance
|
||||
host := model.Instance{
|
||||
Valid: true,
|
||||
Enable: true,
|
||||
InstanceId: "123",
|
||||
Port: 8080,
|
||||
|
@ -159,22 +154,22 @@ func TestSubscribeCallback_ServiceChanged(t *testing.T) {
|
|||
ServiceName: "Test",
|
||||
Clusters: []string{"default"},
|
||||
GroupName: "public",
|
||||
SubscribeCallback: func(services []model.SubscribeService, err error) {
|
||||
SubscribeCallback: func(services []model.Instance, err error) {
|
||||
log.Printf("func1:%s \n", util.ToJsonString(services))
|
||||
},
|
||||
}
|
||||
ed.AddCallbackFuncs(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
ed.AddCallbackFunc(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
|
||||
param2 := vo.SubscribeParam{
|
||||
ServiceName: "Test",
|
||||
Clusters: []string{"default"},
|
||||
GroupName: "public",
|
||||
SubscribeCallback: func(services []model.SubscribeService, err error) {
|
||||
SubscribeCallback: func(services []model.Instance, err error) {
|
||||
log.Printf("func2:%s \n", util.ToJsonString(services))
|
||||
|
||||
},
|
||||
}
|
||||
ed.AddCallbackFuncs(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), ¶m2.SubscribeCallback)
|
||||
ed.AddCallbackFunc(util.GetGroupName(param2.ServiceName, param2.GroupName), strings.Join(param2.Clusters, ","), ¶m2.SubscribeCallback)
|
||||
|
||||
ed.ServiceChanged(&service)
|
||||
}
|
|
@ -19,72 +19,70 @@ package naming_client
|
|||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/nacos_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client"
|
||||
"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_proxy"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type NamingClient struct {
|
||||
nacos_client.INacosClient
|
||||
hostReactor HostReactor
|
||||
serviceProxy NamingProxy
|
||||
subCallback SubscribeCallback
|
||||
beatReactor BeatReactor
|
||||
indexMap cache.ConcurrentMap
|
||||
NamespaceId string
|
||||
serviceProxy naming_proxy.INamingProxy
|
||||
serviceInfoHolder *naming_cache.ServiceInfoHolder
|
||||
}
|
||||
|
||||
type Chooser struct {
|
||||
data []model.Instance
|
||||
totals []int
|
||||
max int
|
||||
}
|
||||
|
||||
func NewNamingClient(nc nacos_client.INacosClient) (NamingClient, error) {
|
||||
naming := NamingClient{}
|
||||
func NewNamingClient(nc nacos_client.INacosClient) (*NamingClient, error) {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
naming := &NamingClient{INacosClient: nc}
|
||||
clientConfig, err := nc.GetClientConfig()
|
||||
if err != nil {
|
||||
return naming, err
|
||||
}
|
||||
naming.NamespaceId = clientConfig.NamespaceId
|
||||
|
||||
serverConfig, err := nc.GetServerConfig()
|
||||
if err != nil {
|
||||
return naming, err
|
||||
}
|
||||
|
||||
httpAgent, err := nc.GetHttpAgent()
|
||||
if err != nil {
|
||||
return naming, err
|
||||
}
|
||||
err = logger.InitLogger(logger.Config{
|
||||
|
||||
if err = initLogger(clientConfig); err != nil {
|
||||
return naming, err
|
||||
}
|
||||
if clientConfig.NamespaceId == "" {
|
||||
clientConfig.NamespaceId = constant.DEFAULT_NAMESPACE_ID
|
||||
}
|
||||
naming.serviceInfoHolder = naming_cache.NewServiceInfoHolder(clientConfig.NamespaceId, clientConfig.CacheDir,
|
||||
clientConfig.UpdateCacheWhenEmpty, clientConfig.NotLoadCacheAtStart)
|
||||
|
||||
naming.serviceProxy, err = naming_proxy.NewNamingProxyDelegate(clientConfig, serverConfig, httpAgent, naming.serviceInfoHolder)
|
||||
|
||||
go NewServiceInfoUpdater(naming.serviceInfoHolder, clientConfig.UpdateThreadNum, naming.serviceProxy).asyncUpdateService()
|
||||
if err != nil {
|
||||
return naming, err
|
||||
}
|
||||
|
||||
return naming, nil
|
||||
}
|
||||
|
||||
func initLogger(clientConfig constant.ClientConfig) error {
|
||||
return logger.InitLogger(logger.Config{
|
||||
Level: clientConfig.LogLevel,
|
||||
OutputPath: clientConfig.LogDir,
|
||||
RotationTime: clientConfig.RotateTime,
|
||||
MaxAge: clientConfig.MaxAge,
|
||||
})
|
||||
if err != nil {
|
||||
return naming, err
|
||||
}
|
||||
naming.subCallback = NewSubscribeCallback()
|
||||
naming.serviceProxy, err = NewNamingProxy(clientConfig, serverConfig, httpAgent)
|
||||
if err != nil {
|
||||
return naming, err
|
||||
}
|
||||
naming.hostReactor = NewHostReactor(naming.serviceProxy, clientConfig.CacheDir+string(os.PathSeparator)+"naming",
|
||||
clientConfig.UpdateThreadNum, clientConfig.NotLoadCacheAtStart, naming.subCallback, clientConfig.UpdateCacheWhenEmpty)
|
||||
naming.beatReactor = NewBeatReactor(naming.serviceProxy, clientConfig.BeatInterval)
|
||||
naming.indexMap = cache.NewConcurrentMap()
|
||||
|
||||
return naming, nil
|
||||
}
|
||||
|
||||
// 注册服务实例
|
||||
|
@ -108,24 +106,8 @@ func (sc *NamingClient) RegisterInstance(param vo.RegisterInstanceParam) (bool,
|
|||
Weight: param.Weight,
|
||||
Ephemeral: param.Ephemeral,
|
||||
}
|
||||
beatInfo := model.BeatInfo{
|
||||
Ip: param.Ip,
|
||||
Port: param.Port,
|
||||
Metadata: param.Metadata,
|
||||
ServiceName: util.GetGroupName(param.ServiceName, param.GroupName),
|
||||
Cluster: param.ClusterName,
|
||||
Weight: param.Weight,
|
||||
Period: util.GetDurationWithDefault(param.Metadata, constant.HEART_BEAT_INTERVAL, time.Second*5),
|
||||
State: model.StateRunning,
|
||||
}
|
||||
_, err := sc.serviceProxy.RegisterInstance(util.GetGroupName(param.ServiceName, param.GroupName), param.GroupName, instance)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if instance.Ephemeral {
|
||||
sc.beatReactor.AddBeatInfo(util.GetGroupName(param.ServiceName, param.GroupName), beatInfo)
|
||||
}
|
||||
return true, nil
|
||||
|
||||
return sc.serviceProxy.RegisterInstance(param.ServiceName, param.GroupName, instance)
|
||||
|
||||
}
|
||||
|
||||
|
@ -134,21 +116,26 @@ func (sc *NamingClient) DeregisterInstance(param vo.DeregisterInstanceParam) (bo
|
|||
if len(param.GroupName) == 0 {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
sc.beatReactor.RemoveBeatInfo(util.GetGroupName(param.ServiceName, param.GroupName), param.Ip, param.Port)
|
||||
|
||||
_, err := sc.serviceProxy.DeregisterInstance(util.GetGroupName(param.ServiceName, param.GroupName), param.Ip, param.Port, param.Cluster, param.Ephemeral)
|
||||
if err != nil {
|
||||
return false, err
|
||||
instance := model.Instance{
|
||||
Ip: param.Ip,
|
||||
Port: param.Port,
|
||||
ClusterName: param.Cluster,
|
||||
Ephemeral: param.Ephemeral,
|
||||
}
|
||||
return true, nil
|
||||
return sc.serviceProxy.DeregisterInstance(param.ServiceName, param.GroupName, instance)
|
||||
}
|
||||
|
||||
// 获取服务列表
|
||||
func (sc *NamingClient) GetService(param vo.GetServiceParam) (model.Service, error) {
|
||||
func (sc *NamingClient) GetService(param vo.GetServiceParam) (service model.Service, err error) {
|
||||
if len(param.GroupName) == 0 {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
service, err := sc.hostReactor.GetServiceInfo(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
|
||||
var ok bool
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
|
||||
if !ok {
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
|
||||
}
|
||||
return service, err
|
||||
}
|
||||
|
||||
|
@ -156,22 +143,33 @@ func (sc *NamingClient) GetAllServicesInfo(param vo.GetAllServiceInfoParam) (mod
|
|||
if len(param.GroupName) == 0 {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
clientConfig, _ := sc.GetClientConfig()
|
||||
if len(param.NameSpace) == 0 {
|
||||
if len(sc.NamespaceId) == 0 {
|
||||
if len(clientConfig.NamespaceId) == 0 {
|
||||
param.NameSpace = constant.DEFAULT_NAMESPACE_ID
|
||||
} else {
|
||||
param.NameSpace = sc.NamespaceId
|
||||
param.NameSpace = clientConfig.NamespaceId
|
||||
}
|
||||
}
|
||||
services := sc.hostReactor.GetAllServiceInfo(param.NameSpace, param.GroupName, param.PageNo, param.PageSize)
|
||||
return services, nil
|
||||
services, err := sc.serviceProxy.GetServiceList(param.PageNo, param.PageSize, param.GroupName, &model.ExpressionSelector{})
|
||||
return services, err
|
||||
}
|
||||
|
||||
func (sc *NamingClient) SelectAllInstances(param vo.SelectAllInstancesParam) ([]model.Instance, error) {
|
||||
if len(param.GroupName) == 0 {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
service, err := sc.hostReactor.GetServiceInfo(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
var (
|
||||
service model.Service
|
||||
ok bool
|
||||
err error
|
||||
)
|
||||
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
|
||||
if !ok {
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
|
||||
}
|
||||
if err != nil || service.Hosts == nil || len(service.Hosts) == 0 {
|
||||
return []model.Instance{}, err
|
||||
}
|
||||
|
@ -182,10 +180,19 @@ func (sc *NamingClient) SelectInstances(param vo.SelectInstancesParam) ([]model.
|
|||
if len(param.GroupName) == 0 {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
service, err := sc.hostReactor.GetServiceInfo(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
|
||||
var (
|
||||
service model.Service
|
||||
ok bool
|
||||
err error
|
||||
)
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
|
||||
if !ok {
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return sc.selectInstances(service, param.HealthyOnly)
|
||||
}
|
||||
|
||||
|
@ -207,10 +214,20 @@ func (sc *NamingClient) SelectOneHealthyInstance(param vo.SelectOneHealthInstanc
|
|||
if len(param.GroupName) == 0 {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
service, err := sc.hostReactor.GetServiceInfo(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","))
|
||||
var (
|
||||
service model.Service
|
||||
ok bool
|
||||
err error
|
||||
)
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
service, ok = sc.serviceInfoHolder.GetServiceInfo(param.ServiceName, param.GroupName, clusters)
|
||||
if !ok {
|
||||
service, err = sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return sc.selectOneHealthyInstances(service)
|
||||
}
|
||||
|
||||
|
@ -234,84 +251,29 @@ func (sc *NamingClient) selectOneHealthyInstances(service model.Service) (*model
|
|||
return nil, errors.New("healthy instance list is empty!")
|
||||
}
|
||||
|
||||
chooser := newChooser(result)
|
||||
instance := chooser.pick()
|
||||
instance := newChooser(result).pick()
|
||||
return &instance, nil
|
||||
}
|
||||
|
||||
func random(instances []model.Instance, mw int) []model.Instance {
|
||||
if len(instances) <= 1 || mw <= 1 {
|
||||
return instances
|
||||
}
|
||||
//实例交叉插入列表,避免列表中是连续的实例
|
||||
var result = make([]model.Instance, 0)
|
||||
for i := 1; i <= mw; i++ {
|
||||
for _, host := range instances {
|
||||
if int(math.Ceil(host.Weight)) >= i {
|
||||
result = append(result, host)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
type instance []model.Instance
|
||||
|
||||
func (a instance) Len() int {
|
||||
return len(a)
|
||||
}
|
||||
|
||||
func (a instance) Swap(i, j int) {
|
||||
a[i], a[j] = a[j], a[i]
|
||||
}
|
||||
|
||||
func (a instance) Less(i, j int) bool {
|
||||
return a[i].Weight < a[j].Weight
|
||||
}
|
||||
|
||||
// NewChooser initializes a new Chooser for picking from the provided Choices.
|
||||
func newChooser(instances []model.Instance) Chooser {
|
||||
sort.Sort(instance(instances))
|
||||
totals := make([]int, len(instances))
|
||||
runningTotal := 0
|
||||
for i, c := range instances {
|
||||
runningTotal += int(c.Weight)
|
||||
totals[i] = runningTotal
|
||||
}
|
||||
return Chooser{data: instances, totals: totals, max: runningTotal}
|
||||
}
|
||||
|
||||
func (chs Chooser) pick() model.Instance {
|
||||
rand.Seed(time.Now().Unix())
|
||||
r := rand.Intn(chs.max) + 1
|
||||
i := sort.SearchInts(chs.totals, r)
|
||||
return chs.data[i]
|
||||
}
|
||||
|
||||
// 服务监听
|
||||
func (sc *NamingClient) Subscribe(param *vo.SubscribeParam) error {
|
||||
if len(param.GroupName) == 0 {
|
||||
param.GroupName = constant.DEFAULT_GROUP
|
||||
}
|
||||
serviceParam := vo.GetServiceParam{
|
||||
ServiceName: param.ServiceName,
|
||||
GroupName: param.GroupName,
|
||||
Clusters: param.Clusters,
|
||||
}
|
||||
|
||||
sc.subCallback.AddCallbackFuncs(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
svc, err := sc.GetService(serviceParam)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !sc.hostReactor.serviceProxy.clientConfig.NotLoadCacheAtStart {
|
||||
sc.subCallback.ServiceChanged(&svc)
|
||||
}
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
sc.serviceInfoHolder.RegisterCallback(util.GetGroupName(param.ServiceName, param.GroupName), clusters, ¶m.SubscribeCallback)
|
||||
sc.serviceProxy.Subscribe(param.ServiceName, param.GroupName, clusters)
|
||||
return nil
|
||||
}
|
||||
|
||||
//取消服务监听
|
||||
func (sc *NamingClient) Unsubscribe(param *vo.SubscribeParam) error {
|
||||
sc.subCallback.RemoveCallbackFuncs(util.GetGroupName(param.ServiceName, param.GroupName), strings.Join(param.Clusters, ","), ¶m.SubscribeCallback)
|
||||
clusters := strings.Join(param.Clusters, ",")
|
||||
serviceFullName := util.GetGroupName(param.ServiceName, param.GroupName)
|
||||
sc.serviceInfoHolder.DeregisterCallback(serviceFullName, clusters, ¶m.SubscribeCallback)
|
||||
if sc.serviceInfoHolder.IsSubscribed(serviceFullName, clusters) {
|
||||
sc.serviceProxy.Unsubscribe(param.ServiceName, param.GroupName, clusters)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -16,8 +16,8 @@
|
|||
package naming_client
|
||||
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
)
|
||||
|
||||
//go:generate mockgen -destination ../../mock/mock_service_client_interface.go -package mock -source=./service_client_interface.go
|
||||
|
|
|
@ -17,18 +17,14 @@
|
|||
package naming_client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/nacos_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/mock"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/http_agent"
|
||||
|
||||
"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/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -38,7 +34,7 @@ var clientConfigTest = *constant.NewClientConfig(
|
|||
constant.WithNotLoadCacheAtStart(true),
|
||||
)
|
||||
|
||||
var serverConfigTest = *constant.NewServerConfig("console.nacos.io", 80, constant.WithContextPath("/nacos"))
|
||||
var serverConfigTest = *constant.NewServerConfig("127.0.0.1", 80, constant.WithContextPath("/nacos"))
|
||||
|
||||
var headers = map[string][]string{
|
||||
"Client-Version": {constant.CLIENT_VERSION},
|
||||
|
@ -49,37 +45,46 @@ var headers = map[string][]string{
|
|||
"Content-Type": {"application/x-www-form-urlencoded"},
|
||||
}
|
||||
|
||||
func Test_RegisterServiceInstance_withoutGroupName(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
mockIHttpAgent.EXPECT().Request(gomock.Eq("POST"),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/ns/instance"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(uint64(10*1000)),
|
||||
gomock.Eq(map[string]string{
|
||||
"namespaceId": "",
|
||||
"serviceName": "DEFAULT_GROUP@@DEMO",
|
||||
"groupName": "DEFAULT_GROUP",
|
||||
"app": "",
|
||||
"clusterName": "",
|
||||
"ip": "10.0.0.10",
|
||||
"port": "80",
|
||||
"weight": "0",
|
||||
"enable": "false",
|
||||
"healthy": "false",
|
||||
"metadata": "{}",
|
||||
"ephemeral": "false",
|
||||
})).Times(1).
|
||||
Return(http_agent.FakeHttpResponse(200, `ok`), nil)
|
||||
type MockNamingProxy struct {
|
||||
}
|
||||
|
||||
func (m *MockNamingProxy) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m *MockNamingProxy) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (m *MockNamingProxy) GetServiceList(pageNo uint32, pageSize uint32, groupName string, selector *model.ExpressionSelector) (model.ServiceList, error) {
|
||||
return model.ServiceList{Doms: []string{""}}, nil
|
||||
}
|
||||
|
||||
func (m *MockNamingProxy) ServerHealthy() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *MockNamingProxy) QueryInstancesOfService(serviceName, groupName, clusters string, udpPort int, healthyOnly bool) (*model.Service, error) {
|
||||
return &model.Service{}, nil
|
||||
}
|
||||
|
||||
func (m *MockNamingProxy) Subscribe(serviceName, groupName, clusters string) (model.Service, error) {
|
||||
return model.Service{}, nil
|
||||
}
|
||||
|
||||
func (m *MockNamingProxy) Unsubscribe(serviceName, groupName, clusters string) {}
|
||||
|
||||
func NewTestNamingClient() *NamingClient {
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewNamingClient(&nc)
|
||||
success, err := client.RegisterInstance(vo.RegisterInstanceParam{
|
||||
client.serviceProxy = &MockNamingProxy{}
|
||||
return client
|
||||
}
|
||||
func Test_RegisterServiceInstance_withoutGroupName(t *testing.T) {
|
||||
success, err := NewTestNamingClient().RegisterInstance(vo.RegisterInstanceParam{
|
||||
ServiceName: "DEMO",
|
||||
Ip: "10.0.0.10",
|
||||
Port: 80,
|
||||
|
@ -90,39 +95,8 @@ func Test_RegisterServiceInstance_withoutGroupName(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_RegisterServiceInstance_withGroupName(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
mockIHttpAgent.EXPECT().Request(gomock.Eq("POST"),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/ns/instance"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(uint64(10*1000)),
|
||||
gomock.Eq(map[string]string{
|
||||
"namespaceId": "",
|
||||
"serviceName": "test_group@@DEMO2",
|
||||
"groupName": "test_group",
|
||||
"app": "",
|
||||
"clusterName": "",
|
||||
"ip": "10.0.0.10",
|
||||
"port": "80",
|
||||
"weight": "0",
|
||||
"enable": "false",
|
||||
"healthy": "false",
|
||||
"metadata": "{}",
|
||||
"ephemeral": "false",
|
||||
})).Times(1).
|
||||
Return(http_agent.FakeHttpResponse(200, `ok`), nil)
|
||||
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
success, err := client.RegisterInstance(vo.RegisterInstanceParam{
|
||||
ServiceName: "DEMO2",
|
||||
success, err := NewTestNamingClient().RegisterInstance(vo.RegisterInstanceParam{
|
||||
ServiceName: "DEMO",
|
||||
Ip: "10.0.0.10",
|
||||
Port: 80,
|
||||
GroupName: "test_group",
|
||||
|
@ -133,39 +107,8 @@ func Test_RegisterServiceInstance_withGroupName(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_RegisterServiceInstance_withCluster(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
mockIHttpAgent.EXPECT().Request(gomock.Eq("POST"),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/ns/instance"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(uint64(10*1000)),
|
||||
gomock.Eq(map[string]string{
|
||||
"namespaceId": "",
|
||||
"serviceName": "test_group@@DEMO3",
|
||||
"groupName": "test_group",
|
||||
"app": "",
|
||||
"clusterName": "test",
|
||||
"ip": "10.0.0.10",
|
||||
"port": "80",
|
||||
"weight": "0",
|
||||
"enable": "false",
|
||||
"healthy": "false",
|
||||
"metadata": "{}",
|
||||
"ephemeral": "false",
|
||||
})).Times(1).
|
||||
Return(http_agent.FakeHttpResponse(200, `ok`), nil)
|
||||
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
success, err := client.RegisterInstance(vo.RegisterInstanceParam{
|
||||
ServiceName: "DEMO3",
|
||||
success, err := NewTestNamingClient().RegisterInstance(vo.RegisterInstanceParam{
|
||||
ServiceName: "DEMO",
|
||||
Ip: "10.0.0.10",
|
||||
Port: 80,
|
||||
GroupName: "test_group",
|
||||
|
@ -175,149 +118,27 @@ func Test_RegisterServiceInstance_withCluster(t *testing.T) {
|
|||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, success)
|
||||
}
|
||||
|
||||
func Test_RegisterServiceInstance_401(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
mockIHttpAgent.EXPECT().Request(gomock.Eq("POST"),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/ns/instance"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(uint64(10*1000)),
|
||||
gomock.Eq(map[string]string{
|
||||
"namespaceId": "",
|
||||
"serviceName": "test_group@@DEMO4",
|
||||
"groupName": "test_group",
|
||||
"app": "",
|
||||
"clusterName": "",
|
||||
"ip": "10.0.0.10",
|
||||
"port": "80",
|
||||
"weight": "0",
|
||||
"enable": "false",
|
||||
"healthy": "false",
|
||||
"metadata": "{}",
|
||||
"ephemeral": "false",
|
||||
})).Times(3).
|
||||
Return(http_agent.FakeHttpResponse(401, `no security`), nil)
|
||||
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
result, err := client.RegisterInstance(vo.RegisterInstanceParam{
|
||||
ServiceName: "DEMO4",
|
||||
Ip: "10.0.0.10",
|
||||
Port: 80,
|
||||
GroupName: "test_group",
|
||||
Ephemeral: false,
|
||||
})
|
||||
assert.Equal(t, false, result)
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestNamingProxy_DeregisterService_WithoutGroupName(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
mockIHttpAgent.EXPECT().Request(gomock.Eq("DELETE"),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/ns/instance"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(uint64(10*1000)),
|
||||
gomock.Eq(map[string]string{
|
||||
"namespaceId": "",
|
||||
"serviceName": "DEFAULT_GROUP@@DEMO5",
|
||||
"clusterName": "",
|
||||
"ip": "10.0.0.10",
|
||||
"port": "80",
|
||||
"ephemeral": "true",
|
||||
})).Times(1).
|
||||
Return(http_agent.FakeHttpResponse(200, `ok`), nil)
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
client.DeregisterInstance(vo.DeregisterInstanceParam{
|
||||
success, err := NewTestNamingClient().DeregisterInstance(vo.DeregisterInstanceParam{
|
||||
ServiceName: "DEMO5",
|
||||
Ip: "10.0.0.10",
|
||||
Port: 80,
|
||||
Ephemeral: true,
|
||||
})
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, success)
|
||||
}
|
||||
|
||||
func TestNamingProxy_DeregisterService_WithGroupName(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
mockIHttpAgent.EXPECT().Request(gomock.Eq("DELETE"),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/ns/instance"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(uint64(10*1000)),
|
||||
gomock.Eq(map[string]string{
|
||||
"namespaceId": "",
|
||||
"serviceName": "test_group@@DEMO6",
|
||||
"clusterName": "",
|
||||
"ip": "10.0.0.10",
|
||||
"port": "80",
|
||||
"ephemeral": "true",
|
||||
})).Times(1).
|
||||
Return(http_agent.FakeHttpResponse(200, `ok`), nil)
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
client.DeregisterInstance(vo.DeregisterInstanceParam{
|
||||
success, err := NewTestNamingClient().DeregisterInstance(vo.DeregisterInstanceParam{
|
||||
ServiceName: "DEMO6",
|
||||
Ip: "10.0.0.10",
|
||||
Port: 80,
|
||||
GroupName: "test_group",
|
||||
Ephemeral: true,
|
||||
})
|
||||
}
|
||||
|
||||
func TestNamingProxy_DeregisterService_401(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
mockIHttpAgent.EXPECT().Request(gomock.Eq("DELETE"),
|
||||
gomock.Eq("http://console.nacos.io:80/nacos/v1/ns/instance"),
|
||||
gomock.AssignableToTypeOf(http.Header{}),
|
||||
gomock.Eq(uint64(10*1000)),
|
||||
gomock.Eq(map[string]string{
|
||||
"namespaceId": "",
|
||||
"serviceName": "test_group@@DEMO7",
|
||||
"clusterName": "",
|
||||
"ip": "10.0.0.10",
|
||||
"port": "80",
|
||||
"ephemeral": "true",
|
||||
})).Times(3).
|
||||
Return(http_agent.FakeHttpResponse(401, `no security`), nil)
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
client.DeregisterInstance(vo.DeregisterInstanceParam{
|
||||
ServiceName: "DEMO7",
|
||||
Ip: "10.0.0.10",
|
||||
Port: 80,
|
||||
GroupName: "test_group",
|
||||
Ephemeral: true,
|
||||
})
|
||||
assert.Equal(t, nil, err)
|
||||
assert.Equal(t, true, success)
|
||||
}
|
||||
|
||||
var serviceJsonTest = `{
|
||||
|
@ -355,11 +176,9 @@ var serviceJsonTest = `{
|
|||
}`
|
||||
|
||||
var serviceTest = model.Service(model.Service{Name: "DEFAULT_GROUP@@DEMO",
|
||||
CacheMillis: 1000, UseSpecifiedURL: false,
|
||||
CacheMillis: 1000,
|
||||
Hosts: []model.Instance{
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.10-8888-a-DEMO",
|
||||
Port: 0x22b8,
|
||||
Ip: "10.10.10.10",
|
||||
|
@ -370,8 +189,6 @@ var serviceTest = model.Service(model.Service{Name: "DEFAULT_GROUP@@DEMO",
|
|||
Enable: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.11-8888-a-DEMO",
|
||||
Port: 0x22b8,
|
||||
Ip: "10.10.10.11",
|
||||
|
@ -383,74 +200,14 @@ var serviceTest = model.Service(model.Service{Name: "DEFAULT_GROUP@@DEMO",
|
|||
},
|
||||
},
|
||||
Checksum: "3bbcf6dd1175203a8afdade0e77a27cd1528787794594",
|
||||
LastRefTime: 1528787794594, Env: "", Clusters: "a",
|
||||
Metadata: map[string]string(nil)})
|
||||
|
||||
//func TestNamingProxy_GetService_WithoutGroupName(t *testing.T) {
|
||||
// ctrl := gomock.NewController(t)
|
||||
// defer func() {
|
||||
// ctrl.Finish()
|
||||
// }()
|
||||
// mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
//
|
||||
// mockIHttpAgent.EXPECT().Request(gomock.Eq("GET"),
|
||||
// gomock.Eq("http://console.nacos.io:80/nacos/v1/ns/instance/list"),
|
||||
// gomock.AssignableToTypeOf(http.Header{}),
|
||||
// gomock.Eq(uint64(10*1000)),
|
||||
// gomock.Any()).Times(2).
|
||||
// Return(http_agent.FakeHttpResponse(200, serviceJsonTest), nil)
|
||||
//
|
||||
// nc := nacos_client.NacosClient{}
|
||||
// nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
// nc.SetClientConfig(clientConfigTest)
|
||||
// nc.SetHttpAgent(mockIHttpAgent)
|
||||
// client, _ := NewNamingClient(&nc)
|
||||
// result, err := client.GetService(vo.GetServiceParam{
|
||||
// ServiceName: "DEMO",
|
||||
// Clusters: []string{"a"},
|
||||
// })
|
||||
// assert.Nil(t, err)
|
||||
// assert.Equal(t, serviceTest, result)
|
||||
//
|
||||
//}
|
||||
|
||||
//func TestNamingClient_SelectAllInstancs(t *testing.T) {
|
||||
// ctrl := gomock.NewController(t)
|
||||
// defer func() {
|
||||
// ctrl.Finish()
|
||||
// }()
|
||||
// mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
//
|
||||
// mockIHttpAgent.EXPECT().Request(gomock.Eq("GET"),
|
||||
// gomock.Eq("http://console.nacos.io:80/nacos/v1/ns/instance/list"),
|
||||
// gomock.AssignableToTypeOf(http.Header{}),
|
||||
// gomock.Eq(uint64(10*1000)),
|
||||
// gomock.Any()).Times(2).
|
||||
// Return(http_agent.FakeHttpResponse(200, serviceJsonTest), nil)
|
||||
//
|
||||
// nc := nacos_client.NacosClient{}
|
||||
// nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
// nc.SetClientConfig(clientConfigTest)
|
||||
// nc.SetHttpAgent(mockIHttpAgent)
|
||||
// client, _ := NewNamingClient(&nc)
|
||||
// instances, err := client.SelectAllInstances(vo.SelectAllInstancesParam{
|
||||
// ServiceName: "DEMO",
|
||||
// Clusters: []string{"a"},
|
||||
// })
|
||||
// fmt.Println(utils.ToJsonString(instances))
|
||||
// assert.Nil(t, err)
|
||||
// assert.Equal(t, 2, len(instances))
|
||||
//}
|
||||
LastRefTime: 1528787794594, Clusters: "a"})
|
||||
|
||||
func TestNamingClient_SelectOneHealthyInstance_SameWeight(t *testing.T) {
|
||||
services := model.Service(model.Service{
|
||||
services := model.Service{
|
||||
Name: "DEFAULT_GROUP@@DEMO",
|
||||
CacheMillis: 1000,
|
||||
UseSpecifiedURL: false,
|
||||
Hosts: []model.Instance{
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.10-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.10",
|
||||
|
@ -462,8 +219,6 @@ func TestNamingClient_SelectOneHealthyInstance_SameWeight(t *testing.T) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.11-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.11",
|
||||
|
@ -475,8 +230,6 @@ func TestNamingClient_SelectOneHealthyInstance_SameWeight(t *testing.T) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.12-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.12",
|
||||
|
@ -488,8 +241,6 @@ func TestNamingClient_SelectOneHealthyInstance_SameWeight(t *testing.T) {
|
|||
Healthy: false,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.13-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.13",
|
||||
|
@ -501,8 +252,6 @@ func TestNamingClient_SelectOneHealthyInstance_SameWeight(t *testing.T) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.14-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.14",
|
||||
|
@ -515,65 +264,33 @@ func TestNamingClient_SelectOneHealthyInstance_SameWeight(t *testing.T) {
|
|||
},
|
||||
},
|
||||
Checksum: "3bbcf6dd1175203a8afdade0e77a27cd1528787794594",
|
||||
LastRefTime: 1528787794594, Env: "", Clusters: "a",
|
||||
Metadata: map[string]string(nil)})
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
instance1, err := client.selectOneHealthyInstances(services)
|
||||
fmt.Println(util.ToJsonString(instance1))
|
||||
LastRefTime: 1528787794594, Clusters: "a"}
|
||||
instance1, err := NewTestNamingClient().selectOneHealthyInstances(services)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, instance1)
|
||||
instance2, err := client.selectOneHealthyInstances(services)
|
||||
fmt.Println(util.ToJsonString(instance2))
|
||||
instance2, err := NewTestNamingClient().selectOneHealthyInstances(services)
|
||||
assert.Nil(t, err)
|
||||
assert.NotNil(t, instance2)
|
||||
//assert.NotEqual(t, instance1, instance2)
|
||||
}
|
||||
|
||||
func TestNamingClient_SelectOneHealthyInstance_Empty(t *testing.T) {
|
||||
services := model.Service(model.Service{
|
||||
services := model.Service{
|
||||
Name: "DEFAULT_GROUP@@DEMO",
|
||||
CacheMillis: 1000,
|
||||
UseSpecifiedURL: false,
|
||||
Hosts: []model.Instance{},
|
||||
Checksum: "3bbcf6dd1175203a8afdade0e77a27cd1528787794594",
|
||||
LastRefTime: 1528787794594, Env: "", Clusters: "a",
|
||||
Metadata: map[string]string(nil)})
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
instance, err := client.selectOneHealthyInstances(services)
|
||||
fmt.Println(util.ToJsonString(instance))
|
||||
LastRefTime: 1528787794594, Clusters: "a"}
|
||||
instance, err := NewTestNamingClient().selectOneHealthyInstances(services)
|
||||
assert.NotNil(t, err)
|
||||
assert.Nil(t, instance)
|
||||
}
|
||||
|
||||
func TestNamingClient_SelectInstances_Healthy(t *testing.T) {
|
||||
services := model.Service(model.Service{
|
||||
services := model.Service{
|
||||
Name: "DEFAULT_GROUP@@DEMO",
|
||||
CacheMillis: 1000,
|
||||
UseSpecifiedURL: false,
|
||||
Hosts: []model.Instance{
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.10-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.10",
|
||||
|
@ -585,8 +302,6 @@ func TestNamingClient_SelectInstances_Healthy(t *testing.T) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.11-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.11",
|
||||
|
@ -598,8 +313,6 @@ func TestNamingClient_SelectInstances_Healthy(t *testing.T) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.12-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.12",
|
||||
|
@ -611,8 +324,6 @@ func TestNamingClient_SelectInstances_Healthy(t *testing.T) {
|
|||
Healthy: false,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.13-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.13",
|
||||
|
@ -624,8 +335,6 @@ func TestNamingClient_SelectInstances_Healthy(t *testing.T) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.14-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.14",
|
||||
|
@ -638,34 +347,18 @@ func TestNamingClient_SelectInstances_Healthy(t *testing.T) {
|
|||
},
|
||||
},
|
||||
Checksum: "3bbcf6dd1175203a8afdade0e77a27cd1528787794594",
|
||||
LastRefTime: 1528787794594, Env: "", Clusters: "a",
|
||||
Metadata: map[string]string(nil)})
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
instances, err := client.selectInstances(services, true)
|
||||
fmt.Println(util.ToJsonString(instances))
|
||||
LastRefTime: 1528787794594, Clusters: "a"}
|
||||
instances, err := NewTestNamingClient().selectInstances(services, true)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, len(instances))
|
||||
}
|
||||
|
||||
func TestNamingClient_SelectInstances_Unhealthy(t *testing.T) {
|
||||
services := model.Service(model.Service{
|
||||
services := model.Service{
|
||||
Name: "DEFAULT_GROUP@@DEMO",
|
||||
CacheMillis: 1000,
|
||||
UseSpecifiedURL: false,
|
||||
Hosts: []model.Instance{
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.10-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.10",
|
||||
|
@ -677,8 +370,6 @@ func TestNamingClient_SelectInstances_Unhealthy(t *testing.T) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.11-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.11",
|
||||
|
@ -690,8 +381,6 @@ func TestNamingClient_SelectInstances_Unhealthy(t *testing.T) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.12-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.12",
|
||||
|
@ -703,8 +392,6 @@ func TestNamingClient_SelectInstances_Unhealthy(t *testing.T) {
|
|||
Healthy: false,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.13-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.13",
|
||||
|
@ -716,8 +403,6 @@ func TestNamingClient_SelectInstances_Unhealthy(t *testing.T) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.14-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.14",
|
||||
|
@ -730,103 +415,41 @@ func TestNamingClient_SelectInstances_Unhealthy(t *testing.T) {
|
|||
},
|
||||
},
|
||||
Checksum: "3bbcf6dd1175203a8afdade0e77a27cd1528787794594",
|
||||
LastRefTime: 1528787794594, Env: "", Clusters: "a",
|
||||
Metadata: map[string]string(nil)})
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
instances, err := client.selectInstances(services, false)
|
||||
fmt.Println(util.ToJsonString(instances))
|
||||
LastRefTime: 1528787794594, Clusters: "a"}
|
||||
instances, err := NewTestNamingClient().selectInstances(services, false)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, len(instances))
|
||||
}
|
||||
|
||||
func TestNamingClient_SelectInstances_Empty(t *testing.T) {
|
||||
services := model.Service(model.Service{
|
||||
services := model.Service{
|
||||
Name: "DEFAULT_GROUP@@DEMO",
|
||||
CacheMillis: 1000,
|
||||
UseSpecifiedURL: false,
|
||||
Hosts: []model.Instance{},
|
||||
Checksum: "3bbcf6dd1175203a8afdade0e77a27cd1528787794594",
|
||||
LastRefTime: 1528787794594, Env: "", Clusters: "a",
|
||||
Metadata: map[string]string(nil)})
|
||||
ctrl := gomock.NewController(t)
|
||||
defer func() {
|
||||
ctrl.Finish()
|
||||
}()
|
||||
mockIHttpAgent := mock.NewMockIHttpAgent(ctrl)
|
||||
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(mockIHttpAgent)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
instances, err := client.selectInstances(services, false)
|
||||
fmt.Println(util.ToJsonString(instances))
|
||||
LastRefTime: 1528787794594, Clusters: "a"}
|
||||
instances, err := NewTestNamingClient().selectInstances(services, false)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, 0, len(instances))
|
||||
}
|
||||
|
||||
func TestNamingClient_GetAllServicesInfo(t *testing.T) {
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
nc.SetHttpAgent(&http_agent.HttpAgent{})
|
||||
client, _ := NewNamingClient(&nc)
|
||||
reslut, err := client.GetAllServicesInfo(vo.GetAllServiceInfoParam{
|
||||
result, err := NewTestNamingClient().GetAllServicesInfo(vo.GetAllServiceInfoParam{
|
||||
GroupName: "DEFAULT_GROUP",
|
||||
PageNo: 1,
|
||||
PageSize: 20,
|
||||
})
|
||||
|
||||
assert.NotNil(t, reslut.Doms)
|
||||
assert.NotNil(t, result.Doms)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestNamingClient_selectOneHealthyInstanceResult(t *testing.T) {
|
||||
services := model.Service(model.Service{
|
||||
Name: "DEFAULT_GROUP@@DEMO",
|
||||
Hosts: []model.Instance{
|
||||
{
|
||||
Ip: "127.0.0.1",
|
||||
Weight: 1,
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Ip: "127.0.0.2",
|
||||
Weight: 9,
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
},
|
||||
}})
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
for i := 0; i < 10; i++ {
|
||||
i, _ := client.selectOneHealthyInstances(services)
|
||||
fmt.Println(i.Ip)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNamingClient_SelectOneHealthyInstances(b *testing.B) {
|
||||
services := model.Service(model.Service{
|
||||
services := model.Service{
|
||||
Name: "DEFAULT_GROUP@@DEMO",
|
||||
CacheMillis: 1000,
|
||||
UseSpecifiedURL: false,
|
||||
Hosts: []model.Instance{
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.10-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.10",
|
||||
|
@ -838,8 +461,6 @@ func BenchmarkNamingClient_SelectOneHealthyInstances(b *testing.B) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.11-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.11",
|
||||
|
@ -851,8 +472,6 @@ func BenchmarkNamingClient_SelectOneHealthyInstances(b *testing.B) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.12-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.12",
|
||||
|
@ -864,8 +483,6 @@ func BenchmarkNamingClient_SelectOneHealthyInstances(b *testing.B) {
|
|||
Healthy: false,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.13-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.13",
|
||||
|
@ -877,8 +494,6 @@ func BenchmarkNamingClient_SelectOneHealthyInstances(b *testing.B) {
|
|||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.14-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.14",
|
||||
|
@ -891,178 +506,11 @@ func BenchmarkNamingClient_SelectOneHealthyInstances(b *testing.B) {
|
|||
},
|
||||
},
|
||||
Checksum: "3bbcf6dd1175203a8afdade0e77a27cd1528787794594",
|
||||
LastRefTime: 1528787794594, Env: "", Clusters: "a",
|
||||
Metadata: map[string]string(nil)})
|
||||
nc := nacos_client.NacosClient{}
|
||||
nc.SetServerConfig([]constant.ServerConfig{serverConfigTest})
|
||||
nc.SetClientConfig(clientConfigTest)
|
||||
client, _ := NewNamingClient(&nc)
|
||||
LastRefTime: 1528787794594, Clusters: "a"}
|
||||
client := NewTestNamingClient()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
client.selectOneHealthyInstances(services)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func BenchmarkNamingClient_Random(b *testing.B) {
|
||||
services := model.Service(model.Service{
|
||||
Name: "DEFAULT_GROUP@@DEMO",
|
||||
CacheMillis: 1000,
|
||||
UseSpecifiedURL: false,
|
||||
Hosts: []model.Instance{
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.10-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.10",
|
||||
Weight: 10,
|
||||
Metadata: map[string]string{},
|
||||
ClusterName: "a",
|
||||
ServiceName: "DEMO1",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.11-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.11",
|
||||
Weight: 9,
|
||||
Metadata: map[string]string{},
|
||||
ClusterName: "a",
|
||||
ServiceName: "DEMO",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.12-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.12",
|
||||
Weight: 8,
|
||||
Metadata: map[string]string{},
|
||||
ClusterName: "a",
|
||||
ServiceName: "DEMO",
|
||||
Enable: true,
|
||||
Healthy: false,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.13-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.13",
|
||||
Weight: 8,
|
||||
Metadata: map[string]string{},
|
||||
ClusterName: "a",
|
||||
ServiceName: "DEMO",
|
||||
Enable: false,
|
||||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.14-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.14",
|
||||
Weight: 7,
|
||||
Metadata: map[string]string{},
|
||||
ClusterName: "a",
|
||||
ServiceName: "DEMO",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
},
|
||||
},
|
||||
Checksum: "3bbcf6dd1175203a8afdade0e77a27cd1528787794594",
|
||||
LastRefTime: 1528787794594, Env: "", Clusters: "a",
|
||||
Metadata: map[string]string(nil)})
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
random(services.Hosts, 10)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNamingClient_ChooserPick(b *testing.B) {
|
||||
services := model.Service(model.Service{
|
||||
Name: "DEFAULT_GROUP@@DEMO",
|
||||
CacheMillis: 1000,
|
||||
UseSpecifiedURL: false,
|
||||
Hosts: []model.Instance{
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.10-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.10",
|
||||
Weight: 10,
|
||||
Metadata: map[string]string{},
|
||||
ClusterName: "a",
|
||||
ServiceName: "DEMO1",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.11-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.11",
|
||||
Weight: 9,
|
||||
Metadata: map[string]string{},
|
||||
ClusterName: "a",
|
||||
ServiceName: "DEMO",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.12-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.12",
|
||||
Weight: 8,
|
||||
Metadata: map[string]string{},
|
||||
ClusterName: "a",
|
||||
ServiceName: "DEMO",
|
||||
Enable: true,
|
||||
Healthy: false,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.13-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.13",
|
||||
Weight: 7,
|
||||
Metadata: map[string]string{},
|
||||
ClusterName: "a",
|
||||
ServiceName: "DEMO",
|
||||
Enable: false,
|
||||
Healthy: true,
|
||||
},
|
||||
{
|
||||
Valid: true,
|
||||
Marked: false,
|
||||
InstanceId: "10.10.10.14-80-a-DEMO",
|
||||
Port: 80,
|
||||
Ip: "10.10.10.14",
|
||||
Weight: 6,
|
||||
Metadata: map[string]string{},
|
||||
ClusterName: "a",
|
||||
ServiceName: "DEMO",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
},
|
||||
},
|
||||
Checksum: "3bbcf6dd1175203a8afdade0e77a27cd1528787794594",
|
||||
LastRefTime: 1528787794594, Env: "", Clusters: "a",
|
||||
Metadata: map[string]string(nil)})
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
chooser := newChooser(services.Hosts)
|
||||
chooser.pick()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* 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 naming_grpc
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"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/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
type ConnectionEventListener struct {
|
||||
clientProxy *NamingGrpcProxy
|
||||
registeredInstanceCached cache.ConcurrentMap
|
||||
subscribes cache.ConcurrentMap
|
||||
}
|
||||
|
||||
func NewConnectionEventListener(clientProxy *NamingGrpcProxy) *ConnectionEventListener {
|
||||
return &ConnectionEventListener{
|
||||
clientProxy: clientProxy,
|
||||
registeredInstanceCached: cache.NewConcurrentMap(),
|
||||
subscribes: cache.NewConcurrentMap(),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) OnConnected() {
|
||||
c.redoSubscribe()
|
||||
c.redoRegisterEachService()
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) OnDisConnect() {
|
||||
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) redoSubscribe() {
|
||||
for _, key := range c.subscribes.Keys() {
|
||||
info := strings.Split(key, constant.SERVICE_INFO_SPLITER)
|
||||
var err error
|
||||
if len(info) > 2 {
|
||||
_, err = c.clientProxy.Subscribe(info[0], info[1], info[2])
|
||||
} else {
|
||||
_, err = c.clientProxy.Subscribe(info[0], info[1], "")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
logger.Warnf("redo subscribe service:%s faild:%+v", info[0], err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) redoRegisterEachService() {
|
||||
for k, v := range c.registeredInstanceCached.Items() {
|
||||
info := strings.Split(k, constant.SERVICE_INFO_SPLITER)
|
||||
serviceName := info[0]
|
||||
groupName := info[1]
|
||||
instances, ok := v.([]model.Instance)
|
||||
if !ok {
|
||||
logger.Warnf("redo register service:%s faild,instances type not is []model.instance", info[0])
|
||||
}
|
||||
for _, instance := range instances {
|
||||
_, err := c.clientProxy.RegisterInstance(serviceName, groupName, instance)
|
||||
if err != nil {
|
||||
logger.Warnf("redo register service:%s groupName:%s faild:%s", info[0], info[1], err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) CacheInstanceForRedo(serviceName, groupName string, instance model.Instance) {
|
||||
var flag bool
|
||||
key := util.GetGroupName(serviceName, groupName)
|
||||
instances, ok := c.registeredInstanceCached.Get(key)
|
||||
if !ok {
|
||||
instances = []model.Instance{instance}
|
||||
c.registeredInstanceCached.Set(key, instances)
|
||||
} else {
|
||||
instances, ok := instances.([]model.Instance)
|
||||
if !ok {
|
||||
c.registeredInstanceCached.Remove(key)
|
||||
logger.Warn("cacheInstanceForRedo faild,instances type not is []model.instance")
|
||||
return
|
||||
}
|
||||
for _, v := range instances {
|
||||
if reflect.DeepEqual(v, instance) {
|
||||
flag = false
|
||||
}
|
||||
}
|
||||
if flag {
|
||||
instances = append(instances, instance)
|
||||
c.registeredInstanceCached.Set(key, instances)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) RemoveInstanceForRedo(serviceName, groupName string, instance model.Instance) {
|
||||
key := util.GetGroupName(serviceName, groupName)
|
||||
instances, ok := c.registeredInstanceCached.Get(key)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
instanceSlice := instances.([]model.Instance)
|
||||
instancesNew := make([]model.Instance, 0, len(instanceSlice))
|
||||
for _, v := range instanceSlice {
|
||||
if !reflect.DeepEqual(v, instance) {
|
||||
instancesNew = append(instancesNew, v)
|
||||
}
|
||||
}
|
||||
c.registeredInstanceCached.Set(key, instancesNew)
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) CacheSubscriberForRedo(fullServiceName, clusters string) {
|
||||
key := util.GetServiceCacheKey(fullServiceName, clusters)
|
||||
if _, ok := c.subscribes.Get(key); !ok {
|
||||
c.subscribes.Set(key, struct{}{})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c *ConnectionEventListener) RemoveSubscriberForRedo(fullServiceName, clusters string) {
|
||||
c.subscribes.Remove(util.GetServiceCacheKey(fullServiceName, clusters))
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* 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 naming_grpc
|
||||
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"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/inner/uuid"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
type NamingGrpcProxy struct {
|
||||
clientConfig constant.ClientConfig
|
||||
nacosServer *nacos_server.NacosServer
|
||||
rpcClient rpc.IRpcClient
|
||||
eventListener *ConnectionEventListener
|
||||
serviceInfoHolder *naming_cache.ServiceInfoHolder
|
||||
}
|
||||
|
||||
func NewNamingGrpcProxy(clientCfg constant.ClientConfig, nacosServer *nacos_server.NacosServer,
|
||||
serviceInfoHolder *naming_cache.ServiceInfoHolder) (*NamingGrpcProxy, error) {
|
||||
srvProxy := NamingGrpcProxy{
|
||||
clientConfig: clientCfg,
|
||||
nacosServer: nacosServer,
|
||||
serviceInfoHolder: serviceInfoHolder,
|
||||
}
|
||||
|
||||
uid, err := uuid.NewV4()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labels := map[string]string{
|
||||
constant.LABEL_SOURCE: constant.LABEL_SOURCE_SDK,
|
||||
constant.LABEL_MODULE: constant.LABEL_MODULE_NAMING,
|
||||
}
|
||||
|
||||
iRpcClient, err := rpc.CreateClient(uid.String(), rpc.GRPC, labels, srvProxy.nacosServer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
srvProxy.rpcClient = iRpcClient
|
||||
|
||||
rpcClient := srvProxy.rpcClient.GetRpcClient()
|
||||
rpcClient.Start()
|
||||
|
||||
rpcClient.RegisterServerRequestHandler(func() rpc_request.IRequest {
|
||||
return &rpc_request.NotifySubscriberRequest{NamingRequest: &rpc_request.NamingRequest{}}
|
||||
}, &rpc.NamingPushRequestHandler{ServiceInfoHolder: serviceInfoHolder})
|
||||
|
||||
srvProxy.eventListener = NewConnectionEventListener(&srvProxy)
|
||||
rpcClient.RegisterConnectionListener(srvProxy.eventListener)
|
||||
|
||||
return &srvProxy, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingGrpcProxy) requestToServer(request rpc_request.IRequest) (rpc_response.IResponse, error) {
|
||||
proxy.nacosServer.InjectSecurityInfo(request.GetHeaders())
|
||||
//todo ak/sk
|
||||
return proxy.rpcClient.GetRpcClient().Request(request, int64(proxy.clientConfig.TimeoutMs))
|
||||
}
|
||||
|
||||
func (proxy *NamingGrpcProxy) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
logger.Infof("register instance namespaceId:<%s>,serviceName:<%s> with instance:<%s>",
|
||||
proxy.clientConfig.NamespaceId, serviceName, util.ToJsonString(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
|
||||
}
|
||||
|
||||
func (proxy *NamingGrpcProxy) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
logger.Infof("deregister instance namespaceId:<%s>,serviceName:<%s> with instance:<%s:%d@%s>",
|
||||
proxy.clientConfig.NamespaceId, serviceName, instance.Ip, instance.Port, instance.ClusterName)
|
||||
instanceRequest := rpc_request.NewInstanceRequest(proxy.clientConfig.NamespaceId, serviceName, groupName, "deregisterInstance", instance)
|
||||
response, err := proxy.requestToServer(instanceRequest)
|
||||
proxy.eventListener.RemoveInstanceForRedo(serviceName, groupName, instance)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return response.IsSuccess(), err
|
||||
}
|
||||
|
||||
func (proxy *NamingGrpcProxy) GetServiceList(pageNo uint32, pageSize uint32, groupName string, selector *model.ExpressionSelector) (model.ServiceList, error) {
|
||||
var selectorStr string
|
||||
if selector != nil {
|
||||
switch selector.Type {
|
||||
case "label":
|
||||
selectorStr = util.ToJsonString(selector)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
response, err := proxy.requestToServer(rpc_request.NewServiceListRequest(proxy.clientConfig.NamespaceId, "",
|
||||
groupName, int(pageNo), int(pageSize), selectorStr))
|
||||
if err != nil {
|
||||
return model.ServiceList{}, err
|
||||
}
|
||||
serviceListResponse := response.(*rpc_response.ServiceListResponse)
|
||||
return model.ServiceList{
|
||||
Count: int64(serviceListResponse.Count),
|
||||
Doms: serviceListResponse.ServiceNames,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingGrpcProxy) ServerHealthy() bool {
|
||||
return proxy.rpcClient.GetRpcClient().IsRunning()
|
||||
}
|
||||
|
||||
func (proxy *NamingGrpcProxy) QueryInstancesOfService(serviceName, groupName, clusters string, udpPort int, healthyOnly bool) (*model.Service, error) {
|
||||
response, err := proxy.requestToServer(rpc_request.NewServiceQueryRequest(proxy.clientConfig.NamespaceId, serviceName, groupName, clusters,
|
||||
healthyOnly, udpPort))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
queryServiceResponse := response.(*rpc_response.QueryServiceResponse)
|
||||
return &queryServiceResponse.ServiceInfo, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingGrpcProxy) Subscribe(serviceName, groupName string, clusters string) (model.Service, error) {
|
||||
response, err := proxy.requestToServer(rpc_request.NewSubscribeServiceRequest(proxy.clientConfig.NamespaceId, serviceName,
|
||||
groupName, clusters, true))
|
||||
if err != nil {
|
||||
return model.Service{}, err
|
||||
}
|
||||
proxy.eventListener.CacheSubscriberForRedo(util.GetGroupName(serviceName, groupName), clusters)
|
||||
subscribeServiceResponse := response.(*rpc_response.SubscribeServiceResponse)
|
||||
return subscribeServiceResponse.ServiceInfo, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingGrpcProxy) Unsubscribe(serviceName, groupName, clusters string) {
|
||||
proxy.requestToServer(rpc_request.NewSubscribeServiceRequest(proxy.clientConfig.NamespaceId, serviceName, groupName,
|
||||
clusters, false))
|
||||
proxy.eventListener.RemoveSubscriberForRedo(util.GetGroupName(serviceName, groupName), clusters)
|
||||
}
|
|
@ -14,40 +14,42 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package naming_client
|
||||
package naming_http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/buger/jsonparser"
|
||||
"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/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/nacos_server"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
nsema "github.com/toolkits/concurrent/semaphore"
|
||||
)
|
||||
|
||||
type BeatReactor struct {
|
||||
beatMap cache.ConcurrentMap
|
||||
serviceProxy NamingProxy
|
||||
clientBeatInterval int64
|
||||
nacosServer *nacos_server.NacosServer
|
||||
beatThreadCount int
|
||||
beatThreadSemaphore *nsema.Semaphore
|
||||
beatRecordMap cache.ConcurrentMap
|
||||
clientCfg constant.ClientConfig
|
||||
}
|
||||
|
||||
const Default_Beat_Thread_Num = 20
|
||||
|
||||
func NewBeatReactor(serviceProxy NamingProxy, clientBeatInterval int64) BeatReactor {
|
||||
func NewBeatReactor(clientCfg constant.ClientConfig, nacosServer *nacos_server.NacosServer) BeatReactor {
|
||||
br := BeatReactor{}
|
||||
if clientBeatInterval <= 0 {
|
||||
clientBeatInterval = 5 * 1000
|
||||
}
|
||||
br.beatMap = cache.NewConcurrentMap()
|
||||
br.serviceProxy = serviceProxy
|
||||
br.clientBeatInterval = clientBeatInterval
|
||||
br.nacosServer = nacosServer
|
||||
br.clientCfg = clientCfg
|
||||
br.beatThreadCount = Default_Beat_Thread_Num
|
||||
br.beatRecordMap = cache.NewConcurrentMap()
|
||||
br.beatThreadSemaphore = nsema.NewSemaphore(br.beatThreadCount)
|
||||
|
@ -87,7 +89,7 @@ func (br *BeatReactor) sendInstanceBeat(k string, beatInfo *model.BeatInfo) {
|
|||
}
|
||||
|
||||
//进行心跳通信
|
||||
beatInterval, err := br.serviceProxy.SendBeat(*beatInfo)
|
||||
beatInterval, err := br.SendBeat(*beatInfo)
|
||||
if err != nil {
|
||||
logger.Errorf("beat to server return error:%+v", err)
|
||||
br.beatThreadSemaphore.Release()
|
||||
|
@ -106,3 +108,26 @@ func (br *BeatReactor) sendInstanceBeat(k string, beatInfo *model.BeatInfo) {
|
|||
<-t.C
|
||||
}
|
||||
}
|
||||
|
||||
func (br *BeatReactor) SendBeat(info model.BeatInfo) (int64, error) {
|
||||
logger.Infof("namespaceId:<%s> sending beat to server:<%s>",
|
||||
br.clientCfg.NamespaceId, util.ToJsonString(info))
|
||||
params := map[string]string{}
|
||||
params["namespaceId"] = br.clientCfg.NamespaceId
|
||||
params["serviceName"] = info.ServiceName
|
||||
params["beat"] = util.ToJsonString(info)
|
||||
api := constant.SERVICE_BASE_PATH + "/instance/beat"
|
||||
result, err := br.nacosServer.ReqApi(api, params, http.MethodPut)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if result != "" {
|
||||
interVal, err := jsonparser.GetInt([]byte(result), "clientBeatInterval")
|
||||
if err != nil {
|
||||
return 0, errors.New(fmt.Sprintf("namespaceId:<%s> sending beat to server:<%s> get 'clientBeatInterval' from <%s> error:<%+v>", br.clientCfg.NamespaceId, util.ToJsonString(info), result, err))
|
||||
} else {
|
||||
return interVal, nil
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}
|
|
@ -14,20 +14,20 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package naming_client
|
||||
package naming_http
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/nacos_server"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/nacos_server"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBeatReactor_AddBeatInfo(t *testing.T) {
|
||||
br := NewBeatReactor(NamingProxy{nacosServer: &nacos_server.NacosServer{}}, 5000)
|
||||
br := NewBeatReactor(constant.ClientConfig{}, &nacos_server.NacosServer{})
|
||||
serviceName := "Test"
|
||||
groupName := "public"
|
||||
beatInfo := model.BeatInfo{
|
||||
|
@ -46,7 +46,7 @@ func TestBeatReactor_AddBeatInfo(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestBeatReactor_RemoveBeatInfo(t *testing.T) {
|
||||
br := NewBeatReactor(NamingProxy{nacosServer: &nacos_server.NacosServer{}}, 5000)
|
||||
br := NewBeatReactor(constant.ClientConfig{}, &nacos_server.NacosServer{})
|
||||
serviceName := "Test"
|
||||
groupName := "public"
|
||||
beatInfo1 := model.BeatInfo{
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* 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 naming_http
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/buger/jsonparser"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/nacos_server"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
type NamingHttpProxy struct {
|
||||
clientConfig constant.ClientConfig
|
||||
nacosServer *nacos_server.NacosServer
|
||||
beatReactor BeatReactor
|
||||
serviceInfoHolder *naming_cache.ServiceInfoHolder
|
||||
}
|
||||
|
||||
func NewNamingHttpProxy(clientCfg constant.ClientConfig, nacosServer *nacos_server.NacosServer,
|
||||
serviceInfoHolder *naming_cache.ServiceInfoHolder) (*NamingHttpProxy, error) {
|
||||
srvProxy := NamingHttpProxy{
|
||||
clientConfig: clientCfg,
|
||||
nacosServer: nacosServer,
|
||||
serviceInfoHolder: serviceInfoHolder,
|
||||
}
|
||||
|
||||
srvProxy.beatReactor = NewBeatReactor(clientCfg, nacosServer)
|
||||
|
||||
NewPushReceiver(serviceInfoHolder).startServer()
|
||||
|
||||
return &srvProxy, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingHttpProxy) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
logger.Infof("register instance namespaceId:<%s>,serviceName:<%s> with instance:<%s>",
|
||||
proxy.clientConfig.NamespaceId, serviceName, util.ToJsonString(instance))
|
||||
serviceName = util.GetGroupName(serviceName, groupName)
|
||||
params := map[string]string{}
|
||||
params["namespaceId"] = proxy.clientConfig.NamespaceId
|
||||
params["serviceName"] = serviceName
|
||||
params["groupName"] = groupName
|
||||
params["app"] = proxy.clientConfig.AppName
|
||||
params["clusterName"] = instance.ClusterName
|
||||
params["ip"] = instance.Ip
|
||||
params["port"] = strconv.Itoa(int(instance.Port))
|
||||
params["weight"] = strconv.FormatFloat(instance.Weight, 'f', -1, 64)
|
||||
params["enable"] = strconv.FormatBool(instance.Enable)
|
||||
params["healthy"] = strconv.FormatBool(instance.Healthy)
|
||||
params["metadata"] = util.ToJsonString(instance.Metadata)
|
||||
params["ephemeral"] = strconv.FormatBool(instance.Ephemeral)
|
||||
_, err := proxy.nacosServer.ReqApi(constant.SERVICE_PATH, params, http.MethodPost)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if instance.Ephemeral {
|
||||
beatInfo := model.BeatInfo{
|
||||
Ip: instance.Ip,
|
||||
Port: instance.Port,
|
||||
Metadata: instance.Metadata,
|
||||
ServiceName: util.GetGroupName(serviceName, groupName),
|
||||
Cluster: instance.ClusterName,
|
||||
Weight: instance.Weight,
|
||||
Period: util.GetDurationWithDefault(instance.Metadata, constant.HEART_BEAT_INTERVAL, time.Second*5),
|
||||
State: model.StateRunning,
|
||||
}
|
||||
proxy.beatReactor.AddBeatInfo(util.GetGroupName(serviceName, groupName), beatInfo)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingHttpProxy) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
serviceName = util.GetGroupName(serviceName, groupName)
|
||||
logger.Infof("deregister instance namespaceId:<%s>,serviceName:<%s> with instance:<%s:%d@%s>",
|
||||
proxy.clientConfig.NamespaceId, serviceName, instance.Ip, instance.Port, instance.ClusterName)
|
||||
proxy.beatReactor.RemoveBeatInfo(serviceName, instance.Ip, instance.Port)
|
||||
params := map[string]string{}
|
||||
params["namespaceId"] = proxy.clientConfig.NamespaceId
|
||||
params["serviceName"] = serviceName
|
||||
params["clusterName"] = instance.ClusterName
|
||||
params["ip"] = instance.Ip
|
||||
params["port"] = strconv.Itoa(int(instance.Port))
|
||||
params["ephemeral"] = strconv.FormatBool(instance.Ephemeral)
|
||||
_, err := proxy.nacosServer.ReqApi(constant.SERVICE_PATH, params, http.MethodDelete)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingHttpProxy) GetServiceList(pageNo uint32, pageSize uint32, groupName string, selector *model.ExpressionSelector) (model.ServiceList, error) {
|
||||
params := map[string]string{}
|
||||
params["namespaceId"] = proxy.clientConfig.NamespaceId
|
||||
params["groupName"] = groupName
|
||||
params["pageNo"] = strconv.Itoa(int(pageNo))
|
||||
params["pageSize"] = strconv.Itoa(int(pageSize))
|
||||
|
||||
if selector != nil {
|
||||
switch selector.Type {
|
||||
case "label":
|
||||
params["selector"] = util.ToJsonString(selector)
|
||||
break
|
||||
default:
|
||||
break
|
||||
|
||||
}
|
||||
}
|
||||
serviceList := model.ServiceList{}
|
||||
|
||||
api := constant.SERVICE_BASE_PATH + "/service/list"
|
||||
result, err := proxy.nacosServer.ReqApi(api, params, http.MethodGet)
|
||||
if err != nil {
|
||||
return serviceList, err
|
||||
}
|
||||
if result == "" {
|
||||
return serviceList, errors.New("request server return empty")
|
||||
}
|
||||
|
||||
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>", proxy.clientConfig.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> ", proxy.clientConfig.NamespaceId, pageNo, pageSize, util.ToJsonString(selector), groupName, result, err))
|
||||
}
|
||||
serviceList.Count = count
|
||||
serviceList.Doms = doms
|
||||
return serviceList, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingHttpProxy) ServerHealthy() bool {
|
||||
api := constant.SERVICE_BASE_PATH + "/operator/metrics"
|
||||
result, err := proxy.nacosServer.ReqApi(api, map[string]string{}, http.MethodGet)
|
||||
if err != nil {
|
||||
logger.Errorf("namespaceId:[%s] sending server healthy failed!,result:%s error:%+v", proxy.clientConfig.NamespaceId, result, err)
|
||||
return false
|
||||
}
|
||||
if result != "" {
|
||||
status, err := jsonparser.GetString([]byte(result), "status")
|
||||
if err != nil {
|
||||
logger.Errorf("namespaceId:[%s] sending server healthy failed!,result:%s error:%+v", proxy.clientConfig.NamespaceId, result, err)
|
||||
} else {
|
||||
return status == "UP"
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (proxy *NamingHttpProxy) QueryInstancesOfService(serviceName, groupName, clusters string, udpPort int, healthyOnly bool) (*model.Service, error) {
|
||||
param := make(map[string]string)
|
||||
param["namespaceId"] = proxy.clientConfig.NamespaceId
|
||||
param["serviceName"] = util.GetGroupName(serviceName, groupName)
|
||||
param["app"] = proxy.clientConfig.AppName
|
||||
param["clusters"] = clusters
|
||||
param["udpPort"] = strconv.Itoa(udpPort)
|
||||
param["healthyOnly"] = strconv.FormatBool(healthyOnly)
|
||||
param["clientIP"] = util.LocalIP()
|
||||
api := constant.SERVICE_PATH + "/list"
|
||||
result, err := proxy.nacosServer.ReqApi(api, param, http.MethodGet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return util.JsonToService(result), nil
|
||||
|
||||
}
|
||||
|
||||
func (proxy *NamingHttpProxy) Subscribe(serviceName, groupName, clusters string) (model.Service, error) {
|
||||
return model.Service{}, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingHttpProxy) Unsubscribe(serviceName, groupName, clusters string) {
|
||||
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package naming_client
|
||||
package naming_http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -26,14 +26,15 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
type PushReceiver struct {
|
||||
port int
|
||||
host string
|
||||
hostReactor *HostReactor
|
||||
serviceInfoHolder *naming_cache.ServiceInfoHolder
|
||||
}
|
||||
|
||||
type PushData struct {
|
||||
|
@ -46,9 +47,9 @@ var (
|
|||
GZIP_MAGIC = []byte("\x1F\x8B")
|
||||
)
|
||||
|
||||
func NewPushReceiver(hostReactor *HostReactor) *PushReceiver {
|
||||
func NewPushReceiver(serviceInfoHolder *naming_cache.ServiceInfoHolder) *PushReceiver {
|
||||
pr := PushReceiver{
|
||||
hostReactor: hostReactor,
|
||||
serviceInfoHolder: serviceInfoHolder,
|
||||
}
|
||||
pr.startServer()
|
||||
return &pr
|
||||
|
@ -118,7 +119,7 @@ func (us *PushReceiver) handleClient(conn *net.UDPConn) {
|
|||
ack := make(map[string]string)
|
||||
|
||||
if pushData.PushType == "dom" || pushData.PushType == "service" {
|
||||
us.hostReactor.ProcessServiceJson(pushData.Data)
|
||||
us.serviceInfoHolder.ProcessServiceJson(pushData.Data)
|
||||
|
||||
ack["type"] = "push-ack"
|
||||
ack["lastRefTime"] = strconv.FormatInt(pushData.LastRefTime, 10)
|
||||
|
@ -127,7 +128,7 @@ func (us *PushReceiver) handleClient(conn *net.UDPConn) {
|
|||
} else if pushData.PushType == "dump" {
|
||||
ack["type"] = "dump-ack"
|
||||
ack["lastRefTime"] = strconv.FormatInt(pushData.LastRefTime, 10)
|
||||
ack["data"] = util.ToJsonString(us.hostReactor.serviceInfoMap)
|
||||
ack["data"] = util.ToJsonString(us.serviceInfoHolder.ServiceInfoMap)
|
||||
} else {
|
||||
ack["type"] = "unknow-ack"
|
||||
ack["lastRefTime"] = strconv.FormatInt(pushData.LastRefTime, 10)
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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 naming_client
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"sort"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
)
|
||||
|
||||
type Chooser struct {
|
||||
data []model.Instance
|
||||
totals []int
|
||||
max int
|
||||
}
|
||||
|
||||
type instance []model.Instance
|
||||
|
||||
func (a instance) Len() int {
|
||||
return len(a)
|
||||
}
|
||||
|
||||
func (a instance) Swap(i, j int) {
|
||||
a[i], a[j] = a[j], a[i]
|
||||
}
|
||||
|
||||
func (a instance) Less(i, j int) bool {
|
||||
return a[i].Weight < a[j].Weight
|
||||
}
|
||||
|
||||
// NewChooser initializes a new Chooser for picking from the provided Choices.
|
||||
func newChooser(instances []model.Instance) Chooser {
|
||||
sort.Sort(instance(instances))
|
||||
totals := make([]int, len(instances))
|
||||
runningTotal := 0
|
||||
for i, c := range instances {
|
||||
runningTotal += int(c.Weight)
|
||||
totals[i] = runningTotal
|
||||
}
|
||||
return Chooser{data: instances, totals: totals, max: runningTotal}
|
||||
}
|
||||
|
||||
func (chs Chooser) pick() model.Instance {
|
||||
r := rand.Intn(chs.max) + 1
|
||||
i := sort.SearchInts(chs.totals, r)
|
||||
return chs.data[i]
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package naming_client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/buger/jsonparser"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/nacos_server"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
)
|
||||
|
||||
type NamingProxy struct {
|
||||
clientConfig constant.ClientConfig
|
||||
nacosServer *nacos_server.NacosServer
|
||||
}
|
||||
|
||||
func NewNamingProxy(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig, httpAgent http_agent.IHttpAgent) (NamingProxy, error) {
|
||||
srvProxy := NamingProxy{}
|
||||
srvProxy.clientConfig = clientCfg
|
||||
|
||||
var err error
|
||||
srvProxy.nacosServer, err = nacos_server.NewNacosServer(serverCfgs, clientCfg, httpAgent, clientCfg.TimeoutMs, clientCfg.Endpoint)
|
||||
if err != nil {
|
||||
return srvProxy, err
|
||||
}
|
||||
|
||||
return srvProxy, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingProxy) RegisterInstance(serviceName string, groupName string, instance model.Instance) (string, error) {
|
||||
logger.Infof("register instance namespaceId:<%s>,serviceName:<%s> with instance:<%s>",
|
||||
proxy.clientConfig.NamespaceId, serviceName, util.ToJsonString(instance))
|
||||
params := map[string]string{}
|
||||
params["namespaceId"] = proxy.clientConfig.NamespaceId
|
||||
params["serviceName"] = serviceName
|
||||
params["groupName"] = groupName
|
||||
params["app"] = proxy.clientConfig.AppName
|
||||
params["clusterName"] = instance.ClusterName
|
||||
params["ip"] = instance.Ip
|
||||
params["port"] = strconv.Itoa(int(instance.Port))
|
||||
params["weight"] = strconv.FormatFloat(instance.Weight, 'f', -1, 64)
|
||||
params["enable"] = strconv.FormatBool(instance.Enable)
|
||||
params["healthy"] = strconv.FormatBool(instance.Healthy)
|
||||
params["metadata"] = util.ToJsonString(instance.Metadata)
|
||||
params["ephemeral"] = strconv.FormatBool(instance.Ephemeral)
|
||||
return proxy.nacosServer.ReqApi(constant.SERVICE_PATH, params, http.MethodPost)
|
||||
}
|
||||
|
||||
func (proxy *NamingProxy) DeregisterInstance(serviceName string, ip string, port uint64, clusterName string, ephemeral bool) (string, error) {
|
||||
logger.Infof("deregister instance namespaceId:<%s>,serviceName:<%s> with instance:<%s:%d@%s>",
|
||||
proxy.clientConfig.NamespaceId, serviceName, ip, port, clusterName)
|
||||
params := map[string]string{}
|
||||
params["namespaceId"] = proxy.clientConfig.NamespaceId
|
||||
params["serviceName"] = serviceName
|
||||
params["clusterName"] = clusterName
|
||||
params["ip"] = ip
|
||||
params["port"] = strconv.Itoa(int(port))
|
||||
params["ephemeral"] = strconv.FormatBool(ephemeral)
|
||||
return proxy.nacosServer.ReqApi(constant.SERVICE_PATH, params, http.MethodDelete)
|
||||
}
|
||||
|
||||
func (proxy *NamingProxy) SendBeat(info model.BeatInfo) (int64, error) {
|
||||
logger.Infof("namespaceId:<%s> sending beat to server:<%s>",
|
||||
proxy.clientConfig.NamespaceId, util.ToJsonString(info))
|
||||
params := map[string]string{}
|
||||
params["namespaceId"] = proxy.clientConfig.NamespaceId
|
||||
params["serviceName"] = info.ServiceName
|
||||
params["beat"] = util.ToJsonString(info)
|
||||
api := constant.SERVICE_BASE_PATH + "/instance/beat"
|
||||
result, err := proxy.nacosServer.ReqApi(api, params, http.MethodPut)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if result != "" {
|
||||
interVal, err := jsonparser.GetInt([]byte(result), "clientBeatInterval")
|
||||
if err != nil {
|
||||
return 0, errors.New(fmt.Sprintf("namespaceId:<%s> sending beat to server:<%s> get 'clientBeatInterval' from <%s> error:<%+v>", proxy.clientConfig.NamespaceId, util.ToJsonString(info), result, err))
|
||||
} else {
|
||||
return interVal, nil
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
|
||||
}
|
||||
|
||||
func (proxy *NamingProxy) GetServiceList(pageNo int, pageSize int, groupName string, selector *model.ExpressionSelector) (*model.ServiceList, error) {
|
||||
params := map[string]string{}
|
||||
params["namespaceId"] = proxy.clientConfig.NamespaceId
|
||||
params["groupName"] = groupName
|
||||
params["pageNo"] = strconv.Itoa(pageNo)
|
||||
params["pageSize"] = strconv.Itoa(pageSize)
|
||||
|
||||
if selector != nil {
|
||||
switch selector.Type {
|
||||
case "label":
|
||||
params["selector"] = util.ToJsonString(selector)
|
||||
break
|
||||
default:
|
||||
break
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
api := constant.SERVICE_BASE_PATH + "/service/list"
|
||||
result, err := proxy.nacosServer.ReqApi(api, params, http.MethodGet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result == "" {
|
||||
return nil, errors.New("request server return empty")
|
||||
}
|
||||
|
||||
serviceList := model.ServiceList{}
|
||||
count, err := jsonparser.GetInt([]byte(result), "count")
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Sprintf("namespaceId:<%s> get service list pageNo:<%d> pageSize:<%d> selector:<%s> from <%s> get 'count' from <%s> error:<%+v>", proxy.clientConfig.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 nil, errors.New(fmt.Sprintf("namespaceId:<%s> get service list pageNo:<%d> pageSize:<%d> selector:<%s> from <%s> get 'doms' from <%s> error:<%+v> ", proxy.clientConfig.NamespaceId, pageNo, pageSize, util.ToJsonString(selector), groupName, result, err))
|
||||
}
|
||||
serviceList.Count = count
|
||||
serviceList.Doms = doms
|
||||
return &serviceList, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingProxy) ServerHealthy() bool {
|
||||
api := constant.SERVICE_BASE_PATH + "/operator/metrics"
|
||||
result, err := proxy.nacosServer.ReqApi(api, map[string]string{}, http.MethodGet)
|
||||
if err != nil {
|
||||
logger.Errorf("namespaceId:[%s] sending server healthy failed!,result:%s error:%+v", proxy.clientConfig.NamespaceId, result, err)
|
||||
return false
|
||||
}
|
||||
if result != "" {
|
||||
status, err := jsonparser.GetString([]byte(result), "status")
|
||||
if err != nil {
|
||||
logger.Errorf("namespaceId:[%s] sending server healthy failed!,result:%s error:%+v", proxy.clientConfig.NamespaceId, result, err)
|
||||
} else {
|
||||
return status == "UP"
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (proxy *NamingProxy) QueryList(serviceName string, clusters string, udpPort int, healthyOnly bool) (string, error) {
|
||||
param := make(map[string]string)
|
||||
param["namespaceId"] = proxy.clientConfig.NamespaceId
|
||||
param["serviceName"] = serviceName
|
||||
param["app"] = proxy.clientConfig.AppName
|
||||
param["clusters"] = clusters
|
||||
param["udpPort"] = strconv.Itoa(udpPort)
|
||||
param["healthyOnly"] = strconv.FormatBool(healthyOnly)
|
||||
param["clientIP"] = util.LocalIP()
|
||||
api := constant.SERVICE_PATH + "/list"
|
||||
return proxy.nacosServer.ReqApi(api, param, http.MethodGet)
|
||||
}
|
||||
|
||||
func (proxy *NamingProxy) GetAllServiceInfoList(namespace, groupName string, pageNo, pageSize uint32) (string, error) {
|
||||
param := make(map[string]string)
|
||||
param["namespaceId"] = namespace
|
||||
param["groupName"] = groupName
|
||||
param["pageNo"] = strconv.Itoa(int(pageNo))
|
||||
param["pageSize"] = strconv.Itoa(int(pageSize))
|
||||
api := constant.SERVICE_INFO_PATH + "/list"
|
||||
return proxy.nacosServer.ReqApi(api, param, http.MethodGet)
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* 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 naming_proxy
|
||||
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_grpc"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_http"
|
||||
"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/nacos_server"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
type NamingProxyDelegate struct {
|
||||
httpClientProxy *naming_http.NamingHttpProxy
|
||||
grpcClientProxy *naming_grpc.NamingGrpcProxy
|
||||
serviceInfoHolder *naming_cache.ServiceInfoHolder
|
||||
}
|
||||
|
||||
func NewNamingProxyDelegate(clientCfg constant.ClientConfig, serverCfgs []constant.ServerConfig,
|
||||
httpAgent http_agent.IHttpAgent, serviceInfoHolder *naming_cache.ServiceInfoHolder) (INamingProxy, error) {
|
||||
|
||||
nacosServer, err := nacos_server.NewNacosServer(serverCfgs, clientCfg, httpAgent, clientCfg.TimeoutMs, clientCfg.Endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
httpClientProxy, err := naming_http.NewNamingHttpProxy(clientCfg, nacosServer, serviceInfoHolder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
grpcClientProxy, err := naming_grpc.NewNamingGrpcProxy(clientCfg, nacosServer, serviceInfoHolder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &NamingProxyDelegate{
|
||||
httpClientProxy: httpClientProxy,
|
||||
grpcClientProxy: grpcClientProxy,
|
||||
serviceInfoHolder: serviceInfoHolder,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingProxyDelegate) getExecuteClientProxy(instance model.Instance) (namingProxy INamingProxy) {
|
||||
if instance.Ephemeral {
|
||||
namingProxy = proxy.grpcClientProxy
|
||||
} else {
|
||||
namingProxy = proxy.httpClientProxy
|
||||
}
|
||||
return namingProxy
|
||||
}
|
||||
|
||||
func (proxy *NamingProxyDelegate) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
return proxy.getExecuteClientProxy(instance).RegisterInstance(serviceName, groupName, instance)
|
||||
}
|
||||
|
||||
func (proxy *NamingProxyDelegate) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) {
|
||||
return proxy.getExecuteClientProxy(instance).DeregisterInstance(serviceName, groupName, instance)
|
||||
}
|
||||
|
||||
func (proxy *NamingProxyDelegate) GetServiceList(pageNo uint32, pageSize uint32, groupName string, selector *model.ExpressionSelector) (model.ServiceList, error) {
|
||||
return proxy.grpcClientProxy.GetServiceList(pageNo, pageSize, groupName, selector)
|
||||
}
|
||||
|
||||
func (proxy *NamingProxyDelegate) ServerHealthy() bool {
|
||||
return proxy.grpcClientProxy.ServerHealthy() || proxy.httpClientProxy.ServerHealthy()
|
||||
}
|
||||
|
||||
func (proxy *NamingProxyDelegate) QueryInstancesOfService(serviceName, groupName, clusters string, udpPort int, healthyOnly bool) (*model.Service, error) {
|
||||
return proxy.grpcClientProxy.QueryInstancesOfService(serviceName, groupName, clusters, udpPort, healthyOnly)
|
||||
}
|
||||
|
||||
func (proxy *NamingProxyDelegate) Subscribe(serviceName, groupName string, clusters string) (model.Service, error) {
|
||||
serviceNameWithGroup := util.GetServiceCacheKey(util.GetGroupName(serviceName, groupName), clusters)
|
||||
serviceInfo, ok := proxy.serviceInfoHolder.ServiceInfoMap.Get(serviceNameWithGroup)
|
||||
if !ok {
|
||||
result, err := proxy.grpcClientProxy.Subscribe(serviceName, groupName, clusters)
|
||||
if err != nil {
|
||||
return model.Service{}, err
|
||||
}
|
||||
serviceInfo = result
|
||||
}
|
||||
service := serviceInfo.(model.Service)
|
||||
proxy.serviceInfoHolder.ProcessService(&service)
|
||||
return service, nil
|
||||
}
|
||||
|
||||
func (proxy *NamingProxyDelegate) Unsubscribe(serviceName, groupName, clusters string) {
|
||||
proxy.serviceInfoHolder.StopUpdateIfContain(util.GetGroupName(serviceName, groupName), clusters)
|
||||
proxy.grpcClientProxy.Unsubscribe(serviceName, groupName, clusters)
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 naming_proxy
|
||||
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
)
|
||||
|
||||
type INamingProxy interface {
|
||||
RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error)
|
||||
|
||||
DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error)
|
||||
|
||||
GetServiceList(pageNo uint32, pageSize uint32, groupName string, selector *model.ExpressionSelector) (model.ServiceList, error)
|
||||
|
||||
ServerHealthy() bool
|
||||
|
||||
QueryInstancesOfService(serviceName, groupName, clusters string, udpPort int, healthyOnly bool) (*model.Service, error)
|
||||
|
||||
Subscribe(serviceName, groupName, clusters string) (model.Service, error)
|
||||
|
||||
Unsubscribe(serviceName, groupName, clusters string)
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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 naming_client
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"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_proxy"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
type ServiceInfoUpdater struct {
|
||||
serviceInfoHolder *naming_cache.ServiceInfoHolder
|
||||
updateThreadNum int
|
||||
namingProxy naming_proxy.INamingProxy
|
||||
}
|
||||
|
||||
func NewServiceInfoUpdater(serviceInfoHolder *naming_cache.ServiceInfoHolder, updateThreadNum int,
|
||||
namingProxy naming_proxy.INamingProxy) *ServiceInfoUpdater {
|
||||
|
||||
return &ServiceInfoUpdater{
|
||||
serviceInfoHolder: serviceInfoHolder,
|
||||
updateThreadNum: updateThreadNum,
|
||||
namingProxy: namingProxy,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServiceInfoUpdater) asyncUpdateService() {
|
||||
sema := util.NewSemaphore(s.updateThreadNum)
|
||||
for {
|
||||
for _, v := range s.serviceInfoHolder.ServiceInfoMap.Items() {
|
||||
service := v.(model.Service)
|
||||
lastRefTime, ok := s.serviceInfoHolder.UpdateTimeMap.Get(util.GetServiceCacheKey(util.GetGroupName(service.Name, service.GroupName),
|
||||
service.Clusters))
|
||||
if !ok {
|
||||
lastRefTime = uint64(0)
|
||||
}
|
||||
if uint64(util.CurrentMillis())-lastRefTime.(uint64) > service.CacheMillis {
|
||||
sema.Acquire()
|
||||
go func() {
|
||||
s.updateServiceNow(service.Name, service.GroupName, service.Clusters)
|
||||
sema.Release()
|
||||
}()
|
||||
}
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServiceInfoUpdater) updateServiceNow(serviceName, groupName, clusters string) {
|
||||
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)
|
||||
return
|
||||
}
|
||||
s.serviceInfoHolder.ProcessService(result)
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package naming_client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
)
|
||||
|
||||
type SubscribeCallback struct {
|
||||
callbackFuncsMap cache.ConcurrentMap
|
||||
}
|
||||
|
||||
func NewSubscribeCallback() SubscribeCallback {
|
||||
ed := SubscribeCallback{}
|
||||
ed.callbackFuncsMap = cache.NewConcurrentMap()
|
||||
return ed
|
||||
}
|
||||
|
||||
func (ed *SubscribeCallback) AddCallbackFuncs(serviceName string, clusters string, callbackFunc *func(services []model.SubscribeService, err error)) {
|
||||
logger.Info("adding " + serviceName + " with " + clusters + " to listener map")
|
||||
key := util.GetServiceCacheKey(serviceName, clusters)
|
||||
var funcs []*func(services []model.SubscribeService, err error)
|
||||
old, ok := ed.callbackFuncsMap.Get(key)
|
||||
if ok {
|
||||
funcs = append(funcs, old.([]*func(services []model.SubscribeService, err error))...)
|
||||
}
|
||||
funcs = append(funcs, callbackFunc)
|
||||
ed.callbackFuncsMap.Set(key, funcs)
|
||||
}
|
||||
|
||||
func (ed *SubscribeCallback) RemoveCallbackFuncs(serviceName string, clusters string, callbackFunc *func(services []model.SubscribeService, err error)) {
|
||||
logger.Info("removing " + serviceName + " with " + clusters + " to listener map")
|
||||
key := util.GetServiceCacheKey(serviceName, clusters)
|
||||
funcs, ok := ed.callbackFuncsMap.Get(key)
|
||||
if ok && funcs != nil {
|
||||
var newFuncs []*func(services []model.SubscribeService, err error)
|
||||
for _, funcItem := range funcs.([]*func(services []model.SubscribeService, err error)) {
|
||||
if funcItem != callbackFunc {
|
||||
newFuncs = append(newFuncs, funcItem)
|
||||
}
|
||||
}
|
||||
ed.callbackFuncsMap.Set(key, newFuncs)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (ed *SubscribeCallback) ServiceChanged(service *model.Service) {
|
||||
if service == nil || service.Name == "" {
|
||||
return
|
||||
}
|
||||
key := util.GetServiceCacheKey(service.Name, service.Clusters)
|
||||
funcs, ok := ed.callbackFuncsMap.Get(key)
|
||||
if ok {
|
||||
for _, funcItem := range funcs.([]*func(services []model.SubscribeService, err error)) {
|
||||
var subscribeServices []model.SubscribeService
|
||||
if len(service.Hosts) == 0 {
|
||||
(*funcItem)(subscribeServices, errors.New("[client.Subscribe] subscribe failed,hosts is empty"))
|
||||
return
|
||||
}
|
||||
for _, host := range service.Hosts {
|
||||
var subscribeService model.SubscribeService
|
||||
subscribeService.Valid = host.Valid
|
||||
subscribeService.Port = host.Port
|
||||
subscribeService.Ip = host.Ip
|
||||
subscribeService.Metadata = host.Metadata
|
||||
subscribeService.ServiceName = host.ServiceName
|
||||
subscribeService.ClusterName = host.ClusterName
|
||||
subscribeService.Weight = host.Weight
|
||||
subscribeService.InstanceId = host.InstanceId
|
||||
subscribeService.Enable = host.Enable
|
||||
subscribeServices = append(subscribeServices, subscribeService)
|
||||
}
|
||||
(*funcItem)(subscribeServices, nil)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ package constant
|
|||
import (
|
||||
"os"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/file"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/file"
|
||||
)
|
||||
|
||||
func NewClientConfig(opts ...ClientOption) *ClientConfig {
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/file"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/file"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
|
|
@ -29,6 +29,7 @@ type ClientConfig struct {
|
|||
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
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package constant
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
KEY_USERNAME = "username"
|
||||
KEY_PASSWORD = "password"
|
||||
|
@ -66,7 +68,7 @@ const (
|
|||
KEY_BEAT = "beat"
|
||||
KEY_DOM = "dom"
|
||||
DEFAULT_CONTEXT_PATH = "/nacos"
|
||||
CLIENT_VERSION = "Nacos-Go-Client:v1.0.1"
|
||||
CLIENT_VERSION = "Nacos-Go-Client:v2.0.0"
|
||||
REQUEST_DOMAIN_RETRY_TIME = 3
|
||||
SERVICE_INFO_SPLITER = "@@"
|
||||
CONFIG_INFO_SPLITER = "@@"
|
||||
|
@ -75,4 +77,19 @@ const (
|
|||
NAMING_INSTANCE_ID_SPLITTER = "#"
|
||||
DefaultClientErrorCode = "SDK.NacosError"
|
||||
DEFAULT_SERVER_SCHEME = "http"
|
||||
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"
|
||||
)
|
||||
|
|
|
@ -20,9 +20,11 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
type HttpAgent struct {
|
||||
|
@ -56,7 +58,7 @@ func (agent *HttpAgent) RequestOnlyResult(method string, path string, header htt
|
|||
logger.Errorf("request method[%s],request path[%s],header:[%s],params:[%s],err:%+v", method, path, util.ToJsonString(header), util.ToJsonString(params), err)
|
||||
return ""
|
||||
}
|
||||
if response.StatusCode != 200 {
|
||||
if response.StatusCode != constant.RESPONSE_CODE_SUCCESS {
|
||||
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 ""
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
func post(path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) {
|
||||
|
|
|
@ -24,7 +24,7 @@ import (
|
|||
"time"
|
||||
|
||||
rotatelogs "github.com/lestrrat/go-file-rotatelogs"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/file"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/file"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
|
|
@ -19,7 +19,7 @@ package nacos_error
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
)
|
||||
|
||||
type NacosError struct {
|
||||
|
|
|
@ -29,15 +29,16 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/nacos_error"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/security"
|
||||
"github.com/nacos-group/nacos-sdk-go/inner/uuid"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"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/nacos_error"
|
||||
"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/util"
|
||||
)
|
||||
|
||||
type NacosServer struct {
|
||||
|
@ -50,6 +51,7 @@ type NacosServer struct {
|
|||
lastSrvRefTime int64
|
||||
vipSrvRefInterMills int64
|
||||
contextPath string
|
||||
currentIndex int32
|
||||
}
|
||||
|
||||
func NewNacosServer(serverList []constant.ServerConfig, clientCfg constant.ClientConfig, httpAgent http_agent.IHttpAgent, timeoutMs uint64, endpoint string) (*NacosServer, error) {
|
||||
|
@ -67,6 +69,7 @@ func NewNacosServer(serverList []constant.ServerConfig, clientCfg constant.Clien
|
|||
endpoint: endpoint,
|
||||
vipSrvRefInterMills: 10000,
|
||||
contextPath: clientCfg.ContextPath,
|
||||
currentIndex: rand.Int31n((int32)(len(serverList))),
|
||||
}
|
||||
ns.initRefreshSrvIfNeed()
|
||||
_, err := securityLogin.Login()
|
||||
|
@ -85,7 +88,7 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
|
|||
contextPath = constant.WEB_CONTEXT
|
||||
}
|
||||
|
||||
signHeaders := getSignHeaders(params, newHeaders)
|
||||
signHeaders := GetSignHeaders(params, newHeaders["secretKey"])
|
||||
|
||||
url := curServer + contextPath + api
|
||||
|
||||
|
@ -110,7 +113,7 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
|
|||
headers["Spas-AccessKey"] = []string{newHeaders["accessKey"]}
|
||||
headers["Timestamp"] = []string{signHeaders["timeStamp"]}
|
||||
headers["Spas-Signature"] = []string{signHeaders["Spas-Signature"]}
|
||||
injectSecurityInfo(server, params)
|
||||
server.InjectSecurityInfo(params)
|
||||
|
||||
var response *http.Response
|
||||
response, err = server.httpAgent.Request(method, url, headers, timeoutMS, params)
|
||||
|
@ -124,7 +127,7 @@ func (server *NacosServer) callConfigServer(api string, params map[string]string
|
|||
return
|
||||
}
|
||||
result = string(bytes)
|
||||
if response.StatusCode == 200 {
|
||||
if response.StatusCode == constant.RESPONSE_CODE_SUCCESS {
|
||||
return
|
||||
} else {
|
||||
err = nacos_error.NewNacosError(strconv.Itoa(response.StatusCode), string(bytes), nil)
|
||||
|
@ -152,7 +155,7 @@ 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"}
|
||||
|
||||
injectSecurityInfo(server, params)
|
||||
server.InjectSecurityInfo(params)
|
||||
|
||||
var response *http.Response
|
||||
response, err = server.httpAgent.Request(method, url, headers, server.timeoutMs, params)
|
||||
|
@ -166,7 +169,7 @@ func (server *NacosServer) callServer(api string, params map[string]string, meth
|
|||
return
|
||||
}
|
||||
result = string(bytes)
|
||||
if response.StatusCode == 200 {
|
||||
if response.StatusCode == constant.RESPONSE_CODE_SUCCESS {
|
||||
return
|
||||
} else {
|
||||
err = errors.New(fmt.Sprintf("request return error code %d", response.StatusCode))
|
||||
|
@ -180,7 +183,7 @@ func (server *NacosServer) ReqConfigApi(api string, params map[string]string, he
|
|||
return "", errors.New("server list is empty")
|
||||
}
|
||||
|
||||
injectSecurityInfo(server, params)
|
||||
server.InjectSecurityInfo(params)
|
||||
|
||||
//only one server,retry request when error
|
||||
var err error
|
||||
|
@ -215,7 +218,7 @@ func (server *NacosServer) ReqApi(api string, params map[string]string, method s
|
|||
return "", errors.New("server list is empty")
|
||||
}
|
||||
|
||||
injectSecurityInfo(server, params)
|
||||
server.InjectSecurityInfo(params)
|
||||
|
||||
//only one server,retry request when error
|
||||
if len(srvs) == 1 {
|
||||
|
@ -305,7 +308,7 @@ func (server *NacosServer) GetServerList() []constant.ServerConfig {
|
|||
return server.serverList
|
||||
}
|
||||
|
||||
func injectSecurityInfo(server *NacosServer, param map[string]string) {
|
||||
func (server *NacosServer) InjectSecurityInfo(param map[string]string) {
|
||||
accessToken := server.securityLogin.GetAccessToken()
|
||||
if accessToken != "" {
|
||||
param[constant.KEY_ACCESS_TOKEN] = accessToken
|
||||
|
@ -319,7 +322,7 @@ func getAddress(cfg constant.ServerConfig) string {
|
|||
return cfg.Scheme + "://" + cfg.IpAddr + ":" + strconv.Itoa(int(cfg.Port))
|
||||
}
|
||||
|
||||
func getSignHeaders(params map[string]string, newHeaders map[string]string) map[string]string {
|
||||
func GetSignHeaders(params map[string]string, secretKey string) map[string]string {
|
||||
resource := ""
|
||||
|
||||
if len(params["tenant"]) != 0 {
|
||||
|
@ -330,15 +333,15 @@ func getSignHeaders(params map[string]string, newHeaders map[string]string) map[
|
|||
|
||||
headers := map[string]string{}
|
||||
|
||||
timeStamp := strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
|
||||
timeStamp := strconv.FormatInt(util.CurrentMillis(), 10)
|
||||
headers["timeStamp"] = timeStamp
|
||||
|
||||
signature := ""
|
||||
|
||||
if resource == "" {
|
||||
signature = signWithhmacSHA1Encrypt(timeStamp, newHeaders["secretKey"])
|
||||
signature = signWithhmacSHA1Encrypt(timeStamp, secretKey)
|
||||
} else {
|
||||
signature = signWithhmacSHA1Encrypt(resource+"+"+timeStamp, newHeaders["secretKey"])
|
||||
signature = signWithhmacSHA1Encrypt(resource+"+"+timeStamp, secretKey)
|
||||
}
|
||||
|
||||
headers["Spas-Signature"] = signature
|
||||
|
@ -354,3 +357,8 @@ func signWithhmacSHA1Encrypt(encryptText, encryptKey string) string {
|
|||
|
||||
return base64.StdEncoding.EncodeToString(mac.Sum(nil))
|
||||
}
|
||||
|
||||
func (server *NacosServer) GetNextServer() constant.ServerConfig {
|
||||
index := atomic.AddInt32(&server.currentIndex, 1) % (int32)(len(server.GetServerList()))
|
||||
return server.GetServerList()[index]
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ package nacos_server
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 rpc
|
||||
|
||||
import (
|
||||
"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"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type IConnection interface {
|
||||
request(request rpc_request.IRequest, timeoutMills int64, client *RpcClient) (rpc_response.IResponse, error)
|
||||
close()
|
||||
getConnectionId() string
|
||||
getServerInfo() ServerInfo
|
||||
setAbandon(flag bool)
|
||||
}
|
||||
|
||||
type Connection struct {
|
||||
conn *grpc.ClientConn
|
||||
connectionId string
|
||||
abandon bool
|
||||
serverInfo ServerInfo
|
||||
}
|
||||
|
||||
func (c *Connection) getConnectionId() string {
|
||||
return c.connectionId
|
||||
}
|
||||
|
||||
func (c *Connection) getServerInfo() ServerInfo {
|
||||
return c.serverInfo
|
||||
}
|
||||
|
||||
func (c *Connection) setAbandon(flag bool) {
|
||||
c.abandon = flag
|
||||
}
|
||||
|
||||
func (c *Connection) close() {
|
||||
c.conn.Close()
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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 rpc
|
||||
|
||||
type IConnectionEventListener interface {
|
||||
|
||||
//notify when connected to server.
|
||||
OnConnected()
|
||||
|
||||
//notify when disconnected to server.
|
||||
OnDisConnect()
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"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"
|
||||
)
|
||||
|
||||
type MockConnection struct {
|
||||
}
|
||||
|
||||
func (m *MockConnection) request(request rpc_request.IRequest, timeoutMills int64, client *RpcClient) (rpc_response.IResponse, error) {
|
||||
return nil, nil
|
||||
}
|
||||
func (m *MockConnection) close() {
|
||||
|
||||
}
|
||||
func (m *MockConnection) getConnectionId() string {
|
||||
return ""
|
||||
}
|
||||
func (m *MockConnection) getServerInfo() ServerInfo {
|
||||
return ServerInfo{}
|
||||
}
|
||||
func (m *MockConnection) setAbandon(flag bool) {
|
||||
|
||||
}
|
|
@ -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 rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
|
||||
nacos_grpc_service "github.com/nacos-group/nacos-sdk-go/v2/api/grpc"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/nacos_server"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
)
|
||||
|
||||
type GrpcClient struct {
|
||||
*RpcClient
|
||||
}
|
||||
|
||||
func NewGrpcClient(clientName string, nacosServer *nacos_server.NacosServer) *GrpcClient {
|
||||
rpcClient := &GrpcClient{
|
||||
&RpcClient{
|
||||
Name: clientName,
|
||||
labels: make(map[string]string, 8),
|
||||
rpcClientStatus: INITIALIZED,
|
||||
eventChan: make(chan ConnectionEvent),
|
||||
reconnectionChan: make(chan ReconnectContext, 1),
|
||||
lastActiveTimeStamp: time.Now(),
|
||||
nacosServer: nacosServer,
|
||||
serverRequestHandlerMapping: make(map[string]ServerRequestHandlerMapping, 8),
|
||||
mux: new(sync.Mutex),
|
||||
},
|
||||
}
|
||||
rpcClient.executeClient = rpcClient
|
||||
return rpcClient
|
||||
}
|
||||
|
||||
func getMaxCallRecvMsgSize() int {
|
||||
maxCallRecvMsgSizeInt, err := strconv.Atoi(os.Getenv("nacos.remote.client.grpc.maxinbound.message.size"))
|
||||
if err != nil {
|
||||
return 10 * 1024 * 1024
|
||||
}
|
||||
return maxCallRecvMsgSizeInt
|
||||
}
|
||||
|
||||
func getKeepAliveTimeMillis() keepalive.ClientParameters {
|
||||
keepAliveTimeMillisInt, err := strconv.Atoi(os.Getenv("nacos.remote.grpc.keep.alive.millis"))
|
||||
var keepAliveTime time.Duration
|
||||
if err != nil {
|
||||
keepAliveTime = 6 * 60 * 1000 * time.Millisecond
|
||||
} else {
|
||||
keepAliveTime = time.Duration(keepAliveTimeMillisInt) * time.Millisecond
|
||||
}
|
||||
return keepalive.ClientParameters{
|
||||
Time: keepAliveTime, // send pings every 10 seconds if there is no activity
|
||||
Timeout: 3 * time.Second, // wait 1 second for ping ack before considering the connection dead
|
||||
PermitWithoutStream: true, // send pings even without active streams
|
||||
}
|
||||
}
|
||||
|
||||
func (c *GrpcClient) createNewConnection(serverInfo ServerInfo) (*grpc.ClientConn, error) {
|
||||
var opts []grpc.DialOption
|
||||
opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(getMaxCallRecvMsgSize())))
|
||||
opts = append(opts, grpc.WithKeepaliveParams(getKeepAliveTimeMillis()))
|
||||
opts = append(opts, grpc.WithInsecure())
|
||||
rpcPort := serverInfo.serverPort + c.rpcPortOffset()
|
||||
return grpc.Dial(serverInfo.serverIp+":"+strconv.FormatUint(rpcPort, 10), opts...)
|
||||
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
client = nacos_grpc_service.NewRequestClient(conn)
|
||||
response, err := serverCheck(client)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
biStreamClient = nacos_grpc_service.NewBiRequestStreamClient(conn)
|
||||
|
||||
serverCheckResponse := response.(*rpc_response.ServerCheckResponse)
|
||||
|
||||
biStreamRequestClient, err := biStreamClient.RequestBiStream(context.Background())
|
||||
|
||||
grpcConn := NewGrpcConnection(serverInfo, serverCheckResponse.ConnectionId, conn, client, biStreamRequestClient)
|
||||
|
||||
c.bindBiRequestStream(biStreamRequestClient, grpcConn)
|
||||
err = c.sendConnectionSetupRequest(grpcConn)
|
||||
return grpcConn, err
|
||||
}
|
||||
|
||||
func (c *GrpcClient) sendConnectionSetupRequest(grpcConn *GrpcConnection) error {
|
||||
csr := rpc_request.NewConnectionSetupRequest()
|
||||
csr.ClientVersion = constant.CLIENT_VERSION
|
||||
csr.Tenant = c.Tenant
|
||||
csr.Labels = c.labels
|
||||
csr.ClientAbilities = c.clientAbilities
|
||||
err := grpcConn.biStreamSend(convertRequest(csr))
|
||||
if err != nil {
|
||||
logger.Warnf("Send ConnectionSetupRequest error:%+v", err)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *GrpcClient) getConnectionType() ConnectionType {
|
||||
return GRPC
|
||||
}
|
||||
|
||||
func (c *GrpcClient) rpcPortOffset() uint64 {
|
||||
return 1000
|
||||
}
|
||||
|
||||
func (c *GrpcClient) bindBiRequestStream(streamClient nacos_grpc_service.BiRequestStream_RequestBiStreamClient, grpcConn *GrpcConnection) {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-grpcConn.streamCloseChan:
|
||||
return
|
||||
default:
|
||||
payload, err := streamClient.Recv()
|
||||
if err != nil {
|
||||
running := c.IsRunning()
|
||||
abandon := grpcConn.abandon
|
||||
if c.IsRunning() && !grpcConn.abandon {
|
||||
if err == io.EOF {
|
||||
logger.Infof("%s Request stream onCompleted, switch server", grpcConn.getConnectionId())
|
||||
} else {
|
||||
logger.Errorf("%s Request stream error, switch server,error=%+v", grpcConn.getConnectionId(), err)
|
||||
}
|
||||
if atomic.CompareAndSwapInt32((*int32)(&c.rpcClientStatus), int32(RUNNING), int32(UNHEALTHY)) {
|
||||
c.switchServerAsync(ServerInfo{}, false)
|
||||
}
|
||||
} else {
|
||||
logger.Infof("%s Ignore event,isRunning:%v,isAbandon=%v", grpcConn.getConnectionId(), running, abandon)
|
||||
}
|
||||
|
||||
} else {
|
||||
c.handleServerRequest(payload, grpcConn)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func serverCheck(client nacos_grpc_service.RequestClient) (rpc_response.IResponse, error) {
|
||||
payload, err := client.Request(context.Background(), convertRequest(rpc_request.NewServerCheckRequest()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var response rpc_response.ServerCheckResponse
|
||||
err = json.Unmarshal(payload.GetBody().Value, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
func (c *GrpcClient) handleServerRequest(p *nacos_grpc_service.Payload, grpcConn *GrpcConnection) {
|
||||
client := c.GetRpcClient()
|
||||
payLoadType := p.GetMetadata().GetType()
|
||||
|
||||
mapping, ok := client.serverRequestHandlerMapping[payLoadType]
|
||||
if !ok {
|
||||
logger.Errorf("%s Unsupported payload type", grpcConn.getConnectionId())
|
||||
return
|
||||
}
|
||||
|
||||
serverRequest := mapping.serverRequest()
|
||||
err := json.Unmarshal(p.GetBody().Value, serverRequest)
|
||||
if err != nil {
|
||||
logger.Errorf("%s Fail to json Unmarshal for request:%s, ackId->%s", grpcConn.getConnectionId(),
|
||||
serverRequest.GetRequestType(), serverRequest.GetRequestId())
|
||||
return
|
||||
}
|
||||
|
||||
serverRequest.PutAllHeaders(p.GetMetadata().Headers)
|
||||
|
||||
response := mapping.handler.RequestReply(serverRequest, client)
|
||||
if response == nil {
|
||||
logger.Warnf("%s Fail to process server request, ackId->%s", grpcConn.getConnectionId(),
|
||||
serverRequest.GetRequestId())
|
||||
return
|
||||
}
|
||||
response.SetRequestId(serverRequest.GetRequestId())
|
||||
err = grpcConn.biStreamSend(convertResponse(response))
|
||||
if err != nil && err != io.EOF {
|
||||
logger.Warnf("%s Fail to send response:%s,ackId->%s", grpcConn.getConnectionId(),
|
||||
response.GetResponseType(), serverRequest.GetRequestId())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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 rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"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/golang/protobuf/ptypes/any"
|
||||
nacos_grpc_service "github.com/nacos-group/nacos-sdk-go/v2/api/grpc"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
type GrpcConnection struct {
|
||||
*Connection
|
||||
client nacos_grpc_service.RequestClient
|
||||
biStreamClient nacos_grpc_service.BiRequestStream_RequestBiStreamClient
|
||||
streamCloseChan chan struct{}
|
||||
}
|
||||
|
||||
func NewGrpcConnection(serverInfo ServerInfo, connectionId string, conn *grpc.ClientConn,
|
||||
client nacos_grpc_service.RequestClient, biStreamClient nacos_grpc_service.BiRequestStream_RequestBiStreamClient) *GrpcConnection {
|
||||
return &GrpcConnection{
|
||||
Connection: &Connection{
|
||||
serverInfo: serverInfo,
|
||||
connectionId: connectionId,
|
||||
abandon: false,
|
||||
conn: conn,
|
||||
},
|
||||
client: client,
|
||||
biStreamClient: biStreamClient,
|
||||
streamCloseChan: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
func (g *GrpcConnection) request(request rpc_request.IRequest, timeoutMills int64, client *RpcClient) (rpc_response.IResponse, error) {
|
||||
p := convertRequest(request)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutMills)*time.Millisecond)
|
||||
defer cancel()
|
||||
responsePayload, err := g.client.Request(ctx, p)
|
||||
if err != nil {
|
||||
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()))
|
||||
}
|
||||
response := responseFunc()
|
||||
err = json.Unmarshal(responsePayload.GetBody().Value, response)
|
||||
return response, err
|
||||
}
|
||||
|
||||
func (g *GrpcConnection) close() {
|
||||
g.streamCloseChan <- struct{}{}
|
||||
}
|
||||
|
||||
func (g *GrpcConnection) biStreamSend(payload *nacos_grpc_service.Payload) error {
|
||||
return g.biStreamClient.Send(payload)
|
||||
}
|
||||
|
||||
func convertRequest(r rpc_request.IRequest) *nacos_grpc_service.Payload {
|
||||
Metadata := nacos_grpc_service.Metadata{
|
||||
Type: r.GetRequestType(),
|
||||
Headers: r.GetHeaders(),
|
||||
ClientIp: util.LocalIP(),
|
||||
}
|
||||
return &nacos_grpc_service.Payload{
|
||||
Metadata: &Metadata,
|
||||
Body: &any.Any{Value: []byte(r.GetBody(r))},
|
||||
}
|
||||
}
|
||||
|
||||
func convertResponse(r rpc_response.IResponse) *nacos_grpc_service.Payload {
|
||||
Metadata := nacos_grpc_service.Metadata{
|
||||
Type: r.GetResponseType(),
|
||||
ClientIp: util.LocalIP(),
|
||||
}
|
||||
return &nacos_grpc_service.Payload{
|
||||
Metadata: &Metadata,
|
||||
Body: &any.Any{Value: []byte(r.GetBody())},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,467 @@
|
|||
/*
|
||||
* Copyright 1999-2020 Alibaba Group Holding Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/nacos_server"
|
||||
"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"
|
||||
)
|
||||
|
||||
type ConnectionType uint32
|
||||
|
||||
const (
|
||||
GRPC ConnectionType = iota
|
||||
)
|
||||
|
||||
type RpcClientStatus int32
|
||||
|
||||
const (
|
||||
INITIALIZED RpcClientStatus = iota
|
||||
STARTING
|
||||
UNHEALTHY
|
||||
RUNNING
|
||||
SHUTDOWN
|
||||
)
|
||||
|
||||
type ConnectionStatus uint32
|
||||
|
||||
const (
|
||||
DISCONNECTED ConnectionStatus = iota
|
||||
CONNECTED
|
||||
)
|
||||
|
||||
var (
|
||||
cMux = new(sync.Mutex)
|
||||
clientMap = make(map[string]IRpcClient)
|
||||
)
|
||||
|
||||
type IRpcClient interface {
|
||||
connectToServer(serverInfo ServerInfo) (IConnection, error)
|
||||
getConnectionType() ConnectionType
|
||||
putAllLabels(labels map[string]string)
|
||||
rpcPortOffset() uint64
|
||||
GetRpcClient() *RpcClient
|
||||
}
|
||||
|
||||
type ServerInfo struct {
|
||||
serverIp string
|
||||
serverPort uint64
|
||||
}
|
||||
|
||||
type RpcClient struct {
|
||||
Name string
|
||||
labels map[string]string
|
||||
currentConnection IConnection
|
||||
rpcClientStatus RpcClientStatus
|
||||
eventChan chan ConnectionEvent
|
||||
reconnectionChan chan ReconnectContext
|
||||
connectionEventListeners []IConnectionEventListener
|
||||
lastActiveTimeStamp time.Time
|
||||
executeClient IRpcClient
|
||||
nacosServer *nacos_server.NacosServer
|
||||
serverRequestHandlerMapping map[string]ServerRequestHandlerMapping
|
||||
mux *sync.Mutex
|
||||
clientAbilities rpc_request.ClientAbilities
|
||||
Tenant string
|
||||
}
|
||||
|
||||
type ServerRequestHandlerMapping struct {
|
||||
serverRequest func() rpc_request.IRequest
|
||||
handler IServerRequestHandler
|
||||
}
|
||||
|
||||
type ReconnectContext struct {
|
||||
onRequestFail bool
|
||||
serverInfo ServerInfo
|
||||
}
|
||||
|
||||
type ConnectionEvent struct {
|
||||
eventType ConnectionStatus
|
||||
}
|
||||
|
||||
func (r *RpcClient) putAllLabels(labels map[string]string) {
|
||||
for k, v := range labels {
|
||||
r.labels[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RpcClient) GetRpcClient() *RpcClient {
|
||||
return r
|
||||
}
|
||||
|
||||
/**
|
||||
* get all client.
|
||||
*
|
||||
*/
|
||||
func getAllClient() map[string]IRpcClient {
|
||||
return clientMap
|
||||
}
|
||||
|
||||
func getClient(clientName string) IRpcClient {
|
||||
return clientMap[clientName]
|
||||
}
|
||||
|
||||
func CreateClient(clientName string, connectionType ConnectionType, labels map[string]string, nacosServer *nacos_server.NacosServer) (IRpcClient, error) {
|
||||
cMux.Lock()
|
||||
defer cMux.Unlock()
|
||||
if _, ok := clientMap[clientName]; !ok {
|
||||
var rpcClient IRpcClient
|
||||
if GRPC == connectionType {
|
||||
rpcClient = NewGrpcClient(clientName, nacosServer)
|
||||
}
|
||||
if rpcClient == nil {
|
||||
return nil, errors.New("unsupported connection type")
|
||||
}
|
||||
rpcClient.putAllLabels(labels)
|
||||
clientMap[clientName] = rpcClient
|
||||
return rpcClient, nil
|
||||
}
|
||||
return clientMap[clientName], nil
|
||||
}
|
||||
|
||||
func (r *RpcClient) Start() {
|
||||
if ok := atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(INITIALIZED), (int32)(STARTING)); !ok {
|
||||
return
|
||||
}
|
||||
r.registerServerRequestHandlers()
|
||||
go func() {
|
||||
for {
|
||||
event := <-r.eventChan
|
||||
r.notifyConnectionEvent(event)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
timer := time.NewTimer(5 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case rc := <-r.reconnectionChan:
|
||||
if (rc.serverInfo != ServerInfo{}) {
|
||||
var serverExist bool
|
||||
for _, v := range r.nacosServer.GetServerList() {
|
||||
if rc.serverInfo.serverIp == v.IpAddr {
|
||||
rc.serverInfo.serverPort = v.Port
|
||||
serverExist = true
|
||||
}
|
||||
}
|
||||
if !serverExist {
|
||||
logger.Infof("%s Recommend server is not in server list ,ignore recommend server %+v", r.Name, rc.serverInfo)
|
||||
rc.serverInfo = ServerInfo{}
|
||||
}
|
||||
}
|
||||
r.reconnect(rc.serverInfo, rc.onRequestFail)
|
||||
case <-timer.C:
|
||||
r.healthCheck(timer)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var currentConnection IConnection
|
||||
startUpRetryTimes := constant.REQUEST_DOMAIN_RETRY_TIME
|
||||
for startUpRetryTimes > 0 && currentConnection == nil {
|
||||
startUpRetryTimes--
|
||||
serverInfo := r.nextRpcServer()
|
||||
|
||||
logger.Infof("[RpcClient.Start] %+v Try to connect to server on start up, server: %+v", r.Name, serverInfo)
|
||||
|
||||
if connection, err := r.executeClient.connectToServer(serverInfo); err != nil {
|
||||
logger.Warnf("[RpcClient.Start] %+v Fail to connect to server on start up, error message=%+v, "+
|
||||
"start up retry times left=%+v", r.Name, err.Error(), startUpRetryTimes)
|
||||
} else {
|
||||
currentConnection = connection
|
||||
}
|
||||
}
|
||||
if currentConnection != nil {
|
||||
logger.Infof("%s Success to connect to server %+v on start up,connectionId=%v", r.Name,
|
||||
currentConnection.getServerInfo(), currentConnection.getConnectionId())
|
||||
r.currentConnection = currentConnection
|
||||
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
|
||||
r.eventChan <- ConnectionEvent{eventType: CONNECTED}
|
||||
} else {
|
||||
r.switchServerAsync(ServerInfo{}, false)
|
||||
}
|
||||
|
||||
r.signalNotify()
|
||||
}
|
||||
|
||||
func (r *RpcClient) registerServerRequestHandlers() {
|
||||
// register ConnectResetRequestHandler.
|
||||
r.RegisterServerRequestHandler(func() rpc_request.IRequest {
|
||||
return &rpc_request.ConnectResetRequest{InternalRequest: rpc_request.NewInternalRequest()}
|
||||
}, &ConnectResetRequestHandler{})
|
||||
|
||||
// register client detection request.
|
||||
r.RegisterServerRequestHandler(func() rpc_request.IRequest {
|
||||
return &rpc_request.ClientDetectionRequest{InternalRequest: rpc_request.NewInternalRequest()}
|
||||
}, &ClientDetectionRequestHandler{})
|
||||
}
|
||||
|
||||
func (r *RpcClient) signalNotify() {
|
||||
c := make(chan os.Signal)
|
||||
signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||
go func() {
|
||||
for {
|
||||
s := <-c
|
||||
switch s {
|
||||
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
|
||||
r.shutdown()
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (r *RpcClient) shutdown() {
|
||||
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(SHUTDOWN))
|
||||
r.closeConnection()
|
||||
}
|
||||
|
||||
func (r *RpcClient) RegisterServerRequestHandler(request func() rpc_request.IRequest, handler IServerRequestHandler) {
|
||||
requestType := request().GetRequestType()
|
||||
if handler == nil || requestType == "" {
|
||||
logger.Errorf("%s Register server push request handler "+
|
||||
"missing required parameters,request:%+v handler:%+v", request, handler)
|
||||
return
|
||||
}
|
||||
logger.Infof("%s Register server push request:%s handler:%+v", r.Name, requestType, handler)
|
||||
r.serverRequestHandlerMapping[requestType] = ServerRequestHandlerMapping{
|
||||
serverRequest: request,
|
||||
handler: handler,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RpcClient) RegisterConnectionListener(listener IConnectionEventListener) {
|
||||
logger.Infof("%s Register connection listener [%+v] to current client", r.Name, listener)
|
||||
r.connectionEventListeners = append(r.connectionEventListeners, listener)
|
||||
}
|
||||
|
||||
func (r *RpcClient) switchServerAsync(recommendServerInfo ServerInfo, onRequestFail bool) {
|
||||
r.reconnectionChan <- ReconnectContext{serverInfo: recommendServerInfo, onRequestFail: onRequestFail}
|
||||
}
|
||||
|
||||
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))
|
||||
return
|
||||
}
|
||||
serverInfoFlag := false
|
||||
if (serverInfo == ServerInfo{}) {
|
||||
serverInfoFlag = true
|
||||
logger.Infof("%s try to re connect to a new server ,server is not appointed,will choose a random server.", r.Name)
|
||||
}
|
||||
switchSuccess := false
|
||||
var reConnectTimes, retryTurns int
|
||||
for !switchSuccess && !r.isShutdown() {
|
||||
if serverInfoFlag {
|
||||
serverInfo = r.nextRpcServer()
|
||||
}
|
||||
connectionNew, err := r.executeClient.connectToServer(serverInfo)
|
||||
if connectionNew != nil && err == nil {
|
||||
logger.Infof("%s success to connect a server %+v,connectionId=%s", r.Name, serverInfo,
|
||||
connectionNew.getConnectionId())
|
||||
|
||||
if r.currentConnection != nil {
|
||||
logger.Infof("%s Abandon prev connection ,server is %+v, connectionId is %s", r.Name, serverInfo,
|
||||
r.currentConnection.getConnectionId())
|
||||
r.currentConnection.setAbandon(true)
|
||||
r.closeConnection()
|
||||
}
|
||||
r.currentConnection = connectionNew
|
||||
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING))
|
||||
switchSuccess = true
|
||||
r.eventChan <- ConnectionEvent{eventType: CONNECTED}
|
||||
return
|
||||
}
|
||||
if r.isShutdown() {
|
||||
r.closeConnection()
|
||||
}
|
||||
if reConnectTimes > 0 && reConnectTimes%len(r.nacosServer.GetServerList()) == 0 {
|
||||
logger.Infof("%s fail to connect server,after trying %v times, last try server is %+v,error=%+v", r.Name,
|
||||
reConnectTimes, serverInfo, err)
|
||||
if retryTurns < 50 {
|
||||
retryTurns++
|
||||
}
|
||||
}
|
||||
reConnectTimes++
|
||||
if !r.IsRunning() {
|
||||
time.Sleep(time.Duration((math.Min(float64(retryTurns), 50))*100) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
if r.isShutdown() {
|
||||
logger.Infof("%s Client is shutdown ,stop reconnect to server", r.Name)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RpcClient) closeConnection() {
|
||||
if r.currentConnection != nil {
|
||||
r.currentConnection.close()
|
||||
r.eventChan <- ConnectionEvent{eventType: DISCONNECTED}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify when client new connected.
|
||||
func (r *RpcClient) notifyConnectionEvent(event ConnectionEvent) {
|
||||
if len(r.connectionEventListeners) == 0 {
|
||||
return
|
||||
}
|
||||
logger.Infof("%s Notify %s event to listeners.", r.Name, event.toString())
|
||||
for _, v := range r.connectionEventListeners {
|
||||
if event.isConnected() {
|
||||
v.OnConnected()
|
||||
}
|
||||
if event.isDisConnected() {
|
||||
v.OnDisConnect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RpcClient) healthCheck(timer *time.Timer) {
|
||||
defer timer.Reset(constant.KEEP_ALIVE_TIME * time.Second)
|
||||
var reconnectContext ReconnectContext
|
||||
if time.Now().Sub(r.lastActiveTimeStamp) < constant.KEEP_ALIVE_TIME*time.Second {
|
||||
return
|
||||
}
|
||||
if r.sendHealthCheck() {
|
||||
r.lastActiveTimeStamp = time.Now()
|
||||
return
|
||||
} else {
|
||||
if r.currentConnection == nil {
|
||||
return
|
||||
}
|
||||
logger.Infof("%s Server healthy check fail,currentConnection=%s", r.Name, r.currentConnection.getConnectionId())
|
||||
atomic.StoreInt32((*int32)(&r.rpcClientStatus), (int32)(UNHEALTHY))
|
||||
reconnectContext = ReconnectContext{onRequestFail: false}
|
||||
}
|
||||
r.reconnect(reconnectContext.serverInfo, reconnectContext.onRequestFail)
|
||||
}
|
||||
|
||||
func (r *RpcClient) sendHealthCheck() bool {
|
||||
if r.currentConnection == nil {
|
||||
return false
|
||||
}
|
||||
response, err := r.currentConnection.request(rpc_request.NewHealthCheckRequest(),
|
||||
constant.DEFAULT_TIMEOUT_MILLS, r)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if !response.IsSuccess() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *RpcClient) nextRpcServer() ServerInfo {
|
||||
serverConfig := r.nacosServer.GetNextServer()
|
||||
return ServerInfo{
|
||||
serverIp: serverConfig.IpAddr,
|
||||
serverPort: serverConfig.Port,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ConnectionEvent) isConnected() bool {
|
||||
return c.eventType == CONNECTED
|
||||
}
|
||||
|
||||
func (c *ConnectionEvent) isDisConnected() bool {
|
||||
return c.eventType == DISCONNECTED
|
||||
}
|
||||
|
||||
//check is this client is shutdown.
|
||||
func (r *RpcClient) isShutdown() bool {
|
||||
return atomic.LoadInt32((*int32)(&r.rpcClientStatus)) == (int32)(SHUTDOWN)
|
||||
}
|
||||
|
||||
//check is this client is running.
|
||||
func (r *RpcClient) IsRunning() bool {
|
||||
return atomic.LoadInt32((*int32)(&r.rpcClientStatus)) == (int32)(RUNNING)
|
||||
}
|
||||
|
||||
func (r *RpcClient) IsInitialized() bool {
|
||||
return atomic.LoadInt32((*int32)(&r.rpcClientStatus)) == (int32)(INITIALIZED)
|
||||
}
|
||||
|
||||
func (c *ConnectionEvent) toString() string {
|
||||
if c.isConnected() {
|
||||
return "connected"
|
||||
}
|
||||
if c.isDisConnected() {
|
||||
return "disconnected"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (r *RpcClient) Request(request rpc_request.IRequest, timeoutMills int64) (rpc_response.IResponse, error) {
|
||||
retryTimes := 0
|
||||
start := util.CurrentMillis()
|
||||
var currentErr error
|
||||
for retryTimes < constant.REQUEST_DOMAIN_RETRY_TIME && util.CurrentMillis() < start+timeoutMills {
|
||||
if r.currentConnection == nil || !r.IsRunning() {
|
||||
currentErr = waitReconnect(timeoutMills, &retryTimes, request, errors.New(fmt.Sprintf(
|
||||
"Client not connected,current status:%v", atomic.LoadInt32((*int32)(&r.rpcClientStatus)))))
|
||||
continue
|
||||
}
|
||||
response, err := r.currentConnection.request(request, timeoutMills, r)
|
||||
if err == nil {
|
||||
if response, ok := response.(*rpc_response.ErrorResponse); ok {
|
||||
if response.GetErrorCode() == constant.UN_REGISTER {
|
||||
r.mux.Lock()
|
||||
if atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), (int32)(RUNNING), (int32)(UNHEALTHY)) {
|
||||
logger.Infof("Connection is unregistered, switch server,connectionId=%s,request=%s",
|
||||
r.currentConnection.getConnectionId(), request.GetRequestType())
|
||||
r.switchServerAsync(ServerInfo{}, false)
|
||||
}
|
||||
r.mux.Unlock()
|
||||
}
|
||||
currentErr = waitReconnect(timeoutMills, &retryTimes, request, errors.New(response.GetMessage()))
|
||||
continue
|
||||
}
|
||||
r.lastActiveTimeStamp = time.Now()
|
||||
return response, nil
|
||||
} else {
|
||||
currentErr = waitReconnect(timeoutMills, &retryTimes, request, err)
|
||||
}
|
||||
}
|
||||
|
||||
if atomic.CompareAndSwapInt32((*int32)(&r.rpcClientStatus), int32(RUNNING), int32(UNHEALTHY)) {
|
||||
r.switchServerAsync(ServerInfo{}, true)
|
||||
}
|
||||
if currentErr != nil {
|
||||
return nil, currentErr
|
||||
}
|
||||
return nil, errors.New("request fail, unknown error")
|
||||
}
|
||||
|
||||
func waitReconnect(timeoutMills int64, retryTimes *int, request rpc_request.IRequest, err error) error {
|
||||
logger.Errorf("Send request fail, request=%+v, retryTimes=%v,error=%+v", request, retryTimes, err)
|
||||
time.Sleep(time.Duration(math.Min(100, float64(timeoutMills/3))) * time.Millisecond)
|
||||
*retryTimes++
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package rpc
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestHealthCheck(t *testing.T) {
|
||||
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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 rpc_request
|
||||
|
||||
import "github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
|
||||
type ConfigRequest struct {
|
||||
*Request
|
||||
Module string `json:"module"`
|
||||
}
|
||||
|
||||
func NewConfigRequest() *ConfigRequest {
|
||||
request := Request{
|
||||
Headers: make(map[string]string, 8),
|
||||
}
|
||||
return &ConfigRequest{
|
||||
Request: &request,
|
||||
Module: "config",
|
||||
}
|
||||
}
|
||||
|
||||
//request of listening a batch of configs.
|
||||
type ConfigBatchListenRequest struct {
|
||||
*ConfigRequest
|
||||
Listen bool `json:"listen"`
|
||||
ConfigListenContexts []model.ConfigListenContext `json:"configListenContexts"`
|
||||
}
|
||||
|
||||
func NewConfigBatchListenRequest(cacheLen int) *ConfigBatchListenRequest {
|
||||
return &ConfigBatchListenRequest{
|
||||
Listen: true,
|
||||
ConfigListenContexts: make([]model.ConfigListenContext, 0, cacheLen),
|
||||
ConfigRequest: NewConfigRequest(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ConfigBatchListenRequest) GetRequestType() string {
|
||||
return "ConfigBatchListenRequest"
|
||||
}
|
||||
|
||||
type ConfigChangeNotifyRequest struct {
|
||||
*ConfigRequest
|
||||
Group string `json:"group"`
|
||||
DataId string `json:"dataId"`
|
||||
Tenant string `json:"tenant"`
|
||||
}
|
||||
|
||||
func NewConfigChangeNotifyRequest(group, dataId, tenant string) *ConfigChangeNotifyRequest {
|
||||
return &ConfigChangeNotifyRequest{ConfigRequest: NewConfigRequest(), Group: group, DataId: dataId, Tenant: tenant}
|
||||
}
|
||||
|
||||
func (r *ConfigChangeNotifyRequest) GetRequestType() string {
|
||||
return "ConfigChangeNotifyRequest"
|
||||
}
|
||||
|
||||
type ConfigQueryRequest struct {
|
||||
*ConfigRequest
|
||||
Group string `json:"group"`
|
||||
DataId string `json:"dataId"`
|
||||
Tenant string `json:"tenant"`
|
||||
Tag string `json:"tag"`
|
||||
}
|
||||
|
||||
func NewConfigQueryRequest(group, dataId, tenant string) *ConfigQueryRequest {
|
||||
return &ConfigQueryRequest{ConfigRequest: NewConfigRequest(), Group: group, DataId: dataId, Tenant: tenant}
|
||||
}
|
||||
|
||||
func (r *ConfigQueryRequest) GetRequestType() string {
|
||||
return "ConfigQueryRequest"
|
||||
}
|
||||
|
||||
type ConfigPublishRequest struct {
|
||||
*ConfigRequest
|
||||
Group string `json:"group"`
|
||||
DataId string `json:"dataId"`
|
||||
Tenant string `json:"tenant"`
|
||||
Content string `json:"content"`
|
||||
CasMd5 string `json:"casMd5"`
|
||||
AdditionMap map[string]string `json:"additionMap"`
|
||||
}
|
||||
|
||||
func NewConfigPublishRequest(group, dataId, tenant, content, casMd5 string) *ConfigPublishRequest {
|
||||
return &ConfigPublishRequest{ConfigRequest: NewConfigRequest(),
|
||||
Group: group, DataId: dataId, Tenant: tenant, Content: content, CasMd5: casMd5, AdditionMap: make(map[string]string)}
|
||||
}
|
||||
|
||||
func (r *ConfigPublishRequest) GetRequestType() string {
|
||||
return "ConfigPublishRequest"
|
||||
}
|
||||
|
||||
type ConfigRemoveRequest struct {
|
||||
*ConfigRequest
|
||||
Group string `json:"group"`
|
||||
DataId string `json:"dataId"`
|
||||
Tenant string `json:"tenant"`
|
||||
}
|
||||
|
||||
func NewConfigRemoveRequest(group, dataId, tenant string) *ConfigRemoveRequest {
|
||||
return &ConfigRemoveRequest{ConfigRequest: NewConfigRequest(),
|
||||
Group: group, DataId: dataId, Tenant: tenant}
|
||||
}
|
||||
|
||||
func (r *ConfigRemoveRequest) GetRequestType() string {
|
||||
return "ConfigRemoveRequest"
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* 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 rpc_request
|
||||
|
||||
type ClientAbilities struct {
|
||||
}
|
||||
|
||||
type InternalRequest struct {
|
||||
*Request
|
||||
Module string `json:"module"`
|
||||
}
|
||||
|
||||
func NewInternalRequest() *InternalRequest {
|
||||
request := Request{
|
||||
Headers: make(map[string]string, 8),
|
||||
}
|
||||
return &InternalRequest{
|
||||
Request: &request,
|
||||
Module: "internal",
|
||||
}
|
||||
}
|
||||
|
||||
type HealthCheckRequest struct {
|
||||
*InternalRequest
|
||||
}
|
||||
|
||||
func NewHealthCheckRequest() *HealthCheckRequest {
|
||||
return &HealthCheckRequest{
|
||||
InternalRequest: NewInternalRequest(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *HealthCheckRequest) GetRequestType() string {
|
||||
return "HealthCheckRequest"
|
||||
}
|
||||
|
||||
type ConnectResetRequest struct {
|
||||
*InternalRequest
|
||||
ServerIp string
|
||||
ServerPort string
|
||||
}
|
||||
|
||||
func (r *ConnectResetRequest) GetRequestType() string {
|
||||
return "ConnectResetRequest"
|
||||
}
|
||||
|
||||
type ClientDetectionRequest struct {
|
||||
*InternalRequest
|
||||
}
|
||||
|
||||
func (r *ClientDetectionRequest) GetRequestType() string {
|
||||
return "ClientDetectionRequest"
|
||||
}
|
||||
|
||||
type ServerCheckRequest struct {
|
||||
*InternalRequest
|
||||
}
|
||||
|
||||
func NewServerCheckRequest() *ServerCheckRequest {
|
||||
return &ServerCheckRequest{
|
||||
InternalRequest: NewInternalRequest(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ServerCheckRequest) GetRequestType() string {
|
||||
return "ServerCheckRequest"
|
||||
}
|
||||
|
||||
type ConnectionSetupRequest struct {
|
||||
*InternalRequest
|
||||
ClientVersion string `json:"clientVersion"`
|
||||
Tenant string `json:"tenant"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
ClientAbilities ClientAbilities `json:"clientAbilities"`
|
||||
}
|
||||
|
||||
func NewConnectionSetupRequest() *ConnectionSetupRequest {
|
||||
return &ConnectionSetupRequest{
|
||||
InternalRequest: NewInternalRequest(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ConnectionSetupRequest) GetRequestType() string {
|
||||
return "ConnectionSetupRequest"
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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 rpc_request
|
||||
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
)
|
||||
|
||||
type NamingRequest struct {
|
||||
*Request
|
||||
Namespace string `json:"namespace"`
|
||||
ServiceName string `json:"serviceName"`
|
||||
GroupName string `json:"groupName"`
|
||||
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),
|
||||
}
|
||||
return &NamingRequest{
|
||||
Request: &request,
|
||||
Namespace: namespace,
|
||||
ServiceName: serviceName,
|
||||
GroupName: groupName,
|
||||
Module: "naming",
|
||||
}
|
||||
}
|
||||
|
||||
func NewInstanceRequest(namespace, serviceName, groupName, Type string, instance model.Instance) *InstanceRequest {
|
||||
return &InstanceRequest{
|
||||
NamingRequest: NewNamingRequest(namespace, serviceName, groupName),
|
||||
Type: Type,
|
||||
Instance: instance,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *InstanceRequest) GetRequestType() string {
|
||||
return "InstanceRequest"
|
||||
}
|
||||
|
||||
type NotifySubscriberRequest struct {
|
||||
*NamingRequest
|
||||
ServiceInfo model.Service `json:"serviceInfo"`
|
||||
}
|
||||
|
||||
func (r *NotifySubscriberRequest) GetRequestType() string {
|
||||
return "NotifySubscriberRequest"
|
||||
}
|
||||
|
||||
type ServiceListRequest struct {
|
||||
*NamingRequest
|
||||
PageNo int `json:"pageNo"`
|
||||
PageSize int `json:"pageSize"`
|
||||
Selector string `json:"selector"`
|
||||
}
|
||||
|
||||
func NewServiceListRequest(namespace, serviceName, groupName string, pageNo, pageSize int, selector string) *ServiceListRequest {
|
||||
return &ServiceListRequest{
|
||||
NamingRequest: NewNamingRequest(namespace, serviceName, groupName),
|
||||
PageNo: pageNo,
|
||||
PageSize: pageSize,
|
||||
Selector: selector,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ServiceListRequest) GetRequestType() string {
|
||||
return "ServiceListRequest"
|
||||
}
|
||||
|
||||
type SubscribeServiceRequest struct {
|
||||
*NamingRequest
|
||||
Subscribe bool `json:"subscribe"`
|
||||
Clusters string `json:"clusters"`
|
||||
}
|
||||
|
||||
func NewSubscribeServiceRequest(namespace, serviceName, groupName, clusters string, subscribe bool) *SubscribeServiceRequest {
|
||||
return &SubscribeServiceRequest{
|
||||
NamingRequest: NewNamingRequest(namespace, serviceName, groupName),
|
||||
Subscribe: subscribe,
|
||||
Clusters: clusters,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *SubscribeServiceRequest) GetRequestType() string {
|
||||
return "SubscribeServiceRequest"
|
||||
}
|
||||
|
||||
type ServiceQueryRequest struct {
|
||||
*NamingRequest
|
||||
Clusters string `json:"clusters"`
|
||||
HealthyOnly bool `json:"healthyOnly"`
|
||||
UdpPort int `json:"udpPort"`
|
||||
}
|
||||
|
||||
func NewServiceQueryRequest(namespace, serviceName, groupName, clusters string, healthyOnly bool, udpPort int) *ServiceQueryRequest {
|
||||
return &ServiceQueryRequest{
|
||||
NamingRequest: NewNamingRequest(namespace, serviceName, groupName),
|
||||
Clusters: clusters,
|
||||
HealthyOnly: healthyOnly,
|
||||
UdpPort: udpPort,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ServiceQueryRequest) GetRequestType() string {
|
||||
return "ServiceQueryRequest"
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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 rpc_request
|
||||
|
||||
import "github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
|
||||
type Request struct {
|
||||
Headers map[string]string `json:"-"`
|
||||
RequestId string `json:"requestId"`
|
||||
}
|
||||
|
||||
type IRequest interface {
|
||||
GetHeaders() map[string]string
|
||||
GetRequestType() string
|
||||
GetBody(request IRequest) string
|
||||
PutAllHeaders(headers map[string]string)
|
||||
GetRequestId() string
|
||||
}
|
||||
|
||||
func (r *Request) PutAllHeaders(headers map[string]string) {
|
||||
for k, v := range headers {
|
||||
r.Headers[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Request) ClearHeaders() {
|
||||
r.Headers = make(map[string]string)
|
||||
}
|
||||
|
||||
func (r *Request) GetHeaders() map[string]string {
|
||||
return r.Headers
|
||||
}
|
||||
|
||||
func (r *Request) GetBody(request IRequest) string {
|
||||
return util.ToJsonString(request)
|
||||
}
|
||||
func (r *Request) GetRequestId() string {
|
||||
return r.RequestId
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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 rpc_response
|
||||
|
||||
import "github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
|
||||
type ConfigChangeBatchListenResponse struct {
|
||||
*Response
|
||||
ChangedConfigs []model.ConfigContext `json:"changedConfigs"`
|
||||
}
|
||||
|
||||
func (c *ConfigChangeBatchListenResponse) GetResponseType() string {
|
||||
return "ConfigChangeBatchListenResponse"
|
||||
}
|
||||
|
||||
type ConfigQueryResponse struct {
|
||||
*Response
|
||||
Content string `json:"content"`
|
||||
EncryptedDataKey string `json:"encryptedDataKey"`
|
||||
ContentType string `json:"contentType"`
|
||||
Md5 string `json:"md5"`
|
||||
LastModified int64 `json:"lastModified"`
|
||||
IsBeta bool `json:"isBeta"`
|
||||
Tag bool `json:"tag"`
|
||||
}
|
||||
|
||||
func (c *ConfigQueryResponse) GetResponseType() string {
|
||||
return "ConfigQueryResponse"
|
||||
}
|
||||
|
||||
type ConfigPublishResponse struct {
|
||||
*Response
|
||||
}
|
||||
|
||||
func (c *ConfigPublishResponse) GetResponseType() string {
|
||||
return "ConfigPublishResponse"
|
||||
}
|
||||
|
||||
type ConfigRemoveResponse struct {
|
||||
*Response
|
||||
}
|
||||
|
||||
func (c *ConfigRemoveResponse) GetResponseType() string {
|
||||
return "ConfigRemoveResponse"
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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 rpc_response
|
||||
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
)
|
||||
|
||||
type ConnectResetResponse struct {
|
||||
*Response
|
||||
}
|
||||
|
||||
func (c *ConnectResetResponse) GetResponseType() string {
|
||||
return "ConnectResetResponse"
|
||||
}
|
||||
|
||||
type ClientDetectionResponse struct {
|
||||
*Response
|
||||
}
|
||||
|
||||
func (c *ClientDetectionResponse) GetResponseType() string {
|
||||
return "ClientDetectionResponse"
|
||||
}
|
||||
|
||||
type ServerCheckResponse struct {
|
||||
*Response
|
||||
ConnectionId string `json:"connectionId"`
|
||||
}
|
||||
|
||||
func (c *ServerCheckResponse) GetResponseType() string {
|
||||
return "ServerCheckResponse"
|
||||
}
|
||||
|
||||
type InstanceResponse struct {
|
||||
*Response
|
||||
}
|
||||
|
||||
func (c *InstanceResponse) GetResponseType() string {
|
||||
return "InstanceResponse"
|
||||
}
|
||||
|
||||
type QueryServiceResponse struct {
|
||||
*Response
|
||||
ServiceInfo model.Service `json:"serviceInfo"`
|
||||
}
|
||||
|
||||
func (c *QueryServiceResponse) GetResponseType() string {
|
||||
return "QueryServiceResponse"
|
||||
}
|
||||
|
||||
type SubscribeServiceResponse struct {
|
||||
*Response
|
||||
ServiceInfo model.Service `json:"serviceInfo"`
|
||||
}
|
||||
|
||||
func (c *SubscribeServiceResponse) GetResponseType() string {
|
||||
return "SubscribeServiceResponse"
|
||||
}
|
||||
|
||||
type ServiceListResponse struct {
|
||||
*Response
|
||||
Count int `json:"count"`
|
||||
ServiceNames []string `json:"serviceNames"`
|
||||
}
|
||||
|
||||
func (c *ServiceListResponse) GetResponseType() string {
|
||||
return "ServiceListResponse"
|
||||
}
|
||||
|
||||
type NotifySubscriberResponse struct {
|
||||
*Response
|
||||
}
|
||||
|
||||
func (c *NotifySubscriberResponse) GetResponseType() string {
|
||||
return "NotifySubscriberResponse"
|
||||
}
|
||||
|
||||
type HealthCheckResponse struct {
|
||||
*Response
|
||||
}
|
||||
|
||||
func (c *HealthCheckResponse) GetResponseType() string {
|
||||
return "HealthCheckResponse"
|
||||
}
|
||||
|
||||
type ErrorResponse struct {
|
||||
*Response
|
||||
}
|
||||
|
||||
func (c *ErrorResponse) GetResponseType() string {
|
||||
return "ErrorResponse"
|
||||
}
|
||||
|
||||
type MockResponse struct {
|
||||
*Response
|
||||
}
|
||||
|
||||
func (c *MockResponse) GetResponseType() string {
|
||||
return "MockResponse"
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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 rpc_response
|
||||
|
||||
import (
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
)
|
||||
|
||||
var ClientResponseMapping map[string]func() IResponse
|
||||
|
||||
func init() {
|
||||
ClientResponseMapping = make(map[string]func() IResponse)
|
||||
registerClientResponses()
|
||||
}
|
||||
|
||||
type IResponse interface {
|
||||
GetResponseType() string
|
||||
SetRequestId(requestId string)
|
||||
GetBody() string
|
||||
GetErrorCode() int
|
||||
IsSuccess() bool
|
||||
GetResultCode() int
|
||||
GetMessage() string
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
ResultCode int `json:"resultCode"`
|
||||
ErrorCode int `json:"errorCode"`
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
RequestId string `json:"requestId"`
|
||||
}
|
||||
|
||||
func (r *Response) SetRequestId(requestId string) {
|
||||
r.RequestId = requestId
|
||||
}
|
||||
|
||||
func (r *Response) GetBody() string {
|
||||
return util.ToJsonString(r)
|
||||
}
|
||||
|
||||
func (r *Response) IsSuccess() bool {
|
||||
return r.Success
|
||||
}
|
||||
|
||||
func (r *Response) GetErrorCode() int {
|
||||
return r.ErrorCode
|
||||
}
|
||||
|
||||
func (r *Response) GetResultCode() int {
|
||||
return r.ResultCode
|
||||
}
|
||||
|
||||
func (r *Response) GetMessage() string {
|
||||
return r.Message
|
||||
}
|
||||
|
||||
func registerClientResponse(response func() IResponse) {
|
||||
responseType := response().GetResponseType()
|
||||
if responseType == "" {
|
||||
logger.Errorf("Register client response error: responseType is nil")
|
||||
return
|
||||
}
|
||||
ClientResponseMapping[responseType] = response
|
||||
}
|
||||
|
||||
func registerClientResponses() {
|
||||
// register InstanceResponse.
|
||||
registerClientResponse(func() IResponse {
|
||||
return &InstanceResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
// register QueryServiceResponse.
|
||||
registerClientResponse(func() IResponse {
|
||||
return &QueryServiceResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
// register SubscribeServiceResponse.
|
||||
registerClientResponse(func() IResponse {
|
||||
return &SubscribeServiceResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
// register ServiceListResponse.
|
||||
registerClientResponse(func() IResponse {
|
||||
return &ServiceListResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
// register NotifySubscriberResponse.
|
||||
registerClientResponse(func() IResponse {
|
||||
return &NotifySubscriberResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
// register HealthCheckResponse.
|
||||
registerClientResponse(func() IResponse {
|
||||
return &HealthCheckResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
// register ErrorResponse.
|
||||
registerClientResponse(func() IResponse {
|
||||
return &ErrorResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
//register ConfigChangeBatchListenResponse
|
||||
registerClientResponse(func() IResponse {
|
||||
return &ConfigChangeBatchListenResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
//register ConfigQueryResponse
|
||||
registerClientResponse(func() IResponse {
|
||||
return &ConfigQueryResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
//register ConfigPublishResponse
|
||||
registerClientResponse(func() IResponse {
|
||||
return &ConfigPublishResponse{Response: &Response{}}
|
||||
})
|
||||
|
||||
//register ConfigRemoveResponse
|
||||
registerClientResponse(func() IResponse {
|
||||
return &ConfigRemoveResponse{Response: &Response{}}
|
||||
})
|
||||
}
|
|
@ -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 rpc
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"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"
|
||||
)
|
||||
|
||||
//ServerRequestHandler, to process the request from server side.
|
||||
type IServerRequestHandler interface {
|
||||
|
||||
//Handle request from server.
|
||||
RequestReply(request rpc_request.IRequest, rpcClient *RpcClient) rpc_response.IResponse
|
||||
}
|
||||
|
||||
type ConnectResetRequestHandler struct {
|
||||
}
|
||||
|
||||
func (c *ConnectResetRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *RpcClient) rpc_response.IResponse {
|
||||
defer rpcClient.mux.Unlock()
|
||||
connectResetRequest, ok := request.(*rpc_request.ConnectResetRequest)
|
||||
if ok {
|
||||
rpcClient.mux.Lock()
|
||||
if rpcClient.IsRunning() {
|
||||
if connectResetRequest.ServerIp != "" {
|
||||
serverPortNum, err := strconv.Atoi(connectResetRequest.ServerPort)
|
||||
if err != nil {
|
||||
logger.Infof("ConnectResetRequest ServerPort type conversion error:%+v", err)
|
||||
return nil
|
||||
}
|
||||
rpcClient.switchServerAsync(ServerInfo{serverIp: connectResetRequest.ServerIp, serverPort: uint64(serverPortNum)}, false)
|
||||
} else {
|
||||
rpcClient.switchServerAsync(ServerInfo{}, true)
|
||||
}
|
||||
}
|
||||
return &rpc_response.ConnectResetResponse{Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS}}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ClientDetectionRequestHandler struct {
|
||||
}
|
||||
|
||||
func (c *ClientDetectionRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *RpcClient) rpc_response.IResponse {
|
||||
_, ok := request.(*rpc_request.ClientDetectionRequest)
|
||||
if ok {
|
||||
return &rpc_response.ClientDetectionResponse{
|
||||
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS},
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NamingPushRequestHandler struct {
|
||||
ServiceInfoHolder *naming_cache.ServiceInfoHolder
|
||||
}
|
||||
|
||||
func (c *NamingPushRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *RpcClient) rpc_response.IResponse {
|
||||
notifySubscriberRequest, ok := request.(*rpc_request.NotifySubscriberRequest)
|
||||
if ok {
|
||||
c.ServiceInfoHolder.ProcessService(¬ifySubscriberRequest.ServiceInfo)
|
||||
return &rpc_response.NotifySubscriberResponse{
|
||||
Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS},
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -26,9 +26,9 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/http_agent"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"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"
|
||||
)
|
||||
|
||||
type AuthClient struct {
|
||||
|
@ -137,7 +137,7 @@ func (ac *AuthClient) login(server constant.ServerConfig) (bool, error) {
|
|||
return false, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
if resp.StatusCode != constant.RESPONSE_CODE_SUCCESS {
|
||||
errMsg := string(bytes)
|
||||
return false, errors.New(errMsg)
|
||||
}
|
||||
|
|
|
@ -20,40 +20,20 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/clients"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"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 ServerConfig
|
||||
sc := []constant.ServerConfig{
|
||||
{
|
||||
IpAddr: "console.nacos.io",
|
||||
Port: 80,
|
||||
},
|
||||
}
|
||||
//or a more graceful way to create ServerConfig
|
||||
_ = []constant.ServerConfig{
|
||||
*constant.NewServerConfig(
|
||||
"console.nacos.io",
|
||||
80,
|
||||
constant.WithScheme("http"),
|
||||
constant.WithContextPath("/nacos")),
|
||||
*constant.NewServerConfig("127.0.0.1", 8848, constant.WithContextPath("/nacos")),
|
||||
}
|
||||
|
||||
cc := constant.ClientConfig{
|
||||
NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468", //namespace id
|
||||
TimeoutMs: 5000,
|
||||
NotLoadCacheAtStart: true,
|
||||
LogDir: "/tmp/nacos/log",
|
||||
CacheDir: "/tmp/nacos/cache",
|
||||
RotateTime: "1h",
|
||||
MaxAge: 3,
|
||||
LogLevel: "debug",
|
||||
}
|
||||
//or a more graceful way to create ClientConfig
|
||||
_ = *constant.NewClientConfig(
|
||||
constant.WithNamespaceId("e525eafa-f7d7-4029-83d9-008937f9d468"),
|
||||
//create ClientConfig
|
||||
cc := *constant.NewClientConfig(
|
||||
constant.WithNamespaceId(""),
|
||||
constant.WithTimeoutMs(5000),
|
||||
constant.WithNotLoadCacheAtStart(true),
|
||||
constant.WithLogDir("/tmp/nacos/log"),
|
||||
|
@ -63,7 +43,7 @@ func main() {
|
|||
constant.WithLogLevel("debug"),
|
||||
)
|
||||
|
||||
// a more graceful way to create config client
|
||||
// create config client
|
||||
client, err := clients.NewConfigClient(
|
||||
vo.NacosClientParam{
|
||||
ClientConfig: &cc,
|
||||
|
@ -90,7 +70,7 @@ func main() {
|
|||
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",
|
||||
|
@ -115,13 +95,15 @@ func main() {
|
|||
},
|
||||
})
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
_, err = client.PublishConfig(vo.ConfigParam{
|
||||
DataId: "test-data",
|
||||
Group: "test-group",
|
||||
Content: "test-listen",
|
||||
})
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
_, err = client.PublishConfig(vo.ConfigParam{
|
||||
DataId: "test-data-2",
|
||||
|
@ -137,12 +119,12 @@ func main() {
|
|||
Group: "test-group",
|
||||
})
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
time.Sleep(1 * time.Second)
|
||||
_, err = client.DeleteConfig(vo.ConfigParam{
|
||||
DataId: "test-data",
|
||||
Group: "test-group",
|
||||
})
|
||||
time.Sleep(5 * time.Second)
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
searchPage, _ := client.SearchConfig(vo.SearchConfigParm{
|
||||
Search: "blur",
|
||||
|
|
|
@ -20,38 +20,22 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/clients"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"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/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/util"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//create ServerConfig
|
||||
sc := []constant.ServerConfig{
|
||||
{
|
||||
IpAddr: "console.nacos.io",
|
||||
Port: 80,
|
||||
},
|
||||
}
|
||||
//or a more graceful way to create ServerConfig
|
||||
_ = []constant.ServerConfig{
|
||||
*constant.NewServerConfig("console.nacos.io", 80),
|
||||
*constant.NewServerConfig("127.0.0.1", 8848, constant.WithContextPath("/nacos")),
|
||||
}
|
||||
|
||||
cc := constant.ClientConfig{
|
||||
NamespaceId: "e525eafa-f7d7-4029-83d9-008937f9d468", //namespace id
|
||||
TimeoutMs: 5000,
|
||||
NotLoadCacheAtStart: true,
|
||||
LogDir: "/tmp/nacos/log",
|
||||
CacheDir: "/tmp/nacos/cache",
|
||||
RotateTime: "1h",
|
||||
MaxAge: 3,
|
||||
LogLevel: "debug",
|
||||
}
|
||||
//or a more graceful way to create ClientConfig
|
||||
_ = *constant.NewClientConfig(
|
||||
constant.WithNamespaceId("e525eafa-f7d7-4029-83d9-008937f9d468"),
|
||||
//create ClientConfig
|
||||
cc := *constant.NewClientConfig(
|
||||
constant.WithNamespaceId(""),
|
||||
constant.WithTimeoutMs(5000),
|
||||
constant.WithNotLoadCacheAtStart(true),
|
||||
constant.WithLogDir("/tmp/nacos/log"),
|
||||
|
@ -61,7 +45,7 @@ func main() {
|
|||
constant.WithLogLevel("debug"),
|
||||
)
|
||||
|
||||
// a more graceful way to create naming client
|
||||
// create naming client
|
||||
client, err := clients.NewNamingClient(
|
||||
vo.NacosClientParam{
|
||||
ClientConfig: &cc,
|
||||
|
@ -79,6 +63,8 @@ func main() {
|
|||
Ip: "10.0.0.10",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
ClusterName: "cluster-a",
|
||||
Weight: 10,
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
|
@ -86,56 +72,6 @@ func main() {
|
|||
Metadata: map[string]string{"idc": "shanghai"},
|
||||
})
|
||||
|
||||
//Register with cluster name
|
||||
//GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.11",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
Weight: 10,
|
||||
ClusterName: "cluster-a",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
})
|
||||
|
||||
//Register different cluster
|
||||
//GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.12",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
Weight: 10,
|
||||
ClusterName: "cluster-b",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
})
|
||||
|
||||
//Register different group
|
||||
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.13",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
Weight: 10,
|
||||
ClusterName: "cluster-b",
|
||||
GroupName: "group-a",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
})
|
||||
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.14",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
Weight: 10,
|
||||
ClusterName: "cluster-b",
|
||||
GroupName: "group-b",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
})
|
||||
|
||||
//DeRegister with ip,port,serviceName
|
||||
//ClusterName=DEFAULT, GroupName=DEFAULT_GROUP
|
||||
//Note:ip=10.0.0.10,port=8848 should belong to the cluster of DEFAULT and the group of DEFAULT_GROUP.
|
||||
|
@ -143,72 +79,50 @@ func main() {
|
|||
Ip: "10.0.0.10",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
Ephemeral: true, //it must be true
|
||||
})
|
||||
|
||||
//DeRegister with ip,port,serviceName,cluster
|
||||
//GroupName=DEFAULT_GROUP
|
||||
//Note:ip=10.0.0.10,port=8848,cluster=cluster-a should belong to the group of DEFAULT_GROUP.
|
||||
ExampleServiceClient_DeRegisterServiceInstance(client, vo.DeregisterInstanceParam{
|
||||
Ip: "10.0.0.11",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
Cluster: "cluster-a",
|
||||
Ephemeral: true, //it must be true
|
||||
})
|
||||
|
||||
//DeRegister with ip,port,serviceName,cluster,group
|
||||
ExampleServiceClient_DeRegisterServiceInstance(client, vo.DeregisterInstanceParam{
|
||||
Ip: "10.0.0.14",
|
||||
//Register with default cluster and group
|
||||
//ClusterName=DEFAULT,GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.10",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
Cluster: "cluster-b",
|
||||
GroupName: "group-b",
|
||||
Ephemeral: true, //it must be true
|
||||
GroupName: "group-a",
|
||||
ClusterName: "cluster-a",
|
||||
Weight: 10,
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
Metadata: map[string]string{"idc": "shanghai"},
|
||||
})
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
//Get service with serviceName
|
||||
//ClusterName=DEFAULT, GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_GetService(client, vo.GetServiceParam{
|
||||
ServiceName: "demo.go",
|
||||
})
|
||||
//Get service with serviceName and cluster
|
||||
//GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_GetService(client, vo.GetServiceParam{
|
||||
ServiceName: "demo.go",
|
||||
Clusters: []string{"cluster-a", "cluster-b"},
|
||||
})
|
||||
//Get service with serviceName ,group
|
||||
//ClusterName=DEFAULT
|
||||
ExampleServiceClient_GetService(client, vo.GetServiceParam{
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
})
|
||||
|
||||
//SelectAllInstance return all instances,include healthy=false,enable=false,weight<=0
|
||||
//ClusterName=DEFAULT, GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_SelectAllInstances(client, vo.SelectAllInstancesParam{
|
||||
ServiceName: "demo.go",
|
||||
Clusters: []string{"cluster-a"},
|
||||
})
|
||||
|
||||
//SelectAllInstance
|
||||
//GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_SelectAllInstances(client, vo.SelectAllInstancesParam{
|
||||
ServiceName: "demo.go",
|
||||
Clusters: []string{"cluster-a", "cluster-b"},
|
||||
})
|
||||
|
||||
//SelectAllInstance
|
||||
//ClusterName=DEFAULT
|
||||
ExampleServiceClient_SelectAllInstances(client, vo.SelectAllInstancesParam{
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
Clusters: []string{"cluster-a"},
|
||||
})
|
||||
|
||||
//SelectInstances only return the instances of healthy=${HealthyOnly},enable=true and weight>0
|
||||
//ClusterName=DEFAULT,GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_SelectInstances(client, vo.SelectInstancesParam{
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
Clusters: []string{"cluster-a"},
|
||||
})
|
||||
|
||||
//SelectOneHealthyInstance return one instance by WRR strategy for load balance
|
||||
|
@ -216,38 +130,36 @@ func main() {
|
|||
//ClusterName=DEFAULT,GroupName=DEFAULT_GROUP
|
||||
ExampleServiceClient_SelectOneHealthyInstance(client, vo.SelectOneHealthInstanceParam{
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
Clusters: []string{"cluster-a"},
|
||||
})
|
||||
|
||||
//Subscribe key=serviceName+groupName+cluster
|
||||
//Note:We call add multiple SubscribeCallback with the same key.
|
||||
param := &vo.SubscribeParam{
|
||||
ServiceName: "demo.go",
|
||||
Clusters: []string{"cluster-b"},
|
||||
SubscribeCallback: func(services []model.SubscribeService, err error) {
|
||||
GroupName: "group-a",
|
||||
Clusters: []string{"cluster-a"},
|
||||
SubscribeCallback: func(services []model.Instance, err error) {
|
||||
fmt.Printf("callback111 return services:%s \n\n", util.ToJsonString(services))
|
||||
},
|
||||
}
|
||||
ExampleServiceClient_Subscribe(client, param)
|
||||
param2 := &vo.SubscribeParam{
|
||||
ServiceName: "demo.go",
|
||||
Clusters: []string{"cluster-b"},
|
||||
SubscribeCallback: func(services []model.SubscribeService, err error) {
|
||||
fmt.Printf("callback222 return services:%s \n\n", util.ToJsonString(services))
|
||||
},
|
||||
}
|
||||
ExampleServiceClient_Subscribe(client, param2)
|
||||
|
||||
ExampleServiceClient_RegisterServiceInstance(client, vo.RegisterInstanceParam{
|
||||
Ip: "10.0.0.112",
|
||||
Ip: "10.0.0.10",
|
||||
Port: 8848,
|
||||
ServiceName: "demo.go",
|
||||
GroupName: "group-a",
|
||||
ClusterName: "cluster-a",
|
||||
Weight: 10,
|
||||
ClusterName: "cluster-b",
|
||||
Enable: true,
|
||||
Healthy: true,
|
||||
Ephemeral: true,
|
||||
Metadata: map[string]string{"idc": "beijing"},
|
||||
})
|
||||
//wait for client pull change from server
|
||||
time.Sleep(10 * time.Second)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
//Now we just unsubscribe callback1, and callback2 will still receive change event
|
||||
ExampleServiceClient_UnSubscribe(client, param)
|
||||
|
@ -259,7 +171,7 @@ func main() {
|
|||
Cluster: "cluster-b",
|
||||
})
|
||||
//wait for client pull change from server
|
||||
time.Sleep(10 * time.Second)
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
//GeAllService will get the list of service name
|
||||
//NameSpace default value is public.If the client set the namespaceId, NameSpace will use it.
|
||||
|
@ -268,10 +180,4 @@ func main() {
|
|||
PageNo: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
|
||||
ExampleServiceClient_GetAllService(client, vo.GetAllServiceInfoParam{
|
||||
NameSpace: "0e83cc81-9d8c-4bb8-a28a-ff703187543f",
|
||||
PageNo: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -19,8 +19,9 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
|
||||
"github.com/nacos-group/nacos-sdk-go/vo"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/vo"
|
||||
)
|
||||
|
||||
func ExampleServiceClient_RegisterServiceInstance(client naming_client.INamingClient, param vo.RegisterInstanceParam) {
|
||||
|
@ -50,7 +51,7 @@ func ExampleServiceClient_SelectInstances(client naming_client.INamingClient, pa
|
|||
|
||||
func ExampleServiceClient_SelectOneHealthyInstance(client naming_client.INamingClient, param vo.SelectOneHealthInstanceParam) {
|
||||
instances, _ := client.SelectOneHealthyInstance(param)
|
||||
fmt.Printf("SelectInstances,param:%+v, result:%+v \n\n", param, instances)
|
||||
fmt.Printf("SelectOneHealthyInstance,param:%+v, result:%+v \n\n", param, instances)
|
||||
}
|
||||
|
||||
func ExampleServiceClient_Subscribe(client naming_client.INamingClient, param *vo.SubscribeParam) {
|
||||
|
|
6
go.mod
6
go.mod
|
@ -1,6 +1,6 @@
|
|||
module github.com/nacos-group/nacos-sdk-go
|
||||
module github.com/nacos-group/nacos-sdk-go/v2
|
||||
|
||||
go 1.12
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18
|
||||
|
@ -8,6 +8,7 @@ require (
|
|||
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
|
||||
github.com/go-errors/errors v1.0.1
|
||||
github.com/golang/mock v1.3.1
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
|
||||
github.com/jonboulle/clockwork v0.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.6 // indirect
|
||||
|
@ -19,5 +20,6 @@ require (
|
|||
github.com/tebeka/strftime v0.1.3 // indirect
|
||||
github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3
|
||||
go.uber.org/zap v1.15.0
|
||||
google.golang.org/grpc v1.36.1
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127
|
||||
)
|
||||
|
|
77
go.sum
77
go.sum
|
@ -1,20 +1,51 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 h1:zOVTBdCKFd9JbCKz9/nt+FovbjPFmb7mUnp8nH9fQBA=
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.18/go.mod h1:v8ESoHo4SyHmuB4b1tJqDHxfTGEciD+yhvOU/5s1Rfk=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
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/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.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 h1:Ghm4eQYC0nEPnSJdVkTrXpu9KtoVCSo1hg7mtI7G9KU=
|
||||
github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239/go.mod h1:Gdwt2ce0yfBxPvZrHkprdPPTTS3N5rwmLE8T22KBXlw=
|
||||
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/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/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 h1:IPJ3dvxmJ4uczJe5YQdrYB16oTJlGSC/OyZDqUk9xX4=
|
||||
|
@ -49,6 +80,7 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
|
@ -73,26 +105,69 @@ go.uber.org/zap v1.15.0 h1:ZZCA22JRF2gQE5FoNmhmrf7jeJJ2uhqDUNRYKm8dvmM=
|
|||
go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
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-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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.36.1 h1:cmUfbeGKnz9+2DD/UYsMQXeqbHZqZDs4eQwW0sFOpBY=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
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=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
||||
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 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
|
@ -102,5 +177,7 @@ gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk=
|
|||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
|
|
|
@ -31,3 +31,16 @@ type ConfigPage struct {
|
|||
PagesAvailable int `param:"pagesAvailable"`
|
||||
PageItems []ConfigItem `param:"pageItems"`
|
||||
}
|
||||
|
||||
type ConfigListenContext struct {
|
||||
Group string `json:"group"`
|
||||
Md5 string `json:"md5"`
|
||||
DataId string `json:"dataId"`
|
||||
Tenant string `json:"tenant"`
|
||||
}
|
||||
|
||||
type ConfigContext struct {
|
||||
Group string `json:"group"`
|
||||
DataId string `json:"dataId"`
|
||||
Tenant string `json:"tenant"`
|
||||
}
|
||||
|
|
|
@ -24,31 +24,32 @@ const (
|
|||
)
|
||||
|
||||
type Instance struct {
|
||||
Valid bool `json:"valid"`
|
||||
Marked bool `json:"marked"`
|
||||
InstanceId string `json:"instanceId"`
|
||||
Port uint64 `json:"port"`
|
||||
Ip string `json:"ip"`
|
||||
Port uint64 `json:"port"`
|
||||
Weight float64 `json:"weight"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
Healthy bool `json:"healthy"`
|
||||
Enable bool `json:"enabled"`
|
||||
Ephemeral bool `json:"ephemeral"`
|
||||
ClusterName string `json:"clusterName"`
|
||||
ServiceName string `json:"serviceName"`
|
||||
Enable bool `json:"enabled"`
|
||||
Healthy bool `json:"healthy"`
|
||||
Ephemeral bool `json:"ephemeral"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
InstanceHeartBeatInterval int `json:"instanceHeartBeatInterval"`
|
||||
IpDeleteTimeout int `json:"ipDeleteTimeout"`
|
||||
InstanceHeartBeatTimeOut int `json:"instanceHeartBeatTimeOut"`
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
Dom string `json:"dom"`
|
||||
CacheMillis uint64 `json:"cacheMillis"`
|
||||
UseSpecifiedURL bool `json:"useSpecifiedUrl"`
|
||||
Hosts []Instance `json:"hosts"`
|
||||
Checksum string `json:"checksum"`
|
||||
LastRefTime uint64 `json:"lastRefTime"`
|
||||
Env string `json:"env"`
|
||||
Clusters string `json:"clusters"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
Name string `json:"name"`
|
||||
GroupName string `json:"groupName"`
|
||||
Valid bool `json:"valid"`
|
||||
AllIPs bool `json:"allIPs"`
|
||||
ReachProtectionThreshold bool `json:"reachProtectionThreshold"`
|
||||
}
|
||||
|
||||
type ServiceDetail struct {
|
||||
|
@ -84,18 +85,6 @@ type ClusterHealthChecker struct {
|
|||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type SubscribeService struct {
|
||||
ClusterName string `json:"clusterName"`
|
||||
Enable bool `json:"enable"`
|
||||
InstanceId string `json:"instanceId"`
|
||||
Ip string `json:"ip"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
Port uint64 `json:"port"`
|
||||
ServiceName string `json:"serviceName"`
|
||||
Valid bool `json:"valid"`
|
||||
Weight float64 `json:"weight"`
|
||||
}
|
||||
|
||||
type BeatInfo struct {
|
||||
Ip string `json:"ip"`
|
||||
Port uint64 `json:"port"`
|
||||
|
|
|
@ -23,9 +23,9 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/model"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
)
|
||||
|
||||
func CurrentMillis() int64 {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
package util
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
const SHOW_CONTENT_SIZE = 100
|
||||
|
||||
func TruncateContent(content string) string {
|
||||
if content == "" {
|
||||
return ""
|
||||
}
|
||||
if len(content) <= SHOW_CONTENT_SIZE {
|
||||
return content
|
||||
}
|
||||
return content[0:SHOW_CONTENT_SIZE]
|
||||
}
|
|
@ -22,7 +22,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/nacos-group/nacos-sdk-go/common/logger"
|
||||
"github.com/nacos-group/nacos-sdk-go/v2/common/logger"
|
||||
)
|
||||
|
||||
func TransformObject2Param(object interface{}) (params map[string]string) {
|
||||
|
|
|
@ -1,6 +1,21 @@
|
|||
/*
|
||||
* 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/nacos-group/nacos-sdk-go/common/constant"
|
||||
import "github.com/nacos-group/nacos-sdk-go/v2/common/constant"
|
||||
|
||||
type NacosClientParam struct {
|
||||
ClientConfig *constant.ClientConfig // optional
|
||||
|
|
|
@ -22,7 +22,12 @@ type ConfigParam struct {
|
|||
DataId string `param:"dataId"` //required
|
||||
Group string `param:"group"` //required
|
||||
Content string `param:"content"` //required
|
||||
DatumId string `param:"datumId"`
|
||||
Tag string `param:"tag"`
|
||||
AppName string `param:"appName"`
|
||||
BetaIps string `param:"betaIps"`
|
||||
CasMd5 string `param:"casMd5"`
|
||||
Type string `param:"type"`
|
||||
EncryptedDataKey string `param:"encryptedDataKey"`
|
||||
OnChange func(namespace, group, dataId, data string)
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package vo
|
||||
|
||||
import "github.com/nacos-group/nacos-sdk-go/model"
|
||||
import "github.com/nacos-group/nacos-sdk-go/v2/model"
|
||||
|
||||
type RegisterInstanceParam struct {
|
||||
Ip string `param:"ip"` //required
|
||||
|
@ -57,7 +57,7 @@ type SubscribeParam struct {
|
|||
ServiceName string `param:"serviceName"` //required
|
||||
Clusters []string `param:"clusters"` //optional,default:DEFAULT
|
||||
GroupName string `param:"groupName"` //optional,default:DEFAULT_GROUP
|
||||
SubscribeCallback func(services []model.SubscribeService, err error) //required
|
||||
SubscribeCallback func(services []model.Instance, err error) //required
|
||||
}
|
||||
|
||||
type SelectAllInstancesParam struct {
|
||||
|
|
Loading…
Reference in New Issue