Compare commits

...

133 Commits

Author SHA1 Message Date
Asim Aslam
e219ace4b4 Update README.md 2020-10-20 11:47:46 +01:00
Asim Aslam
e26a0889ae Update LICENSE 2020-10-20 11:47:26 +01:00
Asim Aslam
5ea51f5a29 Update README.md 2020-10-20 11:32:04 +01:00
Asim Aslam
ee1c429e37 remove start from runtime 2020-10-20 10:28:47 +01:00
Asim Aslam
4a5b91c215 Update README.md 2020-10-20 10:17:33 +01:00
Asim Aslam
321446ce29 Update README.md 2020-10-20 10:17:09 +01:00
Asim Aslam
b508565a78 rename imports to asim/go-micro (#2051) 2020-10-20 10:15:39 +01:00
Asim Aslam
1ee348109e Merge branch 'master' of ssh://github.com/asim/go-micro 2020-10-19 19:18:46 +01:00
Asim Aslam
1fb2d4c51e strip out docker build 2020-10-19 19:18:35 +01:00
Asim Aslam
968a4f89c4 Update README.md 2020-10-19 12:17:50 +01:00
Asim Aslam
5f3b1daf82 Update network.go 2020-10-19 08:19:45 +01:00
Lars Lehtonen
65a5feab3c runtime: fix resource test (#2048) 2020-10-19 07:21:56 +01:00
Asim Aslam
f679b560bb Merge branch 'master' of ssh://github.com/asim/go-micro 2020-10-18 15:26:20 +01:00
Asim Aslam
91dfd46eb1 remove static router 2020-10-18 15:26:01 +01:00
Asim Aslam
95f8aa68f2 Update README.md 2020-10-18 10:25:56 +01:00
Asim Aslam
79834cc131 add build string method 2020-10-18 09:53:04 +01:00
Asim Aslam
04b5fc19c2 change build interface 2020-10-18 09:51:11 +01:00
Asim Aslam
48de9f25a8 acme string 2020-10-18 09:47:05 +01:00
Asim Aslam
68402dcb96 move internal proto to rpc handler dir 2020-10-18 08:43:21 +01:00
Asim Aslam
c3a9013863 Merge branch 'master' of ssh://github.com/asim/go-micro 2020-10-18 08:10:56 +01:00
Asim Aslam
8215db3be9 move acme out of api 2020-10-18 08:10:46 +01:00
xyb
2e45567e56 remove some http hard code (#2047)
Co-authored-by: yonbiaoxiao <yonbiaoxiao@tencent.com>
2020-10-18 05:58:38 +01:00
Asim Aslam
07b32ad3b9 move util 2020-10-17 21:18:59 +01:00
Asim Aslam
2ecd049871 Merge branch 'master' of ssh://github.com/asim/go-micro 2020-10-17 21:17:06 +01:00
Asim Aslam
6bf1bcf1b5 fix store test 2020-10-17 17:02:43 +01:00
Asim Aslam
7058b444ab Update README.md 2020-10-17 16:41:30 +01:00
Asim Aslam
c917566ce4 remove certmagic 2020-10-17 15:50:14 +01:00
Asim Aslam
ef9d975d9b fix store cache test 2020-10-17 15:47:19 +01:00
Asim Aslam
be06de5c47 update api 2020-10-17 15:36:05 +01:00
Asim Aslam
975da990a9 rewrite api package 2020-10-17 15:33:56 +01:00
Asim Aslam
f2728a7fee remove vpath resolver 2020-10-17 15:00:40 +01:00
Asim Aslam
d3b37f14cf Merge branch 'master' of ssh://github.com/asim/go-micro 2020-10-17 14:58:37 +01:00
Asim Aslam
525b436bf1 remove sub 2020-10-17 14:58:29 +01:00
Asim Aslam
7935276c54 Update FUNDING.yml 2020-10-17 14:56:31 +01:00
Asim Aslam
1088fa0a31 strip debug log from logger 2020-10-17 14:56:06 +01:00
Asim Aslam
0ebf401c21 move file store 2020-10-17 14:50:05 +01:00
Asim Aslam
916a2a1a99 Update README.md 2020-10-17 14:44:11 +01:00
Asim Aslam
c459164ad4 Update README.md 2020-10-17 14:43:27 +01:00
Asim Aslam
d7295810da subscribe to consume 2020-10-17 10:33:30 +01:00
Asim Aslam
1b8ccd13a6 fix errors proto and stream 2020-10-17 10:26:26 +01:00
Asim Aslam
ffc9bff208 remove sql model 2020-10-17 10:09:59 +01:00
Asim Aslam
fe67b26bfc replace metrics interface 2020-10-17 10:09:26 +01:00
Asim Aslam
1bdbe0fad5 update comment 2020-10-17 10:05:48 +01:00
Asim Aslam
c7f24aa425 remove events store 2020-10-17 10:04:18 +01:00
Asim Aslam
1ae2ac9020 remove errors proto 2020-10-17 09:54:05 +01:00
Asim Aslam
274aacda1d remove api handlers and proto 2020-10-17 09:52:43 +01:00
Asim Aslam
00c39f4f2c remove server proto 2020-10-17 09:38:21 +01:00
Asim Aslam
cc547a9f1a remove store s3 plugin 2020-10-17 09:37:10 +01:00
Asim Aslam
d31708f8e9 update license to polyform perimeter 2020-10-17 08:16:01 +01:00
Asim Aslam
25ec6331e8 Update README.md 2020-10-16 19:32:32 +01:00
Asim Aslam
97b4762ab2 Update README.md 2020-10-16 19:32:14 +01:00
xyb
a511f1dc64 remove some http hard code (#2045)
Co-authored-by: yonbiaoxiao <yonbiaoxiao@tencent.com>
2020-10-15 16:09:48 +01:00
epicmr
e809cb9117 Just watch services concerned (#2044)
Co-authored-by: 彭能辉 <nenghui.peng@360gst.com>
2020-10-15 13:38:41 +01:00
Prawn
04726dbea5 ResourceQuota support for utils/kubernetes (#2040)
Co-authored-by: chris <chris@Profanity.local>
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-10-14 17:34:01 +01:00
Dominic Wong
c49fef49b8 ignore already exists error (#2043) 2020-10-14 11:32:35 +01:00
Prawn
1a962e46fd Runtime refactoring and NetworkPolicy support (#2016) 2020-10-13 14:54:05 +01:00
Asim Aslam
5e35d89b38 Update README.md 2020-10-10 19:22:36 +01:00
ben-toogood
dad05be95e runtime/kubernetes: rewrite to improve support of multiple versions of a single service (#2035)
* wip: refactor kubernetes package

* runtime/kubernetes: fix invalid labels

* runtime/kubernetes: handle delete service not found error

* Misc Fixes

* runtime: add ServiceAccount option

* router/static: return noop table

* add kubernetes router

* runtime: add port option

* store/file: set directory

* store/file: pass options to blob store

* Revert changes to static router

* Fix merge error

* runtime/kubernetes: Debug => Error logs

* runtime/kubernetes: fix double if
2020-10-09 13:28:15 +01:00
ben-toogood
c701f96a09 store/file: add WithDir option (#2038) 2020-10-07 12:37:28 +01:00
ben-toogood
27aa1ff2ab Depricate runtime scheduler (#2037) 2020-10-07 12:31:41 +01:00
ben-toogood
8f6ba4a56e Kubernetes Router (#2036) 2020-10-07 12:25:50 +01:00
ben-toogood
0a6e451539 Fixes for runtime builder (#2029)
* util/tar: add archive util funcs

* runtime: add store, builder options

* runtime/local: update RuntimeSource func

* runtime/builder/golang: use tar util

* store/s3: make keys safe

* runtime: add entrypoint options

* runtime/builder: remove debugging

* wip: integrate builder into k8s runtime

* runtime/builder/golang: build for a linux architecture

* runtime/kubernetes: write builds to the users namespace

* runtime/local/source: fixes for mono-repo builds

* runtime/local: stop checking out source (the responsibility is on the client)

* runtime/builder: fix golang tests

* runtime/local: fix out of bounds panic

* Update

* revert changes

* runtime/local/source: refactor git package (wip)

* runtime/kubernetes: map err not found

* fix TestRunGenericRemote test

* runtime/local: fix update not reassining source

* Tidy go mod

* runtime.Pending => runtime.Starting

* store/s3: only use credentials option when set

* store/s3: add tls config option
2020-10-02 09:54:26 +01:00
Lars Lehtonen
231cfc48f0 store/test: fix dropped error (#2030) 2020-10-02 09:44:22 +01:00
ben-toogood
a365c51c2b runtime: add WithVolume options and k8s support (#2032)
* runtime: add WithVolume option

* Fix pointer

* k8s: fix template

* k8s: fix template

* k8s: fix template
2020-09-30 16:38:29 +01:00
ben-toogood
02b74a5487 router/static: implement noop watcher (#2031)
* router/static: implement noop watcher

* proxy/mucp: handle nil watcher
2020-09-30 14:53:08 +01:00
Janos Dobronszki
87e898f4fc Secret implementation of config. Supporting config merge (#2027)
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-09-29 15:30:51 +02:00
Asim Aslam
d246ccbeef Update tests.yml 2020-09-28 14:40:53 +01:00
Asim Aslam
017e156440 remove transport options 2020-09-26 13:29:09 +01:00
Asim Aslam
d8f17ac827 readd service package (#2026) 2020-09-26 13:15:05 +01:00
Asim Aslam
6e2c9e7cd4 env config implementation (#2024) 2020-09-25 10:24:02 +01:00
ben-toogood
4028e0156b runtime: remove builder package (moved to micro) (#2023) 2020-09-25 10:02:49 +01:00
Dominic Wong
76275e857c Fix branch names support for k8s runtime (#2020)
* fix branch names support for k8s

* remove logs

Co-authored-by: Asim Aslam <asim@aslam.me>
2020-09-25 08:41:28 +01:00
wangzq
a18806c9ef fix config bug (#2021) 2020-09-25 08:14:21 +01:00
ben-toogood
255fecb4f4 runtime: minor fixes for local runtime (#2019) 2020-09-24 16:46:23 +01:00
Asim Aslam
af8d55eb7f remove memcache and update gomod 2020-09-23 21:16:16 +01:00
Janos Dobronszki
354a169050 Add errors to config methods (#2015) 2020-09-22 16:08:01 +02:00
ben-toogood
6e083b9aca store/file: fix segmentation violation bug (#2013) 2020-09-22 10:00:14 +01:00
Janos Dobronszki
9dbd75f2cc Config interface change (#2010) 2020-09-21 17:45:45 +02:00
ben-toogood
8975184b88 proxy/grpc: fix client streaming bug (EOF not sent to the server) (#2011) 2020-09-18 14:20:42 +01:00
ben-toogood
19a54f2970 client/grpc: fix stream closed bug (#2009)
* client/grpc: fix stream closed bug

* client/grpc: don't use dial context for the stream
2020-09-17 14:08:21 +01:00
ben-toogood
3c7f663e8b store/file: don't keep connection to boltdb open (#2006) 2020-09-16 13:09:04 +01:00
ben-toogood
8fdc8f05ce runtime/builder with golang implementation (#2003) 2020-09-15 17:26:27 +01:00
ben-toogood
35349bd313 store: implement s3 blob store (#2005) 2020-09-15 17:09:40 +01:00
ben-toogood
d5bfa1e795 store: add blob interface with file implementation (#2004) 2020-09-15 14:05:10 +01:00
ben-toogood
3bb76868d1 auth: remove micro specific code (#1999) 2020-09-11 13:41:13 +01:00
Janos Dobronszki
275e92be32 Fix running subfolders (#1998) 2020-09-11 12:57:23 +02:00
ben-toogood
d2728b498c api: fix request body re-sequencing bug (#1996)
* api: don't mutate request body on POST requests

* fix test suite

* Improve solution

Co-authored-by: Asim Aslam <asim@aslam.me>
2020-09-10 16:07:37 +01:00
Dominic Wong
601b223cfb add Name to auth.Account as a user friendly alias (#1992)
* add Name to auth.Account as a user friendly alias
2020-09-10 14:49:51 +01:00
Janos Dobronszki
04d2aa4696 Fixing top level run outside repo (#1993) 2020-09-10 14:36:36 +02:00
ben-toogood
b8f79a3fc6 runtime: normalised service statuses (#1994) 2020-09-10 12:17:11 +01:00
Janos Dobronszki
acd3bea0c6 Add 'Namespace' header to allowed CORS headers (#1990) 2020-09-09 15:40:02 +02:00
Asim Aslam
a02a25d955 Remove all the external plugins except grpc (#1988)
* Remove all the external plugins except grpc

* strip cockroach

* strip nats test

* fix build
2020-09-08 13:14:45 +01:00
ben-toogood
d5e345d41d util/kubernetes: fix TCPSocketAction bug (#1987) 2020-09-08 11:43:47 +01:00
Prawn
71f8cbd5e2 Fixing the metric tagging issue here (#1986)
Co-authored-by: chris <chris@Profanity.local>
2020-09-07 09:10:04 +01:00
Asim Aslam
f12473f4b1 Update runtime.go 2020-09-04 22:43:32 +01:00
Dominic Wong
724e2b5830 Memory events stream not pushing publications correctly (#1984)
* subs not filtered correctly on publish. simplify retry logic

* check fo invalid ackwait
2020-09-04 08:31:49 +01:00
Dominic Wong
6bdf33c4ee Event stream updates (#1981)
- auto and manual acking
- retry limits
2020-09-02 13:28:54 +01:00
dy1006
84f52fd7ac Update log.go (#1976)
change nlog.DefaultLogger.Log to nlog.DefaultLogger.Logf in the Logf function
2020-08-31 07:18:55 +01:00
Dominic Wong
6e30b53280 fix cockroach init to create table in correct database (#1977) 2020-08-28 10:35:47 +01:00
dy1006
a60426c884 Update rpc.go (#1975)
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-08-27 10:24:19 +01:00
Prawn
2998735bf3 Tidying up the new Metrics implementations (#1974)
* Unit tests to check tagging and aggregation of Prometheus metrics

* Removing the logger output routing (because it doesn't actually work in the logger implementation)

* Emitting values with the logging reporter

Co-authored-by: chris <chris@Profanity.local>
2020-08-27 09:08:51 +01:00
wangxu
3a96135df8 add log grpc handler err (#1973)
Co-authored-by: wangxu <wangxu@oneniceapp.com>
2020-08-25 10:11:02 +01:00
zuoan
bf8b3aeac7 remove redunant code and cleanup (#1970)
* remove redundant code

* check invalid ip address first

* remove redundant code

* cleanup

Co-authored-by: 刘海洋 <haiyang@snqu.com>
2020-08-25 09:10:46 +01:00
Dominic Wong
5a52b5929c add create and delete namespace to runtime (#1965)
* add create and delete namespace to runtime

* dial down aggressive expiry

* add logging

* fix deletenamespace

* add start of k8s unit tests

* fix workflow

* turn on k8s tests

* ease tight tests

* mkdir in workflow

* dammit -p

* setup folder
2020-08-24 16:54:39 +01:00
ben-toogood
0adb469a85 runtime/local: fix unknown dir path (#1964)
Co-authored-by: Asim Aslam <asim@aslam.me>
Co-authored-by: Janos Dobronszki <dobronszki@gmail.com>
2020-08-24 15:23:44 +02:00
Asim Aslam
21004341bf Rename reporter.go to metrics.go 2020-08-23 22:18:28 +01:00
Asim Aslam
cc26f2b8b1 delete api service proto 2020-08-23 21:58:16 +01:00
Asim Aslam
1a6652fe6b sql model template 2020-08-23 21:30:46 +01:00
Asim Aslam
d28f0670d6 Move git into local/source 2020-08-23 21:23:07 +01:00
Asim Aslam
7bdd619e1b move plugin to util 2020-08-23 21:18:59 +01:00
Asim Aslam
c62d1d5eb8 move transport (#1967) 2020-08-23 18:37:22 +01:00
Asim Aslam
d60d85de5c move tunnel/resolver into network 2020-08-23 15:00:27 +01:00
Asim Aslam
44f281f8d9 remove test request file 2020-08-23 14:13:45 +01:00
Asim Aslam
f698feac9c remove context from client/server 2020-08-23 14:11:57 +01:00
Asim Aslam
f55701b374 Strip cache from the client. Its only used externally in a wrapper 2020-08-23 13:59:19 +01:00
Asim Aslam
82e8298b73 Router table.Read replaces List/Query (#1966)
* Table.REad insted of list and query

* fmt
2020-08-23 13:10:48 +01:00
Asim Aslam
fc54503232 Merge branch 'master' of ssh://github.com/micro/go-micro 2020-08-22 20:55:52 +01:00
Asim Aslam
6f0594eebe Update static router 2020-08-22 20:55:43 +01:00
Asim Aslam
6b52f859cf Update mucp.go 2020-08-22 16:36:03 +01:00
Asim Aslam
a3d4b8f79b Update mucp.go 2020-08-22 16:35:12 +01:00
Asim Aslam
7c7df6b35d Remove quic transport, move route into router 2020-08-22 16:15:44 +01:00
Asim Aslam
e80eab397a Update events.go 2020-08-22 09:20:53 +01:00
ben-toogood
6cda6ef92e runtime/local: add support for idiomatic folder structures (#1963)
* runtime/local: add support for idiomatic folder structures

* runtime/local: add test coverage

* runtime/local: increase test coverage

* runtime/local: add test for empty local source

* runtime/local: make entrypoint public
2020-08-21 11:17:42 +01:00
Prawn
f9f61d29de Observability/metrics update (#1962)
* Removing logging from the NOOP implementatino

* Simplifying the percentiles option

* Simple logging implementation

Co-authored-by: chris <chris@Profanity.local>
2020-08-21 20:57:10 +12:00
ben-toogood
1ae825032c store: remove write TTL & expiry options (#1960) 2020-08-21 09:35:53 +01:00
Asim Aslam
f146b52418 Registry router fixes (#1961)
* only cache routes if told to do so

* Use roundrobin selector and retry in proxy

* Update lookup to require service

* Fix compile

* Fix compile

* Update

* Update

* rename query to lookup

* Update router.go

* Update
2020-08-21 09:23:01 +01:00
Dominic Wong
78a79ca9e1 Memory and file store list fixes (#1959)
* Refactor file and memory stores
2020-08-20 15:08:35 +01:00
ben-toogood
329bc2f265 events: add store implementation (#1957) 2020-08-20 11:28:04 +01:00
Asim Aslam
8738ed7757 Update debug.go 2020-08-20 10:06:02 +01:00
ben-toogood
29e8cdbfe9 events: update interface (#1954) 2020-08-20 09:29:29 +01:00
Dominic Wong
47f356fc5f Unify the store tests (#1952)
Add more tests for store
2020-08-19 23:41:03 +01:00
Janos Dobronszki
21ffc73c4f Generic git checkout (#1951) 2020-08-19 17:24:42 +02:00
ben-toogood
81a9342b83 util/file: allow context to be passed (#1950) 2020-08-19 16:03:19 +01:00
440 changed files with 6289 additions and 16095 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,3 +1,3 @@
# These are supported funding model platforms
github: micro
github: asim

View File

@@ -25,4 +25,11 @@ jobs:
id: tests
env:
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 ./...

View File

@@ -7,13 +7,17 @@ jobs:
name: Test repo
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.13
uses: actions/setup-go@v1
with:
go-version: 1.13
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
uses: actions/checkout@v2
@@ -25,30 +29,20 @@ jobs:
id: tests
env:
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: |
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 &
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
View File

@@ -1,191 +1,104 @@
# PolyForm Strict License 1.0.0
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
<https://polyformproject.org/licenses/strict/1.0.0>
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,
and distribution as defined by Sections 1 through 9 of this document.
## Copyright License
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
The licensor grants you a copyright license for the software
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
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.
## Patent License
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
The licensor grants you a patent license for the software that
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,
including but not limited to software source code, documentation
source, and configuration files.
## Noncommercial Purposes
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
Any noncommercial purpose is a permitted purpose.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
## Personal Uses
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
Personal use for research, experiment, and testing for
the benefit of public knowledge, personal study, private
entertainment, hobby projects, amateur pursuits, or religious
observance, without any anticipated commercial application,
is use for a permitted purpose.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
## Noncommercial Organizations
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
Use by any charitable organization, educational institution,
public research organization, public safety or health
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
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.
## Fair Use
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
You may have "fair use" rights for the software under the
law. These terms do not limit them.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
## No Other Rights
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
These terms do not allow you to sublicense or transfer any of
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
stating that You changed the files; and
## Patent Defense
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
If you make any written claim that the software infringes or
contributes to infringement of any patent, your patent license
for the software granted under these terms ends immediately. If
your company makes such a claim, your patent license ends
immediately for work on behalf of your company.
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
## Violations
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
The first time you are notified in writing that you have
violated any of these terms, or done anything with the software
not covered by your licenses, your licenses can nonetheless
continue if you come into full compliance with these terms,
and take practical steps to correct past violations, within
32 days of receiving notice. Otherwise, all your licenses
end immediately.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
## No Liability
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
***As far as the law allows, the software comes as is, without
any warranty or condition, and the licensor will not be liable
to you for any damages arising out of these terms or the use
or nature of the software, under any kind of legal claim.***
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
## Definitions
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
The **licensor** is the individual or entity offering these
terms, and the **software** is the software the licensor makes
available under these terms.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
**You** refers to the individual or entity agreeing to these
terms.
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");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**Use** means anything you do with the software requiring one
of your licenses.

View File

@@ -1,6 +1,6 @@
# Go Micro [![License](https://img.shields.io/:license-apache-blue.svg)](https://opensource.org/licenses/Apache-2.0) [![Go.Dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/github.com/micro/go-micro/v3?tab=overview) [![Travis CI](https://api.travis-ci.org/micro/go-micro.svg?branch=master)](https://travis-ci.org/micro/go-micro) [![Go Report Card](https://goreportcard.com/badge/micro/go-micro)](https://goreportcard.com/report/github.com/micro/go-micro)
# Go Micro [![License](https://img.shields.io/badge/license-polyform:perimeter-blue)](https://polyformproject.org/licenses/perimeter/1.0.0/) [![Go.Dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](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
@@ -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
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.
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.
- **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
[github.com/micro/go-plugins](https://github.com/micro/go-plugins).
are pluggable and allows Go Micro to be runtime agnostic. You can plugin any underlying technology. Find external third party (non stdlib)
plugins in [github.com/asim/go-plugins](https://github.com/asim/go-plugins).
## 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
Go Micro is Apache 2.0 licensed.
[Polyform Strict](https://polyformproject.org/licenses/strict/1.0.0/).

View File

@@ -7,6 +7,12 @@ import (
"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 (
// ErrProviderNotImplemented can be returned when attempting to
// instantiate an unimplemented provider
@@ -19,10 +25,6 @@ type Provider interface {
Listen(...string) (net.Listener, error)
// TLSConfig returns a tls config
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"
)

View File

@@ -7,8 +7,8 @@ import (
"net"
"os"
"github.com/micro/go-micro/v3/api/server/acme"
"github.com/micro/go-micro/v3/logger"
"github.com/asim/go-micro/v3/acme"
"github.com/asim/go-micro/v3/logger"
"golang.org/x/crypto/acme/autocert"
)
@@ -40,6 +40,10 @@ func (a *autocertProvider) TLSConfig(hosts ...string) (*tls.Config, error) {
return m.TLSConfig(), nil
}
func (a *autocertProvider) String() string {
return "autocert"
}
// New returns an autocert acme.Provider
func NewProvider() acme.Provider {
return &autocertProvider{}

View File

@@ -2,30 +2,32 @@ package api
import (
"errors"
"net/http"
"regexp"
"strings"
"github.com/micro/go-micro/v3/registry"
"github.com/micro/go-micro/v3/server"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/server"
)
type Api interface {
// Gateway is an api gateway interface
type Gateway interface {
// Initialise options
Init(...Option) error
// Get the options
Options() Options
// Register a http handler
// Register an endpoint
Register(*Endpoint) error
// Register a route
// Deregister a route
Deregister(*Endpoint) error
// Register http handler
Handle(string, http.Handler)
// Start serving requests
Serve() error
// Implementation of api
String() string
}
type Options struct{}
type Option func(*Options) error
// Endpoint is a mapping between an RPC method and HTTP endpoint
type Endpoint struct {
// RPC Method e.g. Greeter.Hello
@@ -58,22 +60,6 @@ type Service struct {
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
func Encode(e *Endpoint) map[string]string {
if e == nil {
@@ -150,28 +136,6 @@ func Validate(e *Endpoint) error {
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
//
// Usage:

View File

@@ -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,
}
}

View File

@@ -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
}

View File

@@ -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])
}
}
}
}
}

View File

@@ -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...),
}
}

View File

@@ -9,9 +9,9 @@ import (
"net/http/httputil"
"net/url"
"github.com/micro/go-micro/v3/api"
"github.com/micro/go-micro/v3/api/handler"
"github.com/micro/go-micro/v3/registry"
"github.com/asim/go-micro/v3/api"
"github.com/asim/go-micro/v3/api/handler"
"github.com/asim/go-micro/v3/registry"
)
const (
@@ -28,7 +28,7 @@ type httpHandler struct {
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
service, err := h.getService(r)
if err != nil {
w.WriteHeader(500)
w.WriteHeader(http.StatusInternalServerError)
return
}
@@ -39,7 +39,7 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rp, err := url.Parse(service)
if err != nil {
w.WriteHeader(500)
w.WriteHeader(http.StatusInternalServerError)
return
}

View File

@@ -6,13 +6,13 @@ import (
"net/http/httptest"
"testing"
"github.com/micro/go-micro/v3/api/handler"
"github.com/micro/go-micro/v3/api/resolver"
"github.com/micro/go-micro/v3/api/resolver/vpath"
"github.com/micro/go-micro/v3/api/router"
regRouter "github.com/micro/go-micro/v3/api/router/registry"
"github.com/micro/go-micro/v3/registry"
"github.com/micro/go-micro/v3/registry/memory"
"github.com/asim/go-micro/v3/api/handler"
"github.com/asim/go-micro/v3/api/resolver"
rpath "github.com/asim/go-micro/v3/api/resolver/path"
"github.com/asim/go-micro/v3/api/router"
regRouter "github.com/asim/go-micro/v3/api/router/registry"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/registry/memory"
)
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(
router.WithHandler("http"),
router.WithRegistry(r),
router.WithResolver(vpath.NewResolver(
router.WithResolver(rpath.NewResolver(
resolver.WithServicePrefix(ns),
)),
)
@@ -92,31 +92,6 @@ func TestHttpHandler(t *testing.T) {
"go.micro.api.test",
"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 {

View File

@@ -1,9 +1,9 @@
package handler
import (
"github.com/micro/go-micro/v3/api/router"
"github.com/micro/go-micro/v3/client"
"github.com/micro/go-micro/v3/client/grpc"
"github.com/asim/go-micro/v3/api/router"
"github.com/asim/go-micro/v3/client"
"github.com/asim/go-micro/v3/client/grpc"
)
var (

View File

@@ -8,20 +8,20 @@ import (
"strconv"
"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"
"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"
)
@@ -249,7 +249,7 @@ func requestPayload(r *http.Request) ([]byte, error) {
return nil, err
}
return raw.Marshal()
case strings.Contains(ct, "application/www-x-form-urlencoded"):
case strings.Contains(ct, "application/x-www-form-urlencoded"):
r.ParseForm()
// generate a new set of values from the form
@@ -364,6 +364,13 @@ func requestPayload(r *http.Request) ([]byte, error) {
bodybuf = b
}
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 {
return out, nil
}
@@ -410,7 +417,6 @@ func requestPayload(r *http.Request) ([]byte, error) {
//fallback to previous unknown behaviour
return bodybuf, nil
}
return []byte{}, nil
@@ -422,11 +428,11 @@ func writeError(w http.ResponseWriter, r *http.Request, err error) {
switch ce.Code {
case 0:
// assuming it's totally screwed
ce.Code = 500
ce.Code = http.StatusInternalServerError
ce.Id = "go.micro.api"
ce.Status = http.StatusText(500)
ce.Status = http.StatusText(http.StatusInternalServerError)
ce.Detail = "error during request: " + ce.Detail
w.WriteHeader(500)
w.WriteHeader(http.StatusInternalServerError)
default:
w.WriteHeader(int(ce.Code))
}

View File

@@ -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), "")
}
})
}

View File

@@ -9,14 +9,14 @@ import (
"strings"
"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/ws"
"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

View File

@@ -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,
}
}

View File

@@ -5,70 +5,62 @@ import (
"crypto/tls"
"net"
"net/http"
"os"
"sync"
"github.com/gorilla/handlers"
"github.com/micro/go-micro/v3/api/server"
"github.com/micro/go-micro/v3/api/server/cors"
"github.com/micro/go-micro/v3/logger"
"github.com/asim/go-micro/v3/api"
"github.com/asim/go-micro/v3/logger"
)
type httpServer struct {
mux *http.ServeMux
opts server.Options
opts api.Options
mtx sync.RWMutex
address string
exit chan chan error
}
func NewServer(address string, opts ...server.Option) server.Server {
var options server.Options
// NewGateway returns a new HTTP api gateway
func NewGateway(opts ...api.Option) api.Gateway {
var options api.Options
for _, o := range opts {
o(&options)
}
return &httpServer{
opts: options,
mux: http.NewServeMux(),
address: address,
exit: make(chan chan error),
opts: options,
mux: http.NewServeMux(),
exit: make(chan chan error),
}
}
func (s *httpServer) Address() string {
s.mtx.RLock()
defer s.mtx.RUnlock()
return s.address
}
func (s *httpServer) Init(opts ...server.Option) error {
func (s *httpServer) Init(opts ...api.Option) error {
for _, o := range opts {
o(&s.opts)
}
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) {
// 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)
}
func (s *httpServer) Serve() error {
if err := s.Start(); err != nil {
return err
}
<-s.exit
return nil
}
func (s *httpServer) Start() error {
var l net.Listener
var err error
@@ -77,10 +69,10 @@ func (s *httpServer) Start() error {
// should we check the address to make sure its using :443?
l, err = s.opts.ACMEProvider.Listen(s.opts.ACMEHosts...)
} 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 {
// otherwise plain listen
l, err = net.Listen("tcp", s.address)
l, err = net.Listen("tcp", s.opts.Address)
}
if err != nil {
return err
@@ -90,10 +82,6 @@ func (s *httpServer) Start() error {
logger.Infof("HTTP API Listening on %s", l.Addr().String())
}
s.mtx.Lock()
s.address = l.Addr().String()
s.mtx.Unlock()
go func() {
if err := http.Serve(l, s.mux); err != nil {
// temporary fix

View File

@@ -1,37 +1,27 @@
package server
package api
import (
"crypto/tls"
"net/http"
"github.com/micro/go-micro/v3/api/resolver"
"github.com/micro/go-micro/v3/api/server/acme"
"github.com/asim/go-micro/v3/acme"
"github.com/asim/go-micro/v3/api/resolver"
)
type Option func(o *Options)
type Options struct {
Address string
EnableACME bool
EnableCORS bool
ACMEProvider acme.Provider
EnableTLS bool
ACMEHosts []string
TLSConfig *tls.Config
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) {
o.Wrappers = append(o.Wrappers, w...)
}
}
func EnableCORS(b bool) Option {
return func(o *Options) {
o.EnableCORS = b
o.Address = a
}
}

View File

@@ -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,
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -6,7 +6,7 @@ import (
"net/http"
"strings"
"github.com/micro/go-micro/v3/api/resolver"
"github.com/asim/go-micro/v3/api/resolver"
)
type Resolver struct {

View File

@@ -4,7 +4,7 @@ package host
import (
"net/http"
"github.com/micro/go-micro/v3/api/resolver"
"github.com/asim/go-micro/v3/api/resolver"
)
type Resolver struct {

View File

@@ -1,7 +1,7 @@
package resolver
import (
"github.com/micro/go-micro/v3/registry"
"github.com/asim/go-micro/v3/registry"
)
type Options struct {

View File

@@ -5,7 +5,7 @@ import (
"net/http"
"strings"
"github.com/micro/go-micro/v3/api/resolver"
"github.com/asim/go-micro/v3/api/resolver"
)
type Resolver struct {

View File

@@ -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"
}

View File

@@ -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)
}
})
}
}

View File

@@ -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, ".")
}

View File

@@ -1,10 +1,10 @@
package router
import (
"github.com/micro/go-micro/v3/api/resolver"
"github.com/micro/go-micro/v3/api/resolver/vpath"
"github.com/micro/go-micro/v3/registry"
"github.com/micro/go-micro/v3/registry/mdns"
"github.com/asim/go-micro/v3/api/resolver"
"github.com/asim/go-micro/v3/api/resolver/path"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/registry/mdns"
)
type Options struct {
@@ -26,7 +26,7 @@ func NewOptions(opts ...Option) Options {
}
if options.Resolver == nil {
options.Resolver = vpath.NewResolver(
options.Resolver = path.NewResolver(
resolver.WithHandler(options.Handler),
)
}

View File

@@ -10,13 +10,13 @@ import (
"sync"
"time"
"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"
"github.com/micro/go-micro/v3/registry/cache"
util "github.com/micro/go-micro/v3/util/router"
"github.com/asim/go-micro/v3/api"
"github.com/asim/go-micro/v3/api/router"
"github.com/asim/go-micro/v3/logger"
"github.com/asim/go-micro/v3/metadata"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/registry/cache"
util "github.com/asim/go-micro/v3/util/router"
)
// endpoint struct, that holds compiled pcre

View File

@@ -3,7 +3,7 @@ package registry
import (
"testing"
"github.com/micro/go-micro/v3/registry"
"github.com/asim/go-micro/v3/registry"
"github.com/stretchr/testify/assert"
)

View File

@@ -4,7 +4,7 @@ package router
import (
"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

View File

@@ -9,20 +9,18 @@ import (
"testing"
"time"
"github.com/micro/go-micro/v3/api"
"github.com/micro/go-micro/v3/api/handler"
"github.com/micro/go-micro/v3/api/handler/rpc"
"github.com/micro/go-micro/v3/api/router"
rregistry "github.com/micro/go-micro/v3/api/router/registry"
rstatic "github.com/micro/go-micro/v3/api/router/static"
"github.com/micro/go-micro/v3/client"
gcli "github.com/micro/go-micro/v3/client/grpc"
rmemory "github.com/micro/go-micro/v3/registry/memory"
rt "github.com/micro/go-micro/v3/router"
regRouter "github.com/micro/go-micro/v3/router/registry"
"github.com/micro/go-micro/v3/server"
gsrv "github.com/micro/go-micro/v3/server/grpc"
pb "github.com/micro/go-micro/v3/server/grpc/proto"
"github.com/asim/go-micro/v3/api/handler"
"github.com/asim/go-micro/v3/api/handler/rpc"
"github.com/asim/go-micro/v3/api/router"
rregistry "github.com/asim/go-micro/v3/api/router/registry"
"github.com/asim/go-micro/v3/client"
gcli "github.com/asim/go-micro/v3/client/grpc"
rmemory "github.com/asim/go-micro/v3/registry/memory"
rt "github.com/asim/go-micro/v3/router"
regRouter "github.com/asim/go-micro/v3/router/registry"
"github.com/asim/go-micro/v3/server"
gsrv "github.com/asim/go-micro/v3/server/grpc"
pb "github.com/asim/go-micro/v3/server/grpc/proto"
)
// server is used to implement helloworld.GreeterServer.
@@ -128,124 +126,3 @@ func TestRouterRegistryPcre(t *testing.T) {
time.Sleep(1 * time.Second)
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
}

View File

@@ -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 := &registry.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
}

View File

@@ -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,
}
}

View File

@@ -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,
}
}

View File

@@ -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")
}

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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",
}

View File

@@ -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)
}

View File

@@ -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
View 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
}

View File

@@ -2,14 +2,11 @@
package auth
import (
"context"
"errors"
"time"
)
const (
// BearerScheme used for Authorization header
BearerScheme = "Bearer "
// ScopePublic is the scope applied to a rule to allow access to the public
ScopePublic = ""
// 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
type Account struct {
// ID of the account e.g. email
// ID of the account e.g. UUID. Should not change
ID string `json:"id"`
// Type of the account, e.g. service
Type string `json:"type"`
@@ -61,6 +58,8 @@ type Account struct {
Scopes []string `json:"scopes"`
// Secret for the account, e.g. the password
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
@@ -115,19 +114,3 @@ type Rule struct {
// rule will be applied
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)
}

View File

@@ -5,9 +5,9 @@ import (
"sync"
"time"
"github.com/micro/go-micro/v3/auth"
"github.com/micro/go-micro/v3/util/token"
"github.com/micro/go-micro/v3/util/token/jwt"
"github.com/asim/go-micro/v3/auth"
"github.com/asim/go-micro/v3/util/token"
"github.com/asim/go-micro/v3/util/token/jwt"
)
// 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 {
options.Issuer = j.Options().Issuer
}
name := options.Name
if name == "" {
name = id
}
account := &auth.Account{
ID: id,
Type: options.Type,
Scopes: options.Scopes,
Metadata: options.Metadata,
Issuer: options.Issuer,
Name: name,
}
// generate a JWT secret which can be provided to the Token() method

View File

@@ -1,8 +1,8 @@
package noop
import (
"github.com/asim/go-micro/v3/auth"
"github.com/google/uuid"
"github.com/micro/go-micro/v3/auth"
)
func NewAuth(opts ...auth.Option) auth.Auth {
@@ -40,13 +40,17 @@ func (n *noop) Options() auth.Options {
// Generate a new account
func (n *noop) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
options := auth.NewGenerateOptions(opts...)
name := options.Name
if name == "" {
name = id
}
return &auth.Account{
ID: id,
Secret: options.Secret,
Metadata: options.Metadata,
Scopes: options.Scopes,
Issuer: n.Options().Issuer,
Name: name,
}, nil
}

View File

@@ -4,7 +4,7 @@ import (
"context"
"time"
"github.com/micro/go-micro/v3/store"
"github.com/asim/go-micro/v3/store"
)
func NewOptions(opts ...Option) Options {
@@ -110,6 +110,8 @@ type GenerateOptions struct {
Secret string
// Issuer of the account, e.g. micro
Issuer string
// Name of the acouunt e.g. an email or username
Name string
}
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
func NewGenerateOptions(opts ...GenerateOption) GenerateOptions {
var options GenerateOptions

View File

@@ -17,16 +17,16 @@ import (
"sync"
"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/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"
)
@@ -283,7 +283,7 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) {
b, err := ioutil.ReadAll(req.Body)
if err != nil {
errr := merr.InternalServerError("go.micro.broker", "Error reading request body: %v", err)
w.WriteHeader(500)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(errr.Error()))
return
}
@@ -291,7 +291,7 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) {
var msg *broker.Message
if err = h.opts.Codec.Unmarshal(b, &msg); err != nil {
errr := merr.InternalServerError("go.micro.broker", "Error parsing request body: %v", err)
w.WriteHeader(500)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(errr.Error()))
return
}
@@ -300,7 +300,7 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if len(topic) == 0 {
errr := merr.InternalServerError("go.micro.broker", "Topic not found")
w.WriteHeader(500)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(errr.Error()))
return
}

View File

@@ -5,10 +5,10 @@ import (
"testing"
"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/micro/go-micro/v3/broker"
"github.com/micro/go-micro/v3/registry"
"github.com/micro/go-micro/v3/registry/memory"
)
var (

View File

@@ -4,7 +4,7 @@ import (
"context"
"net/http"
"github.com/micro/go-micro/v3/broker"
"github.com/asim/go-micro/v3/broker"
)
// Handle registers the handler for the given pattern.

View File

@@ -8,10 +8,10 @@ import (
"sync"
"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/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 {

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"testing"
"github.com/micro/go-micro/v3/broker"
"github.com/asim/go-micro/v3/broker"
)
func TestMemoryBroker(t *testing.T) {

View File

@@ -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)
}
}

View File

@@ -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
}

View File

@@ -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)
}
}
})
}
}

View File

@@ -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{}{})
}

View File

@@ -4,8 +4,8 @@ import (
"context"
"crypto/tls"
"github.com/micro/go-micro/v3/codec"
"github.com/micro/go-micro/v3/registry"
"github.com/asim/go-micro/v3/codec"
"github.com/asim/go-micro/v3/registry"
)
type Options struct {

View File

@@ -4,13 +4,17 @@ package build
// Build is an interface for building packages
type Build interface {
// Package builds a package
Package(name string, src *Source) (*Package, error)
Package(*Source) (*Package, error)
// Remove removes the package
Remove(*Package) error
// Implementation of build
String() string
}
// Source is the source of a build
type Source struct {
// Name of the source
Name string
// Path to the source if local
Path string
// Language is the language of code

View File

@@ -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,
}
}

View File

@@ -6,7 +6,7 @@ import (
"os/exec"
"path/filepath"
"github.com/micro/go-micro/v3/build"
"github.com/asim/go-micro/v3/build"
)
type goBuild struct {
@@ -34,7 +34,8 @@ func whichGo() string {
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)
source := src.Path

View File

@@ -5,12 +5,13 @@ import (
"os"
"path/filepath"
"github.com/micro/go-micro/v3/build"
"github.com/asim/go-micro/v3/build"
)
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"
// path to the tarball
path := filepath.Join(os.TempDir(), src.Path, pkg)

View File

@@ -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...),
}
}

View File

@@ -4,8 +4,8 @@ package memory
import (
"sync"
"github.com/micro/go-micro/v3/cache"
"github.com/micro/go-micro/v3/errors"
"github.com/asim/go-micro/v3/cache"
"github.com/asim/go-micro/v3/errors"
)
type memoryCache struct {

View File

@@ -4,7 +4,7 @@ import (
"context"
"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)

View File

@@ -4,6 +4,8 @@ import (
"context"
"testing"
"time"
"github.com/asim/go-micro/v3/codec"
)
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
}

View File

@@ -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))
}

View File

@@ -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")
}
})
}

View File

@@ -5,7 +5,7 @@ import (
"context"
"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.

View File

@@ -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)
}

View File

@@ -1,6 +1,6 @@
# 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
@@ -12,7 +12,7 @@ Specify the client to your micro service
```go
import (
"github.com/micro/go-micro"
"github.com/asim/go-micro"
"github.com/micro/go-plugins/client/grpc"
)

View File

@@ -7,10 +7,10 @@ import (
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/proto"
"github.com/micro/go-micro/v3/codec"
"github.com/micro/go-micro/v3/codec/bytes"
"github.com/oxtoacart/bpool"
"google.golang.org/grpc"
"google.golang.org/grpc/encoding"

View File

@@ -1,7 +1,7 @@
package grpc
import (
"github.com/micro/go-micro/v3/errors"
"github.com/asim/go-micro/v3/errors"
"google.golang.org/grpc/status"
)

View File

@@ -11,11 +11,11 @@ import (
"sync/atomic"
"time"
"github.com/micro/go-micro/v3/broker"
"github.com/micro/go-micro/v3/client"
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/asim/go-micro/v3/broker"
"github.com/asim/go-micro/v3/client"
raw "github.com/asim/go-micro/v3/codec/bytes"
"github.com/asim/go-micro/v3/errors"
"github.com/asim/go-micro/v3/metadata"
"google.golang.org/grpc"
"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())
}
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}
grpcDialOptions := []grpc.DialOption{
@@ -192,7 +183,7 @@ func (g *grpcClient) stream(ctx context.Context, addr string, req client.Request
grpcDialOptions = append(grpcDialOptions, opts...)
}
cc, err := grpc.DialContext(dialCtx, addr, grpcDialOptions...)
cc, err := g.pool.getConn(addr, grpcDialOptions...)
if err != nil {
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...)
}
// create a new cancelling context
newCtx, cancel := context.WithCancel(ctx)
var cancel context.CancelFunc
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 {
// we need to cleanup as we dialled and created a context
// cancel the context
cancel()
// close the connection
cc.Close()
// release the connection
g.pool.release(addr, cc, err)
// now return the error
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,
gcodec: codec,
},
conn: cc,
cancel: cancel,
conn: cc,
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

View File

@@ -5,12 +5,12 @@ import (
"net"
"testing"
"github.com/micro/go-micro/v3/client"
"github.com/micro/go-micro/v3/errors"
"github.com/micro/go-micro/v3/registry"
"github.com/micro/go-micro/v3/registry/memory"
"github.com/micro/go-micro/v3/router"
regRouter "github.com/micro/go-micro/v3/router/registry"
"github.com/asim/go-micro/v3/client"
"github.com/asim/go-micro/v3/errors"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/registry/memory"
"github.com/asim/go-micro/v3/router"
regRouter "github.com/asim/go-micro/v3/router/registry"
pgrpc "google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)

View File

@@ -1,7 +1,7 @@
package grpc
import (
"github.com/micro/go-micro/v3/client"
"github.com/asim/go-micro/v3/client"
)
type grpcEvent struct {

View File

@@ -5,7 +5,7 @@ import (
"context"
"crypto/tls"
"github.com/micro/go-micro/v3/client"
"github.com/asim/go-micro/v3/client"
"google.golang.org/grpc"
"google.golang.org/grpc/encoding"
)

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"strings"
"github.com/micro/go-micro/v3/client"
"github.com/micro/go-micro/v3/codec"
"github.com/asim/go-micro/v3/client"
"github.com/asim/go-micro/v3/codec"
)
type grpcRequest struct {

View File

@@ -3,14 +3,14 @@ package grpc
import (
"strings"
"github.com/micro/go-micro/v3/codec"
"github.com/micro/go-micro/v3/codec/bytes"
"github.com/asim/go-micro/v3/codec"
"github.com/asim/go-micro/v3/codec/bytes"
"google.golang.org/grpc"
"google.golang.org/grpc/encoding"
)
type response struct {
conn *grpc.ClientConn
conn *poolConn
stream grpc.ClientStream
codec encoding.Codec
gcodec codec.Codec

View File

@@ -5,7 +5,7 @@ import (
"io"
"sync"
"github.com/micro/go-micro/v3/client"
"github.com/asim/go-micro/v3/client"
"google.golang.org/grpc"
)
@@ -17,11 +17,11 @@ type grpcStream struct {
sync.RWMutex
closed bool
err error
conn *grpc.ClientConn
conn *poolConn
request client.Request
response client.Response
context context.Context
cancel func()
close func(err error)
}
func (g *grpcStream) Context() context.Context {
@@ -86,9 +86,9 @@ func (g *grpcStream) Close() error {
if g.closed {
return nil
}
// cancel the context
g.cancel()
// close the connection
g.closed = true
g.ClientStream.CloseSend()
return g.conn.Close()
g.close(g.err)
return g.ClientStream.CloseSend()
}

View File

@@ -4,8 +4,8 @@ import (
"context"
"sort"
"github.com/micro/go-micro/v3/errors"
"github.com/micro/go-micro/v3/router"
"github.com/asim/go-micro/v3/errors"
"github.com/asim/go-micro/v3/router"
)
// 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
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
// own network, which is set during initialisation.
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
routes, err := opts.Router.Lookup(query...)
routes, err := opts.Router.Lookup(req.Service(), query...)
if err == router.ErrRouteNotFound {
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", req.Service(), err.Error())
} else if err != nil {

View File

@@ -1,7 +1,7 @@
package mucp
import (
"github.com/micro/go-micro/v3/registry"
"github.com/asim/go-micro/v3/registry"
)
var (

View File

@@ -1,4 +1,4 @@
// Package mucp provides an mucp client
// Package mucp provides a transport agnostic RPC client
package mucp
import (
@@ -7,16 +7,16 @@ import (
"sync/atomic"
"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/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 {

View File

@@ -4,16 +4,16 @@ import (
"bytes"
errs "errors"
"github.com/micro/go-micro/v3/codec"
raw "github.com/micro/go-micro/v3/codec/bytes"
"github.com/micro/go-micro/v3/codec/grpc"
"github.com/micro/go-micro/v3/codec/json"
"github.com/micro/go-micro/v3/codec/jsonrpc"
"github.com/micro/go-micro/v3/codec/proto"
"github.com/micro/go-micro/v3/codec/protorpc"
"github.com/micro/go-micro/v3/errors"
"github.com/micro/go-micro/v3/registry"
"github.com/micro/go-micro/v3/transport"
"github.com/asim/go-micro/v3/codec"
raw "github.com/asim/go-micro/v3/codec/bytes"
"github.com/asim/go-micro/v3/codec/grpc"
"github.com/asim/go-micro/v3/codec/json"
"github.com/asim/go-micro/v3/codec/jsonrpc"
"github.com/asim/go-micro/v3/codec/proto"
"github.com/asim/go-micro/v3/codec/protorpc"
"github.com/asim/go-micro/v3/errors"
"github.com/asim/go-micro/v3/network/transport"
"github.com/asim/go-micro/v3/registry"
)
const (

View File

@@ -1,7 +1,7 @@
package mucp
import (
"github.com/micro/go-micro/v3/client"
"github.com/asim/go-micro/v3/client"
)
type message struct {

View File

@@ -1,8 +1,8 @@
package mucp
import (
"github.com/micro/go-micro/v3/client"
"github.com/micro/go-micro/v3/codec"
"github.com/asim/go-micro/v3/client"
"github.com/asim/go-micro/v3/codec"
)
type rpcRequest struct {

View File

@@ -3,7 +3,7 @@ package mucp
import (
"testing"
"github.com/micro/go-micro/v3/client"
"github.com/asim/go-micro/v3/client"
)
func TestRequestOptions(t *testing.T) {

View File

@@ -1,8 +1,8 @@
package mucp
import (
"github.com/micro/go-micro/v3/codec"
"github.com/micro/go-micro/v3/transport"
"github.com/asim/go-micro/v3/codec"
"github.com/asim/go-micro/v3/network/transport"
)
type rpcResponse struct {

View File

@@ -5,8 +5,8 @@ import (
"io"
"sync"
"github.com/micro/go-micro/v3/client"
"github.com/micro/go-micro/v3/codec"
"github.com/asim/go-micro/v3/client"
"github.com/asim/go-micro/v3/codec"
)
// Implements the streamer interface

View File

@@ -5,12 +5,12 @@ import (
"fmt"
"testing"
"github.com/micro/go-micro/v3/client"
"github.com/micro/go-micro/v3/errors"
"github.com/micro/go-micro/v3/registry"
"github.com/micro/go-micro/v3/registry/memory"
"github.com/micro/go-micro/v3/router"
regRouter "github.com/micro/go-micro/v3/router/registry"
"github.com/asim/go-micro/v3/client"
"github.com/asim/go-micro/v3/errors"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/registry/memory"
"github.com/asim/go-micro/v3/router"
regRouter "github.com/asim/go-micro/v3/router/registry"
)
func newTestRouter() router.Router {

View File

@@ -4,8 +4,8 @@ import (
"testing"
"time"
"github.com/micro/go-micro/v3/client"
"github.com/micro/go-micro/v3/transport"
"github.com/asim/go-micro/v3/client"
"github.com/asim/go-micro/v3/network/transport"
)
func TestCallOptions(t *testing.T) {

View File

@@ -4,16 +4,16 @@ import (
"context"
"time"
"github.com/micro/go-micro/v3/broker"
"github.com/micro/go-micro/v3/broker/http"
"github.com/micro/go-micro/v3/codec"
"github.com/micro/go-micro/v3/registry"
"github.com/micro/go-micro/v3/router"
regRouter "github.com/micro/go-micro/v3/router/registry"
"github.com/micro/go-micro/v3/selector"
"github.com/micro/go-micro/v3/selector/random"
"github.com/micro/go-micro/v3/transport"
thttp "github.com/micro/go-micro/v3/transport/http"
"github.com/asim/go-micro/v3/broker"
"github.com/asim/go-micro/v3/broker/http"
"github.com/asim/go-micro/v3/codec"
"github.com/asim/go-micro/v3/network/transport"
thttp "github.com/asim/go-micro/v3/network/transport/http"
"github.com/asim/go-micro/v3/registry"
"github.com/asim/go-micro/v3/router"
regRouter "github.com/asim/go-micro/v3/router/registry"
"github.com/asim/go-micro/v3/selector"
"github.com/asim/go-micro/v3/selector/roundrobin"
)
type Options struct {
@@ -36,9 +36,6 @@ type Options struct {
PoolSize int
PoolTTL time.Duration
// Response cache
Cache *Cache
// Middleware for client
Wrappers []Wrapper
@@ -55,8 +52,6 @@ type CallOptions struct {
Address []string
// Backoff func
Backoff BackoffFunc
// Duration to cache the response for
CacheExpiry time.Duration
// Transport Dial Timeout
DialTimeout time.Duration
// Number of Call attempts
@@ -109,7 +104,6 @@ type RequestOptions struct {
func NewOptions(options ...Option) Options {
opts := Options{
Cache: NewCache(),
Context: context.Background(),
ContentType: "application/protobuf",
Codecs: make(map[string]codec.NewCodec),
@@ -125,7 +119,7 @@ func NewOptions(options ...Option) Options {
PoolTTL: DefaultPoolTTL,
Broker: http.NewBroker(),
Router: regRouter.NewRouter(),
Selector: random.NewSelector(),
Selector: roundrobin.NewSelector(),
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
func WithNetwork(n string) CallOption {
return func(o *CallOptions) {

View File

@@ -2,8 +2,9 @@ package client
import (
"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
@@ -27,7 +28,7 @@ func RetryOnError(ctx context.Context, req Request, retryCount int, err error) (
switch e.Code {
// retry on timeout or internal server error
case 408, 500:
case http.StatusRequestTimeout, http.StatusInternalServerError:
return true, nil
default:
return false, nil

View File

@@ -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