Compare commits
	
		
			242 Commits
		
	
	
		
			v0.0.1
			...
			78664a34ed
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 78664a34ed | |||
| bec0e310e9 | |||
| 92436e9016 | |||
| 25618a3859 | |||
| b22f150601 | |||
| 71bcb63b60 | |||
| 698bfbc6f1 | |||
| 209042de3a | |||
| 990685628d | |||
| 0f8ead6acc | |||
| 2fbcee7b59 | |||
| 19a469c4e2 | |||
| 2a6a93a792 | |||
| 2adba9d0da | |||
| 9d70c4dd34 | |||
| b9704903f2 | |||
| 4eda58e404 | |||
| 0f8d0a1123 | |||
| 603b855e2a | |||
| f2cfd562c3 | |||
| 781cf3d719 | |||
| 1b65507fe5 | |||
| 40b5402aa5 | |||
|  | e8b7e30e4d | ||
| 55e7e3d61d | |||
|  | d75c36938a | ||
| a7cec360e9 | |||
|  | 3978256931 | ||
| 6dfff28203 | |||
|  | 373acda151 | ||
| 3f9ed4e83b | |||
|  | 0486780f36 | ||
| 36788b5fbf | |||
|  | c79b83a3c1 | ||
| a6585fd6d4 | |||
|  | 7fce5ccad9 | ||
| b5a5e98f9e | |||
|  | e419c6a67c | ||
| 17c46e63a2 | |||
|  | cdf1a2c3e3 | ||
| aba3df63df | |||
|  | 337df46029 | ||
| bfe4839a00 | |||
|  | 5474c37f8f | ||
| ba88a5568a | |||
|  | 57f903a8c2 | ||
| 9f918bd3f2 | |||
|  | 0d88050daf | ||
|  | d1ed5bed51 | ||
|  | 42697318b1 | ||
| 28aea45725 | |||
|  | ed72c05645 | ||
|  | d239dcde63 | ||
| 6eb07dc351 | |||
|  | a0d704f845 | ||
| 4b8a761f30 | |||
|  | a2c711a1b5 | ||
| be564f50aa | |||
|  | b7b1eff81c | ||
| 671a6b6f7c | |||
| 27c1c4d86b | |||
| 76d37a99eb | |||
|  | 4c2827172f | ||
| e3461dd23f | |||
|  | d8b5c011e5 | ||
|  | 15abd38afd | ||
| 5865a0f388 | |||
|  | 67da8d1165 | ||
|  | c7d24caa03 | ||
| 8c222c4715 | |||
| 6e91cd5cf5 | |||
| a9e673b2ef | |||
| 251f06cc31 | |||
| e97e4580a1 | |||
| bd7dbe94ca | |||
|  | 0f32fad4c0 | ||
|  | 858111106e | ||
|  | dc35dc6d3e | ||
|  | 24b1abfb9a | ||
|  | 205fd53047 | ||
|  | b3b7d1af13 | ||
| 80e2184bba | |||
|  | a920d15d95 | ||
| 5ecbfac164 | |||
|  | 61d7a322de | ||
|  | b43c207f6a | ||
|  | d243b884c7 | ||
| 107b470b9a | |||
|  | 878bac53ac | ||
| e28c584056 | |||
| b8dc821784 | |||
|  | 907d2591df | ||
|  | 8cc656eec7 | ||
|  | 5792434604 | ||
| 402ccee5b9 | |||
|  | 90986a26e2 | ||
| 6d41afd5a0 | |||
| 2e645748bb | |||
| f6b1c8d745 | |||
| ea503d0583 | |||
| 048773c669 | |||
|  | e3cb87ffe3 | ||
| b1af43c4b0 | |||
|  | f994df9e04 | ||
| c556f7157f | |||
|  | 17be582d19 | ||
| 131a150d3d | |||
|  | 7f874a286e | ||
| 2f40797303 | |||
|  | 3e1b2b7c5d | ||
| 6442f4c474 | |||
|  | 1dda7e6b83 | ||
| 2b85cabe1f | |||
| 02895dd712 | |||
| 42b93ce57e | |||
| 763c299ab7 | |||
|  | 937a6d62b2 | ||
| fb6e2c8845 | |||
| 3e9a3a917d | |||
| 289a765784 | |||
| b13ad231d1 | |||
| 0793e84da6 | |||
|  | f2c6d7cc80 | ||
| 6969b228a7 | |||
| 84362e6dd9 | |||
|  | b83cc26ca0 | ||
|  | 6591845ded | ||
| 7c7c93521f | |||
| 9e10237b97 | |||
|  | 856c7dae7c | ||
| e85f2e1f45 | |||
|  | 0a8ccce4e1 | ||
| 1b7e22442f | |||
|  | 4c81ce6a9d | ||
| 89ffe47d06 | |||
|  | a03274011f | ||
| 186ec6bf00 | |||
|  | fefcc273d9 | ||
| a5ca5ec499 | |||
|  | 7104528c7d | ||
| eaa61e254e | |||
|  | 00aa5331f6 | ||
| c165c0f1a8 | |||
|  | fa6fe590bd | ||
| 8cae060e05 | |||
| a10275ad1f | |||
|  | f247a8c906 | ||
|  | 015b2a4b05 | ||
|  | c9da9d36a0 | ||
| 1f69062916 | |||
| c4ca900a56 | |||
|  | 569d95e3e3 | ||
| d2f1b7b3b9 | |||
|  | 65c10f7b0a | ||
| 76537a045a | |||
|  | 7f19288476 | ||
| c3d10b669b | |||
| 20c5840f47 | |||
| 8b2dd91711 | |||
|  | 08621f7cf3 | ||
|  | 8d7d802730 | ||
| 137fbae58e | |||
|  | 13093dd404 | ||
| 12cf576b9c | |||
|  | b91014d287 | ||
| 6b867760e5 | |||
|  | f61f056a8e | ||
| 0525dae1cd | |||
|  | 50d0d836e5 | ||
| a1e7560d6f | |||
| a510f982e2 | |||
| 1129a1e992 | |||
|  | 033fcd3e2b | ||
| c2ef582962 | |||
| 4c9f1f21a9 | |||
|  | 4585b73513 | ||
|  | 728d3f2a8c | ||
| c1a2cfae67 | |||
| 8edc3d35bb | |||
|  | 4d0bb35dd9 | ||
| 0539d08195 | |||
| f40591a520 | |||
| acfab7e10c | |||
| 6697ccddf2 | |||
| d536140a5b | |||
| db02559a00 | |||
| 0fae2e1bdd | |||
|  | 7a1fdef33a | ||
| 2bb81ff232 | |||
|  | 9ac268b2f0 | ||
| 510fa4b379 | |||
|  | 08def4d244 | ||
| a4683c0b78 | |||
|  | 637e3df24a | ||
|  | 36c7fa6a23 | ||
| 2bef21a001 | |||
|  | 78c32dc3e8 | ||
|  | 4d5a2d1a4a | ||
|  | 9817e0c1af | ||
|  | ca4d561efe | ||
|  | 0ffbfc36d7 | ||
|  | 8a1b5b1130 | ||
|  | 1048869e6c | ||
|  | 35e9b9b77e | ||
|  | faeaff358d | ||
|  | 3d7a5f6122 | ||
| 9030637204 | |||
|  | 225cdfd469 | ||
|  | d3696a4bf8 | ||
|  | 88432401ac | ||
|  | e3383bae9b | ||
|  | 60c340cc86 | ||
|  | 8d237e1423 | ||
|  | be27263047 | ||
|  | 41a60a8a16 | ||
| 2e09afca64 | |||
|  | aeb25fec3b | ||
| a4518a12eb | |||
| 2a6e2c72c1 | |||
|  | 1d17c6c962 | ||
|  | 11c265458c | ||
| 8d34fe5dc0 | |||
| 8c480b5f0e | |||
| c1e03ca61d | |||
|  | 22dc300099 | ||
|  | 8584261b44 | ||
| 4d31515547 | |||
| 9f36491023 | |||
|  | 1378d624be | ||
| 0fe6470260 | |||
| db1148c1d1 | |||
| bbd07bb091 | |||
| 067cf68d23 | |||
| 7ef49b03ba | |||
| 60ad0903b9 | |||
| 2ed58a202b | |||
| 15a5d7d2cd | |||
| 131916baca | |||
| 3aa3132caa | |||
| 854839ba45 | |||
| 5350b6ec2b | |||
| c59d400857 | 
							
								
								
									
										29
									
								
								.gitea/workflows/job_lint.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								.gitea/workflows/job_lint.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| name: lint | ||||
|  | ||||
| on: | ||||
|   pull_request: | ||||
|     types: [opened, reopened, synchronize] | ||||
|     branches: | ||||
|     - master | ||||
|     - v3 | ||||
|     - v4 | ||||
|  | ||||
| jobs: | ||||
|   lint: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|     - name: checkout code | ||||
|       uses: actions/checkout@v4 | ||||
|       with: | ||||
|         filter: 'blob:none' | ||||
|     - name: setup go | ||||
|       uses: actions/setup-go@v5 | ||||
|       with: | ||||
|         cache-dependency-path: "**/*.sum" | ||||
|         go-version: 'stable'  | ||||
|     - name: setup deps | ||||
|       run: go get -v ./... | ||||
|     - name: run lint | ||||
|       uses: https://github.com/golangci/golangci-lint-action@v6 | ||||
|       with: | ||||
|         version: 'latest' | ||||
							
								
								
									
										34
									
								
								.gitea/workflows/job_test.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								.gitea/workflows/job_test.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| name: test | ||||
|  | ||||
| on: | ||||
|   pull_request: | ||||
|     types: [opened, reopened, synchronize] | ||||
|     branches: | ||||
|     - master | ||||
|     - v3 | ||||
|     - v4 | ||||
|   push: | ||||
|     branches: | ||||
|     - master | ||||
|     - v3 | ||||
|     - v4 | ||||
|  | ||||
| jobs: | ||||
|   test: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|     - name: checkout code | ||||
|       uses: actions/checkout@v4 | ||||
|       with: | ||||
|         filter: 'blob:none' | ||||
|     - name: setup go | ||||
|       uses: actions/setup-go@v5 | ||||
|       with: | ||||
|         cache-dependency-path: "**/*.sum" | ||||
|         go-version: 'stable' | ||||
|     - name: setup deps | ||||
|       run: go get -v ./... | ||||
|     - name: run test | ||||
|       env: | ||||
|         INTEGRATION_TESTS: yes | ||||
|       run: go test -mod readonly -v ./... | ||||
							
								
								
									
										53
									
								
								.gitea/workflows/job_tests.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								.gitea/workflows/job_tests.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| name: test | ||||
|  | ||||
| on: | ||||
|   pull_request: | ||||
|     types: [opened, reopened, synchronize] | ||||
|     branches: | ||||
|     - master | ||||
|     - v3 | ||||
|     - v4 | ||||
|   push: | ||||
|     branches: | ||||
|     - master | ||||
|     - v3 | ||||
|     - v4 | ||||
|  | ||||
| jobs: | ||||
|   test: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|     - name: checkout code | ||||
|       uses: actions/checkout@v4 | ||||
|       with: | ||||
|         filter: 'blob:none' | ||||
|     - name: checkout tests | ||||
|       uses: actions/checkout@v4 | ||||
|       with: | ||||
|         ref: master | ||||
|         filter: 'blob:none' | ||||
|         repository: unistack-org/micro-tests | ||||
|         path: micro-tests | ||||
|     - name: setup go | ||||
|       uses: actions/setup-go@v5 | ||||
|       with: | ||||
|         cache-dependency-path: "**/*.sum" | ||||
|         go-version: 'stable' | ||||
|     - name: setup go work | ||||
|       env: | ||||
|         GOWORK: /workspace/${{ github.repository_owner }}/go.work | ||||
|       run: | | ||||
|         go work init | ||||
|         go work use . | ||||
|         go work use micro-tests         | ||||
|     - name: setup deps | ||||
|       env: | ||||
|         GOWORK: /workspace/${{ github.repository_owner }}/go.work | ||||
|       run: go get -v ./... | ||||
|     - name: run tests | ||||
|       env: | ||||
|         INTEGRATION_TESTS: yes | ||||
|         GOWORK: /workspace/${{ github.repository_owner }}/go.work | ||||
|       run: | | ||||
|         cd micro-tests | ||||
|         go test -mod readonly -v ./... || true         | ||||
							
								
								
									
										13
									
								
								.github/stale.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								.github/stale.sh
									
									
									
									
										vendored
									
									
								
							| @@ -1,13 +0,0 @@ | ||||
| #!/bin/bash -ex | ||||
|  | ||||
| export PATH=$PATH:$(pwd)/bin | ||||
| export GO111MODULE=on | ||||
| export GOBIN=$(pwd)/bin | ||||
|  | ||||
| #go get github.com/rvflash/goup@v0.4.1 | ||||
|  | ||||
| #goup -v ./... | ||||
| #go get github.com/psampaz/go-mod-outdated@v0.6.0 | ||||
| go list -u -m -mod=mod -json all | go-mod-outdated -update -direct -ci || true | ||||
|  | ||||
| #go list -u -m -json all | go-mod-outdated -update | ||||
							
								
								
									
										46
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,46 +0,0 @@ | ||||
| name: build | ||||
| on: | ||||
|  push: | ||||
|     branches: | ||||
|     - master | ||||
| jobs: | ||||
|   test: | ||||
|     name: test | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|     - name: setup | ||||
|       uses: actions/setup-go@v1 | ||||
|       with: | ||||
|         go-version: 1.15 | ||||
|     - name: checkout | ||||
|       uses: actions/checkout@v2 | ||||
|     - name: cache | ||||
|       uses: actions/cache@v2 | ||||
|       with: | ||||
|         path: ~/go/pkg/mod | ||||
|         key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} | ||||
|         restore-keys: ${{ runner.os }}-go- | ||||
|     - name: deps | ||||
|       run: go get -v -t -d ./... | ||||
|     - name: test | ||||
|       env: | ||||
|         INTEGRATION_TESTS: yes | ||||
|       run: go test -mod readonly -v ./... | ||||
|   lint: | ||||
|     name: lint | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - name: lint | ||||
|         uses: golangci/golangci-lint-action@v1 | ||||
|         continue-on-error: true | ||||
|         with: | ||||
|           # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. | ||||
|           version: v1.30 | ||||
|           # Optional: working directory, useful for monorepos | ||||
|           # working-directory: somedir | ||||
|           # Optional: golangci-lint command line arguments. | ||||
|           # args: --issues-exit-code=0 | ||||
|           # Optional: show only new issues if it's a pull request. The default value is `false`. | ||||
|           # only-new-issues: true | ||||
							
								
								
									
										46
									
								
								.github/workflows/pr.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										46
									
								
								.github/workflows/pr.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,46 +0,0 @@ | ||||
| name: prbuild | ||||
| on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|     - master | ||||
| jobs: | ||||
|   test: | ||||
|     name: test | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|     - name: setup | ||||
|       uses: actions/setup-go@v1 | ||||
|       with: | ||||
|         go-version: 1.15 | ||||
|     - name: checkout | ||||
|       uses: actions/checkout@v2 | ||||
|     - name: cache | ||||
|       uses: actions/cache@v2 | ||||
|       with: | ||||
|         path: ~/go/pkg/mod | ||||
|         key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} | ||||
|         restore-keys: ${{ runner.os }}-go- | ||||
|     - name: deps | ||||
|       run: go get -v -t -d ./... | ||||
|     - name: test | ||||
|       env: | ||||
|         INTEGRATION_TESTS: yes | ||||
|       run: go test -mod readonly -v ./... | ||||
|   lint: | ||||
|     name: lint | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: checkout | ||||
|         uses: actions/checkout@v2 | ||||
|       - name: lint | ||||
|         uses: golangci/golangci-lint-action@v1 | ||||
|         continue-on-error: true | ||||
|         with: | ||||
|           # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. | ||||
|           version: v1.30 | ||||
|           # Optional: working directory, useful for monorepos | ||||
|           # working-directory: somedir | ||||
|           # Optional: golangci-lint command line arguments. | ||||
|           # args: --issues-exit-code=0 | ||||
|           # Optional: show only new issues if it's a pull request. The default value is `false`. | ||||
|           # only-new-issues: true | ||||
							
								
								
									
										24
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| # Binaries for programs and plugins | ||||
| *.exe | ||||
| *.exe~ | ||||
| *.dll | ||||
| *.so | ||||
| *.dylib | ||||
| bin | ||||
|  | ||||
| # Test binary, built with `go test -c` | ||||
| *.test | ||||
|  | ||||
| # Output of the go coverage tool, specifically when used with LiteIDE | ||||
| *.out | ||||
|  | ||||
| # Dependency directories (remove the comment below to include it) | ||||
| # vendor/ | ||||
|  | ||||
| # Go workspace file | ||||
| go.work | ||||
|  | ||||
| # General | ||||
| .DS_Store | ||||
| .idea | ||||
| .vscode | ||||
							
								
								
									
										5
									
								
								.golangci.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.golangci.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| run: | ||||
|   concurrency: 8 | ||||
|   deadline: 5m | ||||
|   issues-exit-code: 1 | ||||
|   tests: true | ||||
							
								
								
									
										192
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,192 @@ | ||||
|  | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|  | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|  | ||||
|    1. Definitions. | ||||
|  | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
|  | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
|  | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
|  | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
|  | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
|  | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
|  | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
|  | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
|  | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
|  | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
|  | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
|  | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
|  | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
|  | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
|  | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
|  | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
|  | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
|  | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
|  | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
|  | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
|  | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
|  | ||||
|    END OF TERMS AND CONDITIONS | ||||
|  | ||||
|    Copyright 2015-2020 Asim Aslam. | ||||
|    Copyright 2019-2020 Unistack LLC. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
							
								
								
									
										25
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,25 +0,0 @@ | ||||
| # GRPC Client | ||||
|  | ||||
| The grpc client is a [micro.Client](https://godoc.org/github.com/micro/go-micro/client#Client) compatible client. | ||||
|  | ||||
| ## Overview | ||||
|  | ||||
| The client makes use of the [google.golang.org/grpc](google.golang.org/grpc) framework for the underlying communication mechanism. | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| Specify the client to your micro service | ||||
|  | ||||
| ```go | ||||
| import ( | ||||
| 	"github.com/micro/go-micro" | ||||
| 	"github.com/micro/go-plugins/client/grpc" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	service := micro.NewService( | ||||
| 		micro.Name("greeter"), | ||||
| 		micro.Client(grpc.NewClient()), | ||||
| 	) | ||||
| } | ||||
| ``` | ||||
							
								
								
									
										246
									
								
								codec.go
									
									
									
									
									
								
							
							
						
						
									
										246
									
								
								codec.go
									
									
									
									
									
								
							| @@ -1,231 +1,65 @@ | ||||
| package grpc | ||||
|  | ||||
| import ( | ||||
| 	b "bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
|  | ||||
| 	oldjsonpb "github.com/golang/protobuf/jsonpb" | ||||
| 	oldproto "github.com/golang/protobuf/proto" | ||||
| 	bytes "github.com/unistack-org/micro-codec-bytes" | ||||
| 	"github.com/unistack-org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"google.golang.org/grpc" | ||||
| 	"google.golang.org/grpc/encoding" | ||||
| 	jsonpb "google.golang.org/protobuf/encoding/protojson" | ||||
| 	"google.golang.org/protobuf/proto" | ||||
| ) | ||||
|  | ||||
| type jsonCodec struct{} | ||||
| type protoCodec struct{} | ||||
| type bytesCodec struct{} | ||||
| type wrapCodec struct{ encoding.Codec } | ||||
|  | ||||
| var jsonpbMarshaler = &jsonpb.MarshalOptions{} | ||||
| var oldjsonpbMarshaler = &oldjsonpb.Marshaler{} | ||||
| var useNumber bool | ||||
|  | ||||
| var ( | ||||
| 	defaultGRPCCodecs = map[string]encoding.Codec{ | ||||
| 		"application/json":         jsonCodec{}, | ||||
| 		"application/proto":        protoCodec{}, | ||||
| 		"application/protobuf":     protoCodec{}, | ||||
| 		"application/octet-stream": protoCodec{}, | ||||
| 		"application/grpc":         protoCodec{}, | ||||
| 		"application/grpc+json":    jsonCodec{}, | ||||
| 		"application/grpc+proto":   protoCodec{}, | ||||
| 		"application/grpc+bytes":   bytesCodec{}, | ||||
| 	} | ||||
| 	_ encoding.Codec = &wrapMicroCodec{} | ||||
| 	_ codec.Codec    = &wrapGrpcCodec{} | ||||
| ) | ||||
|  | ||||
| // UseNumber fix unmarshal Number(8234567890123456789) to interface(8.234567890123457e+18) | ||||
| func UseNumber() { | ||||
| 	useNumber = true | ||||
| type wrapStream struct{ grpc.ClientStream } | ||||
|  | ||||
| func (w *wrapStream) Write(d []byte) (int, error) { | ||||
| 	n := len(d) | ||||
| 	err := w.ClientStream.SendMsg(&codec.Frame{Data: d}) | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| func (w wrapCodec) String() string { | ||||
| func (w *wrapStream) Read(d []byte) (int, error) { | ||||
| 	m := &codec.Frame{} | ||||
| 	err := w.ClientStream.RecvMsg(m) | ||||
| 	copy(d, m.Data) | ||||
| 	return len(d), err | ||||
| } | ||||
|  | ||||
| type wrapMicroCodec struct{ codec.Codec } | ||||
|  | ||||
| func (w *wrapMicroCodec) Name() string { | ||||
| 	return w.Codec.String() | ||||
| } | ||||
|  | ||||
| func (w *wrapMicroCodec) Marshal(v interface{}) ([]byte, error) { | ||||
| 	return w.Codec.Marshal(v) | ||||
| } | ||||
|  | ||||
| func (w *wrapMicroCodec) Unmarshal(d []byte, v interface{}) error { | ||||
| 	return w.Codec.Unmarshal(d, v) | ||||
| } | ||||
|  | ||||
| type wrapGrpcCodec struct{ encoding.Codec } | ||||
|  | ||||
| func (w *wrapGrpcCodec) String() string { | ||||
| 	return w.Codec.Name() | ||||
| } | ||||
|  | ||||
| func (w wrapCodec) Marshal(v interface{}) ([]byte, error) { | ||||
| 	switch m := v.(type) { | ||||
| 	case *bytes.Frame: | ||||
| func (w *wrapGrpcCodec) Marshal(v interface{}, opts ...codec.Option) ([]byte, error) { | ||||
| 	if m, ok := v.(*codec.Frame); ok { | ||||
| 		return m.Data, nil | ||||
| 	} | ||||
| 	return w.Codec.Marshal(v) | ||||
| } | ||||
|  | ||||
| func (w wrapCodec) Unmarshal(data []byte, v interface{}) error { | ||||
| 	if len(data) == 0 { | ||||
| func (w *wrapGrpcCodec) Unmarshal(d []byte, v interface{}, opts ...codec.Option) error { | ||||
| 	if d == nil || v == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if v == nil { | ||||
| 	if m, ok := v.(*codec.Frame); ok { | ||||
| 		m.Data = d | ||||
| 		return nil | ||||
| 	} | ||||
| 	switch m := v.(type) { | ||||
| 	case *bytes.Frame: | ||||
| 		m.Data = data | ||||
| 		return nil | ||||
| 	} | ||||
| 	return w.Codec.Unmarshal(data, v) | ||||
| } | ||||
|  | ||||
| func (protoCodec) Marshal(v interface{}) ([]byte, error) { | ||||
| 	switch m := v.(type) { | ||||
| 	case *bytes.Frame: | ||||
| 		return m.Data, nil | ||||
| 	case proto.Message: | ||||
| 		return proto.Marshal(m) | ||||
| 	case oldproto.Message: | ||||
| 		return oldproto.Marshal(m) | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("failed to marshal: %v is not type of *bytes.Frame or proto.Message", v) | ||||
| } | ||||
|  | ||||
| func (protoCodec) Unmarshal(data []byte, v interface{}) error { | ||||
| 	if len(data) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if v == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	switch m := v.(type) { | ||||
| 	case *bytes.Frame: | ||||
| 		m.Data = data | ||||
| 		return nil | ||||
| 	case proto.Message: | ||||
| 		return proto.Unmarshal(data, m) | ||||
| 	case oldproto.Message: | ||||
| 		return oldproto.Unmarshal(data, m) | ||||
| 	} | ||||
| 	return fmt.Errorf("failed to unmarshal: %v is not type of *bytes.Frame or proto.Message", v) | ||||
| } | ||||
|  | ||||
| func (protoCodec) Name() string { | ||||
| 	return "proto" | ||||
| } | ||||
|  | ||||
| func (bytesCodec) Marshal(v interface{}) ([]byte, error) { | ||||
| 	switch m := v.(type) { | ||||
| 	case *[]byte: | ||||
| 		return *m, nil | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("failed to marshal: %v is not type of *[]byte", v) | ||||
| } | ||||
|  | ||||
| func (bytesCodec) Unmarshal(data []byte, v interface{}) error { | ||||
| 	if len(data) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if v == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	switch m := v.(type) { | ||||
| 	case *[]byte: | ||||
| 		*m = data | ||||
| 		return nil | ||||
| 	} | ||||
| 	return fmt.Errorf("failed to unmarshal: %v is not type of *[]byte", v) | ||||
| } | ||||
|  | ||||
| func (bytesCodec) Name() string { | ||||
| 	return "bytes" | ||||
| } | ||||
|  | ||||
| func (jsonCodec) Marshal(v interface{}) ([]byte, error) { | ||||
| 	switch m := v.(type) { | ||||
| 	case *bytes.Frame: | ||||
| 		return m.Data, nil | ||||
| 	case proto.Message: | ||||
| 		return jsonpbMarshaler.Marshal(m) | ||||
| 	case oldproto.Message: | ||||
| 		buf, err := oldjsonpbMarshaler.MarshalToString(m) | ||||
| 		return []byte(buf), err | ||||
| 	} | ||||
|  | ||||
| 	return json.Marshal(v) | ||||
| } | ||||
|  | ||||
| func (jsonCodec) Unmarshal(data []byte, v interface{}) error { | ||||
| 	if len(data) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if v == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	switch m := v.(type) { | ||||
| 	case *bytes.Frame: | ||||
| 		m.Data = data | ||||
| 		return nil | ||||
| 	case proto.Message: | ||||
| 		return jsonpb.Unmarshal(data, m) | ||||
| 	case oldproto.Message: | ||||
| 		return oldjsonpb.Unmarshal(b.NewReader(data), m) | ||||
| 	} | ||||
| 	dec := json.NewDecoder(b.NewReader(data)) | ||||
| 	if useNumber { | ||||
| 		dec.UseNumber() | ||||
| 	} | ||||
| 	return dec.Decode(v) | ||||
| } | ||||
|  | ||||
| func (jsonCodec) Name() string { | ||||
| 	return "json" | ||||
| } | ||||
|  | ||||
| type grpcCodec struct { | ||||
| 	// headers | ||||
| 	id       string | ||||
| 	target   string | ||||
| 	method   string | ||||
| 	endpoint string | ||||
|  | ||||
| 	s grpc.ClientStream | ||||
| 	c encoding.Codec | ||||
| } | ||||
|  | ||||
| func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error { | ||||
| 	md, err := g.s.Header() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if m == nil { | ||||
| 		m = new(codec.Message) | ||||
| 	} | ||||
| 	if m.Header == nil { | ||||
| 		m.Header = make(map[string]string, len(md)) | ||||
| 	} | ||||
| 	for k, v := range md { | ||||
| 		m.Header[k] = strings.Join(v, ",") | ||||
| 	} | ||||
| 	m.Id = g.id | ||||
| 	m.Target = g.target | ||||
| 	m.Method = g.method | ||||
| 	m.Endpoint = g.endpoint | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (g *grpcCodec) ReadBody(v interface{}) error { | ||||
| 	switch m := v.(type) { | ||||
| 	case *bytes.Frame: | ||||
| 		return g.s.RecvMsg(m) | ||||
| 	} | ||||
| 	return g.s.RecvMsg(v) | ||||
| } | ||||
|  | ||||
| func (g *grpcCodec) Write(m *codec.Message, v interface{}) error { | ||||
| 	// if we don't have a body | ||||
| 	if v != nil { | ||||
| 		return g.s.SendMsg(v) | ||||
| 	} | ||||
| 	// write the body using the framing codec | ||||
| 	return g.s.SendMsg(&bytes.Frame{Data: m.Body}) | ||||
| } | ||||
|  | ||||
| func (g *grpcCodec) Close() error { | ||||
| 	return g.s.CloseSend() | ||||
| } | ||||
|  | ||||
| func (g *grpcCodec) String() string { | ||||
| 	return g.c.Name() | ||||
| 	return w.Codec.Unmarshal(d, v) | ||||
| } | ||||
|   | ||||
							
								
								
									
										66
									
								
								codec_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								codec_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| package grpc | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	gmetadata "google.golang.org/grpc/metadata" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| type mockStream struct { | ||||
| 	msg any | ||||
| } | ||||
|  | ||||
| func (m mockStream) Header() (gmetadata.MD, error) { | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
| func (m mockStream) Trailer() gmetadata.MD { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m mockStream) CloseSend() error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m mockStream) Context() context.Context { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *mockStream) SendMsg(msg any) error { | ||||
| 	m.msg = msg | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *mockStream) RecvMsg(msg any) error { | ||||
|  | ||||
| 	c := msg.(*codec.Frame) | ||||
| 	c.Data = m.msg.(*codec.Frame).Data | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func Test_ReadWrap(t *testing.T) { | ||||
|  | ||||
| 	wp := wrapStream{ | ||||
| 		&mockStream{}, | ||||
| 	} | ||||
|  | ||||
| 	write, err := wp.Write([]byte("test_data")) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
| 	if write != 9 { | ||||
| 		t.Error("uncorrected number wrote bytes") | ||||
| 	} | ||||
|  | ||||
| 	b := make([]byte, write) | ||||
| 	read, err := wp.Read(b) | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if read != 9 || string(b) != "test_data" { | ||||
| 		t.Error("uncorrected number wrote bytes or data") | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										40
									
								
								error.go
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								error.go
									
									
									
									
									
								
							| @@ -1,8 +1,7 @@ | ||||
| package grpc | ||||
|  | ||||
| import ( | ||||
| 	pberr "github.com/unistack-org/micro-client-grpc/errors" | ||||
| 	"github.com/unistack-org/micro/v3/errors" | ||||
| 	"go.unistack.org/micro/v3/errors" | ||||
| 	"google.golang.org/grpc/status" | ||||
| ) | ||||
|  | ||||
| @@ -10,35 +9,46 @@ func microError(err error) error { | ||||
| 	// no error | ||||
|  | ||||
| 	if err == nil { | ||||
| 		// nothing to do | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if verr, ok := err.(*errors.Error); ok { | ||||
| 		// micro error | ||||
| 		return verr | ||||
| 	} | ||||
|  | ||||
| 	if verr, ok := err.(*pberr.Error); ok { | ||||
| 		return &errors.Error{Id: verr.Id, Code: verr.Code, Detail: verr.Detail, Status: verr.Status} | ||||
| 	} | ||||
|  | ||||
| 	// grpc error | ||||
| 	s, ok := status.FromError(err) | ||||
| 	if !ok { | ||||
| 		// can't get status detals from grpc error, return base error | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// return first error from details | ||||
| 	if details := s.Details(); len(details) > 0 { | ||||
| 		if verr, ok := details[0].(error); ok { | ||||
| 			return microError(verr) | ||||
| 	details := s.Details() | ||||
| 	switch len(details) { | ||||
| 	case 0: | ||||
| 		if verr := errors.Parse(s.Message()); verr.Code > 0 { | ||||
| 			// return micro error | ||||
| 			return verr | ||||
| 		} | ||||
| 		// return base error as it not micro error | ||||
| 		return err | ||||
| 	case 1: | ||||
| 		if verr, ok := details[0].(*errors.Error); ok { | ||||
| 			// return nested micro error | ||||
| 			return verr | ||||
| 		} | ||||
| 		// return base error as it not holds micro error | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// try to decode micro *errors.Error | ||||
| 	if e := errors.Parse(s.Message()); e.Code > 0 { | ||||
| 		return e // actually a micro error | ||||
| 	// attached messages in details more then 1, try to fallback to micro error | ||||
| 	if verr := errors.Parse(s.Message()); verr.Code > 0 { | ||||
| 		// return micro error | ||||
| 		return verr | ||||
| 	} | ||||
|  | ||||
| 	// fallback | ||||
| 	return errors.InternalServerError("go.micro.client", s.Message()) | ||||
| 	// not micro error return base error | ||||
| 	return err | ||||
| } | ||||
|   | ||||
							
								
								
									
										159
									
								
								errors/errors.go
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								errors/errors.go
									
									
									
									
									
								
							| @@ -1,159 +0,0 @@ | ||||
| package errors | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
|  | ||||
| func (e *Error) Error() string { | ||||
| 	return fmt.Sprintf(`{"id":"%s","code":%d,"detail":"%s","status":"%s"}`, e.Id, e.Code, e.Detail, e.Status) | ||||
| } | ||||
|  | ||||
| // New generates a custom error. | ||||
| func New(id, detail string, code int32) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   code, | ||||
| 		Detail: detail, | ||||
| 		//	Status: http.StatusText(int(code)), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // BadRequest generates a 400 error. | ||||
| func BadRequest(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   400, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//		Status: http.StatusText(400), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Unauthorized generates a 401 error. | ||||
| func Unauthorized(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   401, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//		Status: http.StatusText(401), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Forbidden generates a 403 error. | ||||
| func Forbidden(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   403, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//		Status: http.StatusText(403), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NotFound generates a 404 error. | ||||
| func NotFound(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   404, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//	Status: http.StatusText(404), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // MethodNotAllowed generates a 405 error. | ||||
| func MethodNotAllowed(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   405, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//Status: http.StatusText(405), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Timeout generates a 408 error. | ||||
| func Timeout(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   408, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//Status: http.StatusText(408), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Conflict generates a 409 error. | ||||
| func Conflict(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   409, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//Status: http.StatusText(409), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // InternalServerError generates a 500 error. | ||||
| func InternalServerError(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   500, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//Status: http.StatusText(500), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // NotImplemented generates a 501 error | ||||
| func NotImplemented(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   501, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//Status: http.StatusText(501), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // BadGateway generates a 502 error | ||||
| func BadGateway(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   502, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//	Status: http.StatusText(502), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // ServiceUnavailable generates a 503 error | ||||
| func ServiceUnavailable(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   503, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//Status: http.StatusText(503), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // GatewayTimeout generates a 504 error | ||||
| func GatewayTimeout(id, format string, a ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		Id:     id, | ||||
| 		Code:   504, | ||||
| 		Detail: fmt.Sprintf(format, a...), | ||||
| 		//Status: http.StatusText(504), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Equal tries to compare errors | ||||
| func Equal(err1 error, err2 error) bool { | ||||
| 	verr1, ok1 := err1.(*Error) | ||||
| 	verr2, ok2 := err2.(*Error) | ||||
|  | ||||
| 	if ok1 != ok2 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	if !ok1 { | ||||
| 		return err1 == err2 | ||||
| 	} | ||||
|  | ||||
| 	if verr1.Code != verr2.Code { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	return true | ||||
| } | ||||
| @@ -1,176 +0,0 @@ | ||||
| // Code generated by protoc-gen-go. DO NOT EDIT. | ||||
| // versions: | ||||
| // 	protoc-gen-go v1.25.0-devel | ||||
| // 	protoc        v3.6.1 | ||||
| // source: errors.proto | ||||
|  | ||||
| package errors | ||||
|  | ||||
| import ( | ||||
| 	proto "github.com/golang/protobuf/proto" | ||||
| 	protoreflect "google.golang.org/protobuf/reflect/protoreflect" | ||||
| 	protoimpl "google.golang.org/protobuf/runtime/protoimpl" | ||||
| 	reflect "reflect" | ||||
| 	sync "sync" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// Verify that this generated code is sufficiently up-to-date. | ||||
| 	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) | ||||
| 	// Verify that runtime/protoimpl is sufficiently up-to-date. | ||||
| 	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) | ||||
| ) | ||||
|  | ||||
| // This is a compile-time assertion that a sufficiently up-to-date version | ||||
| // of the legacy proto package is being used. | ||||
| const _ = proto.ProtoPackageIsVersion4 | ||||
|  | ||||
| type Error struct { | ||||
| 	state         protoimpl.MessageState | ||||
| 	sizeCache     protoimpl.SizeCache | ||||
| 	unknownFields protoimpl.UnknownFields | ||||
|  | ||||
| 	Id     string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` | ||||
| 	Code   int32  `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"` | ||||
| 	Detail string `protobuf:"bytes,3,opt,name=detail,proto3" json:"detail,omitempty"` | ||||
| 	Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` | ||||
| } | ||||
|  | ||||
| func (x *Error) Reset() { | ||||
| 	*x = Error{} | ||||
| 	if protoimpl.UnsafeEnabled { | ||||
| 		mi := &file_errors_proto_msgTypes[0] | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		ms.StoreMessageInfo(mi) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (x *Error) String() string { | ||||
| 	return protoimpl.X.MessageStringOf(x) | ||||
| } | ||||
|  | ||||
| func (*Error) ProtoMessage() {} | ||||
|  | ||||
| func (x *Error) ProtoReflect() protoreflect.Message { | ||||
| 	mi := &file_errors_proto_msgTypes[0] | ||||
| 	if protoimpl.UnsafeEnabled && x != nil { | ||||
| 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) | ||||
| 		if ms.LoadMessageInfo() == nil { | ||||
| 			ms.StoreMessageInfo(mi) | ||||
| 		} | ||||
| 		return ms | ||||
| 	} | ||||
| 	return mi.MessageOf(x) | ||||
| } | ||||
|  | ||||
| // Deprecated: Use Error.ProtoReflect.Descriptor instead. | ||||
| func (*Error) Descriptor() ([]byte, []int) { | ||||
| 	return file_errors_proto_rawDescGZIP(), []int{0} | ||||
| } | ||||
|  | ||||
| func (x *Error) GetId() string { | ||||
| 	if x != nil { | ||||
| 		return x.Id | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (x *Error) GetCode() int32 { | ||||
| 	if x != nil { | ||||
| 		return x.Code | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| func (x *Error) GetDetail() string { | ||||
| 	if x != nil { | ||||
| 		return x.Detail | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (x *Error) GetStatus() string { | ||||
| 	if x != nil { | ||||
| 		return x.Status | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| var File_errors_proto protoreflect.FileDescriptor | ||||
|  | ||||
| var file_errors_proto_rawDesc = []byte{ | ||||
| 	0x0a, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x25, | ||||
| 	0x6f, 0x72, 0x67, 0x2e, 0x75, 0x6e, 0x69, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2e, 0x6d, 0x69, 0x63, | ||||
| 	0x72, 0x6f, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x65, | ||||
| 	0x72, 0x72, 0x6f, 0x72, 0x73, 0x22, 0x5b, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x0e, | ||||
| 	0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, | ||||
| 	0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, | ||||
| 	0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x03, 0x20, 0x01, | ||||
| 	0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, | ||||
| 	0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, | ||||
| 	0x75, 0x73, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x3b, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x62, 0x06, | ||||
| 	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	file_errors_proto_rawDescOnce sync.Once | ||||
| 	file_errors_proto_rawDescData = file_errors_proto_rawDesc | ||||
| ) | ||||
|  | ||||
| func file_errors_proto_rawDescGZIP() []byte { | ||||
| 	file_errors_proto_rawDescOnce.Do(func() { | ||||
| 		file_errors_proto_rawDescData = protoimpl.X.CompressGZIP(file_errors_proto_rawDescData) | ||||
| 	}) | ||||
| 	return file_errors_proto_rawDescData | ||||
| } | ||||
|  | ||||
| var file_errors_proto_msgTypes = make([]protoimpl.MessageInfo, 1) | ||||
| var file_errors_proto_goTypes = []interface{}{ | ||||
| 	(*Error)(nil), // 0: org.unistack.micro.client.grpc.errors.Error | ||||
| } | ||||
| var file_errors_proto_depIdxs = []int32{ | ||||
| 	0, // [0:0] is the sub-list for method output_type | ||||
| 	0, // [0:0] is the sub-list for method input_type | ||||
| 	0, // [0:0] is the sub-list for extension type_name | ||||
| 	0, // [0:0] is the sub-list for extension extendee | ||||
| 	0, // [0:0] is the sub-list for field type_name | ||||
| } | ||||
|  | ||||
| func init() { file_errors_proto_init() } | ||||
| func file_errors_proto_init() { | ||||
| 	if File_errors_proto != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	if !protoimpl.UnsafeEnabled { | ||||
| 		file_errors_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { | ||||
| 			switch v := v.(*Error); i { | ||||
| 			case 0: | ||||
| 				return &v.state | ||||
| 			case 1: | ||||
| 				return &v.sizeCache | ||||
| 			case 2: | ||||
| 				return &v.unknownFields | ||||
| 			default: | ||||
| 				return nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	type x struct{} | ||||
| 	out := protoimpl.TypeBuilder{ | ||||
| 		File: protoimpl.DescBuilder{ | ||||
| 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(), | ||||
| 			RawDescriptor: file_errors_proto_rawDesc, | ||||
| 			NumEnums:      0, | ||||
| 			NumMessages:   1, | ||||
| 			NumExtensions: 0, | ||||
| 			NumServices:   0, | ||||
| 		}, | ||||
| 		GoTypes:           file_errors_proto_goTypes, | ||||
| 		DependencyIndexes: file_errors_proto_depIdxs, | ||||
| 		MessageInfos:      file_errors_proto_msgTypes, | ||||
| 	}.Build() | ||||
| 	File_errors_proto = out.File | ||||
| 	file_errors_proto_rawDesc = nil | ||||
| 	file_errors_proto_goTypes = nil | ||||
| 	file_errors_proto_depIdxs = nil | ||||
| } | ||||
| @@ -1,21 +0,0 @@ | ||||
| // Code generated by protoc-gen-micro. DO NOT EDIT. | ||||
| // source: errors.proto | ||||
|  | ||||
| package errors | ||||
|  | ||||
| import ( | ||||
| 	fmt "fmt" | ||||
| 	proto "github.com/golang/protobuf/proto" | ||||
| 	math "math" | ||||
| ) | ||||
|  | ||||
| // Reference imports to suppress errors if they are not otherwise used. | ||||
| var _ = proto.Marshal | ||||
| var _ = fmt.Errorf | ||||
| var _ = math.Inf | ||||
|  | ||||
| // This is a compile-time assertion to ensure that this generated file | ||||
| // is compatible with the proto package it is being compiled against. | ||||
| // A compilation error at this line likely means your copy of the | ||||
| // proto package needs to be updated. | ||||
| const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package | ||||
| @@ -1,11 +0,0 @@ | ||||
| syntax = "proto3"; | ||||
|  | ||||
| option go_package = ".;errors"; | ||||
| package org.unistack.micro.client.grpc.errors; | ||||
|  | ||||
| message Error { | ||||
|   string id = 1; | ||||
|   int32 code = 2; | ||||
|   string detail = 3; | ||||
|   string status = 4; | ||||
| }; | ||||
| @@ -1,3 +0,0 @@ | ||||
| package grpc | ||||
|  | ||||
| //go:generate protoc -I./errors -I. --go-grpc_out=paths=source_relative:./errors --go_out=paths=source_relative:./errors --micro_out=paths=source_relative:./errors errors/errors.proto | ||||
							
								
								
									
										26
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								go.mod
									
									
									
									
									
								
							| @@ -1,15 +1,19 @@ | ||||
| module github.com/unistack-org/micro-client-grpc | ||||
| module go.unistack.org/micro-client-grpc/v3 | ||||
|  | ||||
| go 1.15 | ||||
| go 1.21 | ||||
|  | ||||
| toolchain go1.23.1 | ||||
|  | ||||
| require ( | ||||
| 	github.com/golang/protobuf v1.4.2 | ||||
| 	github.com/google/go-cmp v0.5.1 // indirect | ||||
| 	github.com/unistack-org/micro-codec-bytes v0.0.0-20200828083432-4e49e953d844 | ||||
| 	github.com/unistack-org/micro/v3 v3.0.0-gamma.0.20200920124807-9b11ea527aeb | ||||
| 	golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 // indirect | ||||
| 	golang.org/x/text v0.3.3 // indirect | ||||
| 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect | ||||
| 	google.golang.org/grpc v1.31.1 | ||||
| 	google.golang.org/protobuf v1.25.0 | ||||
| 	go.unistack.org/micro/v3 v3.10.91 | ||||
| 	google.golang.org/grpc v1.67.0 | ||||
| ) | ||||
|  | ||||
| require ( | ||||
| 	go.unistack.org/micro-proto/v3 v3.4.1 // indirect | ||||
| 	golang.org/x/net v0.29.0 // indirect | ||||
| 	golang.org/x/sys v0.25.0 // indirect | ||||
| 	golang.org/x/text v0.18.0 // indirect | ||||
| 	google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect | ||||
| 	google.golang.org/protobuf v1.34.2 // indirect | ||||
| ) | ||||
|   | ||||
							
								
								
									
										489
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										489
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,471 +1,18 @@ | ||||
| cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | ||||
| cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | ||||
| cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= | ||||
| cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= | ||||
| cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= | ||||
| cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= | ||||
| cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= | ||||
| cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= | ||||
| cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= | ||||
| cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= | ||||
| cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= | ||||
| cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= | ||||
| contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= | ||||
| dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= | ||||
| github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= | ||||
| github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= | ||||
| github.com/Azure/go-autorest/autorest v0.5.0/go.mod h1:9HLKlQjVBH6U3oDfsXOeVc56THsLPw1L03yban4xThw= | ||||
| github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= | ||||
| github.com/Azure/go-autorest/autorest/adal v0.2.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= | ||||
| github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM= | ||||
| github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U= | ||||
| github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= | ||||
| github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= | ||||
| github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= | ||||
| github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= | ||||
| github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= | ||||
| github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= | ||||
| github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | ||||
| github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||||
| github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= | ||||
| github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= | ||||
| github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= | ||||
| github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= | ||||
| github.com/akamai/AkamaiOPEN-edgegrid-golang v0.9.0/go.mod h1:zpDJeKyp9ScW4NNrbdr+Eyxvry3ilGPewKoXw3XGN1k= | ||||
| github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | ||||
| github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= | ||||
| github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190808125512-07798873deee/go.mod h1:myCDvQSzCW+wB1WAlocEru4wMGJxy+vlxHdhegi1CDQ= | ||||
| github.com/aliyun/aliyun-oss-go-sdk v0.0.0-20190307165228-86c17b95fcd5/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= | ||||
| github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= | ||||
| github.com/aws/aws-sdk-go v1.23.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= | ||||
| github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc= | ||||
| github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= | ||||
| github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= | ||||
| github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= | ||||
| github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= | ||||
| github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ= | ||||
| github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg= | ||||
| github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= | ||||
| github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= | ||||
| github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||||
| github.com/cloudflare/cloudflare-go v0.10.2/go.mod h1:qhVI5MKwBGhdNU89ZRz2plgYutcJ5PCekLxXn56w6SY= | ||||
| github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= | ||||
| github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok= | ||||
| github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | ||||
| github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= | ||||
| github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= | ||||
| github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | ||||
| github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= | ||||
| github.com/dnaeon/go-vcr v0.0.0-20180814043457-aafff18a5cc2/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= | ||||
| github.com/dnsimple/dnsimple-go v0.30.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg= | ||||
| github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= | ||||
| github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= | ||||
| github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= | ||||
| github.com/ef-ds/deque v1.0.4-0.20190904040645-54cb57c252a1/go.mod h1:HvODWzv6Y6kBf3Ah2WzN1bHjDUezGLaAhwuWVwfpEJs= | ||||
| github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | ||||
| github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | ||||
| github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= | ||||
| github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= | ||||
| github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= | ||||
| github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= | ||||
| github.com/exoscale/egoscale v0.18.1/go.mod h1:Z7OOdzzTOz1Q1PjQXumlz9Wn/CddH0zSYdCF3rnBKXE= | ||||
| github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= | ||||
| github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | ||||
| github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= | ||||
| github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | ||||
| github.com/go-acme/lego/v3 v3.4.0/go.mod h1:xYbLDuxq3Hy4bMUT1t9JIuz6GWIWb3m5X+TeTHYaT7M= | ||||
| github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= | ||||
| github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= | ||||
| github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= | ||||
| github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= | ||||
| github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= | ||||
| github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= | ||||
| github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= | ||||
| github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= | ||||
| github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= | ||||
| github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= | ||||
| github.com/gobwas/ws v1.0.3/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= | ||||
| github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= | ||||
| github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||
| github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= | ||||
| github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= | ||||
| github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||||
| github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | ||||
| github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | ||||
| github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= | ||||
| github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||
| github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||
| github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||
| github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= | ||||
| github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= | ||||
| github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= | ||||
| github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= | ||||
| github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= | ||||
| github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= | ||||
| github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= | ||||
| github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0= | ||||
| github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= | ||||
| github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= | ||||
| github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | ||||
| github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | ||||
| github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | ||||
| github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||
| github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||
| github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/go-cmp v0.5.1 h1:JFrFEBb2xKufg6XkJsJr+WbKb4FQlURi5RUcBveYu9k= | ||||
| github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||||
| github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= | ||||
| github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||||
| github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= | ||||
| github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||||
| github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||||
| github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= | ||||
| github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= | ||||
| github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= | ||||
| github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||
| github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= | ||||
| github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= | ||||
| github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | ||||
| github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= | ||||
| github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | ||||
| github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | ||||
| github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= | ||||
| github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= | ||||
| github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||||
| github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||||
| github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= | ||||
| github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= | ||||
| github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= | ||||
| github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= | ||||
| github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df/go.mod h1:QMZY7/J/KSQEhKWFeDesPjMj+wCHReeknARU3wqlyN4= | ||||
| github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= | ||||
| github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= | ||||
| github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | ||||
| github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | ||||
| github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||
| github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= | ||||
| github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | ||||
| github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= | ||||
| github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | ||||
| github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= | ||||
| github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ= | ||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||||
| github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= | ||||
| github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= | ||||
| github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||||
| github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= | ||||
| github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= | ||||
| github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||
| github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= | ||||
| github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||||
| github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||||
| github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||||
| github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= | ||||
| github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= | ||||
| github.com/linode/linodego v0.10.0/go.mod h1:cziNP7pbvE3mXIPneHj0oRY8L1WtGEIKlZ8LANE4eXA= | ||||
| github.com/liquidweb/liquidweb-go v1.6.0/go.mod h1:UDcVnAMDkZxpw4Y7NOHkqoeiGacVLEIG/i5J9cyixzQ= | ||||
| github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= | ||||
| github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= | ||||
| github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= | ||||
| github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= | ||||
| github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | ||||
| github.com/micro/cli/v2 v2.1.2 h1:43J1lChg/rZCC1rvdqZNFSQDrGT7qfMrtp6/ztpIkEM= | ||||
| github.com/micro/cli/v2 v2.1.2/go.mod h1:EguNh6DAoWKm9nmk+k/Rg0H3lQnDxqzu5x5srOtGtYg= | ||||
| github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= | ||||
| github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= | ||||
| github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM= | ||||
| github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= | ||||
| github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0= | ||||
| github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||||
| github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||
| github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | ||||
| github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | ||||
| github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= | ||||
| github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY4wsPvgQH/jsuJi4XO2ssZbdsIizr4CVC8= | ||||
| github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= | ||||
| github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= | ||||
| github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= | ||||
| github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw= | ||||
| github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ= | ||||
| github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ= | ||||
| github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw= | ||||
| github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= | ||||
| github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | ||||
| github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= | ||||
| github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= | ||||
| github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= | ||||
| github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888= | ||||
| github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ= | ||||
| github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= | ||||
| github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= | ||||
| github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= | ||||
| github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= | ||||
| github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= | ||||
| github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= | ||||
| github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= | ||||
| github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= | ||||
| github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= | ||||
| github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= | ||||
| github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= | ||||
| github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||||
| github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||||
| github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= | ||||
| github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= | ||||
| github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= | ||||
| github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= | ||||
| github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= | ||||
| github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= | ||||
| github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= | ||||
| github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKcyumwBO6qip7RNQ5r77yrssm9bfCowcLEBcU5IA= | ||||
| github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= | ||||
| github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= | ||||
| github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= | ||||
| github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= | ||||
| github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||||
| github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ= | ||||
| github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= | ||||
| github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= | ||||
| github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= | ||||
| github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= | ||||
| github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= | ||||
| github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= | ||||
| github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | ||||
| github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||
| github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||||
| github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= | ||||
| github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= | ||||
| github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY= | ||||
| github.com/transip/gotransip v0.0.0-20190812104329-6d8d9179b66f/go.mod h1:i0f4R4o2HM0m3DZYQWsj6/MEowD57VzoH0v3d7igeFY= | ||||
| github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= | ||||
| github.com/unistack-org/micro-codec-bytes v0.0.0-20200828083432-4e49e953d844 h1:5b1yuSllbsMm/9fUIlIXSr8DbsKT/sAKSCgOx6+SAfI= | ||||
| github.com/unistack-org/micro-codec-bytes v0.0.0-20200828083432-4e49e953d844/go.mod h1:g5sOI8TWgGZiVHe8zoUPdtz7+0oLnqTnfBoai6Qb7jE= | ||||
| github.com/unistack-org/micro-config-cmd v0.0.0-20200909210346-ec89783dc46c/go.mod h1:6pm1cadbwsFcEW1ZbV5Fp0i3goR3TNfROMNSPih3I8k= | ||||
| github.com/unistack-org/micro-config-cmd v0.0.0-20200909210755-6e7e85eeab34/go.mod h1:fT1gYn+TtfVZZ5tNx56bZIncJjmlji66g7GKdWua5hE= | ||||
| github.com/unistack-org/micro/v3 v3.0.0-20200827083227-aa99378adc6e h1:oMUWUSX7pQNdujHQRp4rlDg3+MCah05uYc2+ouz+V2Q= | ||||
| github.com/unistack-org/micro/v3 v3.0.0-20200827083227-aa99378adc6e/go.mod h1:rPQbnry3nboAnMczj8B1Gzlcyv/HYoMZLgd3/3nttJ4= | ||||
| github.com/unistack-org/micro/v3 v3.0.0-gamma.0.20200909210629-caec730248b1/go.mod h1:mmqHR9WelHUXqg2mELjsQ+FJHcWs6mNmXg+wEYO2T3c= | ||||
| github.com/unistack-org/micro/v3 v3.0.0-gamma.0.20200920124807-9b11ea527aeb h1:ETCShJ27nTE7kMQgaf7S6p1Tbfr2tdGO6MYxZ2LTMWY= | ||||
| github.com/unistack-org/micro/v3 v3.0.0-gamma.0.20200920124807-9b11ea527aeb/go.mod h1:HUzMG4Mcy97958VxWTg8zuazZgwQ/aoLZ8wtBVONwRE= | ||||
| github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= | ||||
| github.com/vultr/govultr v0.1.4/go.mod h1:9H008Uxr/C4vFNGLqKx232C206GL0PBHzOP0809bGNA= | ||||
| github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= | ||||
| github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= | ||||
| github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= | ||||
| go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= | ||||
| go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= | ||||
| go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= | ||||
| go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= | ||||
| go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= | ||||
| go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277/go.mod h1:2X8KaoNd1J0lZV+PxJk/5+DGbO/tpwLR1m++a7FnB/Y= | ||||
| golang.org/x/crypto v0.0.0-20180621125126-a49355c7e3f8/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||
| golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= | ||||
| golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||||
| golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||||
| golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | ||||
| golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= | ||||
| golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= | ||||
| golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | ||||
| golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | ||||
| golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||||
| golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= | ||||
| golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||||
| golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | ||||
| golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | ||||
| golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | ||||
| golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= | ||||
| golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= | ||||
| golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= | ||||
| golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= | ||||
| golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= | ||||
| golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= | ||||
| golang.org/x/net v0.0.0-20180611182652-db08ff08e862/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= | ||||
| golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU= | ||||
| golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= | ||||
| golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= | ||||
| golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= | ||||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||||
| golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||
| golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw= | ||||
| golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | ||||
| golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= | ||||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/time v0.0.0-20190921001708-c4c64cad1fd0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||
| golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= | ||||
| golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||||
| golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||||
| golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||||
| golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||||
| golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= | ||||
| golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= | ||||
| golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= | ||||
| golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||||
| golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||||
| golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||||
| golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||
| golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||
| golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||
| golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||
| golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||||
| golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= | ||||
| golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= | ||||
| golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= | ||||
| google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= | ||||
| google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= | ||||
| google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= | ||||
| google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= | ||||
| google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= | ||||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||||
| google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||||
| google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||||
| google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= | ||||
| google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | ||||
| google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||||
| google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||||
| google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||||
| google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= | ||||
| google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= | ||||
| google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= | ||||
| google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= | ||||
| google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= | ||||
| google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= | ||||
| google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= | ||||
| google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d h1:92D1fum1bJLKSdr11OJ+54YeCMCGYIygTA7R/YZxH5M= | ||||
| google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= | ||||
| google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= | ||||
| google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | ||||
| google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | ||||
| google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= | ||||
| google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | ||||
| google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= | ||||
| google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= | ||||
| google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= | ||||
| google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs= | ||||
| google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= | ||||
| google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= | ||||
| google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= | ||||
| google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= | ||||
| google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= | ||||
| google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= | ||||
| google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= | ||||
| google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= | ||||
| google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= | ||||
| google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= | ||||
| google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= | ||||
| google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= | ||||
| gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= | ||||
| gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= | ||||
| gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= | ||||
| gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | ||||
| gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= | ||||
| gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | ||||
| gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | ||||
| gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw= | ||||
| gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc= | ||||
| gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= | ||||
| gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= | ||||
| gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= | ||||
| gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | ||||
| gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= | ||||
| gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||
| gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||
| gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | ||||
| gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||
| honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
| honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
| honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
| honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
| honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||
| honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= | ||||
| rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= | ||||
| github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= | ||||
| github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | ||||
| go.unistack.org/micro-proto/v3 v3.4.1 h1:UTjLSRz2YZuaHk9iSlVqqsA50JQNAEK2ZFboGqtEa9Q= | ||||
| go.unistack.org/micro-proto/v3 v3.4.1/go.mod h1:okx/cnOhzuCX0ggl/vToatbCupi0O44diiiLLsZ93Zo= | ||||
| go.unistack.org/micro/v3 v3.10.91 h1:vuJY4tXwpqimwIkEJ3TozMYNVQQs+C5QMlQWPgSY/YM= | ||||
| go.unistack.org/micro/v3 v3.10.91/go.mod h1:erMgt3Bl7vQQ0e9UpQyR5NlLiZ9pKeEJ9+1tfYFaqUg= | ||||
| golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= | ||||
| golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= | ||||
| golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= | ||||
| golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | ||||
| golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= | ||||
| golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= | ||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= | ||||
| google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= | ||||
| google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw= | ||||
| google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= | ||||
| google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= | ||||
| google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= | ||||
|   | ||||
							
								
								
									
										621
									
								
								grpc.go
									
									
									
									
									
								
							
							
						
						
									
										621
									
								
								grpc.go
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| // Package grpc provides a gRPC client | ||||
| // Package grpc provides a gRPC client for micro framework | ||||
| package grpc | ||||
|  | ||||
| import ( | ||||
| @@ -6,52 +6,57 @@ import ( | ||||
| 	"crypto/tls" | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"time" | ||||
|  | ||||
| 	raw "github.com/unistack-org/micro-codec-bytes" | ||||
| 	"github.com/unistack-org/micro/v3/broker" | ||||
| 	"github.com/unistack-org/micro/v3/client" | ||||
| 	"github.com/unistack-org/micro/v3/errors" | ||||
| 	"github.com/unistack-org/micro/v3/metadata" | ||||
|  | ||||
| 	"go.unistack.org/micro/v3/broker" | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/errors" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"go.unistack.org/micro/v3/options" | ||||
| 	"go.unistack.org/micro/v3/selector" | ||||
| 	"go.unistack.org/micro/v3/semconv" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"google.golang.org/grpc" | ||||
| 	"google.golang.org/grpc/codes" | ||||
| 	"google.golang.org/grpc/credentials" | ||||
| 	"google.golang.org/grpc/credentials/insecure" | ||||
| 	"google.golang.org/grpc/encoding" | ||||
| 	gmetadata "google.golang.org/grpc/metadata" | ||||
| 	"google.golang.org/grpc/status" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	DefaultContentType = "application/grpc" | ||||
| ) | ||||
|  | ||||
| type grpcClient struct { | ||||
| 	opts   client.Options | ||||
| 	codecs map[string]encoding.Codec | ||||
| 	pool   *pool | ||||
| 	once   atomic.Value | ||||
| 	funcPublish      client.FuncPublish | ||||
| 	funcBatchPublish client.FuncBatchPublish | ||||
| 	funcCall         client.FuncCall | ||||
| 	funcStream       client.FuncStream | ||||
| 	pool             *ConnPool | ||||
| 	opts             client.Options | ||||
| 	sync.RWMutex | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	encoding.RegisterCodec(wrapCodec{jsonCodec{}}) | ||||
| 	encoding.RegisterCodec(wrapCodec{protoCodec{}}) | ||||
| 	encoding.RegisterCodec(wrapCodec{bytesCodec{}}) | ||||
| 	init bool | ||||
| } | ||||
|  | ||||
| // secure returns the dial option for whether its a secure or insecure connection | ||||
| func (g *grpcClient) secure(addr string) grpc.DialOption { | ||||
| 	// first we check if theres'a  tls config | ||||
| 	if g.opts.Context != nil { | ||||
| 		if v := g.opts.Context.Value(tlsAuth{}); v != nil { | ||||
| 			tls := v.(*tls.Config) | ||||
| 			creds := credentials.NewTLS(tls) | ||||
| 			// return tls config if it exists | ||||
| 			return grpc.WithTransportCredentials(creds) | ||||
| 		} | ||||
| 	if g.opts.TLSConfig != nil { | ||||
| 		creds := credentials.NewTLS(g.opts.TLSConfig) | ||||
| 		// return tls config if it exists | ||||
| 		return grpc.WithTransportCredentials(creds) | ||||
| 	} | ||||
|  | ||||
| 	// default config | ||||
| 	tlsConfig := &tls.Config{} | ||||
| 	tlsConfig := &tls.Config{MinVersion: tls.VersionTLS12} | ||||
| 	defaultCreds := grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)) | ||||
|  | ||||
| 	// check if the address is prepended with https | ||||
| @@ -69,37 +74,41 @@ func (g *grpcClient) secure(addr string) grpc.DialOption { | ||||
| 	} | ||||
|  | ||||
| 	// other fallback to insecure | ||||
| 	return grpc.WithInsecure() | ||||
| 	return grpc.WithTransportCredentials(insecure.NewCredentials()) | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) call(ctx context.Context, addr string, req client.Request, rsp interface{}, opts client.CallOptions) error { | ||||
| 	var header map[string]string | ||||
|  | ||||
| 	header = make(map[string]string) | ||||
| 	if md, ok := metadata.FromContext(ctx); ok { | ||||
| 	if md, ok := metadata.FromOutgoingContext(ctx); ok { | ||||
| 		header = make(map[string]string, len(md)) | ||||
| 		for k, v := range md { | ||||
| 			header[strings.ToLower(k)] = v | ||||
| 		} | ||||
| 	} else { | ||||
| 		header = make(map[string]string) | ||||
| 		header = make(map[string]string, 2) | ||||
| 	} | ||||
| 	if opts.RequestMetadata != nil { | ||||
| 		for k, v := range opts.RequestMetadata { | ||||
| 			header[k] = v | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// set timeout in nanoseconds | ||||
| 	header["timeout"] = fmt.Sprintf("%d", opts.RequestTimeout) | ||||
| 	// set the content type for the request | ||||
| 	header["x-content-type"] = req.ContentType() | ||||
| 	header["Grpc-Timeout"] = fmt.Sprintf("%dn", opts.RequestTimeout) | ||||
| 	header["timeout"] = fmt.Sprintf("%dn", opts.RequestTimeout) | ||||
| 	header["content-type"] = req.ContentType() | ||||
|  | ||||
| 	md := gmetadata.New(header) | ||||
| 	ctx = gmetadata.NewOutgoingContext(ctx, md) | ||||
|  | ||||
| 	cf, err := g.newGRPCCodec(req.ContentType()) | ||||
| 	cf, err := g.newCodec(req.ContentType()) | ||||
| 	if err != nil { | ||||
| 		return errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 		return errors.InternalServerError("go.micro.client", "%+v", err) | ||||
| 	} | ||||
|  | ||||
| 	maxRecvMsgSize := g.maxRecvMsgSizeValue() | ||||
| 	maxSendMsgSize := g.maxSendMsgSizeValue() | ||||
| 	cfgService := g.serviceConfig() | ||||
|  | ||||
| 	var grr error | ||||
|  | ||||
| @@ -118,30 +127,50 @@ func (g *grpcClient) call(ctx context.Context, addr string, req client.Request, | ||||
| 			grpc.MaxCallRecvMsgSize(maxRecvMsgSize), | ||||
| 			grpc.MaxCallSendMsgSize(maxSendMsgSize), | ||||
| 		), | ||||
| 		grpc.WithDefaultServiceConfig(cfgService), | ||||
| 	} | ||||
|  | ||||
| 	if opts := g.getGrpcDialOptions(); opts != nil { | ||||
| 	if opts := g.getGrpcDialOptions(g.opts.Context); opts != nil { | ||||
| 		grpcDialOptions = append(grpcDialOptions, opts...) | ||||
| 	} | ||||
| 	if opts := g.getGrpcDialOptions(opts.Context); opts != nil { | ||||
| 		grpcDialOptions = append(grpcDialOptions, opts...) | ||||
| 	} | ||||
|  | ||||
| 	cc, err := g.pool.getConn(dialCtx, addr, grpcDialOptions...) | ||||
| 	contextDialer := g.opts.ContextDialer | ||||
| 	if opts.ContextDialer != nil { | ||||
| 		contextDialer = opts.ContextDialer | ||||
| 	} | ||||
| 	if contextDialer != nil { | ||||
| 		grpcDialOptions = append(grpcDialOptions, grpc.WithContextDialer(contextDialer)) | ||||
| 	} | ||||
|  | ||||
| 	cc, err := g.pool.Get(dialCtx, addr, grpcDialOptions...) | ||||
| 	if err != nil { | ||||
| 		return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) | ||||
| 		return errors.InternalServerError("go.micro.client", "Error sending request: %v", err) | ||||
| 	} | ||||
| 	defer func() { | ||||
| 		// defer execution of release | ||||
| 		g.pool.release(addr, cc, grr) | ||||
| 		g.pool.Put(cc, grr) | ||||
| 	}() | ||||
|  | ||||
| 	ch := make(chan error, 1) | ||||
| 	var gmd gmetadata.MD | ||||
|  | ||||
| 	grpcCallOptions := []grpc.CallOption{ | ||||
| 		grpc.CallContentSubtype((&wrapMicroCodec{cf}).Name()), | ||||
| 	} | ||||
|  | ||||
| 	if opts := g.getGrpcCallOptions(opts.Context); opts != nil { | ||||
| 		grpcCallOptions = append(grpcCallOptions, opts...) | ||||
| 	} | ||||
|  | ||||
| 	if opts.ResponseMetadata != nil { | ||||
| 		gmd = gmetadata.MD{} | ||||
| 		grpcCallOptions = append(grpcCallOptions, grpc.Header(&gmd)) | ||||
| 	} | ||||
|  | ||||
| 	go func() { | ||||
| 		grpcCallOptions := []grpc.CallOption{ | ||||
| 			grpc.ForceCodec(cf), | ||||
| 			grpc.CallContentSubtype(cf.Name())} | ||||
| 		if opts := g.getGrpcCallOptions(); opts != nil { | ||||
| 			grpcCallOptions = append(grpcCallOptions, opts...) | ||||
| 		} | ||||
| 		err := cc.Invoke(ctx, methodToGRPC(req.Service(), req.Endpoint()), req.Body(), rsp, grpcCallOptions...) | ||||
| 		ch <- microError(err) | ||||
| 	}() | ||||
| @@ -153,13 +182,20 @@ func (g *grpcClient) call(ctx context.Context, addr string, req client.Request, | ||||
| 		grr = errors.Timeout("go.micro.client", "%v", ctx.Err()) | ||||
| 	} | ||||
|  | ||||
| 	if opts.ResponseMetadata != nil { | ||||
| 		*opts.ResponseMetadata = metadata.New(gmd.Len()) | ||||
| 		for k, v := range gmd { | ||||
| 			opts.ResponseMetadata.Set(k, strings.Join(v, ",")) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return grr | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request, rsp interface{}, opts client.CallOptions) error { | ||||
| 	var header map[string]string | ||||
|  | ||||
| 	if md, ok := metadata.FromContext(ctx); ok { | ||||
| 	if md, ok := metadata.FromOutgoingContext(ctx); ok { | ||||
| 		header = make(map[string]string, len(md)) | ||||
| 		for k, v := range md { | ||||
| 			header[k] = v | ||||
| @@ -170,17 +206,18 @@ func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request | ||||
|  | ||||
| 	// set timeout in nanoseconds | ||||
| 	if opts.StreamTimeout > time.Duration(0) { | ||||
| 		header["timeout"] = fmt.Sprintf("%d", opts.StreamTimeout) | ||||
| 		header["Grpc-Timeout"] = fmt.Sprintf("%dn", opts.StreamTimeout) | ||||
| 		header["timeout"] = fmt.Sprintf("%dn", opts.StreamTimeout) | ||||
| 	} | ||||
| 	// set the content type for the request | ||||
| 	header["x-content-type"] = req.ContentType() | ||||
| 	header["content-type"] = req.ContentType() | ||||
|  | ||||
| 	md := gmetadata.New(header) | ||||
| 	ctx = gmetadata.NewOutgoingContext(ctx, md) | ||||
|  | ||||
| 	cf, err := g.newGRPCCodec(req.ContentType()) | ||||
| 	cf, err := g.newCodec(req.ContentType()) | ||||
| 	if err != nil { | ||||
| 		return errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 		return errors.InternalServerError("go.micro.client", "%+v", err) | ||||
| 	} | ||||
|  | ||||
| 	var dialCtx context.Context | ||||
| @@ -192,19 +229,36 @@ func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request | ||||
| 	} | ||||
| 	defer cancel() | ||||
|  | ||||
| 	wc := wrapCodec{cf} | ||||
| 	wc := &wrapMicroCodec{cf} | ||||
|  | ||||
| 	maxRecvMsgSize := g.maxRecvMsgSizeValue() | ||||
| 	maxSendMsgSize := g.maxSendMsgSizeValue() | ||||
| 	cfgService := g.serviceConfig() | ||||
|  | ||||
| 	grpcDialOptions := []grpc.DialOption{ | ||||
| 		g.secure(addr), | ||||
| 		grpc.WithDefaultCallOptions( | ||||
| 			grpc.MaxCallRecvMsgSize(maxRecvMsgSize), | ||||
| 			grpc.MaxCallSendMsgSize(maxSendMsgSize), | ||||
| 		), | ||||
| 		grpc.WithDefaultServiceConfig(cfgService), | ||||
| 	} | ||||
|  | ||||
| 	if opts := g.getGrpcDialOptions(); opts != nil { | ||||
| 	if opts := g.getGrpcDialOptions(opts.Context); opts != nil { | ||||
| 		grpcDialOptions = append(grpcDialOptions, opts...) | ||||
| 	} | ||||
|  | ||||
| 	cc, err := g.pool.getConn(dialCtx, addr, grpcDialOptions...) | ||||
| 	contextDialer := g.opts.ContextDialer | ||||
| 	if opts.ContextDialer != nil { | ||||
| 		contextDialer = opts.ContextDialer | ||||
| 	} | ||||
| 	if contextDialer != nil { | ||||
| 		grpcDialOptions = append(grpcDialOptions, grpc.WithContextDialer(contextDialer)) | ||||
| 	} | ||||
|  | ||||
| 	cc, err := g.pool.Get(dialCtx, addr, grpcDialOptions...) | ||||
| 	if err != nil { | ||||
| 		return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) | ||||
| 		return errors.InternalServerError("go.micro.client", "Error sending request: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	desc := &grpc.StreamDesc{ | ||||
| @@ -214,12 +268,17 @@ func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request | ||||
| 	} | ||||
|  | ||||
| 	grpcCallOptions := []grpc.CallOption{ | ||||
| 		grpc.ForceCodec(wc), | ||||
| 		grpc.CallContentSubtype(cf.Name()), | ||||
| 		// grpc.ForceCodec(wc), | ||||
| 		grpc.CallContentSubtype(wc.Name()), | ||||
| 	} | ||||
| 	if opts := g.getGrpcCallOptions(); opts != nil { | ||||
| 	if opts := g.getGrpcCallOptions(opts.Context); opts != nil { | ||||
| 		grpcCallOptions = append(grpcCallOptions, opts...) | ||||
| 	} | ||||
| 	var gmd gmetadata.MD | ||||
| 	if opts.ResponseMetadata != nil { | ||||
| 		gmd = gmetadata.MD{} | ||||
| 		grpcCallOptions = append(grpcCallOptions, grpc.Header(&gmd)) | ||||
| 	} | ||||
|  | ||||
| 	// create a new cancelling context | ||||
| 	newCtx, cancel := context.WithCancel(ctx) | ||||
| @@ -230,19 +289,14 @@ func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request | ||||
| 		// cancel the context | ||||
| 		cancel() | ||||
| 		// release the connection | ||||
| 		g.pool.release(addr, cc, err) | ||||
| 		g.pool.Put(cc, err) | ||||
| 		// now return the error | ||||
| 		return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err)) | ||||
| 	} | ||||
|  | ||||
| 	codec := &grpcCodec{ | ||||
| 		s: st, | ||||
| 		c: wc, | ||||
| 		return errors.InternalServerError("go.micro.client", "Error creating stream: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// set request codec | ||||
| 	if r, ok := req.(*grpcRequest); ok { | ||||
| 		r.codec = codec | ||||
| 		r.codec = cf | ||||
| 	} | ||||
|  | ||||
| 	// setup the stream response | ||||
| @@ -254,23 +308,23 @@ func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request | ||||
| 			conn:   cc, | ||||
| 			stream: st, | ||||
| 			codec:  cf, | ||||
| 			gcodec: codec, | ||||
| 		}, | ||||
| 		conn: cc, | ||||
| 		close: func(err error) { | ||||
| 			// cancel the context if an error occured | ||||
| 			// cancel the context if an error occurred | ||||
| 			if err != nil { | ||||
| 				cancel() | ||||
| 			} | ||||
|  | ||||
| 			// defer execution of release | ||||
| 			g.pool.release(addr, cc, err) | ||||
| 			g.pool.Put(cc, err) | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	// set the stream as the response | ||||
| 	val := reflect.ValueOf(rsp).Elem() | ||||
| 	val.Set(reflect.ValueOf(stream).Elem()) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -318,17 +372,35 @@ func (g *grpcClient) maxSendMsgSizeValue() int { | ||||
| 	return v.(int) | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) newGRPCCodec(contentType string) (encoding.Codec, error) { | ||||
| func (g *grpcClient) newCodec(ct string) (codec.Codec, error) { | ||||
| 	g.RLock() | ||||
| 	defer g.RUnlock() | ||||
|  | ||||
| 	if c, ok := g.codecs[contentType]; ok { | ||||
| 		return wrapCodec{c}, nil | ||||
| 	if idx := strings.IndexRune(ct, ';'); idx >= 0 { | ||||
| 		ct = ct[:idx] | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType) | ||||
|  | ||||
| 	if c, ok := g.opts.Codecs[ct]; ok { | ||||
| 		return c, nil | ||||
| 	} | ||||
| 	return nil, codec.ErrUnknownContentType | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) serviceConfig() string { | ||||
| 	if g.opts.Context == nil { | ||||
| 		return DefaultServiceConfig | ||||
| 	} | ||||
| 	v := g.opts.Context.Value(serviceConfigKey{}) | ||||
| 	if v == nil { | ||||
| 		return DefaultServiceConfig | ||||
| 	} | ||||
| 	return v.(string) | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) Init(opts ...client.Option) error { | ||||
| 	if len(opts) == 0 && g.init { | ||||
| 		return nil | ||||
| 	} | ||||
| 	size := g.opts.PoolSize | ||||
| 	ttl := g.opts.PoolTTL | ||||
|  | ||||
| @@ -344,6 +416,24 @@ func (g *grpcClient) Init(opts ...client.Option) error { | ||||
| 		g.pool.Unlock() | ||||
| 	} | ||||
|  | ||||
| 	g.funcCall = g.fnCall | ||||
| 	g.funcStream = g.fnStream | ||||
| 	g.funcPublish = g.fnPublish | ||||
| 	g.funcBatchPublish = g.fnBatchPublish | ||||
|  | ||||
| 	g.opts.Hooks.EachPrev(func(hook options.Hook) { | ||||
| 		switch h := hook.(type) { | ||||
| 		case client.HookCall: | ||||
| 			g.funcCall = h(g.funcCall) | ||||
| 		case client.HookStream: | ||||
| 			g.funcStream = h(g.funcStream) | ||||
| 		case client.HookPublish: | ||||
| 			g.funcPublish = h(g.funcPublish) | ||||
| 		case client.HookBatchPublish: | ||||
| 			g.funcBatchPublish = h(g.funcBatchPublish) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -365,8 +455,35 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface | ||||
| 	} else if rsp == nil { | ||||
| 		return errors.InternalServerError("go.micro.client", "rsp is nil") | ||||
| 	} | ||||
|  | ||||
| 	ts := time.Now() | ||||
| 	g.opts.Meter.Counter(semconv.ClientRequestInflight, "endpoint", req.Endpoint()).Inc() | ||||
| 	var sp tracer.Span | ||||
| 	ctx, sp = g.opts.Tracer.Start(ctx, req.Endpoint()+" rpc-client", | ||||
| 		tracer.WithSpanKind(tracer.SpanKindClient), | ||||
| 		tracer.WithSpanLabels("endpoint", req.Endpoint()), | ||||
| 	) | ||||
| 	err := g.funcCall(ctx, req, rsp, opts...) | ||||
| 	g.opts.Meter.Counter(semconv.ClientRequestInflight, "endpoint", req.Endpoint()).Dec() | ||||
| 	te := time.Since(ts) | ||||
| 	g.opts.Meter.Summary(semconv.ClientRequestLatencyMicroseconds, "endpoint", req.Endpoint()).Update(te.Seconds()) | ||||
| 	g.opts.Meter.Histogram(semconv.ClientRequestDurationSeconds, "endpoint", req.Endpoint()).Update(te.Seconds()) | ||||
|  | ||||
| 	if me := errors.FromError(err); me == nil { | ||||
| 		sp.Finish() | ||||
| 		g.opts.Meter.Counter(semconv.ClientRequestTotal, "endpoint", req.Endpoint(), "status", "success", "code", strconv.Itoa(int(200))).Inc() | ||||
| 	} else { | ||||
| 		sp.SetStatus(tracer.SpanStatusError, err.Error()) | ||||
| 		g.opts.Meter.Counter(semconv.ClientRequestTotal, "endpoint", req.Endpoint(), "status", "failure", "code", strconv.Itoa(int(me.Code))).Inc() | ||||
| 	} | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) fnCall(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error { | ||||
| 	// make a copy of call opts | ||||
| 	callOpts := g.opts.CallOptions | ||||
|  | ||||
| 	for _, opt := range opts { | ||||
| 		opt(&callOpts) | ||||
| 	} | ||||
| @@ -395,11 +512,6 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface | ||||
| 	// make copy of call method | ||||
| 	gcall := g.call | ||||
|  | ||||
| 	// wrap the call in reverse | ||||
| 	for i := len(callOpts.CallWrappers); i > 0; i-- { | ||||
| 		gcall = callOpts.CallWrappers[i-1](gcall) | ||||
| 	} | ||||
|  | ||||
| 	// use the router passed as a call option, or fallback to the rpc clients router | ||||
| 	if callOpts.Router == nil { | ||||
| 		callOpts.Router = g.opts.Router | ||||
| @@ -415,25 +527,13 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface | ||||
| 		callOpts.Address = []string{g.opts.Proxy} | ||||
| 	} | ||||
|  | ||||
| 	// lookup the route to send the reques to | ||||
| 	// TODO apply any filtering here | ||||
| 	routes, err := g.opts.Lookup(ctx, req, callOpts) | ||||
| 	if err != nil { | ||||
| 		return errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 	} | ||||
| 	var next selector.Next | ||||
|  | ||||
| 	// balance the list of nodes | ||||
| 	next, err := callOpts.Selector.Select(routes) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// return errors.New("go.micro.client", "request timeout", 408) | ||||
| 	call := func(i int) error { | ||||
| 		// call backoff first. Someone may want an initial start delay | ||||
| 		t, err := callOpts.Backoff(ctx, req, i) | ||||
| 		if err != nil { | ||||
| 			return errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 			return errors.InternalServerError("go.micro.client", "%+v", err) | ||||
| 		} | ||||
|  | ||||
| 		// only sleep if greater than 0 | ||||
| @@ -441,6 +541,23 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface | ||||
| 			time.Sleep(t) | ||||
| 		} | ||||
|  | ||||
| 		if next == nil { | ||||
| 			var routes []string | ||||
|  | ||||
| 			// lookup the route to send the reques to | ||||
| 			// TODO apply any filtering here | ||||
| 			routes, err = g.opts.Lookup(ctx, req, callOpts) | ||||
| 			if err != nil { | ||||
| 				return errors.InternalServerError("go.micro.client", "%+v", err) | ||||
| 			} | ||||
|  | ||||
| 			// balance the list of nodes | ||||
| 			next, err = callOpts.Selector.Select(routes) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// get the next node | ||||
| 		node := next() | ||||
|  | ||||
| @@ -494,6 +611,31 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) { | ||||
| 	ts := time.Now() | ||||
| 	g.opts.Meter.Counter(semconv.ClientRequestInflight, "endpoint", req.Endpoint()).Inc() | ||||
| 	var sp tracer.Span | ||||
| 	ctx, sp = g.opts.Tracer.Start(ctx, req.Endpoint()+" rpc-client", | ||||
| 		tracer.WithSpanKind(tracer.SpanKindClient), | ||||
| 		tracer.WithSpanLabels("endpoint", req.Endpoint()), | ||||
| 	) | ||||
| 	stream, err := g.funcStream(ctx, req, opts...) | ||||
| 	g.opts.Meter.Counter(semconv.ClientRequestInflight, "endpoint", req.Endpoint()).Dec() | ||||
| 	te := time.Since(ts) | ||||
| 	g.opts.Meter.Summary(semconv.ClientRequestLatencyMicroseconds, "endpoint", req.Endpoint()).Update(te.Seconds()) | ||||
| 	g.opts.Meter.Histogram(semconv.ClientRequestDurationSeconds, "endpoint", req.Endpoint()).Update(te.Seconds()) | ||||
|  | ||||
| 	if me := status.Convert(err); me == nil { | ||||
| 		sp.Finish() | ||||
| 		g.opts.Meter.Counter(semconv.ClientRequestTotal, "endpoint", req.Endpoint(), "status", "success", "code", strconv.Itoa(int(codes.OK))).Inc() | ||||
| 	} else { | ||||
| 		sp.SetStatus(tracer.SpanStatusError, err.Error()) | ||||
| 		g.opts.Meter.Counter(semconv.ClientRequestTotal, "endpoint", req.Endpoint(), "status", "failure", "code", strconv.Itoa(int(me.Code()))).Inc() | ||||
| 	} | ||||
|  | ||||
| 	return stream, err | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) fnStream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) { | ||||
| 	// make a copy of call opts | ||||
| 	callOpts := g.opts.CallOptions | ||||
| 	for _, opt := range opts { | ||||
| @@ -512,11 +654,6 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli | ||||
| 	// make a copy of stream | ||||
| 	gstream := g.stream | ||||
|  | ||||
| 	// wrap the call in reverse | ||||
| 	for i := len(callOpts.CallWrappers); i > 0; i-- { | ||||
| 		gstream = callOpts.CallWrappers[i-1](gstream) | ||||
| 	} | ||||
|  | ||||
| 	// use the router passed as a call option, or fallback to the rpc clients router | ||||
| 	if callOpts.Router == nil { | ||||
| 		callOpts.Router = g.opts.Router | ||||
| @@ -532,24 +669,13 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli | ||||
| 		callOpts.Address = []string{g.opts.Proxy} | ||||
| 	} | ||||
|  | ||||
| 	// lookup the route to send the reques to | ||||
| 	// TODO: move to internal lookup func | ||||
| 	routes, err := g.opts.Lookup(ctx, req, callOpts) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	// balance the list of nodes | ||||
| 	next, err := callOpts.Selector.Select(routes) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var next selector.Next | ||||
|  | ||||
| 	call := func(i int) (client.Stream, error) { | ||||
| 		// call backoff first. Someone may want an initial start delay | ||||
| 		t, err := callOpts.Backoff(ctx, req, i) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 			return nil, errors.InternalServerError("go.micro.client", "%+v", err) | ||||
| 		} | ||||
|  | ||||
| 		// only sleep if greater than 0 | ||||
| @@ -557,12 +683,29 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli | ||||
| 			time.Sleep(t) | ||||
| 		} | ||||
|  | ||||
| 		if next == nil { | ||||
| 			var routes []string | ||||
|  | ||||
| 			// lookup the route to send the reques to | ||||
| 			// TODO apply any filtering here | ||||
| 			routes, err = g.opts.Lookup(ctx, req, callOpts) | ||||
| 			if err != nil { | ||||
| 				return nil, errors.InternalServerError("go.micro.client", "%+v", err) | ||||
| 			} | ||||
|  | ||||
| 			// balance the list of nodes | ||||
| 			next, err = callOpts.Selector.Select(routes) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// get the next node | ||||
| 		node := next() | ||||
|  | ||||
| 		// make the call | ||||
| 		stream := &grpcStream{} | ||||
| 		err = g.stream(ctx, node, req, stream, callOpts) | ||||
| 		err = gstream(ctx, node, req, stream, callOpts) | ||||
|  | ||||
| 		// record the result of the call to inform future routing decisions | ||||
| 		if verr := g.opts.Selector.Record(node, err); verr != nil { | ||||
| @@ -574,7 +717,10 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli | ||||
| 			return nil, verr | ||||
| 		} | ||||
|  | ||||
| 		g.opts.Selector.Record(node, err) | ||||
| 		if rerr := g.opts.Selector.Record(node, err); rerr != nil { | ||||
| 			return nil, rerr | ||||
| 		} | ||||
|  | ||||
| 		return stream, err | ||||
| 	} | ||||
|  | ||||
| @@ -617,145 +763,164 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli | ||||
| 	return nil, grr | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) BatchPublish(ctx context.Context, ps []client.Message, opts ...client.PublishOption) error { | ||||
| 	return g.funcBatchPublish(ctx, ps, opts...) | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) fnBatchPublish(ctx context.Context, ps []client.Message, opts ...client.PublishOption) error { | ||||
| 	return g.publish(ctx, ps, opts...) | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error { | ||||
| 	var options client.PublishOptions | ||||
| 	return g.funcPublish(ctx, p, opts...) | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) fnPublish(ctx context.Context, p client.Message, opts ...client.PublishOption) error { | ||||
| 	return g.publish(ctx, []client.Message{p}, opts...) | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) publish(ctx context.Context, ps []client.Message, opts ...client.PublishOption) error { | ||||
| 	var body []byte | ||||
|  | ||||
| 	// fail early on connect error | ||||
| 	if !g.once.Load().(bool) { | ||||
| 		if err := g.opts.Broker.Connect(); err != nil { | ||||
| 			return errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 		} | ||||
| 		g.once.Store(true) | ||||
| 	options := client.NewPublishOptions(opts...) | ||||
|  | ||||
| 	// get proxy | ||||
| 	exchange := "" | ||||
| 	if v, ok := os.LookupEnv("MICRO_PROXY"); ok { | ||||
| 		exchange = v | ||||
| 	} | ||||
|  | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| 	} | ||||
|  | ||||
| 	md, ok := metadata.FromContext(ctx) | ||||
| 	if !ok { | ||||
| 		md = make(map[string]string) | ||||
| 	} | ||||
| 	md["Content-Type"] = p.ContentType() | ||||
| 	md["Micro-Topic"] = p.Topic() | ||||
|  | ||||
| 	// passed in raw data | ||||
| 	if d, ok := p.Payload().(*raw.Frame); ok { | ||||
| 		body = d.Data | ||||
| 	} else { | ||||
| 		// use codec for payload | ||||
| 		cf, err := g.newGRPCCodec(p.ContentType()) | ||||
| 		if err != nil { | ||||
| 			return errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 		} | ||||
| 		// set the body | ||||
| 		b, err := cf.Marshal(p.Payload()) | ||||
| 		if err != nil { | ||||
| 			return errors.InternalServerError("go.micro.client", err.Error()) | ||||
| 		} | ||||
| 		body = b | ||||
| 	} | ||||
|  | ||||
| 	topic := p.Topic() | ||||
|  | ||||
| 	// get the exchange | ||||
| 	if len(options.Exchange) > 0 { | ||||
| 		topic = options.Exchange | ||||
| 		exchange = options.Exchange | ||||
| 	} | ||||
|  | ||||
| 	return g.opts.Broker.Publish(topic, &broker.Message{ | ||||
| 		Header: md, | ||||
| 		Body:   body, | ||||
| 	}, broker.PublishContext(options.Context)) | ||||
| 	msgs := make([]*broker.Message, 0, len(ps)) | ||||
|  | ||||
| 	omd, ok := metadata.FromOutgoingContext(ctx) | ||||
| 	if !ok { | ||||
| 		omd = metadata.New(2) | ||||
| 	} | ||||
|  | ||||
| 	for _, p := range ps { | ||||
| 		md := metadata.Copy(omd) | ||||
| 		md[metadata.HeaderContentType] = p.ContentType() | ||||
| 		topic := p.Topic() | ||||
| 		if len(exchange) > 0 { | ||||
| 			topic = exchange | ||||
| 		} | ||||
| 		md.Set(metadata.HeaderTopic, topic) | ||||
| 		iter := p.Metadata().Iterator() | ||||
| 		var k, v string | ||||
| 		for iter.Next(&k, &v) { | ||||
| 			md.Set(k, v) | ||||
| 		} | ||||
|  | ||||
| 		// passed in raw data | ||||
| 		if d, ok := p.Payload().(*codec.Frame); ok { | ||||
| 			body = d.Data | ||||
| 		} else { | ||||
| 			// use codec for payload | ||||
| 			cf, err := g.newCodec(p.ContentType()) | ||||
| 			if err != nil { | ||||
| 				return errors.InternalServerError("go.micro.client", "%+v", err) | ||||
| 			} | ||||
| 			// set the body | ||||
| 			b, err := cf.Marshal(p.Payload()) | ||||
| 			if err != nil { | ||||
| 				return errors.InternalServerError("go.micro.client", "%+v", err) | ||||
| 			} | ||||
| 			body = b | ||||
| 		} | ||||
| 		msgs = append(msgs, &broker.Message{Header: md, Body: body}) | ||||
| 	} | ||||
|  | ||||
| 	return g.opts.Broker.BatchPublish(ctx, msgs, | ||||
| 		broker.PublishContext(options.Context), | ||||
| 		broker.PublishBodyOnly(options.BodyOnly), | ||||
| 	) | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) String() string { | ||||
| 	return "grpc" | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) getGrpcDialOptions() []grpc.DialOption { | ||||
| 	if g.opts.CallOptions.Context == nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	v := g.opts.CallOptions.Context.Value(grpcDialOptions{}) | ||||
|  | ||||
| 	if v == nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	opts, ok := v.([]grpc.DialOption) | ||||
|  | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return opts | ||||
| func (g *grpcClient) Name() string { | ||||
| 	return g.opts.Name | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) getGrpcCallOptions() []grpc.CallOption { | ||||
| 	if g.opts.CallOptions.Context == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| func (g *grpcClient) getGrpcDialOptions(ctx context.Context) []grpc.DialOption { | ||||
| 	var opts []grpc.DialOption | ||||
|  | ||||
| 	v := g.opts.CallOptions.Context.Value(grpcCallOptions{}) | ||||
|  | ||||
| 	if v == nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	opts, ok := v.([]grpc.CallOption) | ||||
|  | ||||
| 	if !ok { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return opts | ||||
| } | ||||
|  | ||||
| func newClient(opts ...client.Option) client.Client { | ||||
| 	options := client.NewOptions() | ||||
| 	// default content type for grpc | ||||
| 	options.ContentType = "application/grpc+proto" | ||||
|  | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| 	} | ||||
|  | ||||
| 	rc := &grpcClient{ | ||||
| 		opts: options, | ||||
| 	} | ||||
| 	rc.once.Store(false) | ||||
|  | ||||
| 	rc.pool = newPool(options.PoolSize, options.PoolTTL, rc.poolMaxIdle(), rc.poolMaxStreams()) | ||||
|  | ||||
| 	c := client.Client(rc) | ||||
|  | ||||
| 	// wrap in reverse | ||||
| 	for i := len(options.Wrappers); i > 0; i-- { | ||||
| 		c = options.Wrappers[i-1](c) | ||||
| 	} | ||||
|  | ||||
| 	rc.codecs = make(map[string]encoding.Codec, len(defaultGRPCCodecs)) | ||||
| 	for k, v := range defaultGRPCCodecs { | ||||
| 		rc.codecs[k] = v | ||||
| 	} | ||||
|  | ||||
| 	var codecs map[string]encoding.Codec | ||||
| 	if rc.opts.Context != nil { | ||||
| 		if v := rc.opts.Context.Value(codecsKey{}); v != nil { | ||||
| 			codecs = v.(map[string]encoding.Codec) | ||||
| 	if g.opts.CallOptions.Context != nil { | ||||
| 		if v := g.opts.CallOptions.Context.Value(grpcDialOptions{}); v != nil { | ||||
| 			if vopts, ok := v.([]grpc.DialOption); ok { | ||||
| 				opts = append(opts, vopts...) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for k, v := range codecs { | ||||
| 		rc.codecs[k] = v | ||||
| 	if ctx != nil { | ||||
| 		if v := ctx.Value(grpcDialOptions{}); v != nil { | ||||
| 			if vopts, ok := v.([]grpc.DialOption); ok { | ||||
| 				opts = append(opts, vopts...) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return c | ||||
| 	return opts | ||||
| } | ||||
|  | ||||
| func (g *grpcClient) getGrpcCallOptions(ctx context.Context) []grpc.CallOption { | ||||
| 	var opts []grpc.CallOption | ||||
|  | ||||
| 	if g.opts.CallOptions.Context != nil { | ||||
| 		if v := g.opts.CallOptions.Context.Value(grpcCallOptions{}); v != nil { | ||||
| 			if vopts, ok := v.([]grpc.CallOption); ok { | ||||
| 				opts = append(opts, vopts...) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if ctx != nil { | ||||
| 		if v := ctx.Value(grpcCallOptions{}); v != nil { | ||||
| 			if vopts, ok := v.([]grpc.CallOption); ok { | ||||
| 				opts = append(opts, vopts...) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return opts | ||||
| } | ||||
|  | ||||
| func NewClient(opts ...client.Option) client.Client { | ||||
| 	return newClient(opts...) | ||||
| 	options := client.NewOptions(opts...) | ||||
| 	// default content type for grpc | ||||
| 	if options.ContentType == "" { | ||||
| 		options.ContentType = DefaultContentType | ||||
| 	} | ||||
|  | ||||
| 	c := &grpcClient{ | ||||
| 		opts: options, | ||||
| 	} | ||||
|  | ||||
| 	c.pool = NewConnPool(options.PoolSize, options.PoolTTL, c.poolMaxIdle(), c.poolMaxStreams()) | ||||
|  | ||||
| 	if c.opts.Context != nil { | ||||
| 		if codecs, ok := c.opts.Context.Value(codecsKey{}).(map[string]encoding.Codec); ok && codecs != nil { | ||||
| 			for k, v := range codecs { | ||||
| 				c.opts.Codecs[k] = &wrapGrpcCodec{v} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, k := range options.Codecs { | ||||
| 		encoding.RegisterCodec(&wrapMicroCodec{k}) | ||||
| 	} | ||||
|  | ||||
| 	c.funcCall = c.fnCall | ||||
| 	c.funcStream = c.fnStream | ||||
| 	c.funcPublish = c.fnPublish | ||||
| 	c.funcBatchPublish = c.fnBatchPublish | ||||
|  | ||||
| 	return c | ||||
| } | ||||
|   | ||||
							
								
								
									
										66
									
								
								grpc_pool.go
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								grpc_pool.go
									
									
									
									
									
								
							| @@ -2,6 +2,7 @@ package grpc | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| @@ -9,56 +10,47 @@ import ( | ||||
| 	"google.golang.org/grpc/connectivity" | ||||
| ) | ||||
|  | ||||
| type pool struct { | ||||
| 	size int | ||||
| 	ttl  int64 | ||||
|  | ||||
| 	//  max streams on a *poolConn | ||||
| type ConnPool struct { | ||||
| 	conns      map[string]*streamsPool | ||||
| 	size       int | ||||
| 	ttl        int64 | ||||
| 	maxStreams int | ||||
| 	//  max idle conns | ||||
| 	maxIdle int | ||||
|  | ||||
| 	maxIdle    int | ||||
| 	sync.Mutex | ||||
| 	conns map[string]*streamsPool | ||||
| } | ||||
|  | ||||
| type streamsPool struct { | ||||
| 	//  head of list | ||||
| 	head *poolConn | ||||
| 	head *PoolConn | ||||
| 	//  busy conns list | ||||
| 	busy *poolConn | ||||
| 	busy *PoolConn | ||||
| 	//  the siza of list | ||||
| 	count int | ||||
| 	//  idle conn | ||||
| 	idle int | ||||
| } | ||||
|  | ||||
| type poolConn struct { | ||||
| 	//  grpc conn | ||||
| type PoolConn struct { | ||||
| 	err error | ||||
| 	*grpc.ClientConn | ||||
| 	err  error | ||||
| 	addr string | ||||
|  | ||||
| 	//  pool and streams pool | ||||
| 	pool    *pool | ||||
| 	next    *PoolConn | ||||
| 	pool    *ConnPool | ||||
| 	sp      *streamsPool | ||||
| 	pre     *PoolConn | ||||
| 	addr    string | ||||
| 	streams int | ||||
| 	created int64 | ||||
|  | ||||
| 	//  list | ||||
| 	pre  *poolConn | ||||
| 	next *poolConn | ||||
| 	in   bool | ||||
| 	in      bool | ||||
| } | ||||
|  | ||||
| func newPool(size int, ttl time.Duration, idle int, ms int) *pool { | ||||
| func NewConnPool(size int, ttl time.Duration, idle int, ms int) *ConnPool { | ||||
| 	if ms <= 0 { | ||||
| 		ms = 1 | ||||
| 	} | ||||
| 	if idle < 0 { | ||||
| 		idle = 0 | ||||
| 	} | ||||
| 	return &pool{ | ||||
| 	return &ConnPool{ | ||||
| 		size:       size, | ||||
| 		ttl:        int64(ttl.Seconds()), | ||||
| 		maxStreams: ms, | ||||
| @@ -67,12 +59,15 @@ func newPool(size int, ttl time.Duration, idle int, ms int) *pool { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (p *pool) getConn(ctx context.Context, addr string, opts ...grpc.DialOption) (*poolConn, error) { | ||||
| func (p *ConnPool) Get(ctx context.Context, addr string, opts ...grpc.DialOption) (*PoolConn, error) { | ||||
| 	if strings.HasPrefix(addr, "http") { | ||||
| 		addr = addr[strings.Index(addr, ":")+3:] | ||||
| 	} | ||||
| 	now := time.Now().Unix() | ||||
| 	p.Lock() | ||||
| 	sp, ok := p.conns[addr] | ||||
| 	if !ok { | ||||
| 		sp = &streamsPool{head: &poolConn{}, busy: &poolConn{}, count: 0, idle: 0} | ||||
| 		sp = &streamsPool{head: &PoolConn{}, busy: &PoolConn{}, count: 0, idle: 0} | ||||
| 		p.conns[addr] = sp | ||||
| 	} | ||||
| 	//  while we have conns check streams and then return one | ||||
| @@ -135,12 +130,12 @@ func (p *pool) getConn(ctx context.Context, addr string, opts ...grpc.DialOption | ||||
| 	} | ||||
| 	p.Unlock() | ||||
|  | ||||
| 	//  create new conn | ||||
| 	// nolint (TODO need fix)  create new conn) | ||||
| 	cc, err := grpc.DialContext(ctx, addr, opts...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	conn = &poolConn{cc, nil, addr, p, sp, 1, time.Now().Unix(), nil, nil, false} | ||||
| 	conn = &PoolConn{ClientConn: cc, err: nil, addr: addr, pool: p, sp: sp, streams: 1, created: time.Now().Unix(), pre: nil, next: nil, in: false} | ||||
|  | ||||
| 	//  add conn to streams pool | ||||
| 	p.Lock() | ||||
| @@ -152,7 +147,7 @@ func (p *pool) getConn(ctx context.Context, addr string, opts ...grpc.DialOption | ||||
| 	return conn, nil | ||||
| } | ||||
|  | ||||
| func (p *pool) release(addr string, conn *poolConn, err error) { | ||||
| func (p *ConnPool) Put(conn *PoolConn, err error) { | ||||
| 	p.Lock() | ||||
| 	p, sp, created := conn.pool, conn.sp, conn.created | ||||
| 	//  try to add conn | ||||
| @@ -185,14 +180,13 @@ func (p *pool) release(addr string, conn *poolConn, err error) { | ||||
| 		sp.idle++ | ||||
| 	} | ||||
| 	p.Unlock() | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (conn *poolConn) Close() { | ||||
| 	conn.pool.release(conn.addr, conn, conn.err) | ||||
| func (conn *PoolConn) Close() { | ||||
| 	conn.pool.Put(conn, conn.err) | ||||
| } | ||||
|  | ||||
| func removeConn(conn *poolConn) { | ||||
| func removeConn(conn *PoolConn) { | ||||
| 	if conn.pre != nil { | ||||
| 		conn.pre.next = conn.next | ||||
| 	} | ||||
| @@ -203,10 +197,9 @@ func removeConn(conn *poolConn) { | ||||
| 	conn.next = nil | ||||
| 	conn.in = false | ||||
| 	conn.sp.count-- | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func addConnAfter(conn *poolConn, after *poolConn) { | ||||
| func addConnAfter(conn *PoolConn, after *PoolConn) { | ||||
| 	conn.next = after.next | ||||
| 	conn.pre = after | ||||
| 	if after.next != nil { | ||||
| @@ -215,5 +208,4 @@ func addConnAfter(conn *poolConn, after *poolConn) { | ||||
| 	after.next = conn | ||||
| 	conn.in = true | ||||
| 	conn.sp.count++ | ||||
| 	return | ||||
| } | ||||
|   | ||||
							
								
								
									
										16
									
								
								message.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								message.go
									
									
									
									
									
								
							| @@ -1,20 +1,19 @@ | ||||
| package grpc | ||||
|  | ||||
| import ( | ||||
| 	"github.com/unistack-org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| ) | ||||
|  | ||||
| type grpcEvent struct { | ||||
| 	payload     interface{} | ||||
| 	topic       string | ||||
| 	contentType string | ||||
| 	payload     interface{} | ||||
| 	opts        client.MessageOptions | ||||
| } | ||||
|  | ||||
| func newGRPCEvent(topic string, payload interface{}, contentType string, opts ...client.MessageOption) client.Message { | ||||
| 	var options client.MessageOptions | ||||
| 	for _, o := range opts { | ||||
| 		o(&options) | ||||
| 	} | ||||
| 	options := client.NewMessageOptions(opts...) | ||||
|  | ||||
| 	if len(options.ContentType) > 0 { | ||||
| 		contentType = options.ContentType | ||||
| @@ -24,6 +23,7 @@ func newGRPCEvent(topic string, payload interface{}, contentType string, opts .. | ||||
| 		payload:     payload, | ||||
| 		topic:       topic, | ||||
| 		contentType: contentType, | ||||
| 		opts:        options, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -38,3 +38,7 @@ func (g *grpcEvent) Topic() string { | ||||
| func (g *grpcEvent) Payload() interface{} { | ||||
| 	return g.payload | ||||
| } | ||||
|  | ||||
| func (g *grpcEvent) Metadata() metadata.Metadata { | ||||
| 	return g.opts.Metadata | ||||
| } | ||||
|   | ||||
							
								
								
									
										58
									
								
								options.go
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								options.go
									
									
									
									
									
								
							| @@ -3,15 +3,14 @@ package grpc | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
|  | ||||
| 	"github.com/unistack-org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"google.golang.org/grpc" | ||||
| 	"google.golang.org/grpc/encoding" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	// DefaultPoolMaxStreams maximum streams on a connectioin | ||||
| 	// DefaultPoolMaxStreams maximum streams on a connection | ||||
| 	// (20) | ||||
| 	DefaultPoolMaxStreams = 20 | ||||
|  | ||||
| @@ -26,16 +25,12 @@ var ( | ||||
| 	// DefaultMaxSendMsgSize maximum message that client can send | ||||
| 	// (4 MB). | ||||
| 	DefaultMaxSendMsgSize = 1024 * 1024 * 4 | ||||
|  | ||||
| 	// DefaultServiceConfig enable load balancing | ||||
| 	DefaultServiceConfig = `{"loadBalancingPolicy":"round_robin"}` | ||||
| ) | ||||
|  | ||||
| type poolMaxStreams struct{} | ||||
| type poolMaxIdle struct{} | ||||
| type codecsKey struct{} | ||||
| type tlsAuth struct{} | ||||
| type maxRecvMsgSizeKey struct{} | ||||
| type maxSendMsgSizeKey struct{} | ||||
| type grpcDialOptions struct{} | ||||
| type grpcCallOptions struct{} | ||||
|  | ||||
| // maximum streams on a connectioin | ||||
| func PoolMaxStreams(n int) client.Option { | ||||
| @@ -47,6 +42,8 @@ func PoolMaxStreams(n int) client.Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type poolMaxIdle struct{} | ||||
|  | ||||
| // maximum idle conns of a pool | ||||
| func PoolMaxIdle(d int) client.Option { | ||||
| 	return func(o *client.Options) { | ||||
| @@ -57,6 +54,8 @@ func PoolMaxIdle(d int) client.Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type codecsKey struct{} | ||||
|  | ||||
| // gRPC Codec to be used to encode/decode requests for a given content type | ||||
| func Codec(contentType string, c encoding.Codec) client.Option { | ||||
| 	return func(o *client.Options) { | ||||
| @@ -72,19 +71,9 @@ func Codec(contentType string, c encoding.Codec) client.Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // AuthTLS should be used to setup a secure authentication using TLS | ||||
| func AuthTLS(t *tls.Config) client.Option { | ||||
| 	return func(o *client.Options) { | ||||
| 		if o.Context == nil { | ||||
| 			o.Context = context.Background() | ||||
| 		} | ||||
| 		o.Context = context.WithValue(o.Context, tlsAuth{}, t) | ||||
| 	} | ||||
| } | ||||
| type maxRecvMsgSizeKey struct{} | ||||
|  | ||||
| // | ||||
| // MaxRecvMsgSize set the maximum size of message that client can receive. | ||||
| // | ||||
| func MaxRecvMsgSize(s int) client.Option { | ||||
| 	return func(o *client.Options) { | ||||
| 		if o.Context == nil { | ||||
| @@ -94,9 +83,9 @@ func MaxRecvMsgSize(s int) client.Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // | ||||
| type maxSendMsgSizeKey struct{} | ||||
|  | ||||
| // MaxSendMsgSize set the maximum size of message that client can send. | ||||
| // | ||||
| func MaxSendMsgSize(s int) client.Option { | ||||
| 	return func(o *client.Options) { | ||||
| 		if o.Context == nil { | ||||
| @@ -106,11 +95,11 @@ func MaxSendMsgSize(s int) client.Option { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // | ||||
| type grpcDialOptions struct{} | ||||
|  | ||||
| // DialOptions to be used to configure gRPC dial options | ||||
| // | ||||
| func DialOptions(opts ...grpc.DialOption) client.CallOption { | ||||
| 	return func(o *client.CallOptions) { | ||||
| func DialOptions(opts ...grpc.DialOption) client.Option { | ||||
| 	return func(o *client.Options) { | ||||
| 		if o.Context == nil { | ||||
| 			o.Context = context.Background() | ||||
| 		} | ||||
| @@ -118,9 +107,9 @@ func DialOptions(opts ...grpc.DialOption) client.CallOption { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // | ||||
| type grpcCallOptions struct{} | ||||
|  | ||||
| // CallOptions to be used to configure gRPC call options | ||||
| // | ||||
| func CallOptions(opts ...grpc.CallOption) client.CallOption { | ||||
| 	return func(o *client.CallOptions) { | ||||
| 		if o.Context == nil { | ||||
| @@ -129,3 +118,14 @@ func CallOptions(opts ...grpc.CallOption) client.CallOption { | ||||
| 		o.Context = context.WithValue(o.Context, grpcCallOptions{}, opts) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type serviceConfigKey struct{} | ||||
|  | ||||
| func ServiceConfig(str string) client.CallOption { | ||||
| 	return func(options *client.CallOptions) { | ||||
| 		if options.Context == nil { | ||||
| 			options.Context = context.Background() | ||||
| 		} | ||||
| 		options.Context = context.WithValue(options.Context, serviceConfigKey{}, str) | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										23
									
								
								request.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								request.go
									
									
									
									
									
								
							| @@ -4,17 +4,17 @@ import ( | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/unistack-org/micro/v3/client" | ||||
| 	"github.com/unistack-org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| ) | ||||
|  | ||||
| type grpcRequest struct { | ||||
| 	request     interface{} | ||||
| 	codec       codec.Codec | ||||
| 	service     string | ||||
| 	method      string | ||||
| 	contentType string | ||||
| 	request     interface{} | ||||
| 	opts        client.RequestOptions | ||||
| 	codec       codec.Codec | ||||
| } | ||||
|  | ||||
| // service Struct.Method /service.Struct/Method | ||||
| @@ -38,15 +38,12 @@ func methodToGRPC(service, method string) string { | ||||
| 	return fmt.Sprintf("/%s.%s/%s", service, mParts[0], mParts[1]) | ||||
| } | ||||
|  | ||||
| func newGRPCRequest(service, method string, request interface{}, contentType string, reqOpts ...client.RequestOption) client.Request { | ||||
| 	var opts client.RequestOptions | ||||
| 	for _, o := range reqOpts { | ||||
| 		o(&opts) | ||||
| 	} | ||||
| func newGRPCRequest(service, method string, request interface{}, contentType string, opts ...client.RequestOption) client.Request { | ||||
| 	options := client.NewRequestOptions(opts...) | ||||
|  | ||||
| 	// set the content-type specified | ||||
| 	if len(opts.ContentType) > 0 { | ||||
| 		contentType = opts.ContentType | ||||
| 	if len(options.ContentType) > 0 { | ||||
| 		contentType = options.ContentType | ||||
| 	} | ||||
|  | ||||
| 	return &grpcRequest{ | ||||
| @@ -54,7 +51,7 @@ func newGRPCRequest(service, method string, request interface{}, contentType str | ||||
| 		method:      method, | ||||
| 		request:     request, | ||||
| 		contentType: contentType, | ||||
| 		opts:        opts, | ||||
| 		opts:        options, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -74,7 +71,7 @@ func (g *grpcRequest) Endpoint() string { | ||||
| 	return g.method | ||||
| } | ||||
|  | ||||
| func (g *grpcRequest) Codec() codec.Writer { | ||||
| func (g *grpcRequest) Codec() codec.Codec { | ||||
| 	return g.codec | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										34
									
								
								response.go
									
									
									
									
									
								
							
							
						
						
									
										34
									
								
								response.go
									
									
									
									
									
								
							| @@ -3,42 +3,36 @@ package grpc | ||||
| import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/unistack-org/micro/v3/codec" | ||||
| 	"github.com/unistack-org/micro-codec-bytes" | ||||
| 	"go.unistack.org/micro/v3/codec" | ||||
| 	"go.unistack.org/micro/v3/metadata" | ||||
| 	"google.golang.org/grpc" | ||||
| 	"google.golang.org/grpc/encoding" | ||||
| ) | ||||
|  | ||||
| type response struct { | ||||
| 	conn   *poolConn | ||||
| 	conn   *PoolConn | ||||
| 	stream grpc.ClientStream | ||||
| 	codec  encoding.Codec | ||||
| 	gcodec codec.Codec | ||||
| 	codec  codec.Codec | ||||
| } | ||||
|  | ||||
| // Read the response | ||||
| func (r *response) Codec() codec.Reader { | ||||
| 	return r.gcodec | ||||
| func (r *response) Codec() codec.Codec { | ||||
| 	return r.codec | ||||
| } | ||||
|  | ||||
| // read the header | ||||
| func (r *response) Header() map[string]string { | ||||
| 	md, err := r.stream.Header() | ||||
| func (r *response) Header() metadata.Metadata { | ||||
| 	meta, err := r.stream.Header() | ||||
| 	if err != nil { | ||||
| 		return map[string]string{} | ||||
| 		return nil | ||||
| 	} | ||||
| 	hdr := make(map[string]string, len(md)) | ||||
| 	for k, v := range md { | ||||
| 		hdr[k] = strings.Join(v, ",") | ||||
| 	md := metadata.New(len(meta)) | ||||
| 	for k, v := range meta { | ||||
| 		md.Set(k, strings.Join(v, ",")) | ||||
| 	} | ||||
| 	return hdr | ||||
| 	return md | ||||
| } | ||||
|  | ||||
| // Read the undecoded response | ||||
| func (r *response) Read() ([]byte, error) { | ||||
| 	f := &bytes.Frame{} | ||||
| 	if err := r.gcodec.ReadBody(f); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return f.Data, nil | ||||
| 	return nil, nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										59
									
								
								stream.go
									
									
									
									
									
								
							
							
						
						
									
										59
									
								
								stream.go
									
									
									
									
									
								
							| @@ -5,23 +5,22 @@ import ( | ||||
| 	"io" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/unistack-org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/client" | ||||
| 	"go.unistack.org/micro/v3/tracer" | ||||
| 	"google.golang.org/grpc" | ||||
| ) | ||||
|  | ||||
| // Implements the streamer interface | ||||
| type grpcStream struct { | ||||
| 	// embed so we can access if need be | ||||
| 	grpc.ClientStream | ||||
|  | ||||
| 	sync.RWMutex | ||||
| 	closed   bool | ||||
| 	context  context.Context | ||||
| 	err      error | ||||
| 	conn     *poolConn | ||||
| 	request  client.Request | ||||
| 	response client.Response | ||||
| 	context  context.Context | ||||
| 	close    func(err error) | ||||
| 	conn     *PoolConn | ||||
| 	sync.RWMutex | ||||
| 	closed bool | ||||
| } | ||||
|  | ||||
| func (g *grpcStream) Context() context.Context { | ||||
| @@ -44,6 +43,14 @@ func (g *grpcStream) Send(msg interface{}) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (g *grpcStream) SendMsg(msg interface{}) error { | ||||
| 	if err := g.ClientStream.SendMsg(msg); err != nil { | ||||
| 		g.setError(err) | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (g *grpcStream) Recv(msg interface{}) (err error) { | ||||
| 	defer g.setError(err) | ||||
|  | ||||
| @@ -62,6 +69,24 @@ func (g *grpcStream) Recv(msg interface{}) (err error) { | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (g *grpcStream) RecvMsg(msg interface{}) (err error) { | ||||
| 	defer g.setError(err) | ||||
|  | ||||
| 	if err = g.ClientStream.RecvMsg(msg); err != nil { | ||||
| 		// #202 - inconsistent gRPC stream behavior | ||||
| 		// the only way to tell if the stream is done is when we get a EOF on the Recv | ||||
| 		// here we should close the underlying gRPC ClientConn | ||||
| 		closeErr := g.Close() | ||||
| 		if err == io.EOF && closeErr != nil { | ||||
| 			err = closeErr | ||||
| 		} | ||||
|  | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (g *grpcStream) Error() error { | ||||
| 	g.RLock() | ||||
| 	defer g.RUnlock() | ||||
| @@ -87,6 +112,26 @@ func (g *grpcStream) Close() error { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if sp, ok := tracer.SpanFromContext(g.context); ok && sp != nil { | ||||
| 		if g.err != nil { | ||||
| 			sp.SetStatus(tracer.SpanStatusError, g.err.Error()) | ||||
| 		} | ||||
| 		sp.Finish() | ||||
| 	} | ||||
| 	// close the connection | ||||
| 	g.closed = true | ||||
| 	g.close(g.err) | ||||
| 	return g.ClientStream.CloseSend() | ||||
| } | ||||
|  | ||||
| func (g *grpcStream) CloseSend() error { | ||||
| 	g.Lock() | ||||
| 	defer g.Unlock() | ||||
|  | ||||
| 	if g.closed { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	// close the connection | ||||
| 	g.closed = true | ||||
| 	g.close(g.err) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user