├── .github ├── ISSUE_TEMPLATE │ ├── bug.md │ ├── feature.md │ └── question.md └── workflows │ └── go.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── README_CN.md ├── api ├── grpc │ └── nacos_grpc_service.pb.go └── proto │ └── nacos_grpc_service.proto ├── clients ├── cache │ ├── concurrent_map.go │ ├── const.go │ ├── disk_cache.go │ └── disk_cache_test.go ├── client_factory.go ├── client_factory_test.go ├── config_client │ ├── config_client.go │ ├── config_client_interface.go │ ├── config_client_test.go │ ├── config_connection_event_listener.go │ ├── config_connection_event_listener_test.go │ ├── config_proxy.go │ ├── config_proxy_interface.go │ ├── limiter.go │ └── limiter_test.go ├── nacos_client │ ├── nacos_client.go │ └── nacos_client_interface.go └── naming_client │ ├── naming_cache │ ├── service_info_holder.go │ ├── service_info_holder_test.go │ ├── subscribe_callback.go │ └── subscribe_callback_test.go │ ├── naming_client.go │ ├── naming_client_interface.go │ ├── naming_client_test.go │ ├── naming_grpc │ ├── connection_event_listener.go │ ├── connection_event_listener_test.go │ ├── naming_grpc_proxy.go │ └── naming_grpc_proxy_test.go │ ├── naming_http │ ├── beat_reactor.go │ ├── beat_reactor_test.go │ ├── naming_http_proxy.go │ └── push_receiver.go │ ├── naming_instance_chooser.go │ ├── naming_proxy │ ├── proxy_interface.go │ └── proxy_interface_mock.go │ ├── naming_proxy_delegate.go │ └── service_info_updater.go ├── common ├── constant │ ├── client_config_options.go │ ├── client_config_options_test.go │ ├── config.go │ ├── const.go │ ├── preserved_metadata_keys.go │ ├── server_config_options.go │ ├── server_config_options_test.go │ ├── server_tls_options.go │ └── server_tls_options_test.go ├── encoding │ └── encryption.go ├── encryption │ ├── aes_ecb_pkcs5padding.go │ ├── const.go │ ├── handler.go │ ├── kms_client.go │ └── kms_plugins.go ├── file │ ├── file.go │ └── file_test.go ├── filter │ ├── config_encryption_filter.go │ └── config_filter.go ├── http_agent │ ├── delete.go │ ├── fake_http_response.go │ ├── get.go │ ├── http_agent.go │ ├── http_agent_interface.go │ ├── post.go │ └── put.go ├── logger │ ├── logger.go │ ├── logger_test.go │ └── logging.go ├── monitor │ ├── monitor.go │ └── monitor_test.go ├── nacos_error │ └── nacos_error.go ├── nacos_server │ ├── nacos_server.go │ └── nacos_server_test.go ├── remote │ └── rpc │ │ ├── connection.go │ │ ├── connection_event_listener.go │ │ ├── connection_test.go │ │ ├── grpc_client.go │ │ ├── grpc_connection.go │ │ ├── rpc_client.go │ │ ├── rpc_client_test.go │ │ ├── rpc_request │ │ ├── config_request.go │ │ ├── internal_request.go │ │ ├── naming_request.go │ │ └── rpc_request.go │ │ ├── rpc_response │ │ ├── config_response.go │ │ ├── const.go │ │ ├── naming_response.go │ │ ├── rpc_response.go │ │ ├── rpc_response_test.go │ │ └── utils.go │ │ └── server_request_handler.go ├── security │ ├── nacos_auth_client.go │ ├── nacos_auth_client_test.go │ ├── ram_auth_client.go │ ├── ram_credential_provider.go │ ├── resource_injector.go │ ├── resource_injector_test.go │ ├── security_proxy.go │ └── signature_util.go └── tls │ ├── tls.go │ └── tls_test.go ├── example ├── config-acm │ ├── ak │ ├── main.go │ └── sk ├── config-endpoint │ └── main-endpoint.go ├── config-mse-kmsv3 │ ├── ak │ ├── ca.pem │ ├── client_key.json │ ├── endpoint │ ├── main.go │ ├── password │ └── sk ├── config │ └── main.go └── service │ ├── main.go │ └── service_client_example.go ├── go.mod ├── go.sum ├── inner └── uuid │ ├── codec.go │ ├── codec_test.go │ ├── generator.go │ ├── generator_test.go │ ├── sql.go │ ├── sql_test.go │ ├── uuid.go │ └── uuid_test.go ├── mock ├── mock_config_client_interface.go ├── mock_http_agent_interface.go ├── mock_nacos_client_interface.go └── mock_naming_client_interface.go ├── model ├── config.go └── service.go ├── util ├── common.go ├── content.go ├── md5.go ├── md5_test.go ├── object2param.go ├── object2param_test.go └── semaphore.go └── vo ├── client_param.go ├── config_param.go ├── config_param_test.go └── service_param.go /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Report a bug. 4 | labels: 'Type: Bug' 5 | 6 | --- 7 | 8 | ### What version of nacos-sdk-go are you using? 9 | 10 | ### What version of nacos-sever are you using? 11 | 12 | ### What version of Go are you using (`go version`)? 13 | 14 | ### What operating system (Linux, Windows, …) and version? 15 | 16 | ### What did you do? 17 | If possible, provide a recipe for reproducing the error. 18 | 19 | ### What did you expect to see? 20 | 21 | ### What did you see instead? 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea for nacos-sdk-go 4 | labels: 'Type: Feature' 5 | 6 | --- 7 | 8 | ### Use case(s) - what problem will this feature solve? 9 | 10 | ### Proposed Solution 11 | 12 | ### Alternatives Considered 13 | 14 | ### Additional Context 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question about nacos-sdk-go 4 | labels: 'Type: Question' 5 | 6 | --- 7 | 8 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: "master" 6 | pull_request: 7 | branches: "*" 8 | 9 | jobs: 10 | 11 | build: 12 | name: ubuntu-latest ${{ matrix.config.go_version }} 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | config: 17 | - go_version: 1.18 18 | steps: 19 | 20 | - name: Set up Go 1.x 21 | uses: actions/setup-go@v2 22 | with: 23 | go-version: ${{ matrix.config.go_version }} 24 | id: go 25 | 26 | - name: Check out code into the Go module directory 27 | uses: actions/checkout@v2 28 | 29 | - name: Test 30 | run: | 31 | diff -u <(echo -n) <(gofmt -d -s .) 32 | diff -u <(echo -n) <(goimports -d .) 33 | go test -v -race ./... -coverprofile=coverage.txt -covermode=atomic 34 | 35 | - name: Coverage 36 | run: bash <(curl -s https://codecov.io/bash) 37 | 38 | 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .data 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### Contribution flow 2 | 3 | This is a rough outline of what a contributor's workflow looks like: 4 | 5 | * Fork the current repository 6 | * Create a topic branch from where to base the contribution. This is usually develop. 7 | * Make commits of logical units. 8 | * Make sure commit messages are in the proper format (see below). 9 | * Push changes in a topic branch to your forked repository. 10 | * Before you sending out the pull request, please sync your forked repository with remote repository, this will make your pull request simple and clear. See guide below: 11 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Nacos-sdk-go 2 | Copyright 2018-2020 3 | 4 | This product includes software developed at 5 | The Alibaba MiddleWare Group. 6 | 7 | The concurrent-map project 8 | ============= 9 | This product contains code from the concurrent-map project: 10 | Please visit the concurrent-map github web site for more information: 11 | https://github.com/orcaman/concurrent-map 12 | 13 | Copyright (c) 2014 streamrail 14 | 15 | 16 | The go.uuid project 17 | ============= 18 | This product contains code from the go.uuid project: 19 | Please visit the go.uuid github web site for more information: 20 | https://github.com/satori/go.uuid 21 | 22 | Copyright (C) 2013-2018 by Maxim Bublis 23 | -------------------------------------------------------------------------------- /api/proto/nacos_grpc_service.proto: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | syntax = "proto3"; 19 | 20 | import "google/protobuf/any.proto"; 21 | 22 | option java_multiple_files = true; 23 | option java_package = "com.alibaba.nacos.api.grpc.auto"; 24 | option go_package = "nacos/api/grpc/auto"; 25 | 26 | message Metadata { 27 | string type = 3; 28 | string clientIp = 8; 29 | map headers = 7; 30 | } 31 | 32 | 33 | message Payload { 34 | Metadata metadata = 2; 35 | google.protobuf.Any body = 3; 36 | } 37 | 38 | service RequestStream { 39 | // build a streamRequest 40 | rpc requestStream (Payload) returns (stream Payload) { 41 | } 42 | } 43 | 44 | service Request { 45 | // Sends a commonRequest 46 | rpc request (Payload) returns (Payload) { 47 | } 48 | } 49 | 50 | service BiRequestStream { 51 | // Sends a commonRequest 52 | rpc requestBiStream (stream Payload) returns (stream Payload) { 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /clients/cache/const.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | type ConfigCachedFileType string 4 | 5 | const ( 6 | ConfigContent ConfigCachedFileType = "Config Content" 7 | ConfigEncryptedDataKey ConfigCachedFileType = "Config Encrypted Data Key" 8 | 9 | ENCRYPTED_DATA_KEY_FILE_NAME = "encrypted-data-key" 10 | FAILOVER_FILE_SUFFIX = "_failover" 11 | ) 12 | -------------------------------------------------------------------------------- /clients/cache/disk_cache_test.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import ( 4 | "fmt" 5 | "github.com/nacos-group/nacos-sdk-go/v2/util" 6 | "math/rand" 7 | "os" 8 | "strconv" 9 | "testing" 10 | 11 | "github.com/stretchr/testify/assert" 12 | 13 | "github.com/nacos-group/nacos-sdk-go/v2/common/file" 14 | ) 15 | 16 | var ( 17 | dir = file.GetCurrentPath() 18 | group = "FILE_GROUP" 19 | ns = "chasu" 20 | ) 21 | 22 | func TestWriteAndGetConfigToFile(t *testing.T) { 23 | dataIdSuffix := strconv.Itoa(rand.Intn(1000)) 24 | t.Run("write and get config content", func(t *testing.T) { 25 | dataId := "config_content" + dataIdSuffix 26 | cacheKey := util.GetConfigCacheKey(dataId, group, ns) 27 | configContent := "config content" 28 | 29 | err := WriteConfigToFile(cacheKey, dir, "") 30 | assert.Nil(t, err) 31 | 32 | configFromFile, err := ReadConfigFromFile(cacheKey, dir) 33 | assert.NotNil(t, err) 34 | assert.Equal(t, configFromFile, "") 35 | 36 | err = WriteConfigToFile(cacheKey, dir, configContent) 37 | assert.Nil(t, err) 38 | 39 | fromFile, err := ReadConfigFromFile(cacheKey, dir) 40 | assert.Nil(t, err) 41 | assert.Equal(t, fromFile, configContent) 42 | 43 | err = WriteConfigToFile(cacheKey, dir, "") 44 | assert.Nil(t, err) 45 | 46 | configFromFile, err = ReadConfigFromFile(cacheKey, dir) 47 | assert.Nil(t, err) 48 | assert.Equal(t, configFromFile, "") 49 | }) 50 | 51 | t.Run("write and get config encryptedDataKey", func(t *testing.T) { 52 | dataId := "config_encryptedDataKey" + dataIdSuffix 53 | cacheKey := util.GetConfigCacheKey(dataId, group, ns) 54 | configContent := "config encrypted data key" 55 | 56 | err := WriteEncryptedDataKeyToFile(cacheKey, dir, "") 57 | assert.Nil(t, err) 58 | 59 | configFromFile, err := ReadEncryptedDataKeyFromFile(cacheKey, dir) 60 | assert.Nil(t, err) 61 | assert.Equal(t, configFromFile, "") 62 | 63 | err = WriteEncryptedDataKeyToFile(cacheKey, dir, configContent) 64 | assert.Nil(t, err) 65 | 66 | fromFile, err := ReadEncryptedDataKeyFromFile(cacheKey, dir) 67 | assert.Nil(t, err) 68 | assert.Equal(t, fromFile, configContent) 69 | 70 | err = WriteEncryptedDataKeyToFile(cacheKey, dir, "") 71 | assert.Nil(t, err) 72 | 73 | configFromFile, err = ReadEncryptedDataKeyFromFile(cacheKey, dir) 74 | assert.Nil(t, err) 75 | assert.Equal(t, configFromFile, "") 76 | }) 77 | t.Run("double write config file", func(t *testing.T) { 78 | dataId := "config_encryptedDataKey" + dataIdSuffix 79 | cacheKey := util.GetConfigCacheKey(dataId, group, ns) 80 | configContent := "config encrypted data key" 81 | 82 | err := WriteConfigToFile(cacheKey, dir, configContent) 83 | assert.Nil(t, err) 84 | 85 | err = WriteConfigToFile(cacheKey, dir, configContent) 86 | assert.Nil(t, err) 87 | 88 | fromFile, err := ReadConfigFromFile(cacheKey, dir) 89 | assert.Nil(t, err) 90 | assert.Equal(t, fromFile, configContent) 91 | }) 92 | t.Run("read doesn't existed config file", func(t *testing.T) { 93 | dataId := "config_encryptedDataKey" + dataIdSuffix + strconv.Itoa(rand.Intn(1000)) 94 | cacheKey := util.GetConfigCacheKey(dataId, group, ns) 95 | 96 | _, err := ReadConfigFromFile(cacheKey, dir) 97 | assert.NotNil(t, err) 98 | 99 | _, err = ReadEncryptedDataKeyFromFile(cacheKey, dir) 100 | assert.Nil(t, err) 101 | }) 102 | } 103 | 104 | func TestGetFailover(t *testing.T) { 105 | cacheKey := "test_failOver" 106 | fileContent := "test_failover" 107 | t.Run("writeContent", func(t *testing.T) { 108 | filepath := dir + string(os.PathSeparator) + cacheKey + "_failover" 109 | fmt.Println(filepath) 110 | err := writeFileContent(filepath, fileContent) 111 | assert.Nil(t, err) 112 | }) 113 | t.Run("getContent", func(t *testing.T) { 114 | content := GetFailover(cacheKey, dir) 115 | assert.Equal(t, content, fileContent) 116 | }) 117 | t.Run("clearContent", func(t *testing.T) { 118 | filepath := dir + string(os.PathSeparator) + cacheKey + "_failover" 119 | err := writeFileContent(filepath, "") 120 | assert.Nil(t, err) 121 | }) 122 | } 123 | 124 | // write file content 125 | func writeFileContent(filepath, content string) error { 126 | return os.WriteFile(filepath, []byte(content), 0666) 127 | } 128 | -------------------------------------------------------------------------------- /clients/client_factory.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package clients 18 | 19 | import ( 20 | "github.com/pkg/errors" 21 | 22 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client" 23 | 24 | "github.com/nacos-group/nacos-sdk-go/v2/clients/config_client" 25 | "github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client" 26 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 27 | "github.com/nacos-group/nacos-sdk-go/v2/common/http_agent" 28 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 29 | ) 30 | 31 | // CreateConfigClient use to create config client 32 | func CreateConfigClient(properties map[string]interface{}) (iClient config_client.IConfigClient, err error) { 33 | param := getConfigParam(properties) 34 | return NewConfigClient(param) 35 | } 36 | 37 | // CreateNamingClient use to create a nacos naming client 38 | func CreateNamingClient(properties map[string]interface{}) (iClient naming_client.INamingClient, err error) { 39 | param := getConfigParam(properties) 40 | return NewNamingClient(param) 41 | } 42 | 43 | func NewConfigClient(param vo.NacosClientParam) (iClient config_client.IConfigClient, err error) { 44 | nacosClient, err := setConfig(param) 45 | if err != nil { 46 | return 47 | } 48 | config, err := config_client.NewConfigClientWithRamCredentialProvider(nacosClient, param.RamCredentialProvider) 49 | if err != nil { 50 | return 51 | } 52 | iClient = config 53 | return 54 | } 55 | 56 | func NewNamingClient(param vo.NacosClientParam) (iClient naming_client.INamingClient, err error) { 57 | nacosClient, err := setConfig(param) 58 | if err != nil { 59 | return 60 | } 61 | naming, err := naming_client.NewNamingClientWithRamCredentialProvider(nacosClient, param.RamCredentialProvider) 62 | if err != nil { 63 | return 64 | } 65 | iClient = naming 66 | return 67 | } 68 | 69 | func getConfigParam(properties map[string]interface{}) (param vo.NacosClientParam) { 70 | 71 | if clientConfigTmp, exist := properties[constant.KEY_CLIENT_CONFIG]; exist { 72 | if clientConfig, ok := clientConfigTmp.(constant.ClientConfig); ok { 73 | param.ClientConfig = &clientConfig 74 | } 75 | } 76 | if serverConfigTmp, exist := properties[constant.KEY_SERVER_CONFIGS]; exist { 77 | if serverConfigs, ok := serverConfigTmp.([]constant.ServerConfig); ok { 78 | param.ServerConfigs = serverConfigs 79 | } 80 | } 81 | return 82 | } 83 | 84 | func setConfig(param vo.NacosClientParam) (iClient nacos_client.INacosClient, err error) { 85 | client := &nacos_client.NacosClient{} 86 | if param.ClientConfig == nil { 87 | // default clientConfig 88 | _ = client.SetClientConfig(constant.ClientConfig{ 89 | TimeoutMs: 10 * 1000, 90 | BeatInterval: 5 * 1000, 91 | }) 92 | } else { 93 | err = client.SetClientConfig(*param.ClientConfig) 94 | if err != nil { 95 | return nil, err 96 | } 97 | } 98 | 99 | if len(param.ServerConfigs) == 0 { 100 | clientConfig, _ := client.GetClientConfig() 101 | if len(clientConfig.Endpoint) <= 0 { 102 | err = errors.New("server configs not found in properties") 103 | return nil, err 104 | } 105 | _ = client.SetServerConfig(nil) 106 | } else { 107 | for i := range param.ServerConfigs { 108 | if param.ServerConfigs[i].Port == 0 { 109 | param.ServerConfigs[i].Port = 8848 110 | } 111 | if param.ServerConfigs[i].GrpcPort == 0 { 112 | param.ServerConfigs[i].GrpcPort = param.ServerConfigs[i].Port + constant.RpcPortOffset 113 | } 114 | } 115 | err = client.SetServerConfig(param.ServerConfigs) 116 | if err != nil { 117 | return nil, err 118 | } 119 | } 120 | 121 | if _, _err := client.GetHttpAgent(); _err != nil { 122 | if clientCfg, err := client.GetClientConfig(); err == nil { 123 | _ = client.SetHttpAgent(&http_agent.HttpAgent{TlsConfig: clientCfg.TLSCfg}) 124 | } 125 | } 126 | iClient = client 127 | return 128 | } 129 | -------------------------------------------------------------------------------- /clients/client_factory_test.go: -------------------------------------------------------------------------------- 1 | package clients 2 | 3 | import ( 4 | "net" 5 | "reflect" 6 | "testing" 7 | 8 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 9 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func getIntranetIP() string { 14 | addrs, err := net.InterfaceAddrs() 15 | if err != nil { 16 | return "127.0.0.1" 17 | } 18 | 19 | for _, address := range addrs { 20 | if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { 21 | if ipnet.IP.To4() != nil { 22 | return ipnet.IP.String() 23 | } 24 | } 25 | } 26 | return "127.0.0.1" 27 | } 28 | 29 | func TestSetConfigClient(t *testing.T) { 30 | ip := getIntranetIP() 31 | sc := []constant.ServerConfig{ 32 | *constant.NewServerConfig( 33 | ip, 34 | 8848, 35 | ), 36 | } 37 | 38 | cc := *constant.NewClientConfig( 39 | constant.WithNamespaceId("public"), 40 | constant.WithTimeoutMs(5000), 41 | constant.WithNotLoadCacheAtStart(true), 42 | constant.WithLogDir("/tmp/nacos/log"), 43 | constant.WithCacheDir("/tmp/nacos/cache"), 44 | constant.WithLogLevel("debug"), 45 | ) 46 | 47 | t.Run("setConfig_error", func(t *testing.T) { 48 | nacosClient, err := setConfig(vo.NacosClientParam{}) 49 | assert.Nil(t, nacosClient) 50 | assert.Equal(t, "server configs not found in properties", err.Error()) 51 | }) 52 | 53 | t.Run("setConfig_normal", func(t *testing.T) { 54 | // use map params setConfig 55 | param := getConfigParam(map[string]interface{}{ 56 | "serverConfigs": sc, 57 | "clientConfig": cc, 58 | }) 59 | nacosClientFromMap, err := setConfig(param) 60 | assert.Nil(t, err) 61 | nacosClientFromStruct, err := setConfig(vo.NacosClientParam{ 62 | ClientConfig: &cc, 63 | ServerConfigs: sc, 64 | }) 65 | assert.Nil(t, err) 66 | assert.True(t, reflect.DeepEqual(nacosClientFromMap, nacosClientFromStruct)) 67 | }) 68 | } 69 | -------------------------------------------------------------------------------- /clients/config_client/config_client_interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package config_client 18 | 19 | import ( 20 | "github.com/nacos-group/nacos-sdk-go/v2/model" 21 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 22 | ) 23 | 24 | //go:generate mockgen -destination ../../mock/mock_config_client_interface.go -package mock -source=./config_client_interface.go 25 | 26 | type IConfigClient interface { 27 | // GetConfig use to get config from nacos server 28 | // dataId require 29 | // group require 30 | // tenant ==>nacos.namespace optional 31 | GetConfig(param vo.ConfigParam) (string, error) 32 | 33 | // PublishConfig use to publish config to nacos server 34 | // dataId require 35 | // group require 36 | // content require 37 | // tenant ==>nacos.namespace optional 38 | PublishConfig(param vo.ConfigParam) (bool, error) 39 | 40 | // DeleteConfig use to delete config 41 | // dataId require 42 | // group require 43 | // tenant ==>nacos.namespace optional 44 | DeleteConfig(param vo.ConfigParam) (bool, error) 45 | 46 | // ListenConfig use to listen config change,it will callback OnChange() when config change 47 | // dataId require 48 | // group require 49 | // onchange require 50 | // tenant ==>nacos.namespace optional 51 | ListenConfig(params vo.ConfigParam) (err error) 52 | 53 | //CancelListenConfig use to cancel listen config change 54 | // dataId require 55 | // group require 56 | // tenant ==>nacos.namespace optional 57 | CancelListenConfig(params vo.ConfigParam) (err error) 58 | 59 | // SearchConfig use to search nacos config 60 | // search require search=accurate--精确搜索 search=blur--模糊搜索 61 | // group option 62 | // dataId option 63 | // tenant ==>nacos.namespace optional 64 | // pageNo option,default is 1 65 | // pageSize option,default is 10 66 | SearchConfig(param vo.SearchConfigParam) (*model.ConfigPage, error) 67 | 68 | // CloseClient Close the GRPC client 69 | CloseClient() 70 | } 71 | -------------------------------------------------------------------------------- /clients/config_client/config_connection_event_listener.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package config_client 18 | 19 | import ( 20 | "strconv" 21 | 22 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 23 | ) 24 | 25 | type ConfigConnectionEventListener struct { 26 | client *ConfigClient 27 | taskId string 28 | } 29 | 30 | func NewConfigConnectionEventListener(client *ConfigClient, taskId string) *ConfigConnectionEventListener { 31 | return &ConfigConnectionEventListener{ 32 | client: client, 33 | taskId: taskId, 34 | } 35 | } 36 | 37 | func (c *ConfigConnectionEventListener) OnConnected() { 38 | logger.Info("[ConfigConnectionEventListener] connect to config server for taskId: " + c.taskId) 39 | if c.client != nil { 40 | c.client.asyncNotifyListenConfig() 41 | } 42 | } 43 | 44 | func (c *ConfigConnectionEventListener) OnDisConnect() { 45 | logger.Info("[ConfigConnectionEventListener] disconnect from config server for taskId: " + c.taskId) 46 | 47 | if c.client != nil { 48 | taskIdInt, err := strconv.Atoi(c.taskId) 49 | if err != nil { 50 | logger.Errorf("[ConfigConnectionEventListener] parse taskId error: %v", err) 51 | return 52 | } 53 | 54 | items := c.client.cacheMap.Items() 55 | for key, v := range items { 56 | if data, ok := v.(cacheData); ok { 57 | if data.taskId == taskIdInt { 58 | data.isSyncWithServer = false 59 | c.client.cacheMap.Set(key, data) 60 | } 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /clients/config_client/config_proxy_interface.go: -------------------------------------------------------------------------------- 1 | package config_client 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc" 7 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request" 8 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response" 9 | "github.com/nacos-group/nacos-sdk-go/v2/model" 10 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 11 | ) 12 | 13 | type IConfigProxy interface { 14 | queryConfig(dataId, group, tenant string, timeout uint64, notify bool, client *ConfigClient) (*rpc_response.ConfigQueryResponse, error) 15 | searchConfigProxy(param vo.SearchConfigParam, tenant, accessKey, secretKey string) (*model.ConfigPage, error) 16 | requestProxy(rpcClient *rpc.RpcClient, request rpc_request.IRequest, timeoutMills uint64) (rpc_response.IResponse, error) 17 | createRpcClient(ctx context.Context, taskId string, client *ConfigClient) *rpc.RpcClient 18 | getRpcClient(client *ConfigClient) *rpc.RpcClient 19 | } 20 | -------------------------------------------------------------------------------- /clients/config_client/limiter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package config_client 18 | 19 | import ( 20 | "sync" 21 | "time" 22 | 23 | "github.com/nacos-group/nacos-sdk-go/v2/clients/cache" 24 | "golang.org/x/time/rate" 25 | ) 26 | 27 | type rateLimiterCheck struct { 28 | rateLimiterCache cache.ConcurrentMap // cache 29 | mux sync.Mutex 30 | } 31 | 32 | var checker rateLimiterCheck 33 | 34 | func init() { 35 | checker = rateLimiterCheck{ 36 | rateLimiterCache: cache.NewConcurrentMap(), 37 | mux: sync.Mutex{}, 38 | } 39 | } 40 | 41 | // IsLimited return true when request is limited 42 | func IsLimited(checkKey string) bool { 43 | checker.mux.Lock() 44 | defer checker.mux.Unlock() 45 | var limiter *rate.Limiter 46 | lm, exist := checker.rateLimiterCache.Get(checkKey) 47 | if !exist { 48 | // define a new limiter,allow 5 times per second,and reserve stock is 5. 49 | limiter = rate.NewLimiter(rate.Limit(5), 5) 50 | checker.rateLimiterCache.Set(checkKey, limiter) 51 | } else { 52 | limiter = lm.(*rate.Limiter) 53 | } 54 | add := time.Now().Add(time.Second) 55 | return !limiter.AllowN(add, 1) 56 | } 57 | -------------------------------------------------------------------------------- /clients/config_client/limiter_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package config_client 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 23 | 24 | "github.com/stretchr/testify/assert" 25 | ) 26 | 27 | func TestLimiter(t *testing.T) { 28 | client := createConfigClientTest() 29 | success, err := client.PublishConfig(vo.ConfigParam{ 30 | DataId: localConfigTest.DataId, 31 | Group: "default-group", 32 | Content: "hello world"}) 33 | 34 | assert.Nil(t, err) 35 | assert.True(t, success) 36 | 37 | for i := 0; i <= 10; i++ { 38 | content, err := client.GetConfig(vo.ConfigParam{ 39 | DataId: localConfigTest.DataId, 40 | Group: "default-group"}) 41 | if i > 4 { 42 | assert.NotNil(t, err) 43 | } else { 44 | assert.Nil(t, err) 45 | assert.Equal(t, "hello world", content) 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /clients/nacos_client/nacos_client.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package nacos_client 18 | 19 | import ( 20 | "os" 21 | "strconv" 22 | 23 | "github.com/pkg/errors" 24 | 25 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 26 | "github.com/nacos-group/nacos-sdk-go/v2/common/file" 27 | "github.com/nacos-group/nacos-sdk-go/v2/common/http_agent" 28 | ) 29 | 30 | type NacosClient struct { 31 | clientConfigValid bool 32 | serverConfigsValid bool 33 | agent http_agent.IHttpAgent 34 | clientConfig constant.ClientConfig 35 | serverConfigs []constant.ServerConfig 36 | } 37 | 38 | // SetClientConfig is use to set nacos client Config 39 | func (client *NacosClient) SetClientConfig(config constant.ClientConfig) (err error) { 40 | if config.TimeoutMs <= 0 { 41 | config.TimeoutMs = 10 * 1000 42 | } 43 | 44 | if config.BeatInterval <= 0 { 45 | config.BeatInterval = 5 * 1000 46 | } 47 | 48 | if config.UpdateThreadNum <= 0 { 49 | config.UpdateThreadNum = 20 50 | } 51 | 52 | if len(config.LogLevel) == 0 { 53 | config.LogLevel = "info" 54 | } 55 | 56 | if config.CacheDir == "" { 57 | config.CacheDir = file.GetCurrentPath() + string(os.PathSeparator) + "cache" 58 | } 59 | 60 | if config.LogDir == "" { 61 | config.LogDir = file.GetCurrentPath() + string(os.PathSeparator) + "log" 62 | } 63 | 64 | client.clientConfig = config 65 | client.clientConfigValid = true 66 | 67 | return 68 | } 69 | 70 | // SetServerConfig is use to set nacos server config 71 | func (client *NacosClient) SetServerConfig(configs []constant.ServerConfig) (err error) { 72 | if len(configs) <= 0 { 73 | //it's may be use endpoint to get nacos server address 74 | client.serverConfigsValid = true 75 | return 76 | } 77 | 78 | for i := 0; i < len(configs); i++ { 79 | if len(configs[i].IpAddr) <= 0 || configs[i].Port <= 0 || configs[i].Port > 65535 { 80 | err = errors.New("[client.SetServerConfig] configs[" + strconv.Itoa(i) + "] is invalid") 81 | return 82 | } 83 | if len(configs[i].ContextPath) <= 0 { 84 | configs[i].ContextPath = constant.DEFAULT_CONTEXT_PATH 85 | } 86 | if len(configs[i].Scheme) <= 0 { 87 | configs[i].Scheme = constant.DEFAULT_SERVER_SCHEME 88 | } 89 | } 90 | client.serverConfigs = configs 91 | client.serverConfigsValid = true 92 | return 93 | } 94 | 95 | // GetClientConfig use to get client config 96 | func (client *NacosClient) GetClientConfig() (config constant.ClientConfig, err error) { 97 | config = client.clientConfig 98 | if !client.clientConfigValid { 99 | err = errors.New("[client.GetClientConfig] invalid client config") 100 | } 101 | return 102 | } 103 | 104 | // GetServerConfig use to get server config 105 | func (client *NacosClient) GetServerConfig() (configs []constant.ServerConfig, err error) { 106 | configs = client.serverConfigs 107 | if !client.serverConfigsValid { 108 | err = errors.New("[client.GetServerConfig] invalid server configs") 109 | } 110 | return 111 | } 112 | 113 | // SetHttpAgent use to set http agent 114 | func (client *NacosClient) SetHttpAgent(agent http_agent.IHttpAgent) (err error) { 115 | if agent == nil { 116 | err = errors.New("[client.SetHttpAgent] http agent can not be nil") 117 | } else { 118 | client.agent = agent 119 | } 120 | return 121 | } 122 | 123 | // GetHttpAgent use to get http agent 124 | func (client *NacosClient) GetHttpAgent() (agent http_agent.IHttpAgent, err error) { 125 | if client.agent == nil { 126 | err = errors.New("[client.GetHttpAgent] invalid http agent") 127 | } else { 128 | agent = client.agent 129 | } 130 | return 131 | } 132 | -------------------------------------------------------------------------------- /clients/nacos_client/nacos_client_interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package nacos_client 18 | 19 | import ( 20 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 21 | "github.com/nacos-group/nacos-sdk-go/v2/common/http_agent" 22 | ) 23 | 24 | //go:generate mockgen -destination mock_nacos_client_interface.go -package nacos_client -source=./nacos_client_interface.go 25 | 26 | type INacosClient interface { 27 | 28 | //SetClientConfig is use to set nacos client config 29 | SetClientConfig(constant.ClientConfig) error 30 | //SetServerConfig is use to set nacos server config 31 | SetServerConfig([]constant.ServerConfig) error 32 | //GetClientConfig use to get client config 33 | GetClientConfig() (constant.ClientConfig, error) 34 | //GetServerConfig use to get server config 35 | GetServerConfig() ([]constant.ServerConfig, error) 36 | //SetHttpAgent use to set http agent 37 | SetHttpAgent(http_agent.IHttpAgent) error 38 | //GetHttpAgent use to get http agent 39 | GetHttpAgent() (http_agent.IHttpAgent, error) 40 | } 41 | -------------------------------------------------------------------------------- /clients/naming_client/naming_cache/service_info_holder_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package naming_cache 17 | 18 | import ( 19 | "fmt" 20 | "math/rand" 21 | "testing" 22 | "time" 23 | 24 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 25 | "github.com/nacos-group/nacos-sdk-go/v2/model" 26 | "github.com/stretchr/testify/assert" 27 | ) 28 | 29 | func TestServiceInfoHolder_isServiceInstanceChanged(t *testing.T) { 30 | rand.Seed(time.Now().Unix()) 31 | defaultIp := createRandomIp() 32 | defaultPort := creatRandomPort() 33 | serviceA := model.Service{ 34 | LastRefTime: 1000, 35 | Hosts: []model.Instance{ 36 | { 37 | Ip: defaultIp, 38 | Port: defaultPort, 39 | }, 40 | { 41 | Ip: defaultIp, 42 | Port: defaultPort + 1, 43 | }, 44 | { 45 | Ip: defaultIp, 46 | Port: defaultPort + 2, 47 | }, 48 | }, 49 | } 50 | serviceB := model.Service{ 51 | LastRefTime: 1001, 52 | Hosts: []model.Instance{ 53 | { 54 | Ip: defaultIp, 55 | Port: defaultPort, 56 | }, 57 | { 58 | Ip: defaultIp, 59 | Port: defaultPort + 3, 60 | }, 61 | { 62 | Ip: defaultIp, 63 | Port: defaultPort + 4, 64 | }, 65 | }, 66 | } 67 | ip := createRandomIp() 68 | serviceC := model.Service{ 69 | LastRefTime: 1001, 70 | Hosts: []model.Instance{ 71 | { 72 | Ip: ip, 73 | Port: defaultPort, 74 | }, 75 | { 76 | Ip: ip, 77 | Port: defaultPort + 3, 78 | }, 79 | { 80 | Ip: ip, 81 | Port: defaultPort + 4, 82 | }, 83 | }, 84 | } 85 | 86 | t.Run("compareWithSelf", func(t *testing.T) { 87 | changed := isServiceInstanceChanged(serviceA, serviceA) 88 | assert.Equal(t, false, changed) 89 | }) 90 | // compareWithIp 91 | t.Run("compareWithIp", func(t *testing.T) { 92 | changed := isServiceInstanceChanged(serviceA, serviceC) 93 | assert.Equal(t, true, changed) 94 | }) 95 | // compareWithPort 96 | t.Run("compareWithPort", func(t *testing.T) { 97 | changed := isServiceInstanceChanged(serviceA, serviceB) 98 | assert.Equal(t, true, changed) 99 | }) 100 | } 101 | 102 | func TestHostReactor_isServiceInstanceChangedWithUnOrdered(t *testing.T) { 103 | rand.Seed(time.Now().Unix()) 104 | serviceA := model.Service{ 105 | LastRefTime: 1001, 106 | Hosts: []model.Instance{ 107 | { 108 | Ip: createRandomIp(), 109 | Port: creatRandomPort(), 110 | }, 111 | { 112 | Ip: createRandomIp(), 113 | Port: creatRandomPort(), 114 | }, 115 | { 116 | Ip: createRandomIp(), 117 | Port: creatRandomPort(), 118 | }, 119 | }, 120 | } 121 | 122 | serviceB := model.Service{ 123 | LastRefTime: 1001, 124 | Hosts: []model.Instance{ 125 | { 126 | Ip: createRandomIp(), 127 | Port: creatRandomPort(), 128 | }, 129 | { 130 | Ip: createRandomIp(), 131 | Port: creatRandomPort(), 132 | }, 133 | { 134 | Ip: createRandomIp(), 135 | Port: creatRandomPort(), 136 | }, 137 | }, 138 | } 139 | logger.Info("serviceA:%s and serviceB:%s are comparing", serviceA.Hosts, serviceB.Hosts) 140 | changed := isServiceInstanceChanged(serviceA, serviceB) 141 | assert.True(t, changed) 142 | } 143 | 144 | // create random ip addr 145 | func createRandomIp() string { 146 | ip := fmt.Sprintf("%d.%d.%d.%d", rand.Intn(255), rand.Intn(255), rand.Intn(255), rand.Intn(255)) 147 | return ip 148 | } 149 | 150 | func creatRandomPort() uint64 { 151 | return rand.Uint64() 152 | } 153 | -------------------------------------------------------------------------------- /clients/naming_client/naming_cache/subscribe_callback.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package naming_cache 18 | 19 | import ( 20 | "sync" 21 | 22 | "github.com/nacos-group/nacos-sdk-go/v2/clients/cache" 23 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 24 | "github.com/nacos-group/nacos-sdk-go/v2/model" 25 | "github.com/nacos-group/nacos-sdk-go/v2/util" 26 | ) 27 | 28 | type SubscribeCallback struct { 29 | callbackFuncMap cache.ConcurrentMap 30 | mux *sync.Mutex 31 | } 32 | 33 | func NewSubscribeCallback() *SubscribeCallback { 34 | return &SubscribeCallback{callbackFuncMap: cache.NewConcurrentMap(), mux: new(sync.Mutex)} 35 | } 36 | 37 | func (ed *SubscribeCallback) IsSubscribed(serviceName, clusters string) bool { 38 | key := util.GetServiceCacheKey(serviceName, clusters) 39 | _, ok := ed.callbackFuncMap.Get(key) 40 | return ok 41 | } 42 | 43 | func (ed *SubscribeCallback) AddCallbackFunc(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) { 44 | key := util.GetServiceCacheKey(serviceName, clusters) 45 | ed.mux.Lock() 46 | defer ed.mux.Unlock() 47 | var funcSlice []*func(services []model.Instance, err error) 48 | old, ok := ed.callbackFuncMap.Get(key) 49 | if ok { 50 | funcSlice = append(funcSlice, old.([]*func(services []model.Instance, err error))...) 51 | } 52 | funcSlice = append(funcSlice, callbackFunc) 53 | ed.callbackFuncMap.Set(key, funcSlice) 54 | } 55 | 56 | func (ed *SubscribeCallback) RemoveCallbackFunc(serviceName string, clusters string, callbackFunc *func(services []model.Instance, err error)) { 57 | logger.Info("removing " + serviceName + " with " + clusters + " to listener map") 58 | key := util.GetServiceCacheKey(serviceName, clusters) 59 | funcs, ok := ed.callbackFuncMap.Get(key) 60 | if ok && funcs != nil { 61 | var newFuncs []*func(services []model.Instance, err error) 62 | for _, funcItem := range funcs.([]*func(services []model.Instance, err error)) { 63 | if funcItem != callbackFunc { 64 | newFuncs = append(newFuncs, funcItem) 65 | } 66 | } 67 | ed.callbackFuncMap.Set(key, newFuncs) 68 | } 69 | 70 | } 71 | 72 | func (ed *SubscribeCallback) ServiceChanged(cacheKey string, service *model.Service) { 73 | funcs, ok := ed.callbackFuncMap.Get(cacheKey) 74 | if ok { 75 | for _, funcItem := range funcs.([]*func(services []model.Instance, err error)) { 76 | (*funcItem)(service.Hosts, nil) 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /clients/naming_client/naming_client_interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package naming_client 18 | 19 | import ( 20 | "github.com/nacos-group/nacos-sdk-go/v2/model" 21 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 22 | ) 23 | 24 | //go:generate mockgen -destination ../../mock/mock_service_client_interface.go -package mock -source=./service_client_interface.go 25 | 26 | // INamingClient interface for naming client 27 | type INamingClient interface { 28 | 29 | // RegisterInstance use to register instance 30 | // Ip require 31 | // Port require 32 | // Weight require,it must be lager than 0 33 | // Enable require,the instance can be access or not 34 | // Healthy require,the instance is health or not 35 | // Metadata optional 36 | // ClusterName optional,default:DEFAULT 37 | // ServiceName require 38 | // GroupName optional,default:DEFAULT_GROUP 39 | // Ephemeral optional 40 | RegisterInstance(param vo.RegisterInstanceParam) (bool, error) 41 | 42 | // BatchRegisterInstance use to batch register instance 43 | // ClusterName optional,default:DEFAULT 44 | // ServiceName require 45 | // GroupName optional,default:DEFAULT_GROUP 46 | // Instances require,batch register instance list (serviceName, groupName in instances do not need to be set) 47 | BatchRegisterInstance(param vo.BatchRegisterInstanceParam) (bool, error) 48 | 49 | // DeregisterInstance use to deregister instance 50 | // Ip required 51 | // Port required 52 | // Tenant optional 53 | // Cluster optional,default:DEFAULT 54 | // ServiceName require 55 | // GroupName optional,default:DEFAULT_GROUP 56 | // Ephemeral optional 57 | DeregisterInstance(param vo.DeregisterInstanceParam) (bool, error) 58 | 59 | // UpdateInstance use to update instance 60 | // Ip require 61 | // Port require 62 | // Weight require,it must be lager than 0 63 | // Enable require,the instance can be access or not 64 | // Healthy require,the instance is health or not 65 | // Metadata optional 66 | // ClusterName optional,default:DEFAULT 67 | // ServiceName require 68 | // GroupName optional,default:DEFAULT_GROUP 69 | // Ephemeral optional 70 | UpdateInstance(param vo.UpdateInstanceParam) (bool, error) 71 | 72 | // GetService use to get service 73 | // ServiceName require 74 | // Clusters optional,default:DEFAULT 75 | // GroupName optional,default:DEFAULT_GROUP 76 | GetService(param vo.GetServiceParam) (model.Service, error) 77 | 78 | // SelectAllInstances return all instances,include healthy=false,enable=false,weight<=0 79 | // ServiceName require 80 | // Clusters optional,default:DEFAULT 81 | // GroupName optional,default:DEFAULT_GROUP 82 | SelectAllInstances(param vo.SelectAllInstancesParam) ([]model.Instance, error) 83 | 84 | // SelectInstances only return the instances of healthy=${HealthyOnly},enable=true and weight>0 85 | // ServiceName require 86 | // Clusters optional,default:DEFAULT 87 | // GroupName optional,default:DEFAULT_GROUP 88 | // HealthyOnly optional 89 | SelectInstances(param vo.SelectInstancesParam) ([]model.Instance, error) 90 | 91 | // SelectOneHealthyInstance return one instance by WRR strategy for load balance 92 | // And the instance should be health=true,enable=true and weight>0 93 | // ServiceName require 94 | // Clusters optional,default:DEFAULT 95 | // GroupName optional,default:DEFAULT_GROUP 96 | SelectOneHealthyInstance(param vo.SelectOneHealthInstanceParam) (*model.Instance, error) 97 | 98 | // Subscribe use to subscribe service change event 99 | // ServiceName require 100 | // Clusters optional,default:DEFAULT 101 | // GroupName optional,default:DEFAULT_GROUP 102 | // SubscribeCallback require 103 | Subscribe(param *vo.SubscribeParam) error 104 | 105 | // Unsubscribe use to unsubscribe service change event 106 | // ServiceName require 107 | // Clusters optional,default:DEFAULT 108 | // GroupName optional,default:DEFAULT_GROUP 109 | // SubscribeCallback require 110 | Unsubscribe(param *vo.SubscribeParam) error 111 | 112 | // GetAllServicesInfo use to get all service info by page 113 | GetAllServicesInfo(param vo.GetAllServiceInfoParam) (model.ServiceList, error) 114 | 115 | // ServerHealthy use to check the connectivity to server 116 | ServerHealthy() bool 117 | 118 | //CloseClient close the GRPC client 119 | CloseClient() 120 | } 121 | -------------------------------------------------------------------------------- /clients/naming_client/naming_grpc/connection_event_listener.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package naming_grpc 18 | 19 | import ( 20 | "strings" 21 | 22 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_proxy" 23 | 24 | "github.com/nacos-group/nacos-sdk-go/v2/clients/cache" 25 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 26 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 27 | "github.com/nacos-group/nacos-sdk-go/v2/model" 28 | "github.com/nacos-group/nacos-sdk-go/v2/util" 29 | ) 30 | 31 | type ConnectionEventListener struct { 32 | clientProxy naming_proxy.INamingProxy 33 | registeredInstanceCached cache.ConcurrentMap 34 | subscribes cache.ConcurrentMap 35 | } 36 | 37 | func NewConnectionEventListener(clientProxy naming_proxy.INamingProxy) *ConnectionEventListener { 38 | return &ConnectionEventListener{ 39 | clientProxy: clientProxy, 40 | registeredInstanceCached: cache.NewConcurrentMap(), 41 | subscribes: cache.NewConcurrentMap(), 42 | } 43 | } 44 | 45 | func (c *ConnectionEventListener) OnConnected() { 46 | c.redoSubscribe() 47 | c.redoRegisterEachService() 48 | } 49 | 50 | func (c *ConnectionEventListener) OnDisConnect() { 51 | 52 | } 53 | 54 | func (c *ConnectionEventListener) redoSubscribe() { 55 | grpcProxy, ok := c.clientProxy.(*NamingGrpcProxy) 56 | if !ok { 57 | logger.Error("redo subscribe clientProxy type error") 58 | return 59 | } 60 | for _, key := range c.subscribes.Keys() { 61 | info := strings.Split(key, constant.SERVICE_INFO_SPLITER) 62 | var err error 63 | var service model.Service 64 | if len(info) > 2 { 65 | service, err = c.clientProxy.Subscribe(info[1], info[0], info[2]) 66 | } else { 67 | service, err = c.clientProxy.Subscribe(info[1], info[0], "") 68 | } 69 | if err != nil { 70 | logger.Warnf("redo subscribe service:%s faild:%+v", info[1], err) 71 | continue 72 | } 73 | grpcProxy.serviceInfoHolder.ProcessService(&service) 74 | } 75 | } 76 | 77 | func (c *ConnectionEventListener) redoRegisterEachService() { 78 | for k, v := range c.registeredInstanceCached.Items() { 79 | info := strings.Split(k, constant.SERVICE_INFO_SPLITER) 80 | serviceName := info[1] 81 | groupName := info[0] 82 | if instance, ok := v.(model.Instance); ok { 83 | if _, err := c.clientProxy.RegisterInstance(serviceName, groupName, instance); err != nil { 84 | logger.Warnf("redo register service:%s groupName:%s faild:%s", info[1], info[0], err.Error()) 85 | continue 86 | } 87 | } 88 | if instances, ok := v.([]model.Instance); ok { 89 | if _, err := c.clientProxy.BatchRegisterInstance(serviceName, groupName, instances); err != nil { 90 | logger.Warnf("redo batch register service:%s groupName:%s faild:%s", info[1], info[0], err.Error()) 91 | continue 92 | } 93 | } 94 | } 95 | } 96 | 97 | func (c *ConnectionEventListener) CacheInstanceForRedo(serviceName, groupName string, instance model.Instance) { 98 | key := util.GetGroupName(serviceName, groupName) 99 | c.registeredInstanceCached.Set(key, instance) 100 | } 101 | 102 | func (c *ConnectionEventListener) CacheInstancesForRedo(serviceName, groupName string, instances []model.Instance) { 103 | key := util.GetGroupName(serviceName, groupName) 104 | c.registeredInstanceCached.Set(key, instances) 105 | } 106 | 107 | func (c *ConnectionEventListener) RemoveInstanceForRedo(serviceName, groupName string, instance model.Instance) { 108 | key := util.GetGroupName(serviceName, groupName) 109 | _, ok := c.registeredInstanceCached.Get(key) 110 | if !ok { 111 | return 112 | } 113 | c.registeredInstanceCached.Remove(key) 114 | } 115 | 116 | func (c *ConnectionEventListener) CacheSubscriberForRedo(fullServiceName, clusters string) { 117 | key := util.GetServiceCacheKey(fullServiceName, clusters) 118 | if !c.IsSubscriberCached(key) { 119 | c.subscribes.Set(key, struct{}{}) 120 | } 121 | } 122 | 123 | func (c *ConnectionEventListener) IsSubscriberCached(key string) bool { 124 | _, ok := c.subscribes.Get(key) 125 | return ok 126 | } 127 | 128 | func (c *ConnectionEventListener) RemoveSubscriberForRedo(fullServiceName, clusters string) { 129 | c.subscribes.Remove(util.GetServiceCacheKey(fullServiceName, clusters)) 130 | } 131 | -------------------------------------------------------------------------------- /clients/naming_client/naming_grpc/connection_event_listener_test.go: -------------------------------------------------------------------------------- 1 | package naming_grpc 2 | 3 | import ( 4 | "github.com/golang/mock/gomock" 5 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_proxy" 6 | "github.com/nacos-group/nacos-sdk-go/v2/util" 7 | "testing" 8 | ) 9 | 10 | func TestRedoSubscribe(t *testing.T) { 11 | t.Skip("Skipping test,It failed due to a previous commit and is difficult to modify because of the use of struct type assertions in the code.") 12 | ctrl := gomock.NewController(t) 13 | defer ctrl.Finish() 14 | 15 | mockProxy := naming_proxy.NewMockINamingProxy(ctrl) 16 | evListener := NewConnectionEventListener(mockProxy) 17 | 18 | cases := []struct { 19 | serviceName string 20 | groupName string 21 | clusters string 22 | }{ 23 | {"service-a", "group-a", ""}, 24 | {"service-b", "group-b", "cluster-b"}, 25 | } 26 | 27 | for _, v := range cases { 28 | fullServiceName := util.GetGroupName(v.serviceName, v.groupName) 29 | evListener.CacheSubscriberForRedo(fullServiceName, v.clusters) 30 | mockProxy.EXPECT().Subscribe(v.serviceName, v.groupName, v.clusters) 31 | evListener.redoSubscribe() 32 | evListener.RemoveSubscriberForRedo(fullServiceName, v.clusters) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /clients/naming_client/naming_grpc/naming_grpc_proxy_test.go: -------------------------------------------------------------------------------- 1 | package naming_grpc 2 | 3 | import "github.com/nacos-group/nacos-sdk-go/v2/model" 4 | 5 | type MockNamingGrpc struct { 6 | } 7 | 8 | func (m *MockNamingGrpc) RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) { 9 | return true, nil 10 | } 11 | 12 | func (m *MockNamingGrpc) BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) { 13 | return true, nil 14 | } 15 | 16 | func (m *MockNamingGrpc) DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) { 17 | return true, nil 18 | } 19 | 20 | func (m *MockNamingGrpc) GetServiceList(pageNo uint32, pageSize uint32, groupName string, selector *model.ExpressionSelector) (model.ServiceList, error) { 21 | return model.ServiceList{Doms: []string{""}}, nil 22 | } 23 | 24 | func (m *MockNamingGrpc) ServerHealthy() bool { 25 | return true 26 | } 27 | 28 | func (m *MockNamingGrpc) QueryInstancesOfService(serviceName, groupName, clusters string, udpPort int, healthyOnly bool) (*model.Service, error) { 29 | return &model.Service{}, nil 30 | } 31 | 32 | func (m *MockNamingGrpc) Subscribe(serviceName, groupName, clusters string) (model.Service, error) { 33 | return model.Service{}, nil 34 | } 35 | 36 | func (m *MockNamingGrpc) Unsubscribe(serviceName, groupName, clusters string) error { 37 | return nil 38 | } 39 | 40 | func (m *MockNamingGrpc) CloseClient() {} 41 | -------------------------------------------------------------------------------- /clients/naming_client/naming_http/beat_reactor_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package naming_http 18 | 19 | import ( 20 | "context" 21 | "testing" 22 | 23 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 24 | "github.com/nacos-group/nacos-sdk-go/v2/common/nacos_server" 25 | "github.com/nacos-group/nacos-sdk-go/v2/model" 26 | "github.com/nacos-group/nacos-sdk-go/v2/util" 27 | "github.com/stretchr/testify/assert" 28 | ) 29 | 30 | func TestBeatReactor_AddBeatInfo(t *testing.T) { 31 | br := NewBeatReactor(context.Background(), constant.ClientConfig{}, &nacos_server.NacosServer{}) 32 | serviceName := "Test" 33 | groupName := "public" 34 | beatInfo := &model.BeatInfo{ 35 | Ip: "127.0.0.1", 36 | Port: 8080, 37 | Metadata: map[string]string{}, 38 | ServiceName: util.GetGroupName(serviceName, groupName), 39 | Cluster: "default", 40 | Weight: 1, 41 | } 42 | br.AddBeatInfo(util.GetGroupName(serviceName, groupName), beatInfo) 43 | key := buildKey(util.GetGroupName(serviceName, groupName), beatInfo.Ip, beatInfo.Port) 44 | result, ok := br.beatMap.Get(key) 45 | assert.Equal(t, ok, true, "key should exists!") 46 | assert.ObjectsAreEqual(result.(*model.BeatInfo), beatInfo) 47 | } 48 | 49 | func TestBeatReactor_RemoveBeatInfo(t *testing.T) { 50 | br := NewBeatReactor(context.Background(), constant.ClientConfig{}, &nacos_server.NacosServer{}) 51 | serviceName := "Test" 52 | groupName := "public" 53 | beatInfo1 := &model.BeatInfo{ 54 | Ip: "127.0.0.1", 55 | Port: 8080, 56 | Metadata: map[string]string{}, 57 | ServiceName: util.GetGroupName(serviceName, groupName), 58 | Cluster: "default", 59 | Weight: 1, 60 | } 61 | br.AddBeatInfo(util.GetGroupName(serviceName, groupName), beatInfo1) 62 | beatInfo2 := &model.BeatInfo{ 63 | Ip: "127.0.0.2", 64 | Port: 8080, 65 | Metadata: map[string]string{}, 66 | ServiceName: util.GetGroupName(serviceName, groupName), 67 | Cluster: "default", 68 | Weight: 1, 69 | } 70 | br.AddBeatInfo(util.GetGroupName(serviceName, groupName), beatInfo2) 71 | br.RemoveBeatInfo(util.GetGroupName(serviceName, groupName), "127.0.0.1", 8080) 72 | key := buildKey(util.GetGroupName(serviceName, groupName), beatInfo2.Ip, beatInfo2.Port) 73 | result, ok := br.beatMap.Get(key) 74 | assert.Equal(t, br.beatMap.Count(), 1, "beatinfo map length should be 1") 75 | assert.Equal(t, ok, true, "key should exists!") 76 | assert.ObjectsAreEqual(result.(*model.BeatInfo), beatInfo2) 77 | 78 | } 79 | -------------------------------------------------------------------------------- /clients/naming_client/naming_instance_chooser.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package naming_client 18 | 19 | import ( 20 | "math/rand" 21 | "sort" 22 | 23 | "github.com/nacos-group/nacos-sdk-go/v2/model" 24 | ) 25 | 26 | type Chooser struct { 27 | data []model.Instance 28 | totals []int 29 | max int 30 | } 31 | 32 | type instance []model.Instance 33 | 34 | func (a instance) Len() int { 35 | return len(a) 36 | } 37 | 38 | func (a instance) Swap(i, j int) { 39 | a[i], a[j] = a[j], a[i] 40 | } 41 | 42 | func (a instance) Less(i, j int) bool { 43 | return a[i].Weight < a[j].Weight 44 | } 45 | 46 | // NewChooser initializes a new Chooser for picking from the provided Choices. 47 | func newChooser(instances []model.Instance) Chooser { 48 | sort.Sort(instance(instances)) 49 | totals := make([]int, len(instances)) 50 | runningTotal := 0 51 | for i, c := range instances { 52 | runningTotal += int(c.Weight) 53 | totals[i] = runningTotal 54 | } 55 | return Chooser{data: instances, totals: totals, max: runningTotal} 56 | } 57 | 58 | func (chs Chooser) pick() model.Instance { 59 | r := rand.Intn(chs.max) + 1 60 | i := sort.SearchInts(chs.totals, r) 61 | return chs.data[i] 62 | } 63 | -------------------------------------------------------------------------------- /clients/naming_client/naming_proxy/proxy_interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package naming_proxy 18 | 19 | import ( 20 | "github.com/nacos-group/nacos-sdk-go/v2/model" 21 | ) 22 | 23 | // INamingProxy ... 24 | type INamingProxy interface { 25 | RegisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) 26 | 27 | BatchRegisterInstance(serviceName string, groupName string, instances []model.Instance) (bool, error) 28 | 29 | DeregisterInstance(serviceName string, groupName string, instance model.Instance) (bool, error) 30 | 31 | GetServiceList(pageNo uint32, pageSize uint32, groupName, namespaceId string, selector *model.ExpressionSelector) (model.ServiceList, error) 32 | 33 | ServerHealthy() bool 34 | 35 | QueryInstancesOfService(serviceName, groupName, clusters string, udpPort int, healthyOnly bool) (*model.Service, error) 36 | 37 | Subscribe(serviceName, groupName, clusters string) (model.Service, error) 38 | 39 | Unsubscribe(serviceName, groupName, clusters string) error 40 | 41 | CloseClient() 42 | } 43 | -------------------------------------------------------------------------------- /clients/naming_client/service_info_updater.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package naming_client 18 | 19 | import ( 20 | "context" 21 | "time" 22 | 23 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache" 24 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_proxy" 25 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 26 | "github.com/nacos-group/nacos-sdk-go/v2/model" 27 | "github.com/nacos-group/nacos-sdk-go/v2/util" 28 | ) 29 | 30 | type ServiceInfoUpdater struct { 31 | ctx context.Context 32 | serviceInfoHolder *naming_cache.ServiceInfoHolder 33 | updateThreadNum int 34 | namingProxy naming_proxy.INamingProxy 35 | } 36 | 37 | func NewServiceInfoUpdater(ctx context.Context, serviceInfoHolder *naming_cache.ServiceInfoHolder, updateThreadNum int, 38 | namingProxy naming_proxy.INamingProxy) *ServiceInfoUpdater { 39 | 40 | return &ServiceInfoUpdater{ 41 | ctx: ctx, 42 | serviceInfoHolder: serviceInfoHolder, 43 | updateThreadNum: updateThreadNum, 44 | namingProxy: namingProxy, 45 | } 46 | } 47 | 48 | func (s *ServiceInfoUpdater) asyncUpdateService() { 49 | sema := util.NewSemaphore(s.updateThreadNum) 50 | for { 51 | select { 52 | case <-s.ctx.Done(): 53 | return 54 | default: 55 | s.serviceInfoHolder.ServiceInfoMap.Range(func(key, value interface{}) bool { 56 | service := value.(model.Service) 57 | lastRefTime, ok := s.serviceInfoHolder.UpdateTimeMap.Load(util.GetServiceCacheKey(util.GetGroupName(service.Name, service.GroupName), 58 | service.Clusters)) 59 | if !ok { 60 | lastRefTime = uint64(0) 61 | } 62 | if uint64(util.CurrentMillis())-lastRefTime.(uint64) > service.CacheMillis { 63 | sema.Acquire() 64 | go func() { 65 | defer sema.Release() 66 | s.updateServiceNow(service.Name, service.GroupName, service.Clusters) 67 | }() 68 | } 69 | return true 70 | }) 71 | time.Sleep(1 * time.Second) 72 | } 73 | } 74 | } 75 | 76 | func (s *ServiceInfoUpdater) updateServiceNow(serviceName, groupName, clusters string) { 77 | result, err := s.namingProxy.QueryInstancesOfService(serviceName, groupName, clusters, 0, false) 78 | 79 | if err != nil { 80 | logger.Errorf("QueryInstances error, serviceName:%s, cluster:%s, err:%v", serviceName, clusters, err) 81 | return 82 | } 83 | s.serviceInfoHolder.ProcessService(result) 84 | } 85 | -------------------------------------------------------------------------------- /common/constant/client_config_options_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package constant 18 | 19 | import ( 20 | "os" 21 | "testing" 22 | 23 | "github.com/nacos-group/nacos-sdk-go/v2/common/file" 24 | 25 | "github.com/stretchr/testify/assert" 26 | ) 27 | 28 | func TestNewClientConfig(t *testing.T) { 29 | config := NewClientConfig() 30 | 31 | assert.Equal(t, config.TimeoutMs, uint64(10000)) 32 | assert.Equal(t, config.Endpoint, "") 33 | assert.Equal(t, config.LogLevel, "info") 34 | assert.Equal(t, config.BeatInterval, int64(5000)) 35 | assert.Equal(t, config.UpdateThreadNum, 20) 36 | 37 | assert.Equal(t, config.LogDir, file.GetCurrentPath()+string(os.PathSeparator)+"log") 38 | assert.Equal(t, config.CacheDir, file.GetCurrentPath()+string(os.PathSeparator)+"cache") 39 | 40 | assert.Equal(t, config.NotLoadCacheAtStart, false) 41 | assert.Equal(t, config.UpdateCacheWhenEmpty, false) 42 | 43 | assert.Equal(t, config.Username, "") 44 | assert.Equal(t, config.Password, "") 45 | assert.Equal(t, config.OpenKMS, false) 46 | assert.Equal(t, config.NamespaceId, "") 47 | assert.Equal(t, config.Username, "") 48 | assert.Equal(t, config.RegionId, "") 49 | assert.Equal(t, config.AccessKey, "") 50 | assert.Equal(t, config.SecretKey, "") 51 | } 52 | 53 | func TestNewClientConfigWithOptions(t *testing.T) { 54 | config := NewClientConfig( 55 | WithTimeoutMs(uint64(20000)), 56 | WithEndpoint("http://console.nacos.io:80"), 57 | WithLogLevel("error"), 58 | WithBeatInterval(int64(2000)), 59 | WithUpdateThreadNum(30), 60 | 61 | WithLogDir("/tmp/nacos/log"), 62 | WithCacheDir("/tmp/nacos/cache"), 63 | 64 | WithNotLoadCacheAtStart(true), 65 | WithUpdateCacheWhenEmpty(true), 66 | 67 | WithUsername("nacos"), 68 | WithPassword("nacos"), 69 | WithOpenKMS(true), 70 | WithRegionId("shanghai"), 71 | WithNamespaceId("namespace_1"), 72 | WithAccessKey("accessKey_1"), 73 | WithSecretKey("secretKey_1"), 74 | ) 75 | 76 | assert.Equal(t, config.TimeoutMs, uint64(20000)) 77 | assert.Equal(t, config.Endpoint, "http://console.nacos.io:80") 78 | assert.Equal(t, config.LogLevel, "error") 79 | assert.Equal(t, config.BeatInterval, int64(2000)) 80 | assert.Equal(t, config.UpdateThreadNum, 30) 81 | 82 | assert.Equal(t, config.LogDir, "/tmp/nacos/log") 83 | assert.Equal(t, config.CacheDir, "/tmp/nacos/cache") 84 | 85 | assert.Equal(t, config.NotLoadCacheAtStart, true) 86 | assert.Equal(t, config.UpdateCacheWhenEmpty, true) 87 | 88 | assert.Equal(t, config.Username, "nacos") 89 | assert.Equal(t, config.Password, "nacos") 90 | assert.Equal(t, config.OpenKMS, true) 91 | assert.Equal(t, config.RegionId, "shanghai") 92 | assert.Equal(t, config.NamespaceId, "namespace_1") 93 | assert.Equal(t, config.AccessKey, "accessKey_1") 94 | assert.Equal(t, config.SecretKey, "secretKey_1") 95 | } 96 | -------------------------------------------------------------------------------- /common/constant/preserved_metadata_keys.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package constant 18 | 19 | const ( 20 | HEART_BEAT_TIMEOUT = "preserved.heart.beat.timeout" 21 | IP_DELETE_TIMEOUT = "preserved.ip.delete.timeout" 22 | HEART_BEAT_INTERVAL = "preserved.heart.beat.interval" 23 | ) 24 | -------------------------------------------------------------------------------- /common/constant/server_config_options.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package constant 18 | 19 | func NewServerConfig(ipAddr string, port uint64, opts ...ServerOption) *ServerConfig { 20 | serverConfig := &ServerConfig{ 21 | IpAddr: ipAddr, 22 | Port: port, 23 | ContextPath: DEFAULT_CONTEXT_PATH, 24 | Scheme: DEFAULT_SERVER_SCHEME, 25 | } 26 | 27 | for _, opt := range opts { 28 | opt(serverConfig) 29 | } 30 | 31 | return serverConfig 32 | } 33 | 34 | // ServerOption ... 35 | type ServerOption func(*ServerConfig) 36 | 37 | //WithScheme set Scheme for server 38 | func WithScheme(scheme string) ServerOption { 39 | return func(config *ServerConfig) { 40 | config.Scheme = scheme 41 | } 42 | } 43 | 44 | //WithContextPath set contextPath for server 45 | func WithContextPath(contextPath string) ServerOption { 46 | return func(config *ServerConfig) { 47 | config.ContextPath = contextPath 48 | } 49 | } 50 | 51 | //WithIpAddr set ip address for server 52 | func WithIpAddr(ipAddr string) ServerOption { 53 | return func(config *ServerConfig) { 54 | config.IpAddr = ipAddr 55 | } 56 | } 57 | 58 | //WithPort set port for server 59 | func WithPort(port uint64) ServerOption { 60 | return func(config *ServerConfig) { 61 | config.Port = port 62 | } 63 | } 64 | 65 | //WithGrpcPort set grpc port for server 66 | func WithGrpcPort(port uint64) ServerOption { 67 | return func(config *ServerConfig) { 68 | config.GrpcPort = port 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /common/constant/server_config_options_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package constant 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestNewServerConfig(t *testing.T) { 26 | config := NewServerConfig("console.nacos.io", 80) 27 | 28 | assert.Equal(t, "console.nacos.io", config.IpAddr) 29 | assert.Equal(t, uint64(80), config.Port) 30 | assert.Equal(t, "/nacos", config.ContextPath) 31 | assert.Equal(t, "http", config.Scheme) 32 | assert.True(t, config.Port > 0 && config.Port < 65535) 33 | } 34 | 35 | func TestNewServerConfigWithOptions(t *testing.T) { 36 | config := NewServerConfig( 37 | "console.nacos.io", 38 | 80, 39 | WithContextPath("/ns"), 40 | WithScheme("https"), 41 | ) 42 | 43 | assert.Equal(t, "console.nacos.io", config.IpAddr) 44 | assert.Equal(t, uint64(80), config.Port) 45 | assert.Equal(t, "/ns", config.ContextPath) 46 | assert.Equal(t, "https", config.Scheme) 47 | assert.True(t, config.Port > 0 && config.Port < 65535) 48 | } 49 | -------------------------------------------------------------------------------- /common/constant/server_tls_options.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package constant 18 | 19 | var SkipVerifyConfig = TLSConfig{Enable: true} 20 | 21 | func NewTLSConfig(opts ...TLSOption) *TLSConfig { 22 | tlsConfig := TLSConfig{Enable: true} 23 | for _, opt := range opts { 24 | opt(&tlsConfig) 25 | } 26 | return &tlsConfig 27 | } 28 | 29 | type TLSOption func(*TLSConfig) 30 | 31 | func WithCA(caFile, serverNameOverride string) TLSOption { 32 | return func(tc *TLSConfig) { 33 | tc.CaFile = caFile 34 | tc.ServerNameOverride = serverNameOverride 35 | } 36 | } 37 | 38 | func WithCertificate(certFile, keyFile string) TLSOption { 39 | return func(tc *TLSConfig) { 40 | tc.CertFile = certFile 41 | tc.KeyFile = keyFile 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /common/constant/server_tls_options_test.go: -------------------------------------------------------------------------------- 1 | package constant 2 | 3 | /* 4 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestNewTLSConfigWithOptions(t *testing.T) { 26 | t.Run("TestNoOption", func(t *testing.T) { 27 | cfg := SkipVerifyConfig 28 | assert.Equal(t, "", cfg.CaFile) 29 | assert.Equal(t, "", cfg.CertFile) 30 | assert.Equal(t, "", cfg.KeyFile) 31 | assert.Equal(t, "", cfg.ServerNameOverride) 32 | }) 33 | 34 | t.Run("TestCAOption", func(t *testing.T) { 35 | cfg := NewTLSConfig( 36 | WithCA("ca", "host"), 37 | ) 38 | assert.Equal(t, "ca", cfg.CaFile) 39 | assert.Equal(t, "", cfg.CertFile) 40 | assert.Equal(t, "", cfg.KeyFile) 41 | assert.Equal(t, "host", cfg.ServerNameOverride) 42 | }) 43 | 44 | t.Run("TestCertOption", func(t *testing.T) { 45 | cfg := NewTLSConfig( 46 | WithCA("ca", "host"), 47 | WithCertificate("cert", "key"), 48 | ) 49 | assert.Equal(t, "ca", cfg.CaFile) 50 | assert.Equal(t, "cert", cfg.CertFile) 51 | assert.Equal(t, "key", cfg.KeyFile) 52 | assert.Equal(t, "host", cfg.ServerNameOverride) 53 | }) 54 | } 55 | -------------------------------------------------------------------------------- /common/encoding/encryption.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package encoding 18 | 19 | import ( 20 | "encoding/base64" 21 | "unicode/utf8" 22 | ) 23 | 24 | func DecodeString2Utf8Bytes(data string) []byte { 25 | resBytes := make([]byte, 0, 8) 26 | if len(data) == 0 { 27 | return resBytes 28 | } 29 | bytesLen := 0 30 | runes := []rune(data) 31 | for _, r := range runes { 32 | bytesLen += utf8.RuneLen(r) 33 | } 34 | resBytes = make([]byte, bytesLen) 35 | pos := 0 36 | for _, r := range runes { 37 | pos += utf8.EncodeRune(resBytes[pos:], r) 38 | } 39 | return resBytes 40 | } 41 | 42 | func EncodeUtf8Bytes2String(bytes []byte) string { 43 | if len(bytes) == 0 { 44 | return "" 45 | } 46 | var startPos, endPos int 47 | resRunes := make([]rune, 0, 8) 48 | for endPos <= len(bytes) { 49 | if utf8.FullRune(bytes[startPos:endPos]) { 50 | decodedRune, _ := utf8.DecodeRune(bytes[startPos:endPos]) 51 | resRunes = append(resRunes, decodedRune) 52 | startPos = endPos 53 | } 54 | endPos++ 55 | } 56 | return string(resRunes) 57 | } 58 | 59 | func DecodeBase64(bytes []byte) ([]byte, error) { 60 | dst := make([]byte, base64.StdEncoding.DecodedLen(len(bytes))) 61 | n, err := base64.StdEncoding.Decode(dst, bytes) 62 | if err != nil { 63 | return nil, err 64 | } 65 | return dst[:n], nil 66 | } 67 | 68 | func EncodeBase64(bytes []byte) ([]byte, error) { 69 | dst := make([]byte, base64.StdEncoding.EncodedLen(len(bytes))) 70 | base64.StdEncoding.Encode(dst, bytes) 71 | return dst[:], nil 72 | } 73 | -------------------------------------------------------------------------------- /common/encryption/aes_ecb_pkcs5padding.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package encryption 18 | 19 | import ( 20 | "bytes" 21 | "crypto/aes" 22 | "crypto/cipher" 23 | "fmt" 24 | ) 25 | 26 | func AesEcbPkcs5PaddingEncrypt(plainContent, key []byte) (retBytes []byte, err error) { 27 | if len(plainContent) == 0 { 28 | return nil, nil 29 | } 30 | aesCipherBlock, err := aes.NewCipher(key) 31 | if err != nil { 32 | return nil, err 33 | } 34 | pkcs5PaddingBytes := PKCS5Padding(plainContent, aesCipherBlock.BlockSize()) 35 | return BlockEncrypt(pkcs5PaddingBytes, aesCipherBlock) 36 | } 37 | 38 | func AesEcbPkcs5PaddingDecrypt(cipherContent, key []byte) (retBytes []byte, err error) { 39 | if len(cipherContent) == 0 { 40 | return nil, nil 41 | } 42 | aesCipherBlock, err := aes.NewCipher(key) 43 | if err != nil { 44 | return nil, err 45 | } 46 | decryptBytes, err := BlockDecrypt(cipherContent, aesCipherBlock) 47 | if err != nil { 48 | return nil, err 49 | } 50 | retBytes = PKCS5UnPadding(decryptBytes) 51 | return retBytes, nil 52 | } 53 | 54 | func PKCS5Padding(ciphertext []byte, blockSize int) []byte { 55 | padding := blockSize - len(ciphertext)%blockSize 56 | padtext := bytes.Repeat([]byte{byte(padding)}, padding) 57 | return append(ciphertext, padtext...) 58 | } 59 | 60 | func PKCS5UnPadding(origData []byte) []byte { 61 | length := len(origData) 62 | unpadding := int(origData[length-1]) 63 | return origData[:(length - unpadding)] 64 | } 65 | 66 | func BlockEncrypt(src []byte, b cipher.Block) (dst []byte, err error) { 67 | if len(src)%b.BlockSize() != 0 { 68 | return nil, fmt.Errorf("input not full blocks") 69 | } 70 | buf := make([]byte, b.BlockSize()) 71 | for i := 0; i < len(src); i += b.BlockSize() { 72 | b.Encrypt(buf, src[i:i+b.BlockSize()]) 73 | dst = append(dst, buf...) 74 | } 75 | return 76 | } 77 | 78 | func BlockDecrypt(src []byte, b cipher.Block) (dst []byte, err error) { 79 | if len(src)%b.BlockSize() != 0 { 80 | return nil, fmt.Errorf("input not full blocks") 81 | } 82 | buf := make([]byte, b.BlockSize()) 83 | for i := 0; i < len(src); i += b.BlockSize() { 84 | b.Decrypt(buf, src[i:i+b.BlockSize()]) 85 | dst = append(dst, buf...) 86 | } 87 | return 88 | } 89 | -------------------------------------------------------------------------------- /common/encryption/const.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package encryption 18 | 19 | import "fmt" 20 | 21 | const ( 22 | CipherPrefix = "cipher-" 23 | 24 | KmsAes128AlgorithmName = "cipher-kms-aes-128" 25 | KmsAes256AlgorithmName = "cipher-kms-aes-256" 26 | KmsAlgorithmName = "cipher" 27 | 28 | kmsAes128KeySpec = "AES_128" 29 | kmsAes256KeySpec = "AES_256" 30 | 31 | kmsScheme = "https" 32 | kmsAcceptFormat = "XML" 33 | 34 | kmsCipherAlgorithm = "AES/ECB/PKCS5Padding" 35 | 36 | maskUnit8Width = 8 37 | maskUnit32Width = 32 38 | 39 | KmsHandlerName = "KmsHandler" 40 | ) 41 | 42 | var ( 43 | DataIdParamCheckError = fmt.Errorf("dataId prefix should start with: %s", CipherPrefix) 44 | ContentParamCheckError = fmt.Errorf("content need to encrypt is nil") 45 | KeyIdParamCheckError = fmt.Errorf("keyId is nil, need to be set") 46 | ) 47 | 48 | var ( 49 | PluginNotFoundError = fmt.Errorf("cannot find encryption plugin by dataId prefix") 50 | ) 51 | 52 | var ( 53 | EmptyEncryptedDataKeyError = fmt.Errorf("empty encrypted data key error") 54 | EmptyPlainDataKeyError = fmt.Errorf("empty plain data key error") 55 | EmptyContentError = fmt.Errorf("encrypt empty content error") 56 | ) 57 | 58 | var ( 59 | EmptyRegionKmsV1ClientInitError = fmt.Errorf("init kmsV1 client failed with empty region") 60 | EmptyAkKmsV1ClientInitError = fmt.Errorf("init kmsV1 client failed with empty ak") 61 | EmptySkKmsV1ClientInitError = fmt.Errorf("init kmsV1 client failed with empty sk") 62 | 63 | EmptyEndpointKmsV3ClientInitError = fmt.Errorf("init kmsV3 client failed with empty endpoint") 64 | EmptyPasswordKmsV3ClientInitError = fmt.Errorf("init kmsV3 client failed with empty password") 65 | EmptyClientKeyContentKmsV3ClientInitError = fmt.Errorf("init kmsV3 client failed with empty client key content") 66 | EmptyCaVerifyKmsV3ClientInitError = fmt.Errorf("init kmsV3 client failed with empty ca verify") 67 | EmptyEndpointKmsRamClientInitError = fmt.Errorf("init kmsRam client failed with empty endpoint") 68 | ) 69 | -------------------------------------------------------------------------------- /common/file/file.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package file 18 | 19 | import ( 20 | "log" 21 | "os" 22 | "path/filepath" 23 | "runtime" 24 | "strings" 25 | ) 26 | 27 | var osType string 28 | var path string 29 | 30 | const WINDOWS = "windows" 31 | 32 | func init() { 33 | osType = runtime.GOOS 34 | if os.IsPathSeparator('\\') { //前边的判断是否是系统的分隔符 35 | path = "\\" 36 | } else { 37 | path = "/" 38 | } 39 | } 40 | 41 | func MkdirIfNecessary(createDir string) (err error) { 42 | s := strings.Split(createDir, path) 43 | startIndex := 0 44 | dir := "" 45 | if s[0] == "" { 46 | startIndex = 1 47 | } else { 48 | dir, _ = os.Getwd() //当前的目录 49 | } 50 | for i := startIndex; i < len(s); i++ { 51 | var d string 52 | if osType == WINDOWS && filepath.IsAbs(createDir) { 53 | d = strings.Join(s[startIndex:i+1], path) 54 | } else { 55 | d = dir + path + strings.Join(s[startIndex:i+1], path) 56 | } 57 | if _, e := os.Stat(d); os.IsNotExist(e) { 58 | err = os.Mkdir(d, os.ModePerm) //在当前目录下生成md目录 59 | if err != nil { 60 | break 61 | } 62 | } 63 | } 64 | 65 | return err 66 | } 67 | 68 | func GetCurrentPath() string { 69 | 70 | dir, err := filepath.Abs(filepath.Dir(os.Args[0])) 71 | if err != nil { 72 | log.Println("can not get current path") 73 | } 74 | return dir 75 | } 76 | 77 | func IsExistFile(filePath string) bool { 78 | if len(filePath) == 0 { 79 | return false 80 | } 81 | _, err := os.Stat(filePath) 82 | if err == nil { 83 | return true 84 | } 85 | if os.IsNotExist(err) { 86 | return false 87 | } 88 | return false 89 | } 90 | -------------------------------------------------------------------------------- /common/file/file_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package file 18 | 19 | import ( 20 | "os" 21 | "testing" 22 | 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | func TestMkdirIfNecessaryForAbsPath(t *testing.T) { 27 | path := GetCurrentPath() + string(os.PathSeparator) + "log" 28 | err := MkdirIfNecessary(path) 29 | assert.Nil(t, err) 30 | } 31 | -------------------------------------------------------------------------------- /common/filter/config_encryption_filter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package filter 18 | 19 | import ( 20 | nacos_inner_encryption "github.com/nacos-group/nacos-sdk-go/v2/common/encryption" 21 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 22 | "github.com/pkg/errors" 23 | "strings" 24 | ) 25 | 26 | const ( 27 | defaultConfigEncryptionFilterName = "defaultConfigEncryptionFilter" 28 | ) 29 | 30 | var ( 31 | noNeedEncryptionError = errors.New("dataId doesn't need to encrypt/decrypt.") 32 | ) 33 | 34 | type DefaultConfigEncryptionFilter struct { 35 | handler nacos_inner_encryption.Handler 36 | } 37 | 38 | func NewDefaultConfigEncryptionFilter(handler nacos_inner_encryption.Handler) IConfigFilter { 39 | return &DefaultConfigEncryptionFilter{handler} 40 | } 41 | 42 | func (d *DefaultConfigEncryptionFilter) DoFilter(param *vo.ConfigParam) error { 43 | if err := d.paramCheck(*param); err != nil { 44 | if errors.Is(err, noNeedEncryptionError) { 45 | return nil 46 | } 47 | } 48 | if param.UsageType == vo.RequestType { 49 | encryptionParam := &nacos_inner_encryption.HandlerParam{ 50 | DataId: param.DataId, 51 | Content: param.Content, 52 | KeyId: param.KmsKeyId, 53 | } 54 | if err := d.handler.EncryptionHandler(encryptionParam); err != nil { 55 | return err 56 | } 57 | param.Content = encryptionParam.Content 58 | param.EncryptedDataKey = encryptionParam.EncryptedDataKey 59 | 60 | } else if param.UsageType == vo.ResponseType { 61 | decryptionParam := &nacos_inner_encryption.HandlerParam{ 62 | DataId: param.DataId, 63 | Content: param.Content, 64 | EncryptedDataKey: param.EncryptedDataKey, 65 | } 66 | if err := d.handler.DecryptionHandler(decryptionParam); err != nil { 67 | return err 68 | } 69 | param.Content = decryptionParam.Content 70 | } 71 | return nil 72 | } 73 | 74 | func (d *DefaultConfigEncryptionFilter) GetOrder() int { 75 | return 0 76 | } 77 | 78 | func (d *DefaultConfigEncryptionFilter) GetFilterName() string { 79 | return defaultConfigEncryptionFilterName 80 | } 81 | func (d *DefaultConfigEncryptionFilter) paramCheck(param vo.ConfigParam) error { 82 | if !strings.HasPrefix(param.DataId, nacos_inner_encryption.CipherPrefix) || 83 | len(strings.TrimSpace(param.Content)) == 0 { 84 | return noNeedEncryptionError 85 | } 86 | return nil 87 | } 88 | -------------------------------------------------------------------------------- /common/filter/config_filter.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package filter 18 | 19 | import ( 20 | "fmt" 21 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 22 | ) 23 | 24 | type IConfigFilterChain interface { 25 | AddFilter(IConfigFilter) error 26 | GetFilters() []IConfigFilter 27 | DoFilters(*vo.ConfigParam) error 28 | DoFilterByName(*vo.ConfigParam, string) error 29 | } 30 | 31 | type IConfigFilter interface { 32 | DoFilter(*vo.ConfigParam) error 33 | GetOrder() int 34 | GetFilterName() string 35 | } 36 | 37 | func RegisterConfigFilterToChain(chain IConfigFilterChain, filter IConfigFilter) error { 38 | return chain.AddFilter(filter) 39 | } 40 | 41 | func NewConfigFilterChainManager() IConfigFilterChain { 42 | return newConfigFilterChainManager() 43 | } 44 | 45 | func newConfigFilterChainManager() *DefaultConfigFilterChainManager { 46 | return &DefaultConfigFilterChainManager{ 47 | configFilterPriorityQueue: make([]IConfigFilter, 0, 2), 48 | } 49 | } 50 | 51 | type DefaultConfigFilterChainManager struct { 52 | configFilterPriorityQueue 53 | } 54 | 55 | func (m *DefaultConfigFilterChainManager) AddFilter(filter IConfigFilter) error { 56 | return m.configFilterPriorityQueue.addFilter(filter) 57 | } 58 | 59 | func (m *DefaultConfigFilterChainManager) GetFilters() []IConfigFilter { 60 | return m.configFilterPriorityQueue 61 | } 62 | 63 | func (m *DefaultConfigFilterChainManager) DoFilters(param *vo.ConfigParam) error { 64 | for index := 0; index < len(m.GetFilters()); index++ { 65 | if err := m.GetFilters()[index].DoFilter(param); err != nil { 66 | return err 67 | } 68 | } 69 | return nil 70 | } 71 | 72 | func (m *DefaultConfigFilterChainManager) DoFilterByName(param *vo.ConfigParam, name string) error { 73 | for index := 0; index < len(m.GetFilters()); index++ { 74 | if m.GetFilters()[index].GetFilterName() == name { 75 | if err := m.GetFilters()[index].DoFilter(param); err != nil { 76 | return err 77 | } 78 | return nil 79 | } 80 | } 81 | return fmt.Errorf("cannot find the filter[%s]", name) 82 | } 83 | 84 | type configFilterPriorityQueue []IConfigFilter 85 | 86 | func (c *configFilterPriorityQueue) addFilter(filter IConfigFilter) error { 87 | var pos int = len(*c) 88 | for i := 0; i < len(*c); i++ { 89 | if filter.GetFilterName() == (*c)[i].GetFilterName() { 90 | return nil 91 | } 92 | if filter.GetOrder() < (*c)[i].GetOrder() { 93 | pos = i 94 | break 95 | } 96 | } 97 | if pos == len(*c) { 98 | *c = append((*c)[:], filter) 99 | } else { 100 | temp := append((*c)[:pos], filter) 101 | *c = append(temp[:], (*c)[pos:]...) 102 | } 103 | return nil 104 | } 105 | -------------------------------------------------------------------------------- /common/http_agent/delete.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package http_agent 18 | 19 | import ( 20 | "net/http" 21 | "net/url" 22 | "strings" 23 | "time" 24 | ) 25 | 26 | func delete(client *http.Client, path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) { 27 | if len(params) > 0 { 28 | if !strings.HasSuffix(path, "?") { 29 | path = path + "?" 30 | } 31 | for key, value := range params { 32 | path = path + key + "=" + url.QueryEscape(value) + "&" 33 | } 34 | if strings.HasSuffix(path, "&") { 35 | path = path[:len(path)-1] 36 | } 37 | } 38 | client.Timeout = time.Millisecond * time.Duration(timeoutMs) 39 | request, errNew := http.NewRequest(http.MethodDelete, path, nil) 40 | if errNew != nil { 41 | err = errNew 42 | return 43 | } 44 | request.Header = header 45 | resp, errDo := client.Do(request) 46 | if errDo != nil { 47 | err = errDo 48 | } else { 49 | response = resp 50 | } 51 | return 52 | } 53 | -------------------------------------------------------------------------------- /common/http_agent/fake_http_response.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package http_agent 18 | 19 | import ( 20 | "bytes" 21 | "io" 22 | "net/http" 23 | "strconv" 24 | ) 25 | 26 | type fakeHttpResponseBody struct { 27 | body io.ReadSeeker 28 | } 29 | 30 | func (body *fakeHttpResponseBody) Read(p []byte) (n int, err error) { 31 | n, err = body.body.Read(p) 32 | if err == io.EOF { 33 | body.body.Seek(0, 0) 34 | } 35 | return n, err 36 | } 37 | 38 | func (body *fakeHttpResponseBody) Close() error { 39 | return nil 40 | } 41 | 42 | func FakeHttpResponse(status int, body string) (resp *http.Response) { 43 | return &http.Response{ 44 | Status: strconv.Itoa(status), 45 | StatusCode: status, 46 | Body: &fakeHttpResponseBody{bytes.NewReader([]byte(body))}, 47 | Header: http.Header{}, 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /common/http_agent/get.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package http_agent 18 | 19 | import ( 20 | "net/http" 21 | "net/url" 22 | "strings" 23 | "time" 24 | ) 25 | 26 | func get(client *http.Client, path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) { 27 | if !strings.Contains(path, "?") { 28 | path = path + "?" 29 | } 30 | 31 | for key, value := range params { 32 | if !strings.HasSuffix(path, "&") { 33 | path = path + "&" 34 | } 35 | path = path + key + "=" + url.QueryEscape(value) + "&" 36 | } 37 | if strings.HasSuffix(path, "&") { 38 | path = path[:len(path)-1] 39 | } 40 | 41 | client.Timeout = time.Millisecond * time.Duration(timeoutMs) 42 | request, errNew := http.NewRequest(http.MethodGet, path, nil) 43 | if errNew != nil { 44 | err = errNew 45 | return 46 | } 47 | request.Header = header 48 | resp, errDo := client.Do(request) 49 | 50 | if errDo != nil { 51 | err = errDo 52 | } else { 53 | response = resp 54 | } 55 | return 56 | } 57 | -------------------------------------------------------------------------------- /common/http_agent/http_agent_interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package http_agent 18 | 19 | import "net/http" 20 | 21 | //go:generate mockgen -destination ../../mock/mock_http_agent_interface.go -package mock -source=./http_agent_interface.go 22 | 23 | type IHttpAgent interface { 24 | Get(path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) 25 | Post(path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) 26 | Delete(path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) 27 | Put(path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) 28 | RequestOnlyResult(method string, path string, header http.Header, timeoutMs uint64, params map[string]string) string 29 | Request(method string, path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) 30 | } 31 | -------------------------------------------------------------------------------- /common/http_agent/post.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package http_agent 17 | 18 | import ( 19 | "net/http" 20 | "strings" 21 | "time" 22 | 23 | "github.com/nacos-group/nacos-sdk-go/v2/util" 24 | ) 25 | 26 | func post(client *http.Client, path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) { 27 | client.Timeout = time.Millisecond * time.Duration(timeoutMs) 28 | 29 | body := util.GetUrlFormedMap(params) 30 | request, errNew := http.NewRequest(http.MethodPost, path, strings.NewReader(body)) 31 | if errNew != nil { 32 | err = errNew 33 | return 34 | } 35 | request.Header = header 36 | resp, errDo := client.Do(request) 37 | if errDo != nil { 38 | err = errDo 39 | } else { 40 | response = resp 41 | } 42 | return 43 | } 44 | -------------------------------------------------------------------------------- /common/http_agent/put.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package http_agent 18 | 19 | import ( 20 | "net/http" 21 | "strings" 22 | "time" 23 | ) 24 | 25 | func put(client *http.Client, path string, header http.Header, timeoutMs uint64, params map[string]string) (response *http.Response, err error) { 26 | client.Timeout = time.Millisecond * time.Duration(timeoutMs) 27 | var body string 28 | for key, value := range params { 29 | if len(value) > 0 { 30 | body += key + "=" + value + "&" 31 | } 32 | } 33 | if strings.HasSuffix(body, "&") { 34 | body = body[:len(body)-1] 35 | } 36 | request, errNew := http.NewRequest(http.MethodPut, path, strings.NewReader(body)) 37 | if errNew != nil { 38 | err = errNew 39 | return 40 | } 41 | request.Header = header 42 | resp, errDo := client.Do(request) 43 | if errDo != nil { 44 | err = errDo 45 | } else { 46 | response = resp 47 | } 48 | return 49 | } 50 | -------------------------------------------------------------------------------- /common/logger/logger_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package logger 18 | 19 | import ( 20 | "sync" 21 | "testing" 22 | 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | func reset() { 27 | SetLogger(nil) 28 | } 29 | 30 | func TestInitLogger(t *testing.T) { 31 | config := Config{ 32 | Level: "degug", 33 | } 34 | err := InitLogger(config) 35 | assert.NoError(t, err) 36 | reset() 37 | } 38 | 39 | func TestGetLogger(t *testing.T) { 40 | // not yet init get default log 41 | log := GetLogger() 42 | config := Config{ 43 | Level: "debug", 44 | } 45 | _ = InitLogger(config) 46 | // after init logger 47 | log2 := GetLogger() 48 | assert.NotEqual(t, log, log2) 49 | 50 | reset() 51 | } 52 | 53 | func TestSetLogger(t *testing.T) { 54 | // not yet init get default log 55 | log := GetLogger() 56 | log1 := &mockLogger{} 57 | SetLogger(log1) 58 | 59 | // after set logger 60 | log2 := GetLogger() 61 | assert.NotEqual(t, log, log2) 62 | assert.Equal(t, log1, log2) 63 | 64 | reset() 65 | } 66 | 67 | func TestRaceLogger(t *testing.T) { 68 | wg := sync.WaitGroup{} 69 | for i := 0; i < 100; i++ { 70 | wg.Add(3) 71 | go func() { 72 | defer wg.Done() 73 | SetLogger(&mockLogger{}) 74 | }() 75 | go func() { 76 | defer wg.Done() 77 | _ = GetLogger() 78 | }() 79 | go func() { 80 | defer wg.Done() 81 | config := Config{ 82 | Level: "degug", 83 | } 84 | _ = InitLogger(config) 85 | }() 86 | } 87 | wg.Wait() 88 | reset() 89 | } 90 | 91 | type mockLogger struct { 92 | } 93 | 94 | func (m mockLogger) Info(args ...interface{}) { 95 | panic("implement me") 96 | } 97 | 98 | func (m mockLogger) Warn(args ...interface{}) { 99 | panic("implement me") 100 | } 101 | 102 | func (m mockLogger) Error(args ...interface{}) { 103 | panic("implement me") 104 | } 105 | 106 | func (m mockLogger) Debug(args ...interface{}) { 107 | panic("implement me") 108 | } 109 | 110 | func (m mockLogger) Infof(fmt string, args ...interface{}) { 111 | panic("implement me") 112 | } 113 | 114 | func (m mockLogger) Warnf(fmt string, args ...interface{}) { 115 | panic("implement me") 116 | } 117 | 118 | func (m mockLogger) Errorf(fmt string, args ...interface{}) { 119 | panic("implement me") 120 | } 121 | 122 | func (m mockLogger) Debugf(fmt string, args ...interface{}) { 123 | panic("implement me") 124 | } 125 | -------------------------------------------------------------------------------- /common/logger/logging.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package logger 18 | 19 | // Info is info level 20 | func Info(args ...interface{}) { 21 | GetLogger().Info(args...) 22 | } 23 | 24 | // Warn is warning level 25 | func Warn(args ...interface{}) { 26 | GetLogger().Warn(args...) 27 | } 28 | 29 | // Error is error level 30 | func Error(args ...interface{}) { 31 | GetLogger().Error(args...) 32 | } 33 | 34 | // Debug is debug level 35 | func Debug(args ...interface{}) { 36 | GetLogger().Debug(args...) 37 | } 38 | 39 | // Infof is format info level 40 | func Infof(fmt string, args ...interface{}) { 41 | GetLogger().Infof(fmt, args...) 42 | } 43 | 44 | // Warnf is format warning level 45 | func Warnf(fmt string, args ...interface{}) { 46 | GetLogger().Warnf(fmt, args...) 47 | } 48 | 49 | // Errorf is format error level 50 | func Errorf(fmt string, args ...interface{}) { 51 | GetLogger().Errorf(fmt, args...) 52 | } 53 | 54 | // Debugf is format debug level 55 | func Debugf(fmt string, args ...interface{}) { 56 | GetLogger().Debugf(fmt, args...) 57 | } 58 | -------------------------------------------------------------------------------- /common/monitor/monitor.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package monitor 18 | 19 | import "github.com/prometheus/client_golang/prometheus" 20 | 21 | var ( 22 | gaugeMonitorVec = prometheus.NewGaugeVec(prometheus.GaugeOpts{ 23 | Name: "nacos_monitor", 24 | Help: "nacos_monitor", 25 | }, []string{"module", "name"}) 26 | histogramMonitorVec = prometheus.NewHistogramVec(prometheus.HistogramOpts{ 27 | Name: "nacos_client_request", 28 | Help: "nacos_client_request", 29 | }, []string{"module", "method", "url", "code"}) 30 | ) 31 | 32 | // register collectors vec 33 | func init() { 34 | prometheus.MustRegister(gaugeMonitorVec, histogramMonitorVec) 35 | } 36 | 37 | // get gauge with labels and use gaugeMonitorVec 38 | func GetGaugeWithLabels(labels ...string) prometheus.Gauge { 39 | return gaugeMonitorVec.WithLabelValues(labels...) 40 | } 41 | 42 | func GetServiceInfoMapSizeMonitor() prometheus.Gauge { 43 | return GetGaugeWithLabels("serviceInfo", "serviceInfoMapSize") 44 | } 45 | 46 | func GetDom2BeatSizeMonitor() prometheus.Gauge { 47 | return GetGaugeWithLabels("dom2Beat", "dom2BeatSize") 48 | } 49 | 50 | func GetListenConfigCountMonitor() prometheus.Gauge { 51 | return GetGaugeWithLabels("listenConfig", "listenConfigCount") 52 | } 53 | 54 | // get histogram with labels and use histogramMonitorVec 55 | func GetHistogramWithLabels(labels ...string) prometheus.Observer { 56 | return histogramMonitorVec.WithLabelValues(labels...) 57 | } 58 | 59 | func GetConfigRequestMonitor(method, url, code string) prometheus.Observer { 60 | return GetHistogramWithLabels("config", method, url, code) 61 | } 62 | 63 | func GetNamingRequestMonitor(method, url, code string) prometheus.Observer { 64 | return GetHistogramWithLabels("naming", method, url, code) 65 | } 66 | -------------------------------------------------------------------------------- /common/monitor/monitor_test.go: -------------------------------------------------------------------------------- 1 | package monitor 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestGaugeMonitor(t *testing.T) { 10 | t.Run("getGaugeWithLabels", func(t *testing.T) { 11 | // will panic because of wrong label count. 12 | defer func() { 13 | r := recover() 14 | assert.NotNil(t, r) 15 | }() 16 | GetGaugeWithLabels("gauge", "test_gauge", "should_not_exist_label") 17 | }) 18 | 19 | t.Run("serviceInfoMapMonitor", func(t *testing.T) { 20 | monitor := GetServiceInfoMapSizeMonitor() 21 | assert.NotNil(t, monitor) 22 | }) 23 | } 24 | 25 | func TestHistorgam(t *testing.T) { 26 | t.Run("getHistogram", func(t *testing.T) { 27 | // will panic because of wrong label count. 28 | defer func() { 29 | r := recover() 30 | assert.NotNil(t, r) 31 | }() 32 | GetHistogramWithLabels("histogram", "test_histogram", "should_not_exist_label") 33 | }) 34 | 35 | t.Run("serviceInfoMapMonitor", func(t *testing.T) { 36 | monitor := GetConfigRequestMonitor("GET", "url", "NA") 37 | assert.NotNil(t, monitor) 38 | }) 39 | } 40 | -------------------------------------------------------------------------------- /common/nacos_error/nacos_error.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package nacos_error 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 23 | ) 24 | 25 | type NacosError struct { 26 | errorCode string 27 | errMsg string 28 | originError error 29 | } 30 | 31 | func NewNacosError(errorCode string, errMsg string, originError error) *NacosError { 32 | return &NacosError{ 33 | errorCode: errorCode, 34 | errMsg: errMsg, 35 | originError: originError, 36 | } 37 | 38 | } 39 | 40 | func (err *NacosError) Error() (str string) { 41 | nacosErrMsg := fmt.Sprintf("[%s] %s", err.ErrorCode(), err.errMsg) 42 | if err.originError != nil { 43 | return nacosErrMsg + "\ncaused by:\n" + err.originError.Error() 44 | } 45 | return nacosErrMsg 46 | } 47 | 48 | func (err *NacosError) ErrorCode() string { 49 | if err.errorCode == "" { 50 | return constant.DefaultClientErrorCode 51 | } else { 52 | return err.errorCode 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /common/remote/rpc/connection.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package rpc 18 | 19 | import ( 20 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request" 21 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response" 22 | "google.golang.org/grpc" 23 | ) 24 | 25 | type IConnection interface { 26 | request(request rpc_request.IRequest, timeoutMills int64, client *RpcClient) (rpc_response.IResponse, error) 27 | close() 28 | getConnectionId() string 29 | getServerInfo() ServerInfo 30 | setAbandon(flag bool) 31 | getAbandon() bool 32 | } 33 | 34 | type Connection struct { 35 | conn *grpc.ClientConn 36 | connectionId string 37 | abandon bool 38 | serverInfo ServerInfo 39 | } 40 | 41 | func (c *Connection) getConnectionId() string { 42 | return c.connectionId 43 | } 44 | 45 | func (c *Connection) getServerInfo() ServerInfo { 46 | return c.serverInfo 47 | } 48 | 49 | func (c *Connection) setAbandon(flag bool) { 50 | c.abandon = flag 51 | } 52 | 53 | func (c *Connection) getAbandon() bool { 54 | return c.abandon 55 | } 56 | 57 | func (c *Connection) close() { 58 | _ = c.conn.Close() 59 | } 60 | -------------------------------------------------------------------------------- /common/remote/rpc/connection_event_listener.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package rpc 18 | 19 | type IConnectionEventListener interface { 20 | 21 | //notify when connected to server. 22 | OnConnected() 23 | 24 | //notify when disconnected to server. 25 | OnDisConnect() 26 | } 27 | -------------------------------------------------------------------------------- /common/remote/rpc/connection_test.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import ( 4 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request" 5 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response" 6 | ) 7 | 8 | type MockConnection struct { 9 | } 10 | 11 | func (m *MockConnection) request(request rpc_request.IRequest, timeoutMills int64, client *RpcClient) (rpc_response.IResponse, error) { 12 | return nil, nil 13 | } 14 | func (m *MockConnection) close() { 15 | 16 | } 17 | func (m *MockConnection) getConnectionId() string { 18 | return "" 19 | } 20 | func (m *MockConnection) getServerInfo() ServerInfo { 21 | return ServerInfo{} 22 | } 23 | func (m *MockConnection) setAbandon(flag bool) { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /common/remote/rpc/grpc_connection.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package rpc 18 | 19 | import ( 20 | "context" 21 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 22 | "time" 23 | 24 | "github.com/golang/protobuf/ptypes/any" 25 | nacos_grpc_service "github.com/nacos-group/nacos-sdk-go/v2/api/grpc" 26 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request" 27 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response" 28 | "github.com/nacos-group/nacos-sdk-go/v2/util" 29 | "github.com/pkg/errors" 30 | 31 | "google.golang.org/grpc" 32 | ) 33 | 34 | type GrpcConnection struct { 35 | *Connection 36 | client nacos_grpc_service.RequestClient 37 | biStreamClient nacos_grpc_service.BiRequestStream_RequestBiStreamClient 38 | } 39 | 40 | func NewGrpcConnection(serverInfo ServerInfo, connectionId string, conn *grpc.ClientConn, 41 | client nacos_grpc_service.RequestClient, biStreamClient nacos_grpc_service.BiRequestStream_RequestBiStreamClient) *GrpcConnection { 42 | return &GrpcConnection{ 43 | Connection: &Connection{ 44 | serverInfo: serverInfo, 45 | connectionId: connectionId, 46 | abandon: false, 47 | conn: conn, 48 | }, 49 | client: client, 50 | biStreamClient: biStreamClient, 51 | } 52 | } 53 | func (g *GrpcConnection) request(request rpc_request.IRequest, timeoutMills int64, client *RpcClient) (rpc_response.IResponse, error) { 54 | p := convertRequest(request) 55 | ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeoutMills)*time.Millisecond) 56 | defer cancel() 57 | responsePayload, err := g.client.Request(ctx, p) 58 | if err != nil { 59 | logger.Debugf("%s grpc request nacos server failed, request=%+v, err=%v ", g.getConnectionId(), p, err) 60 | return nil, err 61 | } 62 | 63 | responseFunc, ok := rpc_response.ClientResponseMapping[responsePayload.Metadata.GetType()] 64 | if !ok { 65 | return nil, errors.Errorf("request:%s,unsupported response type:%s", request.GetRequestType(), 66 | responsePayload.Metadata.GetType()) 67 | } 68 | 69 | logger.Debugf("%s grpc request nacos server success, request=%+v, response=%s", g.getConnectionId(), p, string(responsePayload.GetBody().Value)) 70 | return rpc_response.InnerResponseJsonUnmarshal(responsePayload.GetBody().Value, responseFunc) 71 | } 72 | 73 | func (g *GrpcConnection) close() { 74 | g.Connection.close() 75 | } 76 | 77 | func (g *GrpcConnection) biStreamSend(payload *nacos_grpc_service.Payload) error { 78 | return g.biStreamClient.Send(payload) 79 | } 80 | 81 | func convertRequest(r rpc_request.IRequest) *nacos_grpc_service.Payload { 82 | Metadata := nacos_grpc_service.Metadata{ 83 | Type: r.GetRequestType(), 84 | Headers: r.GetHeaders(), 85 | ClientIp: util.LocalIP(), 86 | } 87 | return &nacos_grpc_service.Payload{ 88 | Metadata: &Metadata, 89 | Body: &any.Any{Value: []byte(r.GetBody(r))}, 90 | } 91 | } 92 | 93 | func convertResponse(r rpc_response.IResponse) *nacos_grpc_service.Payload { 94 | Metadata := nacos_grpc_service.Metadata{ 95 | Type: r.GetResponseType(), 96 | ClientIp: util.LocalIP(), 97 | } 98 | return &nacos_grpc_service.Payload{ 99 | Metadata: &Metadata, 100 | Body: &any.Any{Value: []byte(r.GetBody())}, 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /common/remote/rpc/rpc_client_test.go: -------------------------------------------------------------------------------- 1 | package rpc 2 | 3 | import "testing" 4 | 5 | func TestHealthCheck(t *testing.T) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /common/remote/rpc/rpc_request/config_request.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package rpc_request 18 | 19 | import ( 20 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 21 | "github.com/nacos-group/nacos-sdk-go/v2/model" 22 | ) 23 | 24 | type ConfigRequest struct { 25 | *Request 26 | Group string `json:"group"` 27 | DataId string `json:"dataId"` 28 | Tenant string `json:"tenant"` 29 | Module string `json:"module"` 30 | } 31 | 32 | func NewConfigRequest(group, dataId, tenant string) *ConfigRequest { 33 | request := Request{ 34 | Headers: make(map[string]string, 8), 35 | } 36 | return &ConfigRequest{ 37 | Request: &request, 38 | Group: group, 39 | DataId: dataId, 40 | Tenant: tenant, 41 | Module: "config", 42 | } 43 | } 44 | 45 | func (r *ConfigRequest) GetDataId() string { 46 | return r.DataId 47 | } 48 | 49 | func (r *ConfigRequest) GetGroup() string { 50 | return r.Group 51 | } 52 | 53 | func (r *ConfigRequest) GetTenant() string { 54 | return r.Tenant 55 | } 56 | 57 | // request of listening a batch of configs. 58 | type ConfigBatchListenRequest struct { 59 | *ConfigRequest 60 | Listen bool `json:"listen"` 61 | ConfigListenContexts []model.ConfigListenContext `json:"configListenContexts"` 62 | } 63 | 64 | func NewConfigBatchListenRequest(cacheLen int) *ConfigBatchListenRequest { 65 | return &ConfigBatchListenRequest{ 66 | Listen: true, 67 | ConfigListenContexts: make([]model.ConfigListenContext, 0, cacheLen), 68 | ConfigRequest: NewConfigRequest("", "", ""), 69 | } 70 | } 71 | 72 | func (r *ConfigBatchListenRequest) GetRequestType() string { 73 | return constant.CONFIG_BATCH_LISTEN_REQUEST_NAME 74 | } 75 | 76 | type ConfigChangeNotifyRequest struct { 77 | *ConfigRequest 78 | } 79 | 80 | func NewConfigChangeNotifyRequest(group, dataId, tenant string) *ConfigChangeNotifyRequest { 81 | return &ConfigChangeNotifyRequest{ConfigRequest: NewConfigRequest(group, dataId, tenant)} 82 | } 83 | 84 | func (r *ConfigChangeNotifyRequest) GetRequestType() string { 85 | return constant.CONFIG_CHANGE_NOTIFY_REQUEST_NAME 86 | } 87 | 88 | type ConfigQueryRequest struct { 89 | *ConfigRequest 90 | Tag string `json:"tag"` 91 | } 92 | 93 | func NewConfigQueryRequest(group, dataId, tenant string) *ConfigQueryRequest { 94 | return &ConfigQueryRequest{ConfigRequest: NewConfigRequest(group, dataId, tenant)} 95 | } 96 | 97 | func (r *ConfigQueryRequest) GetRequestType() string { 98 | return constant.CONFIG_QUERY_REQUEST_NAME 99 | } 100 | 101 | type ConfigPublishRequest struct { 102 | *ConfigRequest 103 | Content string `json:"content"` 104 | CasMd5 string `json:"casMd5"` 105 | AdditionMap map[string]string `json:"additionMap"` 106 | } 107 | 108 | func NewConfigPublishRequest(group, dataId, tenant, content, casMd5 string) *ConfigPublishRequest { 109 | return &ConfigPublishRequest{ConfigRequest: NewConfigRequest(group, dataId, tenant), 110 | Content: content, CasMd5: casMd5, AdditionMap: make(map[string]string)} 111 | } 112 | 113 | func (r *ConfigPublishRequest) GetRequestType() string { 114 | return constant.CONFIG_PUBLISH_REQUEST_NAME 115 | } 116 | 117 | type ConfigRemoveRequest struct { 118 | *ConfigRequest 119 | } 120 | 121 | func NewConfigRemoveRequest(group, dataId, tenant string) *ConfigRemoveRequest { 122 | return &ConfigRemoveRequest{ConfigRequest: NewConfigRequest(group, dataId, tenant)} 123 | } 124 | 125 | func (r *ConfigRemoveRequest) GetRequestType() string { 126 | return constant.CONFIG_REMOVE_REQUEST_NAME 127 | } 128 | -------------------------------------------------------------------------------- /common/remote/rpc/rpc_request/internal_request.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package rpc_request 18 | 19 | type ClientAbilities struct { 20 | } 21 | 22 | type InternalRequest struct { 23 | *Request 24 | Module string `json:"module"` 25 | } 26 | 27 | func NewInternalRequest() *InternalRequest { 28 | request := Request{ 29 | Headers: make(map[string]string, 8), 30 | } 31 | return &InternalRequest{ 32 | Request: &request, 33 | Module: "internal", 34 | } 35 | } 36 | 37 | type HealthCheckRequest struct { 38 | *InternalRequest 39 | } 40 | 41 | func NewHealthCheckRequest() *HealthCheckRequest { 42 | return &HealthCheckRequest{ 43 | InternalRequest: NewInternalRequest(), 44 | } 45 | } 46 | 47 | func (r *HealthCheckRequest) GetRequestType() string { 48 | return "HealthCheckRequest" 49 | } 50 | 51 | type ConnectResetRequest struct { 52 | *InternalRequest 53 | ServerIp string 54 | ServerPort string 55 | } 56 | 57 | func (r *ConnectResetRequest) GetRequestType() string { 58 | return "ConnectResetRequest" 59 | } 60 | 61 | type ClientDetectionRequest struct { 62 | *InternalRequest 63 | } 64 | 65 | func (r *ClientDetectionRequest) GetRequestType() string { 66 | return "ClientDetectionRequest" 67 | } 68 | 69 | type ServerCheckRequest struct { 70 | *InternalRequest 71 | } 72 | 73 | func NewServerCheckRequest() *ServerCheckRequest { 74 | return &ServerCheckRequest{ 75 | InternalRequest: NewInternalRequest(), 76 | } 77 | } 78 | 79 | func (r *ServerCheckRequest) GetRequestType() string { 80 | return "ServerCheckRequest" 81 | } 82 | 83 | type ConnectionSetupRequest struct { 84 | *InternalRequest 85 | ClientVersion string `json:"clientVersion"` 86 | Tenant string `json:"tenant"` 87 | Labels map[string]string `json:"labels"` 88 | ClientAbilities ClientAbilities `json:"clientAbilities"` 89 | } 90 | 91 | func NewConnectionSetupRequest() *ConnectionSetupRequest { 92 | return &ConnectionSetupRequest{ 93 | InternalRequest: NewInternalRequest(), 94 | } 95 | } 96 | 97 | func (r *ConnectionSetupRequest) GetRequestType() string { 98 | return "ConnectionSetupRequest" 99 | } 100 | -------------------------------------------------------------------------------- /common/remote/rpc/rpc_request/rpc_request.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package rpc_request 18 | 19 | import "github.com/nacos-group/nacos-sdk-go/v2/util" 20 | 21 | type Request struct { 22 | Headers map[string]string `json:"-"` 23 | RequestId string `json:"requestId"` 24 | } 25 | 26 | type IRequest interface { 27 | GetHeaders() map[string]string 28 | GetRequestType() string 29 | GetBody(request IRequest) string 30 | PutAllHeaders(headers map[string]string) 31 | GetRequestId() string 32 | GetStringToSign() string 33 | } 34 | 35 | type IConfigRequest interface { 36 | GetDataId() string 37 | GetGroup() string 38 | GetTenant() string 39 | } 40 | 41 | func (r *Request) PutAllHeaders(headers map[string]string) { 42 | if r.Headers == nil { 43 | r.Headers = make(map[string]string) 44 | } 45 | for k, v := range headers { 46 | r.Headers[k] = v 47 | } 48 | } 49 | 50 | func (r *Request) ClearHeaders() { 51 | r.Headers = make(map[string]string) 52 | } 53 | 54 | func (r *Request) GetHeaders() map[string]string { 55 | return r.Headers 56 | } 57 | 58 | func (r *Request) GetBody(request IRequest) string { 59 | return util.ToJsonString(request) 60 | } 61 | func (r *Request) GetRequestId() string { 62 | return r.RequestId 63 | } 64 | 65 | func (r *Request) GetStringToSign() string { 66 | return "" 67 | } 68 | -------------------------------------------------------------------------------- /common/remote/rpc/rpc_response/config_response.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package rpc_response 18 | 19 | import "github.com/nacos-group/nacos-sdk-go/v2/model" 20 | 21 | type ConfigChangeBatchListenResponse struct { 22 | *Response 23 | ChangedConfigs []model.ConfigContext `json:"changedConfigs"` 24 | } 25 | 26 | func (c *ConfigChangeBatchListenResponse) GetResponseType() string { 27 | return "ConfigChangeBatchListenResponse" 28 | } 29 | 30 | type ConfigQueryResponse struct { 31 | *Response 32 | Content string `json:"content"` 33 | EncryptedDataKey string `json:"encryptedDataKey"` 34 | ContentType string `json:"contentType"` 35 | Md5 string `json:"md5"` 36 | LastModified int64 `json:"lastModified"` 37 | IsBeta bool `json:"isBeta"` 38 | Tag bool `json:"tag"` 39 | } 40 | 41 | func (c *ConfigQueryResponse) GetResponseType() string { 42 | return "ConfigQueryResponse" 43 | } 44 | 45 | type ConfigPublishResponse struct { 46 | *Response 47 | } 48 | 49 | func (c *ConfigPublishResponse) GetResponseType() string { 50 | return "ConfigPublishResponse" 51 | } 52 | 53 | type ConfigRemoveResponse struct { 54 | *Response 55 | } 56 | 57 | func (c *ConfigRemoveResponse) GetResponseType() string { 58 | return "ConfigRemoveResponse" 59 | } 60 | -------------------------------------------------------------------------------- /common/remote/rpc/rpc_response/const.go: -------------------------------------------------------------------------------- 1 | package rpc_response 2 | 3 | type ResponseCode int 4 | 5 | const ( 6 | ResponseSuccessCode ResponseCode = 200 7 | ResponseFailCode ResponseCode = 500 8 | 9 | ResponseSuccessField = "success" 10 | ) 11 | -------------------------------------------------------------------------------- /common/remote/rpc/rpc_response/naming_response.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package rpc_response 18 | 19 | import ( 20 | "github.com/nacos-group/nacos-sdk-go/v2/model" 21 | ) 22 | 23 | type ConnectResetResponse struct { 24 | *Response 25 | } 26 | 27 | func (c *ConnectResetResponse) GetResponseType() string { 28 | return "ConnectResetResponse" 29 | } 30 | 31 | type ClientDetectionResponse struct { 32 | *Response 33 | } 34 | 35 | func (c *ClientDetectionResponse) GetResponseType() string { 36 | return "ClientDetectionResponse" 37 | } 38 | 39 | type ServerCheckResponse struct { 40 | *Response 41 | ConnectionId string `json:"connectionId"` 42 | } 43 | 44 | func (c *ServerCheckResponse) GetResponseType() string { 45 | return "ServerCheckResponse" 46 | } 47 | 48 | type InstanceResponse struct { 49 | *Response 50 | } 51 | 52 | func (c *InstanceResponse) GetResponseType() string { 53 | return "InstanceResponse" 54 | } 55 | 56 | type BatchInstanceResponse struct { 57 | *Response 58 | } 59 | 60 | func (c *BatchInstanceResponse) GetResponseType() string { 61 | return "BatchInstanceResponse" 62 | } 63 | 64 | type QueryServiceResponse struct { 65 | *Response 66 | ServiceInfo model.Service `json:"serviceInfo"` 67 | } 68 | 69 | func (c *QueryServiceResponse) GetResponseType() string { 70 | return "QueryServiceResponse" 71 | } 72 | 73 | type SubscribeServiceResponse struct { 74 | *Response 75 | ServiceInfo model.Service `json:"serviceInfo"` 76 | } 77 | 78 | func (c *SubscribeServiceResponse) GetResponseType() string { 79 | return "SubscribeServiceResponse" 80 | } 81 | 82 | type ServiceListResponse struct { 83 | *Response 84 | Count int `json:"count"` 85 | ServiceNames []string `json:"serviceNames"` 86 | } 87 | 88 | func (c *ServiceListResponse) GetResponseType() string { 89 | return "ServiceListResponse" 90 | } 91 | 92 | type NotifySubscriberResponse struct { 93 | *Response 94 | } 95 | 96 | func (c *NotifySubscriberResponse) GetResponseType() string { 97 | return "NotifySubscriberResponse" 98 | } 99 | 100 | type HealthCheckResponse struct { 101 | *Response 102 | } 103 | 104 | func (c *HealthCheckResponse) GetResponseType() string { 105 | return "HealthCheckResponse" 106 | } 107 | 108 | type ErrorResponse struct { 109 | *Response 110 | } 111 | 112 | func (c *ErrorResponse) GetResponseType() string { 113 | return "ErrorResponse" 114 | } 115 | 116 | type MockResponse struct { 117 | *Response 118 | } 119 | 120 | func (c *MockResponse) GetResponseType() string { 121 | return "MockResponse" 122 | } 123 | -------------------------------------------------------------------------------- /common/remote/rpc/rpc_response/rpc_response.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package rpc_response 18 | 19 | import ( 20 | "strconv" 21 | 22 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 23 | "github.com/nacos-group/nacos-sdk-go/v2/util" 24 | ) 25 | 26 | var ClientResponseMapping map[string]func() IResponse 27 | 28 | func init() { 29 | ClientResponseMapping = make(map[string]func() IResponse) 30 | registerClientResponses() 31 | } 32 | 33 | type IResponse interface { 34 | GetResponseType() string 35 | SetRequestId(requestId string) 36 | GetBody() string 37 | GetErrorCode() int 38 | IsSuccess() bool 39 | SetSuccess(bool) 40 | GetResultCode() int 41 | GetMessage() string 42 | } 43 | 44 | type Response struct { 45 | ResultCode int `json:"resultCode"` 46 | ErrorCode int `json:"errorCode"` 47 | Success bool `json:"success"` 48 | Message string `json:"message"` 49 | RequestId string `json:"requestId"` 50 | } 51 | 52 | func (r *Response) SetRequestId(requestId string) { 53 | r.RequestId = requestId 54 | } 55 | 56 | func (r *Response) GetBody() string { 57 | return util.ToJsonString(r) 58 | } 59 | 60 | func (r *Response) IsSuccess() bool { 61 | return r.Success 62 | } 63 | 64 | func (r *Response) SetSuccess(successResult bool) { 65 | r.Success = successResult 66 | } 67 | 68 | func (r *Response) GetErrorCode() int { 69 | return r.ErrorCode 70 | } 71 | 72 | func (r *Response) GetResultCode() int { 73 | return r.ResultCode 74 | } 75 | 76 | func (r *Response) GetMessage() string { 77 | return r.Message 78 | } 79 | 80 | func registerClientResponse(response func() IResponse) { 81 | responseType := response().GetResponseType() 82 | if responseType == "" { 83 | logger.Errorf("Register client response error: responseType is nil") 84 | return 85 | } 86 | ClientResponseMapping[responseType] = response 87 | } 88 | 89 | func registerClientResponses() { 90 | // register InstanceResponse. 91 | registerClientResponse(func() IResponse { 92 | return &InstanceResponse{Response: &Response{}} 93 | }) 94 | 95 | // register BatchInstanceResponse. 96 | registerClientResponse(func() IResponse { 97 | return &BatchInstanceResponse{Response: &Response{}} 98 | }) 99 | 100 | // register QueryServiceResponse. 101 | registerClientResponse(func() IResponse { 102 | return &QueryServiceResponse{Response: &Response{}} 103 | }) 104 | 105 | // register SubscribeServiceResponse. 106 | registerClientResponse(func() IResponse { 107 | return &SubscribeServiceResponse{Response: &Response{}} 108 | }) 109 | 110 | // register ServiceListResponse. 111 | registerClientResponse(func() IResponse { 112 | return &ServiceListResponse{Response: &Response{}} 113 | }) 114 | 115 | // register NotifySubscriberResponse. 116 | registerClientResponse(func() IResponse { 117 | return &NotifySubscriberResponse{Response: &Response{}} 118 | }) 119 | 120 | // register HealthCheckResponse. 121 | registerClientResponse(func() IResponse { 122 | return &HealthCheckResponse{Response: &Response{}} 123 | }) 124 | 125 | // register ErrorResponse. 126 | registerClientResponse(func() IResponse { 127 | return &ErrorResponse{Response: &Response{}} 128 | }) 129 | 130 | //register ConfigChangeBatchListenResponse 131 | registerClientResponse(func() IResponse { 132 | return &ConfigChangeBatchListenResponse{Response: &Response{}} 133 | }) 134 | 135 | //register ConfigQueryResponse 136 | registerClientResponse(func() IResponse { 137 | return &ConfigQueryResponse{Response: &Response{}} 138 | }) 139 | 140 | //register ConfigPublishResponse 141 | registerClientResponse(func() IResponse { 142 | return &ConfigPublishResponse{Response: &Response{}} 143 | }) 144 | 145 | //register ConfigRemoveResponse 146 | registerClientResponse(func() IResponse { 147 | return &ConfigRemoveResponse{Response: &Response{}} 148 | }) 149 | } 150 | 151 | // get grpc response status code with NA default. 152 | func GetGrpcResponseStatusCode(response IResponse) string { 153 | if response != nil { 154 | return strconv.Itoa(response.GetResultCode()) 155 | } else { 156 | return "NA" 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /common/remote/rpc/rpc_response/rpc_response_test.go: -------------------------------------------------------------------------------- 1 | package rpc_response 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func TestRpcResponseIsSuccess(t *testing.T) { 9 | responseBody0 := `{"resultCode":200,"errorCode":0}` 10 | responseBody1 := `{"resultCode":200,"errorCode":0,"success":true}` 11 | responseBody2 := `{"resultCode":200,"errorCode":0,"success":"true"}` 12 | responseBody3 := `{"resultCode":200,"errorCode":0,"success":false}` 13 | responseBody4 := `{"resultCode":500,"errorCode":0,"success":true}` 14 | responseBody5 := `{"resultCode":500,"errorCode":0,"success":false}` 15 | 16 | responseBodyList := make([]string, 0) 17 | responseBodyList = append(responseBodyList, responseBody0, responseBody1, responseBody2, responseBody3, responseBody4, responseBody5) 18 | for k, v := range ClientResponseMapping { 19 | t.Run("test "+k, func(t *testing.T) { 20 | for index, responseBody := range responseBodyList { 21 | response, err := InnerResponseJsonUnmarshal([]byte(responseBody), v) 22 | switch index { 23 | case 0, 1, 4: 24 | assert.True(t, response.IsSuccess()) 25 | break 26 | case 3, 5: 27 | assert.False(t, response.IsSuccess()) 28 | break 29 | case 2: 30 | assert.Nil(t, response) 31 | assert.NotNil(t, err) 32 | t.Logf("handle %d failed with responseBody: %s", index, responseBody) 33 | break 34 | default: 35 | panic("unknown index") 36 | } 37 | } 38 | }) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /common/remote/rpc/rpc_response/utils.go: -------------------------------------------------------------------------------- 1 | package rpc_response 2 | 3 | import "encoding/json" 4 | 5 | func InnerResponseJsonUnmarshal(responseBody []byte, responseFunc func() IResponse) (IResponse, error) { 6 | response := responseFunc() 7 | err := json.Unmarshal(responseBody, response) 8 | if err != nil { 9 | return nil, err 10 | } 11 | 12 | if !response.IsSuccess() { 13 | tempFiledMap := make(map[string]interface{}) 14 | err = json.Unmarshal(responseBody, &tempFiledMap) 15 | if err != nil { 16 | return response, nil 17 | } 18 | if _, ok := tempFiledMap[ResponseSuccessField]; !ok { 19 | response.SetSuccess(response.GetResultCode() == int(ResponseSuccessCode)) 20 | } 21 | } 22 | return response, err 23 | 24 | } 25 | -------------------------------------------------------------------------------- /common/remote/rpc/server_request_handler.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package rpc 18 | 19 | import ( 20 | "strconv" 21 | 22 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client/naming_cache" 23 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 24 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 25 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_request" 26 | "github.com/nacos-group/nacos-sdk-go/v2/common/remote/rpc/rpc_response" 27 | ) 28 | 29 | // IServerRequestHandler to process the request from server side. 30 | type IServerRequestHandler interface { 31 | Name() string 32 | //RequestReply Handle request from server. 33 | RequestReply(request rpc_request.IRequest, rpcClient *RpcClient) rpc_response.IResponse 34 | } 35 | 36 | type ConnectResetRequestHandler struct { 37 | } 38 | 39 | func (c *ConnectResetRequestHandler) Name() string { 40 | return "ConnectResetRequestHandler" 41 | } 42 | 43 | func (c *ConnectResetRequestHandler) RequestReply(request rpc_request.IRequest, rpcClient *RpcClient) rpc_response.IResponse { 44 | connectResetRequest, ok := request.(*rpc_request.ConnectResetRequest) 45 | if ok { 46 | rpcClient.mux.Lock() 47 | defer rpcClient.mux.Unlock() 48 | if rpcClient.IsRunning() { 49 | if connectResetRequest.ServerIp != "" { 50 | serverPortNum, err := strconv.Atoi(connectResetRequest.ServerPort) 51 | if err != nil { 52 | logger.Errorf("ConnectResetRequest ServerPort type conversion error:%+v", err) 53 | return nil 54 | } 55 | rpcClient.switchServerAsync(ServerInfo{serverIp: connectResetRequest.ServerIp, serverPort: uint64(serverPortNum)}, false) 56 | } else { 57 | rpcClient.switchServerAsync(ServerInfo{}, true) 58 | } 59 | } 60 | return &rpc_response.ConnectResetResponse{Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS}} 61 | } 62 | return nil 63 | } 64 | 65 | type ClientDetectionRequestHandler struct { 66 | } 67 | 68 | func (c *ClientDetectionRequestHandler) Name() string { 69 | return "ClientDetectionRequestHandler" 70 | } 71 | 72 | func (c *ClientDetectionRequestHandler) RequestReply(request rpc_request.IRequest, _ *RpcClient) rpc_response.IResponse { 73 | _, ok := request.(*rpc_request.ClientDetectionRequest) 74 | if ok { 75 | return &rpc_response.ClientDetectionResponse{ 76 | Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS}, 77 | } 78 | } 79 | return nil 80 | } 81 | 82 | type NamingPushRequestHandler struct { 83 | ServiceInfoHolder *naming_cache.ServiceInfoHolder 84 | } 85 | 86 | func (*NamingPushRequestHandler) Name() string { 87 | return "NamingPushRequestHandler" 88 | } 89 | 90 | func (c *NamingPushRequestHandler) RequestReply(request rpc_request.IRequest, client *RpcClient) rpc_response.IResponse { 91 | notifySubscriberRequest, ok := request.(*rpc_request.NotifySubscriberRequest) 92 | if ok { 93 | c.ServiceInfoHolder.ProcessService(¬ifySubscriberRequest.ServiceInfo) 94 | logger.Debugf("%s naming push response success ackId->%s", client.currentConnection.getConnectionId(), 95 | request.GetRequestId()) 96 | return &rpc_response.NotifySubscriberResponse{ 97 | Response: &rpc_response.Response{ResultCode: constant.RESPONSE_CODE_SUCCESS, Success: true}, 98 | } 99 | } 100 | return nil 101 | } 102 | -------------------------------------------------------------------------------- /common/security/ram_auth_client.go: -------------------------------------------------------------------------------- 1 | package security 2 | 3 | import ( 4 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 5 | ) 6 | 7 | type RamContext struct { 8 | SignatureRegionId string 9 | AccessKey string 10 | SecretKey string 11 | SecurityToken string 12 | EphemeralAccessKeyId bool 13 | } 14 | 15 | type RamAuthClient struct { 16 | clientConfig constant.ClientConfig 17 | ramCredentialProviders []RamCredentialProvider 18 | resourceInjector map[string]ResourceInjector 19 | matchedProvider RamCredentialProvider 20 | } 21 | 22 | func NewRamAuthClient(clientCfg constant.ClientConfig) *RamAuthClient { 23 | var providers = []RamCredentialProvider{ 24 | &RamRoleArnCredentialProvider{ 25 | clientConfig: clientCfg, 26 | }, 27 | &EcsRamRoleCredentialProvider{ 28 | clientConfig: clientCfg, 29 | }, 30 | &OIDCRoleArnCredentialProvider{ 31 | clientConfig: clientCfg, 32 | }, 33 | &CredentialsURICredentialProvider{ 34 | clientConfig: clientCfg, 35 | }, 36 | &AutoRotateCredentialProvider{ 37 | clientConfig: clientCfg, 38 | }, 39 | &StsTokenCredentialProvider{ 40 | clientConfig: clientCfg, 41 | }, 42 | &AccessKeyCredentialProvider{ 43 | clientConfig: clientCfg, 44 | }, 45 | } 46 | injectors := map[string]ResourceInjector{ 47 | REQUEST_TYPE_NAMING: &NamingResourceInjector{}, 48 | REQUEST_TYPE_CONFIG: &ConfigResourceInjector{}, 49 | } 50 | return &RamAuthClient{ 51 | clientConfig: clientCfg, 52 | ramCredentialProviders: providers, 53 | resourceInjector: injectors, 54 | } 55 | } 56 | 57 | func NewRamAuthClientWithProvider(clientCfg constant.ClientConfig, ramCredentialProvider RamCredentialProvider) *RamAuthClient { 58 | ramAuthClient := NewRamAuthClient(clientCfg) 59 | if ramCredentialProvider != nil { 60 | ramAuthClient.ramCredentialProviders = append(ramAuthClient.ramCredentialProviders, ramCredentialProvider) 61 | } 62 | 63 | return ramAuthClient 64 | } 65 | 66 | func (rac *RamAuthClient) Login() (bool, error) { 67 | for _, provider := range rac.ramCredentialProviders { 68 | if provider.MatchProvider() { 69 | rac.matchedProvider = provider 70 | break 71 | } 72 | } 73 | if rac.matchedProvider == nil { 74 | return false, nil 75 | } 76 | err := rac.matchedProvider.Init() 77 | if err != nil { 78 | return false, err 79 | } 80 | return true, nil 81 | } 82 | 83 | func (rac *RamAuthClient) GetSecurityInfo(resource RequestResource) map[string]string { 84 | var securityInfo = make(map[string]string, 4) 85 | if rac.matchedProvider == nil { 86 | return securityInfo 87 | } 88 | ramContext := rac.matchedProvider.GetCredentialsForNacosClient() 89 | rac.resourceInjector[resource.requestType].doInject(resource, ramContext, securityInfo) 90 | return securityInfo 91 | } 92 | 93 | func (rac *RamAuthClient) UpdateServerList(serverList []constant.ServerConfig) { 94 | return 95 | } 96 | -------------------------------------------------------------------------------- /common/security/resource_injector.go: -------------------------------------------------------------------------------- 1 | package security 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "time" 7 | 8 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 9 | ) 10 | 11 | type ResourceInjector interface { 12 | doInject(resource RequestResource, ramContext RamContext, param map[string]string) 13 | } 14 | 15 | const ( 16 | CONFIG_AK_FILED string = "Spas-AccessKey" 17 | NAMING_AK_FILED string = "ak" 18 | SECURITY_TOKEN_HEADER string = "Spas-SecurityToken" 19 | SIGNATURE_VERSION_HEADER string = "signatureVersion" 20 | SIGNATURE_VERSION_V4 string = "v4" 21 | SERVICE_INFO_SPLITER string = "@@" 22 | TIMESTAMP_HEADER string = "Timestamp" 23 | SIGNATURE_HEADER string = "Spas-Signature" 24 | ) 25 | 26 | type NamingResourceInjector struct { 27 | } 28 | 29 | func (n *NamingResourceInjector) doInject(resource RequestResource, ramContext RamContext, param map[string]string) { 30 | param[NAMING_AK_FILED] = ramContext.AccessKey 31 | if ramContext.EphemeralAccessKeyId { 32 | param[SECURITY_TOKEN_HEADER] = ramContext.SecurityToken 33 | } 34 | secretKey := trySignatureWithV4(ramContext, param) 35 | signatures := n.calculateSignature(resource, secretKey, ramContext) 36 | for k, v := range signatures { 37 | param[k] = v 38 | } 39 | } 40 | 41 | func (n *NamingResourceInjector) calculateSignature(resource RequestResource, secretKey string, ramContext RamContext) map[string]string { 42 | var result = make(map[string]string, 4) 43 | signData := n.getSignData(n.getGroupedServiceName(resource)) 44 | signature, err := Sign(signData, secretKey) 45 | if err != nil { 46 | logger.Errorf("get v4 signatrue error: %v", err) 47 | return result 48 | } 49 | result["signature"] = signature 50 | result["data"] = signData 51 | return result 52 | } 53 | 54 | func (n *NamingResourceInjector) getGroupedServiceName(resource RequestResource) string { 55 | if strings.Contains(resource.resource, SERVICE_INFO_SPLITER) || resource.group == "" { 56 | return resource.resource 57 | } 58 | return resource.group + SERVICE_INFO_SPLITER + resource.resource 59 | } 60 | 61 | func (n *NamingResourceInjector) getSignData(serviceName string) string { 62 | if serviceName != "" { 63 | return fmt.Sprintf("%d%s%s", time.Now().UnixMilli(), SERVICE_INFO_SPLITER, serviceName) 64 | } 65 | return fmt.Sprintf("%d", time.Now().UnixMilli()) 66 | } 67 | 68 | type ConfigResourceInjector struct { 69 | } 70 | 71 | func (c *ConfigResourceInjector) doInject(resource RequestResource, ramContext RamContext, param map[string]string) { 72 | param[CONFIG_AK_FILED] = ramContext.AccessKey 73 | if ramContext.EphemeralAccessKeyId { 74 | param[SECURITY_TOKEN_HEADER] = ramContext.SecurityToken 75 | } 76 | secretKey := trySignatureWithV4(ramContext, param) 77 | signatures := c.calculateSignature(resource, secretKey, ramContext) 78 | for k, v := range signatures { 79 | param[k] = v 80 | } 81 | } 82 | 83 | func (c *ConfigResourceInjector) calculateSignature(resource RequestResource, secretKey string, ramContext RamContext) map[string]string { 84 | var result = make(map[string]string, 4) 85 | resourceName := c.getResourceName(resource) 86 | signHeaders := c.getSignHeaders(resourceName, secretKey) 87 | for k, v := range signHeaders { 88 | result[k] = v 89 | } 90 | return result 91 | } 92 | 93 | func (c *ConfigResourceInjector) getResourceName(resource RequestResource) string { 94 | if resource.namespace != "" { 95 | return resource.namespace + "+" + resource.group 96 | } else { 97 | return resource.group 98 | } 99 | } 100 | func (c *ConfigResourceInjector) getSignHeaders(resource, secretKey string) map[string]string { 101 | header := make(map[string]string, 4) 102 | timeStamp := fmt.Sprintf("%d", time.Now().UnixMilli()) 103 | header[TIMESTAMP_HEADER] = timeStamp 104 | if secretKey != "" { 105 | var signature string 106 | if strings.TrimSpace(resource) == "" { 107 | signature = signWithHmacSha1Encrypt(timeStamp, secretKey) 108 | } else { 109 | signature = signWithHmacSha1Encrypt(resource+"+"+timeStamp, secretKey) 110 | } 111 | header[SIGNATURE_HEADER] = signature 112 | } 113 | return header 114 | } 115 | 116 | func trySignatureWithV4(ramContext RamContext, param map[string]string) string { 117 | if ramContext.SignatureRegionId == "" { 118 | return ramContext.SecretKey 119 | } 120 | signatureV4, err := finalSigningKeyStringWithDefaultInfo(ramContext.SecretKey, ramContext.SignatureRegionId) 121 | if err != nil { 122 | logger.Errorf("get v4 signatrue error: %v", err) 123 | return ramContext.SecretKey 124 | } 125 | param[SIGNATURE_VERSION_HEADER] = SIGNATURE_VERSION_V4 126 | return signatureV4 127 | } 128 | -------------------------------------------------------------------------------- /common/security/resource_injector_test.go: -------------------------------------------------------------------------------- 1 | package security 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | func Test_NamingResourceInjector_doInject(t *testing.T) { 9 | namingResourceInjector := NamingResourceInjector{} 10 | resource := BuildNamingResource("testNamespace", "testGroup", "testServiceName") 11 | t.Run("test_doInject_v4_sts", func(t *testing.T) { 12 | ramContext := RamContext{ 13 | AccessKey: "testAccessKey", 14 | SecretKey: "testSecretKey", 15 | SecurityToken: "testSecurityToken", 16 | EphemeralAccessKeyId: true, 17 | SignatureRegionId: "testSignatureRegionId", 18 | } 19 | param := map[string]string{} 20 | namingResourceInjector.doInject(resource, ramContext, param) 21 | assert.Equal(t, param[NAMING_AK_FILED], ramContext.AccessKey) 22 | assert.Equal(t, param[SECURITY_TOKEN_HEADER], ramContext.SecurityToken) 23 | assert.Equal(t, param[SIGNATURE_VERSION_HEADER], SIGNATURE_VERSION_V4) 24 | assert.NotEmpty(t, param["signature"]) 25 | }) 26 | 27 | t.Run("test_doInject", func(t *testing.T) { 28 | ramContext := RamContext{ 29 | AccessKey: "testAccessKey", 30 | SecretKey: "testSecretKey", 31 | } 32 | param := map[string]string{} 33 | namingResourceInjector.doInject(resource, ramContext, param) 34 | assert.Equal(t, param[NAMING_AK_FILED], ramContext.AccessKey) 35 | assert.Empty(t, param[SECURITY_TOKEN_HEADER]) 36 | assert.Empty(t, param[SIGNATURE_VERSION_HEADER]) 37 | assert.NotEmpty(t, param["signature"]) 38 | }) 39 | } 40 | 41 | func Test_NamingResourceInjector_getGroupedServiceName(t *testing.T) { 42 | namingResourceInjector := NamingResourceInjector{} 43 | t.Run("test_getGroupedServiceName", func(t *testing.T) { 44 | resource := BuildNamingResource("testNamespace", "testGroup", "testServiceName") 45 | assert.Equal(t, namingResourceInjector.getGroupedServiceName(resource), "testGroup@@testServiceName") 46 | }) 47 | t.Run("test_getGroupedServiceName_without_group", func(t *testing.T) { 48 | resource := BuildNamingResource("testNamespace", "", "testServiceName") 49 | assert.Equal(t, namingResourceInjector.getGroupedServiceName(resource), "testServiceName") 50 | }) 51 | } 52 | 53 | func Test_ConfigResourceInjector_doInject(t *testing.T) { 54 | configResourceInjector := ConfigResourceInjector{} 55 | resource := BuildConfigResource("testTenant", "testGroup", "testDataId") 56 | t.Run("test_doInject_v4_sts", func(t *testing.T) { 57 | ramContext := RamContext{ 58 | AccessKey: "testAccessKey", 59 | SecretKey: "testSecretKey", 60 | SecurityToken: "testSecurityToken", 61 | EphemeralAccessKeyId: true, 62 | SignatureRegionId: "testSignatureRegionId", 63 | } 64 | param := map[string]string{} 65 | configResourceInjector.doInject(resource, ramContext, param) 66 | assert.Equal(t, param[CONFIG_AK_FILED], ramContext.AccessKey) 67 | assert.Equal(t, param[SECURITY_TOKEN_HEADER], ramContext.SecurityToken) 68 | assert.Equal(t, param[SIGNATURE_VERSION_HEADER], SIGNATURE_VERSION_V4) 69 | assert.NotEmpty(t, param[SIGNATURE_HEADER]) 70 | assert.NotEmpty(t, param[TIMESTAMP_HEADER]) 71 | }) 72 | 73 | t.Run("test_doInject", func(t *testing.T) { 74 | ramContext := RamContext{ 75 | AccessKey: "testAccessKey", 76 | SecretKey: "testSecretKey", 77 | } 78 | param := map[string]string{} 79 | configResourceInjector.doInject(resource, ramContext, param) 80 | assert.Equal(t, param[CONFIG_AK_FILED], ramContext.AccessKey) 81 | assert.Empty(t, param[SECURITY_TOKEN_HEADER]) 82 | assert.Empty(t, param[SIGNATURE_VERSION_HEADER]) 83 | assert.NotEmpty(t, param[SIGNATURE_HEADER]) 84 | assert.NotEmpty(t, param[TIMESTAMP_HEADER]) 85 | }) 86 | } 87 | 88 | func Test_ConfigResourceInjector_getResourceName(t *testing.T) { 89 | configResourceInjector := ConfigResourceInjector{} 90 | t.Run("test_getGroupedServiceName", func(t *testing.T) { 91 | resource := BuildConfigResource("testTenant", "testGroup", "testDataId") 92 | assert.Equal(t, configResourceInjector.getResourceName(resource), "testTenant+testGroup") 93 | }) 94 | t.Run("test_getGroupedServiceName_without_group", func(t *testing.T) { 95 | resource := BuildConfigResource("testTenant", "", "testDataId") 96 | assert.Equal(t, configResourceInjector.getResourceName(resource), "testTenant+") 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /common/security/signature_util.go: -------------------------------------------------------------------------------- 1 | package security 2 | 3 | import ( 4 | "crypto/hmac" 5 | "crypto/sha1" 6 | "crypto/sha256" 7 | "encoding/base64" 8 | "fmt" 9 | "time" 10 | ) 11 | 12 | const ( 13 | PREFIX = "aliyun_v4" 14 | CONSTANT = "aliyun_v4_request" 15 | V4_SIGN_DATE_FORMATTER = "20060102" 16 | SIGNATURE_V4_PRODUCE = "mse" 17 | ) 18 | 19 | func signWithHmacSha1Encrypt(encryptText, encryptKey string) string { 20 | key := []byte(encryptKey) 21 | mac := hmac.New(sha1.New, key) 22 | mac.Write([]byte(encryptText)) 23 | expectedMAC := mac.Sum(nil) 24 | return base64.StdEncoding.EncodeToString(expectedMAC) 25 | } 26 | 27 | func Sign(data, key string) (string, error) { 28 | signature, err := sign([]byte(data), []byte(key)) 29 | if err != nil { 30 | return "", fmt.Errorf("unable to calculate a request signature: %w", err) 31 | } 32 | return base64.StdEncoding.EncodeToString(signature), nil 33 | } 34 | 35 | // sign 方法用于生成签名字节数组 36 | func sign(data, key []byte) ([]byte, error) { 37 | mac := hmac.New(sha1.New, key) 38 | if _, err := mac.Write(data); err != nil { 39 | return nil, err 40 | } 41 | return mac.Sum(nil), nil 42 | } 43 | 44 | func finalSigningKeyStringWithDefaultInfo(secret, region string) (string, error) { 45 | signDate := time.Now().UTC().Format(V4_SIGN_DATE_FORMATTER) 46 | return finalSigningKeyString(secret, signDate, region, SIGNATURE_V4_PRODUCE) 47 | } 48 | 49 | func finalSigningKeyString(secret, date, region, productCode string) (string, error) { 50 | finalKey, err := finalSigningKey(secret, date, region, productCode) 51 | if err != nil { 52 | return "", err 53 | } 54 | return base64.StdEncoding.EncodeToString(finalKey), nil 55 | } 56 | 57 | func finalSigningKey(secret, date, region, productCode string) ([]byte, error) { 58 | secondSignkey, err := regionSigningKey(secret, date, region) 59 | if err != nil { 60 | return nil, err 61 | } 62 | mac := hmac.New(sha256.New, secondSignkey) 63 | _, err = mac.Write([]byte(productCode)) 64 | if err != nil { 65 | return nil, err 66 | } 67 | thirdSigningKey := mac.Sum(nil) 68 | 69 | mac = hmac.New(sha256.New, thirdSigningKey) 70 | _, err = mac.Write([]byte(CONSTANT)) 71 | if err != nil { 72 | return nil, err 73 | } 74 | return mac.Sum(nil), nil 75 | } 76 | 77 | func regionSigningKey(secret, date, region string) ([]byte, error) { 78 | firstSignkey, err := firstSigningKey(secret, date) 79 | if err != nil { 80 | return nil, err 81 | } 82 | mac := hmac.New(sha256.New, firstSignkey) 83 | _, err = mac.Write([]byte(region)) 84 | if err != nil { 85 | return nil, err 86 | } 87 | return mac.Sum(nil), nil 88 | } 89 | 90 | func firstSigningKey(secret, date string) ([]byte, error) { 91 | mac := hmac.New(sha256.New, []byte(PREFIX+secret)) 92 | _, err := mac.Write([]byte(date)) 93 | if err != nil { 94 | return nil, err 95 | } 96 | return mac.Sum(nil), nil 97 | } 98 | -------------------------------------------------------------------------------- /common/tls/tls.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package tls 18 | 19 | import ( 20 | "crypto/tls" 21 | "crypto/x509" 22 | "fmt" 23 | "os" 24 | 25 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 26 | ) 27 | 28 | // NewTLS returns a config structure is used to configure a TLS client 29 | func NewTLS(c constant.TLSConfig) (tc *tls.Config, err error) { 30 | tc = &tls.Config{} 31 | if len(c.CertFile) > 0 && len(c.KeyFile) > 0 { 32 | cert, err := certificate(c.CertFile, c.KeyFile) 33 | if err != nil { 34 | return nil, err 35 | } 36 | tc.Certificates = []tls.Certificate{*cert} 37 | } 38 | 39 | if len(c.CaFile) <= 0 { 40 | tc.InsecureSkipVerify = true 41 | return tc, nil 42 | } 43 | if len(c.ServerNameOverride) > 0 { 44 | tc.ServerName = c.ServerNameOverride 45 | } 46 | tc.RootCAs, err = rootCert(c.CaFile) 47 | return 48 | } 49 | 50 | func rootCert(caFile string) (*x509.CertPool, error) { 51 | b, err := os.ReadFile(caFile) 52 | if err != nil { 53 | return nil, err 54 | } 55 | cp := x509.NewCertPool() 56 | if !cp.AppendCertsFromPEM(b) { 57 | return nil, fmt.Errorf("credentials: failed to append certificates") 58 | } 59 | return cp, nil 60 | } 61 | 62 | func certificate(certFile, keyFile string) (*tls.Certificate, error) { 63 | cert, err := tls.LoadX509KeyPair(certFile, keyFile) 64 | if err != nil { 65 | return nil, err 66 | } 67 | return &cert, nil 68 | } 69 | -------------------------------------------------------------------------------- /example/config-acm/ak: -------------------------------------------------------------------------------- 1 | LTAIxxxxxxxxxxxBHS21E6 -------------------------------------------------------------------------------- /example/config-acm/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | "github.com/nacos-group/nacos-sdk-go/v2/clients/config_client" 22 | "github.com/nacos-group/nacos-sdk-go/v2/clients/nacos_client" 23 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 24 | "github.com/nacos-group/nacos-sdk-go/v2/common/http_agent" 25 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 26 | "time" 27 | ) 28 | 29 | var localServerConfigWithOptions = constant.NewServerConfig( 30 | "mse-d12e6112-p.nacos-ans.mse.aliyuncs.com", 31 | 8848, 32 | ) 33 | 34 | var localClientConfigWithOptions = constant.NewClientConfig( 35 | constant.WithTimeoutMs(10*1000), 36 | constant.WithBeatInterval(2*1000), 37 | constant.WithNotLoadCacheAtStart(true), 38 | //constant.WithAccessKey(getFileContent(path.Join(getWDR(), "ak"))), 39 | //constant.WithSecretKey(getFileContent(path.Join(getWDR(), "sk"))), 40 | constant.WithAccessKey("LTAxxxgQL"), 41 | constant.WithSecretKey("iG4xxxV6C"), 42 | constant.WithOpenKMS(true), 43 | constant.WithKMSVersion(constant.KMSv1), 44 | constant.WithRegionId("cn-beijing"), 45 | ) 46 | 47 | var localConfigList = []vo.ConfigParam{ 48 | { 49 | DataId: "common-config", 50 | Group: "default", 51 | Content: "common", 52 | }, 53 | { 54 | DataId: "cipher-crypt", 55 | Group: "default", 56 | Content: "cipher", 57 | }, 58 | { 59 | DataId: "cipher-kms-aes-128-crypt", 60 | Group: "default", 61 | Content: "cipher-aes-128", 62 | }, 63 | { 64 | DataId: "cipher-kms-aes-256-crypt", 65 | Group: "default", 66 | Content: "cipher-aes-256", 67 | }, 68 | } 69 | 70 | func main() { 71 | 72 | client, err := createConfigClient() 73 | if err != nil { 74 | panic(err) 75 | } 76 | 77 | for _, localConfig := range localConfigList { 78 | // to enable encrypt/decrypt, DataId should be start with "cipher-" 79 | configParam := vo.ConfigParam{ 80 | DataId: localConfig.DataId, 81 | Group: localConfig.Group, 82 | Content: localConfig.Content, 83 | OnChange: func(namespace, group, dataId, data string) { 84 | fmt.Printf("successfully receive changed config: \n"+ 85 | "group[%s], dataId[%s], data[%s]\n", group, dataId, data) 86 | }, 87 | } 88 | 89 | err := client.ListenConfig(configParam) 90 | if err != nil { 91 | fmt.Printf("failed to listen: group[%s], dataId[%s] with error: %s\n", 92 | configParam.Group, configParam.DataId, err) 93 | } else { 94 | fmt.Printf("successfully ListenConfig: group[%s], dataId[%s]\n", configParam.Group, configParam.DataId) 95 | } 96 | 97 | published, err := client.PublishConfig(configParam) 98 | if published && err == nil { 99 | fmt.Printf("successfully publish: group[%s], dataId[%s], data[%s]\n", configParam.Group, configParam.DataId, configParam.Content) 100 | } else { 101 | fmt.Printf("failed to publish: group[%s], dataId[%s], data[%s]\n with error: %s\n", 102 | configParam.Group, configParam.DataId, configParam.Content, err) 103 | } 104 | 105 | //wait for config change callback to execute 106 | time.Sleep(2 * time.Second) 107 | 108 | //get config 109 | content, err := client.GetConfig(configParam) 110 | if err == nil { 111 | fmt.Printf("successfully get config: group[%s], dataId[%s], data[%s]\n", configParam.Group, configParam.DataId, configParam.Content) 112 | } else { 113 | fmt.Printf("failed to get config: group[%s], dataId[%s], data[%s]\n with error: %s\n", 114 | configParam.Group, configParam.DataId, configParam.Content, err) 115 | } 116 | 117 | if content != localConfig.Content { 118 | panic("publish/get encrypted config failed.") 119 | } else { 120 | fmt.Println("publish/get encrypted config success.") 121 | } 122 | //wait for config change callback to execute 123 | //time.Sleep(2 * time.Second) 124 | } 125 | 126 | } 127 | 128 | func createConfigClient() (*config_client.ConfigClient, error) { 129 | nc := nacos_client.NacosClient{} 130 | _ = nc.SetServerConfig([]constant.ServerConfig{*localServerConfigWithOptions}) 131 | _ = nc.SetClientConfig(*localClientConfigWithOptions) 132 | fmt.Println("ak: " + localClientConfigWithOptions.AccessKey) 133 | fmt.Println("sk: " + localClientConfigWithOptions.SecretKey) 134 | _ = nc.SetHttpAgent(&http_agent.HttpAgent{}) 135 | client, err := config_client.NewConfigClient(&nc) 136 | if err != nil { 137 | return nil, err 138 | } 139 | return client, nil 140 | } 141 | -------------------------------------------------------------------------------- /example/config-acm/sk: -------------------------------------------------------------------------------- 1 | kr6JxxxxxxxxxxxxxY8nHnsD6 -------------------------------------------------------------------------------- /example/config-endpoint/main-endpoint.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | "time" 22 | 23 | "github.com/nacos-group/nacos-sdk-go/v2/clients" 24 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 25 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 26 | ) 27 | 28 | func main() { 29 | //create ClientConfig 30 | cc := *constant.NewClientConfig( 31 | constant.WithNamespaceId(""), 32 | constant.WithTimeoutMs(5000), 33 | constant.WithNotLoadCacheAtStart(true), 34 | constant.WithLogDir("/tmp/nacos/log"), 35 | constant.WithCacheDir("/tmp/nacos/cache"), 36 | constant.WithLogLevel("debug"), 37 | constant.WithAppName("yiyantest"), 38 | constant.WithEndpoint("jmenv.tbsite.net:8080"), 39 | constant.WithClusterName("serverlist"), 40 | constant.WithEndpointQueryParams("nofix=1"), 41 | constant.WithEndpointContextPath("nacos"), 42 | ) 43 | 44 | // create config client 45 | client, err := clients.NewConfigClient( 46 | vo.NacosClientParam{ 47 | ClientConfig: &cc, 48 | }, 49 | ) 50 | 51 | if err != nil { 52 | panic(err) 53 | } 54 | 55 | //publish config 56 | //config key=dataId+group+namespaceId 57 | _, err = client.PublishConfig(vo.ConfigParam{ 58 | DataId: "test-data", 59 | Group: "test-group", 60 | Content: "hello world!", 61 | }) 62 | _, err = client.PublishConfig(vo.ConfigParam{ 63 | DataId: "test-data-2", 64 | Group: "test-group", 65 | Content: "hello world!", 66 | }) 67 | if err != nil { 68 | fmt.Printf("PublishConfig err:%+v \n", err) 69 | } 70 | time.Sleep(1 * time.Second) 71 | //get config 72 | content, err := client.GetConfig(vo.ConfigParam{ 73 | DataId: "test-data", 74 | Group: "test-group", 75 | }) 76 | fmt.Println("GetConfig,config :" + content) 77 | 78 | //Listen config change,key=dataId+group+namespaceId. 79 | err = client.ListenConfig(vo.ConfigParam{ 80 | DataId: "test-data", 81 | Group: "test-group", 82 | OnChange: func(namespace, group, dataId, data string) { 83 | fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data) 84 | }, 85 | }) 86 | 87 | err = client.ListenConfig(vo.ConfigParam{ 88 | DataId: "test-data-2", 89 | Group: "test-group", 90 | OnChange: func(namespace, group, dataId, data string) { 91 | fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data) 92 | }, 93 | }) 94 | 95 | time.Sleep(1 * time.Second) 96 | var content2 = "helo 130" 97 | _, err = client.PublishConfig(vo.ConfigParam{ 98 | DataId: "test-data", 99 | Group: "test-group", 100 | Content: content2, 101 | }) 102 | if err == nil { 103 | fmt.Println("publish config success:" + "test-group" + ", dataId:" + "test-data" + ", content:" + content2) 104 | 105 | } else { 106 | fmt.Println("publish config fail :" + "test-group" + ", dataId:" + "test-data" + ", content:" + content2) 107 | 108 | } 109 | time.Sleep(1 * time.Second) 110 | 111 | _, err = client.PublishConfig(vo.ConfigParam{ 112 | DataId: "test-data-2", 113 | Group: "test-group", 114 | Content: "test-listen", 115 | }) 116 | 117 | time.Sleep(2 * time.Second) 118 | 119 | time.Sleep(1 * time.Second) 120 | _, err = client.DeleteConfig(vo.ConfigParam{ 121 | DataId: "test-data", 122 | Group: "test-group", 123 | }) 124 | fmt.Println("delete config success:" + "test-group" + ", dataId:" + "test-data") 125 | 126 | time.Sleep(1 * time.Second) 127 | 128 | /* //cancel config change 129 | err = client.CancelListenConfig(vo.ConfigParam{ 130 | DataId: "test-data", 131 | Group: "test-group", 132 | }) 133 | */ 134 | searchPage, _ := client.SearchConfig(vo.SearchConfigParam{ 135 | Search: "blur", 136 | DataId: "test-data", 137 | Group: "", 138 | PageNo: 1, 139 | PageSize: 10, 140 | }) 141 | fmt.Printf("Search config:%+v \n", searchPage) 142 | 143 | time.Sleep(1000 * time.Second) 144 | 145 | } 146 | -------------------------------------------------------------------------------- /example/config-mse-kmsv3/ak: -------------------------------------------------------------------------------- 1 | LTAxxxxgQL -------------------------------------------------------------------------------- /example/config-mse-kmsv3/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | xxx 3 | -----END CERTIFICATE----- 4 | -------------------------------------------------------------------------------- /example/config-mse-kmsv3/client_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "KeyId": "KAAxxxxe74", 3 | "PrivateKeyData": "MIIxxxA==" 4 | } -------------------------------------------------------------------------------- /example/config-mse-kmsv3/endpoint: -------------------------------------------------------------------------------- 1 | kst-bjj64f82f41yjrs66eygc.cryptoservice.kms.aliyuncs.com -------------------------------------------------------------------------------- /example/config-mse-kmsv3/password: -------------------------------------------------------------------------------- 1 | 19axxxxx213 -------------------------------------------------------------------------------- /example/config-mse-kmsv3/sk: -------------------------------------------------------------------------------- 1 | iG48xxxV6C -------------------------------------------------------------------------------- /example/config/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | "time" 22 | 23 | "github.com/nacos-group/nacos-sdk-go/v2/clients" 24 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 25 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 26 | ) 27 | 28 | func main() { 29 | //create ServerConfig 30 | sc := []constant.ServerConfig{ 31 | *constant.NewServerConfig("127.0.0.1", 8848, constant.WithContextPath("/nacos")), 32 | } 33 | 34 | //create ClientConfig 35 | cc := *constant.NewClientConfig( 36 | constant.WithNamespaceId(""), 37 | constant.WithTimeoutMs(5000), 38 | constant.WithNotLoadCacheAtStart(true), 39 | constant.WithLogDir("/tmp/nacos/log"), 40 | constant.WithCacheDir("/tmp/nacos/cache"), 41 | constant.WithLogLevel("debug"), 42 | ) 43 | 44 | // create config client 45 | client, err := clients.NewConfigClient( 46 | vo.NacosClientParam{ 47 | ClientConfig: &cc, 48 | ServerConfigs: sc, 49 | }, 50 | ) 51 | 52 | if err != nil { 53 | panic(err) 54 | } 55 | 56 | //publish config 57 | //config key=dataId+group+namespaceId 58 | _, err = client.PublishConfig(vo.ConfigParam{ 59 | DataId: "test-data", 60 | Group: "test-group", 61 | Content: "hello world!", 62 | }) 63 | _, err = client.PublishConfig(vo.ConfigParam{ 64 | DataId: "test-data-2", 65 | Group: "test-group", 66 | Content: "hello world!", 67 | }) 68 | if err != nil { 69 | fmt.Printf("PublishConfig err:%+v \n", err) 70 | } 71 | time.Sleep(1 * time.Second) 72 | //get config 73 | content, err := client.GetConfig(vo.ConfigParam{ 74 | DataId: "test-data", 75 | Group: "test-group", 76 | }) 77 | fmt.Println("GetConfig,config :" + content) 78 | 79 | //Listen config change,key=dataId+group+namespaceId. 80 | err = client.ListenConfig(vo.ConfigParam{ 81 | DataId: "test-data", 82 | Group: "test-group", 83 | OnChange: func(namespace, group, dataId, data string) { 84 | fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data) 85 | }, 86 | }) 87 | 88 | err = client.ListenConfig(vo.ConfigParam{ 89 | DataId: "test-data-2", 90 | Group: "test-group", 91 | OnChange: func(namespace, group, dataId, data string) { 92 | fmt.Println("config changed group:" + group + ", dataId:" + dataId + ", content:" + data) 93 | }, 94 | }) 95 | 96 | time.Sleep(1 * time.Second) 97 | 98 | _, err = client.PublishConfig(vo.ConfigParam{ 99 | DataId: "test-data", 100 | Group: "test-group", 101 | Content: "test-listen", 102 | }) 103 | 104 | time.Sleep(1 * time.Second) 105 | 106 | _, err = client.PublishConfig(vo.ConfigParam{ 107 | DataId: "test-data-2", 108 | Group: "test-group", 109 | Content: "test-listen", 110 | }) 111 | 112 | time.Sleep(2 * time.Second) 113 | 114 | time.Sleep(1 * time.Second) 115 | _, err = client.DeleteConfig(vo.ConfigParam{ 116 | DataId: "test-data", 117 | Group: "test-group", 118 | }) 119 | time.Sleep(1 * time.Second) 120 | 121 | //cancel config change 122 | err = client.CancelListenConfig(vo.ConfigParam{ 123 | DataId: "test-data", 124 | Group: "test-group", 125 | }) 126 | 127 | searchPage, _ := client.SearchConfig(vo.SearchConfigParam{ 128 | Search: "blur", 129 | DataId: "", 130 | Group: "", 131 | PageNo: 1, 132 | PageSize: 10, 133 | }) 134 | fmt.Printf("Search config:%+v \n", searchPage) 135 | } 136 | -------------------------------------------------------------------------------- /example/service/service_client_example.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "fmt" 21 | 22 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client" 23 | 24 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 25 | ) 26 | 27 | func registerServiceInstance(client naming_client.INamingClient, param vo.RegisterInstanceParam) { 28 | success, err := client.RegisterInstance(param) 29 | if !success || err != nil { 30 | panic("RegisterServiceInstance failed!" + err.Error()) 31 | } 32 | fmt.Printf("RegisterServiceInstance,param:%+v,result:%+v \n\n", param, success) 33 | } 34 | 35 | func batchRegisterServiceInstance(client naming_client.INamingClient, param vo.BatchRegisterInstanceParam) { 36 | success, err := client.BatchRegisterInstance(param) 37 | if !success || err != nil { 38 | panic("BatchRegisterServiceInstance failed!" + err.Error()) 39 | } 40 | fmt.Printf("BatchRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success) 41 | } 42 | 43 | func deRegisterServiceInstance(client naming_client.INamingClient, param vo.DeregisterInstanceParam) { 44 | success, err := client.DeregisterInstance(param) 45 | if !success || err != nil { 46 | panic("DeRegisterServiceInstance failed!" + err.Error()) 47 | } 48 | fmt.Printf("DeRegisterServiceInstance,param:%+v,result:%+v \n\n", param, success) 49 | } 50 | 51 | func updateServiceInstance(client naming_client.INamingClient, param vo.UpdateInstanceParam) { 52 | success, err := client.UpdateInstance(param) 53 | if !success || err != nil { 54 | panic("UpdateInstance failed!" + err.Error()) 55 | } 56 | fmt.Printf("UpdateServiceInstance,param:%+v,result:%+v \n\n", param, success) 57 | } 58 | 59 | func getService(client naming_client.INamingClient, param vo.GetServiceParam) { 60 | service, err := client.GetService(param) 61 | if err != nil { 62 | panic("GetService failed!" + err.Error()) 63 | } 64 | fmt.Printf("GetService,param:%+v, result:%+v \n\n", param, service) 65 | } 66 | 67 | func selectAllInstances(client naming_client.INamingClient, param vo.SelectAllInstancesParam) { 68 | instances, err := client.SelectAllInstances(param) 69 | if err != nil { 70 | panic("SelectAllInstances failed!" + err.Error()) 71 | } 72 | fmt.Printf("SelectAllInstance,param:%+v, result:%+v \n\n", param, instances) 73 | } 74 | 75 | func selectInstances(client naming_client.INamingClient, param vo.SelectInstancesParam) { 76 | instances, err := client.SelectInstances(param) 77 | if err != nil { 78 | panic("SelectInstances failed!" + err.Error()) 79 | } 80 | fmt.Printf("SelectInstances,param:%+v, result:%+v \n\n", param, instances) 81 | } 82 | 83 | func selectOneHealthyInstance(client naming_client.INamingClient, param vo.SelectOneHealthInstanceParam) { 84 | instances, err := client.SelectOneHealthyInstance(param) 85 | if err != nil { 86 | panic("SelectOneHealthyInstance failed!") 87 | } 88 | fmt.Printf("SelectOneHealthyInstance,param:%+v, result:%+v \n\n", param, instances) 89 | } 90 | 91 | func subscribe(client naming_client.INamingClient, param *vo.SubscribeParam) { 92 | client.Subscribe(param) 93 | } 94 | 95 | func unSubscribe(client naming_client.INamingClient, param *vo.SubscribeParam) { 96 | client.Unsubscribe(param) 97 | } 98 | 99 | func getAllService(client naming_client.INamingClient, param vo.GetAllServiceInfoParam) { 100 | service, err := client.GetAllServicesInfo(param) 101 | if err != nil { 102 | panic("GetAllService failed!") 103 | } 104 | fmt.Printf("GetAllService,param:%+v, result:%+v \n\n", param, service) 105 | } 106 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/nacos-group/nacos-sdk-go/v2 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.10 7 | github.com/alibabacloud-go/kms-20160120/v3 v3.2.3 8 | github.com/alibabacloud-go/tea v1.2.2 9 | github.com/alibabacloud-go/tea-utils/v2 v2.0.7 10 | github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 11 | github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.5.1 12 | github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.8 13 | github.com/buger/jsonparser v1.1.1 14 | github.com/golang/mock v1.6.0 15 | github.com/golang/protobuf v1.5.3 16 | github.com/pkg/errors v0.9.1 17 | github.com/prometheus/client_golang v1.12.2 18 | github.com/stretchr/testify v1.8.1 19 | go.uber.org/zap v1.21.0 20 | golang.org/x/sync v0.10.0 21 | golang.org/x/time v0.1.0 22 | google.golang.org/grpc v1.56.3 23 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f 24 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 25 | ) 26 | 27 | require ( 28 | github.com/alibabacloud-go/alibabacloud-gateway-pop v0.0.6 // indirect 29 | github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect 30 | github.com/alibabacloud-go/darabonba-array v0.1.0 // indirect 31 | github.com/alibabacloud-go/darabonba-encode-util v0.0.2 // indirect 32 | github.com/alibabacloud-go/darabonba-map v0.0.2 // indirect 33 | github.com/alibabacloud-go/darabonba-signature-util v0.0.7 // indirect 34 | github.com/alibabacloud-go/darabonba-string v1.0.2 // indirect 35 | github.com/alibabacloud-go/debug v1.0.1 // indirect 36 | github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect 37 | github.com/alibabacloud-go/openapi-util v0.1.0 // indirect 38 | github.com/alibabacloud-go/tea-utils v1.4.4 // indirect 39 | github.com/alibabacloud-go/tea-xml v1.1.3 // indirect 40 | github.com/aliyun/aliyun-secretsmanager-client-go v1.1.5 // indirect 41 | github.com/aliyun/credentials-go v1.4.3 // indirect 42 | github.com/beorn7/perks v1.0.1 // indirect 43 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 44 | github.com/clbanning/mxj/v2 v2.5.5 // indirect 45 | github.com/davecgh/go-spew v1.1.1 // indirect 46 | github.com/deckarep/golang-set v1.7.1 // indirect 47 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect 48 | github.com/json-iterator/go v1.1.12 // indirect 49 | github.com/kr/text v0.1.0 // indirect 50 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 51 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 52 | github.com/modern-go/reflect2 v1.0.2 // indirect 53 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect 54 | github.com/orcaman/concurrent-map v0.0.0-20210501183033-44dafcb38ecc // indirect 55 | github.com/pmezard/go-difflib v1.0.0 // indirect 56 | github.com/prometheus/client_model v0.2.0 // indirect 57 | github.com/prometheus/common v0.32.1 // indirect 58 | github.com/prometheus/procfs v0.7.3 // indirect 59 | github.com/tjfoc/gmsm v1.4.1 // indirect 60 | go.uber.org/atomic v1.7.0 // indirect 61 | go.uber.org/multierr v1.6.0 // indirect 62 | golang.org/x/crypto v0.31.0 // indirect 63 | golang.org/x/net v0.33.0 // indirect 64 | golang.org/x/sys v0.28.0 // indirect 65 | golang.org/x/text v0.21.0 // indirect 66 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect 67 | google.golang.org/protobuf v1.33.0 // indirect 68 | gopkg.in/ini.v1 v1.67.0 // indirect 69 | gopkg.in/yaml.v3 v3.0.1 // indirect 70 | ) 71 | -------------------------------------------------------------------------------- /inner/uuid/sql.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013-2018 by Maxim Bublis 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining 4 | // a copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to 8 | // permit persons to whom the Software is furnished to do so, subject to 9 | // the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be 12 | // included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | package uuid 23 | 24 | import ( 25 | "database/sql/driver" 26 | "fmt" 27 | ) 28 | 29 | // Value implements the driver.Valuer interface. 30 | func (u UUID) Value() (driver.Value, error) { 31 | return u.String(), nil 32 | } 33 | 34 | // Scan implements the sql.Scanner interface. 35 | // A 16-byte slice is handled by UnmarshalBinary, while 36 | // a longer byte slice or a string is handled by UnmarshalText. 37 | func (u *UUID) Scan(src interface{}) error { 38 | switch src := src.(type) { 39 | case []byte: 40 | if len(src) == Size { 41 | return u.UnmarshalBinary(src) 42 | } 43 | return u.UnmarshalText(src) 44 | 45 | case string: 46 | return u.UnmarshalText([]byte(src)) 47 | } 48 | 49 | return fmt.Errorf("uuid: cannot convert %T to UUID", src) 50 | } 51 | 52 | // NullUUID can be used with the standard sql package to represent a 53 | // UUID value that can be NULL in the database 54 | type NullUUID struct { 55 | UUID UUID 56 | Valid bool 57 | } 58 | 59 | // Value implements the driver.Valuer interface. 60 | func (u NullUUID) Value() (driver.Value, error) { 61 | if !u.Valid { 62 | return nil, nil 63 | } 64 | // Delegate to UUID Value function 65 | return u.UUID.Value() 66 | } 67 | 68 | // Scan implements the sql.Scanner interface. 69 | func (u *NullUUID) Scan(src interface{}) error { 70 | if src == nil { 71 | u.UUID, u.Valid = Nil, false 72 | return nil 73 | } 74 | 75 | // Delegate to UUID Scan function 76 | u.Valid = true 77 | return u.UUID.Scan(src) 78 | } 79 | -------------------------------------------------------------------------------- /inner/uuid/sql_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013-2018 by Maxim Bublis 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining 4 | // a copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to 8 | // permit persons to whom the Software is furnished to do so, subject to 9 | // the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be 12 | // included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | package uuid 23 | 24 | import ( 25 | . "gopkg.in/check.v1" 26 | ) 27 | 28 | type sqlTestSuite struct{} 29 | 30 | var _ = Suite(&sqlTestSuite{}) 31 | 32 | func (s *sqlTestSuite) TestValue(c *C) { 33 | u, err := FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8") 34 | c.Assert(err, IsNil) 35 | 36 | val, err := u.Value() 37 | c.Assert(err, IsNil) 38 | c.Assert(val, Equals, u.String()) 39 | } 40 | 41 | func (s *sqlTestSuite) TestValueNil(c *C) { 42 | u := UUID{} 43 | 44 | val, err := u.Value() 45 | c.Assert(err, IsNil) 46 | c.Assert(val, Equals, Nil.String()) 47 | } 48 | 49 | func (s *sqlTestSuite) TestNullUUIDValueNil(c *C) { 50 | u := NullUUID{} 51 | 52 | val, err := u.Value() 53 | c.Assert(err, IsNil) 54 | c.Assert(val, IsNil) 55 | } 56 | 57 | func (s *sqlTestSuite) TestScanBinary(c *C) { 58 | u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} 59 | b1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} 60 | 61 | u1 := UUID{} 62 | err := u1.Scan(b1) 63 | c.Assert(err, IsNil) 64 | c.Assert(u, Equals, u1) 65 | 66 | b2 := []byte{} 67 | u2 := UUID{} 68 | 69 | err = u2.Scan(b2) 70 | c.Assert(err, NotNil) 71 | } 72 | 73 | func (s *sqlTestSuite) TestScanString(c *C) { 74 | u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} 75 | s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" 76 | 77 | u1 := UUID{} 78 | err := u1.Scan(s1) 79 | c.Assert(err, IsNil) 80 | c.Assert(u, Equals, u1) 81 | 82 | s2 := "" 83 | u2 := UUID{} 84 | 85 | err = u2.Scan(s2) 86 | c.Assert(err, NotNil) 87 | } 88 | 89 | func (s *sqlTestSuite) TestScanText(c *C) { 90 | u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} 91 | b1 := []byte("6ba7b810-9dad-11d1-80b4-00c04fd430c8") 92 | 93 | u1 := UUID{} 94 | err := u1.Scan(b1) 95 | c.Assert(err, IsNil) 96 | c.Assert(u, Equals, u1) 97 | 98 | b2 := []byte("") 99 | u2 := UUID{} 100 | err = u2.Scan(b2) 101 | c.Assert(err, NotNil) 102 | } 103 | 104 | func (s *sqlTestSuite) TestScanUnsupported(c *C) { 105 | u := UUID{} 106 | 107 | err := u.Scan(true) 108 | c.Assert(err, NotNil) 109 | } 110 | 111 | func (s *sqlTestSuite) TestScanNil(c *C) { 112 | u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} 113 | 114 | err := u.Scan(nil) 115 | c.Assert(err, NotNil) 116 | } 117 | 118 | func (s *sqlTestSuite) TestNullUUIDScanValid(c *C) { 119 | u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} 120 | s1 := "6ba7b810-9dad-11d1-80b4-00c04fd430c8" 121 | 122 | u1 := NullUUID{} 123 | err := u1.Scan(s1) 124 | c.Assert(err, IsNil) 125 | c.Assert(u1.Valid, Equals, true) 126 | c.Assert(u1.UUID, Equals, u) 127 | } 128 | 129 | func (s *sqlTestSuite) TestNullUUIDScanNil(c *C) { 130 | u := NullUUID{UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8}, true} 131 | 132 | err := u.Scan(nil) 133 | c.Assert(err, IsNil) 134 | c.Assert(u.Valid, Equals, false) 135 | c.Assert(u.UUID, Equals, Nil) 136 | } 137 | -------------------------------------------------------------------------------- /inner/uuid/uuid.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013-2018 by Maxim Bublis 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining 4 | // a copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to 8 | // permit persons to whom the Software is furnished to do so, subject to 9 | // the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be 12 | // included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | // Package uuid provides implementation of Universally Unique Identifier (UUID). 23 | // Supported versions are 1, 3, 4 and 5 (as specified in RFC 4122) and 24 | // version 2 (as specified in DCE 1.1). 25 | package uuid 26 | 27 | import ( 28 | "bytes" 29 | "encoding/hex" 30 | ) 31 | 32 | // Size of a UUID in bytes. 33 | const Size = 16 34 | 35 | // UUID representation compliant with specification 36 | // described in RFC 4122. 37 | type UUID [Size]byte 38 | 39 | // UUID versions 40 | const ( 41 | _ byte = iota 42 | V1 43 | V2 44 | V3 45 | V4 46 | V5 47 | ) 48 | 49 | // UUID layout variants. 50 | const ( 51 | VariantNCS byte = iota 52 | VariantRFC4122 53 | VariantMicrosoft 54 | VariantFuture 55 | ) 56 | 57 | // UUID DCE domains. 58 | const ( 59 | DomainPerson = iota 60 | DomainGroup 61 | DomainOrg 62 | ) 63 | 64 | // String parse helpers. 65 | var ( 66 | urnPrefix = []byte("urn:uuid:") 67 | byteGroups = []int{8, 4, 4, 4, 12} 68 | ) 69 | 70 | // Nil is special form of UUID that is specified to have all 71 | // 128 bits set to zero. 72 | var Nil = UUID{} 73 | 74 | // Predefined namespace UUIDs. 75 | var ( 76 | NamespaceDNS = Must(FromString("6ba7b810-9dad-11d1-80b4-00c04fd430c8")) 77 | NamespaceURL = Must(FromString("6ba7b811-9dad-11d1-80b4-00c04fd430c8")) 78 | NamespaceOID = Must(FromString("6ba7b812-9dad-11d1-80b4-00c04fd430c8")) 79 | NamespaceX500 = Must(FromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8")) 80 | ) 81 | 82 | // Equal returns true if u1 and u2 equals, otherwise returns false. 83 | func Equal(u1 UUID, u2 UUID) bool { 84 | return bytes.Equal(u1[:], u2[:]) 85 | } 86 | 87 | // Version returns algorithm version used to generate UUID. 88 | func (u UUID) Version() byte { 89 | return u[6] >> 4 90 | } 91 | 92 | // Variant returns UUID layout variant. 93 | func (u UUID) Variant() byte { 94 | switch { 95 | case (u[8] >> 7) == 0x00: 96 | return VariantNCS 97 | case (u[8] >> 6) == 0x02: 98 | return VariantRFC4122 99 | case (u[8] >> 5) == 0x06: 100 | return VariantMicrosoft 101 | case (u[8] >> 5) == 0x07: 102 | fallthrough 103 | default: 104 | return VariantFuture 105 | } 106 | } 107 | 108 | // Bytes returns bytes slice representation of UUID. 109 | func (u UUID) Bytes() []byte { 110 | return u[:] 111 | } 112 | 113 | // Returns canonical string representation of UUID: 114 | // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. 115 | func (u UUID) String() string { 116 | buf := make([]byte, 36) 117 | 118 | hex.Encode(buf[0:8], u[0:4]) 119 | buf[8] = '-' 120 | hex.Encode(buf[9:13], u[4:6]) 121 | buf[13] = '-' 122 | hex.Encode(buf[14:18], u[6:8]) 123 | buf[18] = '-' 124 | hex.Encode(buf[19:23], u[8:10]) 125 | buf[23] = '-' 126 | hex.Encode(buf[24:], u[10:]) 127 | 128 | return string(buf) 129 | } 130 | 131 | // SetVersion sets version bits. 132 | func (u *UUID) SetVersion(v byte) { 133 | u[6] = (u[6] & 0x0f) | (v << 4) 134 | } 135 | 136 | // SetVariant sets variant bits. 137 | func (u *UUID) SetVariant(v byte) { 138 | switch v { 139 | case VariantNCS: 140 | u[8] = (u[8]&(0xff>>1) | (0x00 << 7)) 141 | case VariantRFC4122: 142 | u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) 143 | case VariantMicrosoft: 144 | u[8] = (u[8]&(0xff>>3) | (0x06 << 5)) 145 | case VariantFuture: 146 | fallthrough 147 | default: 148 | u[8] = (u[8]&(0xff>>3) | (0x07 << 5)) 149 | } 150 | } 151 | 152 | // Must is a helper that wraps a call to a function returning (UUID, error) 153 | // and panics if the error is non-nil. It is intended for use in variable 154 | // initializations such as 155 | // var packageUUID = uuid.Must(uuid.FromString("123e4567-e89b-12d3-a456-426655440000")); 156 | func Must(u UUID, err error) UUID { 157 | if err != nil { 158 | panic(err) 159 | } 160 | return u 161 | } 162 | -------------------------------------------------------------------------------- /inner/uuid/uuid_test.go: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013-2018 by Maxim Bublis 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining 4 | // a copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to 8 | // permit persons to whom the Software is furnished to do so, subject to 9 | // the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be 12 | // included in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | package uuid 23 | 24 | import ( 25 | "bytes" 26 | "fmt" 27 | "testing" 28 | 29 | . "gopkg.in/check.v1" 30 | ) 31 | 32 | // Hook up gocheck into the "go test" runner. 33 | func TestUUID(t *testing.T) { TestingT(t) } 34 | 35 | type testSuite struct{} 36 | 37 | var _ = Suite(&testSuite{}) 38 | 39 | func (s *testSuite) TestBytes(c *C) { 40 | u := UUID{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} 41 | 42 | bytes1 := []byte{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} 43 | 44 | c.Assert(bytes.Equal(u.Bytes(), bytes1), Equals, true) 45 | } 46 | 47 | func (s *testSuite) TestString(c *C) { 48 | c.Assert(NamespaceDNS.String(), Equals, "6ba7b810-9dad-11d1-80b4-00c04fd430c8") 49 | } 50 | 51 | func (s *testSuite) TestEqual(c *C) { 52 | c.Assert(Equal(NamespaceDNS, NamespaceDNS), Equals, true) 53 | c.Assert(Equal(NamespaceDNS, NamespaceURL), Equals, false) 54 | } 55 | 56 | func (s *testSuite) TestVersion(c *C) { 57 | u := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 58 | c.Assert(u.Version(), Equals, V1) 59 | } 60 | 61 | func (s *testSuite) TestSetVersion(c *C) { 62 | u := UUID{} 63 | u.SetVersion(4) 64 | c.Assert(u.Version(), Equals, V4) 65 | } 66 | 67 | func (s *testSuite) TestVariant(c *C) { 68 | u1 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 69 | c.Assert(u1.Variant(), Equals, VariantNCS) 70 | 71 | u2 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 72 | c.Assert(u2.Variant(), Equals, VariantRFC4122) 73 | 74 | u3 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 75 | c.Assert(u3.Variant(), Equals, VariantMicrosoft) 76 | 77 | u4 := UUID{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 78 | c.Assert(u4.Variant(), Equals, VariantFuture) 79 | } 80 | 81 | func (s *testSuite) TestSetVariant(c *C) { 82 | u := UUID{} 83 | u.SetVariant(VariantNCS) 84 | c.Assert(u.Variant(), Equals, VariantNCS) 85 | u.SetVariant(VariantRFC4122) 86 | c.Assert(u.Variant(), Equals, VariantRFC4122) 87 | u.SetVariant(VariantMicrosoft) 88 | c.Assert(u.Variant(), Equals, VariantMicrosoft) 89 | u.SetVariant(VariantFuture) 90 | c.Assert(u.Variant(), Equals, VariantFuture) 91 | } 92 | 93 | func (s *testSuite) TestMust(c *C) { 94 | defer func() { 95 | c.Assert(recover(), NotNil) 96 | }() 97 | Must(func() (UUID, error) { 98 | return Nil, fmt.Errorf("uuid: expected error") 99 | }()) 100 | } 101 | -------------------------------------------------------------------------------- /model/config.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package model 18 | 19 | import "encoding/json" 20 | 21 | type ConfigItem struct { 22 | Id json.Number `param:"id"` 23 | DataId string `param:"dataId"` 24 | Group string `param:"group"` 25 | Content string `param:"content"` 26 | Md5 string `param:"md5"` 27 | Tenant string `param:"tenant"` 28 | Appname string `param:"appname"` 29 | } 30 | type ConfigPage struct { 31 | TotalCount int `param:"totalCount"` 32 | PageNumber int `param:"pageNumber"` 33 | PagesAvailable int `param:"pagesAvailable"` 34 | PageItems []ConfigItem `param:"pageItems"` 35 | } 36 | 37 | type ConfigListenContext struct { 38 | Group string `json:"group"` 39 | Md5 string `json:"md5"` 40 | DataId string `json:"dataId"` 41 | Tenant string `json:"tenant"` 42 | } 43 | 44 | type ConfigContext struct { 45 | Group string `json:"group"` 46 | DataId string `json:"dataId"` 47 | Tenant string `json:"tenant"` 48 | } 49 | 50 | type ConfigPageResult struct { 51 | Code int `json:"code"` 52 | Message string `json:"message"` 53 | Data ConfigPage `json:"data"` 54 | } 55 | -------------------------------------------------------------------------------- /model/service.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package model 18 | 19 | import "time" 20 | 21 | const ( 22 | StateRunning = iota 23 | StateShutdown 24 | ) 25 | 26 | type Instance struct { 27 | InstanceId string `json:"instanceId"` 28 | Ip string `json:"ip"` 29 | Port uint64 `json:"port"` 30 | Weight float64 `json:"weight"` 31 | Healthy bool `json:"healthy"` 32 | Enable bool `json:"enabled"` 33 | Ephemeral bool `json:"ephemeral"` 34 | ClusterName string `json:"clusterName"` 35 | ServiceName string `json:"serviceName"` 36 | Metadata map[string]string `json:"metadata"` 37 | InstanceHeartBeatInterval int `json:"instanceHeartBeatInterval"` 38 | IpDeleteTimeout int `json:"ipDeleteTimeout"` 39 | InstanceHeartBeatTimeOut int `json:"instanceHeartBeatTimeOut"` 40 | } 41 | 42 | type Service struct { 43 | CacheMillis uint64 `json:"cacheMillis"` 44 | Hosts []Instance `json:"hosts"` 45 | Checksum string `json:"checksum"` 46 | LastRefTime uint64 `json:"lastRefTime"` 47 | Clusters string `json:"clusters"` 48 | Name string `json:"name"` 49 | GroupName string `json:"groupName"` 50 | Valid bool `json:"valid"` 51 | AllIPs bool `json:"allIPs"` 52 | ReachProtectionThreshold bool `json:"reachProtectionThreshold"` 53 | } 54 | 55 | type ServiceDetail struct { 56 | Service ServiceInfo `json:"service"` 57 | Clusters []Cluster `json:"clusters"` 58 | } 59 | 60 | type ServiceInfo struct { 61 | App string `json:"app"` 62 | Group string `json:"group"` 63 | HealthCheckMode string `json:"healthCheckMode"` 64 | Metadata map[string]string `json:"metadata"` 65 | Name string `json:"name"` 66 | ProtectThreshold float64 `json:"protectThreshold"` 67 | Selector ServiceSelector `json:"selector"` 68 | } 69 | 70 | type ServiceSelector struct { 71 | Selector string 72 | } 73 | 74 | type Cluster struct { 75 | ServiceName string `json:"serviceName"` 76 | Name string `json:"name"` 77 | HealthyChecker ClusterHealthChecker `json:"healthyChecker"` 78 | DefaultPort uint64 `json:"defaultPort"` 79 | DefaultCheckPort uint64 `json:"defaultCheckPort"` 80 | UseIPPort4Check bool `json:"useIpPort4Check"` 81 | Metadata map[string]string `json:"metadata"` 82 | } 83 | 84 | type ClusterHealthChecker struct { 85 | Type string `json:"type"` 86 | } 87 | 88 | type BeatInfo struct { 89 | Ip string `json:"ip"` 90 | Port uint64 `json:"port"` 91 | Weight float64 `json:"weight"` 92 | ServiceName string `json:"serviceName"` 93 | Cluster string `json:"cluster"` 94 | Metadata map[string]string `json:"metadata"` 95 | Scheduled bool `json:"scheduled"` 96 | Period time.Duration `json:"-"` 97 | State int32 `json:"-"` 98 | } 99 | 100 | type ExpressionSelector struct { 101 | Type string `json:"type"` 102 | Expression string `json:"expression"` 103 | } 104 | 105 | type ServiceList struct { 106 | Count int64 `json:"count"` 107 | Doms []string `json:"doms"` 108 | } 109 | -------------------------------------------------------------------------------- /util/common.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "encoding/json" 21 | "net" 22 | "net/http" 23 | "net/url" 24 | "strconv" 25 | "time" 26 | 27 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 28 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 29 | "github.com/nacos-group/nacos-sdk-go/v2/model" 30 | ) 31 | 32 | func CurrentMillis() int64 { 33 | return time.Now().UnixNano() / 1e6 34 | } 35 | 36 | func JsonToService(result string) *model.Service { 37 | var service model.Service 38 | err := json.Unmarshal([]byte(result), &service) 39 | if err != nil { 40 | logger.Errorf("failed to unmarshal json string:%s err:%+v", result, err) 41 | return nil 42 | } 43 | if len(service.Hosts) == 0 { 44 | logger.Warnf("instance list is empty,json string:%s", result) 45 | } 46 | return &service 47 | 48 | } 49 | func ToJsonString(object interface{}) string { 50 | js, _ := json.Marshal(object) 51 | return string(js) 52 | } 53 | 54 | func GetGroupName(serviceName string, groupName string) string { 55 | return groupName + constant.SERVICE_INFO_SPLITER + serviceName 56 | } 57 | 58 | func GetServiceCacheKey(serviceName string, clusters string) string { 59 | if clusters == "" { 60 | return serviceName 61 | } 62 | return serviceName + constant.SERVICE_INFO_SPLITER + clusters 63 | } 64 | 65 | func GetConfigCacheKey(dataId string, group string, tenant string) string { 66 | return dataId + constant.CONFIG_INFO_SPLITER + group + constant.CONFIG_INFO_SPLITER + tenant 67 | } 68 | 69 | var localIP = "" 70 | 71 | func LocalIP() string { 72 | if localIP == "" { 73 | netInterfaces, err := net.Interfaces() 74 | if err != nil { 75 | logger.Errorf("get Interfaces failed,err:%+v", err) 76 | return "" 77 | } 78 | 79 | for i := 0; i < len(netInterfaces); i++ { 80 | if ((netInterfaces[i].Flags & net.FlagUp) != 0) && ((netInterfaces[i].Flags & net.FlagLoopback) == 0) { 81 | addrs, err := netInterfaces[i].Addrs() 82 | if err != nil { 83 | logger.Errorf("get InterfaceAddress failed,err:%+v", err) 84 | return "" 85 | } 86 | for _, address := range addrs { 87 | if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil { 88 | localIP = ipnet.IP.String() 89 | break 90 | } 91 | } 92 | } 93 | } 94 | 95 | if len(localIP) > 0 { 96 | logger.Infof("Local IP:%s", localIP) 97 | } 98 | } 99 | return localIP 100 | } 101 | 102 | func GetDurationWithDefault(metadata map[string]string, key string, defaultDuration time.Duration) time.Duration { 103 | data, ok := metadata[key] 104 | if ok { 105 | value, err := strconv.ParseInt(data, 10, 64) 106 | if err != nil { 107 | logger.Errorf("key:%s is not a number", key) 108 | return defaultDuration 109 | } 110 | return time.Duration(value) 111 | } 112 | return defaultDuration 113 | } 114 | 115 | func GetUrlFormedMap(source map[string]string) (urlEncoded string) { 116 | urlEncoder := url.Values{} 117 | for key, value := range source { 118 | urlEncoder.Add(key, value) 119 | } 120 | urlEncoded = urlEncoder.Encode() 121 | return 122 | } 123 | 124 | // get status code by response,default is NA 125 | func GetStatusCode(response *http.Response) string { 126 | var statusCode string 127 | if response != nil { 128 | statusCode = strconv.Itoa(response.StatusCode) 129 | } else { 130 | statusCode = "NA" 131 | } 132 | return statusCode 133 | } 134 | 135 | func DeepCopyMap(params map[string]string) map[string]string { 136 | result := make(map[string]string, len(params)) 137 | for k, v := range params { 138 | result[k] = v 139 | } 140 | return result 141 | } 142 | -------------------------------------------------------------------------------- /util/content.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | const SHOW_CONTENT_SIZE = 100 20 | 21 | func TruncateContent(content string) string { 22 | if content == "" { 23 | return "" 24 | } 25 | if len(content) <= SHOW_CONTENT_SIZE { 26 | return content 27 | } 28 | return content[0:SHOW_CONTENT_SIZE] 29 | } 30 | -------------------------------------------------------------------------------- /util/md5.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "crypto/md5" 21 | "fmt" 22 | "io" 23 | ) 24 | 25 | func Md5(content string) (md string) { 26 | if content != "" { 27 | h := md5.New() 28 | _, _ = io.WriteString(h, content) 29 | md = fmt.Sprintf("%x", h.Sum(nil)) 30 | } 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /util/md5_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestMd5(t *testing.T) { 26 | md5 := Md5("demo") 27 | assert.Equal(t, "fe01ce2a7fbac8fafaed7c982a04e229", md5) 28 | } 29 | -------------------------------------------------------------------------------- /util/object2param.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "encoding/json" 21 | "reflect" 22 | "strconv" 23 | "strings" 24 | 25 | "github.com/nacos-group/nacos-sdk-go/v2/common/logger" 26 | ) 27 | 28 | func TransformObject2Param(object interface{}) (params map[string]string) { 29 | params = make(map[string]string) 30 | if object != nil { 31 | valueOf := reflect.ValueOf(object) 32 | typeOf := reflect.TypeOf(object) 33 | if reflect.TypeOf(object).Kind() == reflect.Ptr { 34 | valueOf = reflect.ValueOf(object).Elem() 35 | typeOf = reflect.TypeOf(object).Elem() 36 | } 37 | numField := valueOf.NumField() 38 | for i := 0; i < numField; i++ { 39 | tag := typeOf.Field(i).Tag.Get("param") 40 | if len(tag) > 0 && tag != "-" { 41 | switch valueOf.Field(i).Kind() { 42 | case reflect.Int, reflect.Int8, reflect.Int16, 43 | reflect.Int32, reflect.Int64: 44 | params[tag] = strconv.FormatInt(valueOf.Field(i).Int(), 10) 45 | case reflect.Uint, reflect.Uint8, reflect.Uint16, 46 | reflect.Uint32, reflect.Uint64: 47 | params[tag] = strconv.FormatUint(valueOf.Field(i).Uint(), 10) 48 | case reflect.Float32, reflect.Float64: 49 | params[tag] = strconv.FormatFloat(valueOf.Field(i).Float(), 'f', -1, 64) 50 | case reflect.Bool: 51 | params[tag] = strconv.FormatBool(valueOf.Field(i).Bool()) 52 | case reflect.String: 53 | if len(valueOf.Field(i).String()) > 0 { 54 | params[tag] = valueOf.Field(i).String() 55 | } 56 | case reflect.Map: 57 | if !valueOf.Field(i).IsNil() { 58 | bytes, err := json.Marshal(valueOf.Field(i).Interface()) 59 | if err != nil { 60 | logger.Errorf("[TransformObject2Param] json.Marshal err:%+v", err) 61 | } else { 62 | params[tag] = string(bytes) 63 | } 64 | } 65 | case reflect.Slice: 66 | if ss, ok := valueOf.Field(i).Interface().([]string); ok { 67 | var pv string 68 | for _, sv := range ss { 69 | pv += sv + "," 70 | } 71 | if strings.HasSuffix(pv, ",") { 72 | pv = pv[:len(pv)-1] 73 | } 74 | if len(pv) > 0 { 75 | params[tag] = pv 76 | } 77 | } 78 | } 79 | } 80 | } 81 | } 82 | return 83 | } 84 | -------------------------------------------------------------------------------- /util/object2param_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | type object struct { 26 | Name string `param:"name"` 27 | Likes []string `param:"likes"` 28 | Metadata map[string]string `param:"metadata"` 29 | Age uint64 `param:"age"` 30 | Healthy bool `param:"healthy"` 31 | Money int `param:"money"` 32 | } 33 | 34 | func TestTransformObject2Param(t *testing.T) { 35 | assert.Equal(t, map[string]string{}, TransformObject2Param(nil)) 36 | obj := object{ 37 | Name: "code", 38 | Likes: []string{"a", "b"}, 39 | Metadata: map[string]string{ 40 | "M1": "m1", 41 | }, 42 | Age: 10, 43 | Healthy: true, 44 | Money: 10, 45 | } 46 | params := TransformObject2Param(&obj) 47 | assert.Equal(t, map[string]string{ 48 | "name": "code", 49 | "metadata": `{"M1":"m1"}`, 50 | "likes": "a,b", 51 | "age": "10", 52 | "money": "10", 53 | "healthy": "true", 54 | }, params) 55 | } 56 | -------------------------------------------------------------------------------- /util/semaphore.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package util 18 | 19 | type Semaphore struct { 20 | bufSize int 21 | channel chan int8 22 | } 23 | 24 | func NewSemaphore(concurrencyNum int) *Semaphore { 25 | return &Semaphore{channel: make(chan int8, concurrencyNum), bufSize: concurrencyNum} 26 | } 27 | 28 | func (this *Semaphore) TryAcquire() bool { 29 | select { 30 | case this.channel <- int8(0): 31 | return true 32 | default: 33 | return false 34 | } 35 | } 36 | 37 | func (this *Semaphore) Acquire() { 38 | this.channel <- int8(0) 39 | } 40 | 41 | func (this *Semaphore) Release() { 42 | <-this.channel 43 | } 44 | 45 | func (this *Semaphore) AvailablePermits() int { 46 | return this.bufSize - len(this.channel) 47 | } 48 | -------------------------------------------------------------------------------- /vo/client_param.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package vo 18 | 19 | import ( 20 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 21 | "github.com/nacos-group/nacos-sdk-go/v2/common/security" 22 | ) 23 | 24 | type NacosClientParam struct { 25 | ClientConfig *constant.ClientConfig // optional 26 | ServerConfigs []constant.ServerConfig // optional 27 | RamCredentialProvider security.RamCredentialProvider // optinal 28 | } 29 | -------------------------------------------------------------------------------- /vo/config_param.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package vo 18 | 19 | type Listener func(namespace, group, dataId, data string) 20 | 21 | type ConfigParam struct { 22 | DataId string `param:"dataId"` //required 23 | Group string `param:"group"` //required 24 | Content string `param:"content"` //required 25 | Tag string `param:"tag"` 26 | ConfigTags string `param:"configTags"` 27 | AppName string `param:"appName"` 28 | BetaIps string `param:"betaIps"` 29 | CasMd5 string `param:"casMd5"` 30 | Type string `param:"type"` 31 | SrcUser string `param:"srcUser"` 32 | EncryptedDataKey string `param:"encryptedDataKey"` 33 | KmsKeyId string `param:"kmsKeyId"` 34 | UsageType UsageType `param:"usageType"` 35 | OnChange func(namespace, group, dataId, data string) 36 | } 37 | 38 | func (this *ConfigParam) DeepCopy() *ConfigParam { 39 | if this == nil { 40 | return nil 41 | } 42 | result := new(ConfigParam) 43 | *result = *this 44 | return result 45 | } 46 | 47 | type UsageType string 48 | 49 | const ( 50 | RequestType UsageType = "RequestType" 51 | ResponseType UsageType = "ResponseType" 52 | ) 53 | 54 | type SearchConfigParam struct { 55 | Search string `param:"search"` 56 | DataId string `param:"dataId"` 57 | Group string `param:"group"` 58 | Tag string `param:"tag"` 59 | AppName string `param:"appName"` 60 | PageNo int `param:"pageNo"` 61 | PageSize int `param:"pageSize"` 62 | } 63 | -------------------------------------------------------------------------------- /vo/config_param_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 1999-2020 Alibaba Group Holding Ltd. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package vo 18 | 19 | import ( 20 | "github.com/stretchr/testify/assert" 21 | "testing" 22 | ) 23 | 24 | func TestConfigParamDeepCopy(t *testing.T) { 25 | t.Run("test configParam deep copy", func(t *testing.T) { 26 | param := &ConfigParam{ 27 | DataId: "dataId", 28 | Group: "", 29 | Content: "common content", 30 | UsageType: RequestType, 31 | OnChange: func(namespace, group, dataId, data string) { 32 | //do nothing 33 | }, 34 | } 35 | paramDeepCopied := param.DeepCopy() 36 | 37 | assert.Equal(t, param.DataId, paramDeepCopied.DataId) 38 | assert.Equal(t, param.Content, paramDeepCopied.Content) 39 | assert.NotEqual(t, ¶m.OnChange, ¶mDeepCopied.OnChange) 40 | assert.NotEqual(t, ¶m, ¶mDeepCopied) 41 | }) 42 | } 43 | --------------------------------------------------------------------------------