Compare commits
	
		
			133 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e219ace4b4 | ||
|  | e26a0889ae | ||
|  | 5ea51f5a29 | ||
|  | ee1c429e37 | ||
|  | 4a5b91c215 | ||
|  | 321446ce29 | ||
|  | b508565a78 | ||
|  | 1ee348109e | ||
|  | 1fb2d4c51e | ||
|  | 968a4f89c4 | ||
|  | 5f3b1daf82 | ||
|  | 65a5feab3c | ||
|  | f679b560bb | ||
|  | 91dfd46eb1 | ||
|  | 95f8aa68f2 | ||
|  | 79834cc131 | ||
|  | 04b5fc19c2 | ||
|  | 48de9f25a8 | ||
|  | 68402dcb96 | ||
|  | c3a9013863 | ||
|  | 8215db3be9 | ||
|  | 2e45567e56 | ||
|  | 07b32ad3b9 | ||
|  | 2ecd049871 | ||
|  | 6bf1bcf1b5 | ||
|  | 7058b444ab | ||
|  | c917566ce4 | ||
|  | ef9d975d9b | ||
|  | be06de5c47 | ||
|  | 975da990a9 | ||
|  | f2728a7fee | ||
|  | d3b37f14cf | ||
|  | 525b436bf1 | ||
|  | 7935276c54 | ||
|  | 1088fa0a31 | ||
|  | 0ebf401c21 | ||
|  | 916a2a1a99 | ||
|  | c459164ad4 | ||
|  | d7295810da | ||
|  | 1b8ccd13a6 | ||
|  | ffc9bff208 | ||
|  | fe67b26bfc | ||
|  | 1bdbe0fad5 | ||
|  | c7f24aa425 | ||
|  | 1ae2ac9020 | ||
|  | 274aacda1d | ||
|  | 00c39f4f2c | ||
|  | cc547a9f1a | ||
|  | d31708f8e9 | ||
|  | 25ec6331e8 | ||
|  | 97b4762ab2 | ||
|  | a511f1dc64 | ||
|  | e809cb9117 | ||
|  | 04726dbea5 | ||
|  | c49fef49b8 | ||
|  | 1a962e46fd | ||
|  | 5e35d89b38 | ||
|  | dad05be95e | ||
|  | c701f96a09 | ||
|  | 27aa1ff2ab | ||
|  | 8f6ba4a56e | ||
|  | 0a6e451539 | ||
|  | 231cfc48f0 | ||
|  | a365c51c2b | ||
|  | 02b74a5487 | ||
|  | 87e898f4fc | ||
|  | d246ccbeef | ||
|  | 017e156440 | ||
|  | d8f17ac827 | ||
|  | 6e2c9e7cd4 | ||
|  | 4028e0156b | ||
|  | 76275e857c | ||
|  | a18806c9ef | ||
|  | 255fecb4f4 | ||
|  | af8d55eb7f | ||
|  | 354a169050 | ||
|  | 6e083b9aca | ||
|  | 9dbd75f2cc | ||
|  | 8975184b88 | ||
|  | 19a54f2970 | ||
|  | 3c7f663e8b | ||
|  | 8fdc8f05ce | ||
|  | 35349bd313 | ||
|  | d5bfa1e795 | ||
|  | 3bb76868d1 | ||
|  | 275e92be32 | ||
|  | d2728b498c | ||
|  | 601b223cfb | ||
|  | 04d2aa4696 | ||
|  | b8f79a3fc6 | ||
|  | acd3bea0c6 | ||
|  | a02a25d955 | ||
|  | d5e345d41d | ||
|  | 71f8cbd5e2 | ||
|  | f12473f4b1 | ||
|  | 724e2b5830 | ||
|  | 6bdf33c4ee | ||
|  | 84f52fd7ac | ||
|  | 6e30b53280 | ||
|  | a60426c884 | ||
|  | 2998735bf3 | ||
|  | 3a96135df8 | ||
|  | bf8b3aeac7 | ||
|  | 5a52b5929c | ||
|  | 0adb469a85 | ||
|  | 21004341bf | ||
|  | cc26f2b8b1 | ||
|  | 1a6652fe6b | ||
|  | d28f0670d6 | ||
|  | 7bdd619e1b | ||
|  | c62d1d5eb8 | ||
|  | d60d85de5c | ||
|  | 44f281f8d9 | ||
|  | f698feac9c | ||
|  | f55701b374 | ||
|  | 82e8298b73 | ||
|  | fc54503232 | ||
|  | 6f0594eebe | ||
|  | 6b52f859cf | ||
|  | a3d4b8f79b | ||
|  | 7c7df6b35d | ||
|  | e80eab397a | ||
|  | 6cda6ef92e | ||
|  | f9f61d29de | ||
|  | 1ae825032c | ||
|  | f146b52418 | ||
|  | 78a79ca9e1 | ||
|  | 329bc2f265 | ||
|  | 8738ed7757 | ||
|  | 29e8cdbfe9 | ||
|  | 47f356fc5f | ||
|  | 21ffc73c4f | ||
|  | 81a9342b83 | 
							
								
								
									
										2
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
								
							| @@ -1,3 +1,3 @@ | |||||||
| # These are supported funding model platforms | # These are supported funding model platforms | ||||||
|  |  | ||||||
| github: micro | github: asim | ||||||
|   | |||||||
							
								
								
									
										9
									
								
								.github/workflows/pr.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/pr.yml
									
									
									
									
										vendored
									
									
								
							| @@ -25,4 +25,11 @@ jobs: | |||||||
|       id: tests |       id: tests | ||||||
|       env: |       env: | ||||||
|         IN_TRAVIS_CI: yes |         IN_TRAVIS_CI: yes | ||||||
|       run: go test -v ./... |         S3_BLOB_STORE_REGION: ${{ secrets.SCALEWAY_REGION }} | ||||||
|  |         S3_BLOB_STORE_ENDPOINT: ${{ secrets.SCALEWAY_ENDPOINT }} | ||||||
|  |         S3_BLOB_STORE_ACCESS_KEY: ${{ secrets.SCALEWAY_ACCESS_KEY }} | ||||||
|  |         S3_BLOB_STORE_SECRET_KEY: ${{ secrets.SCALEWAY_SECRET_KEY }} | ||||||
|  |       run: | | ||||||
|  |         wget -qO- https://binaries.cockroachdb.com/cockroach-v20.1.4.linux-amd64.tgz | tar  xvz | ||||||
|  |         cockroach-v20.1.4.linux-amd64/cockroach start-single-node --insecure & | ||||||
|  |         go test -v ./... | ||||||
|   | |||||||
							
								
								
									
										42
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								.github/workflows/tests.yml
									
									
									
									
										vendored
									
									
								
							| @@ -7,13 +7,17 @@ jobs: | |||||||
|     name: Test repo |     name: Test repo | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
|     steps: |     steps: | ||||||
|  |  | ||||||
|     - name: Set up Go 1.13 |     - name: Set up Go 1.13 | ||||||
|       uses: actions/setup-go@v1 |       uses: actions/setup-go@v1 | ||||||
|       with: |       with: | ||||||
|         go-version: 1.13 |         go-version: 1.13 | ||||||
|       id: go |       id: go | ||||||
|  |  | ||||||
|  |     - name: Setup Kind | ||||||
|  |       uses: engineerd/setup-kind@v0.4.0 | ||||||
|  |       with: | ||||||
|  |         version: v0.8.1 | ||||||
|  |  | ||||||
|     - name: Check out code into the Go module directory |     - name: Check out code into the Go module directory | ||||||
|       uses: actions/checkout@v2 |       uses: actions/checkout@v2 | ||||||
|  |  | ||||||
| @@ -25,30 +29,20 @@ jobs: | |||||||
|       id: tests |       id: tests | ||||||
|       env: |       env: | ||||||
|         IN_TRAVIS_CI: yes |         IN_TRAVIS_CI: yes | ||||||
|  |         S3_BLOB_STORE_REGION: ${{ secrets.SCALEWAY_REGION }} | ||||||
|  |         S3_BLOB_STORE_ENDPOINT: ${{ secrets.SCALEWAY_ENDPOINT }} | ||||||
|  |         S3_BLOB_STORE_ACCESS_KEY: ${{ secrets.SCALEWAY_ACCESS_KEY }} | ||||||
|  |         S3_BLOB_STORE_SECRET_KEY: ${{ secrets.SCALEWAY_SECRET_KEY }} | ||||||
|       run: | |       run: | | ||||||
|         wget -qO- https://binaries.cockroachdb.com/cockroach-v20.1.4.linux-amd64.tgz | tar  xvz |         kubectl apply -f runtime/kubernetes/test/test.yaml | ||||||
|  |         sudo mkdir -p /var/run/secrets/kubernetes.io/serviceaccount | ||||||
|  |         sudo chmod 777 /var/run/secrets/kubernetes.io/serviceaccount | ||||||
|  |         wget -qO- https://binaries.cockroachdb.com/cockroach-v20.1.4.linux-amd64.tgz | tar -xvz | ||||||
|         cockroach-v20.1.4.linux-amd64/cockroach start-single-node --insecure & |         cockroach-v20.1.4.linux-amd64/cockroach start-single-node --insecure & | ||||||
|         go test -v ./... |         wget -q https://github.com/nats-io/nats-streaming-server/releases/download/v0.18.0/nats-streaming-server-v0.18.0-linux-amd64.zip | ||||||
|  |         unzip ./nats-streaming-server-v0.18.0-linux-amd64.zip | ||||||
|  |         export PATH=$PATH:./nats-streaming-server-v0.18.0-linux-amd64 | ||||||
|  |         nats-streaming-server & | ||||||
|  |         go test -tags kubernetes,nats -v ./... | ||||||
|    |    | ||||||
|     - name: Notify of test failure |  | ||||||
|       if: failure() |  | ||||||
|       uses: rtCamp/action-slack-notify@v2.0.0 |  | ||||||
|       env: |  | ||||||
|         SLACK_CHANNEL: build |  | ||||||
|         SLACK_COLOR: '#BF280A' |  | ||||||
|         SLACK_ICON: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png |  | ||||||
|         SLACK_TITLE: Tests Failed |  | ||||||
|         SLACK_USERNAME: GitHub Actions |  | ||||||
|         SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} |  | ||||||
|          |  | ||||||
|     - name: Notify of test success |  | ||||||
|       if: success() |  | ||||||
|       uses: rtCamp/action-slack-notify@v2.0.0 |  | ||||||
|       env: |  | ||||||
|         SLACK_CHANNEL: build |  | ||||||
|         SLACK_COLOR: '#1FAD2B' |  | ||||||
|         SLACK_ICON: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png |  | ||||||
|         SLACK_TITLE: Tests Passed |  | ||||||
|         SLACK_USERNAME: GitHub Actions |  | ||||||
|         SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} |  | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										237
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										237
									
								
								LICENSE
									
									
									
									
									
								
							| @@ -1,191 +1,104 @@ | |||||||
|  | # PolyForm Strict License 1.0.0 | ||||||
|  |  | ||||||
|                                  Apache License | <https://polyformproject.org/licenses/strict/1.0.0> | ||||||
|                            Version 2.0, January 2004 |  | ||||||
|                         http://www.apache.org/licenses/ |  | ||||||
|  |  | ||||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ## Acceptance | ||||||
|  |  | ||||||
|    1. Definitions. | In order to get any license under these terms, you must agree | ||||||
|  | to them as both strict obligations and conditions to all | ||||||
|  | your licenses. | ||||||
|  |  | ||||||
|       "License" shall mean the terms and conditions for use, reproduction, | ## Copyright License | ||||||
|       and distribution as defined by Sections 1 through 9 of this document. |  | ||||||
|  |  | ||||||
|       "Licensor" shall mean the copyright owner or entity authorized by | The licensor grants you a copyright license for the software | ||||||
|       the copyright owner that is granting the License. | to do everything you might do with the software that would | ||||||
|  | otherwise infringe the licensor's copyright in it for any | ||||||
|  | permitted purpose, other than distributing the software or | ||||||
|  | making changes or new works based on the software. | ||||||
|  |  | ||||||
|       "Legal Entity" shall mean the union of the acting entity and all | ## Patent License | ||||||
|       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 | The licensor grants you a patent license for the software that | ||||||
|       exercising permissions granted by this License. | covers patent claims the licensor can license, or becomes able | ||||||
|  | to license, that you would infringe by using the software. | ||||||
|  |  | ||||||
|       "Source" form shall mean the preferred form for making modifications, | ## Noncommercial Purposes | ||||||
|       including but not limited to software source code, documentation |  | ||||||
|       source, and configuration files. |  | ||||||
|  |  | ||||||
|       "Object" form shall mean any form resulting from mechanical | Any noncommercial purpose is a permitted purpose. | ||||||
|       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 | ## Personal Uses | ||||||
|       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 | Personal use for research, experiment, and testing for | ||||||
|       form, that is based on (or derived from) the Work and for which the | the benefit of public knowledge, personal study, private | ||||||
|       editorial revisions, annotations, elaborations, or other modifications | entertainment, hobby projects, amateur pursuits, or religious | ||||||
|       represent, as a whole, an original work of authorship. For the purposes | observance, without any anticipated commercial application, | ||||||
|       of this License, Derivative Works shall not include works that remain | is use for a permitted purpose. | ||||||
|       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 | ## Noncommercial Organizations | ||||||
|       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 | Use by any charitable organization, educational institution, | ||||||
|       on behalf of whom a Contribution has been received by Licensor and | public research organization, public safety or health | ||||||
|       subsequently incorporated within the Work. | organization, environmental protection organization, | ||||||
|  | or government institution is use for a permitted purpose | ||||||
|  | regardless of the source of funding or obligations resulting | ||||||
|  | from the funding. | ||||||
|  |  | ||||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ## Fair Use | ||||||
|       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 | You may have "fair use" rights for the software under the | ||||||
|       this License, each Contributor hereby grants to You a perpetual, | law. These terms do not limit them. | ||||||
|       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 | ## No Other Rights | ||||||
|       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 | These terms do not allow you to sublicense or transfer any of | ||||||
|           Derivative Works a copy of this License; and | your licenses to anyone else, or prevent the licensor from | ||||||
|  | granting licenses to anyone else.  These terms do not imply | ||||||
|  | any other licenses. | ||||||
|  |  | ||||||
|       (b) You must cause any modified files to carry prominent notices | ## Patent Defense | ||||||
|           stating that You changed the files; and |  | ||||||
|  |  | ||||||
|       (c) You must retain, in the Source form of any Derivative Works | If you make any written claim that the software infringes or | ||||||
|           that You distribute, all copyright, patent, trademark, and | contributes to infringement of any patent, your patent license | ||||||
|           attribution notices from the Source form of the Work, | for the software granted under these terms ends immediately. If | ||||||
|           excluding those notices that do not pertain to any part of | your company makes such a claim, your patent license ends | ||||||
|           the Derivative Works; and | immediately for work on behalf of your company. | ||||||
|  |  | ||||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ## Violations | ||||||
|           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 | The first time you are notified in writing that you have | ||||||
|       may provide additional or different license terms and conditions | violated any of these terms, or done anything with the software | ||||||
|       for use, reproduction, or distribution of Your modifications, or | not covered by your licenses, your licenses can nonetheless | ||||||
|       for any such Derivative Works as a whole, provided Your use, | continue if you come into full compliance with these terms, | ||||||
|       reproduction, and distribution of the Work otherwise complies with | and take practical steps to correct past violations, within | ||||||
|       the conditions stated in this License. | 32 days of receiving notice.  Otherwise, all your licenses | ||||||
|  | end immediately. | ||||||
|  |  | ||||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ## No Liability | ||||||
|       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 | ***As far as the law allows, the software comes as is, without | ||||||
|       names, trademarks, service marks, or product names of the Licensor, | any warranty or condition, and the licensor will not be liable | ||||||
|       except as required for reasonable and customary use in describing the | to you for any damages arising out of these terms or the use | ||||||
|       origin of the Work and reproducing the content of the NOTICE file. | or nature of the software, under any kind of legal claim.*** | ||||||
|  |  | ||||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ## Definitions | ||||||
|       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, | The **licensor** is the individual or entity offering these | ||||||
|       whether in tort (including negligence), contract, or otherwise, | terms, and the **software** is the software the licensor makes | ||||||
|       unless required by applicable law (such as deliberate and grossly | available under these terms. | ||||||
|       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 | **You** refers to the individual or entity agreeing to these | ||||||
|       the Work or Derivative Works thereof, You may choose to offer, | terms. | ||||||
|       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 | **Your company** is any legal entity, sole proprietorship, | ||||||
|  | or other kind of organization that you work for, plus all | ||||||
|  | organizations that have control over, are under the control of, | ||||||
|  | or are under common control with that organization.  **Control** | ||||||
|  | means ownership of substantially all the assets of an entity, | ||||||
|  | or the power to direct its management and policies by vote, | ||||||
|  | contract, or otherwise.  Control can be direct or indirect. | ||||||
|  |  | ||||||
|    Copyright 2015 Asim Aslam. | **Your licenses** are all the licenses granted to you for the | ||||||
|  | software under these terms. | ||||||
|  |  | ||||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | **Use** means anything you do with the software requiring one | ||||||
|    you may not use this file except in compliance with the License. | of your licenses. | ||||||
|    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. |  | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								README.md
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| # Go Micro [](https://opensource.org/licenses/Apache-2.0) [](https://pkg.go.dev/github.com/micro/go-micro/v3?tab=overview) [](https://travis-ci.org/micro/go-micro) [](https://goreportcard.com/report/github.com/micro/go-micro)  | # Go Micro [](https://polyformproject.org/licenses/perimeter/1.0.0/) [](https://pkg.go.dev/github.com/asim/go-micro/v3?tab=overview) | ||||||
|  |  | ||||||
| Go Micro is a standard library for microservices. | Go Micro is a framework for microservices development. | ||||||
|  |  | ||||||
| ## Overview | ## Overview | ||||||
|  |  | ||||||
| @@ -34,7 +34,7 @@ across the services and retry a different node if there's a problem. | |||||||
| to seamlessly encode and decode Go types for you. Any variety of messages could be encoded and sent from different clients. The client  | to seamlessly encode and decode Go types for you. Any variety of messages could be encoded and sent from different clients. The client  | ||||||
| and server handle this by default. This includes protobuf and json by default. | and server handle this by default. This includes protobuf and json by default. | ||||||
|  |  | ||||||
| - **gRPC Transport** - gRPC based request/response with support for bidirectional streaming. We provide an abstraction for synchronous communication. A request made to a service will be automatically resolved, load balanced, dialled and streamed. | - **RPC Communication** - gRPC based request/response with support for bidirectional streaming. We provide an abstraction for synchronous communication. A request made to a service will be automatically resolved, load balanced, dialled and streamed. | ||||||
|  |  | ||||||
| - **Async Messaging** - PubSub is built in as a first class citizen for asynchronous communication and event driven architectures.  | - **Async Messaging** - PubSub is built in as a first class citizen for asynchronous communication and event driven architectures.  | ||||||
| Event notifications are a core pattern in micro service development. The default messaging system is a HTTP event message broker. | Event notifications are a core pattern in micro service development. The default messaging system is a HTTP event message broker. | ||||||
| @@ -43,14 +43,13 @@ Event notifications are a core pattern in micro service development. The default | |||||||
| leadership are built in as a Sync interface. When using an eventually consistent database or scheduling use the Sync interface. | leadership are built in as a Sync interface. When using an eventually consistent database or scheduling use the Sync interface. | ||||||
|  |  | ||||||
| - **Pluggable Interfaces** - Go Micro makes use of Go interfaces for each distributed system abstraction. Because of this these interfaces  | - **Pluggable Interfaces** - Go Micro makes use of Go interfaces for each distributed system abstraction. Because of this these interfaces  | ||||||
| are pluggable and allows Go Micro to be runtime agnostic. You can plugin any underlying technology. Find plugins in  | are pluggable and allows Go Micro to be runtime agnostic. You can plugin any underlying technology. Find external third party (non stdlib)  | ||||||
| [github.com/micro/go-plugins](https://github.com/micro/go-plugins). | plugins in [github.com/asim/go-plugins](https://github.com/asim/go-plugins). | ||||||
|  |  | ||||||
| ## Getting Started | ## Getting Started | ||||||
|  |  | ||||||
| See [pkg.go.dev](https://pkg.go.dev/github.com/micro/go-micro/v3?tab=overview) for usage. | See [pkg.go.dev](https://pkg.go.dev/github.com/asim/go-micro/v3?tab=overview) for usage. | ||||||
|  |  | ||||||
| ## License | ## License | ||||||
|  |  | ||||||
| Go Micro is Apache 2.0 licensed. | [Polyform Strict](https://polyformproject.org/licenses/strict/1.0.0/). | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,6 +7,12 @@ import ( | |||||||
| 	"net" | 	"net" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | // The Let's Encrypt ACME endpoints | ||||||
|  | const ( | ||||||
|  | 	LetsEncryptStagingCA    = "https://acme-staging-v02.api.letsencrypt.org/directory" | ||||||
|  | 	LetsEncryptProductionCA = "https://acme-v02.api.letsencrypt.org/directory" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| var ( | var ( | ||||||
| 	// ErrProviderNotImplemented can be returned when attempting to | 	// ErrProviderNotImplemented can be returned when attempting to | ||||||
| 	// instantiate an unimplemented provider | 	// instantiate an unimplemented provider | ||||||
| @@ -19,10 +25,6 @@ type Provider interface { | |||||||
| 	Listen(...string) (net.Listener, error) | 	Listen(...string) (net.Listener, error) | ||||||
| 	// TLSConfig returns a tls config | 	// TLSConfig returns a tls config | ||||||
| 	TLSConfig(...string) (*tls.Config, error) | 	TLSConfig(...string) (*tls.Config, error) | ||||||
|  | 	// Implementation of the acme provider | ||||||
|  | 	String() string | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // The Let's Encrypt ACME endpoints |  | ||||||
| const ( |  | ||||||
| 	LetsEncryptStagingCA    = "https://acme-staging-v02.api.letsencrypt.org/directory" |  | ||||||
| 	LetsEncryptProductionCA = "https://acme-v02.api.letsencrypt.org/directory" |  | ||||||
| ) |  | ||||||
| @@ -7,8 +7,8 @@ import ( | |||||||
| 	"net" | 	"net" | ||||||
| 	"os" | 	"os" | ||||||
| 
 | 
 | ||||||
| 	"github.com/micro/go-micro/v3/api/server/acme" | 	"github.com/asim/go-micro/v3/acme" | ||||||
| 	"github.com/micro/go-micro/v3/logger" | 	"github.com/asim/go-micro/v3/logger" | ||||||
| 	"golang.org/x/crypto/acme/autocert" | 	"golang.org/x/crypto/acme/autocert" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @@ -40,6 +40,10 @@ func (a *autocertProvider) TLSConfig(hosts ...string) (*tls.Config, error) { | |||||||
| 	return m.TLSConfig(), nil | 	return m.TLSConfig(), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (a *autocertProvider) String() string { | ||||||
|  | 	return "autocert" | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // New returns an autocert acme.Provider | // New returns an autocert acme.Provider | ||||||
| func NewProvider() acme.Provider { | func NewProvider() acme.Provider { | ||||||
| 	return &autocertProvider{} | 	return &autocertProvider{} | ||||||
							
								
								
									
										58
									
								
								api/api.go
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								api/api.go
									
									
									
									
									
								
							| @@ -2,30 +2,32 @@ package api | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"net/http" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| 	"github.com/micro/go-micro/v3/server" | 	"github.com/asim/go-micro/v3/server" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Api interface { | // Gateway is an api gateway interface | ||||||
|  | type Gateway interface { | ||||||
| 	// Initialise options | 	// Initialise options | ||||||
| 	Init(...Option) error | 	Init(...Option) error | ||||||
| 	// Get the options | 	// Get the options | ||||||
| 	Options() Options | 	Options() Options | ||||||
| 	// Register a http handler | 	// Register an endpoint | ||||||
| 	Register(*Endpoint) error | 	Register(*Endpoint) error | ||||||
| 	// Register a route | 	// Deregister a route | ||||||
| 	Deregister(*Endpoint) error | 	Deregister(*Endpoint) error | ||||||
|  | 	// Register http handler | ||||||
|  | 	Handle(string, http.Handler) | ||||||
|  | 	// Start serving requests | ||||||
|  | 	Serve() error | ||||||
| 	// Implementation of api | 	// Implementation of api | ||||||
| 	String() string | 	String() string | ||||||
| } | } | ||||||
|  |  | ||||||
| type Options struct{} |  | ||||||
|  |  | ||||||
| type Option func(*Options) error |  | ||||||
|  |  | ||||||
| // Endpoint is a mapping between an RPC method and HTTP endpoint | // Endpoint is a mapping between an RPC method and HTTP endpoint | ||||||
| type Endpoint struct { | type Endpoint struct { | ||||||
| 	// RPC Method e.g. Greeter.Hello | 	// RPC Method e.g. Greeter.Hello | ||||||
| @@ -58,22 +60,6 @@ type Service struct { | |||||||
| 	Services []*registry.Service | 	Services []*registry.Service | ||||||
| } | } | ||||||
|  |  | ||||||
| func strip(s string) string { |  | ||||||
| 	return strings.TrimSpace(s) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func slice(s string) []string { |  | ||||||
| 	var sl []string |  | ||||||
|  |  | ||||||
| 	for _, p := range strings.Split(s, ",") { |  | ||||||
| 		if str := strip(p); len(str) > 0 { |  | ||||||
| 			sl = append(sl, strip(p)) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return sl |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Encode encodes an endpoint to endpoint metadata | // Encode encodes an endpoint to endpoint metadata | ||||||
| func Encode(e *Endpoint) map[string]string { | func Encode(e *Endpoint) map[string]string { | ||||||
| 	if e == nil { | 	if e == nil { | ||||||
| @@ -150,28 +136,6 @@ func Validate(e *Endpoint) error { | |||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| /* |  | ||||||
| Design ideas |  | ||||||
|  |  | ||||||
| // Gateway is an api gateway interface |  | ||||||
| type Gateway interface { |  | ||||||
| 	// Register a http handler |  | ||||||
| 	Handle(pattern string, http.Handler) |  | ||||||
| 	// Register a route |  | ||||||
| 	RegisterRoute(r Route) |  | ||||||
| 	// Init initialises the command line. |  | ||||||
| 	// It also parses further options. |  | ||||||
| 	Init(...Option) error |  | ||||||
| 	// Run the gateway |  | ||||||
| 	Run() error |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewGateway returns a new api gateway |  | ||||||
| func NewGateway() Gateway { |  | ||||||
| 	return newGateway() |  | ||||||
| } |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| // WithEndpoint returns a server.HandlerOption with endpoint metadata set | // WithEndpoint returns a server.HandlerOption with endpoint metadata set | ||||||
| // | // | ||||||
| // Usage: | // Usage: | ||||||
|   | |||||||
| @@ -1,121 +0,0 @@ | |||||||
| // Package api provides an http-rpc handler which provides the entire http request over rpc |  | ||||||
| package api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
|  |  | ||||||
| 	goapi "github.com/micro/go-micro/v3/api" |  | ||||||
| 	"github.com/micro/go-micro/v3/api/handler" |  | ||||||
| 	api "github.com/micro/go-micro/v3/api/proto" |  | ||||||
| 	"github.com/micro/go-micro/v3/client" |  | ||||||
| 	"github.com/micro/go-micro/v3/errors" |  | ||||||
| 	"github.com/micro/go-micro/v3/util/ctx" |  | ||||||
| 	"github.com/micro/go-micro/v3/util/router" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type apiHandler struct { |  | ||||||
| 	opts handler.Options |  | ||||||
| 	s    *goapi.Service |  | ||||||
| } |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	Handler = "api" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // API handler is the default handler which takes api.Request and returns api.Response |  | ||||||
| func (a *apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 	bsize := handler.DefaultMaxRecvSize |  | ||||||
| 	if a.opts.MaxRecvSize > 0 { |  | ||||||
| 		bsize = a.opts.MaxRecvSize |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r.Body = http.MaxBytesReader(w, r.Body, bsize) |  | ||||||
| 	request, err := requestToProto(r) |  | ||||||
| 	if err != nil { |  | ||||||
| 		er := errors.InternalServerError("go.micro.api", err.Error()) |  | ||||||
| 		w.Header().Set("Content-Type", "application/json") |  | ||||||
| 		w.WriteHeader(500) |  | ||||||
| 		w.Write([]byte(er.Error())) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var service *goapi.Service |  | ||||||
|  |  | ||||||
| 	if a.s != nil { |  | ||||||
| 		// we were given the service |  | ||||||
| 		service = a.s |  | ||||||
| 	} else if a.opts.Router != nil { |  | ||||||
| 		// try get service from router |  | ||||||
| 		s, err := a.opts.Router.Route(r) |  | ||||||
| 		if err != nil { |  | ||||||
| 			er := errors.InternalServerError("go.micro.api", err.Error()) |  | ||||||
| 			w.Header().Set("Content-Type", "application/json") |  | ||||||
| 			w.WriteHeader(500) |  | ||||||
| 			w.Write([]byte(er.Error())) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		service = s |  | ||||||
| 	} else { |  | ||||||
| 		// we have no way of routing the request |  | ||||||
| 		er := errors.InternalServerError("go.micro.api", "no route found") |  | ||||||
| 		w.Header().Set("Content-Type", "application/json") |  | ||||||
| 		w.WriteHeader(500) |  | ||||||
| 		w.Write([]byte(er.Error())) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// create request and response |  | ||||||
| 	c := a.opts.Client |  | ||||||
| 	req := c.NewRequest(service.Name, service.Endpoint.Name, request) |  | ||||||
| 	rsp := &api.Response{} |  | ||||||
|  |  | ||||||
| 	// create the context from headers |  | ||||||
| 	cx := ctx.FromRequest(r) |  | ||||||
|  |  | ||||||
| 	if err := c.Call(cx, req, rsp, client.WithRouter(router.New(service.Services))); err != nil { |  | ||||||
| 		w.Header().Set("Content-Type", "application/json") |  | ||||||
| 		ce := errors.Parse(err.Error()) |  | ||||||
| 		switch ce.Code { |  | ||||||
| 		case 0: |  | ||||||
| 			w.WriteHeader(500) |  | ||||||
| 		default: |  | ||||||
| 			w.WriteHeader(int(ce.Code)) |  | ||||||
| 		} |  | ||||||
| 		w.Write([]byte(ce.Error())) |  | ||||||
| 		return |  | ||||||
| 	} else if rsp.StatusCode == 0 { |  | ||||||
| 		rsp.StatusCode = http.StatusOK |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, header := range rsp.GetHeader() { |  | ||||||
| 		for _, val := range header.Values { |  | ||||||
| 			w.Header().Add(header.Key, val) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(w.Header().Get("Content-Type")) == 0 { |  | ||||||
| 		w.Header().Set("Content-Type", "application/json") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	w.WriteHeader(int(rsp.StatusCode)) |  | ||||||
| 	w.Write([]byte(rsp.Body)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (a *apiHandler) String() string { |  | ||||||
| 	return "api" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewHandler(opts ...handler.Option) handler.Handler { |  | ||||||
| 	options := handler.NewOptions(opts...) |  | ||||||
| 	return &apiHandler{ |  | ||||||
| 		opts: options, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func WithService(s *goapi.Service, opts ...handler.Option) handler.Handler { |  | ||||||
| 	options := handler.NewOptions(opts...) |  | ||||||
| 	return &apiHandler{ |  | ||||||
| 		opts: options, |  | ||||||
| 		s:    s, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,109 +0,0 @@ | |||||||
| package api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"mime" |  | ||||||
| 	"net" |  | ||||||
| 	"net/http" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	api "github.com/micro/go-micro/v3/api/proto" |  | ||||||
| 	"github.com/oxtoacart/bpool" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// need to calculate later to specify useful defaults |  | ||||||
| 	bufferPool = bpool.NewSizedBufferPool(1024, 8) |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func requestToProto(r *http.Request) (*api.Request, error) { |  | ||||||
| 	if err := r.ParseForm(); err != nil { |  | ||||||
| 		return nil, fmt.Errorf("Error parsing form: %v", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	req := &api.Request{ |  | ||||||
| 		Path:   r.URL.Path, |  | ||||||
| 		Method: r.Method, |  | ||||||
| 		Header: make(map[string]*api.Pair), |  | ||||||
| 		Get:    make(map[string]*api.Pair), |  | ||||||
| 		Post:   make(map[string]*api.Pair), |  | ||||||
| 		Url:    r.URL.String(), |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) |  | ||||||
| 	if err != nil { |  | ||||||
| 		ct = "text/plain; charset=UTF-8" //default CT is text/plain |  | ||||||
| 		r.Header.Set("Content-Type", ct) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	//set the body: |  | ||||||
| 	if r.Body != nil { |  | ||||||
| 		switch ct { |  | ||||||
| 		case "application/x-www-form-urlencoded": |  | ||||||
| 			// expect form vals in Post data |  | ||||||
| 		default: |  | ||||||
| 			buf := bufferPool.Get() |  | ||||||
| 			defer bufferPool.Put(buf) |  | ||||||
| 			if _, err = buf.ReadFrom(r.Body); err != nil { |  | ||||||
| 				return nil, err |  | ||||||
| 			} |  | ||||||
| 			req.Body = buf.String() |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Set X-Forwarded-For if it does not exist |  | ||||||
| 	if ip, _, err := net.SplitHostPort(r.RemoteAddr); err == nil { |  | ||||||
| 		if prior, ok := r.Header["X-Forwarded-For"]; ok { |  | ||||||
| 			ip = strings.Join(prior, ", ") + ", " + ip |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// Set the header |  | ||||||
| 		req.Header["X-Forwarded-For"] = &api.Pair{ |  | ||||||
| 			Key:    "X-Forwarded-For", |  | ||||||
| 			Values: []string{ip}, |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Host is stripped from net/http Headers so let's add it |  | ||||||
| 	req.Header["Host"] = &api.Pair{ |  | ||||||
| 		Key:    "Host", |  | ||||||
| 		Values: []string{r.Host}, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Get data |  | ||||||
| 	for key, vals := range r.URL.Query() { |  | ||||||
| 		header, ok := req.Get[key] |  | ||||||
| 		if !ok { |  | ||||||
| 			header = &api.Pair{ |  | ||||||
| 				Key: key, |  | ||||||
| 			} |  | ||||||
| 			req.Get[key] = header |  | ||||||
| 		} |  | ||||||
| 		header.Values = vals |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Post data |  | ||||||
| 	for key, vals := range r.PostForm { |  | ||||||
| 		header, ok := req.Post[key] |  | ||||||
| 		if !ok { |  | ||||||
| 			header = &api.Pair{ |  | ||||||
| 				Key: key, |  | ||||||
| 			} |  | ||||||
| 			req.Post[key] = header |  | ||||||
| 		} |  | ||||||
| 		header.Values = vals |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for key, vals := range r.Header { |  | ||||||
| 		header, ok := req.Header[key] |  | ||||||
| 		if !ok { |  | ||||||
| 			header = &api.Pair{ |  | ||||||
| 				Key: key, |  | ||||||
| 			} |  | ||||||
| 			req.Header[key] = header |  | ||||||
| 		} |  | ||||||
| 		header.Values = vals |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return req, nil |  | ||||||
| } |  | ||||||
| @@ -1,46 +0,0 @@ | |||||||
| package api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
| 	"net/url" |  | ||||||
| 	"testing" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func TestRequestToProto(t *testing.T) { |  | ||||||
| 	testData := []*http.Request{ |  | ||||||
| 		{ |  | ||||||
| 			Method: "GET", |  | ||||||
| 			Header: http.Header{ |  | ||||||
| 				"Header": []string{"test"}, |  | ||||||
| 			}, |  | ||||||
| 			URL: &url.URL{ |  | ||||||
| 				Scheme:   "http", |  | ||||||
| 				Host:     "localhost", |  | ||||||
| 				Path:     "/foo/bar", |  | ||||||
| 				RawQuery: "param1=value1", |  | ||||||
| 			}, |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, d := range testData { |  | ||||||
| 		p, err := requestToProto(d) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatal(err) |  | ||||||
| 		} |  | ||||||
| 		if p.Path != d.URL.Path { |  | ||||||
| 			t.Fatalf("Expected path %s got %s", d.URL.Path, p.Path) |  | ||||||
| 		} |  | ||||||
| 		if p.Method != d.Method { |  | ||||||
| 			t.Fatalf("Expected method %s got %s", d.Method, p.Method) |  | ||||||
| 		} |  | ||||||
| 		for k, v := range d.Header { |  | ||||||
| 			if val, ok := p.Header[k]; !ok { |  | ||||||
| 				t.Fatalf("Expected header %s", k) |  | ||||||
| 			} else { |  | ||||||
| 				if val.Values[0] != v[0] { |  | ||||||
| 					t.Fatalf("Expected val %s, got %s", val.Values[0], v[0]) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,141 +0,0 @@ | |||||||
| // Package event provides a handler which publishes an event |  | ||||||
| package event |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"net/http" |  | ||||||
| 	"path" |  | ||||||
| 	"regexp" |  | ||||||
| 	"strings" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/google/uuid" |  | ||||||
| 	"github.com/micro/go-micro/v3/api/handler" |  | ||||||
| 	proto "github.com/micro/go-micro/v3/api/proto" |  | ||||||
| 	"github.com/micro/go-micro/v3/util/ctx" |  | ||||||
| 	"github.com/oxtoacart/bpool" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	bufferPool = bpool.NewSizedBufferPool(1024, 8) |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type event struct { |  | ||||||
| 	opts handler.Options |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	Handler   = "event" |  | ||||||
| 	versionRe = regexp.MustCompilePOSIX("^v[0-9]+$") |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func eventName(parts []string) string { |  | ||||||
| 	return strings.Join(parts, ".") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func evRoute(ns, p string) (string, string) { |  | ||||||
| 	p = path.Clean(p) |  | ||||||
| 	p = strings.TrimPrefix(p, "/") |  | ||||||
|  |  | ||||||
| 	if len(p) == 0 { |  | ||||||
| 		return ns, "event" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	parts := strings.Split(p, "/") |  | ||||||
|  |  | ||||||
| 	// no path |  | ||||||
| 	if len(parts) == 0 { |  | ||||||
| 		// topic: namespace |  | ||||||
| 		// action: event |  | ||||||
| 		return strings.Trim(ns, "."), "event" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// Treat /v[0-9]+ as versioning |  | ||||||
| 	// /v1/foo/bar => topic: v1.foo action: bar |  | ||||||
| 	if len(parts) >= 2 && versionRe.Match([]byte(parts[0])) { |  | ||||||
| 		topic := ns + "." + strings.Join(parts[:2], ".") |  | ||||||
| 		action := eventName(parts[1:]) |  | ||||||
| 		return topic, action |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// /foo => topic: ns.foo action: foo |  | ||||||
| 	// /foo/bar => topic: ns.foo action: bar |  | ||||||
| 	topic := ns + "." + strings.Join(parts[:1], ".") |  | ||||||
| 	action := eventName(parts[1:]) |  | ||||||
|  |  | ||||||
| 	return topic, action |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (e *event) ServeHTTP(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 	bsize := handler.DefaultMaxRecvSize |  | ||||||
| 	if e.opts.MaxRecvSize > 0 { |  | ||||||
| 		bsize = e.opts.MaxRecvSize |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r.Body = http.MaxBytesReader(w, r.Body, bsize) |  | ||||||
|  |  | ||||||
| 	// request to topic:event |  | ||||||
| 	// create event |  | ||||||
| 	// publish to topic |  | ||||||
|  |  | ||||||
| 	topic, action := evRoute(e.opts.Namespace, r.URL.Path) |  | ||||||
|  |  | ||||||
| 	// create event |  | ||||||
| 	ev := &proto.Event{ |  | ||||||
| 		Name: action, |  | ||||||
| 		// TODO: dedupe event |  | ||||||
| 		Id:        fmt.Sprintf("%s-%s-%s", topic, action, uuid.New().String()), |  | ||||||
| 		Header:    make(map[string]*proto.Pair), |  | ||||||
| 		Timestamp: time.Now().Unix(), |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// set headers |  | ||||||
| 	for key, vals := range r.Header { |  | ||||||
| 		header, ok := ev.Header[key] |  | ||||||
| 		if !ok { |  | ||||||
| 			header = &proto.Pair{ |  | ||||||
| 				Key: key, |  | ||||||
| 			} |  | ||||||
| 			ev.Header[key] = header |  | ||||||
| 		} |  | ||||||
| 		header.Values = vals |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// set body |  | ||||||
| 	if r.Method == "GET" { |  | ||||||
| 		bytes, _ := json.Marshal(r.URL.Query()) |  | ||||||
| 		ev.Data = string(bytes) |  | ||||||
| 	} else { |  | ||||||
| 		// Read body |  | ||||||
| 		buf := bufferPool.Get() |  | ||||||
| 		defer bufferPool.Put(buf) |  | ||||||
| 		if _, err := buf.ReadFrom(r.Body); err != nil { |  | ||||||
| 			http.Error(w, err.Error(), 500) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		ev.Data = buf.String() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// get client |  | ||||||
| 	c := e.opts.Client |  | ||||||
|  |  | ||||||
| 	// create publication |  | ||||||
| 	p := c.NewMessage(topic, ev) |  | ||||||
|  |  | ||||||
| 	// publish event |  | ||||||
| 	if err := c.Publish(ctx.FromRequest(r), p); err != nil { |  | ||||||
| 		http.Error(w, err.Error(), 500) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (e *event) String() string { |  | ||||||
| 	return "event" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewHandler(opts ...handler.Option) handler.Handler { |  | ||||||
| 	return &event{ |  | ||||||
| 		opts: handler.NewOptions(opts...), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -9,9 +9,9 @@ import ( | |||||||
| 	"net/http/httputil" | 	"net/http/httputil" | ||||||
| 	"net/url" | 	"net/url" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api" | 	"github.com/asim/go-micro/v3/api" | ||||||
| 	"github.com/micro/go-micro/v3/api/handler" | 	"github.com/asim/go-micro/v3/api/handler" | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -28,7 +28,7 @@ type httpHandler struct { | |||||||
| func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||||
| 	service, err := h.getService(r) | 	service, err := h.getService(r) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		w.WriteHeader(500) | 		w.WriteHeader(http.StatusInternalServerError) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -39,7 +39,7 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||||||
|  |  | ||||||
| 	rp, err := url.Parse(service) | 	rp, err := url.Parse(service) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		w.WriteHeader(500) | 		w.WriteHeader(http.StatusInternalServerError) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,13 +6,13 @@ import ( | |||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api/handler" | 	"github.com/asim/go-micro/v3/api/handler" | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver" | 	"github.com/asim/go-micro/v3/api/resolver" | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver/vpath" | 	rpath "github.com/asim/go-micro/v3/api/resolver/path" | ||||||
| 	"github.com/micro/go-micro/v3/api/router" | 	"github.com/asim/go-micro/v3/api/router" | ||||||
| 	regRouter "github.com/micro/go-micro/v3/api/router/registry" | 	regRouter "github.com/asim/go-micro/v3/api/router/registry" | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| 	"github.com/micro/go-micro/v3/registry/memory" | 	"github.com/asim/go-micro/v3/registry/memory" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func testHttp(t *testing.T, path, service, ns string) { | func testHttp(t *testing.T, path, service, ns string) { | ||||||
| @@ -57,7 +57,7 @@ func testHttp(t *testing.T, path, service, ns string) { | |||||||
| 	rt := regRouter.NewRouter( | 	rt := regRouter.NewRouter( | ||||||
| 		router.WithHandler("http"), | 		router.WithHandler("http"), | ||||||
| 		router.WithRegistry(r), | 		router.WithRegistry(r), | ||||||
| 		router.WithResolver(vpath.NewResolver( | 		router.WithResolver(rpath.NewResolver( | ||||||
| 			resolver.WithServicePrefix(ns), | 			resolver.WithServicePrefix(ns), | ||||||
| 		)), | 		)), | ||||||
| 	) | 	) | ||||||
| @@ -92,31 +92,6 @@ func TestHttpHandler(t *testing.T) { | |||||||
| 			"go.micro.api.test", | 			"go.micro.api.test", | ||||||
| 			"go.micro.api", | 			"go.micro.api", | ||||||
| 		}, | 		}, | ||||||
| 		{ |  | ||||||
| 			"/v1/foo", |  | ||||||
| 			"go.micro.api.v1.foo", |  | ||||||
| 			"go.micro.api", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/v1/foo/bar", |  | ||||||
| 			"go.micro.api.v1.foo", |  | ||||||
| 			"go.micro.api", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/v2/baz", |  | ||||||
| 			"go.micro.api.v2.baz", |  | ||||||
| 			"go.micro.api", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/v2/baz/bar", |  | ||||||
| 			"go.micro.api.v2.baz", |  | ||||||
| 			"go.micro.api", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/v2/baz/bar", |  | ||||||
| 			"v2.baz", |  | ||||||
| 			"", |  | ||||||
| 		}, |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, d := range testData { | 	for _, d := range testData { | ||||||
|   | |||||||
| @@ -1,9 +1,9 @@ | |||||||
| package handler | package handler | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/v3/api/router" | 	"github.com/asim/go-micro/v3/api/router" | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	"github.com/micro/go-micro/v3/client/grpc" | 	"github.com/asim/go-micro/v3/client/grpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
|   | |||||||
| @@ -8,20 +8,20 @@ import ( | |||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
|  | 	"github.com/asim/go-micro/v3/api" | ||||||
|  | 	"github.com/asim/go-micro/v3/api/handler" | ||||||
|  | 	"github.com/asim/go-micro/v3/api/handler/rpc/proto" | ||||||
|  | 	"github.com/asim/go-micro/v3/client" | ||||||
|  | 	"github.com/asim/go-micro/v3/codec" | ||||||
|  | 	"github.com/asim/go-micro/v3/codec/jsonrpc" | ||||||
|  | 	"github.com/asim/go-micro/v3/codec/protorpc" | ||||||
|  | 	"github.com/asim/go-micro/v3/errors" | ||||||
|  | 	"github.com/asim/go-micro/v3/logger" | ||||||
|  | 	"github.com/asim/go-micro/v3/metadata" | ||||||
|  | 	"github.com/asim/go-micro/v3/util/ctx" | ||||||
|  | 	"github.com/asim/go-micro/v3/util/qson" | ||||||
|  | 	"github.com/asim/go-micro/v3/util/router" | ||||||
| 	jsonpatch "github.com/evanphx/json-patch/v5" | 	jsonpatch "github.com/evanphx/json-patch/v5" | ||||||
| 	"github.com/micro/go-micro/v3/api" |  | ||||||
| 	"github.com/micro/go-micro/v3/api/handler" |  | ||||||
| 	"github.com/micro/go-micro/v3/api/internal/proto" |  | ||||||
| 	"github.com/micro/go-micro/v3/client" |  | ||||||
| 	"github.com/micro/go-micro/v3/codec" |  | ||||||
| 	"github.com/micro/go-micro/v3/codec/jsonrpc" |  | ||||||
| 	"github.com/micro/go-micro/v3/codec/protorpc" |  | ||||||
| 	"github.com/micro/go-micro/v3/errors" |  | ||||||
| 	"github.com/micro/go-micro/v3/logger" |  | ||||||
| 	"github.com/micro/go-micro/v3/metadata" |  | ||||||
| 	"github.com/micro/go-micro/v3/util/ctx" |  | ||||||
| 	"github.com/micro/go-micro/v3/util/qson" |  | ||||||
| 	"github.com/micro/go-micro/v3/util/router" |  | ||||||
| 	"github.com/oxtoacart/bpool" | 	"github.com/oxtoacart/bpool" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -249,7 +249,7 @@ func requestPayload(r *http.Request) ([]byte, error) { | |||||||
| 			return nil, err | 			return nil, err | ||||||
| 		} | 		} | ||||||
| 		return raw.Marshal() | 		return raw.Marshal() | ||||||
| 	case strings.Contains(ct, "application/www-x-form-urlencoded"): | 	case strings.Contains(ct, "application/x-www-form-urlencoded"): | ||||||
| 		r.ParseForm() | 		r.ParseForm() | ||||||
|  |  | ||||||
| 		// generate a new set of values from the form | 		// generate a new set of values from the form | ||||||
| @@ -364,6 +364,13 @@ func requestPayload(r *http.Request) ([]byte, error) { | |||||||
| 			bodybuf = b | 			bodybuf = b | ||||||
| 		} | 		} | ||||||
| 		if bodydst == "" || bodydst == "*" { | 		if bodydst == "" || bodydst == "*" { | ||||||
|  | 			// jsonpatch resequences the json object so we avoid it if possible (some usecases such as | ||||||
|  | 			// validating signatures require the request body to be unchangedd). We're keeping support | ||||||
|  | 			// for the custom paramaters for backwards compatability reasons. | ||||||
|  | 			if string(out) == "{}" { | ||||||
|  | 				return bodybuf, nil | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			if out, err = jsonpatch.MergeMergePatches(out, bodybuf); err == nil { | 			if out, err = jsonpatch.MergeMergePatches(out, bodybuf); err == nil { | ||||||
| 				return out, nil | 				return out, nil | ||||||
| 			} | 			} | ||||||
| @@ -410,7 +417,6 @@ func requestPayload(r *http.Request) ([]byte, error) { | |||||||
|  |  | ||||||
| 		//fallback to previous unknown behaviour | 		//fallback to previous unknown behaviour | ||||||
| 		return bodybuf, nil | 		return bodybuf, nil | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return []byte{}, nil | 	return []byte{}, nil | ||||||
| @@ -422,11 +428,11 @@ func writeError(w http.ResponseWriter, r *http.Request, err error) { | |||||||
| 	switch ce.Code { | 	switch ce.Code { | ||||||
| 	case 0: | 	case 0: | ||||||
| 		// assuming it's totally screwed | 		// assuming it's totally screwed | ||||||
| 		ce.Code = 500 | 		ce.Code = http.StatusInternalServerError | ||||||
| 		ce.Id = "go.micro.api" | 		ce.Id = "go.micro.api" | ||||||
| 		ce.Status = http.StatusText(500) | 		ce.Status = http.StatusText(http.StatusInternalServerError) | ||||||
| 		ce.Detail = "error during request: " + ce.Detail | 		ce.Detail = "error during request: " + ce.Detail | ||||||
| 		w.WriteHeader(500) | 		w.WriteHeader(http.StatusInternalServerError) | ||||||
| 	default: | 	default: | ||||||
| 		w.WriteHeader(int(ce.Code)) | 		w.WriteHeader(int(ce.Code)) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -1,112 +0,0 @@ | |||||||
| package rpc |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"net/http" |  | ||||||
| 	"testing" |  | ||||||
|  |  | ||||||
| 	"github.com/golang/protobuf/proto" |  | ||||||
| 	go_api "github.com/micro/go-micro/v3/api/proto" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func TestRequestPayloadFromRequest(t *testing.T) { |  | ||||||
|  |  | ||||||
| 	// our test event so that we can validate serialising / deserializing of true protos works |  | ||||||
| 	protoEvent := go_api.Event{ |  | ||||||
| 		Name: "Test", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	protoBytes, err := proto.Marshal(&protoEvent) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal("Failed to marshal proto", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	jsonBytes, err := json.Marshal(protoEvent) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal("Failed to marshal proto to JSON ", err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	jsonUrlBytes := []byte(`{"key1":"val1","key2":"val2","name":"Test"}`) |  | ||||||
|  |  | ||||||
| 	t.Run("extracting a json from a POST request with url params", func(t *testing.T) { |  | ||||||
| 		r, err := http.NewRequest("POST", "http://localhost/my/path?key1=val1&key2=val2", bytes.NewReader(jsonBytes)) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatalf("Failed to created http.Request: %v", err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		extByte, err := requestPayload(r) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatalf("Failed to extract payload from request: %v", err) |  | ||||||
| 		} |  | ||||||
| 		if string(extByte) != string(jsonUrlBytes) { |  | ||||||
| 			t.Fatalf("Expected %v and %v to match", string(extByte), jsonUrlBytes) |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	t.Run("extracting a proto from a POST request", func(t *testing.T) { |  | ||||||
| 		r, err := http.NewRequest("POST", "http://localhost/my/path", bytes.NewReader(protoBytes)) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatalf("Failed to created http.Request: %v", err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		extByte, err := requestPayload(r) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatalf("Failed to extract payload from request: %v", err) |  | ||||||
| 		} |  | ||||||
| 		if string(extByte) != string(protoBytes) { |  | ||||||
| 			t.Fatalf("Expected %v and %v to match", string(extByte), string(protoBytes)) |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	t.Run("extracting JSON from a POST request", func(t *testing.T) { |  | ||||||
| 		r, err := http.NewRequest("POST", "http://localhost/my/path", bytes.NewReader(jsonBytes)) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatalf("Failed to created http.Request: %v", err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		extByte, err := requestPayload(r) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatalf("Failed to extract payload from request: %v", err) |  | ||||||
| 		} |  | ||||||
| 		if string(extByte) != string(jsonBytes) { |  | ||||||
| 			t.Fatalf("Expected %v and %v to match", string(extByte), string(jsonBytes)) |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	t.Run("extracting params from a GET request", func(t *testing.T) { |  | ||||||
|  |  | ||||||
| 		r, err := http.NewRequest("GET", "http://localhost/my/path", nil) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatalf("Failed to created http.Request: %v", err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		q := r.URL.Query() |  | ||||||
| 		q.Add("name", "Test") |  | ||||||
| 		r.URL.RawQuery = q.Encode() |  | ||||||
|  |  | ||||||
| 		extByte, err := requestPayload(r) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatalf("Failed to extract payload from request: %v", err) |  | ||||||
| 		} |  | ||||||
| 		if string(extByte) != string(jsonBytes) { |  | ||||||
| 			t.Fatalf("Expected %v and %v to match", string(extByte), string(jsonBytes)) |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	t.Run("GET request with no params", func(t *testing.T) { |  | ||||||
|  |  | ||||||
| 		r, err := http.NewRequest("GET", "http://localhost/my/path", nil) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatalf("Failed to created http.Request: %v", err) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		extByte, err := requestPayload(r) |  | ||||||
| 		if err != nil { |  | ||||||
| 			t.Fatalf("Failed to extract payload from request: %v", err) |  | ||||||
| 		} |  | ||||||
| 		if string(extByte) != "" { |  | ||||||
| 			t.Fatalf("Expected %v and %v to match", string(extByte), "") |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| @@ -9,14 +9,14 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/asim/go-micro/v3/api" | ||||||
|  | 	"github.com/asim/go-micro/v3/client" | ||||||
|  | 	raw "github.com/asim/go-micro/v3/codec/bytes" | ||||||
|  | 	"github.com/asim/go-micro/v3/logger" | ||||||
|  | 	"github.com/asim/go-micro/v3/util/router" | ||||||
| 	"github.com/gobwas/httphead" | 	"github.com/gobwas/httphead" | ||||||
| 	"github.com/gobwas/ws" | 	"github.com/gobwas/ws" | ||||||
| 	"github.com/gobwas/ws/wsutil" | 	"github.com/gobwas/ws/wsutil" | ||||||
| 	"github.com/micro/go-micro/v3/api" |  | ||||||
| 	"github.com/micro/go-micro/v3/client" |  | ||||||
| 	raw "github.com/micro/go-micro/v3/codec/bytes" |  | ||||||
| 	"github.com/micro/go-micro/v3/logger" |  | ||||||
| 	"github.com/micro/go-micro/v3/util/router" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // serveWebsocket will stream rpc back over websockets assuming json | // serveWebsocket will stream rpc back over websockets assuming json | ||||||
|   | |||||||
| @@ -1,181 +0,0 @@ | |||||||
| // Package web contains the web handler including websocket support |  | ||||||
| package web |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"io" |  | ||||||
| 	"math/rand" |  | ||||||
| 	"net" |  | ||||||
| 	"net/http" |  | ||||||
| 	"net/http/httputil" |  | ||||||
| 	"net/url" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api" |  | ||||||
| 	"github.com/micro/go-micro/v3/api/handler" |  | ||||||
| 	"github.com/micro/go-micro/v3/registry" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| const ( |  | ||||||
| 	Handler = "web" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type webHandler struct { |  | ||||||
| 	opts handler.Options |  | ||||||
| 	s    *api.Service |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (wh *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 	service, err := wh.getService(r) |  | ||||||
| 	if err != nil { |  | ||||||
| 		w.WriteHeader(500) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(service) == 0 { |  | ||||||
| 		w.WriteHeader(404) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	rp, err := url.Parse(service) |  | ||||||
| 	if err != nil { |  | ||||||
| 		w.WriteHeader(500) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if isWebSocket(r) { |  | ||||||
| 		wh.serveWebSocket(rp.Host, w, r) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	httputil.NewSingleHostReverseProxy(rp).ServeHTTP(w, r) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // getService returns the service for this request from the selector |  | ||||||
| func (wh *webHandler) getService(r *http.Request) (string, error) { |  | ||||||
| 	var service *api.Service |  | ||||||
|  |  | ||||||
| 	if wh.s != nil { |  | ||||||
| 		// we were given the service |  | ||||||
| 		service = wh.s |  | ||||||
| 	} else if wh.opts.Router != nil { |  | ||||||
| 		// try get service from router |  | ||||||
| 		s, err := wh.opts.Router.Route(r) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return "", err |  | ||||||
| 		} |  | ||||||
| 		service = s |  | ||||||
| 	} else { |  | ||||||
| 		// we have no way of routing the request |  | ||||||
| 		return "", errors.New("no route found") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// get the nodes |  | ||||||
| 	var nodes []*registry.Node |  | ||||||
| 	for _, srv := range service.Services { |  | ||||||
| 		nodes = append(nodes, srv.Nodes...) |  | ||||||
| 	} |  | ||||||
| 	if len(nodes) == 0 { |  | ||||||
| 		return "", errors.New("no route found") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// select a random node |  | ||||||
| 	node := nodes[rand.Int()%len(nodes)] |  | ||||||
|  |  | ||||||
| 	return fmt.Sprintf("http://%s", node.Address), nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // serveWebSocket used to serve a web socket proxied connection |  | ||||||
| func (wh *webHandler) serveWebSocket(host string, w http.ResponseWriter, r *http.Request) { |  | ||||||
| 	req := new(http.Request) |  | ||||||
| 	*req = *r |  | ||||||
|  |  | ||||||
| 	if len(host) == 0 { |  | ||||||
| 		http.Error(w, "invalid host", 500) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// set x-forward-for |  | ||||||
| 	if clientIP, _, err := net.SplitHostPort(r.RemoteAddr); err == nil { |  | ||||||
| 		if ips, ok := req.Header["X-Forwarded-For"]; ok { |  | ||||||
| 			clientIP = strings.Join(ips, ", ") + ", " + clientIP |  | ||||||
| 		} |  | ||||||
| 		req.Header.Set("X-Forwarded-For", clientIP) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// connect to the backend host |  | ||||||
| 	conn, err := net.Dial("tcp", host) |  | ||||||
| 	if err != nil { |  | ||||||
| 		http.Error(w, err.Error(), 500) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// hijack the connection |  | ||||||
| 	hj, ok := w.(http.Hijacker) |  | ||||||
| 	if !ok { |  | ||||||
| 		http.Error(w, "failed to connect", 500) |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	nc, _, err := hj.Hijack() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	defer nc.Close() |  | ||||||
| 	defer conn.Close() |  | ||||||
|  |  | ||||||
| 	if err = req.Write(conn); err != nil { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	errCh := make(chan error, 2) |  | ||||||
|  |  | ||||||
| 	cp := func(dst io.Writer, src io.Reader) { |  | ||||||
| 		_, err := io.Copy(dst, src) |  | ||||||
| 		errCh <- err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	go cp(conn, nc) |  | ||||||
| 	go cp(nc, conn) |  | ||||||
|  |  | ||||||
| 	<-errCh |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func isWebSocket(r *http.Request) bool { |  | ||||||
| 	contains := func(key, val string) bool { |  | ||||||
| 		vv := strings.Split(r.Header.Get(key), ",") |  | ||||||
| 		for _, v := range vv { |  | ||||||
| 			if val == strings.ToLower(strings.TrimSpace(v)) { |  | ||||||
| 				return true |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if contains("Connection", "upgrade") && contains("Upgrade", "websocket") { |  | ||||||
| 		return true |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (wh *webHandler) String() string { |  | ||||||
| 	return "web" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewHandler(opts ...handler.Option) handler.Handler { |  | ||||||
| 	return &webHandler{ |  | ||||||
| 		opts: handler.NewOptions(opts...), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func WithService(s *api.Service, opts ...handler.Option) handler.Handler { |  | ||||||
| 	options := handler.NewOptions(opts...) |  | ||||||
|  |  | ||||||
| 	return &webHandler{ |  | ||||||
| 		opts: options, |  | ||||||
| 		s:    s, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -5,70 +5,62 @@ import ( | |||||||
| 	"crypto/tls" | 	"crypto/tls" | ||||||
| 	"net" | 	"net" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" |  | ||||||
| 	"sync" | 	"sync" | ||||||
| 
 | 
 | ||||||
| 	"github.com/gorilla/handlers" | 	"github.com/asim/go-micro/v3/api" | ||||||
| 	"github.com/micro/go-micro/v3/api/server" | 	"github.com/asim/go-micro/v3/logger" | ||||||
| 	"github.com/micro/go-micro/v3/api/server/cors" |  | ||||||
| 	"github.com/micro/go-micro/v3/logger" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type httpServer struct { | type httpServer struct { | ||||||
| 	mux  *http.ServeMux | 	mux  *http.ServeMux | ||||||
| 	opts server.Options | 	opts api.Options | ||||||
| 
 | 
 | ||||||
| 	mtx     sync.RWMutex | 	mtx     sync.RWMutex | ||||||
| 	address string | 	address string | ||||||
| 	exit    chan chan error | 	exit    chan chan error | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewServer(address string, opts ...server.Option) server.Server { | // NewGateway returns a new HTTP api gateway | ||||||
| 	var options server.Options | func NewGateway(opts ...api.Option) api.Gateway { | ||||||
|  | 	var options api.Options | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		o(&options) | 		o(&options) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return &httpServer{ | 	return &httpServer{ | ||||||
| 		opts:    options, | 		opts: options, | ||||||
| 		mux:     http.NewServeMux(), | 		mux:  http.NewServeMux(), | ||||||
| 		address: address, | 		exit: make(chan chan error), | ||||||
| 		exit:    make(chan chan error), |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *httpServer) Address() string { | func (s *httpServer) Init(opts ...api.Option) error { | ||||||
| 	s.mtx.RLock() |  | ||||||
| 	defer s.mtx.RUnlock() |  | ||||||
| 	return s.address |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (s *httpServer) Init(opts ...server.Option) error { |  | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		o(&s.opts) | 		o(&s.opts) | ||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (s *httpServer) Options() api.Options { | ||||||
|  | 	return s.opts | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *httpServer) Register(ep *api.Endpoint) error   { return nil } | ||||||
|  | func (s *httpServer) Deregister(ep *api.Endpoint) error { return nil } | ||||||
|  | 
 | ||||||
| func (s *httpServer) Handle(path string, handler http.Handler) { | func (s *httpServer) Handle(path string, handler http.Handler) { | ||||||
| 	// TODO: move this stuff out to one place with ServeHTTP |  | ||||||
| 
 |  | ||||||
| 	// apply the wrappers, e.g. auth |  | ||||||
| 	for _, wrapper := range s.opts.Wrappers { |  | ||||||
| 		handler = wrapper(handler) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// wrap with cors |  | ||||||
| 	if s.opts.EnableCORS { |  | ||||||
| 		handler = cors.CombinedCORSHandler(handler) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// wrap with logger |  | ||||||
| 	handler = handlers.CombinedLoggingHandler(os.Stdout, handler) |  | ||||||
| 
 |  | ||||||
| 	s.mux.Handle(path, handler) | 	s.mux.Handle(path, handler) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (s *httpServer) Serve() error { | ||||||
|  | 	if err := s.Start(); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	<-s.exit | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (s *httpServer) Start() error { | func (s *httpServer) Start() error { | ||||||
| 	var l net.Listener | 	var l net.Listener | ||||||
| 	var err error | 	var err error | ||||||
| @@ -77,10 +69,10 @@ func (s *httpServer) Start() error { | |||||||
| 		// should we check the address to make sure its using :443? | 		// should we check the address to make sure its using :443? | ||||||
| 		l, err = s.opts.ACMEProvider.Listen(s.opts.ACMEHosts...) | 		l, err = s.opts.ACMEProvider.Listen(s.opts.ACMEHosts...) | ||||||
| 	} else if s.opts.EnableTLS && s.opts.TLSConfig != nil { | 	} else if s.opts.EnableTLS && s.opts.TLSConfig != nil { | ||||||
| 		l, err = tls.Listen("tcp", s.address, s.opts.TLSConfig) | 		l, err = tls.Listen("tcp", s.opts.Address, s.opts.TLSConfig) | ||||||
| 	} else { | 	} else { | ||||||
| 		// otherwise plain listen | 		// otherwise plain listen | ||||||
| 		l, err = net.Listen("tcp", s.address) | 		l, err = net.Listen("tcp", s.opts.Address) | ||||||
| 	} | 	} | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @@ -90,10 +82,6 @@ func (s *httpServer) Start() error { | |||||||
| 		logger.Infof("HTTP API Listening on %s", l.Addr().String()) | 		logger.Infof("HTTP API Listening on %s", l.Addr().String()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	s.mtx.Lock() |  | ||||||
| 	s.address = l.Addr().String() |  | ||||||
| 	s.mtx.Unlock() |  | ||||||
| 
 |  | ||||||
| 	go func() { | 	go func() { | ||||||
| 		if err := http.Serve(l, s.mux); err != nil { | 		if err := http.Serve(l, s.mux); err != nil { | ||||||
| 			// temporary fix | 			// temporary fix | ||||||
| @@ -1,37 +1,27 @@ | |||||||
| package server | package api | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"crypto/tls" | 	"crypto/tls" | ||||||
| 	"net/http" |  | ||||||
| 
 | 
 | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver" | 	"github.com/asim/go-micro/v3/acme" | ||||||
| 	"github.com/micro/go-micro/v3/api/server/acme" | 	"github.com/asim/go-micro/v3/api/resolver" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Option func(o *Options) |  | ||||||
| 
 |  | ||||||
| type Options struct { | type Options struct { | ||||||
|  | 	Address      string | ||||||
| 	EnableACME   bool | 	EnableACME   bool | ||||||
| 	EnableCORS   bool |  | ||||||
| 	ACMEProvider acme.Provider | 	ACMEProvider acme.Provider | ||||||
| 	EnableTLS    bool | 	EnableTLS    bool | ||||||
| 	ACMEHosts    []string | 	ACMEHosts    []string | ||||||
| 	TLSConfig    *tls.Config | 	TLSConfig    *tls.Config | ||||||
| 	Resolver     resolver.Resolver | 	Resolver     resolver.Resolver | ||||||
| 	Wrappers     []Wrapper |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type Wrapper func(h http.Handler) http.Handler | type Option func(o *Options) | ||||||
| 
 | 
 | ||||||
| func WrapHandler(w ...Wrapper) Option { | func Address(a string) Option { | ||||||
| 	return func(o *Options) { | 	return func(o *Options) { | ||||||
| 		o.Wrappers = append(o.Wrappers, w...) | 		o.Address = a | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func EnableCORS(b bool) Option { |  | ||||||
| 	return func(o *Options) { |  | ||||||
| 		o.EnableCORS = b |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @@ -1,335 +0,0 @@ | |||||||
| // Code generated by protoc-gen-go. DO NOT EDIT. |  | ||||||
| // source: api/proto/api.proto |  | ||||||
|  |  | ||||||
| package go_api |  | ||||||
|  |  | ||||||
| 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 |  | ||||||
|  |  | ||||||
| type Pair struct { |  | ||||||
| 	Key                  string   `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` |  | ||||||
| 	Values               []string `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` |  | ||||||
| 	XXX_sizecache        int32    `json:"-"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Pair) Reset()         { *m = Pair{} } |  | ||||||
| func (m *Pair) String() string { return proto.CompactTextString(m) } |  | ||||||
| func (*Pair) ProtoMessage()    {} |  | ||||||
| func (*Pair) Descriptor() ([]byte, []int) { |  | ||||||
| 	return fileDescriptor_2df576b66d12087a, []int{0} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Pair) XXX_Unmarshal(b []byte) error { |  | ||||||
| 	return xxx_messageInfo_Pair.Unmarshal(m, b) |  | ||||||
| } |  | ||||||
| func (m *Pair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |  | ||||||
| 	return xxx_messageInfo_Pair.Marshal(b, m, deterministic) |  | ||||||
| } |  | ||||||
| func (m *Pair) XXX_Merge(src proto.Message) { |  | ||||||
| 	xxx_messageInfo_Pair.Merge(m, src) |  | ||||||
| } |  | ||||||
| func (m *Pair) XXX_Size() int { |  | ||||||
| 	return xxx_messageInfo_Pair.Size(m) |  | ||||||
| } |  | ||||||
| func (m *Pair) XXX_DiscardUnknown() { |  | ||||||
| 	xxx_messageInfo_Pair.DiscardUnknown(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var xxx_messageInfo_Pair proto.InternalMessageInfo |  | ||||||
|  |  | ||||||
| func (m *Pair) GetKey() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Key |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Pair) GetValues() []string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Values |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // A HTTP request as RPC |  | ||||||
| // Forward by the api handler |  | ||||||
| type Request struct { |  | ||||||
| 	Method               string           `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` |  | ||||||
| 	Path                 string           `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` |  | ||||||
| 	Header               map[string]*Pair `protobuf:"bytes,3,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` |  | ||||||
| 	Get                  map[string]*Pair `protobuf:"bytes,4,rep,name=get,proto3" json:"get,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` |  | ||||||
| 	Post                 map[string]*Pair `protobuf:"bytes,5,rep,name=post,proto3" json:"post,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` |  | ||||||
| 	Body                 string           `protobuf:"bytes,6,opt,name=body,proto3" json:"body,omitempty"` |  | ||||||
| 	Url                  string           `protobuf:"bytes,7,opt,name=url,proto3" json:"url,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{}         `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte           `json:"-"` |  | ||||||
| 	XXX_sizecache        int32            `json:"-"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) Reset()         { *m = Request{} } |  | ||||||
| func (m *Request) String() string { return proto.CompactTextString(m) } |  | ||||||
| func (*Request) ProtoMessage()    {} |  | ||||||
| func (*Request) Descriptor() ([]byte, []int) { |  | ||||||
| 	return fileDescriptor_2df576b66d12087a, []int{1} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) XXX_Unmarshal(b []byte) error { |  | ||||||
| 	return xxx_messageInfo_Request.Unmarshal(m, b) |  | ||||||
| } |  | ||||||
| func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |  | ||||||
| 	return xxx_messageInfo_Request.Marshal(b, m, deterministic) |  | ||||||
| } |  | ||||||
| func (m *Request) XXX_Merge(src proto.Message) { |  | ||||||
| 	xxx_messageInfo_Request.Merge(m, src) |  | ||||||
| } |  | ||||||
| func (m *Request) XXX_Size() int { |  | ||||||
| 	return xxx_messageInfo_Request.Size(m) |  | ||||||
| } |  | ||||||
| func (m *Request) XXX_DiscardUnknown() { |  | ||||||
| 	xxx_messageInfo_Request.DiscardUnknown(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var xxx_messageInfo_Request proto.InternalMessageInfo |  | ||||||
|  |  | ||||||
| func (m *Request) GetMethod() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Method |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) GetPath() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Path |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) GetHeader() map[string]*Pair { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Header |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) GetGet() map[string]*Pair { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Get |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) GetPost() map[string]*Pair { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Post |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) GetBody() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Body |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) GetUrl() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Url |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // A HTTP response as RPC |  | ||||||
| // Expected response for the api handler |  | ||||||
| type Response struct { |  | ||||||
| 	StatusCode           int32            `protobuf:"varint,1,opt,name=statusCode,proto3" json:"statusCode,omitempty"` |  | ||||||
| 	Header               map[string]*Pair `protobuf:"bytes,2,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` |  | ||||||
| 	Body                 string           `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{}         `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte           `json:"-"` |  | ||||||
| 	XXX_sizecache        int32            `json:"-"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Response) Reset()         { *m = Response{} } |  | ||||||
| func (m *Response) String() string { return proto.CompactTextString(m) } |  | ||||||
| func (*Response) ProtoMessage()    {} |  | ||||||
| func (*Response) Descriptor() ([]byte, []int) { |  | ||||||
| 	return fileDescriptor_2df576b66d12087a, []int{2} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Response) XXX_Unmarshal(b []byte) error { |  | ||||||
| 	return xxx_messageInfo_Response.Unmarshal(m, b) |  | ||||||
| } |  | ||||||
| func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |  | ||||||
| 	return xxx_messageInfo_Response.Marshal(b, m, deterministic) |  | ||||||
| } |  | ||||||
| func (m *Response) XXX_Merge(src proto.Message) { |  | ||||||
| 	xxx_messageInfo_Response.Merge(m, src) |  | ||||||
| } |  | ||||||
| func (m *Response) XXX_Size() int { |  | ||||||
| 	return xxx_messageInfo_Response.Size(m) |  | ||||||
| } |  | ||||||
| func (m *Response) XXX_DiscardUnknown() { |  | ||||||
| 	xxx_messageInfo_Response.DiscardUnknown(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var xxx_messageInfo_Response proto.InternalMessageInfo |  | ||||||
|  |  | ||||||
| func (m *Response) GetStatusCode() int32 { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.StatusCode |  | ||||||
| 	} |  | ||||||
| 	return 0 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Response) GetHeader() map[string]*Pair { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Header |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Response) GetBody() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Body |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // A HTTP event as RPC |  | ||||||
| // Forwarded by the event handler |  | ||||||
| type Event struct { |  | ||||||
| 	// e.g login |  | ||||||
| 	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` |  | ||||||
| 	// uuid |  | ||||||
| 	Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` |  | ||||||
| 	// unix timestamp of event |  | ||||||
| 	Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` |  | ||||||
| 	// event headers |  | ||||||
| 	Header map[string]*Pair `protobuf:"bytes,4,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` |  | ||||||
| 	// the event data |  | ||||||
| 	Data                 string   `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` |  | ||||||
| 	XXX_sizecache        int32    `json:"-"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Event) Reset()         { *m = Event{} } |  | ||||||
| func (m *Event) String() string { return proto.CompactTextString(m) } |  | ||||||
| func (*Event) ProtoMessage()    {} |  | ||||||
| func (*Event) Descriptor() ([]byte, []int) { |  | ||||||
| 	return fileDescriptor_2df576b66d12087a, []int{3} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Event) XXX_Unmarshal(b []byte) error { |  | ||||||
| 	return xxx_messageInfo_Event.Unmarshal(m, b) |  | ||||||
| } |  | ||||||
| func (m *Event) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |  | ||||||
| 	return xxx_messageInfo_Event.Marshal(b, m, deterministic) |  | ||||||
| } |  | ||||||
| func (m *Event) XXX_Merge(src proto.Message) { |  | ||||||
| 	xxx_messageInfo_Event.Merge(m, src) |  | ||||||
| } |  | ||||||
| func (m *Event) XXX_Size() int { |  | ||||||
| 	return xxx_messageInfo_Event.Size(m) |  | ||||||
| } |  | ||||||
| func (m *Event) XXX_DiscardUnknown() { |  | ||||||
| 	xxx_messageInfo_Event.DiscardUnknown(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var xxx_messageInfo_Event proto.InternalMessageInfo |  | ||||||
|  |  | ||||||
| func (m *Event) GetName() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Name |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Event) GetId() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Id |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Event) GetTimestamp() int64 { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Timestamp |  | ||||||
| 	} |  | ||||||
| 	return 0 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Event) GetHeader() map[string]*Pair { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Header |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Event) GetData() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Data |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	proto.RegisterType((*Pair)(nil), "go.api.Pair") |  | ||||||
| 	proto.RegisterType((*Request)(nil), "go.api.Request") |  | ||||||
| 	proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Request.GetEntry") |  | ||||||
| 	proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Request.HeaderEntry") |  | ||||||
| 	proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Request.PostEntry") |  | ||||||
| 	proto.RegisterType((*Response)(nil), "go.api.Response") |  | ||||||
| 	proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Response.HeaderEntry") |  | ||||||
| 	proto.RegisterType((*Event)(nil), "go.api.Event") |  | ||||||
| 	proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Event.HeaderEntry") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func init() { proto.RegisterFile("api/proto/api.proto", fileDescriptor_2df576b66d12087a) } |  | ||||||
|  |  | ||||||
| var fileDescriptor_2df576b66d12087a = []byte{ |  | ||||||
| 	// 393 bytes of a gzipped FileDescriptorProto |  | ||||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xcd, 0xce, 0xd3, 0x30, |  | ||||||
| 	0x10, 0x54, 0xe2, 0x24, 0x6d, 0xb6, 0x08, 0x21, 0x23, 0x21, 0x53, 0x2a, 0x54, 0xe5, 0x54, 0x21, |  | ||||||
| 	0x91, 0x42, 0xcb, 0x01, 0x71, 0x85, 0xaa, 0x1c, 0x2b, 0xbf, 0x81, 0xab, 0x58, 0x6d, 0x44, 0x13, |  | ||||||
| 	0x9b, 0xd8, 0xa9, 0xd4, 0x87, 0xe3, 0xc0, 0x63, 0xf0, 0x36, 0xc8, 0x1b, 0xf7, 0xe7, 0xab, 0xfa, |  | ||||||
| 	0x5d, 0xbe, 0xaf, 0xb7, 0x89, 0x3d, 0x3b, 0x3b, 0x3b, 0xeb, 0xc0, 0x6b, 0xa1, 0xcb, 0xa9, 0x6e, |  | ||||||
| 	0x94, 0x55, 0x53, 0xa1, 0xcb, 0x1c, 0x11, 0x4d, 0x36, 0x2a, 0x17, 0xba, 0xcc, 0x3e, 0x41, 0xb4, |  | ||||||
| 	0x12, 0x65, 0x43, 0x5f, 0x01, 0xf9, 0x25, 0x0f, 0x2c, 0x18, 0x07, 0x93, 0x94, 0x3b, 0x48, 0xdf, |  | ||||||
| 	0x40, 0xb2, 0x17, 0xbb, 0x56, 0x1a, 0x16, 0x8e, 0xc9, 0x24, 0xe5, 0xfe, 0x2b, 0xfb, 0x4b, 0xa0, |  | ||||||
| 	0xc7, 0xe5, 0xef, 0x56, 0x1a, 0xeb, 0x38, 0x95, 0xb4, 0x5b, 0x55, 0xf8, 0x42, 0xff, 0x45, 0x29, |  | ||||||
| 	0x44, 0x5a, 0xd8, 0x2d, 0x0b, 0xf1, 0x14, 0x31, 0x9d, 0x43, 0xb2, 0x95, 0xa2, 0x90, 0x0d, 0x23, |  | ||||||
| 	0x63, 0x32, 0x19, 0xcc, 0xde, 0xe5, 0x9d, 0x85, 0xdc, 0x8b, 0xe5, 0x3f, 0xf1, 0x76, 0x51, 0xdb, |  | ||||||
| 	0xe6, 0xc0, 0x3d, 0x95, 0x7e, 0x00, 0xb2, 0x91, 0x96, 0x45, 0x58, 0xc1, 0xae, 0x2b, 0x96, 0xd2, |  | ||||||
| 	0x76, 0x74, 0x47, 0xa2, 0x1f, 0x21, 0xd2, 0xca, 0x58, 0x16, 0x23, 0xf9, 0xed, 0x35, 0x79, 0xa5, |  | ||||||
| 	0x8c, 0x67, 0x23, 0xcd, 0x79, 0x5c, 0xab, 0xe2, 0xc0, 0x92, 0xce, 0xa3, 0xc3, 0x2e, 0x85, 0xb6, |  | ||||||
| 	0xd9, 0xb1, 0x5e, 0x97, 0x42, 0xdb, 0xec, 0x86, 0x4b, 0x18, 0x5c, 0xf8, 0xba, 0x11, 0x53, 0x06, |  | ||||||
| 	0x31, 0x06, 0x83, 0xb3, 0x0e, 0x66, 0x2f, 0x8e, 0x6d, 0x5d, 0xaa, 0xbc, 0xbb, 0xfa, 0x16, 0x7e, |  | ||||||
| 	0x0d, 0x86, 0x3f, 0xa0, 0x7f, 0xb4, 0xfb, 0x0c, 0x95, 0x05, 0xa4, 0xa7, 0x39, 0x9e, 0x2e, 0x93, |  | ||||||
| 	0xfd, 0x09, 0xa0, 0xcf, 0xa5, 0xd1, 0xaa, 0x36, 0x92, 0xbe, 0x07, 0x30, 0x56, 0xd8, 0xd6, 0x7c, |  | ||||||
| 	0x57, 0x85, 0x44, 0xb5, 0x98, 0x5f, 0x9c, 0xd0, 0x2f, 0xa7, 0xc5, 0x85, 0x98, 0xec, 0xe8, 0x9c, |  | ||||||
| 	0x6c, 0xa7, 0x70, 0x73, 0x73, 0xc7, 0x78, 0xc9, 0x39, 0xde, 0xbb, 0x85, 0x99, 0xfd, 0x0b, 0x20, |  | ||||||
| 	0x5e, 0xec, 0x65, 0x8d, 0x5b, 0xac, 0x45, 0x25, 0xbd, 0x08, 0x62, 0xfa, 0x12, 0xc2, 0xb2, 0xf0, |  | ||||||
| 	0x6f, 0x2f, 0x2c, 0x0b, 0x3a, 0x82, 0xd4, 0x96, 0x95, 0x34, 0x56, 0x54, 0x1a, 0xfd, 0x10, 0x7e, |  | ||||||
| 	0x3e, 0xa0, 0x9f, 0x4f, 0xe3, 0x45, 0x0f, 0x1f, 0x0e, 0x36, 0x78, 0x6c, 0xb6, 0x42, 0x58, 0xc1, |  | ||||||
| 	0xe2, 0xae, 0xa9, 0xc3, 0x77, 0x9b, 0x6d, 0x9d, 0xe0, 0x0f, 0x3a, 0xff, 0x1f, 0x00, 0x00, 0xff, |  | ||||||
| 	0xff, 0xd4, 0x6d, 0x70, 0x51, 0xb7, 0x03, 0x00, 0x00, |  | ||||||
| } |  | ||||||
| @@ -1,21 +0,0 @@ | |||||||
| // Code generated by protoc-gen-micro. DO NOT EDIT. |  | ||||||
| // source: api/proto/api.proto |  | ||||||
|  |  | ||||||
| package go_api |  | ||||||
|  |  | ||||||
| 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,43 +0,0 @@ | |||||||
| syntax = "proto3"; |  | ||||||
|  |  | ||||||
| package go.api; |  | ||||||
|  |  | ||||||
| message Pair { |  | ||||||
| 	string key = 1; |  | ||||||
| 	repeated string values = 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // A HTTP request as RPC |  | ||||||
| // Forward by the api handler |  | ||||||
| message Request { |  | ||||||
|         string method = 1; |  | ||||||
|         string path = 2; |  | ||||||
|         map<string, Pair> header = 3; |  | ||||||
|         map<string, Pair> get = 4; |  | ||||||
|         map<string, Pair> post = 5; |  | ||||||
|         string body = 6;  // raw request body; if not application/x-www-form-urlencoded |  | ||||||
| 	string url = 7; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // A HTTP response as RPC |  | ||||||
| // Expected response for the api handler |  | ||||||
| message Response { |  | ||||||
|         int32 statusCode = 1; |  | ||||||
|         map<string, Pair> header = 2; |  | ||||||
|         string body = 3; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // A HTTP event as RPC |  | ||||||
| // Forwarded by the event handler |  | ||||||
| message Event { |  | ||||||
| 	// e.g login |  | ||||||
| 	string name = 1; |  | ||||||
| 	// uuid |  | ||||||
| 	string id = 2; |  | ||||||
| 	// unix timestamp of event |  | ||||||
| 	int64 timestamp = 3; |  | ||||||
| 	// event headers |  | ||||||
|         map<string, Pair> header = 4; |  | ||||||
| 	// the event data |  | ||||||
| 	string data = 5; |  | ||||||
| } |  | ||||||
| @@ -6,7 +6,7 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver" | 	"github.com/asim/go-micro/v3/api/resolver" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Resolver struct { | type Resolver struct { | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ package host | |||||||
| import ( | import ( | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver" | 	"github.com/asim/go-micro/v3/api/resolver" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Resolver struct { | type Resolver struct { | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package resolver | package resolver | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Options struct { | type Options struct { | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver" | 	"github.com/asim/go-micro/v3/api/resolver" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Resolver struct { | type Resolver struct { | ||||||
|   | |||||||
| @@ -1,85 +0,0 @@ | |||||||
| // Package subdomain is a resolver which uses the subdomain to determine the domain to route to. It |  | ||||||
| // offloads the endpoint resolution to a child resolver which is provided in New. |  | ||||||
| package subdomain |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net" |  | ||||||
| 	"net/http" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver" |  | ||||||
| 	"github.com/micro/go-micro/v3/logger" |  | ||||||
| 	"golang.org/x/net/publicsuffix" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func NewResolver(parent resolver.Resolver, opts ...resolver.Option) resolver.Resolver { |  | ||||||
| 	options := resolver.NewOptions(opts...) |  | ||||||
| 	return &Resolver{options, parent} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Resolver struct { |  | ||||||
| 	opts resolver.Options |  | ||||||
| 	resolver.Resolver |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Resolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) { |  | ||||||
| 	if dom := r.Domain(req); len(dom) > 0 { |  | ||||||
| 		opts = append(opts, resolver.Domain(dom)) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return r.Resolver.Resolve(req, opts...) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Resolver) Domain(req *http.Request) string { |  | ||||||
| 	// determine the host, e.g. foobar.m3o.app |  | ||||||
| 	host := req.URL.Hostname() |  | ||||||
| 	if len(host) == 0 { |  | ||||||
| 		if h, _, err := net.SplitHostPort(req.Host); err == nil { |  | ||||||
| 			host = h // host does contain a port |  | ||||||
| 		} else if strings.Contains(err.Error(), "missing port in address") { |  | ||||||
| 			host = req.Host // host does not contain a port |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// check for an ip address |  | ||||||
| 	if net.ParseIP(host) != nil { |  | ||||||
| 		return "" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// check for dev enviroment |  | ||||||
| 	if host == "localhost" || host == "127.0.0.1" { |  | ||||||
| 		return "" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// extract the top level domain plus one (e.g. 'myapp.com') |  | ||||||
| 	domain, err := publicsuffix.EffectiveTLDPlusOne(host) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logger.Debugf("Unable to extract domain from %v", host) |  | ||||||
| 		return "" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// there was no subdomain |  | ||||||
| 	if host == domain { |  | ||||||
| 		return "" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// remove the domain from the host, leaving the subdomain, e.g. "staging.foo.myapp.com" => "staging.foo" |  | ||||||
| 	subdomain := strings.TrimSuffix(host, "."+domain) |  | ||||||
|  |  | ||||||
| 	// ignore the API subdomain |  | ||||||
| 	if subdomain == "api" { |  | ||||||
| 		return "" |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// return the reversed subdomain as the namespace, e.g. "staging.foo" => "foo-staging" |  | ||||||
| 	comps := strings.Split(subdomain, ".") |  | ||||||
| 	for i := len(comps)/2 - 1; i >= 0; i-- { |  | ||||||
| 		opp := len(comps) - 1 - i |  | ||||||
| 		comps[i], comps[opp] = comps[opp], comps[i] |  | ||||||
| 	} |  | ||||||
| 	return strings.Join(comps, "-") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Resolver) String() string { |  | ||||||
| 	return "subdomain" |  | ||||||
| } |  | ||||||
| @@ -1,71 +0,0 @@ | |||||||
| package subdomain |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
| 	"net/url" |  | ||||||
| 	"testing" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver/vpath" |  | ||||||
|  |  | ||||||
| 	"github.com/stretchr/testify/assert" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func TestResolve(t *testing.T) { |  | ||||||
| 	tt := []struct { |  | ||||||
| 		Name   string |  | ||||||
| 		Host   string |  | ||||||
| 		Result string |  | ||||||
| 	}{ |  | ||||||
| 		{ |  | ||||||
| 			Name:   "Top level domain", |  | ||||||
| 			Host:   "micro.mu", |  | ||||||
| 			Result: "micro", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			Name:   "Effective top level domain", |  | ||||||
| 			Host:   "micro.com.au", |  | ||||||
| 			Result: "micro", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			Name:   "Subdomain dev", |  | ||||||
| 			Host:   "dev.micro.mu", |  | ||||||
| 			Result: "dev", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			Name:   "Subdomain foo", |  | ||||||
| 			Host:   "foo.micro.mu", |  | ||||||
| 			Result: "foo", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			Name:   "Multi-level subdomain", |  | ||||||
| 			Host:   "staging.myapp.m3o.app", |  | ||||||
| 			Result: "myapp-staging", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			Name:   "Dev host", |  | ||||||
| 			Host:   "127.0.0.1", |  | ||||||
| 			Result: "micro", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			Name:   "Localhost", |  | ||||||
| 			Host:   "localhost", |  | ||||||
| 			Result: "micro", |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			Name:   "IP host", |  | ||||||
| 			Host:   "81.151.101.146", |  | ||||||
| 			Result: "micro", |  | ||||||
| 		}, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, tc := range tt { |  | ||||||
| 		t.Run(tc.Name, func(t *testing.T) { |  | ||||||
| 			r := NewResolver(vpath.NewResolver()) |  | ||||||
| 			result, err := r.Resolve(&http.Request{URL: &url.URL{Host: tc.Host, Path: "foo/bar"}}) |  | ||||||
| 			assert.Nil(t, err, "Expecter err to be nil") |  | ||||||
| 			if result != nil { |  | ||||||
| 				assert.Equal(t, tc.Result, result.Domain, "Expected %v but got %v", tc.Result, result.Domain) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,75 +0,0 @@ | |||||||
| // Package vpath resolves using http path and recognised versioned urls |  | ||||||
| package vpath |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"errors" |  | ||||||
| 	"net/http" |  | ||||||
| 	"regexp" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func NewResolver(opts ...resolver.Option) resolver.Resolver { |  | ||||||
| 	return &Resolver{opts: resolver.NewOptions(opts...)} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Resolver struct { |  | ||||||
| 	opts resolver.Options |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	re = regexp.MustCompile("^v[0-9]+$") |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func (r *Resolver) Resolve(req *http.Request, opts ...resolver.ResolveOption) (*resolver.Endpoint, error) { |  | ||||||
| 	if req.URL.Path == "/" { |  | ||||||
| 		return nil, errors.New("unknown name") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	options := resolver.NewResolveOptions(opts...) |  | ||||||
|  |  | ||||||
| 	parts := strings.Split(req.URL.Path[1:], "/") |  | ||||||
| 	if len(parts) == 1 { |  | ||||||
| 		return &resolver.Endpoint{ |  | ||||||
| 			Name:   r.withPrefix(parts...), |  | ||||||
| 			Host:   req.Host, |  | ||||||
| 			Method: req.Method, |  | ||||||
| 			Path:   req.URL.Path, |  | ||||||
| 			Domain: options.Domain, |  | ||||||
| 		}, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// /v1/foo |  | ||||||
| 	if re.MatchString(parts[0]) { |  | ||||||
| 		return &resolver.Endpoint{ |  | ||||||
| 			Name:   r.withPrefix(parts[0:2]...), |  | ||||||
| 			Host:   req.Host, |  | ||||||
| 			Method: req.Method, |  | ||||||
| 			Path:   req.URL.Path, |  | ||||||
| 			Domain: options.Domain, |  | ||||||
| 		}, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return &resolver.Endpoint{ |  | ||||||
| 		Name:   r.withPrefix(parts[0]), |  | ||||||
| 		Host:   req.Host, |  | ||||||
| 		Method: req.Method, |  | ||||||
| 		Path:   req.URL.Path, |  | ||||||
| 		Domain: options.Domain, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *Resolver) String() string { |  | ||||||
| 	return "path" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // withPrefix transforms "foo" into "go.micro.api.foo" |  | ||||||
| func (r *Resolver) withPrefix(parts ...string) string { |  | ||||||
| 	p := r.opts.ServicePrefix |  | ||||||
| 	if len(p) > 0 { |  | ||||||
| 		parts = append([]string{p}, parts...) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return strings.Join(parts, ".") |  | ||||||
| } |  | ||||||
| @@ -1,10 +1,10 @@ | |||||||
| package router | package router | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver" | 	"github.com/asim/go-micro/v3/api/resolver" | ||||||
| 	"github.com/micro/go-micro/v3/api/resolver/vpath" | 	"github.com/asim/go-micro/v3/api/resolver/path" | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| 	"github.com/micro/go-micro/v3/registry/mdns" | 	"github.com/asim/go-micro/v3/registry/mdns" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Options struct { | type Options struct { | ||||||
| @@ -26,7 +26,7 @@ func NewOptions(opts ...Option) Options { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if options.Resolver == nil { | 	if options.Resolver == nil { | ||||||
| 		options.Resolver = vpath.NewResolver( | 		options.Resolver = path.NewResolver( | ||||||
| 			resolver.WithHandler(options.Handler), | 			resolver.WithHandler(options.Handler), | ||||||
| 		) | 		) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -10,13 +10,13 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api" | 	"github.com/asim/go-micro/v3/api" | ||||||
| 	"github.com/micro/go-micro/v3/api/router" | 	"github.com/asim/go-micro/v3/api/router" | ||||||
| 	"github.com/micro/go-micro/v3/logger" | 	"github.com/asim/go-micro/v3/logger" | ||||||
| 	"github.com/micro/go-micro/v3/metadata" | 	"github.com/asim/go-micro/v3/metadata" | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| 	"github.com/micro/go-micro/v3/registry/cache" | 	"github.com/asim/go-micro/v3/registry/cache" | ||||||
| 	util "github.com/micro/go-micro/v3/util/router" | 	util "github.com/asim/go-micro/v3/util/router" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // endpoint struct, that holds compiled pcre | // endpoint struct, that holds compiled pcre | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ package registry | |||||||
| import ( | import ( | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ package router | |||||||
| import ( | import ( | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api" | 	"github.com/asim/go-micro/v3/api" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Router is used to determine an endpoint for a request | // Router is used to determine an endpoint for a request | ||||||
|   | |||||||
| @@ -9,20 +9,18 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api" | 	"github.com/asim/go-micro/v3/api/handler" | ||||||
| 	"github.com/micro/go-micro/v3/api/handler" | 	"github.com/asim/go-micro/v3/api/handler/rpc" | ||||||
| 	"github.com/micro/go-micro/v3/api/handler/rpc" | 	"github.com/asim/go-micro/v3/api/router" | ||||||
| 	"github.com/micro/go-micro/v3/api/router" | 	rregistry "github.com/asim/go-micro/v3/api/router/registry" | ||||||
| 	rregistry "github.com/micro/go-micro/v3/api/router/registry" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	rstatic "github.com/micro/go-micro/v3/api/router/static" | 	gcli "github.com/asim/go-micro/v3/client/grpc" | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	rmemory "github.com/asim/go-micro/v3/registry/memory" | ||||||
| 	gcli "github.com/micro/go-micro/v3/client/grpc" | 	rt "github.com/asim/go-micro/v3/router" | ||||||
| 	rmemory "github.com/micro/go-micro/v3/registry/memory" | 	regRouter "github.com/asim/go-micro/v3/router/registry" | ||||||
| 	rt "github.com/micro/go-micro/v3/router" | 	"github.com/asim/go-micro/v3/server" | ||||||
| 	regRouter "github.com/micro/go-micro/v3/router/registry" | 	gsrv "github.com/asim/go-micro/v3/server/grpc" | ||||||
| 	"github.com/micro/go-micro/v3/server" | 	pb "github.com/asim/go-micro/v3/server/grpc/proto" | ||||||
| 	gsrv "github.com/micro/go-micro/v3/server/grpc" |  | ||||||
| 	pb "github.com/micro/go-micro/v3/server/grpc/proto" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // server is used to implement helloworld.GreeterServer. | // server is used to implement helloworld.GreeterServer. | ||||||
| @@ -128,124 +126,3 @@ func TestRouterRegistryPcre(t *testing.T) { | |||||||
| 	time.Sleep(1 * time.Second) | 	time.Sleep(1 * time.Second) | ||||||
| 	check(t, hsrv.Addr, "http://%s/api/v0/test/call/TEST", `{"msg":"Hello TEST"}`) | 	check(t, hsrv.Addr, "http://%s/api/v0/test/call/TEST", `{"msg":"Hello TEST"}`) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestRouterStaticPcre(t *testing.T) { |  | ||||||
| 	s, c := initial(t) |  | ||||||
| 	defer s.Stop() |  | ||||||
|  |  | ||||||
| 	router := rstatic.NewRouter( |  | ||||||
| 		router.WithHandler(rpc.Handler), |  | ||||||
| 		router.WithRegistry(s.Options().Registry), |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	err := router.Register(&api.Endpoint{ |  | ||||||
| 		Name:    "foo.Test.Call", |  | ||||||
| 		Method:  []string{"POST"}, |  | ||||||
| 		Path:    []string{"^/api/v0/test/call/?$"}, |  | ||||||
| 		Handler: "rpc", |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	hrpc := rpc.NewHandler( |  | ||||||
| 		handler.WithClient(c), |  | ||||||
| 		handler.WithRouter(router), |  | ||||||
| 	) |  | ||||||
| 	hsrv := &http.Server{ |  | ||||||
| 		Handler:        hrpc, |  | ||||||
| 		Addr:           "127.0.0.1:6543", |  | ||||||
| 		WriteTimeout:   15 * time.Second, |  | ||||||
| 		ReadTimeout:    15 * time.Second, |  | ||||||
| 		IdleTimeout:    20 * time.Second, |  | ||||||
| 		MaxHeaderBytes: 1024 * 1024 * 1, // 1Mb |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	go func() { |  | ||||||
| 		log.Println(hsrv.ListenAndServe()) |  | ||||||
| 	}() |  | ||||||
| 	defer hsrv.Close() |  | ||||||
|  |  | ||||||
| 	time.Sleep(1 * time.Second) |  | ||||||
| 	check(t, hsrv.Addr, "http://%s/api/v0/test/call", `{"msg":"Hello "}`) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestRouterStaticGpath(t *testing.T) { |  | ||||||
| 	s, c := initial(t) |  | ||||||
| 	defer s.Stop() |  | ||||||
|  |  | ||||||
| 	router := rstatic.NewRouter( |  | ||||||
| 		router.WithHandler(rpc.Handler), |  | ||||||
| 		router.WithRegistry(s.Options().Registry), |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	err := router.Register(&api.Endpoint{ |  | ||||||
| 		Name:    "foo.Test.Call", |  | ||||||
| 		Method:  []string{"POST"}, |  | ||||||
| 		Path:    []string{"/api/v0/test/call/{uuid}"}, |  | ||||||
| 		Handler: "rpc", |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	hrpc := rpc.NewHandler( |  | ||||||
| 		handler.WithClient(c), |  | ||||||
| 		handler.WithRouter(router), |  | ||||||
| 	) |  | ||||||
| 	hsrv := &http.Server{ |  | ||||||
| 		Handler:        hrpc, |  | ||||||
| 		Addr:           "127.0.0.1:6543", |  | ||||||
| 		WriteTimeout:   15 * time.Second, |  | ||||||
| 		ReadTimeout:    15 * time.Second, |  | ||||||
| 		IdleTimeout:    20 * time.Second, |  | ||||||
| 		MaxHeaderBytes: 1024 * 1024 * 1, // 1Mb |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	go func() { |  | ||||||
| 		log.Println(hsrv.ListenAndServe()) |  | ||||||
| 	}() |  | ||||||
| 	defer hsrv.Close() |  | ||||||
|  |  | ||||||
| 	time.Sleep(1 * time.Second) |  | ||||||
| 	check(t, hsrv.Addr, "http://%s/api/v0/test/call/TEST", `{"msg":"Hello TEST"}`) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestRouterStaticPcreInvalid(t *testing.T) { |  | ||||||
| 	var ep *api.Endpoint |  | ||||||
| 	var err error |  | ||||||
|  |  | ||||||
| 	s, c := initial(t) |  | ||||||
| 	defer s.Stop() |  | ||||||
|  |  | ||||||
| 	router := rstatic.NewRouter( |  | ||||||
| 		router.WithHandler(rpc.Handler), |  | ||||||
| 		router.WithRegistry(s.Options().Registry), |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	ep = &api.Endpoint{ |  | ||||||
| 		Name:    "foo.Test.Call", |  | ||||||
| 		Method:  []string{"POST"}, |  | ||||||
| 		Path:    []string{"^/api/v0/test/call/?"}, |  | ||||||
| 		Handler: "rpc", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = router.Register(ep) |  | ||||||
| 	if err == nil { |  | ||||||
| 		t.Fatalf("invalid endpoint %v", ep) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	ep = &api.Endpoint{ |  | ||||||
| 		Name:    "foo.Test.Call", |  | ||||||
| 		Method:  []string{"POST"}, |  | ||||||
| 		Path:    []string{"/api/v0/test/call/?$"}, |  | ||||||
| 		Handler: "rpc", |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	err = router.Register(ep) |  | ||||||
| 	if err == nil { |  | ||||||
| 		t.Fatalf("invalid endpoint %v", ep) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	_ = c |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,356 +0,0 @@ | |||||||
| package static |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"net/http" |  | ||||||
| 	"regexp" |  | ||||||
| 	"strings" |  | ||||||
| 	"sync" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/api" |  | ||||||
| 	"github.com/micro/go-micro/v3/api/router" |  | ||||||
| 	"github.com/micro/go-micro/v3/logger" |  | ||||||
| 	"github.com/micro/go-micro/v3/metadata" |  | ||||||
| 	"github.com/micro/go-micro/v3/registry" |  | ||||||
| 	rutil "github.com/micro/go-micro/v3/util/registry" |  | ||||||
| 	util "github.com/micro/go-micro/v3/util/router" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type endpoint struct { |  | ||||||
| 	apiep    *api.Endpoint |  | ||||||
| 	hostregs []*regexp.Regexp |  | ||||||
| 	pathregs []util.Pattern |  | ||||||
| 	pcreregs []*regexp.Regexp |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // router is the default router |  | ||||||
| type staticRouter struct { |  | ||||||
| 	exit chan bool |  | ||||||
| 	opts router.Options |  | ||||||
| 	sync.RWMutex |  | ||||||
| 	eps map[string]*endpoint |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *staticRouter) isClosed() bool { |  | ||||||
| 	select { |  | ||||||
| 	case <-r.exit: |  | ||||||
| 		return true |  | ||||||
| 	default: |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| /* |  | ||||||
| // watch for endpoint changes |  | ||||||
| func (r *staticRouter) watch() { |  | ||||||
| 	var attempts int |  | ||||||
|  |  | ||||||
| 	for { |  | ||||||
| 		if r.isClosed() { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// watch for changes |  | ||||||
| 		w, err := r.opts.Registry.Watch() |  | ||||||
| 		if err != nil { |  | ||||||
| 			attempts++ |  | ||||||
| 			log.Println("Error watching endpoints", err) |  | ||||||
| 			time.Sleep(time.Duration(attempts) * time.Second) |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		ch := make(chan bool) |  | ||||||
|  |  | ||||||
| 		go func() { |  | ||||||
| 			select { |  | ||||||
| 			case <-ch: |  | ||||||
| 				w.Stop() |  | ||||||
| 			case <-r.exit: |  | ||||||
| 				w.Stop() |  | ||||||
| 			} |  | ||||||
| 		}() |  | ||||||
|  |  | ||||||
| 		// reset if we get here |  | ||||||
| 		attempts = 0 |  | ||||||
|  |  | ||||||
| 		for { |  | ||||||
| 			// process next event |  | ||||||
| 			res, err := w.Next() |  | ||||||
| 			if err != nil { |  | ||||||
| 				log.Println("Error getting next endpoint", err) |  | ||||||
| 				close(ch) |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 			r.process(res) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| */ |  | ||||||
|  |  | ||||||
| func (r *staticRouter) Register(ep *api.Endpoint) error { |  | ||||||
| 	if err := api.Validate(ep); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var pathregs []util.Pattern |  | ||||||
| 	var hostregs []*regexp.Regexp |  | ||||||
| 	var pcreregs []*regexp.Regexp |  | ||||||
|  |  | ||||||
| 	for _, h := range ep.Host { |  | ||||||
| 		if h == "" || h == "*" { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		hostreg, err := regexp.CompilePOSIX(h) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		hostregs = append(hostregs, hostreg) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, p := range ep.Path { |  | ||||||
| 		var pcreok bool |  | ||||||
|  |  | ||||||
| 		// pcre only when we have start and end markers |  | ||||||
| 		if p[0] == '^' && p[len(p)-1] == '$' { |  | ||||||
| 			pcrereg, err := regexp.CompilePOSIX(p) |  | ||||||
| 			if err == nil { |  | ||||||
| 				pcreregs = append(pcreregs, pcrereg) |  | ||||||
| 				pcreok = true |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		rule, err := util.Parse(p) |  | ||||||
| 		if err != nil && !pcreok { |  | ||||||
| 			return err |  | ||||||
| 		} else if err != nil && pcreok { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		tpl := rule.Compile() |  | ||||||
| 		pathreg, err := util.NewPattern(tpl.Version, tpl.OpCodes, tpl.Pool, "") |  | ||||||
| 		if err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		pathregs = append(pathregs, pathreg) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r.Lock() |  | ||||||
| 	r.eps[ep.Name] = &endpoint{ |  | ||||||
| 		apiep:    ep, |  | ||||||
| 		pcreregs: pcreregs, |  | ||||||
| 		pathregs: pathregs, |  | ||||||
| 		hostregs: hostregs, |  | ||||||
| 	} |  | ||||||
| 	r.Unlock() |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *staticRouter) Deregister(ep *api.Endpoint) error { |  | ||||||
| 	if err := api.Validate(ep); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	r.Lock() |  | ||||||
| 	delete(r.eps, ep.Name) |  | ||||||
| 	r.Unlock() |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *staticRouter) Options() router.Options { |  | ||||||
| 	return r.opts |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *staticRouter) Close() error { |  | ||||||
| 	select { |  | ||||||
| 	case <-r.exit: |  | ||||||
| 		return nil |  | ||||||
| 	default: |  | ||||||
| 		close(r.exit) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *staticRouter) Endpoint(req *http.Request) (*api.Service, error) { |  | ||||||
| 	ep, err := r.endpoint(req) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	epf := strings.Split(ep.apiep.Name, ".") |  | ||||||
| 	services, err := r.opts.Registry.GetService(epf[0]) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// hack for stream endpoint |  | ||||||
| 	if ep.apiep.Stream { |  | ||||||
| 		svcs := rutil.Copy(services) |  | ||||||
| 		for _, svc := range svcs { |  | ||||||
| 			if len(svc.Endpoints) == 0 { |  | ||||||
| 				e := ®istry.Endpoint{} |  | ||||||
| 				e.Name = strings.Join(epf[1:], ".") |  | ||||||
| 				e.Metadata = make(map[string]string) |  | ||||||
| 				e.Metadata["stream"] = "true" |  | ||||||
| 				svc.Endpoints = append(svc.Endpoints, e) |  | ||||||
| 			} |  | ||||||
| 			for _, e := range svc.Endpoints { |  | ||||||
| 				e.Name = strings.Join(epf[1:], ".") |  | ||||||
| 				e.Metadata = make(map[string]string) |  | ||||||
| 				e.Metadata["stream"] = "true" |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		services = svcs |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	svc := &api.Service{ |  | ||||||
| 		Name: epf[0], |  | ||||||
| 		Endpoint: &api.Endpoint{ |  | ||||||
| 			Name:    strings.Join(epf[1:], "."), |  | ||||||
| 			Handler: "rpc", |  | ||||||
| 			Host:    ep.apiep.Host, |  | ||||||
| 			Method:  ep.apiep.Method, |  | ||||||
| 			Path:    ep.apiep.Path, |  | ||||||
| 			Body:    ep.apiep.Body, |  | ||||||
| 			Stream:  ep.apiep.Stream, |  | ||||||
| 		}, |  | ||||||
| 		Services: services, |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return svc, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *staticRouter) endpoint(req *http.Request) (*endpoint, error) { |  | ||||||
| 	if r.isClosed() { |  | ||||||
| 		return nil, errors.New("router closed") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	r.RLock() |  | ||||||
| 	defer r.RUnlock() |  | ||||||
|  |  | ||||||
| 	var idx int |  | ||||||
| 	if len(req.URL.Path) > 0 && req.URL.Path != "/" { |  | ||||||
| 		idx = 1 |  | ||||||
| 	} |  | ||||||
| 	path := strings.Split(req.URL.Path[idx:], "/") |  | ||||||
| 	// use the first match |  | ||||||
| 	// TODO: weighted matching |  | ||||||
|  |  | ||||||
| 	for _, ep := range r.eps { |  | ||||||
| 		var mMatch, hMatch, pMatch bool |  | ||||||
|  |  | ||||||
| 		// 1. try method |  | ||||||
| 		for _, m := range ep.apiep.Method { |  | ||||||
| 			if m == req.Method { |  | ||||||
| 				mMatch = true |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if !mMatch { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if logger.V(logger.DebugLevel, logger.DefaultLogger) { |  | ||||||
| 			logger.Debugf("api method match %s", req.Method) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// 2. try host |  | ||||||
| 		if len(ep.apiep.Host) == 0 { |  | ||||||
| 			hMatch = true |  | ||||||
| 		} else { |  | ||||||
| 			for idx, h := range ep.apiep.Host { |  | ||||||
| 				if h == "" || h == "*" { |  | ||||||
| 					hMatch = true |  | ||||||
| 					break |  | ||||||
| 				} else { |  | ||||||
| 					if ep.hostregs[idx].MatchString(req.URL.Host) { |  | ||||||
| 						hMatch = true |  | ||||||
| 						break |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 		if !hMatch { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if logger.V(logger.DebugLevel, logger.DefaultLogger) { |  | ||||||
| 			logger.Debugf("api host match %s", req.URL.Host) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// 3. try google.api path |  | ||||||
| 		for _, pathreg := range ep.pathregs { |  | ||||||
| 			matches, err := pathreg.Match(path, "") |  | ||||||
| 			if err != nil { |  | ||||||
| 				if logger.V(logger.DebugLevel, logger.DefaultLogger) { |  | ||||||
| 					logger.Debugf("api gpath not match %s != %v", path, pathreg) |  | ||||||
| 				} |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 			if logger.V(logger.DebugLevel, logger.DefaultLogger) { |  | ||||||
| 				logger.Debugf("api gpath match %s = %v", path, pathreg) |  | ||||||
| 			} |  | ||||||
| 			pMatch = true |  | ||||||
| 			ctx := req.Context() |  | ||||||
| 			md, ok := metadata.FromContext(ctx) |  | ||||||
| 			if !ok { |  | ||||||
| 				md = make(metadata.Metadata) |  | ||||||
| 			} |  | ||||||
| 			for k, v := range matches { |  | ||||||
| 				md[fmt.Sprintf("x-api-field-%s", k)] = v |  | ||||||
| 			} |  | ||||||
| 			md["x-api-body"] = ep.apiep.Body |  | ||||||
| 			*req = *req.Clone(metadata.NewContext(ctx, md)) |  | ||||||
| 			break |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if !pMatch { |  | ||||||
| 			// 4. try path via pcre path matching |  | ||||||
| 			for _, pathreg := range ep.pcreregs { |  | ||||||
| 				if !pathreg.MatchString(req.URL.Path) { |  | ||||||
| 					if logger.V(logger.DebugLevel, logger.DefaultLogger) { |  | ||||||
| 						logger.Debugf("api pcre path not match %s != %v", req.URL.Path, pathreg) |  | ||||||
| 					} |  | ||||||
| 					continue |  | ||||||
| 				} |  | ||||||
| 				pMatch = true |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if !pMatch { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		// TODO: Percentage traffic |  | ||||||
|  |  | ||||||
| 		// we got here, so its a match |  | ||||||
| 		return ep, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// no match |  | ||||||
| 	return nil, fmt.Errorf("endpoint not found for %v", req.URL) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (r *staticRouter) Route(req *http.Request) (*api.Service, error) { |  | ||||||
| 	if r.isClosed() { |  | ||||||
| 		return nil, errors.New("router closed") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// try get an endpoint |  | ||||||
| 	ep, err := r.Endpoint(req) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return ep, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewRouter(opts ...router.Option) *staticRouter { |  | ||||||
| 	options := router.NewOptions(opts...) |  | ||||||
| 	r := &staticRouter{ |  | ||||||
| 		exit: make(chan bool), |  | ||||||
| 		opts: options, |  | ||||||
| 		eps:  make(map[string]*endpoint), |  | ||||||
| 	} |  | ||||||
| 	//go r.watch() |  | ||||||
| 	//go r.refresh() |  | ||||||
| 	return r |  | ||||||
| } |  | ||||||
| @@ -1,68 +0,0 @@ | |||||||
| // Package certmagic is the ACME provider from github.com/caddyserver/certmagic |  | ||||||
| package certmagic |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"crypto/tls" |  | ||||||
| 	"math/rand" |  | ||||||
| 	"net" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/caddyserver/certmagic" |  | ||||||
| 	"github.com/micro/go-micro/v3/api/server/acme" |  | ||||||
| 	"github.com/micro/go-micro/v3/logger" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type certmagicProvider struct { |  | ||||||
| 	opts acme.Options |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // TODO: set self-contained options |  | ||||||
| func (c *certmagicProvider) setup() { |  | ||||||
| 	certmagic.DefaultACME.CA = c.opts.CA |  | ||||||
| 	if c.opts.ChallengeProvider != nil { |  | ||||||
| 		// Enabling DNS Challenge disables the other challenges |  | ||||||
| 		certmagic.DefaultACME.DNSProvider = c.opts.ChallengeProvider |  | ||||||
| 	} |  | ||||||
| 	if c.opts.OnDemand { |  | ||||||
| 		certmagic.Default.OnDemand = new(certmagic.OnDemandConfig) |  | ||||||
| 	} |  | ||||||
| 	if c.opts.Cache != nil { |  | ||||||
| 		// already validated by new() |  | ||||||
| 		certmagic.Default.Storage = c.opts.Cache.(certmagic.Storage) |  | ||||||
| 	} |  | ||||||
| 	// If multiple instances of the provider are running, inject some |  | ||||||
| 	// randomness so they don't collide |  | ||||||
| 	// RenewalWindowRatio [0.33 - 0.50) |  | ||||||
| 	rand.Seed(time.Now().UnixNano()) |  | ||||||
| 	randomRatio := float64(rand.Intn(17)+33) * 0.01 |  | ||||||
| 	certmagic.Default.RenewalWindowRatio = randomRatio |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *certmagicProvider) Listen(hosts ...string) (net.Listener, error) { |  | ||||||
| 	c.setup() |  | ||||||
| 	return certmagic.Listen(hosts) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *certmagicProvider) TLSConfig(hosts ...string) (*tls.Config, error) { |  | ||||||
| 	c.setup() |  | ||||||
| 	return certmagic.TLS(hosts) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewProvider returns a certmagic provider |  | ||||||
| func NewProvider(options ...acme.Option) acme.Provider { |  | ||||||
| 	opts := acme.DefaultOptions() |  | ||||||
|  |  | ||||||
| 	for _, o := range options { |  | ||||||
| 		o(&opts) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if opts.Cache != nil { |  | ||||||
| 		if _, ok := opts.Cache.(certmagic.Storage); !ok { |  | ||||||
| 			logger.Fatal("ACME: cache provided doesn't implement certmagic's Storage interface") |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return &certmagicProvider{ |  | ||||||
| 		opts: opts, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,147 +0,0 @@ | |||||||
| package certmagic |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| 	"encoding/gob" |  | ||||||
| 	"errors" |  | ||||||
| 	"fmt" |  | ||||||
| 	"path" |  | ||||||
| 	"strings" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/caddyserver/certmagic" |  | ||||||
| 	"github.com/micro/go-micro/v3/store" |  | ||||||
| 	"github.com/micro/go-micro/v3/sync" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // File represents a "File" that will be stored in store.Store - the contents and last modified time |  | ||||||
| type File struct { |  | ||||||
| 	// last modified time |  | ||||||
| 	LastModified time.Time |  | ||||||
| 	// Contents |  | ||||||
| 	Contents []byte |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // storage is an implementation of certmagic.Storage using micro's sync.Map and store.Store interfaces. |  | ||||||
| // As certmagic storage expects a filesystem (with stat() abilities) we have to implement |  | ||||||
| // the bare minimum of metadata. |  | ||||||
| type storage struct { |  | ||||||
| 	lock  sync.Sync |  | ||||||
| 	store store.Store |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *storage) Lock(key string) error { |  | ||||||
| 	return s.lock.Lock(key, sync.LockTTL(10*time.Minute)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *storage) Unlock(key string) error { |  | ||||||
| 	return s.lock.Unlock(key) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *storage) Store(key string, value []byte) error { |  | ||||||
| 	f := File{ |  | ||||||
| 		LastModified: time.Now(), |  | ||||||
| 		Contents:     value, |  | ||||||
| 	} |  | ||||||
| 	buf := &bytes.Buffer{} |  | ||||||
| 	e := gob.NewEncoder(buf) |  | ||||||
| 	if err := e.Encode(f); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	r := &store.Record{ |  | ||||||
| 		Key:   key, |  | ||||||
| 		Value: buf.Bytes(), |  | ||||||
| 	} |  | ||||||
| 	return s.store.Write(r) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *storage) Load(key string) ([]byte, error) { |  | ||||||
| 	if !s.Exists(key) { |  | ||||||
| 		return nil, certmagic.ErrNotExist(errors.New(key + " doesn't exist")) |  | ||||||
| 	} |  | ||||||
| 	records, err := s.store.Read(key) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if len(records) != 1 { |  | ||||||
| 		return nil, fmt.Errorf("ACME Storage: multiple records matched key %s", key) |  | ||||||
| 	} |  | ||||||
| 	b := bytes.NewBuffer(records[0].Value) |  | ||||||
| 	d := gob.NewDecoder(b) |  | ||||||
| 	var f File |  | ||||||
| 	err = d.Decode(&f) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return f.Contents, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *storage) Delete(key string) error { |  | ||||||
| 	return s.store.Delete(key) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *storage) Exists(key string) bool { |  | ||||||
| 	if _, err := s.store.Read(key); err != nil { |  | ||||||
| 		return false |  | ||||||
| 	} |  | ||||||
| 	return true |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *storage) List(prefix string, recursive bool) ([]string, error) { |  | ||||||
| 	keys, err := s.store.List() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	//nolint:prealloc |  | ||||||
| 	var results []string |  | ||||||
| 	for _, k := range keys { |  | ||||||
| 		if strings.HasPrefix(k, prefix) { |  | ||||||
| 			results = append(results, k) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	if recursive { |  | ||||||
| 		return results, nil |  | ||||||
| 	} |  | ||||||
| 	keysMap := make(map[string]bool) |  | ||||||
| 	for _, key := range results { |  | ||||||
| 		dir := strings.Split(strings.TrimPrefix(key, prefix+"/"), "/") |  | ||||||
| 		keysMap[dir[0]] = true |  | ||||||
| 	} |  | ||||||
| 	results = make([]string, 0) |  | ||||||
| 	for k := range keysMap { |  | ||||||
| 		results = append(results, path.Join(prefix, k)) |  | ||||||
| 	} |  | ||||||
| 	return results, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *storage) Stat(key string) (certmagic.KeyInfo, error) { |  | ||||||
| 	records, err := s.store.Read(key) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return certmagic.KeyInfo{}, err |  | ||||||
| 	} |  | ||||||
| 	if len(records) != 1 { |  | ||||||
| 		return certmagic.KeyInfo{}, fmt.Errorf("ACME Storage: multiple records matched key %s", key) |  | ||||||
| 	} |  | ||||||
| 	b := bytes.NewBuffer(records[0].Value) |  | ||||||
| 	d := gob.NewDecoder(b) |  | ||||||
| 	var f File |  | ||||||
| 	err = d.Decode(&f) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return certmagic.KeyInfo{}, err |  | ||||||
| 	} |  | ||||||
| 	return certmagic.KeyInfo{ |  | ||||||
| 		Key:        key, |  | ||||||
| 		Modified:   f.LastModified, |  | ||||||
| 		Size:       int64(len(f.Contents)), |  | ||||||
| 		IsTerminal: false, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewStorage returns a certmagic.Storage backed by a go-micro/lock and go-micro/store |  | ||||||
| func NewStorage(lock sync.Sync, store store.Store) certmagic.Storage { |  | ||||||
| 	return &storage{ |  | ||||||
| 		lock:  lock, |  | ||||||
| 		store: store, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,44 +0,0 @@ | |||||||
| package cors |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // CombinedCORSHandler wraps a server and provides CORS headers |  | ||||||
| func CombinedCORSHandler(h http.Handler) http.Handler { |  | ||||||
| 	return corsHandler{h} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type corsHandler struct { |  | ||||||
| 	handler http.Handler |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c corsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 	SetHeaders(w, r) |  | ||||||
|  |  | ||||||
| 	if r.Method == "OPTIONS" { |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	c.handler.ServeHTTP(w, r) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // SetHeaders sets the CORS headers |  | ||||||
| func SetHeaders(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 	set := func(w http.ResponseWriter, k, v string) { |  | ||||||
| 		if v := w.Header().Get(k); len(v) > 0 { |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		w.Header().Set(k, v) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if origin := r.Header.Get("Origin"); len(origin) > 0 { |  | ||||||
| 		set(w, "Access-Control-Allow-Origin", origin) |  | ||||||
| 	} else { |  | ||||||
| 		set(w, "Access-Control-Allow-Origin", "*") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	set(w, "Access-Control-Allow-Credentials", "true") |  | ||||||
| 	set(w, "Access-Control-Allow-Methods", "POST, PATCH, GET, OPTIONS, PUT, DELETE") |  | ||||||
| 	set(w, "Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") |  | ||||||
| } |  | ||||||
| @@ -1,41 +0,0 @@ | |||||||
| package http |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"io/ioutil" |  | ||||||
| 	"net/http" |  | ||||||
| 	"testing" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func TestHTTPServer(t *testing.T) { |  | ||||||
| 	testResponse := "hello world" |  | ||||||
|  |  | ||||||
| 	s := NewServer("localhost:0") |  | ||||||
|  |  | ||||||
| 	s.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |  | ||||||
| 		fmt.Fprint(w, testResponse) |  | ||||||
| 	})) |  | ||||||
|  |  | ||||||
| 	if err := s.Start(); err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	rsp, err := http.Get(fmt.Sprintf("http://%s/", s.Address())) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 	defer rsp.Body.Close() |  | ||||||
|  |  | ||||||
| 	b, err := ioutil.ReadAll(rsp.Body) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if string(b) != testResponse { |  | ||||||
| 		t.Fatalf("Unexpected response, got %s, expected %s", string(b), testResponse) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := s.Stop(); err != nil { |  | ||||||
| 		t.Fatal(err) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,15 +0,0 @@ | |||||||
| // Package server provides an API gateway server which handles inbound requests |  | ||||||
| package server |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"net/http" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // Server serves api requests |  | ||||||
| type Server interface { |  | ||||||
| 	Address() string |  | ||||||
| 	Init(opts ...Option) error |  | ||||||
| 	Handle(path string, handler http.Handler) |  | ||||||
| 	Start() error |  | ||||||
| 	Stop() error |  | ||||||
| } |  | ||||||
| @@ -1,268 +0,0 @@ | |||||||
| // Code generated by protoc-gen-go. DO NOT EDIT. |  | ||||||
| // source: api/service/proto/api.proto |  | ||||||
|  |  | ||||||
| package go_micro_api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	context "context" |  | ||||||
| 	fmt "fmt" |  | ||||||
| 	proto "github.com/golang/protobuf/proto" |  | ||||||
| 	grpc "google.golang.org/grpc" |  | ||||||
| 	codes "google.golang.org/grpc/codes" |  | ||||||
| 	status "google.golang.org/grpc/status" |  | ||||||
| 	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 |  | ||||||
|  |  | ||||||
| type Endpoint struct { |  | ||||||
| 	Name                 string   `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` |  | ||||||
| 	Host                 []string `protobuf:"bytes,2,rep,name=host,proto3" json:"host,omitempty"` |  | ||||||
| 	Path                 []string `protobuf:"bytes,3,rep,name=path,proto3" json:"path,omitempty"` |  | ||||||
| 	Method               []string `protobuf:"bytes,4,rep,name=method,proto3" json:"method,omitempty"` |  | ||||||
| 	Stream               bool     `protobuf:"varint,5,opt,name=stream,proto3" json:"stream,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` |  | ||||||
| 	XXX_sizecache        int32    `json:"-"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Endpoint) Reset()         { *m = Endpoint{} } |  | ||||||
| func (m *Endpoint) String() string { return proto.CompactTextString(m) } |  | ||||||
| func (*Endpoint) ProtoMessage()    {} |  | ||||||
| func (*Endpoint) Descriptor() ([]byte, []int) { |  | ||||||
| 	return fileDescriptor_c4a48b6b680b5c31, []int{0} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Endpoint) XXX_Unmarshal(b []byte) error { |  | ||||||
| 	return xxx_messageInfo_Endpoint.Unmarshal(m, b) |  | ||||||
| } |  | ||||||
| func (m *Endpoint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |  | ||||||
| 	return xxx_messageInfo_Endpoint.Marshal(b, m, deterministic) |  | ||||||
| } |  | ||||||
| func (m *Endpoint) XXX_Merge(src proto.Message) { |  | ||||||
| 	xxx_messageInfo_Endpoint.Merge(m, src) |  | ||||||
| } |  | ||||||
| func (m *Endpoint) XXX_Size() int { |  | ||||||
| 	return xxx_messageInfo_Endpoint.Size(m) |  | ||||||
| } |  | ||||||
| func (m *Endpoint) XXX_DiscardUnknown() { |  | ||||||
| 	xxx_messageInfo_Endpoint.DiscardUnknown(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var xxx_messageInfo_Endpoint proto.InternalMessageInfo |  | ||||||
|  |  | ||||||
| func (m *Endpoint) GetName() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Name |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Endpoint) GetHost() []string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Host |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Endpoint) GetPath() []string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Path |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Endpoint) GetMethod() []string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Method |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Endpoint) GetStream() bool { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Stream |  | ||||||
| 	} |  | ||||||
| 	return false |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type EmptyResponse struct { |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` |  | ||||||
| 	XXX_sizecache        int32    `json:"-"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *EmptyResponse) Reset()         { *m = EmptyResponse{} } |  | ||||||
| func (m *EmptyResponse) String() string { return proto.CompactTextString(m) } |  | ||||||
| func (*EmptyResponse) ProtoMessage()    {} |  | ||||||
| func (*EmptyResponse) Descriptor() ([]byte, []int) { |  | ||||||
| 	return fileDescriptor_c4a48b6b680b5c31, []int{1} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *EmptyResponse) XXX_Unmarshal(b []byte) error { |  | ||||||
| 	return xxx_messageInfo_EmptyResponse.Unmarshal(m, b) |  | ||||||
| } |  | ||||||
| func (m *EmptyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |  | ||||||
| 	return xxx_messageInfo_EmptyResponse.Marshal(b, m, deterministic) |  | ||||||
| } |  | ||||||
| func (m *EmptyResponse) XXX_Merge(src proto.Message) { |  | ||||||
| 	xxx_messageInfo_EmptyResponse.Merge(m, src) |  | ||||||
| } |  | ||||||
| func (m *EmptyResponse) XXX_Size() int { |  | ||||||
| 	return xxx_messageInfo_EmptyResponse.Size(m) |  | ||||||
| } |  | ||||||
| func (m *EmptyResponse) XXX_DiscardUnknown() { |  | ||||||
| 	xxx_messageInfo_EmptyResponse.DiscardUnknown(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var xxx_messageInfo_EmptyResponse proto.InternalMessageInfo |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	proto.RegisterType((*Endpoint)(nil), "go.micro.api.Endpoint") |  | ||||||
| 	proto.RegisterType((*EmptyResponse)(nil), "go.micro.api.EmptyResponse") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func init() { proto.RegisterFile("api/service/proto/api.proto", fileDescriptor_c4a48b6b680b5c31) } |  | ||||||
|  |  | ||||||
| var fileDescriptor_c4a48b6b680b5c31 = []byte{ |  | ||||||
| 	// 212 bytes of a gzipped FileDescriptorProto |  | ||||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0xd0, 0xc1, 0x4a, 0x03, 0x31, |  | ||||||
| 	0x10, 0x80, 0x61, 0xd7, 0xad, 0x65, 0x1d, 0x14, 0x21, 0x87, 0x12, 0xec, 0x65, 0xd9, 0x53, 0x4f, |  | ||||||
| 	0x59, 0xd0, 0x27, 0x28, 0xda, 0x17, 0xd8, 0x37, 0x88, 0xed, 0xd0, 0x9d, 0x43, 0x32, 0x43, 0x32, |  | ||||||
| 	0x14, 0x7c, 0x08, 0xdf, 0x59, 0x12, 0x2b, 0x2c, 0x5e, 0xbd, 0xfd, 0xf3, 0x1d, 0x86, 0x61, 0x60, |  | ||||||
| 	0xeb, 0x85, 0xc6, 0x8c, 0xe9, 0x42, 0x47, 0x1c, 0x25, 0xb1, 0xf2, 0xe8, 0x85, 0x5c, 0x2d, 0xf3, |  | ||||||
| 	0x70, 0x66, 0x17, 0xe8, 0x98, 0xd8, 0x79, 0xa1, 0xe1, 0x02, 0xdd, 0x21, 0x9e, 0x84, 0x29, 0xaa, |  | ||||||
| 	0x31, 0xb0, 0x8a, 0x3e, 0xa0, 0x6d, 0xfa, 0x66, 0x77, 0x3f, 0xd5, 0x2e, 0x36, 0x73, 0x56, 0x7b, |  | ||||||
| 	0xdb, 0xb7, 0xc5, 0x4a, 0x17, 0x13, 0xaf, 0xb3, 0x6d, 0x7f, 0xac, 0xb4, 0xd9, 0xc0, 0x3a, 0xa0, |  | ||||||
| 	0xce, 0x7c, 0xb2, 0xab, 0xaa, 0xd7, 0xa9, 0x78, 0xd6, 0x84, 0x3e, 0xd8, 0xbb, 0xbe, 0xd9, 0x75, |  | ||||||
| 	0xd3, 0x75, 0x1a, 0x9e, 0xe0, 0xf1, 0x10, 0x44, 0x3f, 0x27, 0xcc, 0xc2, 0x31, 0xe3, 0xcb, 0x57, |  | ||||||
| 	0x03, 0xed, 0x5e, 0xc8, 0xec, 0xa1, 0x9b, 0xf0, 0x4c, 0x59, 0x31, 0x99, 0x8d, 0x5b, 0xde, 0xea, |  | ||||||
| 	0x7e, 0x0f, 0x7d, 0xde, 0xfe, 0xf1, 0xe5, 0xa2, 0xe1, 0xc6, 0xbc, 0x01, 0xbc, 0x63, 0xfa, 0xdf, |  | ||||||
| 	0x92, 0x8f, 0x75, 0xfd, 0xd6, 0xeb, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x46, 0x62, 0x67, 0x30, |  | ||||||
| 	0x4c, 0x01, 0x00, 0x00, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Reference imports to suppress errors if they are not otherwise used. |  | ||||||
| var _ context.Context |  | ||||||
| var _ grpc.ClientConn |  | ||||||
|  |  | ||||||
| // This is a compile-time assertion to ensure that this generated file |  | ||||||
| // is compatible with the grpc package it is being compiled against. |  | ||||||
| const _ = grpc.SupportPackageIsVersion4 |  | ||||||
|  |  | ||||||
| // ApiClient is the client API for Api service. |  | ||||||
| // |  | ||||||
| // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. |  | ||||||
| type ApiClient interface { |  | ||||||
| 	Register(ctx context.Context, in *Endpoint, opts ...grpc.CallOption) (*EmptyResponse, error) |  | ||||||
| 	Deregister(ctx context.Context, in *Endpoint, opts ...grpc.CallOption) (*EmptyResponse, error) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type apiClient struct { |  | ||||||
| 	cc *grpc.ClientConn |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewApiClient(cc *grpc.ClientConn) ApiClient { |  | ||||||
| 	return &apiClient{cc} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *apiClient) Register(ctx context.Context, in *Endpoint, opts ...grpc.CallOption) (*EmptyResponse, error) { |  | ||||||
| 	out := new(EmptyResponse) |  | ||||||
| 	err := c.cc.Invoke(ctx, "/go.micro.api.Api/Register", in, out, opts...) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return out, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *apiClient) Deregister(ctx context.Context, in *Endpoint, opts ...grpc.CallOption) (*EmptyResponse, error) { |  | ||||||
| 	out := new(EmptyResponse) |  | ||||||
| 	err := c.cc.Invoke(ctx, "/go.micro.api.Api/Deregister", in, out, opts...) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return out, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ApiServer is the server API for Api service. |  | ||||||
| type ApiServer interface { |  | ||||||
| 	Register(context.Context, *Endpoint) (*EmptyResponse, error) |  | ||||||
| 	Deregister(context.Context, *Endpoint) (*EmptyResponse, error) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // UnimplementedApiServer can be embedded to have forward compatible implementations. |  | ||||||
| type UnimplementedApiServer struct { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (*UnimplementedApiServer) Register(ctx context.Context, req *Endpoint) (*EmptyResponse, error) { |  | ||||||
| 	return nil, status.Errorf(codes.Unimplemented, "method Register not implemented") |  | ||||||
| } |  | ||||||
| func (*UnimplementedApiServer) Deregister(ctx context.Context, req *Endpoint) (*EmptyResponse, error) { |  | ||||||
| 	return nil, status.Errorf(codes.Unimplemented, "method Deregister not implemented") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func RegisterApiServer(s *grpc.Server, srv ApiServer) { |  | ||||||
| 	s.RegisterService(&_Api_serviceDesc, srv) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func _Api_Register_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |  | ||||||
| 	in := new(Endpoint) |  | ||||||
| 	if err := dec(in); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if interceptor == nil { |  | ||||||
| 		return srv.(ApiServer).Register(ctx, in) |  | ||||||
| 	} |  | ||||||
| 	info := &grpc.UnaryServerInfo{ |  | ||||||
| 		Server:     srv, |  | ||||||
| 		FullMethod: "/go.micro.api.Api/Register", |  | ||||||
| 	} |  | ||||||
| 	handler := func(ctx context.Context, req interface{}) (interface{}, error) { |  | ||||||
| 		return srv.(ApiServer).Register(ctx, req.(*Endpoint)) |  | ||||||
| 	} |  | ||||||
| 	return interceptor(ctx, in, info, handler) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func _Api_Deregister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |  | ||||||
| 	in := new(Endpoint) |  | ||||||
| 	if err := dec(in); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if interceptor == nil { |  | ||||||
| 		return srv.(ApiServer).Deregister(ctx, in) |  | ||||||
| 	} |  | ||||||
| 	info := &grpc.UnaryServerInfo{ |  | ||||||
| 		Server:     srv, |  | ||||||
| 		FullMethod: "/go.micro.api.Api/Deregister", |  | ||||||
| 	} |  | ||||||
| 	handler := func(ctx context.Context, req interface{}) (interface{}, error) { |  | ||||||
| 		return srv.(ApiServer).Deregister(ctx, req.(*Endpoint)) |  | ||||||
| 	} |  | ||||||
| 	return interceptor(ctx, in, info, handler) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var _Api_serviceDesc = grpc.ServiceDesc{ |  | ||||||
| 	ServiceName: "go.micro.api.Api", |  | ||||||
| 	HandlerType: (*ApiServer)(nil), |  | ||||||
| 	Methods: []grpc.MethodDesc{ |  | ||||||
| 		{ |  | ||||||
| 			MethodName: "Register", |  | ||||||
| 			Handler:    _Api_Register_Handler, |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			MethodName: "Deregister", |  | ||||||
| 			Handler:    _Api_Deregister_Handler, |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
| 	Streams:  []grpc.StreamDesc{}, |  | ||||||
| 	Metadata: "api/service/proto/api.proto", |  | ||||||
| } |  | ||||||
| @@ -1,110 +0,0 @@ | |||||||
| // Code generated by protoc-gen-micro. DO NOT EDIT. |  | ||||||
| // source: api/service/proto/api.proto |  | ||||||
|  |  | ||||||
| package go_micro_api |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	fmt "fmt" |  | ||||||
| 	proto "github.com/golang/protobuf/proto" |  | ||||||
| 	math "math" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	context "context" |  | ||||||
| 	api "github.com/micro/go-micro/v3/api" |  | ||||||
| 	client "github.com/micro/go-micro/v3/client" |  | ||||||
| 	server "github.com/micro/go-micro/v3/server" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // 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 |  | ||||||
|  |  | ||||||
| // Reference imports to suppress errors if they are not otherwise used. |  | ||||||
| var _ api.Endpoint |  | ||||||
| var _ context.Context |  | ||||||
| var _ client.Option |  | ||||||
| var _ server.Option |  | ||||||
|  |  | ||||||
| // Api Endpoints for Api service |  | ||||||
|  |  | ||||||
| func NewApiEndpoints() []*api.Endpoint { |  | ||||||
| 	return []*api.Endpoint{} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Client API for Api service |  | ||||||
|  |  | ||||||
| type ApiService interface { |  | ||||||
| 	Register(ctx context.Context, in *Endpoint, opts ...client.CallOption) (*EmptyResponse, error) |  | ||||||
| 	Deregister(ctx context.Context, in *Endpoint, opts ...client.CallOption) (*EmptyResponse, error) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type apiService struct { |  | ||||||
| 	c    client.Client |  | ||||||
| 	name string |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewApiService(name string, c client.Client) ApiService { |  | ||||||
| 	return &apiService{ |  | ||||||
| 		c:    c, |  | ||||||
| 		name: name, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *apiService) Register(ctx context.Context, in *Endpoint, opts ...client.CallOption) (*EmptyResponse, error) { |  | ||||||
| 	req := c.c.NewRequest(c.name, "Api.Register", in) |  | ||||||
| 	out := new(EmptyResponse) |  | ||||||
| 	err := c.c.Call(ctx, req, out, opts...) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return out, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *apiService) Deregister(ctx context.Context, in *Endpoint, opts ...client.CallOption) (*EmptyResponse, error) { |  | ||||||
| 	req := c.c.NewRequest(c.name, "Api.Deregister", in) |  | ||||||
| 	out := new(EmptyResponse) |  | ||||||
| 	err := c.c.Call(ctx, req, out, opts...) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return out, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Server API for Api service |  | ||||||
|  |  | ||||||
| type ApiHandler interface { |  | ||||||
| 	Register(context.Context, *Endpoint, *EmptyResponse) error |  | ||||||
| 	Deregister(context.Context, *Endpoint, *EmptyResponse) error |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func RegisterApiHandler(s server.Server, hdlr ApiHandler, opts ...server.HandlerOption) error { |  | ||||||
| 	type api interface { |  | ||||||
| 		Register(ctx context.Context, in *Endpoint, out *EmptyResponse) error |  | ||||||
| 		Deregister(ctx context.Context, in *Endpoint, out *EmptyResponse) error |  | ||||||
| 	} |  | ||||||
| 	type Api struct { |  | ||||||
| 		api |  | ||||||
| 	} |  | ||||||
| 	h := &apiHandler{hdlr} |  | ||||||
| 	return s.Handle(s.NewHandler(&Api{h}, opts...)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type apiHandler struct { |  | ||||||
| 	ApiHandler |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (h *apiHandler) Register(ctx context.Context, in *Endpoint, out *EmptyResponse) error { |  | ||||||
| 	return h.ApiHandler.Register(ctx, in, out) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (h *apiHandler) Deregister(ctx context.Context, in *Endpoint, out *EmptyResponse) error { |  | ||||||
| 	return h.ApiHandler.Deregister(ctx, in, out) |  | ||||||
| } |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| syntax = "proto3"; |  | ||||||
|  |  | ||||||
| package go.micro.api; |  | ||||||
|  |  | ||||||
| service Api { |  | ||||||
|   rpc Register(Endpoint) returns (EmptyResponse) {}; |  | ||||||
|   rpc Deregister(Endpoint) returns (EmptyResponse) {}; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message Endpoint { |  | ||||||
|   string name = 1; |  | ||||||
|   repeated string host = 2; |  | ||||||
|   repeated string path = 3; |  | ||||||
|   repeated string method = 4; |  | ||||||
|   bool stream = 5; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message EmptyResponse {} |  | ||||||
							
								
								
									
										21
									
								
								api/util.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								api/util.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | package api | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"strings" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func strip(s string) string { | ||||||
|  | 	return strings.TrimSpace(s) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func slice(s string) []string { | ||||||
|  | 	var sl []string | ||||||
|  |  | ||||||
|  | 	for _, p := range strings.Split(s, ",") { | ||||||
|  | 		if str := strip(p); len(str) > 0 { | ||||||
|  | 			sl = append(sl, strip(p)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return sl | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								auth/auth.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								auth/auth.go
									
									
									
									
									
								
							| @@ -2,14 +2,11 @@ | |||||||
| package auth | package auth | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" |  | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"time" | 	"time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| 	// BearerScheme used for Authorization header |  | ||||||
| 	BearerScheme = "Bearer " |  | ||||||
| 	// ScopePublic is the scope applied to a rule to allow access to the public | 	// ScopePublic is the scope applied to a rule to allow access to the public | ||||||
| 	ScopePublic = "" | 	ScopePublic = "" | ||||||
| 	// ScopeAccount is the scope applied to a rule to limit to users with any valid account | 	// ScopeAccount is the scope applied to a rule to limit to users with any valid account | ||||||
| @@ -49,7 +46,7 @@ type Auth interface { | |||||||
|  |  | ||||||
| // Account provided by an auth provider | // Account provided by an auth provider | ||||||
| type Account struct { | type Account struct { | ||||||
| 	// ID of the account e.g. email | 	// ID of the account e.g. UUID. Should not change | ||||||
| 	ID string `json:"id"` | 	ID string `json:"id"` | ||||||
| 	// Type of the account, e.g. service | 	// Type of the account, e.g. service | ||||||
| 	Type string `json:"type"` | 	Type string `json:"type"` | ||||||
| @@ -61,6 +58,8 @@ type Account struct { | |||||||
| 	Scopes []string `json:"scopes"` | 	Scopes []string `json:"scopes"` | ||||||
| 	// Secret for the account, e.g. the password | 	// Secret for the account, e.g. the password | ||||||
| 	Secret string `json:"secret"` | 	Secret string `json:"secret"` | ||||||
|  | 	// Name of the account. User friendly name that might change e.g. a username or email | ||||||
|  | 	Name string `json:"name"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // Token can be short or long lived | // Token can be short or long lived | ||||||
| @@ -115,19 +114,3 @@ type Rule struct { | |||||||
| 	// rule will be applied | 	// rule will be applied | ||||||
| 	Priority int32 | 	Priority int32 | ||||||
| } | } | ||||||
|  |  | ||||||
| type accountKey struct{} |  | ||||||
|  |  | ||||||
| // AccountFromContext gets the account from the context, which |  | ||||||
| // is set by the auth wrapper at the start of a call. If the account |  | ||||||
| // is not set, a nil account will be returned. The error is only returned |  | ||||||
| // when there was a problem retrieving an account |  | ||||||
| func AccountFromContext(ctx context.Context) (*Account, bool) { |  | ||||||
| 	acc, ok := ctx.Value(accountKey{}).(*Account) |  | ||||||
| 	return acc, ok |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ContextWithAccount sets the account in the context |  | ||||||
| func ContextWithAccount(ctx context.Context, account *Account) context.Context { |  | ||||||
| 	return context.WithValue(ctx, accountKey{}, account) |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -5,9 +5,9 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/auth" | 	"github.com/asim/go-micro/v3/auth" | ||||||
| 	"github.com/micro/go-micro/v3/util/token" | 	"github.com/asim/go-micro/v3/util/token" | ||||||
| 	"github.com/micro/go-micro/v3/util/token/jwt" | 	"github.com/asim/go-micro/v3/util/token/jwt" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // NewAuth returns a new instance of the Auth service | // NewAuth returns a new instance of the Auth service | ||||||
| @@ -54,13 +54,17 @@ func (j *jwtAuth) Generate(id string, opts ...auth.GenerateOption) (*auth.Accoun | |||||||
| 	if len(options.Issuer) == 0 { | 	if len(options.Issuer) == 0 { | ||||||
| 		options.Issuer = j.Options().Issuer | 		options.Issuer = j.Options().Issuer | ||||||
| 	} | 	} | ||||||
|  | 	name := options.Name | ||||||
|  | 	if name == "" { | ||||||
|  | 		name = id | ||||||
|  | 	} | ||||||
| 	account := &auth.Account{ | 	account := &auth.Account{ | ||||||
| 		ID:       id, | 		ID:       id, | ||||||
| 		Type:     options.Type, | 		Type:     options.Type, | ||||||
| 		Scopes:   options.Scopes, | 		Scopes:   options.Scopes, | ||||||
| 		Metadata: options.Metadata, | 		Metadata: options.Metadata, | ||||||
| 		Issuer:   options.Issuer, | 		Issuer:   options.Issuer, | ||||||
|  | 		Name:     name, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// generate a JWT secret which can be provided to the Token() method | 	// generate a JWT secret which can be provided to the Token() method | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package noop | package noop | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"github.com/asim/go-micro/v3/auth" | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/micro/go-micro/v3/auth" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func NewAuth(opts ...auth.Option) auth.Auth { | func NewAuth(opts ...auth.Option) auth.Auth { | ||||||
| @@ -40,13 +40,17 @@ func (n *noop) Options() auth.Options { | |||||||
| // Generate a new account | // Generate a new account | ||||||
| func (n *noop) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) { | func (n *noop) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) { | ||||||
| 	options := auth.NewGenerateOptions(opts...) | 	options := auth.NewGenerateOptions(opts...) | ||||||
|  | 	name := options.Name | ||||||
|  | 	if name == "" { | ||||||
|  | 		name = id | ||||||
|  | 	} | ||||||
| 	return &auth.Account{ | 	return &auth.Account{ | ||||||
| 		ID:       id, | 		ID:       id, | ||||||
| 		Secret:   options.Secret, | 		Secret:   options.Secret, | ||||||
| 		Metadata: options.Metadata, | 		Metadata: options.Metadata, | ||||||
| 		Scopes:   options.Scopes, | 		Scopes:   options.Scopes, | ||||||
| 		Issuer:   n.Options().Issuer, | 		Issuer:   n.Options().Issuer, | ||||||
|  | 		Name:     name, | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/store" | 	"github.com/asim/go-micro/v3/store" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func NewOptions(opts ...Option) Options { | func NewOptions(opts ...Option) Options { | ||||||
| @@ -110,6 +110,8 @@ type GenerateOptions struct { | |||||||
| 	Secret string | 	Secret string | ||||||
| 	// Issuer of the account, e.g. micro | 	// Issuer of the account, e.g. micro | ||||||
| 	Issuer string | 	Issuer string | ||||||
|  | 	// Name of the acouunt e.g. an email or username | ||||||
|  | 	Name string | ||||||
| } | } | ||||||
|  |  | ||||||
| type GenerateOption func(o *GenerateOptions) | type GenerateOption func(o *GenerateOptions) | ||||||
| @@ -156,6 +158,13 @@ func WithIssuer(i string) GenerateOption { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // WithName for the generated account | ||||||
|  | func WithName(n string) GenerateOption { | ||||||
|  | 	return func(o *GenerateOptions) { | ||||||
|  | 		o.Name = n | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| // NewGenerateOptions from a slice of options | // NewGenerateOptions from a slice of options | ||||||
| func NewGenerateOptions(opts ...GenerateOption) GenerateOptions { | func NewGenerateOptions(opts ...GenerateOption) GenerateOptions { | ||||||
| 	var options GenerateOptions | 	var options GenerateOptions | ||||||
|   | |||||||
| @@ -17,16 +17,16 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/asim/go-micro/v3/broker" | ||||||
|  | 	"github.com/asim/go-micro/v3/codec/json" | ||||||
|  | 	merr "github.com/asim/go-micro/v3/errors" | ||||||
|  | 	"github.com/asim/go-micro/v3/registry" | ||||||
|  | 	"github.com/asim/go-micro/v3/registry/cache" | ||||||
|  | 	"github.com/asim/go-micro/v3/registry/mdns" | ||||||
|  | 	maddr "github.com/asim/go-micro/v3/util/addr" | ||||||
|  | 	mnet "github.com/asim/go-micro/v3/util/net" | ||||||
|  | 	mls "github.com/asim/go-micro/v3/util/tls" | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/micro/go-micro/v3/broker" |  | ||||||
| 	"github.com/micro/go-micro/v3/codec/json" |  | ||||||
| 	merr "github.com/micro/go-micro/v3/errors" |  | ||||||
| 	"github.com/micro/go-micro/v3/registry" |  | ||||||
| 	"github.com/micro/go-micro/v3/registry/cache" |  | ||||||
| 	"github.com/micro/go-micro/v3/registry/mdns" |  | ||||||
| 	maddr "github.com/micro/go-micro/v3/util/addr" |  | ||||||
| 	mnet "github.com/micro/go-micro/v3/util/net" |  | ||||||
| 	mls "github.com/micro/go-micro/v3/util/tls" |  | ||||||
| 	"golang.org/x/net/http2" | 	"golang.org/x/net/http2" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -283,7 +283,7 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) { | |||||||
| 	b, err := ioutil.ReadAll(req.Body) | 	b, err := ioutil.ReadAll(req.Body) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		errr := merr.InternalServerError("go.micro.broker", "Error reading request body: %v", err) | 		errr := merr.InternalServerError("go.micro.broker", "Error reading request body: %v", err) | ||||||
| 		w.WriteHeader(500) | 		w.WriteHeader(http.StatusInternalServerError) | ||||||
| 		w.Write([]byte(errr.Error())) | 		w.Write([]byte(errr.Error())) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @@ -291,7 +291,7 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) { | |||||||
| 	var msg *broker.Message | 	var msg *broker.Message | ||||||
| 	if err = h.opts.Codec.Unmarshal(b, &msg); err != nil { | 	if err = h.opts.Codec.Unmarshal(b, &msg); err != nil { | ||||||
| 		errr := merr.InternalServerError("go.micro.broker", "Error parsing request body: %v", err) | 		errr := merr.InternalServerError("go.micro.broker", "Error parsing request body: %v", err) | ||||||
| 		w.WriteHeader(500) | 		w.WriteHeader(http.StatusInternalServerError) | ||||||
| 		w.Write([]byte(errr.Error())) | 		w.Write([]byte(errr.Error())) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @@ -300,7 +300,7 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) { | |||||||
|  |  | ||||||
| 	if len(topic) == 0 { | 	if len(topic) == 0 { | ||||||
| 		errr := merr.InternalServerError("go.micro.broker", "Topic not found") | 		errr := merr.InternalServerError("go.micro.broker", "Topic not found") | ||||||
| 		w.WriteHeader(500) | 		w.WriteHeader(http.StatusInternalServerError) | ||||||
| 		w.Write([]byte(errr.Error())) | 		w.Write([]byte(errr.Error())) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -5,10 +5,10 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/asim/go-micro/v3/broker" | ||||||
|  | 	"github.com/asim/go-micro/v3/registry" | ||||||
|  | 	"github.com/asim/go-micro/v3/registry/memory" | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/micro/go-micro/v3/broker" |  | ||||||
| 	"github.com/micro/go-micro/v3/registry" |  | ||||||
| 	"github.com/micro/go-micro/v3/registry/memory" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/broker" | 	"github.com/asim/go-micro/v3/broker" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Handle registers the handler for the given pattern. | // Handle registers the handler for the given pattern. | ||||||
|   | |||||||
| @@ -8,10 +8,10 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/asim/go-micro/v3/broker" | ||||||
|  | 	maddr "github.com/asim/go-micro/v3/util/addr" | ||||||
|  | 	mnet "github.com/asim/go-micro/v3/util/net" | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/micro/go-micro/v3/broker" |  | ||||||
| 	maddr "github.com/micro/go-micro/v3/util/addr" |  | ||||||
| 	mnet "github.com/micro/go-micro/v3/util/net" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type memoryBroker struct { | type memoryBroker struct { | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/broker" | 	"github.com/asim/go-micro/v3/broker" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestMemoryBroker(t *testing.T) { | func TestMemoryBroker(t *testing.T) { | ||||||
|   | |||||||
| @@ -1,17 +0,0 @@ | |||||||
| package nats |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/broker" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // setBrokerOption returns a function to setup a context with given value |  | ||||||
| func setBrokerOption(k, v interface{}) broker.Option { |  | ||||||
| 	return func(o *broker.Options) { |  | ||||||
| 		if o.Context == nil { |  | ||||||
| 			o.Context = context.Background() |  | ||||||
| 		} |  | ||||||
| 		o.Context = context.WithValue(o.Context, k, v) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,294 +0,0 @@ | |||||||
| // Package nats provides a NATS broker |  | ||||||
| package nats |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"errors" |  | ||||||
| 	"strings" |  | ||||||
| 	"sync" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/broker" |  | ||||||
| 	"github.com/micro/go-micro/v3/codec/json" |  | ||||||
| 	"github.com/micro/go-micro/v3/logger" |  | ||||||
| 	"github.com/micro/go-micro/v3/registry/mdns" |  | ||||||
| 	nats "github.com/nats-io/nats.go" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type natsBroker struct { |  | ||||||
| 	sync.Once |  | ||||||
| 	sync.RWMutex |  | ||||||
|  |  | ||||||
| 	// indicate if we're connected |  | ||||||
| 	connected bool |  | ||||||
|  |  | ||||||
| 	addrs []string |  | ||||||
| 	conn  *nats.Conn |  | ||||||
| 	opts  broker.Options |  | ||||||
| 	nopts nats.Options |  | ||||||
|  |  | ||||||
| 	// should we drain the connection |  | ||||||
| 	drain   bool |  | ||||||
| 	closeCh chan (error) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type subscriber struct { |  | ||||||
| 	s    *nats.Subscription |  | ||||||
| 	opts broker.SubscribeOptions |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *subscriber) Options() broker.SubscribeOptions { |  | ||||||
| 	return s.opts |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *subscriber) Topic() string { |  | ||||||
| 	return s.s.Subject |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *subscriber) Unsubscribe() error { |  | ||||||
| 	return s.s.Unsubscribe() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) Address() string { |  | ||||||
| 	if n.conn != nil && n.conn.IsConnected() { |  | ||||||
| 		return n.conn.ConnectedUrl() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if len(n.addrs) > 0 { |  | ||||||
| 		return n.addrs[0] |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) setAddrs(addrs []string) []string { |  | ||||||
| 	//nolint:prealloc |  | ||||||
| 	var cAddrs []string |  | ||||||
| 	for _, addr := range addrs { |  | ||||||
| 		if len(addr) == 0 { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 		if !strings.HasPrefix(addr, "nats://") { |  | ||||||
| 			addr = "nats://" + addr |  | ||||||
| 		} |  | ||||||
| 		cAddrs = append(cAddrs, addr) |  | ||||||
| 	} |  | ||||||
| 	if len(cAddrs) == 0 { |  | ||||||
| 		cAddrs = []string{nats.DefaultURL} |  | ||||||
| 	} |  | ||||||
| 	return cAddrs |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) Connect() error { |  | ||||||
| 	n.Lock() |  | ||||||
| 	defer n.Unlock() |  | ||||||
|  |  | ||||||
| 	if n.connected { |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	status := nats.CLOSED |  | ||||||
| 	if n.conn != nil { |  | ||||||
| 		status = n.conn.Status() |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	switch status { |  | ||||||
| 	case nats.CONNECTED, nats.RECONNECTING, nats.CONNECTING: |  | ||||||
| 		n.connected = true |  | ||||||
| 		return nil |  | ||||||
| 	default: // DISCONNECTED or CLOSED or DRAINING |  | ||||||
| 		opts := n.nopts |  | ||||||
| 		opts.Servers = n.addrs |  | ||||||
| 		opts.Secure = n.opts.Secure |  | ||||||
| 		opts.TLSConfig = n.opts.TLSConfig |  | ||||||
|  |  | ||||||
| 		// secure might not be set |  | ||||||
| 		if n.opts.TLSConfig != nil { |  | ||||||
| 			opts.Secure = true |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		c, err := opts.Connect() |  | ||||||
| 		if err != nil { |  | ||||||
| 			if logger.V(logger.WarnLevel, logger.DefaultLogger) { |  | ||||||
| 				logger.Warnf("Error connecting to broker: %v", err) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		n.conn = c |  | ||||||
| 		n.connected = true |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) Disconnect() error { |  | ||||||
| 	n.Lock() |  | ||||||
| 	defer n.Unlock() |  | ||||||
|  |  | ||||||
| 	// drain the connection if specified |  | ||||||
| 	if n.drain { |  | ||||||
| 		n.conn.Drain() |  | ||||||
| 		n.closeCh <- nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// close the client connection |  | ||||||
| 	n.conn.Close() |  | ||||||
|  |  | ||||||
| 	// set not connected |  | ||||||
| 	n.connected = false |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) Init(opts ...broker.Option) error { |  | ||||||
| 	n.setOption(opts...) |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) Options() broker.Options { |  | ||||||
| 	return n.opts |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) Publish(topic string, msg *broker.Message, opts ...broker.PublishOption) error { |  | ||||||
| 	n.RLock() |  | ||||||
| 	defer n.RUnlock() |  | ||||||
|  |  | ||||||
| 	if n.conn == nil { |  | ||||||
| 		return errors.New("not connected") |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	b, err := n.opts.Codec.Marshal(msg) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
| 	return n.conn.Publish(topic, b) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) { |  | ||||||
| 	n.RLock() |  | ||||||
| 	if n.conn == nil { |  | ||||||
| 		n.RUnlock() |  | ||||||
| 		return nil, errors.New("not connected") |  | ||||||
| 	} |  | ||||||
| 	n.RUnlock() |  | ||||||
|  |  | ||||||
| 	opt := broker.SubscribeOptions{ |  | ||||||
| 		Context: context.Background(), |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, o := range opts { |  | ||||||
| 		o(&opt) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	fn := func(msg *nats.Msg) { |  | ||||||
| 		var m *broker.Message |  | ||||||
| 		eh := opt.ErrorHandler |  | ||||||
| 		err := n.opts.Codec.Unmarshal(msg.Data, &m) |  | ||||||
| 		if err != nil { |  | ||||||
| 			m.Body = msg.Data |  | ||||||
| 			if logger.V(logger.ErrorLevel, logger.DefaultLogger) { |  | ||||||
| 				logger.Error(err) |  | ||||||
| 			} |  | ||||||
| 			if eh != nil { |  | ||||||
| 				eh(m, err) |  | ||||||
| 			} |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 		if err := handler(m); err != nil { |  | ||||||
| 			if logger.V(logger.ErrorLevel, logger.DefaultLogger) { |  | ||||||
| 				logger.Error(err) |  | ||||||
| 			} |  | ||||||
| 			if eh != nil { |  | ||||||
| 				eh(m, err) |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var sub *nats.Subscription |  | ||||||
| 	var err error |  | ||||||
|  |  | ||||||
| 	n.RLock() |  | ||||||
| 	if len(opt.Queue) > 0 { |  | ||||||
| 		sub, err = n.conn.QueueSubscribe(topic, opt.Queue, fn) |  | ||||||
| 	} else { |  | ||||||
| 		sub, err = n.conn.Subscribe(topic, fn) |  | ||||||
| 	} |  | ||||||
| 	n.RUnlock() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &subscriber{s: sub, opts: opt}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) String() string { |  | ||||||
| 	return "nats" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) setOption(opts ...broker.Option) { |  | ||||||
| 	for _, o := range opts { |  | ||||||
| 		o(&n.opts) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	n.Once.Do(func() { |  | ||||||
| 		n.nopts = nats.GetDefaultOptions() |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	if nopts, ok := n.opts.Context.Value(optionsKey{}).(nats.Options); ok { |  | ||||||
| 		n.nopts = nopts |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// broker.Options have higher priority than nats.Options |  | ||||||
| 	// only if Addrs, Secure or TLSConfig were not set through a broker.Option |  | ||||||
| 	// we read them from nats.Option |  | ||||||
| 	if len(n.opts.Addrs) == 0 { |  | ||||||
| 		n.opts.Addrs = n.nopts.Servers |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if !n.opts.Secure { |  | ||||||
| 		n.opts.Secure = n.nopts.Secure |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if n.opts.TLSConfig == nil { |  | ||||||
| 		n.opts.TLSConfig = n.nopts.TLSConfig |  | ||||||
| 	} |  | ||||||
| 	n.addrs = n.setAddrs(n.opts.Addrs) |  | ||||||
|  |  | ||||||
| 	if n.opts.Context.Value(drainConnectionKey{}) != nil { |  | ||||||
| 		n.drain = true |  | ||||||
| 		n.closeCh = make(chan error) |  | ||||||
| 		n.nopts.ClosedCB = n.onClose |  | ||||||
| 		n.nopts.AsyncErrorCB = n.onAsyncError |  | ||||||
| 		n.nopts.DisconnectedErrCB = n.onDisconnectedError |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) onClose(conn *nats.Conn) { |  | ||||||
| 	n.closeCh <- nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) onAsyncError(conn *nats.Conn, sub *nats.Subscription, err error) { |  | ||||||
| 	// There are kinds of different async error nats might callback, but we are interested |  | ||||||
| 	// in ErrDrainTimeout only here. |  | ||||||
| 	if err == nats.ErrDrainTimeout { |  | ||||||
| 		n.closeCh <- err |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (n *natsBroker) onDisconnectedError(conn *nats.Conn, err error) { |  | ||||||
| 	n.closeCh <- err |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewBroker(opts ...broker.Option) broker.Broker { |  | ||||||
| 	options := broker.Options{ |  | ||||||
| 		// Default codec |  | ||||||
| 		Codec:    json.Marshaler{}, |  | ||||||
| 		Context:  context.Background(), |  | ||||||
| 		Registry: mdns.NewRegistry(), |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	n := &natsBroker{ |  | ||||||
| 		opts: options, |  | ||||||
| 	} |  | ||||||
| 	n.setOption(opts...) |  | ||||||
|  |  | ||||||
| 	return n |  | ||||||
| } |  | ||||||
| @@ -1,98 +0,0 @@ | |||||||
| package nats |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"testing" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/broker" |  | ||||||
| 	nats "github.com/nats-io/nats.go" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| var addrTestCases = []struct { |  | ||||||
| 	name        string |  | ||||||
| 	description string |  | ||||||
| 	addrs       map[string]string // expected address : set address |  | ||||||
| }{ |  | ||||||
| 	{ |  | ||||||
| 		"brokerOpts", |  | ||||||
| 		"set broker addresses through a broker.Option in constructor", |  | ||||||
| 		map[string]string{ |  | ||||||
| 			"nats://192.168.10.1:5222": "192.168.10.1:5222", |  | ||||||
| 			"nats://10.20.10.0:4222":   "10.20.10.0:4222"}, |  | ||||||
| 	}, |  | ||||||
| 	{ |  | ||||||
| 		"brokerInit", |  | ||||||
| 		"set broker addresses through a broker.Option in broker.Init()", |  | ||||||
| 		map[string]string{ |  | ||||||
| 			"nats://192.168.10.1:5222": "192.168.10.1:5222", |  | ||||||
| 			"nats://10.20.10.0:4222":   "10.20.10.0:4222"}, |  | ||||||
| 	}, |  | ||||||
| 	{ |  | ||||||
| 		"natsOpts", |  | ||||||
| 		"set broker addresses through the nats.Option in constructor", |  | ||||||
| 		map[string]string{ |  | ||||||
| 			"nats://192.168.10.1:5222": "192.168.10.1:5222", |  | ||||||
| 			"nats://10.20.10.0:4222":   "10.20.10.0:4222"}, |  | ||||||
| 	}, |  | ||||||
| 	{ |  | ||||||
| 		"default", |  | ||||||
| 		"check if default Address is set correctly", |  | ||||||
| 		map[string]string{ |  | ||||||
| 			"nats://127.0.0.1:4222": "", |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // TestInitAddrs tests issue #100. Ensures that if the addrs is set by an option in init it will be used. |  | ||||||
| func TestInitAddrs(t *testing.T) { |  | ||||||
|  |  | ||||||
| 	for _, tc := range addrTestCases { |  | ||||||
| 		t.Run(fmt.Sprintf("%s: %s", tc.name, tc.description), func(t *testing.T) { |  | ||||||
|  |  | ||||||
| 			var br broker.Broker |  | ||||||
| 			var addrs []string |  | ||||||
|  |  | ||||||
| 			for _, addr := range tc.addrs { |  | ||||||
| 				addrs = append(addrs, addr) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			switch tc.name { |  | ||||||
| 			case "brokerOpts": |  | ||||||
| 				// we know that there are just two addrs in the dict |  | ||||||
| 				br = NewBroker(broker.Addrs(addrs[0], addrs[1])) |  | ||||||
| 				br.Init() |  | ||||||
| 			case "brokerInit": |  | ||||||
| 				br = NewBroker() |  | ||||||
| 				// we know that there are just two addrs in the dict |  | ||||||
| 				br.Init(broker.Addrs(addrs[0], addrs[1])) |  | ||||||
| 			case "natsOpts": |  | ||||||
| 				nopts := nats.GetDefaultOptions() |  | ||||||
| 				nopts.Servers = addrs |  | ||||||
| 				br = NewBroker(Options(nopts)) |  | ||||||
| 				br.Init() |  | ||||||
| 			case "default": |  | ||||||
| 				br = NewBroker() |  | ||||||
| 				br.Init() |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			natsBroker, ok := br.(*natsBroker) |  | ||||||
| 			if !ok { |  | ||||||
| 				t.Fatal("Expected broker to be of types *natsBroker") |  | ||||||
| 			} |  | ||||||
| 			// check if the same amount of addrs we set has actually been set, default |  | ||||||
| 			// have only 1 address nats://127.0.0.1:4222 (current nats code) or |  | ||||||
| 			// nats://localhost:4222 (older code version) |  | ||||||
| 			if len(natsBroker.addrs) != len(tc.addrs) && tc.name != "default" { |  | ||||||
| 				t.Errorf("Expected Addr count = %d, Actual Addr count = %d", |  | ||||||
| 					len(natsBroker.addrs), len(tc.addrs)) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			for _, addr := range natsBroker.addrs { |  | ||||||
| 				_, ok := tc.addrs[addr] |  | ||||||
| 				if !ok { |  | ||||||
| 					t.Errorf("Expected '%s' has not been set", addr) |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| package nats |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/micro/go-micro/v3/broker" |  | ||||||
| 	nats "github.com/nats-io/nats.go" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type optionsKey struct{} |  | ||||||
| type drainConnectionKey struct{} |  | ||||||
|  |  | ||||||
| // Options accepts nats.Options |  | ||||||
| func Options(opts nats.Options) broker.Option { |  | ||||||
| 	return setBrokerOption(optionsKey{}, opts) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // DrainConnection will drain subscription on close |  | ||||||
| func DrainConnection() broker.Option { |  | ||||||
| 	return setBrokerOption(drainConnectionKey{}, struct{}{}) |  | ||||||
| } |  | ||||||
| @@ -4,8 +4,8 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"crypto/tls" | 	"crypto/tls" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/codec" | 	"github.com/asim/go-micro/v3/codec" | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Options struct { | type Options struct { | ||||||
|   | |||||||
| @@ -4,13 +4,17 @@ package build | |||||||
| // Build is an interface for building packages | // Build is an interface for building packages | ||||||
| type Build interface { | type Build interface { | ||||||
| 	// Package builds a package | 	// Package builds a package | ||||||
| 	Package(name string, src *Source) (*Package, error) | 	Package(*Source) (*Package, error) | ||||||
| 	// Remove removes the package | 	// Remove removes the package | ||||||
| 	Remove(*Package) error | 	Remove(*Package) error | ||||||
|  | 	// Implementation of build | ||||||
|  | 	String() string | ||||||
| } | } | ||||||
|  |  | ||||||
| // Source is the source of a build | // Source is the source of a build | ||||||
| type Source struct { | type Source struct { | ||||||
|  | 	// Name of the source | ||||||
|  | 	Name string | ||||||
| 	// Path to the source if local | 	// Path to the source if local | ||||||
| 	Path string | 	Path string | ||||||
| 	// Language is the language of code | 	// Language is the language of code | ||||||
|   | |||||||
| @@ -1,96 +0,0 @@ | |||||||
| // Package docker builds docker images |  | ||||||
| package docker |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"archive/tar" |  | ||||||
| 	"bytes" |  | ||||||
| 	"io/ioutil" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
|  |  | ||||||
| 	docker "github.com/fsouza/go-dockerclient" |  | ||||||
| 	"github.com/micro/go-micro/v3/build" |  | ||||||
| 	"github.com/micro/go-micro/v3/logger" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type dockerBuild struct { |  | ||||||
| 	Options build.Options |  | ||||||
| 	Client  *docker.Client |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (d *dockerBuild) Package(name string, s *build.Source) (*build.Package, error) { |  | ||||||
| 	image := name |  | ||||||
|  |  | ||||||
| 	buf := new(bytes.Buffer) |  | ||||||
| 	tw := tar.NewWriter(buf) |  | ||||||
| 	defer tw.Close() |  | ||||||
|  |  | ||||||
| 	dockerFile := "Dockerfile" |  | ||||||
|  |  | ||||||
| 	// open docker file |  | ||||||
| 	f, err := os.Open(filepath.Join(s.Path, dockerFile)) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	// read docker file |  | ||||||
| 	by, err := ioutil.ReadAll(f) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	tarHeader := &tar.Header{ |  | ||||||
| 		Name: dockerFile, |  | ||||||
| 		Size: int64(len(by)), |  | ||||||
| 	} |  | ||||||
| 	err = tw.WriteHeader(tarHeader) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	_, err = tw.Write(by) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	tr := bytes.NewReader(buf.Bytes()) |  | ||||||
|  |  | ||||||
| 	err = d.Client.BuildImage(docker.BuildImageOptions{ |  | ||||||
| 		Name:           image, |  | ||||||
| 		Dockerfile:     dockerFile, |  | ||||||
| 		InputStream:    tr, |  | ||||||
| 		OutputStream:   ioutil.Discard, |  | ||||||
| 		RmTmpContainer: true, |  | ||||||
| 		SuppressOutput: true, |  | ||||||
| 	}) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &build.Package{ |  | ||||||
| 		Name:   image, |  | ||||||
| 		Path:   image, |  | ||||||
| 		Type:   "docker", |  | ||||||
| 		Source: s, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (d *dockerBuild) Remove(b *build.Package) error { |  | ||||||
| 	return d.Client.RemoveImage(b.Name) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (d *dockerBuild) String() string { |  | ||||||
| 	return "docker" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewBuild(opts ...build.Option) build.Build { |  | ||||||
| 	options := build.Options{} |  | ||||||
| 	for _, o := range opts { |  | ||||||
| 		o(&options) |  | ||||||
| 	} |  | ||||||
| 	endpoint := "unix:///var/run/docker.sock" |  | ||||||
| 	client, err := docker.NewClient(endpoint) |  | ||||||
| 	if err != nil { |  | ||||||
| 		logger.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 	return &dockerBuild{ |  | ||||||
| 		Options: options, |  | ||||||
| 		Client:  client, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -6,7 +6,7 @@ import ( | |||||||
| 	"os/exec" | 	"os/exec" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/build" | 	"github.com/asim/go-micro/v3/build" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type goBuild struct { | type goBuild struct { | ||||||
| @@ -34,7 +34,8 @@ func whichGo() string { | |||||||
| 	return "go" | 	return "go" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (g *goBuild) Package(name string, src *build.Source) (*build.Package, error) { | func (g *goBuild) Package(src *build.Source) (*build.Package, error) { | ||||||
|  | 	name := src.Name | ||||||
| 	binary := filepath.Join(g.Path, name) | 	binary := filepath.Join(g.Path, name) | ||||||
| 	source := src.Path | 	source := src.Path | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,12 +5,13 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/build" | 	"github.com/asim/go-micro/v3/build" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type tarBuild struct{} | type tarBuild struct{} | ||||||
|  |  | ||||||
| func (t *tarBuild) Package(name string, src *build.Source) (*build.Package, error) { | func (t *tarBuild) Package(src *build.Source) (*build.Package, error) { | ||||||
|  | 	name := src.Name | ||||||
| 	pkg := name + ".tar.gz" | 	pkg := name + ".tar.gz" | ||||||
| 	// path to the tarball | 	// path to the tarball | ||||||
| 	path := filepath.Join(os.TempDir(), src.Path, pkg) | 	path := filepath.Join(os.TempDir(), src.Path, pkg) | ||||||
|   | |||||||
							
								
								
									
										80
									
								
								cache/memcache/memcache.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										80
									
								
								cache/memcache/memcache.go
									
									
									
									
										vendored
									
									
								
							| @@ -1,80 +0,0 @@ | |||||||
| // Package memcache is a memcache implementation of the Cache |  | ||||||
| package memcache |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"encoding/json" |  | ||||||
|  |  | ||||||
| 	"github.com/bradfitz/gomemcache/memcache" |  | ||||||
| 	"github.com/micro/go-micro/v3/cache" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type memcacheCache struct { |  | ||||||
| 	options cache.Options |  | ||||||
| 	client  *memcache.Client |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type memcacheItem struct { |  | ||||||
| 	Key   string |  | ||||||
| 	Value interface{} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *memcacheCache) Init(opts ...cache.Option) error { |  | ||||||
| 	for _, o := range opts { |  | ||||||
| 		o(&m.options) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *memcacheCache) Get(key string) (interface{}, error) { |  | ||||||
| 	item, err := m.client.Get(key) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var mc *memcacheItem |  | ||||||
|  |  | ||||||
| 	if err := json.Unmarshal(item.Value, &mc); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return mc.Value, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *memcacheCache) Set(key string, val interface{}) error { |  | ||||||
| 	b, err := json.Marshal(val) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return m.client.Set(&memcache.Item{ |  | ||||||
| 		Key:   key, |  | ||||||
| 		Value: b, |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *memcacheCache) Delete(key string) error { |  | ||||||
| 	return m.client.Delete(key) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *memcacheCache) String() string { |  | ||||||
| 	return "memcache" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewCache returns a new memcache Cache |  | ||||||
| func NewCache(opts ...cache.Option) cache.Cache { |  | ||||||
| 	var options cache.Options |  | ||||||
| 	for _, o := range opts { |  | ||||||
| 		o(&options) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// get and set the nodes |  | ||||||
| 	nodes := options.Nodes |  | ||||||
| 	if len(nodes) == 0 { |  | ||||||
| 		nodes = []string{"localhost:11211"} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return &memcacheCache{ |  | ||||||
| 		options: options, |  | ||||||
| 		client:  memcache.New(nodes...), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
							
								
								
									
										4
									
								
								cache/memory/memory.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								cache/memory/memory.go
									
									
									
									
										vendored
									
									
								
							| @@ -4,8 +4,8 @@ package memory | |||||||
| import ( | import ( | ||||||
| 	"sync" | 	"sync" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/cache" | 	"github.com/asim/go-micro/v3/cache" | ||||||
| 	"github.com/micro/go-micro/v3/errors" | 	"github.com/asim/go-micro/v3/errors" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type memoryCache struct { | type memoryCache struct { | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/util/backoff" | 	"github.com/asim/go-micro/v3/util/backoff" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type BackoffFunc func(ctx context.Context, req Request, attempts int) (time.Duration, error) | type BackoffFunc func(ctx context.Context, req Request, attempts int) (time.Duration, error) | ||||||
|   | |||||||
| @@ -4,6 +4,8 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/asim/go-micro/v3/codec" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestBackoff(t *testing.T) { | func TestBackoff(t *testing.T) { | ||||||
| @@ -32,3 +34,63 @@ func TestBackoff(t *testing.T) { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type testRequest struct { | ||||||
|  | 	service     string | ||||||
|  | 	method      string | ||||||
|  | 	endpoint    string | ||||||
|  | 	contentType string | ||||||
|  | 	codec       codec.Codec | ||||||
|  | 	body        interface{} | ||||||
|  | 	opts        RequestOptions | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newRequest(service, endpoint string, request interface{}, contentType string, reqOpts ...RequestOption) Request { | ||||||
|  | 	var opts RequestOptions | ||||||
|  |  | ||||||
|  | 	for _, o := range reqOpts { | ||||||
|  | 		o(&opts) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// set the content-type specified | ||||||
|  | 	if len(opts.ContentType) > 0 { | ||||||
|  | 		contentType = opts.ContentType | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &testRequest{ | ||||||
|  | 		service:     service, | ||||||
|  | 		method:      endpoint, | ||||||
|  | 		endpoint:    endpoint, | ||||||
|  | 		body:        request, | ||||||
|  | 		contentType: contentType, | ||||||
|  | 		opts:        opts, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *testRequest) ContentType() string { | ||||||
|  | 	return r.contentType | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *testRequest) Service() string { | ||||||
|  | 	return r.service | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *testRequest) Method() string { | ||||||
|  | 	return r.method | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *testRequest) Endpoint() string { | ||||||
|  | 	return r.endpoint | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *testRequest) Body() interface{} { | ||||||
|  | 	return r.body | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *testRequest) Codec() codec.Writer { | ||||||
|  | 	return r.codec | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *testRequest) Stream() bool { | ||||||
|  | 	return r.opts.Stream | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,66 +0,0 @@ | |||||||
| package client |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"encoding/json" |  | ||||||
| 	"fmt" |  | ||||||
| 	"hash/fnv" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/metadata" |  | ||||||
| 	cache "github.com/patrickmn/go-cache" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| // NewCache returns an initialised cache. |  | ||||||
| func NewCache() *Cache { |  | ||||||
| 	return &Cache{ |  | ||||||
| 		cache: cache.New(cache.NoExpiration, 30*time.Second), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Cache for responses |  | ||||||
| type Cache struct { |  | ||||||
| 	cache *cache.Cache |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Get a response from the cache |  | ||||||
| func (c *Cache) Get(ctx context.Context, req Request) (interface{}, bool) { |  | ||||||
| 	return c.cache.Get(key(ctx, req)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Set a response in the cache |  | ||||||
| func (c *Cache) Set(ctx context.Context, req Request, rsp interface{}, expiry time.Duration) { |  | ||||||
| 	c.cache.Set(key(ctx, req), rsp, expiry) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // List the key value pairs in the cache |  | ||||||
| func (c *Cache) List() map[string]string { |  | ||||||
| 	items := c.cache.Items() |  | ||||||
|  |  | ||||||
| 	rsp := make(map[string]string, len(items)) |  | ||||||
| 	for k, v := range items { |  | ||||||
| 		bytes, _ := json.Marshal(v.Object) |  | ||||||
| 		rsp[k] = string(bytes) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return rsp |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // key returns a hash for the context and request |  | ||||||
| func key(ctx context.Context, req Request) string { |  | ||||||
| 	ns, _ := metadata.Get(ctx, "Micro-Namespace") |  | ||||||
|  |  | ||||||
| 	bytes, _ := json.Marshal(map[string]interface{}{ |  | ||||||
| 		"namespace": ns, |  | ||||||
| 		"request": map[string]interface{}{ |  | ||||||
| 			"service":  req.Service(), |  | ||||||
| 			"endpoint": req.Endpoint(), |  | ||||||
| 			"method":   req.Method(), |  | ||||||
| 			"body":     req.Body(), |  | ||||||
| 		}, |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	h := fnv.New64() |  | ||||||
| 	h.Write(bytes) |  | ||||||
| 	return fmt.Sprintf("%x", h.Sum(nil)) |  | ||||||
| } |  | ||||||
| @@ -1,77 +0,0 @@ | |||||||
| package client |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"testing" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/metadata" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func TestCache(t *testing.T) { |  | ||||||
| 	ctx := context.TODO() |  | ||||||
| 	req := &testRequest{service: "go.micro.service.foo", method: "Foo.Bar"} |  | ||||||
|  |  | ||||||
| 	t.Run("CacheMiss", func(t *testing.T) { |  | ||||||
| 		if _, ok := NewCache().Get(ctx, req); ok { |  | ||||||
| 			t.Errorf("Expected to get no result from Get") |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	t.Run("CacheHit", func(t *testing.T) { |  | ||||||
| 		c := NewCache() |  | ||||||
|  |  | ||||||
| 		rsp := "theresponse" |  | ||||||
| 		c.Set(ctx, req, rsp, time.Minute) |  | ||||||
|  |  | ||||||
| 		if res, ok := c.Get(ctx, req); !ok { |  | ||||||
| 			t.Errorf("Expected a result, got nothing") |  | ||||||
| 		} else if res != rsp { |  | ||||||
| 			t.Errorf("Expected '%v' result, got '%v'", rsp, res) |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestCacheKey(t *testing.T) { |  | ||||||
| 	ctx := context.TODO() |  | ||||||
|  |  | ||||||
| 	req1 := &testRequest{service: "go.micro.service.foo", method: "Foo.Bar"} |  | ||||||
| 	req2 := &testRequest{service: "go.micro.service.foo", method: "Foo.Baz"} |  | ||||||
| 	req3 := &testRequest{service: "go.micro.service.foo", method: "Foo.Bar", body: "customquery"} |  | ||||||
|  |  | ||||||
| 	t.Run("IdenticalRequests", func(t *testing.T) { |  | ||||||
| 		key1 := key(ctx, req1) |  | ||||||
| 		key2 := key(ctx, req1) |  | ||||||
| 		if key1 != key2 { |  | ||||||
| 			t.Errorf("Expected the keys to match for identical requests and context") |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	t.Run("DifferentRequestEndpoints", func(t *testing.T) { |  | ||||||
| 		key1 := key(ctx, req1) |  | ||||||
| 		key2 := key(ctx, req2) |  | ||||||
|  |  | ||||||
| 		if key1 == key2 { |  | ||||||
| 			t.Errorf("Expected the keys to differ for different request endpoints") |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	t.Run("DifferentRequestBody", func(t *testing.T) { |  | ||||||
| 		key1 := key(ctx, req2) |  | ||||||
| 		key2 := key(ctx, req3) |  | ||||||
|  |  | ||||||
| 		if key1 == key2 { |  | ||||||
| 			t.Errorf("Expected the keys to differ for different request bodies") |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
|  |  | ||||||
| 	t.Run("DifferentMetadata", func(t *testing.T) { |  | ||||||
| 		mdCtx := metadata.Set(context.TODO(), "Micro-Namespace", "bar") |  | ||||||
| 		key1 := key(mdCtx, req1) |  | ||||||
| 		key2 := key(ctx, req1) |  | ||||||
|  |  | ||||||
| 		if key1 == key2 { |  | ||||||
| 			t.Errorf("Expected the keys to differ for different metadata") |  | ||||||
| 		} |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| @@ -5,7 +5,7 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/codec" | 	"github.com/asim/go-micro/v3/codec" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Client is the interface used to make requests to services. | // Client is the interface used to make requests to services. | ||||||
|   | |||||||
| @@ -1,16 +0,0 @@ | |||||||
| package client |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type clientKey struct{} |  | ||||||
|  |  | ||||||
| func FromContext(ctx context.Context) (Client, bool) { |  | ||||||
| 	c, ok := ctx.Value(clientKey{}).(Client) |  | ||||||
| 	return c, ok |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewContext(ctx context.Context, c Client) context.Context { |  | ||||||
| 	return context.WithValue(ctx, clientKey{}, c) |  | ||||||
| } |  | ||||||
| @@ -1,6 +1,6 @@ | |||||||
| # GRPC Client | # GRPC Client | ||||||
|  |  | ||||||
| The grpc client is a [micro.Client](https://godoc.org/github.com/micro/go-micro/client#Client) compatible client. | The grpc client is a [micro.Client](https://godoc.org/github.com/asim/go-micro/client#Client) compatible client. | ||||||
|  |  | ||||||
| ## Overview | ## Overview | ||||||
|  |  | ||||||
| @@ -12,7 +12,7 @@ Specify the client to your micro service | |||||||
|  |  | ||||||
| ```go | ```go | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro" | 	"github.com/asim/go-micro" | ||||||
| 	"github.com/micro/go-plugins/client/grpc" | 	"github.com/micro/go-plugins/client/grpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -7,10 +7,10 @@ import ( | |||||||
|  |  | ||||||
| 	b "bytes" | 	b "bytes" | ||||||
|  |  | ||||||
|  | 	"github.com/asim/go-micro/v3/codec" | ||||||
|  | 	"github.com/asim/go-micro/v3/codec/bytes" | ||||||
| 	"github.com/golang/protobuf/jsonpb" | 	"github.com/golang/protobuf/jsonpb" | ||||||
| 	"github.com/golang/protobuf/proto" | 	"github.com/golang/protobuf/proto" | ||||||
| 	"github.com/micro/go-micro/v3/codec" |  | ||||||
| 	"github.com/micro/go-micro/v3/codec/bytes" |  | ||||||
| 	"github.com/oxtoacart/bpool" | 	"github.com/oxtoacart/bpool" | ||||||
| 	"google.golang.org/grpc" | 	"google.golang.org/grpc" | ||||||
| 	"google.golang.org/grpc/encoding" | 	"google.golang.org/grpc/encoding" | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package grpc | package grpc | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/v3/errors" | 	"github.com/asim/go-micro/v3/errors" | ||||||
| 	"google.golang.org/grpc/status" | 	"google.golang.org/grpc/status" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -11,11 +11,11 @@ import ( | |||||||
| 	"sync/atomic" | 	"sync/atomic" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/broker" | 	"github.com/asim/go-micro/v3/broker" | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	raw "github.com/micro/go-micro/v3/codec/bytes" | 	raw "github.com/asim/go-micro/v3/codec/bytes" | ||||||
| 	"github.com/micro/go-micro/v3/errors" | 	"github.com/asim/go-micro/v3/errors" | ||||||
| 	"github.com/micro/go-micro/v3/metadata" | 	"github.com/asim/go-micro/v3/metadata" | ||||||
|  |  | ||||||
| 	"google.golang.org/grpc" | 	"google.golang.org/grpc" | ||||||
| 	"google.golang.org/grpc/credentials" | 	"google.golang.org/grpc/credentials" | ||||||
| @@ -172,15 +172,6 @@ func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request | |||||||
| 		return errors.InternalServerError("go.micro.client", err.Error()) | 		return errors.InternalServerError("go.micro.client", err.Error()) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var dialCtx context.Context |  | ||||||
| 	var cancel context.CancelFunc |  | ||||||
| 	if opts.DialTimeout >= 0 { |  | ||||||
| 		dialCtx, cancel = context.WithTimeout(ctx, opts.DialTimeout) |  | ||||||
| 	} else { |  | ||||||
| 		dialCtx, cancel = context.WithCancel(ctx) |  | ||||||
| 	} |  | ||||||
| 	defer cancel() |  | ||||||
|  |  | ||||||
| 	wc := wrapCodec{cf} | 	wc := wrapCodec{cf} | ||||||
|  |  | ||||||
| 	grpcDialOptions := []grpc.DialOption{ | 	grpcDialOptions := []grpc.DialOption{ | ||||||
| @@ -192,7 +183,7 @@ func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request | |||||||
| 		grpcDialOptions = append(grpcDialOptions, opts...) | 		grpcDialOptions = append(grpcDialOptions, opts...) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	cc, err := grpc.DialContext(dialCtx, addr, grpcDialOptions...) | 	cc, err := g.pool.getConn(addr, grpcDialOptions...) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) | 		return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) | ||||||
| 	} | 	} | ||||||
| @@ -211,16 +202,16 @@ func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request | |||||||
| 		grpcCallOptions = append(grpcCallOptions, opts...) | 		grpcCallOptions = append(grpcCallOptions, opts...) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// create a new cancelling context | 	var cancel context.CancelFunc | ||||||
| 	newCtx, cancel := context.WithCancel(ctx) | 	ctx, cancel = context.WithCancel(ctx) | ||||||
|  |  | ||||||
| 	st, err := cc.NewStream(newCtx, desc, methodToGRPC(req.Service(), req.Endpoint()), grpcCallOptions...) | 	st, err := cc.NewStream(ctx, desc, methodToGRPC(req.Service(), req.Endpoint()), grpcCallOptions...) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		// we need to cleanup as we dialled and created a context | 		// we need to cleanup as we dialled and created a context | ||||||
| 		// cancel the context | 		// cancel the context | ||||||
| 		cancel() | 		cancel() | ||||||
| 		// close the connection | 		// release the connection | ||||||
| 		cc.Close() | 		g.pool.release(addr, cc, err) | ||||||
| 		// now return the error | 		// now return the error | ||||||
| 		return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err)) | 		return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err)) | ||||||
| 	} | 	} | ||||||
| @@ -246,8 +237,16 @@ func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request | |||||||
| 			codec:  cf, | 			codec:  cf, | ||||||
| 			gcodec: codec, | 			gcodec: codec, | ||||||
| 		}, | 		}, | ||||||
| 		conn:   cc, | 		conn: cc, | ||||||
| 		cancel: cancel, | 		close: func(err error) { | ||||||
|  | 			// cancel the context if an error occured | ||||||
|  | 			if err != nil { | ||||||
|  | 				cancel() | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// defer execution of release | ||||||
|  | 			g.pool.release(addr, cc, err) | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// set the stream as the response | 	// set the stream as the response | ||||||
|   | |||||||
| @@ -5,12 +5,12 @@ import ( | |||||||
| 	"net" | 	"net" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	"github.com/micro/go-micro/v3/errors" | 	"github.com/asim/go-micro/v3/errors" | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| 	"github.com/micro/go-micro/v3/registry/memory" | 	"github.com/asim/go-micro/v3/registry/memory" | ||||||
| 	"github.com/micro/go-micro/v3/router" | 	"github.com/asim/go-micro/v3/router" | ||||||
| 	regRouter "github.com/micro/go-micro/v3/router/registry" | 	regRouter "github.com/asim/go-micro/v3/router/registry" | ||||||
| 	pgrpc "google.golang.org/grpc" | 	pgrpc "google.golang.org/grpc" | ||||||
| 	pb "google.golang.org/grpc/examples/helloworld/helloworld" | 	pb "google.golang.org/grpc/examples/helloworld/helloworld" | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package grpc | package grpc | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type grpcEvent struct { | type grpcEvent struct { | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"crypto/tls" | 	"crypto/tls" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	"google.golang.org/grpc" | 	"google.golang.org/grpc" | ||||||
| 	"google.golang.org/grpc/encoding" | 	"google.golang.org/grpc/encoding" | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -4,8 +4,8 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	"github.com/micro/go-micro/v3/codec" | 	"github.com/asim/go-micro/v3/codec" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type grpcRequest struct { | type grpcRequest struct { | ||||||
|   | |||||||
| @@ -3,14 +3,14 @@ package grpc | |||||||
| import ( | import ( | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/codec" | 	"github.com/asim/go-micro/v3/codec" | ||||||
| 	"github.com/micro/go-micro/v3/codec/bytes" | 	"github.com/asim/go-micro/v3/codec/bytes" | ||||||
| 	"google.golang.org/grpc" | 	"google.golang.org/grpc" | ||||||
| 	"google.golang.org/grpc/encoding" | 	"google.golang.org/grpc/encoding" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type response struct { | type response struct { | ||||||
| 	conn   *grpc.ClientConn | 	conn   *poolConn | ||||||
| 	stream grpc.ClientStream | 	stream grpc.ClientStream | ||||||
| 	codec  encoding.Codec | 	codec  encoding.Codec | ||||||
| 	gcodec codec.Codec | 	gcodec codec.Codec | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
| 	"sync" | 	"sync" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	"google.golang.org/grpc" | 	"google.golang.org/grpc" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -17,11 +17,11 @@ type grpcStream struct { | |||||||
| 	sync.RWMutex | 	sync.RWMutex | ||||||
| 	closed   bool | 	closed   bool | ||||||
| 	err      error | 	err      error | ||||||
| 	conn     *grpc.ClientConn | 	conn     *poolConn | ||||||
| 	request  client.Request | 	request  client.Request | ||||||
| 	response client.Response | 	response client.Response | ||||||
| 	context  context.Context | 	context  context.Context | ||||||
| 	cancel   func() | 	close    func(err error) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (g *grpcStream) Context() context.Context { | func (g *grpcStream) Context() context.Context { | ||||||
| @@ -86,9 +86,9 @@ func (g *grpcStream) Close() error { | |||||||
| 	if g.closed { | 	if g.closed { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	// cancel the context |  | ||||||
| 	g.cancel() | 	// close the connection | ||||||
| 	g.closed = true | 	g.closed = true | ||||||
| 	g.ClientStream.CloseSend() | 	g.close(g.err) | ||||||
| 	return g.conn.Close() | 	return g.ClientStream.CloseSend() | ||||||
| } | } | ||||||
|   | |||||||
| @@ -4,8 +4,8 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"sort" | 	"sort" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/errors" | 	"github.com/asim/go-micro/v3/errors" | ||||||
| 	"github.com/micro/go-micro/v3/router" | 	"github.com/asim/go-micro/v3/router" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // LookupFunc is used to lookup routes for a service | // LookupFunc is used to lookup routes for a service | ||||||
| @@ -19,16 +19,16 @@ func LookupRoute(ctx context.Context, req Request, opts CallOptions) ([]string, | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// construct the router query | 	// construct the router query | ||||||
| 	query := []router.QueryOption{router.QueryService(req.Service())} | 	query := []router.LookupOption{} | ||||||
|  |  | ||||||
| 	// if a custom network was requested, pass this to the router. By default the router will use it's | 	// if a custom network was requested, pass this to the router. By default the router will use it's | ||||||
| 	// own network, which is set during initialisation. | 	// own network, which is set during initialisation. | ||||||
| 	if len(opts.Network) > 0 { | 	if len(opts.Network) > 0 { | ||||||
| 		query = append(query, router.QueryNetwork(opts.Network)) | 		query = append(query, router.LookupNetwork(opts.Network)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// lookup the routes which can be used to execute the request | 	// lookup the routes which can be used to execute the request | ||||||
| 	routes, err := opts.Router.Lookup(query...) | 	routes, err := opts.Router.Lookup(req.Service(), query...) | ||||||
| 	if err == router.ErrRouteNotFound { | 	if err == router.ErrRouteNotFound { | ||||||
| 		return nil, errors.InternalServerError("go.micro.client", "service %s: %s", req.Service(), err.Error()) | 		return nil, errors.InternalServerError("go.micro.client", "service %s: %s", req.Service(), err.Error()) | ||||||
| 	} else if err != nil { | 	} else if err != nil { | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package mucp | package mucp | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| // Package mucp provides an mucp client | // Package mucp provides a transport agnostic RPC client | ||||||
| package mucp | package mucp | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| @@ -7,16 +7,16 @@ import ( | |||||||
| 	"sync/atomic" | 	"sync/atomic" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/asim/go-micro/v3/broker" | ||||||
|  | 	"github.com/asim/go-micro/v3/client" | ||||||
|  | 	"github.com/asim/go-micro/v3/codec" | ||||||
|  | 	raw "github.com/asim/go-micro/v3/codec/bytes" | ||||||
|  | 	"github.com/asim/go-micro/v3/errors" | ||||||
|  | 	"github.com/asim/go-micro/v3/metadata" | ||||||
|  | 	"github.com/asim/go-micro/v3/network/transport" | ||||||
|  | 	"github.com/asim/go-micro/v3/util/buf" | ||||||
|  | 	"github.com/asim/go-micro/v3/util/pool" | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/micro/go-micro/v3/broker" |  | ||||||
| 	"github.com/micro/go-micro/v3/client" |  | ||||||
| 	"github.com/micro/go-micro/v3/codec" |  | ||||||
| 	raw "github.com/micro/go-micro/v3/codec/bytes" |  | ||||||
| 	"github.com/micro/go-micro/v3/errors" |  | ||||||
| 	"github.com/micro/go-micro/v3/metadata" |  | ||||||
| 	"github.com/micro/go-micro/v3/transport" |  | ||||||
| 	"github.com/micro/go-micro/v3/util/buf" |  | ||||||
| 	"github.com/micro/go-micro/v3/util/pool" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type rpcClient struct { | type rpcClient struct { | ||||||
|   | |||||||
| @@ -4,16 +4,16 @@ import ( | |||||||
| 	"bytes" | 	"bytes" | ||||||
| 	errs "errors" | 	errs "errors" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/codec" | 	"github.com/asim/go-micro/v3/codec" | ||||||
| 	raw "github.com/micro/go-micro/v3/codec/bytes" | 	raw "github.com/asim/go-micro/v3/codec/bytes" | ||||||
| 	"github.com/micro/go-micro/v3/codec/grpc" | 	"github.com/asim/go-micro/v3/codec/grpc" | ||||||
| 	"github.com/micro/go-micro/v3/codec/json" | 	"github.com/asim/go-micro/v3/codec/json" | ||||||
| 	"github.com/micro/go-micro/v3/codec/jsonrpc" | 	"github.com/asim/go-micro/v3/codec/jsonrpc" | ||||||
| 	"github.com/micro/go-micro/v3/codec/proto" | 	"github.com/asim/go-micro/v3/codec/proto" | ||||||
| 	"github.com/micro/go-micro/v3/codec/protorpc" | 	"github.com/asim/go-micro/v3/codec/protorpc" | ||||||
| 	"github.com/micro/go-micro/v3/errors" | 	"github.com/asim/go-micro/v3/errors" | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/network/transport" | ||||||
| 	"github.com/micro/go-micro/v3/transport" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| package mucp | package mucp | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type message struct { | type message struct { | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package mucp | package mucp | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	"github.com/micro/go-micro/v3/codec" | 	"github.com/asim/go-micro/v3/codec" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type rpcRequest struct { | type rpcRequest struct { | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ package mucp | |||||||
| import ( | import ( | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestRequestOptions(t *testing.T) { | func TestRequestOptions(t *testing.T) { | ||||||
|   | |||||||
| @@ -1,8 +1,8 @@ | |||||||
| package mucp | package mucp | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/v3/codec" | 	"github.com/asim/go-micro/v3/codec" | ||||||
| 	"github.com/micro/go-micro/v3/transport" | 	"github.com/asim/go-micro/v3/network/transport" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type rpcResponse struct { | type rpcResponse struct { | ||||||
|   | |||||||
| @@ -5,8 +5,8 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
| 	"sync" | 	"sync" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	"github.com/micro/go-micro/v3/codec" | 	"github.com/asim/go-micro/v3/codec" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Implements the streamer interface | // Implements the streamer interface | ||||||
|   | |||||||
| @@ -5,12 +5,12 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	"github.com/micro/go-micro/v3/errors" | 	"github.com/asim/go-micro/v3/errors" | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| 	"github.com/micro/go-micro/v3/registry/memory" | 	"github.com/asim/go-micro/v3/registry/memory" | ||||||
| 	"github.com/micro/go-micro/v3/router" | 	"github.com/asim/go-micro/v3/router" | ||||||
| 	regRouter "github.com/micro/go-micro/v3/router/registry" | 	regRouter "github.com/asim/go-micro/v3/router/registry" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func newTestRouter() router.Router { | func newTestRouter() router.Router { | ||||||
|   | |||||||
| @@ -4,8 +4,8 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/client" | 	"github.com/asim/go-micro/v3/client" | ||||||
| 	"github.com/micro/go-micro/v3/transport" | 	"github.com/asim/go-micro/v3/network/transport" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestCallOptions(t *testing.T) { | func TestCallOptions(t *testing.T) { | ||||||
|   | |||||||
| @@ -4,16 +4,16 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/broker" | 	"github.com/asim/go-micro/v3/broker" | ||||||
| 	"github.com/micro/go-micro/v3/broker/http" | 	"github.com/asim/go-micro/v3/broker/http" | ||||||
| 	"github.com/micro/go-micro/v3/codec" | 	"github.com/asim/go-micro/v3/codec" | ||||||
| 	"github.com/micro/go-micro/v3/registry" | 	"github.com/asim/go-micro/v3/network/transport" | ||||||
| 	"github.com/micro/go-micro/v3/router" | 	thttp "github.com/asim/go-micro/v3/network/transport/http" | ||||||
| 	regRouter "github.com/micro/go-micro/v3/router/registry" | 	"github.com/asim/go-micro/v3/registry" | ||||||
| 	"github.com/micro/go-micro/v3/selector" | 	"github.com/asim/go-micro/v3/router" | ||||||
| 	"github.com/micro/go-micro/v3/selector/random" | 	regRouter "github.com/asim/go-micro/v3/router/registry" | ||||||
| 	"github.com/micro/go-micro/v3/transport" | 	"github.com/asim/go-micro/v3/selector" | ||||||
| 	thttp "github.com/micro/go-micro/v3/transport/http" | 	"github.com/asim/go-micro/v3/selector/roundrobin" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type Options struct { | type Options struct { | ||||||
| @@ -36,9 +36,6 @@ type Options struct { | |||||||
| 	PoolSize int | 	PoolSize int | ||||||
| 	PoolTTL  time.Duration | 	PoolTTL  time.Duration | ||||||
|  |  | ||||||
| 	// Response cache |  | ||||||
| 	Cache *Cache |  | ||||||
|  |  | ||||||
| 	// Middleware for client | 	// Middleware for client | ||||||
| 	Wrappers []Wrapper | 	Wrappers []Wrapper | ||||||
|  |  | ||||||
| @@ -55,8 +52,6 @@ type CallOptions struct { | |||||||
| 	Address []string | 	Address []string | ||||||
| 	// Backoff func | 	// Backoff func | ||||||
| 	Backoff BackoffFunc | 	Backoff BackoffFunc | ||||||
| 	// Duration to cache the response for |  | ||||||
| 	CacheExpiry time.Duration |  | ||||||
| 	// Transport Dial Timeout | 	// Transport Dial Timeout | ||||||
| 	DialTimeout time.Duration | 	DialTimeout time.Duration | ||||||
| 	// Number of Call attempts | 	// Number of Call attempts | ||||||
| @@ -109,7 +104,6 @@ type RequestOptions struct { | |||||||
|  |  | ||||||
| func NewOptions(options ...Option) Options { | func NewOptions(options ...Option) Options { | ||||||
| 	opts := Options{ | 	opts := Options{ | ||||||
| 		Cache:       NewCache(), |  | ||||||
| 		Context:     context.Background(), | 		Context:     context.Background(), | ||||||
| 		ContentType: "application/protobuf", | 		ContentType: "application/protobuf", | ||||||
| 		Codecs:      make(map[string]codec.NewCodec), | 		Codecs:      make(map[string]codec.NewCodec), | ||||||
| @@ -125,7 +119,7 @@ func NewOptions(options ...Option) Options { | |||||||
| 		PoolTTL:   DefaultPoolTTL, | 		PoolTTL:   DefaultPoolTTL, | ||||||
| 		Broker:    http.NewBroker(), | 		Broker:    http.NewBroker(), | ||||||
| 		Router:    regRouter.NewRouter(), | 		Router:    regRouter.NewRouter(), | ||||||
| 		Selector:  random.NewSelector(), | 		Selector:  roundrobin.NewSelector(), | ||||||
| 		Transport: thttp.NewTransport(), | 		Transport: thttp.NewTransport(), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -357,14 +351,6 @@ func WithAuthToken() CallOption { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // WithCache is a CallOption which sets the duration the response |  | ||||||
| // shoull be cached for |  | ||||||
| func WithCache(c time.Duration) CallOption { |  | ||||||
| 	return func(o *CallOptions) { |  | ||||||
| 		o.CacheExpiry = c |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // WithNetwork is a CallOption which sets the network attribute | // WithNetwork is a CallOption which sets the network attribute | ||||||
| func WithNetwork(n string) CallOption { | func WithNetwork(n string) CallOption { | ||||||
| 	return func(o *CallOptions) { | 	return func(o *CallOptions) { | ||||||
|   | |||||||
| @@ -2,8 +2,9 @@ package client | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"net/http" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/v3/errors" | 	"github.com/asim/go-micro/v3/errors" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // note that returning either false or a non-nil error will result in the call not being retried | // note that returning either false or a non-nil error will result in the call not being retried | ||||||
| @@ -27,7 +28,7 @@ func RetryOnError(ctx context.Context, req Request, retryCount int, err error) ( | |||||||
|  |  | ||||||
| 	switch e.Code { | 	switch e.Code { | ||||||
| 	// retry on timeout or internal server error | 	// retry on timeout or internal server error | ||||||
| 	case 408, 500: | 	case http.StatusRequestTimeout, http.StatusInternalServerError: | ||||||
| 		return true, nil | 		return true, nil | ||||||
| 	default: | 	default: | ||||||
| 		return false, nil | 		return false, nil | ||||||
|   | |||||||
| @@ -1,402 +0,0 @@ | |||||||
| // Code generated by protoc-gen-go. DO NOT EDIT. |  | ||||||
| // source: client/service/proto/client.proto |  | ||||||
|  |  | ||||||
| package go_micro_client |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	context "context" |  | ||||||
| 	fmt "fmt" |  | ||||||
| 	proto "github.com/golang/protobuf/proto" |  | ||||||
| 	grpc "google.golang.org/grpc" |  | ||||||
| 	codes "google.golang.org/grpc/codes" |  | ||||||
| 	status "google.golang.org/grpc/status" |  | ||||||
| 	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 |  | ||||||
|  |  | ||||||
| type Request struct { |  | ||||||
| 	Service              string   `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"` |  | ||||||
| 	Endpoint             string   `protobuf:"bytes,2,opt,name=endpoint,proto3" json:"endpoint,omitempty"` |  | ||||||
| 	ContentType          string   `protobuf:"bytes,3,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` |  | ||||||
| 	Body                 []byte   `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` |  | ||||||
| 	XXX_sizecache        int32    `json:"-"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) Reset()         { *m = Request{} } |  | ||||||
| func (m *Request) String() string { return proto.CompactTextString(m) } |  | ||||||
| func (*Request) ProtoMessage()    {} |  | ||||||
| func (*Request) Descriptor() ([]byte, []int) { |  | ||||||
| 	return fileDescriptor_27c3d425ddd1a066, []int{0} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) XXX_Unmarshal(b []byte) error { |  | ||||||
| 	return xxx_messageInfo_Request.Unmarshal(m, b) |  | ||||||
| } |  | ||||||
| func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |  | ||||||
| 	return xxx_messageInfo_Request.Marshal(b, m, deterministic) |  | ||||||
| } |  | ||||||
| func (m *Request) XXX_Merge(src proto.Message) { |  | ||||||
| 	xxx_messageInfo_Request.Merge(m, src) |  | ||||||
| } |  | ||||||
| func (m *Request) XXX_Size() int { |  | ||||||
| 	return xxx_messageInfo_Request.Size(m) |  | ||||||
| } |  | ||||||
| func (m *Request) XXX_DiscardUnknown() { |  | ||||||
| 	xxx_messageInfo_Request.DiscardUnknown(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var xxx_messageInfo_Request proto.InternalMessageInfo |  | ||||||
|  |  | ||||||
| func (m *Request) GetService() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Service |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) GetEndpoint() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Endpoint |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) GetContentType() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.ContentType |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Request) GetBody() []byte { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Body |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Response struct { |  | ||||||
| 	Body                 []byte   `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` |  | ||||||
| 	XXX_sizecache        int32    `json:"-"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Response) Reset()         { *m = Response{} } |  | ||||||
| func (m *Response) String() string { return proto.CompactTextString(m) } |  | ||||||
| func (*Response) ProtoMessage()    {} |  | ||||||
| func (*Response) Descriptor() ([]byte, []int) { |  | ||||||
| 	return fileDescriptor_27c3d425ddd1a066, []int{1} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Response) XXX_Unmarshal(b []byte) error { |  | ||||||
| 	return xxx_messageInfo_Response.Unmarshal(m, b) |  | ||||||
| } |  | ||||||
| func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |  | ||||||
| 	return xxx_messageInfo_Response.Marshal(b, m, deterministic) |  | ||||||
| } |  | ||||||
| func (m *Response) XXX_Merge(src proto.Message) { |  | ||||||
| 	xxx_messageInfo_Response.Merge(m, src) |  | ||||||
| } |  | ||||||
| func (m *Response) XXX_Size() int { |  | ||||||
| 	return xxx_messageInfo_Response.Size(m) |  | ||||||
| } |  | ||||||
| func (m *Response) XXX_DiscardUnknown() { |  | ||||||
| 	xxx_messageInfo_Response.DiscardUnknown(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var xxx_messageInfo_Response proto.InternalMessageInfo |  | ||||||
|  |  | ||||||
| func (m *Response) GetBody() []byte { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Body |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Message struct { |  | ||||||
| 	Topic                string   `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"` |  | ||||||
| 	ContentType          string   `protobuf:"bytes,2,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"` |  | ||||||
| 	Body                 []byte   `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` |  | ||||||
| 	XXX_NoUnkeyedLiteral struct{} `json:"-"` |  | ||||||
| 	XXX_unrecognized     []byte   `json:"-"` |  | ||||||
| 	XXX_sizecache        int32    `json:"-"` |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Message) Reset()         { *m = Message{} } |  | ||||||
| func (m *Message) String() string { return proto.CompactTextString(m) } |  | ||||||
| func (*Message) ProtoMessage()    {} |  | ||||||
| func (*Message) Descriptor() ([]byte, []int) { |  | ||||||
| 	return fileDescriptor_27c3d425ddd1a066, []int{2} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Message) XXX_Unmarshal(b []byte) error { |  | ||||||
| 	return xxx_messageInfo_Message.Unmarshal(m, b) |  | ||||||
| } |  | ||||||
| func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { |  | ||||||
| 	return xxx_messageInfo_Message.Marshal(b, m, deterministic) |  | ||||||
| } |  | ||||||
| func (m *Message) XXX_Merge(src proto.Message) { |  | ||||||
| 	xxx_messageInfo_Message.Merge(m, src) |  | ||||||
| } |  | ||||||
| func (m *Message) XXX_Size() int { |  | ||||||
| 	return xxx_messageInfo_Message.Size(m) |  | ||||||
| } |  | ||||||
| func (m *Message) XXX_DiscardUnknown() { |  | ||||||
| 	xxx_messageInfo_Message.DiscardUnknown(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var xxx_messageInfo_Message proto.InternalMessageInfo |  | ||||||
|  |  | ||||||
| func (m *Message) GetTopic() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Topic |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Message) GetContentType() string { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.ContentType |  | ||||||
| 	} |  | ||||||
| 	return "" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (m *Message) GetBody() []byte { |  | ||||||
| 	if m != nil { |  | ||||||
| 		return m.Body |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	proto.RegisterType((*Request)(nil), "go.micro.client.Request") |  | ||||||
| 	proto.RegisterType((*Response)(nil), "go.micro.client.Response") |  | ||||||
| 	proto.RegisterType((*Message)(nil), "go.micro.client.Message") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func init() { proto.RegisterFile("client/service/proto/client.proto", fileDescriptor_27c3d425ddd1a066) } |  | ||||||
|  |  | ||||||
| var fileDescriptor_27c3d425ddd1a066 = []byte{ |  | ||||||
| 	// 267 bytes of a gzipped FileDescriptorProto |  | ||||||
| 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x91, 0xc1, 0x4b, 0xc3, 0x30, |  | ||||||
| 	0x14, 0xc6, 0x97, 0x6d, 0xb6, 0xf3, 0x39, 0x10, 0x1e, 0x1e, 0x62, 0x0f, 0xb2, 0xf5, 0xd4, 0x53, |  | ||||||
| 	0x2b, 0x7a, 0x16, 0x0f, 0x3d, 0x0b, 0x52, 0xc5, 0xab, 0xb4, 0xd9, 0x63, 0x06, 0xba, 0x24, 0x36, |  | ||||||
| 	0xd9, 0xa0, 0x7f, 0xa4, 0xff, 0x93, 0x90, 0x46, 0x27, 0xba, 0x5d, 0xbc, 0xe5, 0xfb, 0x7e, 0xe4, |  | ||||||
| 	0x7b, 0x2f, 0x5f, 0x60, 0x29, 0x5a, 0x49, 0xca, 0x15, 0x96, 0xba, 0x9d, 0x14, 0x54, 0x98, 0x4e, |  | ||||||
| 	0x3b, 0x5d, 0x0c, 0x66, 0xee, 0x05, 0x9e, 0xaf, 0x75, 0xbe, 0x91, 0xa2, 0xd3, 0xf9, 0x60, 0xa7, |  | ||||||
| 	0x3b, 0x88, 0x2b, 0x7a, 0xdf, 0x92, 0x75, 0xc8, 0x21, 0x0e, 0x37, 0x39, 0x5b, 0xb0, 0xec, 0xb4, |  | ||||||
| 	0xfa, 0x92, 0x98, 0xc0, 0x8c, 0xd4, 0xca, 0x68, 0xa9, 0x1c, 0x1f, 0x7b, 0xf4, 0xad, 0x71, 0x09, |  | ||||||
| 	0x73, 0xa1, 0x95, 0x23, 0xe5, 0x5e, 0x5d, 0x6f, 0x88, 0x4f, 0x3c, 0x3f, 0x0b, 0xde, 0x73, 0x6f, |  | ||||||
| 	0x08, 0x11, 0xa6, 0x8d, 0x5e, 0xf5, 0x7c, 0xba, 0x60, 0xd9, 0xbc, 0xf2, 0xe7, 0xf4, 0x0a, 0x66, |  | ||||||
| 	0x15, 0x59, 0xa3, 0x95, 0xdd, 0x73, 0xf6, 0x83, 0xbf, 0x40, 0xfc, 0x40, 0xd6, 0xd6, 0x6b, 0xc2, |  | ||||||
| 	0x0b, 0x38, 0x71, 0xda, 0x48, 0x11, 0xb6, 0x1a, 0xc4, 0x9f, 0xb9, 0xe3, 0xe3, 0x73, 0x27, 0xfb, |  | ||||||
| 	0xdc, 0x9b, 0x0f, 0x06, 0x51, 0xe9, 0x9f, 0x8e, 0x77, 0x30, 0x2d, 0xeb, 0xb6, 0x45, 0x9e, 0xff, |  | ||||||
| 	0x2a, 0x25, 0x0f, 0x8d, 0x24, 0x97, 0x07, 0xc8, 0xb0, 0x73, 0x3a, 0xc2, 0x12, 0xa2, 0x27, 0xd7, |  | ||||||
| 	0x51, 0xbd, 0xf9, 0x67, 0x40, 0xc6, 0xae, 0x19, 0xde, 0x43, 0xfc, 0xb8, 0x6d, 0x5a, 0x69, 0xdf, |  | ||||||
| 	0x0e, 0xa4, 0x84, 0x02, 0x92, 0xa3, 0x24, 0x1d, 0x35, 0x91, 0xff, 0xd7, 0xdb, 0xcf, 0x00, 0x00, |  | ||||||
| 	0x00, 0xff, 0xff, 0xd6, 0x3f, 0xc3, 0xa1, 0xfc, 0x01, 0x00, 0x00, |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Reference imports to suppress errors if they are not otherwise used. |  | ||||||
| var _ context.Context |  | ||||||
| var _ grpc.ClientConn |  | ||||||
|  |  | ||||||
| // This is a compile-time assertion to ensure that this generated file |  | ||||||
| // is compatible with the grpc package it is being compiled against. |  | ||||||
| const _ = grpc.SupportPackageIsVersion4 |  | ||||||
|  |  | ||||||
| // ClientClient is the client API for Client service. |  | ||||||
| // |  | ||||||
| // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. |  | ||||||
| type ClientClient interface { |  | ||||||
| 	// Call allows a single request to be made |  | ||||||
| 	Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) |  | ||||||
| 	// Stream is a bidirectional stream |  | ||||||
| 	Stream(ctx context.Context, opts ...grpc.CallOption) (Client_StreamClient, error) |  | ||||||
| 	// Publish publishes a message and returns an empty Message |  | ||||||
| 	Publish(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type clientClient struct { |  | ||||||
| 	cc *grpc.ClientConn |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func NewClientClient(cc *grpc.ClientConn) ClientClient { |  | ||||||
| 	return &clientClient{cc} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *clientClient) Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { |  | ||||||
| 	out := new(Response) |  | ||||||
| 	err := c.cc.Invoke(ctx, "/go.micro.client.Client/Call", in, out, opts...) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return out, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *clientClient) Stream(ctx context.Context, opts ...grpc.CallOption) (Client_StreamClient, error) { |  | ||||||
| 	stream, err := c.cc.NewStream(ctx, &_Client_serviceDesc.Streams[0], "/go.micro.client.Client/Stream", opts...) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	x := &clientStreamClient{stream} |  | ||||||
| 	return x, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Client_StreamClient interface { |  | ||||||
| 	Send(*Request) error |  | ||||||
| 	Recv() (*Response, error) |  | ||||||
| 	grpc.ClientStream |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type clientStreamClient struct { |  | ||||||
| 	grpc.ClientStream |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *clientStreamClient) Send(m *Request) error { |  | ||||||
| 	return x.ClientStream.SendMsg(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *clientStreamClient) Recv() (*Response, error) { |  | ||||||
| 	m := new(Response) |  | ||||||
| 	if err := x.ClientStream.RecvMsg(m); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return m, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (c *clientClient) Publish(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error) { |  | ||||||
| 	out := new(Message) |  | ||||||
| 	err := c.cc.Invoke(ctx, "/go.micro.client.Client/Publish", in, out, opts...) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return out, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ClientServer is the server API for Client service. |  | ||||||
| type ClientServer interface { |  | ||||||
| 	// Call allows a single request to be made |  | ||||||
| 	Call(context.Context, *Request) (*Response, error) |  | ||||||
| 	// Stream is a bidirectional stream |  | ||||||
| 	Stream(Client_StreamServer) error |  | ||||||
| 	// Publish publishes a message and returns an empty Message |  | ||||||
| 	Publish(context.Context, *Message) (*Message, error) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // UnimplementedClientServer can be embedded to have forward compatible implementations. |  | ||||||
| type UnimplementedClientServer struct { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (*UnimplementedClientServer) Call(ctx context.Context, req *Request) (*Response, error) { |  | ||||||
| 	return nil, status.Errorf(codes.Unimplemented, "method Call not implemented") |  | ||||||
| } |  | ||||||
| func (*UnimplementedClientServer) Stream(srv Client_StreamServer) error { |  | ||||||
| 	return status.Errorf(codes.Unimplemented, "method Stream not implemented") |  | ||||||
| } |  | ||||||
| func (*UnimplementedClientServer) Publish(ctx context.Context, req *Message) (*Message, error) { |  | ||||||
| 	return nil, status.Errorf(codes.Unimplemented, "method Publish not implemented") |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func RegisterClientServer(s *grpc.Server, srv ClientServer) { |  | ||||||
| 	s.RegisterService(&_Client_serviceDesc, srv) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func _Client_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |  | ||||||
| 	in := new(Request) |  | ||||||
| 	if err := dec(in); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if interceptor == nil { |  | ||||||
| 		return srv.(ClientServer).Call(ctx, in) |  | ||||||
| 	} |  | ||||||
| 	info := &grpc.UnaryServerInfo{ |  | ||||||
| 		Server:     srv, |  | ||||||
| 		FullMethod: "/go.micro.client.Client/Call", |  | ||||||
| 	} |  | ||||||
| 	handler := func(ctx context.Context, req interface{}) (interface{}, error) { |  | ||||||
| 		return srv.(ClientServer).Call(ctx, req.(*Request)) |  | ||||||
| 	} |  | ||||||
| 	return interceptor(ctx, in, info, handler) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func _Client_Stream_Handler(srv interface{}, stream grpc.ServerStream) error { |  | ||||||
| 	return srv.(ClientServer).Stream(&clientStreamServer{stream}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type Client_StreamServer interface { |  | ||||||
| 	Send(*Response) error |  | ||||||
| 	Recv() (*Request, error) |  | ||||||
| 	grpc.ServerStream |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type clientStreamServer struct { |  | ||||||
| 	grpc.ServerStream |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *clientStreamServer) Send(m *Response) error { |  | ||||||
| 	return x.ServerStream.SendMsg(m) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (x *clientStreamServer) Recv() (*Request, error) { |  | ||||||
| 	m := new(Request) |  | ||||||
| 	if err := x.ServerStream.RecvMsg(m); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return m, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func _Client_Publish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { |  | ||||||
| 	in := new(Message) |  | ||||||
| 	if err := dec(in); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	if interceptor == nil { |  | ||||||
| 		return srv.(ClientServer).Publish(ctx, in) |  | ||||||
| 	} |  | ||||||
| 	info := &grpc.UnaryServerInfo{ |  | ||||||
| 		Server:     srv, |  | ||||||
| 		FullMethod: "/go.micro.client.Client/Publish", |  | ||||||
| 	} |  | ||||||
| 	handler := func(ctx context.Context, req interface{}) (interface{}, error) { |  | ||||||
| 		return srv.(ClientServer).Publish(ctx, req.(*Message)) |  | ||||||
| 	} |  | ||||||
| 	return interceptor(ctx, in, info, handler) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var _Client_serviceDesc = grpc.ServiceDesc{ |  | ||||||
| 	ServiceName: "go.micro.client.Client", |  | ||||||
| 	HandlerType: (*ClientServer)(nil), |  | ||||||
| 	Methods: []grpc.MethodDesc{ |  | ||||||
| 		{ |  | ||||||
| 			MethodName: "Call", |  | ||||||
| 			Handler:    _Client_Call_Handler, |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			MethodName: "Publish", |  | ||||||
| 			Handler:    _Client_Publish_Handler, |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
| 	Streams: []grpc.StreamDesc{ |  | ||||||
| 		{ |  | ||||||
| 			StreamName:    "Stream", |  | ||||||
| 			Handler:       _Client_Stream_Handler, |  | ||||||
| 			ServerStreams: true, |  | ||||||
| 			ClientStreams: true, |  | ||||||
| 		}, |  | ||||||
| 	}, |  | ||||||
| 	Metadata: "client/service/proto/client.proto", |  | ||||||
| } |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user