├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── pr-check.yml │ └── push-check.yml ├── .gitignore ├── .licenserc.yaml ├── LICENSE ├── Makefile ├── OWNERS ├── README.md ├── README_CN.md ├── _typos.toml ├── example ├── basic │ ├── client │ │ └── main.go │ └── server │ │ └── main.go ├── custom-config │ ├── client │ │ └── main.go │ └── server │ │ └── main.go ├── custom-logger │ └── main.go └── hello │ ├── hello.thrift │ ├── kitex_gen │ └── api │ │ ├── hello.go │ │ ├── hello │ │ ├── client.go │ │ ├── hello.go │ │ ├── invoker.go │ │ └── server.go │ │ ├── k-consts.go │ │ └── k-hello.go │ └── kitex_info.yaml ├── go.mod ├── go.sum ├── hack ├── resolve-modules.sh ├── tools.sh └── util.sh ├── licenses ├── LICENSE-nacos-sdk-go └── LICENSE-testify ├── nacos ├── client.go ├── env.go ├── env_test.go └── logger.go ├── registry ├── registry.go └── registry_test.go ├── resolver ├── resolver.go └── resolver_test.go └── v2 ├── Makefile ├── README.md ├── README_CN.md ├── example ├── basic │ ├── client │ │ └── client.go │ └── server │ │ └── server.go ├── custom-config │ ├── client │ │ └── main.go │ └── server │ │ └── main.go └── hello │ ├── hello.thrift │ ├── kitex_gen │ └── api │ │ ├── hello.go │ │ ├── hello │ │ ├── client.go │ │ ├── hello.go │ │ ├── invoker.go │ │ └── server.go │ │ ├── k-consts.go │ │ └── k-hello.go │ └── kitex_info.yaml ├── go.mod ├── go.sum ├── nacos ├── client.go ├── env.go └── env_test.go ├── registry ├── registry.go └── registry_test.go └── resolver ├── resolver.go └── resolver_test.go /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/pr-check.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Check 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | compliant: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | 11 | - name: Check License Header 12 | uses: apache/skywalking-eyes/header@v0.4.0 13 | env: 14 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 15 | 16 | build: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Set up Go 22 | uses: actions/setup-go@v5 23 | with: 24 | go-version: stable 25 | # Enable it if we're going to use GitHub only 26 | cache: true 27 | 28 | resolve-modules: 29 | name: resolve module 30 | runs-on: ubuntu-latest 31 | outputs: 32 | matrix: ${{ steps.set-matrix.outputs.matrix }} 33 | steps: 34 | - name: Checkout Repo 35 | uses: actions/checkout@v4 36 | 37 | - id: set-matrix 38 | run: ./hack/resolve-modules.sh 39 | 40 | lint: 41 | name: lint module 42 | runs-on: ubuntu-latest 43 | needs: resolve-modules 44 | strategy: 45 | matrix: ${{ fromJson(needs.resolve-modules.outputs.matrix) }} 46 | steps: 47 | - uses: actions/checkout@v4 48 | - name: Lint 49 | uses: golangci/golangci-lint-action@v6 50 | with: 51 | version: latest 52 | working-directory: ${{ matrix.workdir }} 53 | args: -E gofumpt --timeout 10m 54 | -------------------------------------------------------------------------------- /.github/workflows/push-check.yml: -------------------------------------------------------------------------------- 1 | name: Push Check 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | matrix: 9 | go: [1.20.x, 1.21.x, 1.22.x, 1.23.x] 10 | runs-on: ubuntu-latest 11 | 12 | services: 13 | nacos: 14 | image: 'nacos/nacos-server:v2.4.0.1' 15 | ports: 16 | - '8848:8848' 17 | - '9848:9848' 18 | env: 19 | MODE: standalone 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | - name: Set up Go 25 | uses: actions/setup-go@v5 26 | with: 27 | go-version: ${{ matrix.go }} 28 | 29 | - name: Module cache 30 | uses: actions/cache@v4 31 | with: 32 | path: | 33 | ~/.cache/go-build 34 | ~/go/pkg/mod 35 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 36 | restore-keys: | 37 | ${{ runner.os }}-go 38 | 39 | # - name: typos-action 40 | # uses: crate-ci/typos@v1.2.1 41 | 42 | - name: Benchmark 43 | run: go test -bench=. -benchmem -run=none ./... 44 | 45 | - name: Unit Test 46 | run: go test -race -covermode=atomic -coverprofile=coverage.out ./... 47 | env: 48 | serverAddr: 127.0.0.1 49 | serverPort: 8848 50 | namespace: public 51 | 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | # Files generated by IDEs 18 | .idea/ 19 | *.iml 20 | # Vscode files 21 | .vscode 22 | -------------------------------------------------------------------------------- /.licenserc.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021 CloudWeGo Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | header: 17 | license: 18 | spdx-id: Apache-2.0 19 | copyright-owner: CloudWeGo Authors 20 | paths: 21 | - '**/*.go' 22 | paths-ignore: 23 | - example/hello/** 24 | - v2/example/hello/** 25 | comment: on-failure 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NACOS_VERSION ?= 2.0.3 2 | TOOLS_SHELL="./hack/tools.sh" 3 | 4 | prepare: 5 | docker pull nacos/nacos-server:$(NACOS_VERSION) 6 | docker run --rm --name nacos-quick -e MODE=standalone -p 8848:8848 -p 9848:9848 -d nacos/nacos-server:$(NACOS_VERSION) 7 | 8 | stop: 9 | docker stop nacos-quick 10 | 11 | 12 | .PHONY: test 13 | test: 14 | @${TOOLS_SHELL} test 15 | @echo "go test finished" 16 | 17 | 18 | 19 | .PHONY: vet 20 | vet: 21 | @${TOOLS_SHELL} vet 22 | @echo "vet check finished" 23 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | approvers: 2 | - baiyutang 3 | - joway 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # registry-nacos (*This is a community driven project*) 2 | 3 | [中文](https://github.com/kitex-contrib/registry-nacos/blob/main/README_CN.md) 4 | 5 | Nacos as service discovery. 6 | 7 | ## How to use? 8 | 9 | ### Basic 10 | 11 | #### Server 12 | 13 | ```go 14 | import ( 15 | // ... 16 | "github.com/kitex-contrib/registry-nacos/registry" 17 | "github.com/nacos-group/nacos-sdk-go/clients" 18 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 19 | "github.com/nacos-group/nacos-sdk-go/common/constant" 20 | "github.com/nacos-group/nacos-sdk-go/vo" 21 | "github.com/cloudwego/kitex/pkg/rpcinfo" 22 | // ... 23 | ) 24 | 25 | func main() { 26 | // ... 27 | r, err := registry.NewDefaultNacosRegistry() 28 | if err != nil { 29 | panic(err) 30 | } 31 | svr := echo.NewServer( 32 | new(EchoImpl), 33 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "echo"}), 34 | server.WithRegistry(r), 35 | ) 36 | if err := svr.Run(); err != nil { 37 | log.Println("server stopped with error:", err) 38 | } else { 39 | log.Println("server stopped") 40 | } 41 | // ... 42 | } 43 | ``` 44 | 45 | #### Client 46 | 47 | ```go 48 | import ( 49 | // ... 50 | "github.com/kitex-contrib/registry-nacos/resolver" 51 | "github.com/nacos-group/nacos-sdk-go/clients" 52 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 53 | "github.com/nacos-group/nacos-sdk-go/common/constant" 54 | "github.com/nacos-group/nacos-sdk-go/vo" 55 | // ... 56 | ) 57 | 58 | func main() { 59 | // ... 60 | r, err := resolver.NewDefaultNacosResolver() 61 | if err != nil { 62 | panic(err) 63 | } 64 | client, err := echo.NewClient("echo", client.WithResolver(r)) 65 | if err != nil { 66 | log.Fatal(err) 67 | } 68 | // ... 69 | } 70 | ``` 71 | 72 | ### Custom Nacos Client Configuration 73 | 74 | #### Server 75 | 76 | ```go 77 | import ( 78 | // ... 79 | "github.com/kitex-contrib/registry-nacos/registry" 80 | "github.com/nacos-group/nacos-sdk-go/clients" 81 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 82 | "github.com/nacos-group/nacos-sdk-go/common/constant" 83 | "github.com/nacos-group/nacos-sdk-go/vo" 84 | // ... 85 | ) 86 | func main() { 87 | // ... 88 | sc := []constant.ServerConfig{ 89 | *constant.NewServerConfig("127.0.0.1", 8848), 90 | } 91 | 92 | cc := constant.ClientConfig{ 93 | NamespaceId: "public", 94 | TimeoutMs: 5000, 95 | NotLoadCacheAtStart: true, 96 | LogDir: "/tmp/nacos/log", 97 | CacheDir: "/tmp/nacos/cache", 98 | LogLevel: "info", 99 | Username: "your-name", 100 | Password: "your-password", 101 | } 102 | 103 | cli, err := clients.NewNamingClient( 104 | vo.NacosClientParam{ 105 | ClientConfig: &cc, 106 | ServerConfigs: sc, 107 | }, 108 | ) 109 | if err != nil { 110 | panic(err) 111 | } 112 | 113 | svr := echo.NewServer(new(EchoImpl), 114 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "echo"}), 115 | server.WithRegistry(registry.NewNacosRegistry(cli)), 116 | ) 117 | if err := svr.Run(); err != nil { 118 | log.Println("server stopped with error:", err) 119 | } else { 120 | log.Println("server stopped") 121 | } 122 | // ... 123 | } 124 | ``` 125 | 126 | #### Client 127 | 128 | ```go 129 | import ( 130 | // ... 131 | "github.com/kitex-contrib/registry-nacos/resolver" 132 | "github.com/nacos-group/nacos-sdk-go/clients" 133 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 134 | "github.com/nacos-group/nacos-sdk-go/common/constant" 135 | "github.com/nacos-group/nacos-sdk-go/vo" 136 | // ... 137 | ) 138 | func main() { 139 | // ... 140 | sc := []constant.ServerConfig{ 141 | *constant.NewServerConfig("127.0.0.1", 8848), 142 | } 143 | cc := constant.ClientConfig{ 144 | NamespaceId: "public", 145 | TimeoutMs: 5000, 146 | NotLoadCacheAtStart: true, 147 | LogDir: "/tmp/nacos/log", 148 | CacheDir: "/tmp/nacos/cache", 149 | LogLevel: "info", 150 | Username: "your-name", 151 | Password: "your-password", 152 | } 153 | 154 | cli, err := clients.NewNamingClient( 155 | vo.NacosClientParam{ 156 | ClientConfig: &cc, 157 | ServerConfigs: sc, 158 | }, 159 | ) 160 | if err != nil { 161 | panic(err) 162 | } 163 | client, err := echo.NewClient("echo", client.WithResolver(resolver.NewNacosResolver(cli)) 164 | if err != nil { 165 | log.Fatal(err) 166 | } 167 | // ... 168 | } 169 | ``` 170 | 171 | ### Environment Variable 172 | 173 | | Environment Variable Name | Environment Variable Default Value | Environment Variable Introduction | 174 | | ------------------------- | ---------------------------------- | --------------------------------- | 175 | | serverAddr | 127.0.0.1 | nacos server address | 176 | | serverPort | 8848 | nacos server port | 177 | | namespace | | the namespaceId of nacos | 178 | | KITEX_NACOS_ENV_TAGS | "" | support inject default tags| 179 | 180 | ### More Info 181 | 182 | Refer to [example](example) for more usage. 183 | 184 | ## Compatibility 185 | This Package use Nacos1.x client. The Nacos2.0 and Nacos1.0 Server are fully compatible with it. [see](https://nacos.io/en-us/docs/v2/upgrading/2.0.0-compatibility.html) 186 | 187 | maintained by: [baiyutang](https://github.com/baiyutang) 188 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # registry-nacos (*这是一个由社区驱动的项目*) 2 | 3 | [English](https://github.com/kitex-contrib/registry-nacos/blob/main/README.md) 4 | 5 | 使用 **nacos** 作为 **Kitex** 的注册中心 6 | 7 | ## 这个项目应当如何使用? 8 | 9 | ### 基本使用 10 | 11 | #### 服务端 12 | 13 | ```go 14 | import ( 15 | // ... 16 | "github.com/kitex-contrib/registry-nacos/registry" 17 | "github.com/nacos-group/nacos-sdk-go/clients" 18 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 19 | "github.com/nacos-group/nacos-sdk-go/common/constant" 20 | "github.com/nacos-group/nacos-sdk-go/vo" 21 | "github.com/cloudwego/kitex/pkg/rpcinfo" 22 | // ... 23 | ) 24 | 25 | func main() { 26 | // ... 27 | r, err := registry.NewDefaultNacosRegistry() 28 | if err != nil { 29 | panic(err) 30 | } 31 | svr := echo.NewServer( 32 | new(EchoImpl), 33 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "echo"}), 34 | server.WithRegistry(r), 35 | ) 36 | if err := svr.Run(); err != nil { 37 | log.Println("server stopped with error:", err) 38 | } else { 39 | log.Println("server stopped") 40 | } 41 | // ... 42 | } 43 | ``` 44 | 45 | #### 客户端 46 | 47 | ```go 48 | import ( 49 | // ... 50 | "github.com/kitex-contrib/registry-nacos/resolver" 51 | "github.com/nacos-group/nacos-sdk-go/clients" 52 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 53 | "github.com/nacos-group/nacos-sdk-go/common/constant" 54 | "github.com/nacos-group/nacos-sdk-go/vo" 55 | // ... 56 | ) 57 | 58 | func main() { 59 | // ... 60 | r, err := resolver.NewDefaultNacosResolver() 61 | if err != nil { 62 | panic(err) 63 | } 64 | client, err := echo.NewClient("echo", client.WithResolver(r)) 65 | if err != nil { 66 | log.Fatal(err) 67 | } 68 | // ... 69 | } 70 | ``` 71 | 72 | ### 自定义 Nacos Client 配置 73 | 74 | #### 服务端 75 | 76 | ```go 77 | import ( 78 | // ... 79 | "github.com/kitex-contrib/registry-nacos/registry" 80 | "github.com/nacos-group/nacos-sdk-go/clients" 81 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 82 | "github.com/nacos-group/nacos-sdk-go/common/constant" 83 | "github.com/nacos-group/nacos-sdk-go/vo" 84 | // ... 85 | ) 86 | func main() { 87 | // ... 88 | sc := []constant.ServerConfig{ 89 | *constant.NewServerConfig("127.0.0.1", 8848), 90 | } 91 | 92 | cc := constant.ClientConfig{ 93 | NamespaceId: "public", 94 | TimeoutMs: 5000, 95 | NotLoadCacheAtStart: true, 96 | LogDir: "/tmp/nacos/log", 97 | CacheDir: "/tmp/nacos/cache", 98 | LogLevel: "info", 99 | Username: "your-name", 100 | Password: "your-password", 101 | } 102 | 103 | cli, err := clients.NewNamingClient( 104 | vo.NacosClientParam{ 105 | ClientConfig: &cc, 106 | ServerConfigs: sc, 107 | }, 108 | ) 109 | if err != nil { 110 | panic(err) 111 | } 112 | 113 | svr := echo.NewServer(new(EchoImpl), 114 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "echo"}), 115 | server.WithRegistry(registry.NewNacosRegistry(cli)), 116 | ) 117 | if err := svr.Run(); err != nil { 118 | log.Println("server stopped with error:", err) 119 | } else { 120 | log.Println("server stopped") 121 | } 122 | // ... 123 | } 124 | ``` 125 | 126 | #### 客户端 127 | 128 | ```go 129 | import ( 130 | // ... 131 | "github.com/kitex-contrib/registry-nacos/resolver" 132 | "github.com/nacos-group/nacos-sdk-go/clients" 133 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 134 | "github.com/nacos-group/nacos-sdk-go/common/constant" 135 | "github.com/nacos-group/nacos-sdk-go/vo" 136 | // ... 137 | ) 138 | func main() { 139 | // ... 140 | sc := []constant.ServerConfig{ 141 | *constant.NewServerConfig("127.0.0.1", 8848), 142 | } 143 | cc := constant.ClientConfig{ 144 | NamespaceId: "public", 145 | TimeoutMs: 5000, 146 | NotLoadCacheAtStart: true, 147 | LogDir: "/tmp/nacos/log", 148 | CacheDir: "/tmp/nacos/cache", 149 | LogLevel: "info", 150 | Username: "your-name", 151 | Password: "your-password", 152 | } 153 | 154 | cli, err := clients.NewNamingClient( 155 | vo.NacosClientParam{ 156 | ClientConfig: &cc, 157 | ServerConfigs: sc, 158 | }, 159 | ) 160 | if err != nil { 161 | panic(err) 162 | } 163 | client, err := echo.NewClient("echo", client.WithResolver(resolver.NewNacosResolver(cli)) 164 | if err != nil { 165 | log.Fatal(err) 166 | } 167 | // ... 168 | } 169 | ``` 170 | 171 | ### 环境变量 172 | 173 | | 变量名 | 变量默认值 | 作用 | 174 | | ------------------------- | ---------------------------------- | --------------------------------- | 175 | | serverAddr | 127.0.0.1 | nacos 服务器地址 | 176 | | serverPort | 8848 | nacos 服务器端口 | 177 | | namespace | | nacos 中的 namespace Id | 178 | | NACOS_ENV_TAGS | "" | 支持注入默认 nacos tags| 179 | 180 | ### 更多信息 181 | 182 | 更多示例请参考 [example](example) 183 | 184 | ## 兼容性 185 | 该包使用 Nacos1.x 客户端,Nacos2.0 和 Nacos1.0 服务端完全兼容该版本. [详情](https://nacos.io/zh-cn/docs/v2/upgrading/2.0.0-compatibility.html) 186 | 187 | 主要贡献者: [baiyutang](https://github.com/baiyutang) 188 | 189 | -------------------------------------------------------------------------------- /_typos.toml: -------------------------------------------------------------------------------- 1 | # Typo check: https://github.com/crate-ci/typos 2 | 3 | [files] 4 | extend-exclude = ["go.mod", "go.sum"] 5 | -------------------------------------------------------------------------------- /example/basic/client/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "log" 20 | "time" 21 | 22 | "github.com/cloudwego/kitex/client" 23 | "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api" 24 | "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api/hello" 25 | "github.com/kitex-contrib/registry-nacos/resolver" 26 | ) 27 | 28 | func main() { 29 | r, err := resolver.NewDefaultNacosResolver() 30 | if err != nil { 31 | panic(err) 32 | } 33 | newClient := hello.MustNewClient( 34 | "Hello", 35 | client.WithResolver(r), 36 | client.WithRPCTimeout(time.Second*3), 37 | ) 38 | for { 39 | resp, err := newClient.Echo(context.Background(), &api.Request{Message: "Hello"}) 40 | if err != nil { 41 | log.Fatal(err) 42 | } 43 | log.Println(resp) 44 | time.Sleep(time.Second) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /example/basic/server/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "log" 20 | "net" 21 | 22 | "github.com/cloudwego/kitex/pkg/rpcinfo" 23 | "github.com/cloudwego/kitex/server" 24 | "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api" 25 | "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api/hello" 26 | "github.com/kitex-contrib/registry-nacos/registry" 27 | ) 28 | 29 | type HelloImpl struct{} 30 | 31 | func (h *HelloImpl) Echo(_ context.Context, req *api.Request) (resp *api.Response, err error) { 32 | resp = &api.Response{ 33 | Message: req.Message, 34 | } 35 | return 36 | } 37 | 38 | func main() { 39 | r, err := registry.NewDefaultNacosRegistry() 40 | if err != nil { 41 | panic(err) 42 | } 43 | svr := hello.NewServer( 44 | new(HelloImpl), 45 | server.WithRegistry(r), 46 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "Hello"}), 47 | server.WithServiceAddr(&net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8080}), 48 | ) 49 | if err := svr.Run(); err != nil { 50 | log.Println("server stopped with error:", err) 51 | } else { 52 | log.Println("server stopped") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /example/custom-config/client/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "log" 20 | "time" 21 | 22 | "github.com/cloudwego/kitex/client" 23 | "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api" 24 | "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api/hello" 25 | "github.com/kitex-contrib/registry-nacos/resolver" 26 | "github.com/nacos-group/nacos-sdk-go/clients" 27 | "github.com/nacos-group/nacos-sdk-go/common/constant" 28 | "github.com/nacos-group/nacos-sdk-go/vo" 29 | ) 30 | 31 | func main() { 32 | // the nacos server config 33 | sc := []constant.ServerConfig{ 34 | *constant.NewServerConfig("127.0.0.1", 8848), 35 | } 36 | 37 | // the nacos client config 38 | cc := constant.ClientConfig{ 39 | NamespaceId: "public", 40 | TimeoutMs: 5000, 41 | NotLoadCacheAtStart: true, 42 | LogDir: "/tmp/nacos/log", 43 | CacheDir: "/tmp/nacos/cache", 44 | LogLevel: "info", 45 | // more ... 46 | } 47 | 48 | cli, err := clients.NewNamingClient( 49 | vo.NacosClientParam{ 50 | ClientConfig: &cc, 51 | ServerConfigs: sc, 52 | }, 53 | ) 54 | if err != nil { 55 | panic(err) 56 | } 57 | newClient := hello.MustNewClient( 58 | "Hello", 59 | client.WithResolver(resolver.NewNacosResolver(cli)), 60 | client.WithRPCTimeout(time.Second*3), 61 | ) 62 | for { 63 | resp, err := newClient.Echo(context.Background(), &api.Request{Message: "Hello"}) 64 | if err != nil { 65 | log.Fatal(err) 66 | } 67 | log.Println(resp) 68 | time.Sleep(time.Second) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /example/custom-config/server/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "log" 20 | 21 | "github.com/cloudwego/kitex/pkg/rpcinfo" 22 | "github.com/cloudwego/kitex/server" 23 | "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api" 24 | "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api/hello" 25 | "github.com/kitex-contrib/registry-nacos/registry" 26 | "github.com/nacos-group/nacos-sdk-go/clients" 27 | "github.com/nacos-group/nacos-sdk-go/common/constant" 28 | "github.com/nacos-group/nacos-sdk-go/vo" 29 | ) 30 | 31 | type HelloImpl struct{} 32 | 33 | func (h *HelloImpl) Echo(_ context.Context, req *api.Request) (resp *api.Response, err error) { 34 | resp = &api.Response{ 35 | Message: req.Message, 36 | } 37 | return 38 | } 39 | 40 | func main() { 41 | // the nacos server config 42 | sc := []constant.ServerConfig{ 43 | *constant.NewServerConfig("127.0.0.1", 8848), 44 | } 45 | 46 | // the nacos client config 47 | cc := constant.ClientConfig{ 48 | NamespaceId: "public", 49 | TimeoutMs: 5000, 50 | NotLoadCacheAtStart: true, 51 | LogDir: "/tmp/nacos/log", 52 | CacheDir: "/tmp/nacos/cache", 53 | LogLevel: "info", 54 | // more ... 55 | } 56 | 57 | cli, err := clients.NewNamingClient( 58 | vo.NacosClientParam{ 59 | ClientConfig: &cc, 60 | ServerConfigs: sc, 61 | }, 62 | ) 63 | if err != nil { 64 | panic(err) 65 | } 66 | 67 | svr := hello.NewServer( 68 | new(HelloImpl), 69 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "Hello"}), 70 | server.WithRegistry(registry.NewNacosRegistry(cli)), 71 | ) 72 | if err := svr.Run(); err != nil { 73 | log.Println("server stopped with error:", err) 74 | } else { 75 | log.Println("server stopped") 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /example/custom-logger/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "log" 20 | 21 | "github.com/cloudwego/kitex/pkg/rpcinfo" 22 | "github.com/cloudwego/kitex/server" 23 | "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api" 24 | "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api/hello" 25 | "github.com/kitex-contrib/registry-nacos/nacos" 26 | "github.com/kitex-contrib/registry-nacos/registry" 27 | "github.com/nacos-group/nacos-sdk-go/clients" 28 | "github.com/nacos-group/nacos-sdk-go/common/constant" 29 | "github.com/nacos-group/nacos-sdk-go/vo" 30 | ) 31 | 32 | type HelloImpl struct{} 33 | 34 | func (h *HelloImpl) Echo(_ context.Context, req *api.Request) (resp *api.Response, err error) { 35 | resp = &api.Response{ 36 | Message: req.Message, 37 | } 38 | return 39 | } 40 | 41 | func main() { 42 | // the nacos server config 43 | sc := []constant.ServerConfig{ 44 | *constant.NewServerConfig("127.0.0.1", 8848), 45 | } 46 | 47 | // the nacos client config 48 | cc := constant.ClientConfig{ 49 | NamespaceId: "public", 50 | TimeoutMs: 5000, 51 | NotLoadCacheAtStart: true, 52 | LogDir: "/tmp/nacos/log", 53 | CacheDir: "/tmp/nacos/cache", 54 | LogLevel: "info", 55 | CustomLogger: nacos.NewCustomNacosLogger(), // With a custom Logger,you can use kitex `klog` or other. 56 | } 57 | 58 | cli, err := clients.NewNamingClient( 59 | vo.NacosClientParam{ 60 | ClientConfig: &cc, 61 | ServerConfigs: sc, 62 | }, 63 | ) 64 | if err != nil { 65 | panic(err) 66 | } 67 | 68 | svr := hello.NewServer( 69 | new(HelloImpl), 70 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "Hello"}), 71 | server.WithRegistry(registry.NewNacosRegistry(cli)), 72 | ) 73 | if err := svr.Run(); err != nil { 74 | log.Println("server stopped with error:", err) 75 | } else { 76 | log.Println("server stopped") 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /example/hello/hello.thrift: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | 16 | namespace go api 17 | 18 | struct Request { 19 | 1: string message 20 | } 21 | 22 | struct Response { 23 | 1: string message 24 | } 25 | 26 | service Hello { 27 | Response echo(1: Request req) 28 | } 29 | -------------------------------------------------------------------------------- /example/hello/kitex_gen/api/hello.go: -------------------------------------------------------------------------------- 1 | // Code generated by thriftgo (0.2.8). DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "strings" 9 | 10 | "github.com/apache/thrift/lib/go/thrift" 11 | ) 12 | 13 | type Request struct { 14 | Message string `thrift:"message,1" frugal:"1,default,string" json:"message"` 15 | } 16 | 17 | func NewRequest() *Request { 18 | return &Request{} 19 | } 20 | 21 | func (p *Request) InitDefault() { 22 | *p = Request{} 23 | } 24 | 25 | func (p *Request) GetMessage() (v string) { 26 | return p.Message 27 | } 28 | func (p *Request) SetMessage(val string) { 29 | p.Message = val 30 | } 31 | 32 | var fieldIDToName_Request = map[int16]string{ 33 | 1: "message", 34 | } 35 | 36 | func (p *Request) Read(iprot thrift.TProtocol) (err error) { 37 | 38 | var fieldTypeId thrift.TType 39 | var fieldId int16 40 | 41 | if _, err = iprot.ReadStructBegin(); err != nil { 42 | goto ReadStructBeginError 43 | } 44 | 45 | for { 46 | _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() 47 | if err != nil { 48 | goto ReadFieldBeginError 49 | } 50 | if fieldTypeId == thrift.STOP { 51 | break 52 | } 53 | 54 | switch fieldId { 55 | case 1: 56 | if fieldTypeId == thrift.STRING { 57 | if err = p.ReadField1(iprot); err != nil { 58 | goto ReadFieldError 59 | } 60 | } else { 61 | if err = iprot.Skip(fieldTypeId); err != nil { 62 | goto SkipFieldError 63 | } 64 | } 65 | default: 66 | if err = iprot.Skip(fieldTypeId); err != nil { 67 | goto SkipFieldError 68 | } 69 | } 70 | 71 | if err = iprot.ReadFieldEnd(); err != nil { 72 | goto ReadFieldEndError 73 | } 74 | } 75 | if err = iprot.ReadStructEnd(); err != nil { 76 | goto ReadStructEndError 77 | } 78 | 79 | return nil 80 | ReadStructBeginError: 81 | return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 82 | ReadFieldBeginError: 83 | return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 84 | ReadFieldError: 85 | return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_Request[fieldId]), err) 86 | SkipFieldError: 87 | return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 88 | 89 | ReadFieldEndError: 90 | return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 91 | ReadStructEndError: 92 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 93 | } 94 | 95 | func (p *Request) ReadField1(iprot thrift.TProtocol) error { 96 | if v, err := iprot.ReadString(); err != nil { 97 | return err 98 | } else { 99 | p.Message = v 100 | } 101 | return nil 102 | } 103 | 104 | func (p *Request) Write(oprot thrift.TProtocol) (err error) { 105 | var fieldId int16 106 | if err = oprot.WriteStructBegin("Request"); err != nil { 107 | goto WriteStructBeginError 108 | } 109 | if p != nil { 110 | if err = p.writeField1(oprot); err != nil { 111 | fieldId = 1 112 | goto WriteFieldError 113 | } 114 | 115 | } 116 | if err = oprot.WriteFieldStop(); err != nil { 117 | goto WriteFieldStopError 118 | } 119 | if err = oprot.WriteStructEnd(); err != nil { 120 | goto WriteStructEndError 121 | } 122 | return nil 123 | WriteStructBeginError: 124 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) 125 | WriteFieldError: 126 | return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) 127 | WriteFieldStopError: 128 | return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) 129 | WriteStructEndError: 130 | return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) 131 | } 132 | 133 | func (p *Request) writeField1(oprot thrift.TProtocol) (err error) { 134 | if err = oprot.WriteFieldBegin("message", thrift.STRING, 1); err != nil { 135 | goto WriteFieldBeginError 136 | } 137 | if err := oprot.WriteString(p.Message); err != nil { 138 | return err 139 | } 140 | if err = oprot.WriteFieldEnd(); err != nil { 141 | goto WriteFieldEndError 142 | } 143 | return nil 144 | WriteFieldBeginError: 145 | return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) 146 | WriteFieldEndError: 147 | return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) 148 | } 149 | 150 | func (p *Request) String() string { 151 | if p == nil { 152 | return "" 153 | } 154 | return fmt.Sprintf("Request(%+v)", *p) 155 | } 156 | 157 | func (p *Request) DeepEqual(ano *Request) bool { 158 | if p == ano { 159 | return true 160 | } else if p == nil || ano == nil { 161 | return false 162 | } 163 | if !p.Field1DeepEqual(ano.Message) { 164 | return false 165 | } 166 | return true 167 | } 168 | 169 | func (p *Request) Field1DeepEqual(src string) bool { 170 | 171 | if strings.Compare(p.Message, src) != 0 { 172 | return false 173 | } 174 | return true 175 | } 176 | 177 | type Response struct { 178 | Message string `thrift:"message,1" frugal:"1,default,string" json:"message"` 179 | } 180 | 181 | func NewResponse() *Response { 182 | return &Response{} 183 | } 184 | 185 | func (p *Response) InitDefault() { 186 | *p = Response{} 187 | } 188 | 189 | func (p *Response) GetMessage() (v string) { 190 | return p.Message 191 | } 192 | func (p *Response) SetMessage(val string) { 193 | p.Message = val 194 | } 195 | 196 | var fieldIDToName_Response = map[int16]string{ 197 | 1: "message", 198 | } 199 | 200 | func (p *Response) Read(iprot thrift.TProtocol) (err error) { 201 | 202 | var fieldTypeId thrift.TType 203 | var fieldId int16 204 | 205 | if _, err = iprot.ReadStructBegin(); err != nil { 206 | goto ReadStructBeginError 207 | } 208 | 209 | for { 210 | _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() 211 | if err != nil { 212 | goto ReadFieldBeginError 213 | } 214 | if fieldTypeId == thrift.STOP { 215 | break 216 | } 217 | 218 | switch fieldId { 219 | case 1: 220 | if fieldTypeId == thrift.STRING { 221 | if err = p.ReadField1(iprot); err != nil { 222 | goto ReadFieldError 223 | } 224 | } else { 225 | if err = iprot.Skip(fieldTypeId); err != nil { 226 | goto SkipFieldError 227 | } 228 | } 229 | default: 230 | if err = iprot.Skip(fieldTypeId); err != nil { 231 | goto SkipFieldError 232 | } 233 | } 234 | 235 | if err = iprot.ReadFieldEnd(); err != nil { 236 | goto ReadFieldEndError 237 | } 238 | } 239 | if err = iprot.ReadStructEnd(); err != nil { 240 | goto ReadStructEndError 241 | } 242 | 243 | return nil 244 | ReadStructBeginError: 245 | return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 246 | ReadFieldBeginError: 247 | return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 248 | ReadFieldError: 249 | return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_Response[fieldId]), err) 250 | SkipFieldError: 251 | return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 252 | 253 | ReadFieldEndError: 254 | return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 255 | ReadStructEndError: 256 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 257 | } 258 | 259 | func (p *Response) ReadField1(iprot thrift.TProtocol) error { 260 | if v, err := iprot.ReadString(); err != nil { 261 | return err 262 | } else { 263 | p.Message = v 264 | } 265 | return nil 266 | } 267 | 268 | func (p *Response) Write(oprot thrift.TProtocol) (err error) { 269 | var fieldId int16 270 | if err = oprot.WriteStructBegin("Response"); err != nil { 271 | goto WriteStructBeginError 272 | } 273 | if p != nil { 274 | if err = p.writeField1(oprot); err != nil { 275 | fieldId = 1 276 | goto WriteFieldError 277 | } 278 | 279 | } 280 | if err = oprot.WriteFieldStop(); err != nil { 281 | goto WriteFieldStopError 282 | } 283 | if err = oprot.WriteStructEnd(); err != nil { 284 | goto WriteStructEndError 285 | } 286 | return nil 287 | WriteStructBeginError: 288 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) 289 | WriteFieldError: 290 | return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) 291 | WriteFieldStopError: 292 | return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) 293 | WriteStructEndError: 294 | return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) 295 | } 296 | 297 | func (p *Response) writeField1(oprot thrift.TProtocol) (err error) { 298 | if err = oprot.WriteFieldBegin("message", thrift.STRING, 1); err != nil { 299 | goto WriteFieldBeginError 300 | } 301 | if err := oprot.WriteString(p.Message); err != nil { 302 | return err 303 | } 304 | if err = oprot.WriteFieldEnd(); err != nil { 305 | goto WriteFieldEndError 306 | } 307 | return nil 308 | WriteFieldBeginError: 309 | return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) 310 | WriteFieldEndError: 311 | return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) 312 | } 313 | 314 | func (p *Response) String() string { 315 | if p == nil { 316 | return "" 317 | } 318 | return fmt.Sprintf("Response(%+v)", *p) 319 | } 320 | 321 | func (p *Response) DeepEqual(ano *Response) bool { 322 | if p == ano { 323 | return true 324 | } else if p == nil || ano == nil { 325 | return false 326 | } 327 | if !p.Field1DeepEqual(ano.Message) { 328 | return false 329 | } 330 | return true 331 | } 332 | 333 | func (p *Response) Field1DeepEqual(src string) bool { 334 | 335 | if strings.Compare(p.Message, src) != 0 { 336 | return false 337 | } 338 | return true 339 | } 340 | 341 | type Hello interface { 342 | Echo(ctx context.Context, req *Request) (r *Response, err error) 343 | } 344 | 345 | type HelloClient struct { 346 | c thrift.TClient 347 | } 348 | 349 | func NewHelloClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *HelloClient { 350 | return &HelloClient{ 351 | c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t)), 352 | } 353 | } 354 | 355 | func NewHelloClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *HelloClient { 356 | return &HelloClient{ 357 | c: thrift.NewTStandardClient(iprot, oprot), 358 | } 359 | } 360 | 361 | func NewHelloClient(c thrift.TClient) *HelloClient { 362 | return &HelloClient{ 363 | c: c, 364 | } 365 | } 366 | 367 | func (p *HelloClient) Client_() thrift.TClient { 368 | return p.c 369 | } 370 | 371 | func (p *HelloClient) Echo(ctx context.Context, req *Request) (r *Response, err error) { 372 | var _args HelloEchoArgs 373 | _args.Req = req 374 | var _result HelloEchoResult 375 | if err = p.Client_().Call(ctx, "echo", &_args, &_result); err != nil { 376 | return 377 | } 378 | return _result.GetSuccess(), nil 379 | } 380 | 381 | type HelloProcessor struct { 382 | processorMap map[string]thrift.TProcessorFunction 383 | handler Hello 384 | } 385 | 386 | func (p *HelloProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { 387 | p.processorMap[key] = processor 388 | } 389 | 390 | func (p *HelloProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { 391 | processor, ok = p.processorMap[key] 392 | return processor, ok 393 | } 394 | 395 | func (p *HelloProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { 396 | return p.processorMap 397 | } 398 | 399 | func NewHelloProcessor(handler Hello) *HelloProcessor { 400 | self := &HelloProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} 401 | self.AddToProcessorMap("echo", &helloProcessorEcho{handler: handler}) 402 | return self 403 | } 404 | func (p *HelloProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { 405 | name, _, seqId, err := iprot.ReadMessageBegin() 406 | if err != nil { 407 | return false, err 408 | } 409 | if processor, ok := p.GetProcessorFunction(name); ok { 410 | return processor.Process(ctx, seqId, iprot, oprot) 411 | } 412 | iprot.Skip(thrift.STRUCT) 413 | iprot.ReadMessageEnd() 414 | x := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) 415 | oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) 416 | x.Write(oprot) 417 | oprot.WriteMessageEnd() 418 | oprot.Flush(ctx) 419 | return false, x 420 | } 421 | 422 | type helloProcessorEcho struct { 423 | handler Hello 424 | } 425 | 426 | func (p *helloProcessorEcho) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { 427 | args := HelloEchoArgs{} 428 | if err = args.Read(iprot); err != nil { 429 | iprot.ReadMessageEnd() 430 | x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) 431 | oprot.WriteMessageBegin("echo", thrift.EXCEPTION, seqId) 432 | x.Write(oprot) 433 | oprot.WriteMessageEnd() 434 | oprot.Flush(ctx) 435 | return false, err 436 | } 437 | 438 | iprot.ReadMessageEnd() 439 | var err2 error 440 | result := HelloEchoResult{} 441 | var retval *Response 442 | if retval, err2 = p.handler.Echo(ctx, args.Req); err2 != nil { 443 | x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing echo: "+err2.Error()) 444 | oprot.WriteMessageBegin("echo", thrift.EXCEPTION, seqId) 445 | x.Write(oprot) 446 | oprot.WriteMessageEnd() 447 | oprot.Flush(ctx) 448 | return true, err2 449 | } else { 450 | result.Success = retval 451 | } 452 | if err2 = oprot.WriteMessageBegin("echo", thrift.REPLY, seqId); err2 != nil { 453 | err = err2 454 | } 455 | if err2 = result.Write(oprot); err == nil && err2 != nil { 456 | err = err2 457 | } 458 | if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { 459 | err = err2 460 | } 461 | if err2 = oprot.Flush(ctx); err == nil && err2 != nil { 462 | err = err2 463 | } 464 | if err != nil { 465 | return 466 | } 467 | return true, err 468 | } 469 | 470 | type HelloEchoArgs struct { 471 | Req *Request `thrift:"req,1" frugal:"1,default,Request" json:"req"` 472 | } 473 | 474 | func NewHelloEchoArgs() *HelloEchoArgs { 475 | return &HelloEchoArgs{} 476 | } 477 | 478 | func (p *HelloEchoArgs) InitDefault() { 479 | *p = HelloEchoArgs{} 480 | } 481 | 482 | var HelloEchoArgs_Req_DEFAULT *Request 483 | 484 | func (p *HelloEchoArgs) GetReq() (v *Request) { 485 | if !p.IsSetReq() { 486 | return HelloEchoArgs_Req_DEFAULT 487 | } 488 | return p.Req 489 | } 490 | func (p *HelloEchoArgs) SetReq(val *Request) { 491 | p.Req = val 492 | } 493 | 494 | var fieldIDToName_HelloEchoArgs = map[int16]string{ 495 | 1: "req", 496 | } 497 | 498 | func (p *HelloEchoArgs) IsSetReq() bool { 499 | return p.Req != nil 500 | } 501 | 502 | func (p *HelloEchoArgs) Read(iprot thrift.TProtocol) (err error) { 503 | 504 | var fieldTypeId thrift.TType 505 | var fieldId int16 506 | 507 | if _, err = iprot.ReadStructBegin(); err != nil { 508 | goto ReadStructBeginError 509 | } 510 | 511 | for { 512 | _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() 513 | if err != nil { 514 | goto ReadFieldBeginError 515 | } 516 | if fieldTypeId == thrift.STOP { 517 | break 518 | } 519 | 520 | switch fieldId { 521 | case 1: 522 | if fieldTypeId == thrift.STRUCT { 523 | if err = p.ReadField1(iprot); err != nil { 524 | goto ReadFieldError 525 | } 526 | } else { 527 | if err = iprot.Skip(fieldTypeId); err != nil { 528 | goto SkipFieldError 529 | } 530 | } 531 | default: 532 | if err = iprot.Skip(fieldTypeId); err != nil { 533 | goto SkipFieldError 534 | } 535 | } 536 | 537 | if err = iprot.ReadFieldEnd(); err != nil { 538 | goto ReadFieldEndError 539 | } 540 | } 541 | if err = iprot.ReadStructEnd(); err != nil { 542 | goto ReadStructEndError 543 | } 544 | 545 | return nil 546 | ReadStructBeginError: 547 | return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 548 | ReadFieldBeginError: 549 | return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 550 | ReadFieldError: 551 | return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_HelloEchoArgs[fieldId]), err) 552 | SkipFieldError: 553 | return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 554 | 555 | ReadFieldEndError: 556 | return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 557 | ReadStructEndError: 558 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 559 | } 560 | 561 | func (p *HelloEchoArgs) ReadField1(iprot thrift.TProtocol) error { 562 | p.Req = NewRequest() 563 | if err := p.Req.Read(iprot); err != nil { 564 | return err 565 | } 566 | return nil 567 | } 568 | 569 | func (p *HelloEchoArgs) Write(oprot thrift.TProtocol) (err error) { 570 | var fieldId int16 571 | if err = oprot.WriteStructBegin("echo_args"); err != nil { 572 | goto WriteStructBeginError 573 | } 574 | if p != nil { 575 | if err = p.writeField1(oprot); err != nil { 576 | fieldId = 1 577 | goto WriteFieldError 578 | } 579 | 580 | } 581 | if err = oprot.WriteFieldStop(); err != nil { 582 | goto WriteFieldStopError 583 | } 584 | if err = oprot.WriteStructEnd(); err != nil { 585 | goto WriteStructEndError 586 | } 587 | return nil 588 | WriteStructBeginError: 589 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) 590 | WriteFieldError: 591 | return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) 592 | WriteFieldStopError: 593 | return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) 594 | WriteStructEndError: 595 | return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) 596 | } 597 | 598 | func (p *HelloEchoArgs) writeField1(oprot thrift.TProtocol) (err error) { 599 | if err = oprot.WriteFieldBegin("req", thrift.STRUCT, 1); err != nil { 600 | goto WriteFieldBeginError 601 | } 602 | if err := p.Req.Write(oprot); err != nil { 603 | return err 604 | } 605 | if err = oprot.WriteFieldEnd(); err != nil { 606 | goto WriteFieldEndError 607 | } 608 | return nil 609 | WriteFieldBeginError: 610 | return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) 611 | WriteFieldEndError: 612 | return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) 613 | } 614 | 615 | func (p *HelloEchoArgs) String() string { 616 | if p == nil { 617 | return "" 618 | } 619 | return fmt.Sprintf("HelloEchoArgs(%+v)", *p) 620 | } 621 | 622 | func (p *HelloEchoArgs) DeepEqual(ano *HelloEchoArgs) bool { 623 | if p == ano { 624 | return true 625 | } else if p == nil || ano == nil { 626 | return false 627 | } 628 | if !p.Field1DeepEqual(ano.Req) { 629 | return false 630 | } 631 | return true 632 | } 633 | 634 | func (p *HelloEchoArgs) Field1DeepEqual(src *Request) bool { 635 | 636 | if !p.Req.DeepEqual(src) { 637 | return false 638 | } 639 | return true 640 | } 641 | 642 | type HelloEchoResult struct { 643 | Success *Response `thrift:"success,0,optional" frugal:"0,optional,Response" json:"success,omitempty"` 644 | } 645 | 646 | func NewHelloEchoResult() *HelloEchoResult { 647 | return &HelloEchoResult{} 648 | } 649 | 650 | func (p *HelloEchoResult) InitDefault() { 651 | *p = HelloEchoResult{} 652 | } 653 | 654 | var HelloEchoResult_Success_DEFAULT *Response 655 | 656 | func (p *HelloEchoResult) GetSuccess() (v *Response) { 657 | if !p.IsSetSuccess() { 658 | return HelloEchoResult_Success_DEFAULT 659 | } 660 | return p.Success 661 | } 662 | func (p *HelloEchoResult) SetSuccess(x interface{}) { 663 | p.Success = x.(*Response) 664 | } 665 | 666 | var fieldIDToName_HelloEchoResult = map[int16]string{ 667 | 0: "success", 668 | } 669 | 670 | func (p *HelloEchoResult) IsSetSuccess() bool { 671 | return p.Success != nil 672 | } 673 | 674 | func (p *HelloEchoResult) Read(iprot thrift.TProtocol) (err error) { 675 | 676 | var fieldTypeId thrift.TType 677 | var fieldId int16 678 | 679 | if _, err = iprot.ReadStructBegin(); err != nil { 680 | goto ReadStructBeginError 681 | } 682 | 683 | for { 684 | _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() 685 | if err != nil { 686 | goto ReadFieldBeginError 687 | } 688 | if fieldTypeId == thrift.STOP { 689 | break 690 | } 691 | 692 | switch fieldId { 693 | case 0: 694 | if fieldTypeId == thrift.STRUCT { 695 | if err = p.ReadField0(iprot); err != nil { 696 | goto ReadFieldError 697 | } 698 | } else { 699 | if err = iprot.Skip(fieldTypeId); err != nil { 700 | goto SkipFieldError 701 | } 702 | } 703 | default: 704 | if err = iprot.Skip(fieldTypeId); err != nil { 705 | goto SkipFieldError 706 | } 707 | } 708 | 709 | if err = iprot.ReadFieldEnd(); err != nil { 710 | goto ReadFieldEndError 711 | } 712 | } 713 | if err = iprot.ReadStructEnd(); err != nil { 714 | goto ReadStructEndError 715 | } 716 | 717 | return nil 718 | ReadStructBeginError: 719 | return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 720 | ReadFieldBeginError: 721 | return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 722 | ReadFieldError: 723 | return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_HelloEchoResult[fieldId]), err) 724 | SkipFieldError: 725 | return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 726 | 727 | ReadFieldEndError: 728 | return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 729 | ReadStructEndError: 730 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 731 | } 732 | 733 | func (p *HelloEchoResult) ReadField0(iprot thrift.TProtocol) error { 734 | p.Success = NewResponse() 735 | if err := p.Success.Read(iprot); err != nil { 736 | return err 737 | } 738 | return nil 739 | } 740 | 741 | func (p *HelloEchoResult) Write(oprot thrift.TProtocol) (err error) { 742 | var fieldId int16 743 | if err = oprot.WriteStructBegin("echo_result"); err != nil { 744 | goto WriteStructBeginError 745 | } 746 | if p != nil { 747 | if err = p.writeField0(oprot); err != nil { 748 | fieldId = 0 749 | goto WriteFieldError 750 | } 751 | 752 | } 753 | if err = oprot.WriteFieldStop(); err != nil { 754 | goto WriteFieldStopError 755 | } 756 | if err = oprot.WriteStructEnd(); err != nil { 757 | goto WriteStructEndError 758 | } 759 | return nil 760 | WriteStructBeginError: 761 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) 762 | WriteFieldError: 763 | return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) 764 | WriteFieldStopError: 765 | return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) 766 | WriteStructEndError: 767 | return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) 768 | } 769 | 770 | func (p *HelloEchoResult) writeField0(oprot thrift.TProtocol) (err error) { 771 | if p.IsSetSuccess() { 772 | if err = oprot.WriteFieldBegin("success", thrift.STRUCT, 0); err != nil { 773 | goto WriteFieldBeginError 774 | } 775 | if err := p.Success.Write(oprot); err != nil { 776 | return err 777 | } 778 | if err = oprot.WriteFieldEnd(); err != nil { 779 | goto WriteFieldEndError 780 | } 781 | } 782 | return nil 783 | WriteFieldBeginError: 784 | return thrift.PrependError(fmt.Sprintf("%T write field 0 begin error: ", p), err) 785 | WriteFieldEndError: 786 | return thrift.PrependError(fmt.Sprintf("%T write field 0 end error: ", p), err) 787 | } 788 | 789 | func (p *HelloEchoResult) String() string { 790 | if p == nil { 791 | return "" 792 | } 793 | return fmt.Sprintf("HelloEchoResult(%+v)", *p) 794 | } 795 | 796 | func (p *HelloEchoResult) DeepEqual(ano *HelloEchoResult) bool { 797 | if p == ano { 798 | return true 799 | } else if p == nil || ano == nil { 800 | return false 801 | } 802 | if !p.Field0DeepEqual(ano.Success) { 803 | return false 804 | } 805 | return true 806 | } 807 | 808 | func (p *HelloEchoResult) Field0DeepEqual(src *Response) bool { 809 | 810 | if !p.Success.DeepEqual(src) { 811 | return false 812 | } 813 | return true 814 | } 815 | -------------------------------------------------------------------------------- /example/hello/kitex_gen/api/hello/client.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.5.1. DO NOT EDIT. 2 | 3 | package hello 4 | 5 | import ( 6 | "context" 7 | 8 | client "github.com/cloudwego/kitex/client" 9 | callopt "github.com/cloudwego/kitex/client/callopt" 10 | api "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api" 11 | ) 12 | 13 | // Client is designed to provide IDL-compatible methods with call-option parameter for kitex framework. 14 | type Client interface { 15 | Echo(ctx context.Context, req *api.Request, callOptions ...callopt.Option) (r *api.Response, err error) 16 | } 17 | 18 | // NewClient creates a client for the service defined in IDL. 19 | func NewClient(destService string, opts ...client.Option) (Client, error) { 20 | var options []client.Option 21 | options = append(options, client.WithDestService(destService)) 22 | 23 | options = append(options, opts...) 24 | 25 | kc, err := client.NewClient(serviceInfo(), options...) 26 | if err != nil { 27 | return nil, err 28 | } 29 | return &kHelloClient{ 30 | kClient: newServiceClient(kc), 31 | }, nil 32 | } 33 | 34 | // MustNewClient creates a client for the service defined in IDL. It panics if any error occurs. 35 | func MustNewClient(destService string, opts ...client.Option) Client { 36 | kc, err := NewClient(destService, opts...) 37 | if err != nil { 38 | panic(err) 39 | } 40 | return kc 41 | } 42 | 43 | type kHelloClient struct { 44 | *kClient 45 | } 46 | 47 | func (p *kHelloClient) Echo(ctx context.Context, req *api.Request, callOptions ...callopt.Option) (r *api.Response, err error) { 48 | ctx = client.NewCtxWithCallOptions(ctx, callOptions) 49 | return p.kClient.Echo(ctx, req) 50 | } 51 | -------------------------------------------------------------------------------- /example/hello/kitex_gen/api/hello/hello.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.5.1. DO NOT EDIT. 2 | 3 | package hello 4 | 5 | import ( 6 | "context" 7 | 8 | client "github.com/cloudwego/kitex/client" 9 | kitex "github.com/cloudwego/kitex/pkg/serviceinfo" 10 | api "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api" 11 | ) 12 | 13 | func serviceInfo() *kitex.ServiceInfo { 14 | return helloServiceInfo 15 | } 16 | 17 | var helloServiceInfo = NewServiceInfo() 18 | 19 | func NewServiceInfo() *kitex.ServiceInfo { 20 | serviceName := "Hello" 21 | handlerType := (*api.Hello)(nil) 22 | methods := map[string]kitex.MethodInfo{ 23 | "echo": kitex.NewMethodInfo(echoHandler, newHelloEchoArgs, newHelloEchoResult, false), 24 | } 25 | extra := map[string]interface{}{ 26 | "PackageName": "api", 27 | } 28 | svcInfo := &kitex.ServiceInfo{ 29 | ServiceName: serviceName, 30 | HandlerType: handlerType, 31 | Methods: methods, 32 | PayloadCodec: kitex.Thrift, 33 | KiteXGenVersion: "v0.5.1", 34 | Extra: extra, 35 | } 36 | return svcInfo 37 | } 38 | 39 | func echoHandler(ctx context.Context, handler interface{}, arg, result interface{}) error { 40 | realArg := arg.(*api.HelloEchoArgs) 41 | realResult := result.(*api.HelloEchoResult) 42 | success, err := handler.(api.Hello).Echo(ctx, realArg.Req) 43 | if err != nil { 44 | return err 45 | } 46 | realResult.Success = success 47 | return nil 48 | } 49 | func newHelloEchoArgs() interface{} { 50 | return api.NewHelloEchoArgs() 51 | } 52 | 53 | func newHelloEchoResult() interface{} { 54 | return api.NewHelloEchoResult() 55 | } 56 | 57 | type kClient struct { 58 | c client.Client 59 | } 60 | 61 | func newServiceClient(c client.Client) *kClient { 62 | return &kClient{ 63 | c: c, 64 | } 65 | } 66 | 67 | func (p *kClient) Echo(ctx context.Context, req *api.Request) (r *api.Response, err error) { 68 | var _args api.HelloEchoArgs 69 | _args.Req = req 70 | var _result api.HelloEchoResult 71 | if err = p.c.Call(ctx, "echo", &_args, &_result); err != nil { 72 | return 73 | } 74 | return _result.GetSuccess(), nil 75 | } 76 | -------------------------------------------------------------------------------- /example/hello/kitex_gen/api/hello/invoker.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.5.1. DO NOT EDIT. 2 | 3 | package hello 4 | 5 | import ( 6 | server "github.com/cloudwego/kitex/server" 7 | api "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api" 8 | ) 9 | 10 | // NewInvoker creates a server.Invoker with the given handler and options. 11 | func NewInvoker(handler api.Hello, opts ...server.Option) server.Invoker { 12 | var options []server.Option 13 | 14 | options = append(options, opts...) 15 | 16 | s := server.NewInvoker(options...) 17 | if err := s.RegisterService(serviceInfo(), handler); err != nil { 18 | panic(err) 19 | } 20 | if err := s.Init(); err != nil { 21 | panic(err) 22 | } 23 | return s 24 | } 25 | -------------------------------------------------------------------------------- /example/hello/kitex_gen/api/hello/server.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.5.1. DO NOT EDIT. 2 | package hello 3 | 4 | import ( 5 | server "github.com/cloudwego/kitex/server" 6 | api "github.com/kitex-contrib/registry-nacos/example/hello/kitex_gen/api" 7 | ) 8 | 9 | // NewServer creates a server.Server with the given handler and options. 10 | func NewServer(handler api.Hello, opts ...server.Option) server.Server { 11 | var options []server.Option 12 | 13 | options = append(options, opts...) 14 | 15 | svr := server.NewServer(options...) 16 | if err := svr.RegisterService(serviceInfo(), handler); err != nil { 17 | panic(err) 18 | } 19 | return svr 20 | } 21 | -------------------------------------------------------------------------------- /example/hello/kitex_gen/api/k-consts.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | // KitexUnusedProtection is used to prevent 'imported and not used' error. 4 | var KitexUnusedProtection = struct{}{} 5 | -------------------------------------------------------------------------------- /example/hello/kitex_gen/api/k-hello.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.5.1. DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "bytes" 7 | "fmt" 8 | "reflect" 9 | "strings" 10 | 11 | "github.com/apache/thrift/lib/go/thrift" 12 | 13 | "github.com/cloudwego/kitex/pkg/protocol/bthrift" 14 | ) 15 | 16 | // unused protection 17 | var ( 18 | _ = fmt.Formatter(nil) 19 | _ = (*bytes.Buffer)(nil) 20 | _ = (*strings.Builder)(nil) 21 | _ = reflect.Type(nil) 22 | _ = thrift.TProtocol(nil) 23 | _ = bthrift.BinaryWriter(nil) 24 | ) 25 | 26 | func (p *Request) FastRead(buf []byte) (int, error) { 27 | var err error 28 | var offset int 29 | var l int 30 | var fieldTypeId thrift.TType 31 | var fieldId int16 32 | _, l, err = bthrift.Binary.ReadStructBegin(buf) 33 | offset += l 34 | if err != nil { 35 | goto ReadStructBeginError 36 | } 37 | 38 | for { 39 | _, fieldTypeId, fieldId, l, err = bthrift.Binary.ReadFieldBegin(buf[offset:]) 40 | offset += l 41 | if err != nil { 42 | goto ReadFieldBeginError 43 | } 44 | if fieldTypeId == thrift.STOP { 45 | break 46 | } 47 | switch fieldId { 48 | case 1: 49 | if fieldTypeId == thrift.STRING { 50 | l, err = p.FastReadField1(buf[offset:]) 51 | offset += l 52 | if err != nil { 53 | goto ReadFieldError 54 | } 55 | } else { 56 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 57 | offset += l 58 | if err != nil { 59 | goto SkipFieldError 60 | } 61 | } 62 | default: 63 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 64 | offset += l 65 | if err != nil { 66 | goto SkipFieldError 67 | } 68 | } 69 | 70 | l, err = bthrift.Binary.ReadFieldEnd(buf[offset:]) 71 | offset += l 72 | if err != nil { 73 | goto ReadFieldEndError 74 | } 75 | } 76 | l, err = bthrift.Binary.ReadStructEnd(buf[offset:]) 77 | offset += l 78 | if err != nil { 79 | goto ReadStructEndError 80 | } 81 | 82 | return offset, nil 83 | ReadStructBeginError: 84 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 85 | ReadFieldBeginError: 86 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 87 | ReadFieldError: 88 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_Request[fieldId]), err) 89 | SkipFieldError: 90 | return offset, thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 91 | ReadFieldEndError: 92 | return offset, thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 93 | ReadStructEndError: 94 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 95 | } 96 | 97 | func (p *Request) FastReadField1(buf []byte) (int, error) { 98 | offset := 0 99 | 100 | if v, l, err := bthrift.Binary.ReadString(buf[offset:]); err != nil { 101 | return offset, err 102 | } else { 103 | offset += l 104 | 105 | p.Message = v 106 | 107 | } 108 | return offset, nil 109 | } 110 | 111 | // for compatibility 112 | func (p *Request) FastWrite(buf []byte) int { 113 | return 0 114 | } 115 | 116 | func (p *Request) FastWriteNocopy(buf []byte, binaryWriter bthrift.BinaryWriter) int { 117 | offset := 0 118 | offset += bthrift.Binary.WriteStructBegin(buf[offset:], "Request") 119 | if p != nil { 120 | offset += p.fastWriteField1(buf[offset:], binaryWriter) 121 | } 122 | offset += bthrift.Binary.WriteFieldStop(buf[offset:]) 123 | offset += bthrift.Binary.WriteStructEnd(buf[offset:]) 124 | return offset 125 | } 126 | 127 | func (p *Request) BLength() int { 128 | l := 0 129 | l += bthrift.Binary.StructBeginLength("Request") 130 | if p != nil { 131 | l += p.field1Length() 132 | } 133 | l += bthrift.Binary.FieldStopLength() 134 | l += bthrift.Binary.StructEndLength() 135 | return l 136 | } 137 | 138 | func (p *Request) fastWriteField1(buf []byte, binaryWriter bthrift.BinaryWriter) int { 139 | offset := 0 140 | offset += bthrift.Binary.WriteFieldBegin(buf[offset:], "message", thrift.STRING, 1) 141 | offset += bthrift.Binary.WriteStringNocopy(buf[offset:], binaryWriter, p.Message) 142 | 143 | offset += bthrift.Binary.WriteFieldEnd(buf[offset:]) 144 | return offset 145 | } 146 | 147 | func (p *Request) field1Length() int { 148 | l := 0 149 | l += bthrift.Binary.FieldBeginLength("message", thrift.STRING, 1) 150 | l += bthrift.Binary.StringLengthNocopy(p.Message) 151 | 152 | l += bthrift.Binary.FieldEndLength() 153 | return l 154 | } 155 | 156 | func (p *Response) FastRead(buf []byte) (int, error) { 157 | var err error 158 | var offset int 159 | var l int 160 | var fieldTypeId thrift.TType 161 | var fieldId int16 162 | _, l, err = bthrift.Binary.ReadStructBegin(buf) 163 | offset += l 164 | if err != nil { 165 | goto ReadStructBeginError 166 | } 167 | 168 | for { 169 | _, fieldTypeId, fieldId, l, err = bthrift.Binary.ReadFieldBegin(buf[offset:]) 170 | offset += l 171 | if err != nil { 172 | goto ReadFieldBeginError 173 | } 174 | if fieldTypeId == thrift.STOP { 175 | break 176 | } 177 | switch fieldId { 178 | case 1: 179 | if fieldTypeId == thrift.STRING { 180 | l, err = p.FastReadField1(buf[offset:]) 181 | offset += l 182 | if err != nil { 183 | goto ReadFieldError 184 | } 185 | } else { 186 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 187 | offset += l 188 | if err != nil { 189 | goto SkipFieldError 190 | } 191 | } 192 | default: 193 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 194 | offset += l 195 | if err != nil { 196 | goto SkipFieldError 197 | } 198 | } 199 | 200 | l, err = bthrift.Binary.ReadFieldEnd(buf[offset:]) 201 | offset += l 202 | if err != nil { 203 | goto ReadFieldEndError 204 | } 205 | } 206 | l, err = bthrift.Binary.ReadStructEnd(buf[offset:]) 207 | offset += l 208 | if err != nil { 209 | goto ReadStructEndError 210 | } 211 | 212 | return offset, nil 213 | ReadStructBeginError: 214 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 215 | ReadFieldBeginError: 216 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 217 | ReadFieldError: 218 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_Response[fieldId]), err) 219 | SkipFieldError: 220 | return offset, thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 221 | ReadFieldEndError: 222 | return offset, thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 223 | ReadStructEndError: 224 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 225 | } 226 | 227 | func (p *Response) FastReadField1(buf []byte) (int, error) { 228 | offset := 0 229 | 230 | if v, l, err := bthrift.Binary.ReadString(buf[offset:]); err != nil { 231 | return offset, err 232 | } else { 233 | offset += l 234 | 235 | p.Message = v 236 | 237 | } 238 | return offset, nil 239 | } 240 | 241 | // for compatibility 242 | func (p *Response) FastWrite(buf []byte) int { 243 | return 0 244 | } 245 | 246 | func (p *Response) FastWriteNocopy(buf []byte, binaryWriter bthrift.BinaryWriter) int { 247 | offset := 0 248 | offset += bthrift.Binary.WriteStructBegin(buf[offset:], "Response") 249 | if p != nil { 250 | offset += p.fastWriteField1(buf[offset:], binaryWriter) 251 | } 252 | offset += bthrift.Binary.WriteFieldStop(buf[offset:]) 253 | offset += bthrift.Binary.WriteStructEnd(buf[offset:]) 254 | return offset 255 | } 256 | 257 | func (p *Response) BLength() int { 258 | l := 0 259 | l += bthrift.Binary.StructBeginLength("Response") 260 | if p != nil { 261 | l += p.field1Length() 262 | } 263 | l += bthrift.Binary.FieldStopLength() 264 | l += bthrift.Binary.StructEndLength() 265 | return l 266 | } 267 | 268 | func (p *Response) fastWriteField1(buf []byte, binaryWriter bthrift.BinaryWriter) int { 269 | offset := 0 270 | offset += bthrift.Binary.WriteFieldBegin(buf[offset:], "message", thrift.STRING, 1) 271 | offset += bthrift.Binary.WriteStringNocopy(buf[offset:], binaryWriter, p.Message) 272 | 273 | offset += bthrift.Binary.WriteFieldEnd(buf[offset:]) 274 | return offset 275 | } 276 | 277 | func (p *Response) field1Length() int { 278 | l := 0 279 | l += bthrift.Binary.FieldBeginLength("message", thrift.STRING, 1) 280 | l += bthrift.Binary.StringLengthNocopy(p.Message) 281 | 282 | l += bthrift.Binary.FieldEndLength() 283 | return l 284 | } 285 | 286 | func (p *HelloEchoArgs) FastRead(buf []byte) (int, error) { 287 | var err error 288 | var offset int 289 | var l int 290 | var fieldTypeId thrift.TType 291 | var fieldId int16 292 | _, l, err = bthrift.Binary.ReadStructBegin(buf) 293 | offset += l 294 | if err != nil { 295 | goto ReadStructBeginError 296 | } 297 | 298 | for { 299 | _, fieldTypeId, fieldId, l, err = bthrift.Binary.ReadFieldBegin(buf[offset:]) 300 | offset += l 301 | if err != nil { 302 | goto ReadFieldBeginError 303 | } 304 | if fieldTypeId == thrift.STOP { 305 | break 306 | } 307 | switch fieldId { 308 | case 1: 309 | if fieldTypeId == thrift.STRUCT { 310 | l, err = p.FastReadField1(buf[offset:]) 311 | offset += l 312 | if err != nil { 313 | goto ReadFieldError 314 | } 315 | } else { 316 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 317 | offset += l 318 | if err != nil { 319 | goto SkipFieldError 320 | } 321 | } 322 | default: 323 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 324 | offset += l 325 | if err != nil { 326 | goto SkipFieldError 327 | } 328 | } 329 | 330 | l, err = bthrift.Binary.ReadFieldEnd(buf[offset:]) 331 | offset += l 332 | if err != nil { 333 | goto ReadFieldEndError 334 | } 335 | } 336 | l, err = bthrift.Binary.ReadStructEnd(buf[offset:]) 337 | offset += l 338 | if err != nil { 339 | goto ReadStructEndError 340 | } 341 | 342 | return offset, nil 343 | ReadStructBeginError: 344 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 345 | ReadFieldBeginError: 346 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 347 | ReadFieldError: 348 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_HelloEchoArgs[fieldId]), err) 349 | SkipFieldError: 350 | return offset, thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 351 | ReadFieldEndError: 352 | return offset, thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 353 | ReadStructEndError: 354 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 355 | } 356 | 357 | func (p *HelloEchoArgs) FastReadField1(buf []byte) (int, error) { 358 | offset := 0 359 | 360 | tmp := NewRequest() 361 | if l, err := tmp.FastRead(buf[offset:]); err != nil { 362 | return offset, err 363 | } else { 364 | offset += l 365 | } 366 | p.Req = tmp 367 | return offset, nil 368 | } 369 | 370 | // for compatibility 371 | func (p *HelloEchoArgs) FastWrite(buf []byte) int { 372 | return 0 373 | } 374 | 375 | func (p *HelloEchoArgs) FastWriteNocopy(buf []byte, binaryWriter bthrift.BinaryWriter) int { 376 | offset := 0 377 | offset += bthrift.Binary.WriteStructBegin(buf[offset:], "echo_args") 378 | if p != nil { 379 | offset += p.fastWriteField1(buf[offset:], binaryWriter) 380 | } 381 | offset += bthrift.Binary.WriteFieldStop(buf[offset:]) 382 | offset += bthrift.Binary.WriteStructEnd(buf[offset:]) 383 | return offset 384 | } 385 | 386 | func (p *HelloEchoArgs) BLength() int { 387 | l := 0 388 | l += bthrift.Binary.StructBeginLength("echo_args") 389 | if p != nil { 390 | l += p.field1Length() 391 | } 392 | l += bthrift.Binary.FieldStopLength() 393 | l += bthrift.Binary.StructEndLength() 394 | return l 395 | } 396 | 397 | func (p *HelloEchoArgs) fastWriteField1(buf []byte, binaryWriter bthrift.BinaryWriter) int { 398 | offset := 0 399 | offset += bthrift.Binary.WriteFieldBegin(buf[offset:], "req", thrift.STRUCT, 1) 400 | offset += p.Req.FastWriteNocopy(buf[offset:], binaryWriter) 401 | offset += bthrift.Binary.WriteFieldEnd(buf[offset:]) 402 | return offset 403 | } 404 | 405 | func (p *HelloEchoArgs) field1Length() int { 406 | l := 0 407 | l += bthrift.Binary.FieldBeginLength("req", thrift.STRUCT, 1) 408 | l += p.Req.BLength() 409 | l += bthrift.Binary.FieldEndLength() 410 | return l 411 | } 412 | 413 | func (p *HelloEchoResult) FastRead(buf []byte) (int, error) { 414 | var err error 415 | var offset int 416 | var l int 417 | var fieldTypeId thrift.TType 418 | var fieldId int16 419 | _, l, err = bthrift.Binary.ReadStructBegin(buf) 420 | offset += l 421 | if err != nil { 422 | goto ReadStructBeginError 423 | } 424 | 425 | for { 426 | _, fieldTypeId, fieldId, l, err = bthrift.Binary.ReadFieldBegin(buf[offset:]) 427 | offset += l 428 | if err != nil { 429 | goto ReadFieldBeginError 430 | } 431 | if fieldTypeId == thrift.STOP { 432 | break 433 | } 434 | switch fieldId { 435 | case 0: 436 | if fieldTypeId == thrift.STRUCT { 437 | l, err = p.FastReadField0(buf[offset:]) 438 | offset += l 439 | if err != nil { 440 | goto ReadFieldError 441 | } 442 | } else { 443 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 444 | offset += l 445 | if err != nil { 446 | goto SkipFieldError 447 | } 448 | } 449 | default: 450 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 451 | offset += l 452 | if err != nil { 453 | goto SkipFieldError 454 | } 455 | } 456 | 457 | l, err = bthrift.Binary.ReadFieldEnd(buf[offset:]) 458 | offset += l 459 | if err != nil { 460 | goto ReadFieldEndError 461 | } 462 | } 463 | l, err = bthrift.Binary.ReadStructEnd(buf[offset:]) 464 | offset += l 465 | if err != nil { 466 | goto ReadStructEndError 467 | } 468 | 469 | return offset, nil 470 | ReadStructBeginError: 471 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 472 | ReadFieldBeginError: 473 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 474 | ReadFieldError: 475 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_HelloEchoResult[fieldId]), err) 476 | SkipFieldError: 477 | return offset, thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 478 | ReadFieldEndError: 479 | return offset, thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 480 | ReadStructEndError: 481 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 482 | } 483 | 484 | func (p *HelloEchoResult) FastReadField0(buf []byte) (int, error) { 485 | offset := 0 486 | 487 | tmp := NewResponse() 488 | if l, err := tmp.FastRead(buf[offset:]); err != nil { 489 | return offset, err 490 | } else { 491 | offset += l 492 | } 493 | p.Success = tmp 494 | return offset, nil 495 | } 496 | 497 | // for compatibility 498 | func (p *HelloEchoResult) FastWrite(buf []byte) int { 499 | return 0 500 | } 501 | 502 | func (p *HelloEchoResult) FastWriteNocopy(buf []byte, binaryWriter bthrift.BinaryWriter) int { 503 | offset := 0 504 | offset += bthrift.Binary.WriteStructBegin(buf[offset:], "echo_result") 505 | if p != nil { 506 | offset += p.fastWriteField0(buf[offset:], binaryWriter) 507 | } 508 | offset += bthrift.Binary.WriteFieldStop(buf[offset:]) 509 | offset += bthrift.Binary.WriteStructEnd(buf[offset:]) 510 | return offset 511 | } 512 | 513 | func (p *HelloEchoResult) BLength() int { 514 | l := 0 515 | l += bthrift.Binary.StructBeginLength("echo_result") 516 | if p != nil { 517 | l += p.field0Length() 518 | } 519 | l += bthrift.Binary.FieldStopLength() 520 | l += bthrift.Binary.StructEndLength() 521 | return l 522 | } 523 | 524 | func (p *HelloEchoResult) fastWriteField0(buf []byte, binaryWriter bthrift.BinaryWriter) int { 525 | offset := 0 526 | if p.IsSetSuccess() { 527 | offset += bthrift.Binary.WriteFieldBegin(buf[offset:], "success", thrift.STRUCT, 0) 528 | offset += p.Success.FastWriteNocopy(buf[offset:], binaryWriter) 529 | offset += bthrift.Binary.WriteFieldEnd(buf[offset:]) 530 | } 531 | return offset 532 | } 533 | 534 | func (p *HelloEchoResult) field0Length() int { 535 | l := 0 536 | if p.IsSetSuccess() { 537 | l += bthrift.Binary.FieldBeginLength("success", thrift.STRUCT, 0) 538 | l += p.Success.BLength() 539 | l += bthrift.Binary.FieldEndLength() 540 | } 541 | return l 542 | } 543 | 544 | func (p *HelloEchoArgs) GetFirstArgument() interface{} { 545 | return p.Req 546 | } 547 | 548 | func (p *HelloEchoResult) GetResult() interface{} { 549 | return p.Success 550 | } 551 | -------------------------------------------------------------------------------- /example/hello/kitex_info.yaml: -------------------------------------------------------------------------------- 1 | kitexinfo: 2 | ServiceName: 'hello' 3 | ToolVersion: 'v0.5.1' 4 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kitex-contrib/registry-nacos 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/apache/thrift v0.16.0 7 | github.com/cloudwego/kitex v0.12.3 8 | github.com/cloudwego/kitex/pkg/protocol/bthrift v0.0.0-20250311043234-fedc8b81483b 9 | github.com/nacos-group/nacos-sdk-go v1.1.5 10 | github.com/stretchr/testify v1.10.0 11 | ) 12 | 13 | require ( 14 | github.com/aliyun/alibaba-cloud-sdk-go v1.61.18 // indirect 15 | github.com/buger/jsonparser v1.1.1 // indirect 16 | github.com/bytedance/gopkg v0.1.1 // indirect 17 | github.com/bytedance/sonic v1.12.7 // indirect 18 | github.com/bytedance/sonic/loader v0.2.2 // indirect 19 | github.com/cloudwego/base64x v0.1.4 // indirect 20 | github.com/cloudwego/configmanager v0.2.2 // indirect 21 | github.com/cloudwego/dynamicgo v0.5.2 // indirect 22 | github.com/cloudwego/fastpb v0.0.5 // indirect 23 | github.com/cloudwego/frugal v0.2.3 // indirect 24 | github.com/cloudwego/gopkg v0.1.4 // indirect 25 | github.com/cloudwego/iasm v0.2.0 // indirect 26 | github.com/cloudwego/localsession v0.1.2 // indirect 27 | github.com/cloudwego/netpoll v0.6.5 // indirect 28 | github.com/cloudwego/runtimex v0.1.1 // indirect 29 | github.com/cloudwego/thriftgo v0.3.18 // indirect 30 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 31 | github.com/fatih/structtag v1.2.0 // indirect 32 | github.com/go-errors/errors v1.0.1 // indirect 33 | github.com/golang/protobuf v1.5.4 // indirect 34 | github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect 35 | github.com/iancoleman/strcase v0.2.0 // indirect 36 | github.com/jhump/protoreflect v1.8.2 // indirect 37 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect 38 | github.com/json-iterator/go v1.1.12 // indirect 39 | github.com/klauspost/cpuid/v2 v2.2.9 // indirect 40 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 41 | github.com/modern-go/reflect2 v1.0.2 // indirect 42 | github.com/pkg/errors v0.9.1 // indirect 43 | github.com/pmezard/go-difflib v1.0.0 // indirect 44 | github.com/tidwall/gjson v1.17.3 // indirect 45 | github.com/tidwall/match v1.1.1 // indirect 46 | github.com/tidwall/pretty v1.2.0 // indirect 47 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 48 | go.uber.org/atomic v1.6.0 // indirect 49 | go.uber.org/multierr v1.5.0 // indirect 50 | go.uber.org/zap v1.15.0 // indirect 51 | golang.org/x/arch v0.12.0 // indirect 52 | golang.org/x/net v0.24.0 // indirect 53 | golang.org/x/sync v0.8.0 // indirect 54 | golang.org/x/sys v0.27.0 // indirect 55 | golang.org/x/text v0.14.0 // indirect 56 | google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384 // indirect 57 | google.golang.org/protobuf v1.33.0 // indirect 58 | gopkg.in/ini.v1 v1.42.0 // indirect 59 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect 60 | gopkg.in/yaml.v3 v3.0.1 // indirect 61 | ) 62 | 63 | replace github.com/apache/thrift => github.com/apache/thrift v0.13.0 64 | -------------------------------------------------------------------------------- /hack/resolve-modules.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This is used by the linter action. 4 | # Recursively finds all directories with a go.mod file and creates 5 | # a GitHub Actions JSON output option. 6 | 7 | set -o errexit 8 | 9 | HOME=$( 10 | cd "$(dirname "${BASH_SOURCE[0]}")" && 11 | cd .. && 12 | pwd 13 | ) 14 | 15 | source "${HOME}/hack/util.sh" 16 | all_modules=$(util::find_modules) 17 | PATHS="" 18 | for mod in $all_modules; do 19 | PATHS+=$(printf '{"workdir":"%s"},' ${mod}) 20 | done 21 | 22 | echo "::set-output name=matrix::{\"include\":[${PATHS%?}]}" -------------------------------------------------------------------------------- /hack/tools.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit 4 | set -o nounset 5 | set -o pipefail 6 | 7 | HOME=$( 8 | cd "$(dirname "${BASH_SOURCE[0]}")" && 9 | cd .. && 10 | pwd 11 | ) 12 | 13 | source "${HOME}/hack/util.sh" 14 | 15 | all_modules=$(util::find_modules) 16 | 17 | # test all mod 18 | function test() { 19 | for mod in $all_modules; do 20 | pushd "$mod" >/dev/null && 21 | echo "go test $(sed -n 1p go.mod | cut -d ' ' -f2)" && 22 | go test -race -covermode=atomic -coverprofile=coverage.out ./... 23 | popd >/dev/null || exit 24 | done 25 | } 26 | 27 | # vet all mod 28 | function vet() { 29 | for mod in $all_modules; do 30 | pushd "$mod" >/dev/null && 31 | echo "go vet $(sed -n 1p go.mod | cut -d ' ' -f2)" && 32 | go vet -stdmethods=false ./... 33 | popd >/dev/null || exit 34 | done 35 | } 36 | 37 | function help() { 38 | echo "use: test,vet" 39 | } 40 | 41 | case $1 in 42 | vet) 43 | vet 44 | ;; 45 | test) 46 | test 47 | ;; 48 | *) 49 | help 50 | ;; 51 | esac 52 | -------------------------------------------------------------------------------- /hack/util.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # find all go mod path 4 | # returns an array contains mod path 5 | function util::find_modules() { 6 | find . -not \( \ 7 | \( \ 8 | -path './output' \ 9 | -o -path './.git' \ 10 | -o -path '*/third_party/*' \ 11 | -o -path '*/vendor/*' \ 12 | -o -path '*/example/*' \ 13 | \) -prune \ 14 | \) -name 'go.mod' -print0 | xargs -0 -I {} dirname {} 15 | } -------------------------------------------------------------------------------- /licenses/LICENSE-nacos-sdk-go: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /licenses/LICENSE-testify: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /nacos/client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package nacos 16 | 17 | import ( 18 | "github.com/nacos-group/nacos-sdk-go/clients" 19 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 20 | "github.com/nacos-group/nacos-sdk-go/common/constant" 21 | "github.com/nacos-group/nacos-sdk-go/vo" 22 | ) 23 | 24 | // Option is the way to config a client. 25 | type Option struct { 26 | F func(o *vo.NacosClientParam) 27 | } 28 | 29 | // NewDefaultNacosClient Create a default Nacos client 30 | // It can create a client with default config by env variable. 31 | // See: env.go 32 | func NewDefaultNacosClient(opts ...Option) (naming_client.INamingClient, error) { 33 | sc := []constant.ServerConfig{ 34 | *constant.NewServerConfig(NacosAddr(), uint64(NacosPort())), 35 | } 36 | cc := constant.ClientConfig{ 37 | NamespaceId: NacosNameSpaceId(), 38 | RegionId: NACOS_DEFAULT_REGIONID, 39 | NotLoadCacheAtStart: true, 40 | CustomLogger: NewCustomNacosLogger(), 41 | } 42 | param := vo.NacosClientParam{ 43 | ClientConfig: &cc, 44 | ServerConfigs: sc, 45 | } 46 | for _, opt := range opts { 47 | opt.F(¶m) 48 | } 49 | cli, err := clients.NewNamingClient(param) 50 | if err != nil { 51 | return nil, err 52 | } 53 | return cli, nil 54 | } 55 | -------------------------------------------------------------------------------- /nacos/env.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package nacos 16 | 17 | import ( 18 | "os" 19 | "strconv" 20 | "strings" 21 | 22 | "github.com/cloudwego/kitex/pkg/klog" 23 | ) 24 | 25 | const ( 26 | NACOS_ENV_SERVER_ADDR = "serverAddr" 27 | NACOS_ENV_PORT = "serverPort" 28 | NACOS_ENV_TAGS = "KITEX_NACOS_ENV_TAGS" 29 | NACOS_ENV_NAMESPACE_ID = "namespace" 30 | NACOS_DEFAULT_SERVER_ADDR = "127.0.0.1" 31 | NACOS_DEFAULT_PORT = 8848 32 | NACOS_DEFAULT_REGIONID = "cn-hangzhou" 33 | ) 34 | 35 | // Tags providers the default tags to inject nacos. 36 | var Tags map[string]string 37 | 38 | func init() { 39 | Tags = parseTags(os.Getenv(NACOS_ENV_TAGS)) 40 | } 41 | 42 | func parseTags(tags string) map[string]string { 43 | out := map[string]string{ 44 | "cloudwego.nacos.client": "kitex", 45 | } 46 | if len(tags) == 0 { 47 | return out 48 | } 49 | parts := strings.Split(tags, ",") 50 | for _, part := range parts { 51 | tag := strings.Split(part, "=") 52 | if len(tag) == 2 { 53 | out[tag[0]] = tag[1] 54 | } 55 | } 56 | return out 57 | } 58 | 59 | // NacosPort Get Nacos port from environment variables 60 | func NacosPort() int64 { 61 | portText := os.Getenv(NACOS_ENV_PORT) 62 | if len(portText) == 0 { 63 | return NACOS_DEFAULT_PORT 64 | } 65 | port, err := strconv.ParseInt(portText, 10, 64) 66 | if err != nil { 67 | klog.Errorf("ParseInt failed,err:%s", err.Error()) 68 | return NACOS_DEFAULT_PORT 69 | } 70 | return port 71 | } 72 | 73 | // NacosAddr Get Nacos addr from environment variables 74 | func NacosAddr() string { 75 | addr := os.Getenv(NACOS_ENV_SERVER_ADDR) 76 | if len(addr) == 0 { 77 | return NACOS_DEFAULT_SERVER_ADDR 78 | } 79 | return addr 80 | } 81 | 82 | // NacosNameSpaceId Get Nacos namespace id from environment variables 83 | func NacosNameSpaceId() string { 84 | return os.Getenv(NACOS_ENV_NAMESPACE_ID) 85 | } 86 | -------------------------------------------------------------------------------- /nacos/env_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package nacos 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/stretchr/testify/assert" 21 | ) 22 | 23 | // TestEnvFunc test env func 24 | func TestEnvFunc(t *testing.T) { 25 | assert.Equal(t, int64(8848), NacosPort()) 26 | assert.Equal(t, "127.0.0.1", NacosAddr()) 27 | assert.Equal(t, "public", NacosNameSpaceId()) 28 | } 29 | 30 | func TestParseTags(t *testing.T) { 31 | assert.Equal(t, parseTags("k1=v1,k2=v2"), map[string]string{ 32 | "cloudwego.nacos.client": "kitex", 33 | "k1": "v1", 34 | "k2": "v2", 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /nacos/logger.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package nacos 16 | 17 | import ( 18 | "github.com/cloudwego/kitex/pkg/klog" 19 | "github.com/nacos-group/nacos-sdk-go/common/logger" 20 | ) 21 | 22 | type customNacosLogger struct{} 23 | 24 | func NewCustomNacosLogger() logger.Logger { 25 | return customNacosLogger{} 26 | } 27 | 28 | func (m customNacosLogger) Info(args ...interface{}) { 29 | klog.Info(args...) 30 | } 31 | 32 | func (m customNacosLogger) Warn(args ...interface{}) { 33 | klog.Warn(args...) 34 | } 35 | 36 | func (m customNacosLogger) Error(args ...interface{}) { 37 | klog.Error(args...) 38 | } 39 | 40 | func (m customNacosLogger) Debug(args ...interface{}) { 41 | klog.Debug(args) 42 | } 43 | 44 | func (m customNacosLogger) Infof(fmt string, args ...interface{}) { 45 | klog.Infof(fmt, args...) 46 | } 47 | 48 | func (m customNacosLogger) Warnf(fmt string, args ...interface{}) { 49 | klog.Warnf(fmt, args...) 50 | } 51 | 52 | func (m customNacosLogger) Errorf(fmt string, args ...interface{}) { 53 | klog.Errorf(fmt, args...) 54 | } 55 | 56 | func (m customNacosLogger) Debugf(fmt string, args ...interface{}) { 57 | klog.Debugf(fmt, args...) 58 | } 59 | -------------------------------------------------------------------------------- /registry/registry.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package registry 16 | 17 | import ( 18 | "errors" 19 | "fmt" 20 | "net" 21 | "strconv" 22 | 23 | "github.com/cloudwego/kitex/pkg/registry" 24 | "github.com/kitex-contrib/registry-nacos/nacos" 25 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 26 | "github.com/nacos-group/nacos-sdk-go/vo" 27 | ) 28 | 29 | type options struct { 30 | cluster string 31 | group string 32 | } 33 | 34 | // Option is nacos option. 35 | type Option func(o *options) 36 | 37 | // WithCluster with cluster option. 38 | func WithCluster(cluster string) Option { 39 | return func(o *options) { o.cluster = cluster } 40 | } 41 | 42 | // WithGroup with group option. 43 | func WithGroup(group string) Option { 44 | return func(o *options) { o.group = group } 45 | } 46 | 47 | type nacosRegistry struct { 48 | cli naming_client.INamingClient 49 | opts options 50 | } 51 | 52 | // NewDefaultNacosRegistry create a default service registry using nacos. 53 | func NewDefaultNacosRegistry(opts ...Option) (registry.Registry, error) { 54 | cli, err := nacos.NewDefaultNacosClient() 55 | if err != nil { 56 | return nil, err 57 | } 58 | return NewNacosRegistry(cli, opts...), nil 59 | } 60 | 61 | // NewNacosRegistry create a new registry using nacos. 62 | func NewNacosRegistry(cli naming_client.INamingClient, opts ...Option) registry.Registry { 63 | op := options{ 64 | cluster: "DEFAULT", 65 | group: "DEFAULT_GROUP", 66 | } 67 | for _, option := range opts { 68 | option(&op) 69 | } 70 | return &nacosRegistry{cli: cli, opts: op} 71 | } 72 | 73 | var _ registry.Registry = (*nacosRegistry)(nil) 74 | 75 | // Register service info to nacos. 76 | func (n *nacosRegistry) Register(info *registry.Info) error { 77 | if err := n.validateRegistryInfo(info); err != nil { 78 | return err 79 | } 80 | host, port, err := net.SplitHostPort(info.Addr.String()) 81 | if err != nil { 82 | return fmt.Errorf("parse registry info addr error: %w", err) 83 | } 84 | p, err := strconv.Atoi(port) 85 | if err != nil { 86 | return fmt.Errorf("parse registry info port error: %w", err) 87 | } 88 | if host == "" || host == "::" { 89 | host, err = n.getLocalIpv4Host() 90 | if err != nil { 91 | return fmt.Errorf("parse registry info addr error: %w", err) 92 | } 93 | } 94 | 95 | _, e := n.cli.RegisterInstance(vo.RegisterInstanceParam{ 96 | Ip: host, 97 | Port: uint64(p), 98 | ServiceName: info.ServiceName, 99 | Weight: float64(info.Weight), 100 | Enable: true, 101 | Healthy: true, 102 | Metadata: mergeTags(info.Tags, nacos.Tags), 103 | GroupName: n.opts.group, 104 | ClusterName: n.opts.cluster, 105 | Ephemeral: true, 106 | }) 107 | if e != nil { 108 | return fmt.Errorf("register instance error: %w", e) 109 | } 110 | return nil 111 | } 112 | 113 | func (n *nacosRegistry) getLocalIpv4Host() (string, error) { 114 | addr, err := net.InterfaceAddrs() 115 | if err != nil { 116 | return "", err 117 | } 118 | for _, addr := range addr { 119 | ipNet, isIpNet := addr.(*net.IPNet) 120 | if isIpNet && !ipNet.IP.IsLoopback() { 121 | ipv4 := ipNet.IP.To4() 122 | if ipv4 != nil { 123 | return ipv4.String(), nil 124 | } 125 | } 126 | } 127 | return "", errors.New("not found ipv4 address") 128 | } 129 | 130 | func (n *nacosRegistry) validateRegistryInfo(info *registry.Info) error { 131 | if info == nil { 132 | return errors.New("registry.Info can not be empty") 133 | } 134 | if info.ServiceName == "" { 135 | return errors.New("registry.Info ServiceName can not be empty") 136 | } 137 | if info.Addr == nil { 138 | return errors.New("registry.Info Addr can not be empty") 139 | } 140 | 141 | return nil 142 | } 143 | 144 | // Deregister a service info from nacos. 145 | func (n *nacosRegistry) Deregister(info *registry.Info) error { 146 | if err := n.validateRegistryInfo(info); err != nil { 147 | return err 148 | } 149 | host, port, err := net.SplitHostPort(info.Addr.String()) 150 | if err != nil { 151 | return err 152 | } 153 | p, err := strconv.Atoi(port) 154 | if err != nil { 155 | return fmt.Errorf("parse registry info port error: %w", err) 156 | } 157 | if host == "" || host == "::" { 158 | host, err = n.getLocalIpv4Host() 159 | if err != nil { 160 | return fmt.Errorf("parse registry info addr error: %w", err) 161 | } 162 | } 163 | if _, err = n.cli.DeregisterInstance(vo.DeregisterInstanceParam{ 164 | Ip: host, 165 | Port: uint64(p), 166 | ServiceName: info.ServiceName, 167 | Ephemeral: true, 168 | GroupName: n.opts.group, 169 | Cluster: n.opts.cluster, 170 | }); err != nil { 171 | return err 172 | } 173 | return nil 174 | } 175 | 176 | // should not modify the source data. 177 | func mergeTags(ts ...map[string]string) map[string]string { 178 | if len(ts) == 0 { 179 | return nil 180 | } 181 | if len(ts) == 1 { 182 | return ts[0] 183 | } 184 | tags := map[string]string{} 185 | for _, t := range ts { 186 | for k, v := range t { 187 | tags[k] = v 188 | } 189 | } 190 | return tags 191 | } 192 | -------------------------------------------------------------------------------- /registry/registry_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package registry 16 | 17 | import ( 18 | "net" 19 | "testing" 20 | "time" 21 | 22 | "github.com/cloudwego/kitex/pkg/registry" 23 | "github.com/kitex-contrib/registry-nacos/nacos" 24 | "github.com/nacos-group/nacos-sdk-go/clients" 25 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 26 | "github.com/nacos-group/nacos-sdk-go/common/constant" 27 | "github.com/nacos-group/nacos-sdk-go/vo" 28 | "github.com/stretchr/testify/assert" 29 | ) 30 | 31 | func getNacosClient() (naming_client.INamingClient, error) { 32 | sc := []constant.ServerConfig{ 33 | *constant.NewServerConfig("127.0.0.1", 8848), 34 | } 35 | 36 | cc := constant.ClientConfig{ 37 | NamespaceId: "public", 38 | TimeoutMs: 5000, 39 | NotLoadCacheAtStart: true, 40 | CustomLogger: nacos.NewCustomNacosLogger(), 41 | CacheDir: "/tmp/nacos/cache", 42 | } 43 | 44 | return clients.NewNamingClient( 45 | vo.NacosClientParam{ 46 | ClientConfig: &cc, 47 | ServerConfigs: sc, 48 | }, 49 | ) 50 | } 51 | 52 | // TestNewNacosRegistry test new a nacos registry 53 | func TestNewNacosRegistry(t *testing.T) { 54 | client, err := getNacosClient() 55 | if err != nil { 56 | t.Errorf("err:%v", err) 57 | return 58 | } 59 | got := NewNacosRegistry(client, WithCluster("DEFAULT"), WithGroup("DEFAULT_GROUP")) 60 | assert.NotNil(t, got) 61 | } 62 | 63 | // TestNewNacosRegistry test registry a service 64 | func TestNacosRegistryRegister(t *testing.T) { 65 | client, err := getNacosClient() 66 | if err != nil { 67 | t.Errorf("err:%v", err) 68 | return 69 | } 70 | type fields struct { 71 | cli naming_client.INamingClient 72 | } 73 | type args struct { 74 | info *registry.Info 75 | } 76 | tests := []struct { 77 | name string 78 | fields fields 79 | args args 80 | wantErr bool 81 | }{ 82 | { 83 | name: "common", 84 | fields: fields{client}, 85 | args: args{info: ®istry.Info{ 86 | ServiceName: "demo.kitex-contrib.local", 87 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8080}, 88 | Weight: 999, 89 | StartTime: time.Now(), 90 | Tags: map[string]string{"env": "local"}, 91 | }}, 92 | wantErr: false, 93 | }, 94 | } 95 | for _, tt := range tests { 96 | t.Run(tt.name, func(t *testing.T) { 97 | n := NewNacosRegistry(tt.fields.cli, WithCluster("DEFAULT"), WithGroup("DEFAULT_GROUP")) 98 | if err := n.Register(tt.args.info); (err != nil) != tt.wantErr { 99 | t.Errorf("Register() error = %v, wantErr %v", err, tt.wantErr) 100 | } 101 | }) 102 | } 103 | } 104 | 105 | // TestNacosRegistryDeregister test deregister a service 106 | func TestNacosRegistryDeregister(t *testing.T) { 107 | client, err := getNacosClient() 108 | if err != nil { 109 | t.Errorf("err:%v", err) 110 | return 111 | } 112 | type fields struct { 113 | cli naming_client.INamingClient 114 | } 115 | type args struct { 116 | info *registry.Info 117 | } 118 | tests := []struct { 119 | name string 120 | fields fields 121 | args args 122 | wantErr bool 123 | }{ 124 | { 125 | name: "common", 126 | args: args{info: ®istry.Info{ 127 | ServiceName: "demo.kitex-contrib.local", 128 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8080}, 129 | Weight: 999, 130 | StartTime: time.Now(), 131 | Tags: map[string]string{"env": "local"}, 132 | }}, 133 | fields: fields{client}, 134 | wantErr: false, 135 | }, 136 | } 137 | for _, tt := range tests { 138 | t.Run(tt.name, func(t *testing.T) { 139 | n := NewNacosRegistry(tt.fields.cli, WithCluster("DEFAULT"), WithGroup("DEFAULT_GROUP")) 140 | if err := n.Deregister(tt.args.info); (err != nil) != tt.wantErr { 141 | t.Errorf("Deregister() error = %v, wantErr %v", err, tt.wantErr) 142 | } 143 | }) 144 | } 145 | } 146 | 147 | // TestNacosMultipleInstances test registry multiple service,then deregister one 148 | func TestNacosMultipleInstances(t *testing.T) { 149 | var ( 150 | svcName = "MultipleInstances" 151 | clusterName = "TheCluster" 152 | groupName = "TheGroup" 153 | ) 154 | client, err := getNacosClient() 155 | if err != nil { 156 | t.Errorf("err:%v", err) 157 | return 158 | } 159 | time.Sleep(time.Second) 160 | got := NewNacosRegistry(client, WithCluster(clusterName), WithGroup(groupName)) 161 | if !assert.NotNil(t, got) { 162 | t.Errorf("err: new registry fail") 163 | return 164 | } 165 | time.Sleep(time.Second) 166 | err = got.Register(®istry.Info{ 167 | ServiceName: svcName, 168 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8081}, 169 | }) 170 | assert.Nil(t, err) 171 | if err != nil { 172 | t.Errorf("err:%v", err) 173 | return 174 | } 175 | 176 | err = got.Register(®istry.Info{ 177 | ServiceName: svcName, 178 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8082}, 179 | }) 180 | assert.Nil(t, err) 181 | if err != nil { 182 | t.Errorf("err:%v", err) 183 | return 184 | } 185 | 186 | err = got.Register(®istry.Info{ 187 | ServiceName: svcName, 188 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8083}, 189 | }) 190 | assert.Nil(t, err) 191 | 192 | time.Sleep(time.Second) 193 | res, err := client.SelectAllInstances(vo.SelectAllInstancesParam{ 194 | ServiceName: svcName, 195 | GroupName: groupName, 196 | Clusters: []string{clusterName}, 197 | }) 198 | assert.Nil(t, err) 199 | assert.Equal(t, 3, len(res), "successful register not three") 200 | 201 | time.Sleep(time.Second) 202 | err = got.Deregister(®istry.Info{ 203 | ServiceName: svcName, 204 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8083}, 205 | }) 206 | assert.Nil(t, err) 207 | 208 | time.Sleep(time.Second * 3) 209 | res, err = client.SelectAllInstances(vo.SelectAllInstancesParam{ 210 | ServiceName: svcName, 211 | GroupName: groupName, 212 | Clusters: []string{clusterName}, 213 | }) 214 | assert.Nil(t, err) 215 | if assert.Equal(t, 2, len(res), "deregister one, instances num should be two") { 216 | for _, i := range res { 217 | assert.Equal(t, "127.0.0.1", i.Ip) 218 | assert.Contains(t, []uint64{8081, 8082}, i.Port) 219 | } 220 | } 221 | } 222 | 223 | // TestNewDefaultNacosRegistry test new a default nacos registry 224 | func TestNewDefaultNacosRegistry(t *testing.T) { 225 | r, err := NewDefaultNacosRegistry() 226 | assert.Nil(t, err) 227 | assert.NotNil(t, r) 228 | } 229 | 230 | // TestNacosMultipleInstancesWithDefaultNacosRegistry use DefaultNacosRegistry to test registry multiple service,then deregister one 231 | func TestNacosMultipleInstancesWithDefaultNacosRegistry(t *testing.T) { 232 | var ( 233 | svcName = "MultipleInstances" 234 | clusterName = "TheCluster" 235 | groupName = "TheGroup" 236 | ) 237 | got, err := NewDefaultNacosRegistry(WithCluster(clusterName), WithGroup(groupName)) 238 | assert.Nil(t, err) 239 | if !assert.NotNil(t, got) { 240 | t.Errorf("err: new registry fail") 241 | return 242 | } 243 | time.Sleep(time.Second) 244 | err = got.Register(®istry.Info{ 245 | ServiceName: svcName, 246 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8081}, 247 | }) 248 | assert.Nil(t, err) 249 | if err != nil { 250 | t.Errorf("err:%v", err) 251 | return 252 | } 253 | 254 | err = got.Register(®istry.Info{ 255 | ServiceName: svcName, 256 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8082}, 257 | }) 258 | assert.Nil(t, err) 259 | if err != nil { 260 | t.Errorf("err:%v", err) 261 | return 262 | } 263 | 264 | err = got.Register(®istry.Info{ 265 | ServiceName: svcName, 266 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8083}, 267 | }) 268 | assert.Nil(t, err) 269 | 270 | time.Sleep(time.Second * 1) 271 | client, err := getNacosClient() 272 | if err != nil { 273 | t.Errorf("err:%v", err) 274 | return 275 | } 276 | res, err := client.SelectAllInstances(vo.SelectAllInstancesParam{ 277 | ServiceName: svcName, 278 | GroupName: groupName, 279 | Clusters: []string{clusterName}, 280 | }) 281 | assert.Nil(t, err) 282 | assert.Equal(t, 3, len(res), "successful register not three") 283 | 284 | time.Sleep(time.Second) 285 | err = got.Deregister(®istry.Info{ 286 | ServiceName: svcName, 287 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8083}, 288 | }) 289 | assert.Nil(t, err) 290 | 291 | time.Sleep(time.Second * 3) 292 | res, err = client.SelectAllInstances(vo.SelectAllInstancesParam{ 293 | ServiceName: svcName, 294 | GroupName: groupName, 295 | Clusters: []string{clusterName}, 296 | }) 297 | assert.Nil(t, err) 298 | if assert.Equal(t, 2, len(res), "deregister one, instances num should be two") { 299 | for _, i := range res { 300 | assert.Equal(t, "127.0.0.1", i.Ip) 301 | assert.Contains(t, []uint64{8081, 8082}, i.Port) 302 | } 303 | } 304 | } 305 | 306 | func TestMergeTags(t *testing.T) { 307 | t1 := map[string]string{ 308 | "k1": "v1", 309 | "k2": "v2", 310 | } 311 | t2 := map[string]string{ 312 | "k3": "v3", 313 | "k4": "v4", 314 | } 315 | merged := mergeTags(t1, t2) 316 | assert.Equal(t, merged, map[string]string{ 317 | "k1": "v1", 318 | "k2": "v2", 319 | "k3": "v3", 320 | "k4": "v4", 321 | }) 322 | assert.Equal(t, t1, map[string]string{ 323 | "k1": "v1", 324 | "k2": "v2", 325 | }) 326 | assert.Equal(t, t2, map[string]string{ 327 | "k3": "v3", 328 | "k4": "v4", 329 | }) 330 | } 331 | -------------------------------------------------------------------------------- /resolver/resolver.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package resolver 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | 21 | "github.com/cloudwego/kitex/pkg/discovery" 22 | "github.com/cloudwego/kitex/pkg/rpcinfo" 23 | "github.com/kitex-contrib/registry-nacos/nacos" 24 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 25 | "github.com/nacos-group/nacos-sdk-go/vo" 26 | ) 27 | 28 | type options struct { 29 | cluster string 30 | group string 31 | } 32 | 33 | // Option is nacos option. 34 | type Option func(o *options) 35 | 36 | // WithCluster with cluster option. 37 | func WithCluster(cluster string) Option { 38 | return func(o *options) { o.cluster = cluster } 39 | } 40 | 41 | // WithGroup with group option. 42 | func WithGroup(group string) Option { 43 | return func(o *options) { o.group = group } 44 | } 45 | 46 | type nacosResolver struct { 47 | cli naming_client.INamingClient 48 | opts options 49 | } 50 | 51 | // NewDefaultNacosResolver create a default service resolver using nacos. 52 | func NewDefaultNacosResolver(opts ...Option) (discovery.Resolver, error) { 53 | cli, err := nacos.NewDefaultNacosClient() 54 | if err != nil { 55 | return nil, err 56 | } 57 | return NewNacosResolver(cli, opts...), nil 58 | } 59 | 60 | // NewNacosResolver create a service resolver using nacos. 61 | func NewNacosResolver(cli naming_client.INamingClient, opts ...Option) discovery.Resolver { 62 | op := options{ 63 | cluster: "DEFAULT", 64 | group: "DEFAULT_GROUP", 65 | } 66 | for _, option := range opts { 67 | option(&op) 68 | } 69 | return &nacosResolver{cli: cli, opts: op} 70 | } 71 | 72 | // Target return a description for the given target that is suitable for being a key for cache. 73 | func (n *nacosResolver) Target(_ context.Context, target rpcinfo.EndpointInfo) (description string) { 74 | return target.ServiceName() 75 | } 76 | 77 | // Resolve a service info by desc. 78 | func (n *nacosResolver) Resolve(_ context.Context, desc string) (discovery.Result, error) { 79 | res, err := n.cli.SelectInstances(vo.SelectInstancesParam{ 80 | ServiceName: desc, 81 | HealthyOnly: true, 82 | GroupName: n.opts.group, 83 | Clusters: []string{n.opts.cluster}, 84 | }) 85 | if err != nil { 86 | return discovery.Result{}, err 87 | } 88 | if len(res) == 0 { 89 | return discovery.Result{}, fmt.Errorf("no instance remains for %v", desc) 90 | } 91 | instances := make([]discovery.Instance, 0, len(res)) 92 | for _, in := range res { 93 | if !in.Enable { 94 | continue 95 | } 96 | instances = append(instances, discovery.NewInstance( 97 | "tcp", 98 | fmt.Sprintf("%s:%d", in.Ip, in.Port), 99 | int(in.Weight), 100 | in.Metadata), 101 | ) 102 | } 103 | if len(instances) == 0 { 104 | return discovery.Result{}, fmt.Errorf("no instance remains for %v", desc) 105 | } 106 | return discovery.Result{ 107 | Cacheable: true, 108 | CacheKey: desc, 109 | Instances: instances, 110 | }, nil 111 | } 112 | 113 | // Diff computes the difference between two results. 114 | func (n *nacosResolver) Diff(cacheKey string, prev, next discovery.Result) (discovery.Change, bool) { 115 | return discovery.DefaultDiff(cacheKey, prev, next) 116 | } 117 | 118 | // Name returns the name of the resolver. 119 | func (n *nacosResolver) Name() string { 120 | return "nacos" + ":" + n.opts.cluster + ":" + n.opts.group 121 | } 122 | 123 | var _ discovery.Resolver = (*nacosResolver)(nil) 124 | -------------------------------------------------------------------------------- /resolver/resolver_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package resolver 16 | 17 | import ( 18 | "context" 19 | "net" 20 | "strings" 21 | "testing" 22 | "time" 23 | 24 | "github.com/cloudwego/kitex/pkg/discovery" 25 | "github.com/cloudwego/kitex/pkg/registry" 26 | "github.com/kitex-contrib/registry-nacos/nacos" 27 | nacosregistry "github.com/kitex-contrib/registry-nacos/registry" 28 | "github.com/nacos-group/nacos-sdk-go/clients" 29 | "github.com/nacos-group/nacos-sdk-go/clients/naming_client" 30 | "github.com/nacos-group/nacos-sdk-go/common/constant" 31 | "github.com/nacos-group/nacos-sdk-go/vo" 32 | "github.com/stretchr/testify/assert" 33 | ) 34 | 35 | var ( 36 | nacosCli naming_client.INamingClient 37 | svcName = "demo.kitex-contrib.local" 38 | svcAddr = net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8080} 39 | svcInfo = ®istry.Info{ 40 | ServiceName: svcName, 41 | Addr: &svcAddr, 42 | Weight: 999, 43 | StartTime: time.Now(), 44 | Tags: map[string]string{"env": "local"}, 45 | } 46 | ) 47 | 48 | func init() { 49 | cli, err := getNacosClient() 50 | if err != nil { 51 | return 52 | } 53 | time.Sleep(time.Second) 54 | err = nacosregistry.NewNacosRegistry(cli).Register(svcInfo) 55 | if err != nil { 56 | return 57 | } 58 | time.Sleep(time.Second) 59 | nacosCli = cli 60 | } 61 | 62 | func getNacosClient() (naming_client.INamingClient, error) { 63 | sc := []constant.ServerConfig{ 64 | *constant.NewServerConfig("127.0.0.1", 8848), 65 | } 66 | 67 | cc := constant.ClientConfig{ 68 | NamespaceId: "public", 69 | TimeoutMs: 5000, 70 | NotLoadCacheAtStart: true, 71 | CacheDir: "/tmp/nacos/cache", 72 | CustomLogger: nacos.NewCustomNacosLogger(), 73 | } 74 | 75 | return clients.NewNamingClient( 76 | vo.NacosClientParam{ 77 | ClientConfig: &cc, 78 | ServerConfigs: sc, 79 | }, 80 | ) 81 | } 82 | 83 | // TestNacosResolverResolve test Resolve a service 84 | func TestNacosResolverResolve(t *testing.T) { 85 | type fields struct { 86 | cli naming_client.INamingClient 87 | } 88 | type args struct { 89 | ctx context.Context 90 | desc string 91 | } 92 | tests := []struct { 93 | name string 94 | fields fields 95 | args args 96 | want discovery.Result 97 | wantErr bool 98 | }{ 99 | { 100 | name: "common", 101 | args: args{ 102 | ctx: context.Background(), 103 | desc: svcName, 104 | }, 105 | fields: fields{cli: nacosCli}, 106 | }, 107 | { 108 | name: "wrong desc", 109 | args: args{ 110 | ctx: context.Background(), 111 | desc: "xxxx.kitex-contrib.local", 112 | }, 113 | fields: fields{cli: nacosCli}, 114 | wantErr: true, 115 | }, 116 | } 117 | 118 | for _, tt := range tests { 119 | t.Run(tt.name, func(t *testing.T) { 120 | n := NewNacosResolver(tt.fields.cli) 121 | _, err := n.Resolve(tt.args.ctx, tt.args.desc) 122 | if (err != nil) != tt.wantErr { 123 | t.Errorf("Resolve() error = %v, wantErr %v", err, tt.wantErr) 124 | return 125 | } 126 | if err != nil && !strings.Contains(err.Error(), "instance list is empty") { 127 | t.Errorf("Resolve err is not expectant") 128 | return 129 | } 130 | }) 131 | } 132 | 133 | err := nacosregistry.NewNacosRegistry(nacosCli).Deregister(svcInfo) 134 | if err != nil { 135 | t.Errorf("Deregister Fail") 136 | return 137 | } 138 | } 139 | 140 | // TestNacosResolverDifferentCluster test NewNacosResolver WithCluster option 141 | func TestNacosResolverDifferentCluster(t *testing.T) { 142 | ctx := context.Background() 143 | n := NewNacosResolver(nacosCli) 144 | got, err := n.Resolve(ctx, svcName) 145 | assert.Nil(t, err) 146 | assert.NotNil(t, got) 147 | assert.Equal(t, svcName, got.CacheKey) 148 | if assert.NotEmpty(t, got.Instances) { 149 | gotSvc := got.Instances[0] 150 | assert.Equal(t, gotSvc.Address().String(), svcAddr.String()) 151 | } 152 | 153 | n = NewNacosResolver(nacosCli, WithCluster("OTHER")) 154 | _, err = n.Resolve(ctx, svcName) 155 | assert.NotNil(t, err) 156 | assert.Contains(t, err.Error(), "instance list is empty") 157 | } 158 | 159 | // TestNewDefaultNacosResolver test new a default nacos resolver 160 | func TestNewDefaultNacosResolver(t *testing.T) { 161 | r, err := NewDefaultNacosResolver() 162 | assert.Nil(t, err) 163 | assert.NotNil(t, r) 164 | } 165 | -------------------------------------------------------------------------------- /v2/Makefile: -------------------------------------------------------------------------------- 1 | NACOS_VERSION ?= 2.0.3 2 | TOOLS_SHELL="./hack/tools.sh" 3 | 4 | prepare: 5 | docker pull nacos/nacos-server:$(NACOS_VERSION) 6 | docker run --rm --name nacos-quick -e MODE=standalone -p 8848:8848 -p 9848:9848 -d nacos/nacos-server:$(NACOS_VERSION) 7 | 8 | stop: 9 | docker stop nacos-quick 10 | -------------------------------------------------------------------------------- /v2/README.md: -------------------------------------------------------------------------------- 1 | # registry-nacos (*This is a community driven project*) 2 | 3 | [中文](https://github.com/kitex-contrib/registry-nacos/blob/main/v2/README_CN.md) 4 | 5 | Nacos as service discovery. 6 | 7 | ## Compatibility 8 | 9 | - This Package use Nacos2.x client. 10 | 11 | - Nacos2.x detail [see](https://nacos.io/en-us/docs/v2/upgrading/2.0.0-compatibility.html) 12 | 13 | - Supported Go version over 1.16 14 | 15 | - Supported Nacos version over 2.x 16 | 17 | ### More Info 18 | 19 | Refer to [example](example) for more usage. 20 | -------------------------------------------------------------------------------- /v2/README_CN.md: -------------------------------------------------------------------------------- 1 | # registry-nacos (*这是一个由社区驱动的项目*) 2 | 3 | [English](https://github.com/kitex-contrib/registry-nacos/blob/main/v2/README.md) 4 | 5 | 使用 **nacos** 作为 **Kitex** 的注册中心 6 | 7 | ## 兼容性 8 | 9 | - 使用 Nacos2.x 客户端 10 | 11 | - Nacos2.x 详细信息[see](https://nacos.io/en-us/docs/v2/upgrading/2.0.0-compatibility.html) 12 | 13 | - Go 版本不低于 1.16 14 | 15 | - 支持Nacos 2.x 16 | 17 | ### 更多信息 18 | 19 | 更多示例请参考 [example](example) 20 | 21 | -------------------------------------------------------------------------------- /v2/example/basic/client/client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "log" 20 | "time" 21 | 22 | "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api" 23 | "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api/hello" 24 | 25 | "github.com/cloudwego/kitex/client" 26 | "github.com/kitex-contrib/registry-nacos/v2/resolver" 27 | ) 28 | 29 | func main() { 30 | r, err := resolver.NewDefaultNacosResolver() 31 | if err != nil { 32 | panic(err) 33 | } 34 | newClient := hello.MustNewClient( 35 | "Hello", 36 | client.WithResolver(r), 37 | client.WithRPCTimeout(time.Second*3), 38 | ) 39 | for { 40 | resp, err := newClient.Echo(context.Background(), &api.Request{Message: "Hello"}) 41 | if err != nil { 42 | log.Fatal(err) 43 | } 44 | log.Println(resp) 45 | time.Sleep(time.Second) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /v2/example/basic/server/server.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "log" 20 | "net" 21 | 22 | "github.com/cloudwego/kitex/pkg/rpcinfo" 23 | "github.com/cloudwego/kitex/server" 24 | "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api" 25 | "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api/hello" 26 | "github.com/kitex-contrib/registry-nacos/v2/registry" 27 | ) 28 | 29 | type HelloImpl struct{} 30 | 31 | func (h *HelloImpl) Echo(_ context.Context, req *api.Request) (resp *api.Response, err error) { 32 | resp = &api.Response{ 33 | Message: req.Message, 34 | } 35 | return 36 | } 37 | 38 | func main() { 39 | r, err := registry.NewDefaultNacosRegistry() 40 | if err != nil { 41 | panic(err) 42 | } 43 | svr := hello.NewServer( 44 | new(HelloImpl), 45 | server.WithRegistry(r), 46 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "Hello"}), 47 | server.WithServiceAddr(&net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8080}), 48 | ) 49 | if err := svr.Run(); err != nil { 50 | log.Println("server stopped with error:", err) 51 | } else { 52 | log.Println("server stopped") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /v2/example/custom-config/client/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "log" 20 | "time" 21 | 22 | "github.com/cloudwego/kitex/client" 23 | "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api" 24 | "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api/hello" 25 | "github.com/kitex-contrib/registry-nacos/v2/resolver" 26 | "github.com/nacos-group/nacos-sdk-go/v2/clients" 27 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 28 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 29 | ) 30 | 31 | func main() { 32 | // the nacos server config 33 | sc := []constant.ServerConfig{ 34 | *constant.NewServerConfig("127.0.0.1", 8848, 35 | func(sc *constant.ServerConfig) { 36 | // it is not recommended to modify GRPC-Port unless necessary,default by server port +1000 37 | sc.GrpcPort = 9848 38 | }), 39 | } 40 | 41 | // the nacos client config 42 | cc := constant.ClientConfig{ 43 | NamespaceId: "public", 44 | TimeoutMs: 5000, 45 | NotLoadCacheAtStart: true, 46 | LogDir: "/tmp/nacos/log", 47 | CacheDir: "/tmp/nacos/cache", 48 | LogLevel: "info", 49 | // more ... 50 | } 51 | 52 | cli, err := clients.NewNamingClient( 53 | vo.NacosClientParam{ 54 | ClientConfig: &cc, 55 | ServerConfigs: sc, 56 | }, 57 | ) 58 | if err != nil { 59 | panic(err) 60 | } 61 | newClient := hello.MustNewClient( 62 | "Hello", 63 | client.WithResolver(resolver.NewNacosResolver(cli)), 64 | client.WithRPCTimeout(time.Second*3), 65 | ) 66 | for { 67 | resp, err := newClient.Echo(context.Background(), &api.Request{Message: "Hello"}) 68 | if err != nil { 69 | log.Fatal(err) 70 | } 71 | log.Println(resp) 72 | time.Sleep(time.Second) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /v2/example/custom-config/server/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "context" 19 | "log" 20 | 21 | "github.com/cloudwego/kitex/pkg/rpcinfo" 22 | "github.com/cloudwego/kitex/server" 23 | "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api" 24 | "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api/hello" 25 | "github.com/kitex-contrib/registry-nacos/v2/registry" 26 | "github.com/nacos-group/nacos-sdk-go/v2/clients" 27 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 28 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 29 | ) 30 | 31 | type HelloImpl struct{} 32 | 33 | func (h *HelloImpl) Echo(_ context.Context, req *api.Request) (resp *api.Response, err error) { 34 | resp = &api.Response{ 35 | Message: req.Message, 36 | } 37 | return 38 | } 39 | 40 | func main() { 41 | // the nacos server config 42 | sc := []constant.ServerConfig{ 43 | *constant.NewServerConfig("127.0.0.1", 8848, 44 | func(sc *constant.ServerConfig) { 45 | // it is not recommended to modify GRPC-Port unless necessary,default by server port +1000 46 | sc.GrpcPort = 9848 47 | }), 48 | } 49 | 50 | // the nacos client config 51 | cc := constant.ClientConfig{ 52 | NamespaceId: "public", 53 | TimeoutMs: 5000, 54 | NotLoadCacheAtStart: true, 55 | LogDir: "/tmp/nacos/log", 56 | CacheDir: "/tmp/nacos/cache", 57 | LogLevel: "info", 58 | // more ... 59 | } 60 | 61 | cli, err := clients.NewNamingClient( 62 | vo.NacosClientParam{ 63 | ClientConfig: &cc, 64 | ServerConfigs: sc, 65 | }, 66 | ) 67 | if err != nil { 68 | panic(err) 69 | } 70 | 71 | svr := hello.NewServer( 72 | new(HelloImpl), 73 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "Hello"}), 74 | server.WithRegistry(registry.NewNacosRegistry(cli)), 75 | ) 76 | if err := svr.Run(); err != nil { 77 | log.Println("server stopped with error:", err) 78 | } else { 79 | log.Println("server stopped") 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /v2/example/hello/hello.thrift: -------------------------------------------------------------------------------- 1 | // Copyright 2021 CloudWeGo Authors 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | 16 | namespace go api 17 | 18 | struct Request { 19 | 1: string message 20 | } 21 | 22 | struct Response { 23 | 1: string message 24 | } 25 | 26 | service Hello { 27 | Response echo(1: Request req) 28 | } 29 | -------------------------------------------------------------------------------- /v2/example/hello/kitex_gen/api/hello.go: -------------------------------------------------------------------------------- 1 | // Code generated by thriftgo (0.2.8). DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "strings" 9 | 10 | "github.com/apache/thrift/lib/go/thrift" 11 | ) 12 | 13 | type Request struct { 14 | Message string `thrift:"message,1" frugal:"1,default,string" json:"message"` 15 | } 16 | 17 | func NewRequest() *Request { 18 | return &Request{} 19 | } 20 | 21 | func (p *Request) InitDefault() { 22 | *p = Request{} 23 | } 24 | 25 | func (p *Request) GetMessage() (v string) { 26 | return p.Message 27 | } 28 | func (p *Request) SetMessage(val string) { 29 | p.Message = val 30 | } 31 | 32 | var fieldIDToName_Request = map[int16]string{ 33 | 1: "message", 34 | } 35 | 36 | func (p *Request) Read(iprot thrift.TProtocol) (err error) { 37 | 38 | var fieldTypeId thrift.TType 39 | var fieldId int16 40 | 41 | if _, err = iprot.ReadStructBegin(); err != nil { 42 | goto ReadStructBeginError 43 | } 44 | 45 | for { 46 | _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() 47 | if err != nil { 48 | goto ReadFieldBeginError 49 | } 50 | if fieldTypeId == thrift.STOP { 51 | break 52 | } 53 | 54 | switch fieldId { 55 | case 1: 56 | if fieldTypeId == thrift.STRING { 57 | if err = p.ReadField1(iprot); err != nil { 58 | goto ReadFieldError 59 | } 60 | } else { 61 | if err = iprot.Skip(fieldTypeId); err != nil { 62 | goto SkipFieldError 63 | } 64 | } 65 | default: 66 | if err = iprot.Skip(fieldTypeId); err != nil { 67 | goto SkipFieldError 68 | } 69 | } 70 | 71 | if err = iprot.ReadFieldEnd(); err != nil { 72 | goto ReadFieldEndError 73 | } 74 | } 75 | if err = iprot.ReadStructEnd(); err != nil { 76 | goto ReadStructEndError 77 | } 78 | 79 | return nil 80 | ReadStructBeginError: 81 | return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 82 | ReadFieldBeginError: 83 | return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 84 | ReadFieldError: 85 | return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_Request[fieldId]), err) 86 | SkipFieldError: 87 | return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 88 | 89 | ReadFieldEndError: 90 | return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 91 | ReadStructEndError: 92 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 93 | } 94 | 95 | func (p *Request) ReadField1(iprot thrift.TProtocol) error { 96 | if v, err := iprot.ReadString(); err != nil { 97 | return err 98 | } else { 99 | p.Message = v 100 | } 101 | return nil 102 | } 103 | 104 | func (p *Request) Write(oprot thrift.TProtocol) (err error) { 105 | var fieldId int16 106 | if err = oprot.WriteStructBegin("Request"); err != nil { 107 | goto WriteStructBeginError 108 | } 109 | if p != nil { 110 | if err = p.writeField1(oprot); err != nil { 111 | fieldId = 1 112 | goto WriteFieldError 113 | } 114 | 115 | } 116 | if err = oprot.WriteFieldStop(); err != nil { 117 | goto WriteFieldStopError 118 | } 119 | if err = oprot.WriteStructEnd(); err != nil { 120 | goto WriteStructEndError 121 | } 122 | return nil 123 | WriteStructBeginError: 124 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) 125 | WriteFieldError: 126 | return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) 127 | WriteFieldStopError: 128 | return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) 129 | WriteStructEndError: 130 | return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) 131 | } 132 | 133 | func (p *Request) writeField1(oprot thrift.TProtocol) (err error) { 134 | if err = oprot.WriteFieldBegin("message", thrift.STRING, 1); err != nil { 135 | goto WriteFieldBeginError 136 | } 137 | if err := oprot.WriteString(p.Message); err != nil { 138 | return err 139 | } 140 | if err = oprot.WriteFieldEnd(); err != nil { 141 | goto WriteFieldEndError 142 | } 143 | return nil 144 | WriteFieldBeginError: 145 | return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) 146 | WriteFieldEndError: 147 | return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) 148 | } 149 | 150 | func (p *Request) String() string { 151 | if p == nil { 152 | return "" 153 | } 154 | return fmt.Sprintf("Request(%+v)", *p) 155 | } 156 | 157 | func (p *Request) DeepEqual(ano *Request) bool { 158 | if p == ano { 159 | return true 160 | } else if p == nil || ano == nil { 161 | return false 162 | } 163 | if !p.Field1DeepEqual(ano.Message) { 164 | return false 165 | } 166 | return true 167 | } 168 | 169 | func (p *Request) Field1DeepEqual(src string) bool { 170 | 171 | if strings.Compare(p.Message, src) != 0 { 172 | return false 173 | } 174 | return true 175 | } 176 | 177 | type Response struct { 178 | Message string `thrift:"message,1" frugal:"1,default,string" json:"message"` 179 | } 180 | 181 | func NewResponse() *Response { 182 | return &Response{} 183 | } 184 | 185 | func (p *Response) InitDefault() { 186 | *p = Response{} 187 | } 188 | 189 | func (p *Response) GetMessage() (v string) { 190 | return p.Message 191 | } 192 | func (p *Response) SetMessage(val string) { 193 | p.Message = val 194 | } 195 | 196 | var fieldIDToName_Response = map[int16]string{ 197 | 1: "message", 198 | } 199 | 200 | func (p *Response) Read(iprot thrift.TProtocol) (err error) { 201 | 202 | var fieldTypeId thrift.TType 203 | var fieldId int16 204 | 205 | if _, err = iprot.ReadStructBegin(); err != nil { 206 | goto ReadStructBeginError 207 | } 208 | 209 | for { 210 | _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() 211 | if err != nil { 212 | goto ReadFieldBeginError 213 | } 214 | if fieldTypeId == thrift.STOP { 215 | break 216 | } 217 | 218 | switch fieldId { 219 | case 1: 220 | if fieldTypeId == thrift.STRING { 221 | if err = p.ReadField1(iprot); err != nil { 222 | goto ReadFieldError 223 | } 224 | } else { 225 | if err = iprot.Skip(fieldTypeId); err != nil { 226 | goto SkipFieldError 227 | } 228 | } 229 | default: 230 | if err = iprot.Skip(fieldTypeId); err != nil { 231 | goto SkipFieldError 232 | } 233 | } 234 | 235 | if err = iprot.ReadFieldEnd(); err != nil { 236 | goto ReadFieldEndError 237 | } 238 | } 239 | if err = iprot.ReadStructEnd(); err != nil { 240 | goto ReadStructEndError 241 | } 242 | 243 | return nil 244 | ReadStructBeginError: 245 | return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 246 | ReadFieldBeginError: 247 | return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 248 | ReadFieldError: 249 | return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_Response[fieldId]), err) 250 | SkipFieldError: 251 | return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 252 | 253 | ReadFieldEndError: 254 | return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 255 | ReadStructEndError: 256 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 257 | } 258 | 259 | func (p *Response) ReadField1(iprot thrift.TProtocol) error { 260 | if v, err := iprot.ReadString(); err != nil { 261 | return err 262 | } else { 263 | p.Message = v 264 | } 265 | return nil 266 | } 267 | 268 | func (p *Response) Write(oprot thrift.TProtocol) (err error) { 269 | var fieldId int16 270 | if err = oprot.WriteStructBegin("Response"); err != nil { 271 | goto WriteStructBeginError 272 | } 273 | if p != nil { 274 | if err = p.writeField1(oprot); err != nil { 275 | fieldId = 1 276 | goto WriteFieldError 277 | } 278 | 279 | } 280 | if err = oprot.WriteFieldStop(); err != nil { 281 | goto WriteFieldStopError 282 | } 283 | if err = oprot.WriteStructEnd(); err != nil { 284 | goto WriteStructEndError 285 | } 286 | return nil 287 | WriteStructBeginError: 288 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) 289 | WriteFieldError: 290 | return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) 291 | WriteFieldStopError: 292 | return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) 293 | WriteStructEndError: 294 | return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) 295 | } 296 | 297 | func (p *Response) writeField1(oprot thrift.TProtocol) (err error) { 298 | if err = oprot.WriteFieldBegin("message", thrift.STRING, 1); err != nil { 299 | goto WriteFieldBeginError 300 | } 301 | if err := oprot.WriteString(p.Message); err != nil { 302 | return err 303 | } 304 | if err = oprot.WriteFieldEnd(); err != nil { 305 | goto WriteFieldEndError 306 | } 307 | return nil 308 | WriteFieldBeginError: 309 | return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) 310 | WriteFieldEndError: 311 | return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) 312 | } 313 | 314 | func (p *Response) String() string { 315 | if p == nil { 316 | return "" 317 | } 318 | return fmt.Sprintf("Response(%+v)", *p) 319 | } 320 | 321 | func (p *Response) DeepEqual(ano *Response) bool { 322 | if p == ano { 323 | return true 324 | } else if p == nil || ano == nil { 325 | return false 326 | } 327 | if !p.Field1DeepEqual(ano.Message) { 328 | return false 329 | } 330 | return true 331 | } 332 | 333 | func (p *Response) Field1DeepEqual(src string) bool { 334 | 335 | if strings.Compare(p.Message, src) != 0 { 336 | return false 337 | } 338 | return true 339 | } 340 | 341 | type Hello interface { 342 | Echo(ctx context.Context, req *Request) (r *Response, err error) 343 | } 344 | 345 | type HelloClient struct { 346 | c thrift.TClient 347 | } 348 | 349 | func NewHelloClientFactory(t thrift.TTransport, f thrift.TProtocolFactory) *HelloClient { 350 | return &HelloClient{ 351 | c: thrift.NewTStandardClient(f.GetProtocol(t), f.GetProtocol(t)), 352 | } 353 | } 354 | 355 | func NewHelloClientProtocol(t thrift.TTransport, iprot thrift.TProtocol, oprot thrift.TProtocol) *HelloClient { 356 | return &HelloClient{ 357 | c: thrift.NewTStandardClient(iprot, oprot), 358 | } 359 | } 360 | 361 | func NewHelloClient(c thrift.TClient) *HelloClient { 362 | return &HelloClient{ 363 | c: c, 364 | } 365 | } 366 | 367 | func (p *HelloClient) Client_() thrift.TClient { 368 | return p.c 369 | } 370 | 371 | func (p *HelloClient) Echo(ctx context.Context, req *Request) (r *Response, err error) { 372 | var _args HelloEchoArgs 373 | _args.Req = req 374 | var _result HelloEchoResult 375 | if err = p.Client_().Call(ctx, "echo", &_args, &_result); err != nil { 376 | return 377 | } 378 | return _result.GetSuccess(), nil 379 | } 380 | 381 | type HelloProcessor struct { 382 | processorMap map[string]thrift.TProcessorFunction 383 | handler Hello 384 | } 385 | 386 | func (p *HelloProcessor) AddToProcessorMap(key string, processor thrift.TProcessorFunction) { 387 | p.processorMap[key] = processor 388 | } 389 | 390 | func (p *HelloProcessor) GetProcessorFunction(key string) (processor thrift.TProcessorFunction, ok bool) { 391 | processor, ok = p.processorMap[key] 392 | return processor, ok 393 | } 394 | 395 | func (p *HelloProcessor) ProcessorMap() map[string]thrift.TProcessorFunction { 396 | return p.processorMap 397 | } 398 | 399 | func NewHelloProcessor(handler Hello) *HelloProcessor { 400 | self := &HelloProcessor{handler: handler, processorMap: make(map[string]thrift.TProcessorFunction)} 401 | self.AddToProcessorMap("echo", &helloProcessorEcho{handler: handler}) 402 | return self 403 | } 404 | func (p *HelloProcessor) Process(ctx context.Context, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { 405 | name, _, seqId, err := iprot.ReadMessageBegin() 406 | if err != nil { 407 | return false, err 408 | } 409 | if processor, ok := p.GetProcessorFunction(name); ok { 410 | return processor.Process(ctx, seqId, iprot, oprot) 411 | } 412 | iprot.Skip(thrift.STRUCT) 413 | iprot.ReadMessageEnd() 414 | x := thrift.NewTApplicationException(thrift.UNKNOWN_METHOD, "Unknown function "+name) 415 | oprot.WriteMessageBegin(name, thrift.EXCEPTION, seqId) 416 | x.Write(oprot) 417 | oprot.WriteMessageEnd() 418 | oprot.Flush(ctx) 419 | return false, x 420 | } 421 | 422 | type helloProcessorEcho struct { 423 | handler Hello 424 | } 425 | 426 | func (p *helloProcessorEcho) Process(ctx context.Context, seqId int32, iprot, oprot thrift.TProtocol) (success bool, err thrift.TException) { 427 | args := HelloEchoArgs{} 428 | if err = args.Read(iprot); err != nil { 429 | iprot.ReadMessageEnd() 430 | x := thrift.NewTApplicationException(thrift.PROTOCOL_ERROR, err.Error()) 431 | oprot.WriteMessageBegin("echo", thrift.EXCEPTION, seqId) 432 | x.Write(oprot) 433 | oprot.WriteMessageEnd() 434 | oprot.Flush(ctx) 435 | return false, err 436 | } 437 | 438 | iprot.ReadMessageEnd() 439 | var err2 error 440 | result := HelloEchoResult{} 441 | var retval *Response 442 | if retval, err2 = p.handler.Echo(ctx, args.Req); err2 != nil { 443 | x := thrift.NewTApplicationException(thrift.INTERNAL_ERROR, "Internal error processing echo: "+err2.Error()) 444 | oprot.WriteMessageBegin("echo", thrift.EXCEPTION, seqId) 445 | x.Write(oprot) 446 | oprot.WriteMessageEnd() 447 | oprot.Flush(ctx) 448 | return true, err2 449 | } else { 450 | result.Success = retval 451 | } 452 | if err2 = oprot.WriteMessageBegin("echo", thrift.REPLY, seqId); err2 != nil { 453 | err = err2 454 | } 455 | if err2 = result.Write(oprot); err == nil && err2 != nil { 456 | err = err2 457 | } 458 | if err2 = oprot.WriteMessageEnd(); err == nil && err2 != nil { 459 | err = err2 460 | } 461 | if err2 = oprot.Flush(ctx); err == nil && err2 != nil { 462 | err = err2 463 | } 464 | if err != nil { 465 | return 466 | } 467 | return true, err 468 | } 469 | 470 | type HelloEchoArgs struct { 471 | Req *Request `thrift:"req,1" frugal:"1,default,Request" json:"req"` 472 | } 473 | 474 | func NewHelloEchoArgs() *HelloEchoArgs { 475 | return &HelloEchoArgs{} 476 | } 477 | 478 | func (p *HelloEchoArgs) InitDefault() { 479 | *p = HelloEchoArgs{} 480 | } 481 | 482 | var HelloEchoArgs_Req_DEFAULT *Request 483 | 484 | func (p *HelloEchoArgs) GetReq() (v *Request) { 485 | if !p.IsSetReq() { 486 | return HelloEchoArgs_Req_DEFAULT 487 | } 488 | return p.Req 489 | } 490 | func (p *HelloEchoArgs) SetReq(val *Request) { 491 | p.Req = val 492 | } 493 | 494 | var fieldIDToName_HelloEchoArgs = map[int16]string{ 495 | 1: "req", 496 | } 497 | 498 | func (p *HelloEchoArgs) IsSetReq() bool { 499 | return p.Req != nil 500 | } 501 | 502 | func (p *HelloEchoArgs) Read(iprot thrift.TProtocol) (err error) { 503 | 504 | var fieldTypeId thrift.TType 505 | var fieldId int16 506 | 507 | if _, err = iprot.ReadStructBegin(); err != nil { 508 | goto ReadStructBeginError 509 | } 510 | 511 | for { 512 | _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() 513 | if err != nil { 514 | goto ReadFieldBeginError 515 | } 516 | if fieldTypeId == thrift.STOP { 517 | break 518 | } 519 | 520 | switch fieldId { 521 | case 1: 522 | if fieldTypeId == thrift.STRUCT { 523 | if err = p.ReadField1(iprot); err != nil { 524 | goto ReadFieldError 525 | } 526 | } else { 527 | if err = iprot.Skip(fieldTypeId); err != nil { 528 | goto SkipFieldError 529 | } 530 | } 531 | default: 532 | if err = iprot.Skip(fieldTypeId); err != nil { 533 | goto SkipFieldError 534 | } 535 | } 536 | 537 | if err = iprot.ReadFieldEnd(); err != nil { 538 | goto ReadFieldEndError 539 | } 540 | } 541 | if err = iprot.ReadStructEnd(); err != nil { 542 | goto ReadStructEndError 543 | } 544 | 545 | return nil 546 | ReadStructBeginError: 547 | return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 548 | ReadFieldBeginError: 549 | return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 550 | ReadFieldError: 551 | return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_HelloEchoArgs[fieldId]), err) 552 | SkipFieldError: 553 | return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 554 | 555 | ReadFieldEndError: 556 | return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 557 | ReadStructEndError: 558 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 559 | } 560 | 561 | func (p *HelloEchoArgs) ReadField1(iprot thrift.TProtocol) error { 562 | p.Req = NewRequest() 563 | if err := p.Req.Read(iprot); err != nil { 564 | return err 565 | } 566 | return nil 567 | } 568 | 569 | func (p *HelloEchoArgs) Write(oprot thrift.TProtocol) (err error) { 570 | var fieldId int16 571 | if err = oprot.WriteStructBegin("echo_args"); err != nil { 572 | goto WriteStructBeginError 573 | } 574 | if p != nil { 575 | if err = p.writeField1(oprot); err != nil { 576 | fieldId = 1 577 | goto WriteFieldError 578 | } 579 | 580 | } 581 | if err = oprot.WriteFieldStop(); err != nil { 582 | goto WriteFieldStopError 583 | } 584 | if err = oprot.WriteStructEnd(); err != nil { 585 | goto WriteStructEndError 586 | } 587 | return nil 588 | WriteStructBeginError: 589 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) 590 | WriteFieldError: 591 | return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) 592 | WriteFieldStopError: 593 | return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) 594 | WriteStructEndError: 595 | return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) 596 | } 597 | 598 | func (p *HelloEchoArgs) writeField1(oprot thrift.TProtocol) (err error) { 599 | if err = oprot.WriteFieldBegin("req", thrift.STRUCT, 1); err != nil { 600 | goto WriteFieldBeginError 601 | } 602 | if err := p.Req.Write(oprot); err != nil { 603 | return err 604 | } 605 | if err = oprot.WriteFieldEnd(); err != nil { 606 | goto WriteFieldEndError 607 | } 608 | return nil 609 | WriteFieldBeginError: 610 | return thrift.PrependError(fmt.Sprintf("%T write field 1 begin error: ", p), err) 611 | WriteFieldEndError: 612 | return thrift.PrependError(fmt.Sprintf("%T write field 1 end error: ", p), err) 613 | } 614 | 615 | func (p *HelloEchoArgs) String() string { 616 | if p == nil { 617 | return "" 618 | } 619 | return fmt.Sprintf("HelloEchoArgs(%+v)", *p) 620 | } 621 | 622 | func (p *HelloEchoArgs) DeepEqual(ano *HelloEchoArgs) bool { 623 | if p == ano { 624 | return true 625 | } else if p == nil || ano == nil { 626 | return false 627 | } 628 | if !p.Field1DeepEqual(ano.Req) { 629 | return false 630 | } 631 | return true 632 | } 633 | 634 | func (p *HelloEchoArgs) Field1DeepEqual(src *Request) bool { 635 | 636 | if !p.Req.DeepEqual(src) { 637 | return false 638 | } 639 | return true 640 | } 641 | 642 | type HelloEchoResult struct { 643 | Success *Response `thrift:"success,0,optional" frugal:"0,optional,Response" json:"success,omitempty"` 644 | } 645 | 646 | func NewHelloEchoResult() *HelloEchoResult { 647 | return &HelloEchoResult{} 648 | } 649 | 650 | func (p *HelloEchoResult) InitDefault() { 651 | *p = HelloEchoResult{} 652 | } 653 | 654 | var HelloEchoResult_Success_DEFAULT *Response 655 | 656 | func (p *HelloEchoResult) GetSuccess() (v *Response) { 657 | if !p.IsSetSuccess() { 658 | return HelloEchoResult_Success_DEFAULT 659 | } 660 | return p.Success 661 | } 662 | func (p *HelloEchoResult) SetSuccess(x interface{}) { 663 | p.Success = x.(*Response) 664 | } 665 | 666 | var fieldIDToName_HelloEchoResult = map[int16]string{ 667 | 0: "success", 668 | } 669 | 670 | func (p *HelloEchoResult) IsSetSuccess() bool { 671 | return p.Success != nil 672 | } 673 | 674 | func (p *HelloEchoResult) Read(iprot thrift.TProtocol) (err error) { 675 | 676 | var fieldTypeId thrift.TType 677 | var fieldId int16 678 | 679 | if _, err = iprot.ReadStructBegin(); err != nil { 680 | goto ReadStructBeginError 681 | } 682 | 683 | for { 684 | _, fieldTypeId, fieldId, err = iprot.ReadFieldBegin() 685 | if err != nil { 686 | goto ReadFieldBeginError 687 | } 688 | if fieldTypeId == thrift.STOP { 689 | break 690 | } 691 | 692 | switch fieldId { 693 | case 0: 694 | if fieldTypeId == thrift.STRUCT { 695 | if err = p.ReadField0(iprot); err != nil { 696 | goto ReadFieldError 697 | } 698 | } else { 699 | if err = iprot.Skip(fieldTypeId); err != nil { 700 | goto SkipFieldError 701 | } 702 | } 703 | default: 704 | if err = iprot.Skip(fieldTypeId); err != nil { 705 | goto SkipFieldError 706 | } 707 | } 708 | 709 | if err = iprot.ReadFieldEnd(); err != nil { 710 | goto ReadFieldEndError 711 | } 712 | } 713 | if err = iprot.ReadStructEnd(); err != nil { 714 | goto ReadStructEndError 715 | } 716 | 717 | return nil 718 | ReadStructBeginError: 719 | return thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 720 | ReadFieldBeginError: 721 | return thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 722 | ReadFieldError: 723 | return thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_HelloEchoResult[fieldId]), err) 724 | SkipFieldError: 725 | return thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 726 | 727 | ReadFieldEndError: 728 | return thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 729 | ReadStructEndError: 730 | return thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 731 | } 732 | 733 | func (p *HelloEchoResult) ReadField0(iprot thrift.TProtocol) error { 734 | p.Success = NewResponse() 735 | if err := p.Success.Read(iprot); err != nil { 736 | return err 737 | } 738 | return nil 739 | } 740 | 741 | func (p *HelloEchoResult) Write(oprot thrift.TProtocol) (err error) { 742 | var fieldId int16 743 | if err = oprot.WriteStructBegin("echo_result"); err != nil { 744 | goto WriteStructBeginError 745 | } 746 | if p != nil { 747 | if err = p.writeField0(oprot); err != nil { 748 | fieldId = 0 749 | goto WriteFieldError 750 | } 751 | 752 | } 753 | if err = oprot.WriteFieldStop(); err != nil { 754 | goto WriteFieldStopError 755 | } 756 | if err = oprot.WriteStructEnd(); err != nil { 757 | goto WriteStructEndError 758 | } 759 | return nil 760 | WriteStructBeginError: 761 | return thrift.PrependError(fmt.Sprintf("%T write struct begin error: ", p), err) 762 | WriteFieldError: 763 | return thrift.PrependError(fmt.Sprintf("%T write field %d error: ", p, fieldId), err) 764 | WriteFieldStopError: 765 | return thrift.PrependError(fmt.Sprintf("%T write field stop error: ", p), err) 766 | WriteStructEndError: 767 | return thrift.PrependError(fmt.Sprintf("%T write struct end error: ", p), err) 768 | } 769 | 770 | func (p *HelloEchoResult) writeField0(oprot thrift.TProtocol) (err error) { 771 | if p.IsSetSuccess() { 772 | if err = oprot.WriteFieldBegin("success", thrift.STRUCT, 0); err != nil { 773 | goto WriteFieldBeginError 774 | } 775 | if err := p.Success.Write(oprot); err != nil { 776 | return err 777 | } 778 | if err = oprot.WriteFieldEnd(); err != nil { 779 | goto WriteFieldEndError 780 | } 781 | } 782 | return nil 783 | WriteFieldBeginError: 784 | return thrift.PrependError(fmt.Sprintf("%T write field 0 begin error: ", p), err) 785 | WriteFieldEndError: 786 | return thrift.PrependError(fmt.Sprintf("%T write field 0 end error: ", p), err) 787 | } 788 | 789 | func (p *HelloEchoResult) String() string { 790 | if p == nil { 791 | return "" 792 | } 793 | return fmt.Sprintf("HelloEchoResult(%+v)", *p) 794 | } 795 | 796 | func (p *HelloEchoResult) DeepEqual(ano *HelloEchoResult) bool { 797 | if p == ano { 798 | return true 799 | } else if p == nil || ano == nil { 800 | return false 801 | } 802 | if !p.Field0DeepEqual(ano.Success) { 803 | return false 804 | } 805 | return true 806 | } 807 | 808 | func (p *HelloEchoResult) Field0DeepEqual(src *Response) bool { 809 | 810 | if !p.Success.DeepEqual(src) { 811 | return false 812 | } 813 | return true 814 | } 815 | -------------------------------------------------------------------------------- /v2/example/hello/kitex_gen/api/hello/client.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.5.1. DO NOT EDIT. 2 | 3 | package hello 4 | 5 | import ( 6 | "context" 7 | 8 | client "github.com/cloudwego/kitex/client" 9 | callopt "github.com/cloudwego/kitex/client/callopt" 10 | api "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api" 11 | ) 12 | 13 | // Client is designed to provide IDL-compatible methods with call-option parameter for kitex framework. 14 | type Client interface { 15 | Echo(ctx context.Context, req *api.Request, callOptions ...callopt.Option) (r *api.Response, err error) 16 | } 17 | 18 | // NewClient creates a client for the service defined in IDL. 19 | func NewClient(destService string, opts ...client.Option) (Client, error) { 20 | var options []client.Option 21 | options = append(options, client.WithDestService(destService)) 22 | 23 | options = append(options, opts...) 24 | 25 | kc, err := client.NewClient(serviceInfo(), options...) 26 | if err != nil { 27 | return nil, err 28 | } 29 | return &kHelloClient{ 30 | kClient: newServiceClient(kc), 31 | }, nil 32 | } 33 | 34 | // MustNewClient creates a client for the service defined in IDL. It panics if any error occurs. 35 | func MustNewClient(destService string, opts ...client.Option) Client { 36 | kc, err := NewClient(destService, opts...) 37 | if err != nil { 38 | panic(err) 39 | } 40 | return kc 41 | } 42 | 43 | type kHelloClient struct { 44 | *kClient 45 | } 46 | 47 | func (p *kHelloClient) Echo(ctx context.Context, req *api.Request, callOptions ...callopt.Option) (r *api.Response, err error) { 48 | ctx = client.NewCtxWithCallOptions(ctx, callOptions) 49 | return p.kClient.Echo(ctx, req) 50 | } 51 | -------------------------------------------------------------------------------- /v2/example/hello/kitex_gen/api/hello/hello.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.5.1. DO NOT EDIT. 2 | 3 | package hello 4 | 5 | import ( 6 | "context" 7 | 8 | client "github.com/cloudwego/kitex/client" 9 | kitex "github.com/cloudwego/kitex/pkg/serviceinfo" 10 | api "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api" 11 | ) 12 | 13 | func serviceInfo() *kitex.ServiceInfo { 14 | return helloServiceInfo 15 | } 16 | 17 | var helloServiceInfo = NewServiceInfo() 18 | 19 | func NewServiceInfo() *kitex.ServiceInfo { 20 | serviceName := "Hello" 21 | handlerType := (*api.Hello)(nil) 22 | methods := map[string]kitex.MethodInfo{ 23 | "echo": kitex.NewMethodInfo(echoHandler, newHelloEchoArgs, newHelloEchoResult, false), 24 | } 25 | extra := map[string]interface{}{ 26 | "PackageName": "api", 27 | } 28 | svcInfo := &kitex.ServiceInfo{ 29 | ServiceName: serviceName, 30 | HandlerType: handlerType, 31 | Methods: methods, 32 | PayloadCodec: kitex.Thrift, 33 | KiteXGenVersion: "v0.5.1", 34 | Extra: extra, 35 | } 36 | return svcInfo 37 | } 38 | 39 | func echoHandler(ctx context.Context, handler interface{}, arg, result interface{}) error { 40 | realArg := arg.(*api.HelloEchoArgs) 41 | realResult := result.(*api.HelloEchoResult) 42 | success, err := handler.(api.Hello).Echo(ctx, realArg.Req) 43 | if err != nil { 44 | return err 45 | } 46 | realResult.Success = success 47 | return nil 48 | } 49 | func newHelloEchoArgs() interface{} { 50 | return api.NewHelloEchoArgs() 51 | } 52 | 53 | func newHelloEchoResult() interface{} { 54 | return api.NewHelloEchoResult() 55 | } 56 | 57 | type kClient struct { 58 | c client.Client 59 | } 60 | 61 | func newServiceClient(c client.Client) *kClient { 62 | return &kClient{ 63 | c: c, 64 | } 65 | } 66 | 67 | func (p *kClient) Echo(ctx context.Context, req *api.Request) (r *api.Response, err error) { 68 | var _args api.HelloEchoArgs 69 | _args.Req = req 70 | var _result api.HelloEchoResult 71 | if err = p.c.Call(ctx, "echo", &_args, &_result); err != nil { 72 | return 73 | } 74 | return _result.GetSuccess(), nil 75 | } 76 | -------------------------------------------------------------------------------- /v2/example/hello/kitex_gen/api/hello/invoker.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.5.1. DO NOT EDIT. 2 | 3 | package hello 4 | 5 | import ( 6 | server "github.com/cloudwego/kitex/server" 7 | api "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api" 8 | ) 9 | 10 | // NewInvoker creates a server.Invoker with the given handler and options. 11 | func NewInvoker(handler api.Hello, opts ...server.Option) server.Invoker { 12 | var options []server.Option 13 | 14 | options = append(options, opts...) 15 | 16 | s := server.NewInvoker(options...) 17 | if err := s.RegisterService(serviceInfo(), handler); err != nil { 18 | panic(err) 19 | } 20 | if err := s.Init(); err != nil { 21 | panic(err) 22 | } 23 | return s 24 | } 25 | -------------------------------------------------------------------------------- /v2/example/hello/kitex_gen/api/hello/server.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.5.1. DO NOT EDIT. 2 | package hello 3 | 4 | import ( 5 | server "github.com/cloudwego/kitex/server" 6 | api "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api" 7 | ) 8 | 9 | // NewServer creates a server.Server with the given handler and options. 10 | func NewServer(handler api.Hello, opts ...server.Option) server.Server { 11 | var options []server.Option 12 | 13 | options = append(options, opts...) 14 | 15 | svr := server.NewServer(options...) 16 | if err := svr.RegisterService(serviceInfo(), handler); err != nil { 17 | panic(err) 18 | } 19 | return svr 20 | } 21 | -------------------------------------------------------------------------------- /v2/example/hello/kitex_gen/api/k-consts.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | // KitexUnusedProtection is used to prevent 'imported and not used' error. 4 | var KitexUnusedProtection = struct{}{} 5 | -------------------------------------------------------------------------------- /v2/example/hello/kitex_gen/api/k-hello.go: -------------------------------------------------------------------------------- 1 | // Code generated by Kitex v0.5.1. DO NOT EDIT. 2 | 3 | package api 4 | 5 | import ( 6 | "bytes" 7 | "fmt" 8 | "reflect" 9 | "strings" 10 | 11 | "github.com/apache/thrift/lib/go/thrift" 12 | 13 | "github.com/cloudwego/kitex/pkg/protocol/bthrift" 14 | ) 15 | 16 | // unused protection 17 | var ( 18 | _ = fmt.Formatter(nil) 19 | _ = (*bytes.Buffer)(nil) 20 | _ = (*strings.Builder)(nil) 21 | _ = reflect.Type(nil) 22 | _ = thrift.TProtocol(nil) 23 | _ = bthrift.BinaryWriter(nil) 24 | ) 25 | 26 | func (p *Request) FastRead(buf []byte) (int, error) { 27 | var err error 28 | var offset int 29 | var l int 30 | var fieldTypeId thrift.TType 31 | var fieldId int16 32 | _, l, err = bthrift.Binary.ReadStructBegin(buf) 33 | offset += l 34 | if err != nil { 35 | goto ReadStructBeginError 36 | } 37 | 38 | for { 39 | _, fieldTypeId, fieldId, l, err = bthrift.Binary.ReadFieldBegin(buf[offset:]) 40 | offset += l 41 | if err != nil { 42 | goto ReadFieldBeginError 43 | } 44 | if fieldTypeId == thrift.STOP { 45 | break 46 | } 47 | switch fieldId { 48 | case 1: 49 | if fieldTypeId == thrift.STRING { 50 | l, err = p.FastReadField1(buf[offset:]) 51 | offset += l 52 | if err != nil { 53 | goto ReadFieldError 54 | } 55 | } else { 56 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 57 | offset += l 58 | if err != nil { 59 | goto SkipFieldError 60 | } 61 | } 62 | default: 63 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 64 | offset += l 65 | if err != nil { 66 | goto SkipFieldError 67 | } 68 | } 69 | 70 | l, err = bthrift.Binary.ReadFieldEnd(buf[offset:]) 71 | offset += l 72 | if err != nil { 73 | goto ReadFieldEndError 74 | } 75 | } 76 | l, err = bthrift.Binary.ReadStructEnd(buf[offset:]) 77 | offset += l 78 | if err != nil { 79 | goto ReadStructEndError 80 | } 81 | 82 | return offset, nil 83 | ReadStructBeginError: 84 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 85 | ReadFieldBeginError: 86 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 87 | ReadFieldError: 88 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_Request[fieldId]), err) 89 | SkipFieldError: 90 | return offset, thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 91 | ReadFieldEndError: 92 | return offset, thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 93 | ReadStructEndError: 94 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 95 | } 96 | 97 | func (p *Request) FastReadField1(buf []byte) (int, error) { 98 | offset := 0 99 | 100 | if v, l, err := bthrift.Binary.ReadString(buf[offset:]); err != nil { 101 | return offset, err 102 | } else { 103 | offset += l 104 | 105 | p.Message = v 106 | 107 | } 108 | return offset, nil 109 | } 110 | 111 | // for compatibility 112 | func (p *Request) FastWrite(buf []byte) int { 113 | return 0 114 | } 115 | 116 | func (p *Request) FastWriteNocopy(buf []byte, binaryWriter bthrift.BinaryWriter) int { 117 | offset := 0 118 | offset += bthrift.Binary.WriteStructBegin(buf[offset:], "Request") 119 | if p != nil { 120 | offset += p.fastWriteField1(buf[offset:], binaryWriter) 121 | } 122 | offset += bthrift.Binary.WriteFieldStop(buf[offset:]) 123 | offset += bthrift.Binary.WriteStructEnd(buf[offset:]) 124 | return offset 125 | } 126 | 127 | func (p *Request) BLength() int { 128 | l := 0 129 | l += bthrift.Binary.StructBeginLength("Request") 130 | if p != nil { 131 | l += p.field1Length() 132 | } 133 | l += bthrift.Binary.FieldStopLength() 134 | l += bthrift.Binary.StructEndLength() 135 | return l 136 | } 137 | 138 | func (p *Request) fastWriteField1(buf []byte, binaryWriter bthrift.BinaryWriter) int { 139 | offset := 0 140 | offset += bthrift.Binary.WriteFieldBegin(buf[offset:], "message", thrift.STRING, 1) 141 | offset += bthrift.Binary.WriteStringNocopy(buf[offset:], binaryWriter, p.Message) 142 | 143 | offset += bthrift.Binary.WriteFieldEnd(buf[offset:]) 144 | return offset 145 | } 146 | 147 | func (p *Request) field1Length() int { 148 | l := 0 149 | l += bthrift.Binary.FieldBeginLength("message", thrift.STRING, 1) 150 | l += bthrift.Binary.StringLengthNocopy(p.Message) 151 | 152 | l += bthrift.Binary.FieldEndLength() 153 | return l 154 | } 155 | 156 | func (p *Response) FastRead(buf []byte) (int, error) { 157 | var err error 158 | var offset int 159 | var l int 160 | var fieldTypeId thrift.TType 161 | var fieldId int16 162 | _, l, err = bthrift.Binary.ReadStructBegin(buf) 163 | offset += l 164 | if err != nil { 165 | goto ReadStructBeginError 166 | } 167 | 168 | for { 169 | _, fieldTypeId, fieldId, l, err = bthrift.Binary.ReadFieldBegin(buf[offset:]) 170 | offset += l 171 | if err != nil { 172 | goto ReadFieldBeginError 173 | } 174 | if fieldTypeId == thrift.STOP { 175 | break 176 | } 177 | switch fieldId { 178 | case 1: 179 | if fieldTypeId == thrift.STRING { 180 | l, err = p.FastReadField1(buf[offset:]) 181 | offset += l 182 | if err != nil { 183 | goto ReadFieldError 184 | } 185 | } else { 186 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 187 | offset += l 188 | if err != nil { 189 | goto SkipFieldError 190 | } 191 | } 192 | default: 193 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 194 | offset += l 195 | if err != nil { 196 | goto SkipFieldError 197 | } 198 | } 199 | 200 | l, err = bthrift.Binary.ReadFieldEnd(buf[offset:]) 201 | offset += l 202 | if err != nil { 203 | goto ReadFieldEndError 204 | } 205 | } 206 | l, err = bthrift.Binary.ReadStructEnd(buf[offset:]) 207 | offset += l 208 | if err != nil { 209 | goto ReadStructEndError 210 | } 211 | 212 | return offset, nil 213 | ReadStructBeginError: 214 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 215 | ReadFieldBeginError: 216 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 217 | ReadFieldError: 218 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_Response[fieldId]), err) 219 | SkipFieldError: 220 | return offset, thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 221 | ReadFieldEndError: 222 | return offset, thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 223 | ReadStructEndError: 224 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 225 | } 226 | 227 | func (p *Response) FastReadField1(buf []byte) (int, error) { 228 | offset := 0 229 | 230 | if v, l, err := bthrift.Binary.ReadString(buf[offset:]); err != nil { 231 | return offset, err 232 | } else { 233 | offset += l 234 | 235 | p.Message = v 236 | 237 | } 238 | return offset, nil 239 | } 240 | 241 | // for compatibility 242 | func (p *Response) FastWrite(buf []byte) int { 243 | return 0 244 | } 245 | 246 | func (p *Response) FastWriteNocopy(buf []byte, binaryWriter bthrift.BinaryWriter) int { 247 | offset := 0 248 | offset += bthrift.Binary.WriteStructBegin(buf[offset:], "Response") 249 | if p != nil { 250 | offset += p.fastWriteField1(buf[offset:], binaryWriter) 251 | } 252 | offset += bthrift.Binary.WriteFieldStop(buf[offset:]) 253 | offset += bthrift.Binary.WriteStructEnd(buf[offset:]) 254 | return offset 255 | } 256 | 257 | func (p *Response) BLength() int { 258 | l := 0 259 | l += bthrift.Binary.StructBeginLength("Response") 260 | if p != nil { 261 | l += p.field1Length() 262 | } 263 | l += bthrift.Binary.FieldStopLength() 264 | l += bthrift.Binary.StructEndLength() 265 | return l 266 | } 267 | 268 | func (p *Response) fastWriteField1(buf []byte, binaryWriter bthrift.BinaryWriter) int { 269 | offset := 0 270 | offset += bthrift.Binary.WriteFieldBegin(buf[offset:], "message", thrift.STRING, 1) 271 | offset += bthrift.Binary.WriteStringNocopy(buf[offset:], binaryWriter, p.Message) 272 | 273 | offset += bthrift.Binary.WriteFieldEnd(buf[offset:]) 274 | return offset 275 | } 276 | 277 | func (p *Response) field1Length() int { 278 | l := 0 279 | l += bthrift.Binary.FieldBeginLength("message", thrift.STRING, 1) 280 | l += bthrift.Binary.StringLengthNocopy(p.Message) 281 | 282 | l += bthrift.Binary.FieldEndLength() 283 | return l 284 | } 285 | 286 | func (p *HelloEchoArgs) FastRead(buf []byte) (int, error) { 287 | var err error 288 | var offset int 289 | var l int 290 | var fieldTypeId thrift.TType 291 | var fieldId int16 292 | _, l, err = bthrift.Binary.ReadStructBegin(buf) 293 | offset += l 294 | if err != nil { 295 | goto ReadStructBeginError 296 | } 297 | 298 | for { 299 | _, fieldTypeId, fieldId, l, err = bthrift.Binary.ReadFieldBegin(buf[offset:]) 300 | offset += l 301 | if err != nil { 302 | goto ReadFieldBeginError 303 | } 304 | if fieldTypeId == thrift.STOP { 305 | break 306 | } 307 | switch fieldId { 308 | case 1: 309 | if fieldTypeId == thrift.STRUCT { 310 | l, err = p.FastReadField1(buf[offset:]) 311 | offset += l 312 | if err != nil { 313 | goto ReadFieldError 314 | } 315 | } else { 316 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 317 | offset += l 318 | if err != nil { 319 | goto SkipFieldError 320 | } 321 | } 322 | default: 323 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 324 | offset += l 325 | if err != nil { 326 | goto SkipFieldError 327 | } 328 | } 329 | 330 | l, err = bthrift.Binary.ReadFieldEnd(buf[offset:]) 331 | offset += l 332 | if err != nil { 333 | goto ReadFieldEndError 334 | } 335 | } 336 | l, err = bthrift.Binary.ReadStructEnd(buf[offset:]) 337 | offset += l 338 | if err != nil { 339 | goto ReadStructEndError 340 | } 341 | 342 | return offset, nil 343 | ReadStructBeginError: 344 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 345 | ReadFieldBeginError: 346 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 347 | ReadFieldError: 348 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_HelloEchoArgs[fieldId]), err) 349 | SkipFieldError: 350 | return offset, thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 351 | ReadFieldEndError: 352 | return offset, thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 353 | ReadStructEndError: 354 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 355 | } 356 | 357 | func (p *HelloEchoArgs) FastReadField1(buf []byte) (int, error) { 358 | offset := 0 359 | 360 | tmp := NewRequest() 361 | if l, err := tmp.FastRead(buf[offset:]); err != nil { 362 | return offset, err 363 | } else { 364 | offset += l 365 | } 366 | p.Req = tmp 367 | return offset, nil 368 | } 369 | 370 | // for compatibility 371 | func (p *HelloEchoArgs) FastWrite(buf []byte) int { 372 | return 0 373 | } 374 | 375 | func (p *HelloEchoArgs) FastWriteNocopy(buf []byte, binaryWriter bthrift.BinaryWriter) int { 376 | offset := 0 377 | offset += bthrift.Binary.WriteStructBegin(buf[offset:], "echo_args") 378 | if p != nil { 379 | offset += p.fastWriteField1(buf[offset:], binaryWriter) 380 | } 381 | offset += bthrift.Binary.WriteFieldStop(buf[offset:]) 382 | offset += bthrift.Binary.WriteStructEnd(buf[offset:]) 383 | return offset 384 | } 385 | 386 | func (p *HelloEchoArgs) BLength() int { 387 | l := 0 388 | l += bthrift.Binary.StructBeginLength("echo_args") 389 | if p != nil { 390 | l += p.field1Length() 391 | } 392 | l += bthrift.Binary.FieldStopLength() 393 | l += bthrift.Binary.StructEndLength() 394 | return l 395 | } 396 | 397 | func (p *HelloEchoArgs) fastWriteField1(buf []byte, binaryWriter bthrift.BinaryWriter) int { 398 | offset := 0 399 | offset += bthrift.Binary.WriteFieldBegin(buf[offset:], "req", thrift.STRUCT, 1) 400 | offset += p.Req.FastWriteNocopy(buf[offset:], binaryWriter) 401 | offset += bthrift.Binary.WriteFieldEnd(buf[offset:]) 402 | return offset 403 | } 404 | 405 | func (p *HelloEchoArgs) field1Length() int { 406 | l := 0 407 | l += bthrift.Binary.FieldBeginLength("req", thrift.STRUCT, 1) 408 | l += p.Req.BLength() 409 | l += bthrift.Binary.FieldEndLength() 410 | return l 411 | } 412 | 413 | func (p *HelloEchoResult) FastRead(buf []byte) (int, error) { 414 | var err error 415 | var offset int 416 | var l int 417 | var fieldTypeId thrift.TType 418 | var fieldId int16 419 | _, l, err = bthrift.Binary.ReadStructBegin(buf) 420 | offset += l 421 | if err != nil { 422 | goto ReadStructBeginError 423 | } 424 | 425 | for { 426 | _, fieldTypeId, fieldId, l, err = bthrift.Binary.ReadFieldBegin(buf[offset:]) 427 | offset += l 428 | if err != nil { 429 | goto ReadFieldBeginError 430 | } 431 | if fieldTypeId == thrift.STOP { 432 | break 433 | } 434 | switch fieldId { 435 | case 0: 436 | if fieldTypeId == thrift.STRUCT { 437 | l, err = p.FastReadField0(buf[offset:]) 438 | offset += l 439 | if err != nil { 440 | goto ReadFieldError 441 | } 442 | } else { 443 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 444 | offset += l 445 | if err != nil { 446 | goto SkipFieldError 447 | } 448 | } 449 | default: 450 | l, err = bthrift.Binary.Skip(buf[offset:], fieldTypeId) 451 | offset += l 452 | if err != nil { 453 | goto SkipFieldError 454 | } 455 | } 456 | 457 | l, err = bthrift.Binary.ReadFieldEnd(buf[offset:]) 458 | offset += l 459 | if err != nil { 460 | goto ReadFieldEndError 461 | } 462 | } 463 | l, err = bthrift.Binary.ReadStructEnd(buf[offset:]) 464 | offset += l 465 | if err != nil { 466 | goto ReadStructEndError 467 | } 468 | 469 | return offset, nil 470 | ReadStructBeginError: 471 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct begin error: ", p), err) 472 | ReadFieldBeginError: 473 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d begin error: ", p, fieldId), err) 474 | ReadFieldError: 475 | return offset, thrift.PrependError(fmt.Sprintf("%T read field %d '%s' error: ", p, fieldId, fieldIDToName_HelloEchoResult[fieldId]), err) 476 | SkipFieldError: 477 | return offset, thrift.PrependError(fmt.Sprintf("%T field %d skip type %d error: ", p, fieldId, fieldTypeId), err) 478 | ReadFieldEndError: 479 | return offset, thrift.PrependError(fmt.Sprintf("%T read field end error", p), err) 480 | ReadStructEndError: 481 | return offset, thrift.PrependError(fmt.Sprintf("%T read struct end error: ", p), err) 482 | } 483 | 484 | func (p *HelloEchoResult) FastReadField0(buf []byte) (int, error) { 485 | offset := 0 486 | 487 | tmp := NewResponse() 488 | if l, err := tmp.FastRead(buf[offset:]); err != nil { 489 | return offset, err 490 | } else { 491 | offset += l 492 | } 493 | p.Success = tmp 494 | return offset, nil 495 | } 496 | 497 | // for compatibility 498 | func (p *HelloEchoResult) FastWrite(buf []byte) int { 499 | return 0 500 | } 501 | 502 | func (p *HelloEchoResult) FastWriteNocopy(buf []byte, binaryWriter bthrift.BinaryWriter) int { 503 | offset := 0 504 | offset += bthrift.Binary.WriteStructBegin(buf[offset:], "echo_result") 505 | if p != nil { 506 | offset += p.fastWriteField0(buf[offset:], binaryWriter) 507 | } 508 | offset += bthrift.Binary.WriteFieldStop(buf[offset:]) 509 | offset += bthrift.Binary.WriteStructEnd(buf[offset:]) 510 | return offset 511 | } 512 | 513 | func (p *HelloEchoResult) BLength() int { 514 | l := 0 515 | l += bthrift.Binary.StructBeginLength("echo_result") 516 | if p != nil { 517 | l += p.field0Length() 518 | } 519 | l += bthrift.Binary.FieldStopLength() 520 | l += bthrift.Binary.StructEndLength() 521 | return l 522 | } 523 | 524 | func (p *HelloEchoResult) fastWriteField0(buf []byte, binaryWriter bthrift.BinaryWriter) int { 525 | offset := 0 526 | if p.IsSetSuccess() { 527 | offset += bthrift.Binary.WriteFieldBegin(buf[offset:], "success", thrift.STRUCT, 0) 528 | offset += p.Success.FastWriteNocopy(buf[offset:], binaryWriter) 529 | offset += bthrift.Binary.WriteFieldEnd(buf[offset:]) 530 | } 531 | return offset 532 | } 533 | 534 | func (p *HelloEchoResult) field0Length() int { 535 | l := 0 536 | if p.IsSetSuccess() { 537 | l += bthrift.Binary.FieldBeginLength("success", thrift.STRUCT, 0) 538 | l += p.Success.BLength() 539 | l += bthrift.Binary.FieldEndLength() 540 | } 541 | return l 542 | } 543 | 544 | func (p *HelloEchoArgs) GetFirstArgument() interface{} { 545 | return p.Req 546 | } 547 | 548 | func (p *HelloEchoResult) GetResult() interface{} { 549 | return p.Success 550 | } 551 | -------------------------------------------------------------------------------- /v2/example/hello/kitex_info.yaml: -------------------------------------------------------------------------------- 1 | kitexinfo: 2 | ServiceName: 'hello' 3 | ToolVersion: 'v0.5.1' 4 | -------------------------------------------------------------------------------- /v2/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kitex-contrib/registry-nacos/v2 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/apache/thrift v0.16.0 7 | github.com/cloudwego/kitex v0.11.3 8 | github.com/nacos-group/nacos-sdk-go/v2 v2.2.7 9 | github.com/stretchr/testify v1.9.0 10 | ) 11 | 12 | require ( 13 | github.com/alibabacloud-go/debug v1.0.0 // indirect 14 | github.com/alibabacloud-go/tea v1.1.17 // indirect 15 | github.com/alibabacloud-go/tea-utils v1.4.4 // indirect 16 | github.com/aliyun/alibaba-cloud-sdk-go v1.61.1800 // indirect 17 | github.com/aliyun/alibabacloud-dkms-gcs-go-sdk v0.2.2 // indirect 18 | github.com/aliyun/alibabacloud-dkms-transfer-go-sdk v0.1.7 // indirect 19 | github.com/beorn7/perks v1.0.1 // indirect 20 | github.com/buger/jsonparser v1.1.1 // indirect 21 | github.com/bytedance/gopkg v0.1.1 // indirect 22 | github.com/bytedance/sonic v1.12.5 // indirect 23 | github.com/bytedance/sonic/loader v0.2.0 // indirect 24 | github.com/cespare/xxhash/v2 v2.2.0 // indirect 25 | github.com/cloudwego/base64x v0.1.4 // indirect 26 | github.com/cloudwego/configmanager v0.2.2 // indirect 27 | github.com/cloudwego/dynamicgo v0.4.0 // indirect 28 | github.com/cloudwego/fastpb v0.0.5 // indirect 29 | github.com/cloudwego/frugal v0.2.0 // indirect 30 | github.com/cloudwego/gopkg v0.1.2 // indirect 31 | github.com/cloudwego/iasm v0.2.0 // indirect 32 | github.com/cloudwego/localsession v0.0.2 // indirect 33 | github.com/cloudwego/netpoll v0.6.4 // indirect 34 | github.com/cloudwego/runtimex v0.1.0 // indirect 35 | github.com/cloudwego/thriftgo v0.3.17 // indirect 36 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 37 | github.com/fatih/structtag v1.2.0 // indirect 38 | github.com/golang/mock v1.6.0 // indirect 39 | github.com/golang/protobuf v1.5.4 // indirect 40 | github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect 41 | github.com/iancoleman/strcase v0.2.0 // indirect 42 | github.com/jhump/protoreflect v1.8.2 // indirect 43 | github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect 44 | github.com/json-iterator/go v1.1.12 // indirect 45 | github.com/klauspost/cpuid/v2 v2.2.4 // indirect 46 | github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect 47 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 48 | github.com/modern-go/gls v0.0.0-20220109145502-612d0167dce5 // indirect 49 | github.com/modern-go/reflect2 v1.0.2 // indirect 50 | github.com/pkg/errors v0.9.1 // indirect 51 | github.com/pmezard/go-difflib v1.0.0 // indirect 52 | github.com/prometheus/client_golang v1.12.2 // indirect 53 | github.com/prometheus/client_model v0.2.0 // indirect 54 | github.com/prometheus/common v0.32.1 // indirect 55 | github.com/prometheus/procfs v0.7.3 // indirect 56 | github.com/tidwall/gjson v1.17.3 // indirect 57 | github.com/tidwall/match v1.1.1 // indirect 58 | github.com/tidwall/pretty v1.2.0 // indirect 59 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 60 | go.uber.org/atomic v1.7.0 // indirect 61 | go.uber.org/multierr v1.6.0 // indirect 62 | go.uber.org/zap v1.21.0 // indirect 63 | golang.org/x/arch v0.2.0 // indirect 64 | golang.org/x/crypto v0.22.0 // indirect 65 | golang.org/x/net v0.24.0 // indirect 66 | golang.org/x/sync v0.8.0 // indirect 67 | golang.org/x/sys v0.19.0 // indirect 68 | golang.org/x/text v0.14.0 // indirect 69 | golang.org/x/time v0.1.0 // indirect 70 | google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect 71 | google.golang.org/grpc v1.56.3 // indirect 72 | google.golang.org/protobuf v1.33.0 // indirect 73 | gopkg.in/ini.v1 v1.66.2 // indirect 74 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect 75 | gopkg.in/yaml.v3 v3.0.1 // indirect 76 | ) 77 | 78 | replace github.com/apache/thrift => github.com/apache/thrift v0.13.0 79 | -------------------------------------------------------------------------------- /v2/nacos/client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package nacos 16 | 17 | import ( 18 | "github.com/nacos-group/nacos-sdk-go/v2/clients" 19 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client" 20 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 21 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 22 | ) 23 | 24 | // Option is the way to config a client. 25 | type Option struct { 26 | F func(o *vo.NacosClientParam) 27 | } 28 | 29 | // NewDefaultNacosClient Create a default Nacos client 30 | // It can create a client with default config by env variable. 31 | // See: env.go 32 | func NewDefaultNacosClient(opts ...Option) (naming_client.INamingClient, error) { 33 | sc := []constant.ServerConfig{ 34 | *constant.NewServerConfig(NacosAddr(), uint64(NacosPort())), 35 | } 36 | cc := constant.ClientConfig{ 37 | NamespaceId: NacosNameSpaceId(), 38 | RegionId: NACOS_DEFAULT_REGIONID, 39 | NotLoadCacheAtStart: true, 40 | } 41 | param := vo.NacosClientParam{ 42 | ClientConfig: &cc, 43 | ServerConfigs: sc, 44 | } 45 | for _, opt := range opts { 46 | opt.F(¶m) 47 | } 48 | cli, err := clients.NewNamingClient(param) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return cli, nil 53 | } 54 | -------------------------------------------------------------------------------- /v2/nacos/env.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package nacos 16 | 17 | import ( 18 | "os" 19 | "strconv" 20 | "strings" 21 | 22 | "github.com/cloudwego/kitex/pkg/klog" 23 | ) 24 | 25 | const ( 26 | NACOS_ENV_SERVER_ADDR = "serverAddr" 27 | NACOS_ENV_PORT = "serverPort" 28 | NACOS_ENV_TAGS = "KITEX_NACOS_ENV_TAGS" 29 | NACOS_ENV_NAMESPACE_ID = "namespace" 30 | NACOS_DEFAULT_SERVER_ADDR = "127.0.0.1" 31 | NACOS_DEFAULT_PORT = 8848 32 | NACOS_DEFAULT_REGIONID = "cn-hangzhou" 33 | ) 34 | 35 | // Tags providers the default tags to inject nacos. 36 | var Tags map[string]string 37 | 38 | func init() { 39 | Tags = parseTags(os.Getenv(NACOS_ENV_TAGS)) 40 | } 41 | 42 | func parseTags(tags string) map[string]string { 43 | if len(tags) == 0 { 44 | return nil 45 | } 46 | out := map[string]string{} 47 | parts := strings.Split(tags, ",") 48 | for _, part := range parts { 49 | tag := strings.Split(part, "=") 50 | if len(tag) == 2 { 51 | out[tag[0]] = tag[1] 52 | } 53 | } 54 | return out 55 | } 56 | 57 | // NacosPort Get Nacos port from environment variables 58 | func NacosPort() int64 { 59 | portText := os.Getenv(NACOS_ENV_PORT) 60 | if len(portText) == 0 { 61 | return NACOS_DEFAULT_PORT 62 | } 63 | port, err := strconv.ParseInt(portText, 10, 64) 64 | if err != nil { 65 | klog.Errorf("ParseInt failed,err:%s", err.Error()) 66 | return NACOS_DEFAULT_PORT 67 | } 68 | return port 69 | } 70 | 71 | // NacosAddr Get Nacos addr from environment variables 72 | func NacosAddr() string { 73 | addr := os.Getenv(NACOS_ENV_SERVER_ADDR) 74 | if len(addr) == 0 { 75 | return NACOS_DEFAULT_SERVER_ADDR 76 | } 77 | return addr 78 | } 79 | 80 | // NacosNameSpaceId Get Nacos namespace id from environment variables 81 | func NacosNameSpaceId() string { 82 | return os.Getenv(NACOS_ENV_NAMESPACE_ID) 83 | } 84 | -------------------------------------------------------------------------------- /v2/nacos/env_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package nacos 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/stretchr/testify/assert" 21 | ) 22 | 23 | func TestParseTags(t *testing.T) { 24 | assert.Equal(t, parseTags("k1=v1,k2=v2"), map[string]string{ 25 | "k1": "v1", 26 | "k2": "v2", 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /v2/registry/registry.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package registry 16 | 17 | import ( 18 | "errors" 19 | "fmt" 20 | "net" 21 | "strconv" 22 | 23 | "github.com/cloudwego/kitex/pkg/registry" 24 | "github.com/kitex-contrib/registry-nacos/v2/nacos" 25 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client" 26 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 27 | ) 28 | 29 | type options struct { 30 | cluster string 31 | group string 32 | } 33 | 34 | // Option is nacos option. 35 | type Option func(o *options) 36 | 37 | // WithCluster with cluster option. 38 | func WithCluster(cluster string) Option { 39 | return func(o *options) { o.cluster = cluster } 40 | } 41 | 42 | // WithGroup with group option. 43 | func WithGroup(group string) Option { 44 | return func(o *options) { o.group = group } 45 | } 46 | 47 | type nacosRegistry struct { 48 | cli naming_client.INamingClient 49 | opts options 50 | } 51 | 52 | // NewDefaultNacosRegistry create a default service registry using nacos. 53 | func NewDefaultNacosRegistry(opts ...Option) (registry.Registry, error) { 54 | cli, err := nacos.NewDefaultNacosClient() 55 | if err != nil { 56 | return nil, err 57 | } 58 | return NewNacosRegistry(cli, opts...), nil 59 | } 60 | 61 | // NewNacosRegistry create a new registry using nacos. 62 | func NewNacosRegistry(cli naming_client.INamingClient, opts ...Option) registry.Registry { 63 | op := options{ 64 | cluster: "DEFAULT", 65 | group: "DEFAULT_GROUP", 66 | } 67 | for _, option := range opts { 68 | option(&op) 69 | } 70 | return &nacosRegistry{cli: cli, opts: op} 71 | } 72 | 73 | var _ registry.Registry = (*nacosRegistry)(nil) 74 | 75 | // Register service info to nacos. 76 | func (n *nacosRegistry) Register(info *registry.Info) error { 77 | if err := n.validateRegistryInfo(info); err != nil { 78 | return err 79 | } 80 | host, port, err := net.SplitHostPort(info.Addr.String()) 81 | if err != nil { 82 | return fmt.Errorf("parse registry info addr error: %w", err) 83 | } 84 | p, err := strconv.Atoi(port) 85 | if err != nil { 86 | return fmt.Errorf("parse registry info port error: %w", err) 87 | } 88 | if host == "" || host == "::" { 89 | host, err = n.getLocalIpv4Host() 90 | if err != nil { 91 | return fmt.Errorf("parse registry info addr error: %w", err) 92 | } 93 | } 94 | 95 | _, e := n.cli.RegisterInstance(vo.RegisterInstanceParam{ 96 | Ip: host, 97 | Port: uint64(p), 98 | ServiceName: info.ServiceName, 99 | Weight: float64(info.Weight), 100 | Enable: true, 101 | Healthy: true, 102 | Metadata: mergeTags(info.Tags, nacos.Tags), 103 | GroupName: n.opts.group, 104 | ClusterName: n.opts.cluster, 105 | Ephemeral: true, 106 | }) 107 | if e != nil { 108 | return fmt.Errorf("register instance error: %w", e) 109 | } 110 | return nil 111 | } 112 | 113 | func (n *nacosRegistry) getLocalIpv4Host() (string, error) { 114 | addr, err := net.InterfaceAddrs() 115 | if err != nil { 116 | return "", err 117 | } 118 | for _, addr := range addr { 119 | ipNet, isIpNet := addr.(*net.IPNet) 120 | if isIpNet && !ipNet.IP.IsLoopback() { 121 | ipv4 := ipNet.IP.To4() 122 | if ipv4 != nil { 123 | return ipv4.String(), nil 124 | } 125 | } 126 | } 127 | return "", errors.New("not found ipv4 address") 128 | } 129 | 130 | func (n *nacosRegistry) validateRegistryInfo(info *registry.Info) error { 131 | if info == nil { 132 | return errors.New("registry.Info can not be empty") 133 | } 134 | if info.ServiceName == "" { 135 | return errors.New("registry.Info ServiceName can not be empty") 136 | } 137 | if info.Addr == nil { 138 | return errors.New("registry.Info Addr can not be empty") 139 | } 140 | 141 | return nil 142 | } 143 | 144 | // Deregister a service info from nacos. 145 | func (n *nacosRegistry) Deregister(info *registry.Info) error { 146 | if err := n.validateRegistryInfo(info); err != nil { 147 | return err 148 | } 149 | host, port, err := net.SplitHostPort(info.Addr.String()) 150 | if err != nil { 151 | return err 152 | } 153 | p, err := strconv.Atoi(port) 154 | if err != nil { 155 | return fmt.Errorf("parse registry info port error: %w", err) 156 | } 157 | if host == "" || host == "::" { 158 | host, err = n.getLocalIpv4Host() 159 | if err != nil { 160 | return fmt.Errorf("parse registry info addr error: %w", err) 161 | } 162 | } 163 | if _, err = n.cli.DeregisterInstance(vo.DeregisterInstanceParam{ 164 | Ip: host, 165 | Port: uint64(p), 166 | ServiceName: info.ServiceName, 167 | Ephemeral: true, 168 | GroupName: n.opts.group, 169 | Cluster: n.opts.cluster, 170 | }); err != nil { 171 | return err 172 | } 173 | return nil 174 | } 175 | 176 | // should not modify the source data. 177 | func mergeTags(ts ...map[string]string) map[string]string { 178 | if len(ts) == 0 { 179 | return nil 180 | } 181 | if len(ts) == 1 { 182 | return ts[0] 183 | } 184 | tags := map[string]string{} 185 | for _, t := range ts { 186 | for k, v := range t { 187 | tags[k] = v 188 | } 189 | } 190 | return tags 191 | } 192 | -------------------------------------------------------------------------------- /v2/registry/registry_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package registry 16 | 17 | import ( 18 | "context" 19 | "net" 20 | "testing" 21 | "time" 22 | 23 | "github.com/cloudwego/kitex/client" 24 | "github.com/cloudwego/kitex/pkg/registry" 25 | "github.com/cloudwego/kitex/pkg/rpcinfo" 26 | "github.com/cloudwego/kitex/pkg/utils" 27 | "github.com/cloudwego/kitex/server" 28 | "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api" 29 | "github.com/kitex-contrib/registry-nacos/v2/example/hello/kitex_gen/api/hello" 30 | "github.com/kitex-contrib/registry-nacos/v2/resolver" 31 | "github.com/nacos-group/nacos-sdk-go/v2/clients" 32 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client" 33 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 34 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 35 | "github.com/stretchr/testify/assert" 36 | ) 37 | 38 | func getNacosClient() (naming_client.INamingClient, error) { 39 | // create ServerConfig 40 | sc := []constant.ServerConfig{ 41 | *constant.NewServerConfig("127.0.0.1", 8848, constant.WithContextPath("/nacos"), constant.WithScheme("http")), 42 | } 43 | 44 | // create ClientConfig 45 | cc := *constant.NewClientConfig( 46 | constant.WithTimeoutMs(50000), 47 | constant.WithUpdateCacheWhenEmpty(true), 48 | constant.WithNotLoadCacheAtStart(true), 49 | ) 50 | 51 | // create naming client 52 | newClient, err := clients.NewNamingClient( 53 | vo.NacosClientParam{ 54 | ClientConfig: &cc, 55 | ServerConfigs: sc, 56 | }, 57 | ) 58 | return newClient, err 59 | } 60 | 61 | // TestNewNacosRegistry test registry a service 62 | func TestNacosRegistryRegister(t *testing.T) { 63 | nacosClient, err := getNacosClient() 64 | if err != nil { 65 | t.Errorf("err:%v", err) 66 | return 67 | } 68 | type fields struct { 69 | cli naming_client.INamingClient 70 | } 71 | type args struct { 72 | info *registry.Info 73 | } 74 | tests := []struct { 75 | name string 76 | fields fields 77 | args args 78 | wantErr bool 79 | }{ 80 | { 81 | name: "common", 82 | fields: fields{nacosClient}, 83 | args: args{info: ®istry.Info{ 84 | ServiceName: "demo.kitex-contrib.local", 85 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8080}, 86 | Weight: 999, 87 | StartTime: time.Now(), 88 | Tags: map[string]string{"env": "local"}, 89 | }}, 90 | wantErr: false, 91 | }, 92 | } 93 | for _, tt := range tests { 94 | t.Run(tt.name, func(t *testing.T) { 95 | n := NewNacosRegistry(tt.fields.cli, WithCluster("DEFAULT"), WithGroup("DEFAULT_GROUP")) 96 | if err := n.Register(tt.args.info); (err != nil) != tt.wantErr { 97 | t.Errorf("Register() error = %v, wantErr %v", err, tt.wantErr) 98 | } 99 | }) 100 | } 101 | } 102 | 103 | // TestNacosRegistryDeregister test deregister a service 104 | func TestNacosRegistryDeregister(t *testing.T) { 105 | nacosClient, err := getNacosClient() 106 | if err != nil { 107 | t.Errorf("err:%v", err) 108 | return 109 | } 110 | type fields struct { 111 | cli naming_client.INamingClient 112 | } 113 | type args struct { 114 | info *registry.Info 115 | } 116 | tests := []struct { 117 | name string 118 | fields fields 119 | args args 120 | wantErr bool 121 | }{ 122 | { 123 | name: "common", 124 | args: args{info: ®istry.Info{ 125 | ServiceName: "demo.kitex-contrib.local", 126 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8080}, 127 | Weight: 999, 128 | StartTime: time.Now(), 129 | Tags: map[string]string{"env": "local"}, 130 | }}, 131 | fields: fields{nacosClient}, 132 | wantErr: false, 133 | }, 134 | } 135 | for _, tt := range tests { 136 | t.Run(tt.name, func(t *testing.T) { 137 | n := NewNacosRegistry(tt.fields.cli, WithCluster("DEFAULT"), WithGroup("DEFAULT_GROUP")) 138 | if err := n.Deregister(tt.args.info); (err != nil) != tt.wantErr { 139 | t.Errorf("Deregister() error = %v, wantErr %v", err, tt.wantErr) 140 | } 141 | }) 142 | } 143 | } 144 | 145 | // TestNacosMultipleInstancesWithDefaultNacosRegistry use DefaultNacosRegistry to test registry multiple service,then deregister one 146 | func TestNacosMultipleInstancesWithDefaultNacosRegistry(t *testing.T) { 147 | var ( 148 | svcName = "MultipleInstances" 149 | clusterName = "TheCluster" 150 | groupName = "TheGroup" 151 | ) 152 | got, err := NewDefaultNacosRegistry(WithCluster(clusterName), WithGroup(groupName)) 153 | assert.Nil(t, err) 154 | if !assert.NotNil(t, got) { 155 | t.Errorf("err: new registry fail") 156 | return 157 | } 158 | time.Sleep(time.Second) 159 | err = got.Register(®istry.Info{ 160 | ServiceName: svcName, 161 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8081}, 162 | }) 163 | assert.Nil(t, err) 164 | 165 | time.Sleep(time.Second * 1) 166 | nacosClient, err := getNacosClient() 167 | assert.Nil(t, err) 168 | res, err := nacosClient.SelectAllInstances(vo.SelectAllInstancesParam{ 169 | ServiceName: svcName, 170 | GroupName: groupName, 171 | Clusters: []string{clusterName}, 172 | }) 173 | assert.Nil(t, err) 174 | assert.Equal(t, 1, len(res)) 175 | 176 | time.Sleep(time.Second) 177 | err = got.Deregister(®istry.Info{ 178 | ServiceName: svcName, 179 | Addr: &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8081}, 180 | }) 181 | assert.Nil(t, err) 182 | 183 | time.Sleep(time.Second * 3) 184 | res, err = nacosClient.SelectInstances(vo.SelectInstancesParam{ 185 | ServiceName: svcName, 186 | GroupName: groupName, 187 | Clusters: []string{clusterName}, 188 | HealthyOnly: true, 189 | }) 190 | assert.Equal(t, "instance list is empty!", err.Error()) 191 | assert.Equal(t, 0, len(res)) 192 | } 193 | 194 | func TestMergeTags(t *testing.T) { 195 | t1 := map[string]string{ 196 | "k1": "v1", 197 | "k2": "v2", 198 | } 199 | t2 := map[string]string{ 200 | "k3": "v3", 201 | "k4": "v4", 202 | } 203 | merged := mergeTags(t1, t2) 204 | assert.Equal(t, merged, map[string]string{ 205 | "k1": "v1", 206 | "k2": "v2", 207 | "k3": "v3", 208 | "k4": "v4", 209 | }) 210 | assert.Equal(t, t1, map[string]string{ 211 | "k1": "v1", 212 | "k2": "v2", 213 | }) 214 | assert.Equal(t, t2, map[string]string{ 215 | "k3": "v3", 216 | "k4": "v4", 217 | }) 218 | } 219 | 220 | type HelloImpl struct{} 221 | 222 | func (h *HelloImpl) Echo(_ context.Context, req *api.Request) (resp *api.Response, err error) { 223 | resp = &api.Response{ 224 | Message: req.Message, 225 | } 226 | return 227 | } 228 | 229 | func TestResolverDifferentGroup(t *testing.T) { 230 | r, err := NewDefaultNacosRegistry() 231 | assert.Nil(t, err) 232 | r2, err := NewDefaultNacosRegistry(WithGroup("OTHER")) 233 | assert.Nil(t, err) 234 | 235 | svr := hello.NewServer( 236 | new(HelloImpl), 237 | server.WithRegistry(r), 238 | server.WithRegistryInfo(®istry.Info{ 239 | ServiceName: "demo1", 240 | Addr: utils.NewNetAddr("tcp", "127.0.0.1:8081"), 241 | Weight: 10, 242 | Tags: nil, 243 | }), 244 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "demo1"}), 245 | server.WithServiceAddr(&net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8081}), 246 | ) 247 | 248 | svr2 := hello.NewServer( 249 | new(HelloImpl), 250 | server.WithRegistry(r2), 251 | server.WithRegistryInfo(®istry.Info{ 252 | ServiceName: "demo2", 253 | Addr: utils.NewNetAddr("tcp", "127.0.0.1:8082"), 254 | Weight: 10, 255 | Tags: nil, 256 | }), 257 | server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "demo2"}), 258 | server.WithServiceAddr(&net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8082}), 259 | ) 260 | 261 | go func() { 262 | e := svr.Run() //nolint:errcheck 263 | assert.Nil(t, e) 264 | }() 265 | go func() { 266 | e := svr2.Run() //nolint:errcheck 267 | assert.Nil(t, e) 268 | }() 269 | time.Sleep(2 * time.Second) 270 | 271 | resolver1, err := resolver.NewDefaultNacosResolver() 272 | assert.Nil(t, err) 273 | resolver2, err := resolver.NewDefaultNacosResolver(resolver.WithGroup("OTHER")) 274 | assert.Nil(t, err) 275 | 276 | client1 := hello.MustNewClient( 277 | "demo1", 278 | client.WithResolver(resolver1), 279 | client.WithRPCTimeout(time.Second*3), 280 | ) 281 | client2 := hello.MustNewClient( 282 | "demo2", 283 | client.WithResolver(resolver2), 284 | client.WithRPCTimeout(time.Second*3), 285 | ) 286 | resp, err := client1.Echo(context.Background(), &api.Request{Message: "Hello"}) 287 | assert.Nil(t, err) 288 | assert.Equal(t, resp.Message, "Hello") 289 | 290 | resp, err = client2.Echo(context.Background(), &api.Request{Message: "Hello1"}) 291 | assert.Nil(t, err) 292 | assert.Equal(t, resp.Message, "Hello1") 293 | 294 | defer func() { 295 | svr.Stop() //nolint:errcheck 296 | svr2.Stop() //nolint:errcheck 297 | }() 298 | } 299 | -------------------------------------------------------------------------------- /v2/resolver/resolver.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package resolver 16 | 17 | import ( 18 | "context" 19 | "fmt" 20 | 21 | "github.com/cloudwego/kitex/pkg/discovery" 22 | "github.com/cloudwego/kitex/pkg/rpcinfo" 23 | "github.com/kitex-contrib/registry-nacos/v2/nacos" 24 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client" 25 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 26 | ) 27 | 28 | var _ discovery.Resolver = (*nacosResolver)(nil) 29 | 30 | type options struct { 31 | cluster string 32 | group string 33 | } 34 | 35 | // Option is nacos option. 36 | type Option func(o *options) 37 | 38 | // WithCluster with cluster option. 39 | func WithCluster(cluster string) Option { 40 | return func(o *options) { o.cluster = cluster } 41 | } 42 | 43 | // WithGroup with group option. 44 | func WithGroup(group string) Option { 45 | return func(o *options) { o.group = group } 46 | } 47 | 48 | type nacosResolver struct { 49 | cli naming_client.INamingClient 50 | opts options 51 | } 52 | 53 | // NewDefaultNacosResolver create a default service resolver using nacos. 54 | func NewDefaultNacosResolver(opts ...Option) (discovery.Resolver, error) { 55 | cli, err := nacos.NewDefaultNacosClient() 56 | if err != nil { 57 | return nil, err 58 | } 59 | return NewNacosResolver(cli, opts...), nil 60 | } 61 | 62 | // NewNacosResolver create a service resolver using nacos. 63 | func NewNacosResolver(cli naming_client.INamingClient, opts ...Option) discovery.Resolver { 64 | op := options{ 65 | cluster: "DEFAULT", 66 | group: "DEFAULT_GROUP", 67 | } 68 | for _, option := range opts { 69 | option(&op) 70 | } 71 | return &nacosResolver{cli: cli, opts: op} 72 | } 73 | 74 | // Target return a description for the given target that is suitable for being a key for cache. 75 | func (n *nacosResolver) Target(_ context.Context, target rpcinfo.EndpointInfo) (description string) { 76 | return target.ServiceName() 77 | } 78 | 79 | // Resolve a service info by desc. 80 | func (n *nacosResolver) Resolve(_ context.Context, desc string) (discovery.Result, error) { 81 | res, err := n.cli.SelectInstances(vo.SelectInstancesParam{ 82 | ServiceName: desc, 83 | HealthyOnly: true, 84 | GroupName: n.opts.group, 85 | Clusters: []string{n.opts.cluster}, 86 | }) 87 | if err != nil { 88 | return discovery.Result{}, err 89 | } 90 | 91 | if len(res) == 0 { 92 | return discovery.Result{}, fmt.Errorf("no instance remains for %v", desc) 93 | } 94 | instances := make([]discovery.Instance, 0, len(res)) 95 | for _, in := range res { 96 | if !in.Enable { 97 | continue 98 | } 99 | instances = append(instances, discovery.NewInstance( 100 | "tcp", 101 | fmt.Sprintf("%s:%d", in.Ip, in.Port), 102 | int(in.Weight), 103 | in.Metadata), 104 | ) 105 | } 106 | if len(instances) == 0 { 107 | return discovery.Result{}, fmt.Errorf("no instance remains for %v", desc) 108 | } 109 | return discovery.Result{ 110 | Cacheable: true, 111 | CacheKey: desc, 112 | Instances: instances, 113 | }, nil 114 | } 115 | 116 | // Diff computes the difference between two results. 117 | func (n *nacosResolver) Diff(cacheKey string, prev, next discovery.Result) (discovery.Change, bool) { 118 | return discovery.DefaultDiff(cacheKey, prev, next) 119 | } 120 | 121 | // Name returns the name of the resolver. 122 | func (n *nacosResolver) Name() string { 123 | return "nacos" + ":" + n.opts.cluster + ":" + n.opts.group 124 | } 125 | -------------------------------------------------------------------------------- /v2/resolver/resolver_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2024 CloudWeGo Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package resolver 16 | 17 | import ( 18 | "context" 19 | "net" 20 | "strings" 21 | "testing" 22 | "time" 23 | 24 | "github.com/cloudwego/kitex/pkg/discovery" 25 | "github.com/cloudwego/kitex/pkg/registry" 26 | nacosregistry "github.com/kitex-contrib/registry-nacos/v2/registry" 27 | "github.com/nacos-group/nacos-sdk-go/v2/clients" 28 | "github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client" 29 | "github.com/nacos-group/nacos-sdk-go/v2/common/constant" 30 | "github.com/nacos-group/nacos-sdk-go/v2/vo" 31 | "github.com/stretchr/testify/assert" 32 | ) 33 | 34 | var ( 35 | nacosCli naming_client.INamingClient 36 | svcName = "demo.kitex-contrib.local" 37 | svcAddr = net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 8080} 38 | svcInfo = ®istry.Info{ 39 | ServiceName: svcName, 40 | Addr: &svcAddr, 41 | Weight: 999, 42 | StartTime: time.Now(), 43 | Tags: map[string]string{"env": "local"}, 44 | } 45 | ) 46 | 47 | func init() { 48 | cli, err := getNacosClient() 49 | if err != nil { 50 | return 51 | } 52 | time.Sleep(time.Second) 53 | err = nacosregistry.NewNacosRegistry(cli).Register(svcInfo) 54 | if err != nil { 55 | return 56 | } 57 | time.Sleep(time.Second) 58 | nacosCli = cli 59 | } 60 | 61 | func getNacosClient() (naming_client.INamingClient, error) { 62 | // create ServerConfig 63 | sc := []constant.ServerConfig{ 64 | *constant.NewServerConfig("127.0.0.1", 8848, constant.WithContextPath("/nacos"), constant.WithScheme("http")), 65 | } 66 | 67 | // create ClientConfig 68 | cc := *constant.NewClientConfig( 69 | constant.WithTimeoutMs(50000), 70 | constant.WithUpdateCacheWhenEmpty(true), 71 | constant.WithNotLoadCacheAtStart(true), 72 | ) 73 | 74 | // create naming client 75 | newClient, err := clients.NewNamingClient( 76 | vo.NacosClientParam{ 77 | ClientConfig: &cc, 78 | ServerConfigs: sc, 79 | }, 80 | ) 81 | return newClient, err 82 | } 83 | 84 | // TestNacosResolverResolve test Resolve a service 85 | func TestNacosResolverResolve(t *testing.T) { 86 | type fields struct { 87 | cli naming_client.INamingClient 88 | } 89 | type args struct { 90 | ctx context.Context 91 | desc string 92 | } 93 | tests := []struct { 94 | name string 95 | fields fields 96 | args args 97 | want discovery.Result 98 | wantErr bool 99 | }{ 100 | { 101 | name: "common", 102 | args: args{ 103 | ctx: context.Background(), 104 | desc: svcName, 105 | }, 106 | fields: fields{cli: nacosCli}, 107 | }, 108 | { 109 | name: "wrong desc", 110 | args: args{ 111 | ctx: context.Background(), 112 | desc: "xxxx.kitex-contrib.local", 113 | }, 114 | fields: fields{cli: nacosCli}, 115 | wantErr: true, 116 | }, 117 | } 118 | 119 | for _, tt := range tests { 120 | t.Run(tt.name, func(t *testing.T) { 121 | n := NewNacosResolver(tt.fields.cli) 122 | _, err := n.Resolve(tt.args.ctx, tt.args.desc) 123 | if (err != nil) != tt.wantErr { 124 | t.Errorf("Resolve() error = %v, wantErr %v", err, tt.wantErr) 125 | return 126 | } 127 | if err != nil && !strings.Contains(err.Error(), "instance list is empty") { 128 | t.Errorf("Resolve err is not expectant") 129 | return 130 | } 131 | }) 132 | } 133 | 134 | err := nacosregistry.NewNacosRegistry(nacosCli).Deregister(svcInfo) 135 | assert.Nil(t, err) 136 | } 137 | 138 | // TestNacosResolverDifferentCluster test NewNacosResolver WithCluster option 139 | func TestNacosResolverDifferentCluster(t *testing.T) { 140 | ctx := context.Background() 141 | n := NewNacosResolver(nacosCli) 142 | got, err := n.Resolve(ctx, svcName) 143 | assert.Nil(t, err) 144 | assert.NotNil(t, got) 145 | assert.Equal(t, svcName, got.CacheKey) 146 | if assert.NotEmpty(t, got.Instances) { 147 | gotSvc := got.Instances[0] 148 | assert.Equal(t, gotSvc.Address().String(), svcAddr.String()) 149 | } 150 | 151 | n = NewNacosResolver(nacosCli, WithCluster("OTHER")) 152 | _, err = n.Resolve(ctx, svcName) 153 | assert.NotNil(t, err) 154 | assert.Contains(t, err.Error(), "instance list is empty") 155 | } 156 | 157 | // TestNewDefaultNacosResolver test new a default nacos resolver 158 | func TestNewDefaultNacosResolver(t *testing.T) { 159 | r, err := NewDefaultNacosResolver() 160 | assert.Nil(t, err) 161 | assert.NotNil(t, r) 162 | } 163 | --------------------------------------------------------------------------------