Compare commits
121 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b884a68347 | |||
| bfcdfc3c7f | |||
| 392610022a | |||
| 34a51c9f29 | |||
| a5fb3fab66 | |||
| 96576a612a | |||
| 87c96bc4d0 | |||
| 65a2e4ed02 | |||
| 9960cd1d36 | |||
| 107bd74187 | |||
| 7a6a2b6373 | |||
| cf51ddeb26 | |||
| 13b76331ec | |||
| de0b456b46 | |||
| 072547201c | |||
| 8293988499 | |||
| 367771923c | |||
| 4ca75f3ab3 | |||
| 4a7c16419e | |||
| 1d396bdd64 | |||
| ca807e36c5 | |||
| cce02927e7 | |||
| 034ba9a0de | |||
| 1919048c8f | |||
| 62c2981baf | |||
| efa2c4f2d2 | |||
| 27b98c450e | |||
| e8604f065c | |||
| aaca7c27da | |||
| 664ee31b1a | |||
| 6dedee5d8c | |||
| d1806e2883 | |||
| 1f086a3002 | |||
| 73eda3346d | |||
| c6d352c832 | |||
| 356448017f | |||
| d6a74c1a8e | |||
| e5a35d38f9 | |||
| a2f6fac852 | |||
| dca3a3b553 | |||
| 4154ed6a80 | |||
| 69b4b5d1c6 | |||
| d47c2d984b | |||
| 91cfd18373 | |||
| 9e0be6c85d | |||
| 23f1de80c5 | |||
| 6bc97c16ee | |||
| a612e09a34 | |||
| 1e2d197c7d | |||
| 3a999a0db6 | |||
| b8c2eb2b28 | |||
| 6f15174a2f | |||
| 748fb39cac | |||
| 5f2251cfad | |||
| ef7528ebdb | |||
| 696a0ba714 | |||
| 267da35259 | |||
| d152870bdb | |||
| da41ab146e | |||
| 757d0fe343 | |||
| c8d94c44f0 | |||
| 5fa6e89f4f | |||
| 85f1c44000 | |||
| 3ba69f11ff | |||
| af5e70a1d6 | |||
| 5fe884e59f | |||
| 415016c6e4 | |||
| e0de23c546 | |||
| 7af0eb4b7a | |||
| 8e52761edb | |||
| 37de747d19 | |||
| a40f6e8fae | |||
| b00c8368b9 | |||
| 97f169c424 | |||
| 81244a41f1 | |||
| 229b369702 | |||
| c0e0b2b225 | |||
| 1e4dd94b71 | |||
| b25d744f5c | |||
| 685f9979a1 | |||
| 6fc5e45626 | |||
| 2c6515152a | |||
| 70d2bd8a6b | |||
| 90b3e4af0b | |||
| 4f1a571704 | |||
| 799b8d6a65 | |||
| 8e312801a1 | |||
| 335c4e54a1 | |||
| e6d17257b0 | |||
| 0c2041e439 | |||
| c5be9f560c | |||
| 62b985f49c | |||
| 2b9a6f9aeb | |||
| 3c70d23a1d | |||
| adaa98e6cf | |||
| ed90a65783 | |||
| 268278c53e | |||
| 5d5aee1f08 | |||
| ed690ed838 | |||
| e155029a4b | |||
| 880d751df4 | |||
| a3202b00ee | |||
| efcda9a48c | |||
| 2c73c7fcf3 | |||
| d2a51d05c4 | |||
| af3cfa0a4c | |||
| f96b48dad9 | |||
| 9edc569e68 | |||
| 29fefbad4e | |||
| 9f4770e7fd | |||
| e7dbda689e | |||
| 00f461141a | |||
| 8cad88edae | |||
| 62801c3d68 | |||
| 7136c61dbd | |||
| a87f9a808c | |||
| ca594b922c | |||
| aa4a87ed9a | |||
| 690facdb5c | |||
| f63e46a7d1 | |||
| 1cd7cfaa6c |
@@ -8,10 +8,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.15
|
||||
- name: Set up Go 1.17
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.15
|
||||
go-version: 1.17
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
|
||||
@@ -8,10 +8,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.15
|
||||
- name: Set up Go 1.17
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.15
|
||||
go-version: 1.17
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
|
||||
+774
@@ -0,0 +1,774 @@
|
||||
# 4.7.0 (2022/05/19)
|
||||
|
||||
### Features
|
||||
|
||||
- remove unused variable in loop (#2495)
|
||||
- option to disable file watcher (#2485)
|
||||
- Support direct generation of grpc method (#2474)
|
||||
- remove cli
|
||||
- remove dashboard
|
||||
- Remove examples
|
||||
- Add header suppor for Kafka broker plugin; (#2470)
|
||||
- Fix codec/bytes (#2466)
|
||||
- Add Wait option support for sync/etcd plugins (#2459)
|
||||
- #2453 Fix with associated test update (#2454)
|
||||
- style:arrays pre-allocation (#2449)
|
||||
- Bump github.com/nats-io/nats-server/v2 in /plugins/events/natsjs (#2447)
|
||||
- add NATS JetStream events plugin (#2433)
|
||||
- add tls option for sync etcd plugin (#2440)
|
||||
- add new services
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fix: consume and publish blocked after rabbitmq reconnecting (#2492)
|
||||
- typo fix; (#2480)
|
||||
- fix https://github.com/asim/go-micro/issues/2344 (#2462)
|
||||
- fix natsjs syntax error, remove TODOs and enable tests (#2446)
|
||||
- http transport deadlock (#2441)
|
||||
- Support for `-micro_out=module=<module_prefix>` for protoc-gen-micro (#2435)
|
||||
|
||||
# 4.6.0 (2022/02/08)
|
||||
|
||||
### Features
|
||||
|
||||
- add service updates (#2418)
|
||||
- Add files via upload
|
||||
- default the content type to json (#2412)
|
||||
- Add Kafka asynchronous send support (#2409)
|
||||
- use read lock and unlock instead of write ones (#2410)
|
||||
- move the api client
|
||||
- Update client_test.go
|
||||
- switch services client
|
||||
- remove the client
|
||||
- add service interfaces
|
||||
- [FEATURE] add changelog (#2400)
|
||||
- nats config plugin (#2397)
|
||||
- Update and rename m3o.go to services.go
|
||||
- Update services/ (#2392)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fix client
|
||||
- fix context value nil (#2391)
|
||||
|
||||
# 4.5.0 (2021/12/19)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- nats deregister issue (#2384)
|
||||
- fixing f.IsExported undefined issue (#2382)
|
||||
- fix http_transport Recv and Close race condition on buff (#2374)
|
||||
- update protoc-gen-micro install doc
|
||||
- zookeeper registry delete event (#2372)
|
||||
- delete redundant lines (#2364)
|
||||
- modify the dependencies urls (#2363)
|
||||
- ignore unexported field (#2354)
|
||||
- Fix Micro CLI's proto comments (#2353)
|
||||
|
||||
### Features
|
||||
|
||||
- Extend client mock with ability to test publish, and a few useful method like SetResponse and SetSubscriber (#2375)
|
||||
- go micro dashboard (#2361)
|
||||
|
||||
# 4.4.0 (2021/11/11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fix(#2333): etcd grpc marshal issue (#2334)
|
||||
|
||||
### Features
|
||||
|
||||
- upgrade to go 1.17 (#2346)
|
||||
- add nats and redis events plugins
|
||||
- add events package (#2341)
|
||||
|
||||
# 4.3.0 (2021/11/01)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- flatten cli (#2332)
|
||||
- m3o client changed
|
||||
- use vanity url for cli command
|
||||
- fix broker nsq plugin nil pointer error (#2329)
|
||||
- fix config json slice parsing (#2330)
|
||||
- replace ioutil with io and os (#2327)
|
||||
- fixing #2308 (#2326)
|
||||
- Fix Micro CLI by removing replace line in go.mod
|
||||
- remove unnecessary dependencies between plugins
|
||||
- 1. use default memory registry in grpc plugins (#2317)
|
||||
- Add update rule to Makefile (#2315)
|
||||
- Plugins (#2311)
|
||||
|
||||
### Features
|
||||
|
||||
- Rename gomu to micro (#2325)
|
||||
- stream CloseSend (#2323)
|
||||
- strip protoc-gen-micro go mod
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- go install go-micro.dev/v4/cmd/micro@v4
|
||||
- go install go-micro.dev/v4/cmd/protoc-gen-micro@v4
|
||||
- upgrade go micro to support stream.CloseSend
|
||||
|
||||
# 4.2.1 (2021/10/14)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fix gomu.
|
||||
|
||||
# 4.2.0 (2021/10/13)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- fix examples go mod.
|
||||
- update go sums.
|
||||
- move to go-micro.dev.
|
||||
- upgrade protoc-gen-micro to v4.
|
||||
|
||||
# 4.1.0 (2021/10/12)
|
||||
|
||||
- v4.1.0.
|
||||
|
||||
# 4.0.0 (2021/10/12)
|
||||
|
||||
### Features
|
||||
|
||||
- Vanity URL go-micro.dev([#2271](https://github.com/asim/go-micro/issues/2271)).
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- upgrade github.com/asim/go-micro/v3 to go-micro.dev/v4.
|
||||
|
||||
# 3.7.0 (2021/10/11)
|
||||
|
||||
- Add latest version (#2303).
|
||||
|
||||
# 3.6.0 (2021/08/23)
|
||||
|
||||
- Minor fixes https://github.com/asim/go-micro/compare/v3.5.2...c7195aae9817db4eaf5483990fcb8706f86d3002.
|
||||
|
||||
# 3.5.2 (2021/07/06)
|
||||
|
||||
- Tag it and bag it.
|
||||
|
||||
# 3.5.1 (2021/04/20)
|
||||
|
||||
- Minor bug fixes.
|
||||
|
||||
# 3.5.0 (2021/01/29)
|
||||
|
||||
- kill the bugs.
|
||||
|
||||
# 3.0.1 (2021/01/20)
|
||||
|
||||
- Tag with protoc changes.
|
||||
|
||||
# 3.0.0 (2021/01/20)
|
||||
|
||||
- V3.
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- upgrade github.com/micro/go-micro/v2 to github.com/asim/go-micro/v3.
|
||||
- change default transport from gRPC to mucp, using grpc server/client plugins.
|
||||
|
||||
# 3.0.0-beta.3 (2020/09/29)
|
||||
|
||||
- Secret implementation of config. Supporting config merge (#2027)
|
||||
- remove transport options
|
||||
- read service package (#2026)
|
||||
- env config implementation (#2024)
|
||||
- runtime: remove builder package (moved to micro) (#2023)
|
||||
- Fix branch names support for k8s runtime (#2020)
|
||||
- fix config bug (#2021)
|
||||
- runtime: minor fixes for local runtime (#2019)
|
||||
- remove memcache and update gomod
|
||||
- Add errors to config methods (#2015)
|
||||
- store/file: fix segmentation violation bug (#2013)
|
||||
- Config interface change (#2010)
|
||||
- proxy/grpc: fix client streaming bug (EOF not sent to the server) (#2011)
|
||||
- client/grpc: fix stream closed bug (#2009)
|
||||
- store/file: don't keep connection to boltdb open (#2006)
|
||||
- runtime/builder with golang implementation (#2003)
|
||||
- store: implement s3 blob store (#2005)
|
||||
- store: add blob interface with file implementation (#2004)
|
||||
- auth: remove micro specific code (#1999)
|
||||
- Fix running subfolders (#1998)
|
||||
- api: fix request body re-sequencing bug (#1996)
|
||||
- add Name to auth.Account as a user friendly alias (#1992)
|
||||
- Fixing top level run outside repo (#1993)
|
||||
- runtime: normalised service statuses (#1994)
|
||||
- Add 'Namespace' header to allowed CORS headers (#1990)
|
||||
- Remove all the external plugins except grpc (#1988)
|
||||
- util/kubernetes: fix TCPSocketAction bug (#1987)
|
||||
- Fixing the metric tagging issue here (#1986).
|
||||
|
||||
# 3.0.0-beta.2 (2020/09/05)
|
||||
|
||||
- Cut a v3 beta 2.
|
||||
|
||||
# 3.0.0-beta (2020/08/12)
|
||||
|
||||
- write nil when expiry is zero.
|
||||
|
||||
# 3.0.0-alpha (2020/07/27)
|
||||
|
||||
- v3 refactor (#1868).
|
||||
|
||||
# 2.9.1 (2020/07/03)
|
||||
|
||||
- push tags to docker hub (#1766).
|
||||
|
||||
# 2.9.0 (2020/06/12)
|
||||
|
||||
- Fix regex detection. Fixes #1663 (#1696).
|
||||
|
||||
# 2.9.0-rc5 (2020/06/11)
|
||||
|
||||
- Merge branch 'master' into release-2.9.0.
|
||||
|
||||
# 2.9.0-rc4 (2020/06/11)
|
||||
|
||||
- Merge branch 'master' into release-2.9.0.
|
||||
|
||||
# 2.9.0-rc1 (2020/06/11)
|
||||
|
||||
- Merge branch 'master' into release-2.9.0.
|
||||
|
||||
# 2.8.0 (2020/05/31)
|
||||
|
||||
- Rewrite Auth interface to use Rules
|
||||
- Add Cache interface into the Client for request caching
|
||||
- Fix atomic sequence updates in Client
|
||||
- Update go mod deps
|
||||
- Fix ipv6 parsing in mdns registry
|
||||
- Add namespacing to the default runtime
|
||||
- Replace go-git with v5
|
||||
- Increase register ttl to 90 seconds.
|
||||
|
||||
# 2.7.0 (2020/05/18)
|
||||
|
||||
- Fix the rpc handler json rpc body parsing
|
||||
- Use caddyserver/certmagic instead of mholt
|
||||
- Add HasRole to Account
|
||||
- Add jwt refresh token generation
|
||||
- Fix rpc stream close locking race
|
||||
- Add auth namespace env var
|
||||
- Strip the router penalty code
|
||||
- Add file upload util
|
||||
- Fix killing processes in runtime
|
||||
- Pass namespace to runtime commands
|
||||
- Generate account on start
|
||||
- Check errors in cockroachdb.
|
||||
|
||||
# 2.6.0 (2020/05/04)
|
||||
|
||||
- Fix discord bot authentication header
|
||||
- Improve api rpc regexp matching
|
||||
- Change auth account access via context
|
||||
- Create a jwt implementation of auth
|
||||
- Fix grpc content-type encoding bug
|
||||
- Consolidate proxy/network env var logic
|
||||
- Change secrets interface naming
|
||||
- Log file path in the logger
|
||||
- Change location of network resolver
|
||||
- Add Store to service options
|
||||
- Fix default runtime log parsing
|
||||
- Add namespace checks to k8s runtime
|
||||
- Add proper git checkout in local runtime
|
||||
- Add database/table options for store
|
||||
- Add pki implementation
|
||||
- Import qson.
|
||||
|
||||
# 2.5.0 (2020/04/15)
|
||||
|
||||
- api/router/registry: extract path based parameters from url to req (#1530).
|
||||
|
||||
# 2.4.0 (2020/03/31)
|
||||
|
||||
- There can be only one! (#1445).
|
||||
|
||||
# 2.3.0 (2020/03/17)
|
||||
|
||||
- grpc client/server fixes (#1355).
|
||||
|
||||
# 2.2.0 (2020/02/28)
|
||||
|
||||
- Rename Auth Validate to Verify
|
||||
- Replaces noop auth with base32 generated tokens
|
||||
- Change Excludes to Exclude
|
||||
- Add token option to auth
|
||||
- Add profile option and flags for debug
|
||||
- Add config loading for auth token
|
||||
- Move before start to before listening.
|
||||
|
||||
# 2.1.2 (2020/02/24)
|
||||
|
||||
- fix router panic (#1254).
|
||||
|
||||
# 2.1.1 (2020/02/23)
|
||||
|
||||
- update go modules (#1240).
|
||||
|
||||
# 2.1.0 (2020/02/13)
|
||||
|
||||
- Exclude Stats & Trace from Auth (#1192).
|
||||
|
||||
# 2.0.0 (2020/01/30)
|
||||
|
||||
- v2 release.
|
||||
|
||||
# 1.18.0 (2019/12/08)
|
||||
|
||||
- Add golang ci linter
|
||||
- Add race detection to travis
|
||||
- Please the linter
|
||||
- Do some perf optimisations on slice alloc
|
||||
- Move http broker to use single entry in registry
|
||||
- Strip the grpc metadata filtering
|
||||
- Strip the old codec usage
|
||||
- Disable retries in client when MICRO_PROXY is enabled
|
||||
- Strip old X-Micro headers
|
||||
- Add debug/log streaming implementations
|
||||
- Add first debug/log interface
|
||||
- Huge network/tunnel refactor to fix bugs
|
||||
- Fix proxy slice allocation bug
|
||||
- Splay out some of the network events
|
||||
- Default to AdvertiseLocal for router
|
||||
- Add runtime filtering with Type
|
||||
- Remove SIGKILL processing.
|
||||
|
||||
# 1.17.1 (2019/11/27)
|
||||
|
||||
- fix rpc server go routine leak
|
||||
- add a psuedo socket pool
|
||||
- update debug buffer to return entries.
|
||||
|
||||
# 1.17.0 (2019/11/27)
|
||||
|
||||
- Add github related issue templates
|
||||
- Add Dockerfile for predownloaded go-micro source
|
||||
- Regenerate all the protos to move to \*.pb.micro.go
|
||||
- Fix api handler to parse text/plain as default content type
|
||||
- Fix event handler to allow GET requests
|
||||
- Change http broker ids to go.micro.http.broker-uuid
|
||||
- Require protocol field in metadata to query services via client
|
||||
- Process raw frames in call to Publish
|
||||
- Complete proxy support for processing messages
|
||||
- Proxy support for publishing of messages
|
||||
- Fix grpc connection leak by always closing the connection
|
||||
- Add a debug ring buffer
|
||||
- Add broker to tunnel and network
|
||||
- Force network dns resolver to use cloudflare 1.0.0.1
|
||||
- Add option to specify whether server should handle signalling
|
||||
- Change mdns request timeout to 10ms rather than 100ms
|
||||
- Add router AdvertiseNone and AdvertiseLocal strategies
|
||||
- Rename runtime packager to builder
|
||||
- Add full support for a kubernetes runtime.
|
||||
|
||||
# 1.16.0 (2019/11/09)
|
||||
|
||||
- Pre-make slices for perf optimisation
|
||||
- Add runtime flag and k8s runtime
|
||||
- Add debug/profile for pprof profiling
|
||||
- Reduce go routines in mdns registry and registry cache
|
||||
- Optimise the router flap detection.
|
||||
|
||||
# 1.15.1 (2019/11/03)
|
||||
|
||||
- Router recovery penalty should be below 500.
|
||||
|
||||
# 1.15.0 (2019/11/03)
|
||||
|
||||
- go fmt -s
|
||||
- web generate service on registration
|
||||
- downgrade some network messages to trace
|
||||
- fix tunnel panic on deleting link
|
||||
- add postgres store
|
||||
- change grpc recover logging
|
||||
- add runtime service
|
||||
- add kubernetes runtime
|
||||
- add runtime notifier
|
||||
- proxy add header based routing for Micro-{Gateway, Router, Network}
|
||||
- network hash address based on service + node id
|
||||
- metadata add mergecontext function.
|
||||
|
||||
# 1.14.0 (2019/10/25)
|
||||
|
||||
- Remove consul registry
|
||||
- Change store Sync endpoint to List
|
||||
- Remove cloudflare-go usage in store
|
||||
- Add non-backwards compatible link changes.
|
||||
|
||||
# 1.13.2 (2019/10/22)
|
||||
|
||||
- Fix proxy selection to use round robin strategy.
|
||||
|
||||
# 1.13.1 (2019/10/19)
|
||||
|
||||
- Fix divide by zero bug in broker.
|
||||
|
||||
# 1.13.0 (2019/10/18)
|
||||
|
||||
- Fix network recursive read lock bug
|
||||
- Add certmagic random pull time
|
||||
- Strip http broker topic: prefix.
|
||||
|
||||
# 1.12.0 (2019/10/17)
|
||||
|
||||
- Add ACME Provider interface
|
||||
- Implement certmagic ACME Provider
|
||||
- Add certmagic Store implementation
|
||||
- Add broker service implementation
|
||||
- Add ability to set grpc dial and call options
|
||||
- Add etcd registry and other plugins
|
||||
- Add Network.Connect rpc endpoint
|
||||
- Resolve network node dns names
|
||||
- Support Network.Routes querying
|
||||
- Fix caching registry bugs
|
||||
- Move gossip registry to go-plugins
|
||||
- Add router advertise strategy
|
||||
- Add Cloudflare store implementation
|
||||
- Add store service implementation.
|
||||
|
||||
# 1.11.3 (2019/10/12)
|
||||
|
||||
- Fix the quic-go checksum mismatch by updating to 0.12.1.
|
||||
|
||||
# 1.11.2 (2019/10/12)
|
||||
|
||||
- Fix cache error check.
|
||||
|
||||
# 1.11.1 (2019/10/07)
|
||||
|
||||
- Fix cache registry deadlocking bug.
|
||||
|
||||
# 1.11.0 (2019/10/01)
|
||||
|
||||
- This is likely the last release of v1.
|
||||
|
||||
# 1.10.0 (2019/09/11)
|
||||
|
||||
- Add grpc client code application/grpc content-type
|
||||
- Move client to use stream dialer
|
||||
- Add network implementation
|
||||
- Add dynamic plugin loading
|
||||
- Add multilink usage in proxy
|
||||
- Add registry implementation
|
||||
- Scope mdns to .micro domain
|
||||
- Support grpc server processing by default
|
||||
- Add tunnel broker.
|
||||
|
||||
# 1.9.1 (2019/08/19)
|
||||
|
||||
- Fix waitgroup race condition.
|
||||
|
||||
# 1.9.0 (2019/08/19)
|
||||
|
||||
- Fix grpc codec for broker publishing
|
||||
- Use the connection pool for streaming
|
||||
- Send EOS from client when closing stream
|
||||
- Add stream header to mucp protocol
|
||||
- Add stream multiplexing in the server
|
||||
- Fix watcher bug in file config source
|
||||
- Fix monitoring watcher to only look at mucp services
|
||||
- Only check router status on lookup failure
|
||||
- Fix proxy streaming and client request processing
|
||||
- Fix host:port processing for messaging systems
|
||||
- Add start method to the router
|
||||
- Fix router race condition for default values
|
||||
- Add loopback detection to the tunnel
|
||||
- Add connection retry logic to tunnel
|
||||
- Make log levels accessible for the logger
|
||||
- Add proxy muxer for internal calls.
|
||||
|
||||
# 1.8.3 (2019/08/12)
|
||||
|
||||
- Fix nats draining
|
||||
- More verbose selector errors to return service name
|
||||
- Move handler debug package
|
||||
- Add a monitoring package
|
||||
- Fix consul address parsing
|
||||
- Fix server extraction code
|
||||
- Add tunnel implementation
|
||||
- Add util log level
|
||||
- Add util io package to wrap transport socket.
|
||||
|
||||
# 1.8.2 (2019/08/06)
|
||||
|
||||
- Point release for micro
|
||||
- Adds travis caching
|
||||
- Removes unused network code
|
||||
- Adds tunnel interface
|
||||
- Consul agent check
|
||||
- Router handler interface
|
||||
- Non host:port fixes.
|
||||
|
||||
# 1.8.1 (2019/07/31)
|
||||
|
||||
- Use mdns 0.2.0 release tag.
|
||||
|
||||
# 1.8.0 (2019/07/29)
|
||||
|
||||
- Move the selector into client
|
||||
- Change broker.Publication to broker.Event
|
||||
- Move cmd into config
|
||||
- Enable default json processing in api
|
||||
- Remove port from registry
|
||||
- Memory broker/transport race fixes
|
||||
- GRPC codec fix
|
||||
- Client pool interface
|
||||
- Router interface/service implementations
|
||||
- Config decoding fixes
|
||||
- Memory store expiration fix
|
||||
- Network link/tunnel/resolver packages
|
||||
- Proxy router caching
|
||||
- Registry util functions.
|
||||
|
||||
# 1.7.0 (2019/06/21)
|
||||
|
||||
- Update go mod
|
||||
- Move mock data out of memory registry
|
||||
- wrap the grpc codecs to support framing
|
||||
- change grpc resolution to use service.method
|
||||
- support full proxying via grpc
|
||||
- add text codec
|
||||
- move data/store
|
||||
- add network interface
|
||||
- add router package and implementation
|
||||
- move options to config/options
|
||||
- send gossip updates on register/deregister
|
||||
- fix node add/del bug
|
||||
- add handler wrapper back into core router.
|
||||
|
||||
# 1.6.0 (2019/06/07)
|
||||
|
||||
- Massive go.mod dependency cleanup _ Moved etcd, memcache, redis sync things to go-plugins _ uuid to google uuid \* blew away go.mod
|
||||
- Add better proxy interface and features
|
||||
- Add new options interface.
|
||||
|
||||
# 1.5.0 (2019/06/05)
|
||||
|
||||
- Fix go mod issues.
|
||||
|
||||
# 1.4.0 (2019/06/04)
|
||||
|
||||
- Final consolidation of all libraries.
|
||||
|
||||
# 1.3.1 (2019/06/03)
|
||||
|
||||
- Fix broken pipe bug. Don't send message when client closed connection..
|
||||
|
||||
# 1.3.0 (2019/05/31)
|
||||
|
||||
- The great rewrite.
|
||||
|
||||
# 1.2.0 (2019/05/22)
|
||||
|
||||
- Update go mod
|
||||
- Fix mock client
|
||||
- Fix retries logic
|
||||
- Fix consul api change
|
||||
- Use consul client for watcher
|
||||
- Fix gossip data races
|
||||
- Add registry check function.
|
||||
|
||||
# 1.1.0 (2019/03/28)
|
||||
|
||||
- Update go mod
|
||||
- Fix endpoint extractor generation.
|
||||
|
||||
# 1.0.0 (2019/03/05)
|
||||
|
||||
- 1.0.0 release.
|
||||
|
||||
# 0.27.1 (2019/03/05)
|
||||
|
||||
- Fix nil consul client.
|
||||
|
||||
# 0.27.0 (2019/02/23)
|
||||
|
||||
- Remove buff check in http transport
|
||||
- Change default version to latest
|
||||
- Add exchange routing
|
||||
- Update go modules.
|
||||
|
||||
# 0.26.1 (2019/02/13)
|
||||
|
||||
- Fix gossip registry
|
||||
- Update go modules for rcache.
|
||||
|
||||
# 0.26.0 (2019/02/13)
|
||||
|
||||
- Update go modules
|
||||
- Add gossip registry rejoin
|
||||
- Move selector to rcache.
|
||||
|
||||
# 0.25.0 (2019/02/04)
|
||||
|
||||
- Add server request body.
|
||||
|
||||
# 0.24.1 (2019/02/01)
|
||||
|
||||
- Various bug fixes
|
||||
- Backwards compatible with 0.14 and older
|
||||
- Fix mdns and gossip race conditions
|
||||
- Use official h2c server
|
||||
- Enable support for MICRO_PROXY.
|
||||
|
||||
# 0.24.0 (2019/01/30)
|
||||
|
||||
- Add go mod.
|
||||
|
||||
# 0.23.0 (2019/01/29)
|
||||
|
||||
- Move headers from X-Micro to Micro
|
||||
- Remove Register/Deregister methods from server
|
||||
- Move register_interval to be internal
|
||||
- Add subscriber context option.
|
||||
|
||||
# 0.22.1 (2019/01/22)
|
||||
|
||||
- Fix broken error handling
|
||||
- now returns error from ServeRequest router.
|
||||
|
||||
# 0.22.0 (2019/01/18)
|
||||
|
||||
- Address backwards compatibility.
|
||||
|
||||
# 0.21.0 (2019/01/17)
|
||||
|
||||
- Make MDNS the default registry
|
||||
- Move mocks to be memory implementations
|
||||
- Add metadata.Copy function.
|
||||
|
||||
# 0.20.0 (2019/01/14)
|
||||
|
||||
- BREAKING CHANGES.
|
||||
|
||||
# 0.17.0 (2019/01/03)
|
||||
|
||||
- Offline inbox for http broker
|
||||
- JSON/Proto/GRPC codecs
|
||||
- HTTP proxy from environment.
|
||||
|
||||
# 0.16.0 (2018/12/29)
|
||||
|
||||
- Fix cache/gossip data race
|
||||
- Rename cache selector to registry.
|
||||
|
||||
# 0.15.1 (2018/12/18)
|
||||
|
||||
- Selector cache lookup optimization.
|
||||
|
||||
# 0.15.0 (2018/12/13)
|
||||
|
||||
- Public NewSubscribeOptions
|
||||
- http2 broker support
|
||||
- Timeout error function
|
||||
- Consul Query Options
|
||||
- Gossip registry
|
||||
- RPC Codec renaming.
|
||||
|
||||
# 0.14.1 (2018/11/22)
|
||||
|
||||
- bug fix socket headers.
|
||||
|
||||
# 0.14.0 (2018/11/21)
|
||||
|
||||
- use google uuid
|
||||
- add http handler option.
|
||||
|
||||
# 0.13.0 (2018/11/15)
|
||||
|
||||
- add local/remote ip methods
|
||||
- various linting things
|
||||
- get checks on 0 ttl
|
||||
- accept loop.
|
||||
|
||||
# 0.12.0 (2018/10/09)
|
||||
|
||||
- reorder server flag
|
||||
- atomic increment sequence
|
||||
- new error method.
|
||||
|
||||
# 0.11.0 (2018/08/24)
|
||||
|
||||
- Support Consul Connect registration
|
||||
- Add/Use Init for initialisation from cmd.
|
||||
|
||||
# 0.10.0 (2018/07/26)
|
||||
|
||||
- Fix broker locking
|
||||
- Add RetryOnError as default retry policy
|
||||
- Fix mock client reflection
|
||||
- Support dialtimeout only above 0
|
||||
- Add verbose client errors
|
||||
- Allow client retries to be 0.
|
||||
|
||||
# 0.9.0 (2018/06/09)
|
||||
|
||||
- Reset server address on shutdown
|
||||
- Set default pool size to 1
|
||||
- Support reinitialising connection pool
|
||||
- Set retries to 1 by default
|
||||
- Return error for subscribers.
|
||||
|
||||
# 0.8.0 (2018/04/20)
|
||||
|
||||
- Rework of interfaces.
|
||||
|
||||
# 0.7.0 (2018/04/10)
|
||||
|
||||
- Move misc to util package
|
||||
- Add register ttl and interval flags
|
||||
- Fix protoc-gen-micro example.
|
||||
|
||||
# 0.6.0 (2018/04/05)
|
||||
|
||||
- Add consul TCP check
|
||||
- Atomic increment rpc stream sequence.
|
||||
|
||||
# 0.5.0 (2018/03/04)
|
||||
|
||||
- Support consul services without version
|
||||
- Switch to stdlib context.
|
||||
|
||||
# 0.4.0 (2018/02/19)
|
||||
|
||||
- Add WatchOption which allows filtering by service
|
||||
- Add Options method to registry
|
||||
- Add Conflict error
|
||||
- Only watch selected services in cache.
|
||||
|
||||
# 0.3.0 (2018/01/02)
|
||||
|
||||
- https support for consul
|
||||
- subscriber deadlock fix
|
||||
- selector top level option.
|
||||
|
||||
# 0.2.0 (2017/10/29)
|
||||
|
||||
- Performance improvements.
|
||||
|
||||
# 0.1.4 (2017/09/04)
|
||||
|
||||
- sort handler/subscriber endpoints
|
||||
- pass options to new subscriber.
|
||||
|
||||
# 0.1.3 (2017/08/15)
|
||||
|
||||
- Bug fix nil consul http client.
|
||||
|
||||
# 0.1.2 (2017/07/20)
|
||||
|
||||
- respond when codec errors out.
|
||||
|
||||
# 0.1.1 (2017/06/12)
|
||||
|
||||
- Fix potential panic/waitgroup bug.
|
||||
|
||||
# 0.1.0 (2017/06/12)
|
||||
|
||||
- Initial release.
|
||||
@@ -1,57 +1,61 @@
|
||||
# Go Micro [](https://opensource.org/licenses/Apache-2.0) [](https://pkg.go.dev/github.com/asim/go-micro/v3?tab=doc)
|
||||
# Go Micro [](https://opensource.org/licenses/Apache-2.0) [](https://pkg.go.dev/go-micro.dev/v4?tab=doc) [](https://github.com/go-micro)
|
||||
|
||||
|
||||
Go Micro is a framework for distributed systems development.
|
||||
|
||||
## Overview
|
||||
|
||||
Go Micro provides the core requirements for distributed systems development including RPC and Event driven communication.
|
||||
The **Micro** philosophy is sane defaults with a pluggable architecture. We provide defaults to get you started quickly
|
||||
but everything can be easily swapped out.
|
||||
Go Micro provides the core requirements for distributed systems development including RPC and Event driven communication.
|
||||
The Go Micro philosophy is sane defaults with a pluggable architecture. We provide defaults to get you started quickly
|
||||
but everything can be easily swapped out.
|
||||
|
||||
## Features
|
||||
|
||||
Go Micro abstracts away the details of distributed systems. Here are the main features.
|
||||
|
||||
- **Authentication** - Auth is built in as a first class citizen. Authentication and authorization enable secure
|
||||
zero trust networking by providing every service an identity and certificates. This additionally includes rule
|
||||
based access control.
|
||||
- **Authentication** - Auth is built in as a first class citizen. Authentication and authorization enable secure
|
||||
zero trust networking by providing every service an identity and certificates. This additionally includes rule
|
||||
based access control.
|
||||
|
||||
- **Dynamic Config** - Load and hot reload dynamic config from anywhere. The config interface provides a way to load application
|
||||
level config from any source such as env vars, file, etcd. You can merge the sources and even define fallbacks.
|
||||
- **Dynamic Config** - Load and hot reload dynamic config from anywhere. The config interface provides a way to load application
|
||||
level config from any source such as env vars, file, etcd. You can merge the sources and even define fallbacks.
|
||||
|
||||
- **Data Storage** - A simple data store interface to read, write and delete records. It includes support for memory, file and
|
||||
CockroachDB by default. State and persistence becomes a core requirement beyond prototyping and Micro looks to build that into the framework.
|
||||
- **Data Storage** - A simple data store interface to read, write and delete records. It includes support for memory, file and
|
||||
CockroachDB by default. State and persistence becomes a core requirement beyond prototyping and Micro looks to build that into the framework.
|
||||
|
||||
- **Service Discovery** - Automatic service registration and name resolution. Service discovery is at the core of micro service
|
||||
development. When service A needs to speak to service B it needs the location of that service. The default discovery mechanism is
|
||||
multicast DNS (mdns), a zeroconf system.
|
||||
- **Service Discovery** - Automatic service registration and name resolution. Service discovery is at the core of micro service
|
||||
development. When service A needs to speak to service B it needs the location of that service. The default discovery mechanism is
|
||||
multicast DNS (mdns), a zeroconf system.
|
||||
|
||||
- **Load Balancing** - Client side load balancing built on service discovery. Once we have the addresses of any number of instances
|
||||
of a service we now need a way to decide which node to route to. We use random hashed load balancing to provide even distribution
|
||||
across the services and retry a different node if there's a problem.
|
||||
- **Load Balancing** - Client side load balancing built on service discovery. Once we have the addresses of any number of instances
|
||||
of a service we now need a way to decide which node to route to. We use random hashed load balancing to provide even distribution
|
||||
across the services and retry a different node if there's a problem.
|
||||
|
||||
- **Message Encoding** - Dynamic message encoding based on content-type. The client and server will use codecs along with content-type
|
||||
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.
|
||||
- **Message Encoding** - Dynamic message encoding based on content-type. The client and server will use codecs along with content-type
|
||||
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.
|
||||
|
||||
- **RPC Client/Server** - RPC 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 Client/Server** - RPC 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.
|
||||
- **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.
|
||||
|
||||
- **Synchronization** - Distributed systems are often built in an eventually consistent manner. Support for distributed locking and
|
||||
leadership are built in as a Sync interface. When using an eventually consistent database or scheduling use the Sync interface.
|
||||
- **Event Streaming** - PubSub is great for async notifications but for more advanced use cases event streaming is preferred. Offering
|
||||
persistent storage, consuming from offsets and acking. Go Micro includes support for NATS Jetstream and Redis streams.
|
||||
|
||||
- **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.
|
||||
- **Synchronization** - Distributed systems are often built in an eventually consistent manner. Support for distributed locking and
|
||||
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.
|
||||
|
||||
## Getting Started
|
||||
|
||||
To make use of Go Micro
|
||||
|
||||
```golang
|
||||
import "github.com/asim/go-micro/v3"
|
||||
import "go-micro.dev/v4"
|
||||
|
||||
// create a new service
|
||||
service := micro.NewService(
|
||||
@@ -65,27 +69,29 @@ service.Init()
|
||||
service.Run()
|
||||
```
|
||||
|
||||
See the [examples](https://github.com/micro/go-micro/tree/master/examples) for detailed information on usage.
|
||||
|
||||
## Command Line Interface
|
||||
|
||||
See [cmd/gomu](https://github.com/asim/go-micro/tree/master/cmd/gomu) for the command line interface.
|
||||
See the [examples](https://github.com/go-micro/examples) for detailed information on usage.
|
||||
|
||||
## Code Generation
|
||||
|
||||
See [cmd/protoc-gen-micro](https://github.com/micro/go-micro/tree/master/cmd/protoc-gen-micro) for protobuf code generation.
|
||||
|
||||
## Example Usage
|
||||
## Community
|
||||
|
||||
See [examples](https://github.com/micro/go-micro/tree/master/examples) directory for usage examples.
|
||||
See [github.com/go-micro](https://github.com/go-micro) for community led projects.
|
||||
|
||||
## Plugins
|
||||
- [Demo](https://github.com/go-micro/demo)
|
||||
- [Plugins](https://github.com/go-micro/plugins)
|
||||
- [Examples](https://github.com/go-micro/examples)
|
||||
- [Dashboard](https://github.com/go-micro/dashboard)
|
||||
- [CLI](https://github.com/go-micro/cli)
|
||||
|
||||
See [plugins](https://github.com/micro/go-micro/tree/master/plugins) directory for all the plugins.
|
||||
## Changelog
|
||||
|
||||
## Services
|
||||
See [CHANGELOG.md](https://github.com/micro/go-micro/tree/master/CHANGELOG.md) for release history.
|
||||
|
||||
See [services](https://github.com/micro/go-micro/tree/master/services) directory for third party services.
|
||||
## Evolution
|
||||
|
||||
Go Micro started in 2015. It's since evolved into a platform called [Micro](https://micro.dev) and a service called [M3O](https://m3o.com).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+2
-2
@@ -5,8 +5,8 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"github.com/asim/go-micro/v3/server"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
type Api interface {
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
// Package client provides an api client
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
const (
|
||||
// local address for api
|
||||
localAddress = "http://localhost:8080"
|
||||
)
|
||||
|
||||
// Options of the Client
|
||||
type Options struct {
|
||||
// Token for authentication
|
||||
Token string
|
||||
// Address of the micro platform.
|
||||
// By default it connects to live. Change it or use the local flag
|
||||
// to connect to your local installation.
|
||||
Address string
|
||||
// Helper flag to help users connect to the default local address
|
||||
Local bool
|
||||
// set a timeout
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// Request is the request of the generic `api-client` call
|
||||
type Request struct {
|
||||
// eg. "go.micro.srv.greeter"
|
||||
Service string `json:"service"`
|
||||
// eg. "Say.Hello"
|
||||
Endpoint string `json:"endpoint"`
|
||||
// json and then base64 encoded body
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
// Response is the response of the generic `api-client` call.
|
||||
type Response struct {
|
||||
// json and base64 encoded response body
|
||||
Body string `json:"body"`
|
||||
// error fields. Error json example
|
||||
// {"id":"go.micro.client","code":500,"detail":"malformed method name: \"\"","status":"Internal Server Error"}
|
||||
Code int `json:"code"`
|
||||
ID string `json:"id"`
|
||||
Detail string `json:"detail"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
// Client enables generic calls to micro
|
||||
type Client struct {
|
||||
options Options
|
||||
}
|
||||
|
||||
type Stream struct {
|
||||
conn *websocket.Conn
|
||||
service, endpoint string
|
||||
}
|
||||
|
||||
// NewClient returns a generic micro client that connects to live by default
|
||||
func NewClient(options *Options) *Client {
|
||||
ret := new(Client)
|
||||
ret.options = Options{
|
||||
Address: localAddress,
|
||||
}
|
||||
|
||||
// no options provided
|
||||
if options == nil {
|
||||
return ret
|
||||
}
|
||||
|
||||
if options.Token != "" {
|
||||
ret.options.Token = options.Token
|
||||
}
|
||||
|
||||
if options.Local {
|
||||
ret.options.Address = localAddress
|
||||
ret.options.Local = true
|
||||
}
|
||||
|
||||
if options.Timeout > 0 {
|
||||
ret.options.Timeout = options.Timeout
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
// SetToken sets the api auth token
|
||||
func (client *Client) SetToken(t string) {
|
||||
client.options.Token = t
|
||||
}
|
||||
|
||||
// SetTimeout sets the http client's timeout
|
||||
func (client *Client) SetTimeout(d time.Duration) {
|
||||
client.options.Timeout = d
|
||||
}
|
||||
|
||||
// Call enables you to access any endpoint of any service on Micro
|
||||
func (client *Client) Call(service, endpoint string, request, response interface{}) error {
|
||||
// example curl: curl -XPOST -d '{"service": "go.micro.srv.greeter", "endpoint": "Say.Hello"}'
|
||||
// -H 'Content-Type: application/json' http://localhost:8080/client {"body":"eyJtc2ciOiJIZWxsbyAifQ=="}
|
||||
uri, err := url.Parse(client.options.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the url to go through the v1 api
|
||||
uri.Path = "/" + service + "/" + endpoint
|
||||
|
||||
b, err := marshalRequest(service, endpoint, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", uri.String(), bytes.NewBuffer(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the token if it exists
|
||||
if len(client.options.Token) > 0 {
|
||||
req.Header.Set("Authorization", "Bearer "+client.options.Token)
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// if user didn't specify Timeout the default is 0 i.e no timeout
|
||||
httpClient := &http.Client{
|
||||
Timeout: client.options.Timeout,
|
||||
}
|
||||
|
||||
resp, err := httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !(resp.StatusCode >= 200 && resp.StatusCode < 300) {
|
||||
return errors.New(string(body))
|
||||
}
|
||||
return unmarshalResponse(body, response)
|
||||
}
|
||||
|
||||
// Stream enables the ability to stream via websockets
|
||||
func (client *Client) Stream(service, endpoint string, request interface{}) (*Stream, error) {
|
||||
b, err := marshalRequest(service, endpoint, request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uri, err := url.Parse(client.options.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// set the url to go through the v1 api
|
||||
uri.Path = "/" + service + "/" + endpoint
|
||||
|
||||
// replace http with websocket
|
||||
uri.Scheme = strings.Replace(uri.Scheme, "http", "ws", 1)
|
||||
|
||||
// create the headers
|
||||
header := make(http.Header)
|
||||
// set the token if it exists
|
||||
if len(client.options.Token) > 0 {
|
||||
header.Set("Authorization", "Bearer "+client.options.Token)
|
||||
}
|
||||
header.Set("Content-Type", "application/json")
|
||||
|
||||
// dial the connection
|
||||
conn, _, err := websocket.DefaultDialer.Dial(uri.String(), header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// send the first request
|
||||
if err := conn.WriteMessage(websocket.TextMessage, b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Stream{conn, service, endpoint}, nil
|
||||
}
|
||||
|
||||
func (s *Stream) Recv(v interface{}) error {
|
||||
// read response
|
||||
_, message, err := s.conn.ReadMessage()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return unmarshalResponse(message, v)
|
||||
}
|
||||
|
||||
func (s *Stream) Send(v interface{}) error {
|
||||
b, err := marshalRequest(s.service, s.endpoint, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.conn.WriteMessage(websocket.TextMessage, b)
|
||||
}
|
||||
|
||||
func marshalRequest(service, endpoint string, v interface{}) ([]byte, error) {
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func unmarshalResponse(body []byte, v interface{}) error {
|
||||
return json.Unmarshal(body, &v)
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBasicCall(t *testing.T) {
|
||||
if v := os.Getenv("IN_TRAVIS_CI"); v == "yes" {
|
||||
return
|
||||
}
|
||||
|
||||
response := map[string]interface{}{}
|
||||
if err := NewClient(&Options{
|
||||
Token: os.Getenv("TOKEN"),
|
||||
}).Call("groups", "list", map[string]interface{}{
|
||||
"memberId": "random",
|
||||
}, &response); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(response) > 0 {
|
||||
t.Fatal(len(response))
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,13 @@ package api
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
goapi "github.com/asim/go-micro/v3/api"
|
||||
"github.com/asim/go-micro/v3/api/handler"
|
||||
api "github.com/asim/go-micro/v3/api/proto"
|
||||
"github.com/asim/go-micro/v3/client"
|
||||
"github.com/asim/go-micro/v3/errors"
|
||||
"github.com/asim/go-micro/v3/selector"
|
||||
"github.com/asim/go-micro/v3/util/ctx"
|
||||
goapi "go-micro.dev/v4/api"
|
||||
"go-micro.dev/v4/api/handler"
|
||||
api "go-micro.dev/v4/api/proto"
|
||||
"go-micro.dev/v4/client"
|
||||
"go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/selector"
|
||||
"go-micro.dev/v4/util/ctx"
|
||||
)
|
||||
|
||||
type apiHandler struct {
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
api "github.com/asim/go-micro/v3/api/proto"
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"github.com/asim/go-micro/v3/selector"
|
||||
"github.com/oxtoacart/bpool"
|
||||
api "go-micro.dev/v4/api/proto"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/selector"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -10,11 +10,11 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/api/handler"
|
||||
proto "github.com/asim/go-micro/v3/api/proto"
|
||||
"github.com/asim/go-micro/v3/util/ctx"
|
||||
"github.com/google/uuid"
|
||||
"github.com/oxtoacart/bpool"
|
||||
"go-micro.dev/v4/api/handler"
|
||||
proto "go-micro.dev/v4/api/proto"
|
||||
"go-micro.dev/v4/util/ctx"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
|
||||
"github.com/asim/go-micro/v3/api"
|
||||
"github.com/asim/go-micro/v3/api/handler"
|
||||
"github.com/asim/go-micro/v3/selector"
|
||||
"go-micro.dev/v4/api"
|
||||
"go-micro.dev/v4/api/handler"
|
||||
"go-micro.dev/v4/selector"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -6,12 +6,12 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/asim/go-micro/v3/api/handler"
|
||||
"github.com/asim/go-micro/v3/api/resolver"
|
||||
"github.com/asim/go-micro/v3/api/resolver/vpath"
|
||||
"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"
|
||||
"go-micro.dev/v4/api/handler"
|
||||
"go-micro.dev/v4/api/resolver"
|
||||
"go-micro.dev/v4/api/resolver/vpath"
|
||||
"go-micro.dev/v4/api/router"
|
||||
regRouter "go-micro.dev/v4/api/router/registry"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
func testHttp(t *testing.T, path, service, ns string) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"github.com/asim/go-micro/v3/api/router"
|
||||
"github.com/asim/go-micro/v3/client"
|
||||
"go-micro.dev/v4/api/router"
|
||||
"go-micro.dev/v4/client"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
+14
-14
@@ -9,22 +9,22 @@ 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/internal/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/registry"
|
||||
"github.com/asim/go-micro/v3/selector"
|
||||
"github.com/asim/go-micro/v3/util/ctx"
|
||||
"github.com/asim/go-micro/v3/util/qson"
|
||||
jsonpatch "github.com/evanphx/json-patch/v5"
|
||||
"github.com/oxtoacart/bpool"
|
||||
"go-micro.dev/v4/api"
|
||||
"go-micro.dev/v4/api/handler"
|
||||
"go-micro.dev/v4/api/internal/proto"
|
||||
"go-micro.dev/v4/client"
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/codec/jsonrpc"
|
||||
"go-micro.dev/v4/codec/protorpc"
|
||||
"go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/selector"
|
||||
"go-micro.dev/v4/util/ctx"
|
||||
"go-micro.dev/v4/util/qson"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
go_api "github.com/asim/go-micro/v3/api/proto"
|
||||
"github.com/golang/protobuf/proto"
|
||||
go_api "go-micro.dev/v4/api/proto"
|
||||
)
|
||||
|
||||
func TestRequestPayloadFromRequest(t *testing.T) {
|
||||
|
||||
@@ -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/selector"
|
||||
"github.com/gobwas/httphead"
|
||||
"github.com/gobwas/ws"
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
"go-micro.dev/v4/api"
|
||||
"go-micro.dev/v4/client"
|
||||
raw "go-micro.dev/v4/codec/bytes"
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/selector"
|
||||
)
|
||||
|
||||
// serveWebsocket will stream rpc back over websockets assuming json
|
||||
|
||||
@@ -11,9 +11,9 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/v3/api"
|
||||
"github.com/asim/go-micro/v3/api/handler"
|
||||
"github.com/asim/go-micro/v3/selector"
|
||||
"go-micro.dev/v4/api"
|
||||
"go-micro.dev/v4/api/handler"
|
||||
"go-micro.dev/v4/selector"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/v3/api/resolver"
|
||||
"go-micro.dev/v4/api/resolver"
|
||||
)
|
||||
|
||||
type Resolver struct{}
|
||||
|
||||
@@ -4,7 +4,7 @@ package host
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/asim/go-micro/v3/api/resolver"
|
||||
"go-micro.dev/v4/api/resolver"
|
||||
)
|
||||
|
||||
type Resolver struct {
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/v3/api/resolver"
|
||||
"go-micro.dev/v4/api/resolver"
|
||||
)
|
||||
|
||||
type Resolver struct {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/v3/api/resolver"
|
||||
"go-micro.dev/v4/api/resolver"
|
||||
)
|
||||
|
||||
func NewResolver(opts ...resolver.Option) resolver.Resolver {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/asim/go-micro/v3/api/resolver"
|
||||
"github.com/asim/go-micro/v3/api/resolver/vpath"
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"go-micro.dev/v4/api/resolver"
|
||||
"go-micro.dev/v4/api/resolver/vpath"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/api"
|
||||
"github.com/asim/go-micro/v3/api/router"
|
||||
"github.com/asim/go-micro/v3/api/router/util"
|
||||
"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"
|
||||
"go-micro.dev/v4/api"
|
||||
"go-micro.dev/v4/api/router"
|
||||
"go-micro.dev/v4/api/router/util"
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/registry/cache"
|
||||
)
|
||||
|
||||
// endpoint struct, that holds compiled pcre
|
||||
|
||||
@@ -3,8 +3,8 @@ package registry
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
func TestStoreRegex(t *testing.T) {
|
||||
|
||||
@@ -4,7 +4,7 @@ package router
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/asim/go-micro/v3/api"
|
||||
"go-micro.dev/v4/api"
|
||||
)
|
||||
|
||||
// Router is used to determine an endpoint for a request
|
||||
|
||||
@@ -8,13 +8,13 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/asim/go-micro/v3/api"
|
||||
"github.com/asim/go-micro/v3/api/router"
|
||||
"github.com/asim/go-micro/v3/api/router/util"
|
||||
"github.com/asim/go-micro/v3/logger"
|
||||
"github.com/asim/go-micro/v3/metadata"
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
rutil "github.com/asim/go-micro/v3/util/registry"
|
||||
"go-micro.dev/v4/api"
|
||||
"go-micro.dev/v4/api/router"
|
||||
"go-micro.dev/v4/api/router/util"
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"go-micro.dev/v4/registry"
|
||||
rutil "go-micro.dev/v4/util/registry"
|
||||
)
|
||||
|
||||
type endpoint struct {
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/v3/logger"
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
// InvalidTemplateError indicates that the path template is not valid.
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/asim/go-micro/v3/logger"
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
func TestTokenize(t *testing.T) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/v3/logger"
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/asim/go-micro/v3/api/server/acme"
|
||||
"github.com/asim/go-micro/v3/logger"
|
||||
"go-micro.dev/v4/api/server/acme"
|
||||
"go-micro.dev/v4/logger"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
)
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/asim/go-micro/v3/api/server"
|
||||
"github.com/asim/go-micro/v3/api/server/cors"
|
||||
"github.com/asim/go-micro/v3/logger"
|
||||
"github.com/gorilla/handlers"
|
||||
"go-micro.dev/v4/api/server"
|
||||
"go-micro.dev/v4/api/server/cors"
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
type httpServer struct {
|
||||
|
||||
@@ -2,9 +2,9 @@ package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/asim/go-micro/v3/api/server"
|
||||
"github.com/asim/go-micro/v3/api/server/cors"
|
||||
"io/ioutil"
|
||||
"go-micro.dev/v4/api/server"
|
||||
"go-micro.dev/v4/api/server/cors"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
@@ -28,7 +28,7 @@ func TestHTTPServer(t *testing.T) {
|
||||
}
|
||||
defer rsp.Body.Close()
|
||||
|
||||
b, err := ioutil.ReadAll(rsp.Body)
|
||||
b, err := io.ReadAll(rsp.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func TestCORSHTTPServer(t *testing.T) {
|
||||
}
|
||||
defer rsp.Body.Close()
|
||||
|
||||
b, err := ioutil.ReadAll(rsp.Body)
|
||||
b, err := io.ReadAll(rsp.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package server
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"github.com/asim/go-micro/v3/api/server/cors"
|
||||
"go-micro.dev/v4/api/server/cors"
|
||||
"net/http"
|
||||
|
||||
"github.com/asim/go-micro/v3/api/resolver"
|
||||
"github.com/asim/go-micro/v3/api/server/acme"
|
||||
"go-micro.dev/v4/api/resolver"
|
||||
"go-micro.dev/v4/api/server/acme"
|
||||
)
|
||||
|
||||
type Option func(o *Options)
|
||||
|
||||
+9
-10
@@ -8,7 +8,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -17,14 +16,14 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"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"
|
||||
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"
|
||||
"go-micro.dev/v4/codec/json"
|
||||
merr "go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/registry/cache"
|
||||
maddr "go-micro.dev/v4/util/addr"
|
||||
mnet "go-micro.dev/v4/util/net"
|
||||
mls "go-micro.dev/v4/util/tls"
|
||||
"golang.org/x/net/http2"
|
||||
)
|
||||
|
||||
@@ -300,7 +299,7 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
|
||||
req.ParseForm()
|
||||
|
||||
b, err := ioutil.ReadAll(req.Body)
|
||||
b, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
errr := merr.InternalServerError("go.micro.broker", "Error reading request body: %v", err)
|
||||
w.WriteHeader(500)
|
||||
@@ -558,7 +557,7 @@ func (h *httpBroker) Publish(topic string, msg *Message, opts ...PublishOption)
|
||||
}
|
||||
|
||||
// discard response body
|
||||
io.Copy(ioutil.Discard, r.Body)
|
||||
io.Copy(io.Discard, r.Body)
|
||||
r.Body.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
+2
-2
@@ -5,9 +5,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/broker"
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"github.com/google/uuid"
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
// Package memory provides a memory broker
|
||||
package broker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go-micro.dev/v4/logger"
|
||||
maddr "go-micro.dev/v4/util/addr"
|
||||
mnet "go-micro.dev/v4/util/net"
|
||||
)
|
||||
|
||||
type memoryBroker struct {
|
||||
opts Options
|
||||
|
||||
addr string
|
||||
sync.RWMutex
|
||||
connected bool
|
||||
Subscribers map[string][]*memorySubscriber
|
||||
}
|
||||
|
||||
type memoryEvent struct {
|
||||
opts Options
|
||||
topic string
|
||||
err error
|
||||
message interface{}
|
||||
}
|
||||
|
||||
type memorySubscriber struct {
|
||||
id string
|
||||
topic string
|
||||
exit chan bool
|
||||
handler Handler
|
||||
opts SubscribeOptions
|
||||
}
|
||||
|
||||
func (m *memoryBroker) Options() Options {
|
||||
return m.opts
|
||||
}
|
||||
|
||||
func (m *memoryBroker) Address() string {
|
||||
return m.addr
|
||||
}
|
||||
|
||||
func (m *memoryBroker) Connect() error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if m.connected {
|
||||
return nil
|
||||
}
|
||||
|
||||
// use 127.0.0.1 to avoid scan of all network interfaces
|
||||
addr, err := maddr.Extract("127.0.0.1")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i := rand.Intn(20000)
|
||||
// set addr with port
|
||||
addr = mnet.HostPort(addr, 10000+i)
|
||||
|
||||
m.addr = addr
|
||||
m.connected = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryBroker) Disconnect() error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if !m.connected {
|
||||
return nil
|
||||
}
|
||||
|
||||
m.connected = false
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryBroker) Init(opts ...Option) error {
|
||||
for _, o := range opts {
|
||||
o(&m.opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryBroker) Publish(topic string, msg *Message, opts ...PublishOption) error {
|
||||
m.RLock()
|
||||
if !m.connected {
|
||||
m.RUnlock()
|
||||
return errors.New("not connected")
|
||||
}
|
||||
|
||||
subs, ok := m.Subscribers[topic]
|
||||
m.RUnlock()
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
var v interface{}
|
||||
if m.opts.Codec != nil {
|
||||
buf, err := m.opts.Codec.Marshal(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v = buf
|
||||
} else {
|
||||
v = msg
|
||||
}
|
||||
|
||||
p := &memoryEvent{
|
||||
topic: topic,
|
||||
message: v,
|
||||
opts: m.opts,
|
||||
}
|
||||
|
||||
for _, sub := range subs {
|
||||
if err := sub.handler(p); err != nil {
|
||||
p.err = err
|
||||
if eh := m.opts.ErrorHandler; eh != nil {
|
||||
eh(p)
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryBroker) Subscribe(topic string, handler Handler, opts ...SubscribeOption) (Subscriber, error) {
|
||||
m.RLock()
|
||||
if !m.connected {
|
||||
m.RUnlock()
|
||||
return nil, errors.New("not connected")
|
||||
}
|
||||
m.RUnlock()
|
||||
|
||||
var options SubscribeOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
sub := &memorySubscriber{
|
||||
exit: make(chan bool, 1),
|
||||
id: uuid.New().String(),
|
||||
topic: topic,
|
||||
handler: handler,
|
||||
opts: options,
|
||||
}
|
||||
|
||||
m.Lock()
|
||||
m.Subscribers[topic] = append(m.Subscribers[topic], sub)
|
||||
m.Unlock()
|
||||
|
||||
go func() {
|
||||
<-sub.exit
|
||||
m.Lock()
|
||||
var newSubscribers []*memorySubscriber
|
||||
for _, sb := range m.Subscribers[topic] {
|
||||
if sb.id == sub.id {
|
||||
continue
|
||||
}
|
||||
newSubscribers = append(newSubscribers, sb)
|
||||
}
|
||||
m.Subscribers[topic] = newSubscribers
|
||||
m.Unlock()
|
||||
}()
|
||||
|
||||
return sub, nil
|
||||
}
|
||||
|
||||
func (m *memoryBroker) String() string {
|
||||
return "memory"
|
||||
}
|
||||
|
||||
func (m *memoryEvent) Topic() string {
|
||||
return m.topic
|
||||
}
|
||||
|
||||
func (m *memoryEvent) Message() *Message {
|
||||
switch v := m.message.(type) {
|
||||
case *Message:
|
||||
return v
|
||||
case []byte:
|
||||
msg := &Message{}
|
||||
if err := m.opts.Codec.Unmarshal(v, msg); err != nil {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("[memory]: failed to unmarshal: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryEvent) Ack() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryEvent) Error() error {
|
||||
return m.err
|
||||
}
|
||||
|
||||
func (m *memorySubscriber) Options() SubscribeOptions {
|
||||
return m.opts
|
||||
}
|
||||
|
||||
func (m *memorySubscriber) Topic() string {
|
||||
return m.topic
|
||||
}
|
||||
|
||||
func (m *memorySubscriber) Unsubscribe() error {
|
||||
m.exit <- true
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewMemoryBroker(opts ...Option) Broker {
|
||||
options := Options{
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &memoryBroker{
|
||||
opts: options,
|
||||
Subscribers: make(map[string][]*memorySubscriber),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package broker_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"go-micro.dev/v4/broker"
|
||||
)
|
||||
|
||||
func TestMemoryBroker(t *testing.T) {
|
||||
b := broker.NewMemoryBroker()
|
||||
|
||||
if err := b.Connect(); err != nil {
|
||||
t.Fatalf("Unexpected connect error %v", err)
|
||||
}
|
||||
|
||||
topic := "test"
|
||||
count := 10
|
||||
|
||||
fn := func(p broker.Event) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
sub, err := b.Subscribe(topic, fn)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error subscribing %v", err)
|
||||
}
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
message := &broker.Message{
|
||||
Header: map[string]string{
|
||||
"foo": "bar",
|
||||
"id": fmt.Sprintf("%d", i),
|
||||
},
|
||||
Body: []byte(`hello world`),
|
||||
}
|
||||
|
||||
if err := b.Publish(topic, message); err != nil {
|
||||
t.Fatalf("Unexpected error publishing %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
if err := sub.Unsubscribe(); err != nil {
|
||||
t.Fatalf("Unexpected error unsubscribing from %s: %v", topic, err)
|
||||
}
|
||||
|
||||
if err := b.Disconnect(); err != nil {
|
||||
t.Fatalf("Unexpected connect error %v", err)
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
|
||||
"github.com/asim/go-micro/v3/codec"
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
|
||||
Vendored
+8
-8
@@ -23,15 +23,15 @@ var (
|
||||
|
||||
// Cache is the interface that wraps the cache.
|
||||
//
|
||||
// Context specifies the context for the cache.
|
||||
// Get gets a cached value by key.
|
||||
// Put stores a key-value pair into cache.
|
||||
// Delete removes a key from cache.
|
||||
type Cache interface {
|
||||
Context(ctx context.Context) Cache
|
||||
Get(key string) (interface{}, time.Time, error)
|
||||
Put(key string, val interface{}, d time.Duration) error
|
||||
Delete(key string) error
|
||||
// Get gets a cached value by key.
|
||||
Get(ctx context.Context, key string) (interface{}, time.Time, error)
|
||||
// Put stores a key-value pair into cache.
|
||||
Put(ctx context.Context, key string, val interface{}, d time.Duration) error
|
||||
// Delete removes a key from cache.
|
||||
Delete(ctx context.Context, key string) error
|
||||
// String returns the name of the implementation.
|
||||
String() string
|
||||
}
|
||||
|
||||
// Item represents an item stored in the cache.
|
||||
|
||||
Vendored
+9
-11
@@ -9,19 +9,13 @@ import (
|
||||
type memCache struct {
|
||||
opts Options
|
||||
sync.RWMutex
|
||||
ctx context.Context
|
||||
|
||||
items map[string]Item
|
||||
}
|
||||
|
||||
func (c *memCache) Context(ctx context.Context) Cache {
|
||||
c.ctx = ctx
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *memCache) Get(key string) (interface{}, time.Time, error) {
|
||||
c.RWMutex.Lock()
|
||||
defer c.RWMutex.Unlock()
|
||||
func (c *memCache) Get(ctx context.Context, key string) (interface{}, time.Time, error) {
|
||||
c.RWMutex.RLock()
|
||||
defer c.RWMutex.RUnlock()
|
||||
|
||||
item, found := c.items[key]
|
||||
if !found {
|
||||
@@ -34,7 +28,7 @@ func (c *memCache) Get(key string) (interface{}, time.Time, error) {
|
||||
return item.Value, time.Unix(0, item.Expiration), nil
|
||||
}
|
||||
|
||||
func (c *memCache) Put(key string, val interface{}, d time.Duration) error {
|
||||
func (c *memCache) Put(ctx context.Context, key string, val interface{}, d time.Duration) error {
|
||||
var e int64
|
||||
if d == DefaultExpiration {
|
||||
d = c.opts.Expiration
|
||||
@@ -54,7 +48,7 @@ func (c *memCache) Put(key string, val interface{}, d time.Duration) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *memCache) Delete(key string) error {
|
||||
func (c *memCache) Delete(ctx context.Context, key string) error {
|
||||
c.RWMutex.Lock()
|
||||
defer c.RWMutex.Unlock()
|
||||
|
||||
@@ -66,3 +60,7 @@ func (c *memCache) Delete(key string) error {
|
||||
delete(c.items, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memCache) String() string {
|
||||
return "memory"
|
||||
}
|
||||
+17
-17
@@ -7,15 +7,15 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ctx context.Context = context.TODO()
|
||||
key string = "test"
|
||||
val interface{} = "hello go-micro"
|
||||
ctx = context.TODO()
|
||||
key string = "test"
|
||||
val interface{} = "hello go-micro"
|
||||
)
|
||||
|
||||
// TestMemCache tests the in-memory cache implementation.
|
||||
func TestCache(t *testing.T) {
|
||||
t.Run("CacheGetMiss", func(t *testing.T) {
|
||||
if _, _, err := NewCache().Context(ctx).Get(key); err == nil {
|
||||
if _, _, err := NewCache().Get(ctx, key); err == nil {
|
||||
t.Error("expected to get no value from cache")
|
||||
}
|
||||
})
|
||||
@@ -23,11 +23,11 @@ func TestCache(t *testing.T) {
|
||||
t.Run("CacheGetHit", func(t *testing.T) {
|
||||
c := NewCache()
|
||||
|
||||
if err := c.Context(ctx).Put(key, val, 0); err != nil {
|
||||
if err := c.Put(ctx, key, val, 0); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if a, _, err := c.Context(ctx).Get(key); err != nil {
|
||||
if a, _, err := c.Get(ctx, key); err != nil {
|
||||
t.Errorf("Expected a value, got err: %s", err)
|
||||
} else if a != val {
|
||||
t.Errorf("Expected '%v', got '%v'", val, a)
|
||||
@@ -38,12 +38,12 @@ func TestCache(t *testing.T) {
|
||||
c := NewCache()
|
||||
e := 20 * time.Millisecond
|
||||
|
||||
if err := c.Context(ctx).Put(key, val, e); err != nil {
|
||||
if err := c.Put(ctx, key, val, e); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
<-time.After(25 * time.Millisecond)
|
||||
if _, _, err := c.Context(ctx).Get(key); err == nil {
|
||||
if _, _, err := c.Get(ctx, key); err == nil {
|
||||
t.Error("expected to get no value from cache")
|
||||
}
|
||||
})
|
||||
@@ -52,18 +52,18 @@ func TestCache(t *testing.T) {
|
||||
c := NewCache()
|
||||
e := 25 * time.Millisecond
|
||||
|
||||
if err := c.Context(ctx).Put(key, val, e); err != nil {
|
||||
if err := c.Put(ctx, key, val, e); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
<-time.After(20 * time.Millisecond)
|
||||
if _, _, err := c.Context(ctx).Get(key); err != nil {
|
||||
if _, _, err := c.Get(ctx, key); err != nil {
|
||||
t.Errorf("expected a value, got err: %s", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CacheDeleteMiss", func(t *testing.T) {
|
||||
if err := NewCache().Context(ctx).Delete(key); err == nil {
|
||||
if err := NewCache().Delete(ctx, key); err == nil {
|
||||
t.Error("expected to delete no value from cache")
|
||||
}
|
||||
})
|
||||
@@ -71,15 +71,15 @@ func TestCache(t *testing.T) {
|
||||
t.Run("CacheDeleteHit", func(t *testing.T) {
|
||||
c := NewCache()
|
||||
|
||||
if err := c.Context(ctx).Put(key, val, 0); err != nil {
|
||||
if err := c.Put(ctx, key, val, 0); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if err := c.Context(ctx).Delete(key); err != nil {
|
||||
if err := c.Delete(ctx, key); err != nil {
|
||||
t.Errorf("Expected to delete an item, got err: %s", err)
|
||||
}
|
||||
|
||||
if _, _, err := c.Context(ctx).Get(key); err == nil {
|
||||
if _, _, err := c.Get(ctx, key); err == nil {
|
||||
t.Errorf("Expected error")
|
||||
}
|
||||
})
|
||||
@@ -89,12 +89,12 @@ func TestCacheWithOptions(t *testing.T) {
|
||||
t.Run("CacheWithExpiration", func(t *testing.T) {
|
||||
c := NewCache(Expiration(20 * time.Millisecond))
|
||||
|
||||
if err := c.Context(ctx).Put(key, val, 0); err != nil {
|
||||
if err := c.Put(ctx, key, val, 0); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
<-time.After(25 * time.Millisecond)
|
||||
if _, _, err := c.Context(ctx).Get(key); err == nil {
|
||||
if _, _, err := c.Get(ctx, key); err == nil {
|
||||
t.Error("expected to get no value from cache")
|
||||
}
|
||||
})
|
||||
@@ -102,7 +102,7 @@ func TestCacheWithOptions(t *testing.T) {
|
||||
t.Run("CacheWithItems", func(t *testing.T) {
|
||||
c := NewCache(Items(map[string]Item{key: {val, 0}}))
|
||||
|
||||
if a, _, err := c.Context(ctx).Get(key); err != nil {
|
||||
if a, _, err := c.Get(ctx, key); err != nil {
|
||||
t.Errorf("Expected a value, got err: %s", err)
|
||||
} else if a != val {
|
||||
t.Errorf("Expected '%v', got '%v'", val, a)
|
||||
Vendored
+22
-1
@@ -1,11 +1,18 @@
|
||||
package cache
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Options represents the options for the cache.
|
||||
type Options struct {
|
||||
Expiration time.Duration
|
||||
Items map[string]Item
|
||||
// Address represents the address or other connection information of the cache service.
|
||||
Address string
|
||||
// Context should contain all implementation specific options, using context.WithValue.
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// Option manipulates the Options passed.
|
||||
@@ -25,6 +32,20 @@ func Items(i map[string]Item) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithAddress sets the cache service address or connection information
|
||||
func WithAddress(addr string) Option {
|
||||
return func(o *Options) {
|
||||
o.Address = addr
|
||||
}
|
||||
}
|
||||
|
||||
// WithContext sets the cache context, for any extra configuration
|
||||
func WithContext(c context.Context) Option {
|
||||
return func(o *Options) {
|
||||
o.Context = c
|
||||
}
|
||||
}
|
||||
|
||||
// NewOptions returns a new options struct.
|
||||
func NewOptions(opts ...Option) Options {
|
||||
options := Options{
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/util/backoff"
|
||||
"go-micro.dev/v4/util/backoff"
|
||||
)
|
||||
|
||||
type BackoffFunc func(ctx context.Context, req Request, attempts int) (time.Duration, error)
|
||||
|
||||
+1
-1
@@ -7,8 +7,8 @@ import (
|
||||
"hash/fnv"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/metadata"
|
||||
cache "github.com/patrickmn/go-cache"
|
||||
"go-micro.dev/v4/metadata"
|
||||
)
|
||||
|
||||
// NewCache returns an initialised cache.
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/metadata"
|
||||
"go-micro.dev/v4/metadata"
|
||||
)
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
|
||||
+8
-1
@@ -5,7 +5,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/codec"
|
||||
"go-micro.dev/v4/codec"
|
||||
)
|
||||
|
||||
// Client is the interface used to make requests to services.
|
||||
@@ -64,6 +64,7 @@ type Response interface {
|
||||
|
||||
// Stream is the inteface for a bidirectional synchronous stream
|
||||
type Stream interface {
|
||||
Closer
|
||||
// Context for the stream
|
||||
Context() context.Context
|
||||
// The request made
|
||||
@@ -80,6 +81,12 @@ type Stream interface {
|
||||
Close() error
|
||||
}
|
||||
|
||||
// Closer handle client close
|
||||
type Closer interface {
|
||||
// CloseSend closes the send direction of the stream.
|
||||
CloseSend() error
|
||||
}
|
||||
|
||||
// Option used by the Client
|
||||
type Option func(*Options)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
+5
-5
@@ -4,11 +4,11 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/broker"
|
||||
"github.com/asim/go-micro/v3/codec"
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"github.com/asim/go-micro/v3/selector"
|
||||
"github.com/asim/go-micro/v3/transport"
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/selector"
|
||||
"go-micro.dev/v4/transport"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/transport"
|
||||
"go-micro.dev/v4/transport"
|
||||
)
|
||||
|
||||
func TestCallOptions(t *testing.T) {
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package client
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/asim/go-micro/v3/errors"
|
||||
"go-micro.dev/v4/errors"
|
||||
)
|
||||
|
||||
// note that returning either false or a non-nil error will result in the call not being retried
|
||||
|
||||
+12
-12
@@ -6,18 +6,18 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/broker"
|
||||
"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/registry"
|
||||
"github.com/asim/go-micro/v3/selector"
|
||||
"github.com/asim/go-micro/v3/transport"
|
||||
"github.com/asim/go-micro/v3/util/buf"
|
||||
"github.com/asim/go-micro/v3/util/net"
|
||||
"github.com/asim/go-micro/v3/util/pool"
|
||||
"github.com/google/uuid"
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/codec"
|
||||
raw "go-micro.dev/v4/codec/bytes"
|
||||
"go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/selector"
|
||||
"go-micro.dev/v4/transport"
|
||||
"go-micro.dev/v4/util/buf"
|
||||
"go-micro.dev/v4/util/net"
|
||||
"go-micro.dev/v4/util/pool"
|
||||
)
|
||||
|
||||
type rpcClient struct {
|
||||
@@ -60,7 +60,7 @@ func (r *rpcClient) newCodec(contentType string) (codec.NewCodec, error) {
|
||||
if cf, ok := DefaultCodecs[contentType]; ok {
|
||||
return cf, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
|
||||
return nil, fmt.Errorf("unsupported Content-Type: %s", contentType)
|
||||
}
|
||||
|
||||
func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request, resp interface{}, opts CallOptions) error {
|
||||
|
||||
@@ -5,9 +5,9 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/asim/go-micro/v3/errors"
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"github.com/asim/go-micro/v3/selector"
|
||||
"go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/selector"
|
||||
)
|
||||
|
||||
func newTestRegistry() registry.Registry {
|
||||
|
||||
+11
-11
@@ -4,16 +4,16 @@ import (
|
||||
"bytes"
|
||||
errs "errors"
|
||||
|
||||
"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/registry"
|
||||
"github.com/asim/go-micro/v3/transport"
|
||||
"go-micro.dev/v4/codec"
|
||||
raw "go-micro.dev/v4/codec/bytes"
|
||||
"go-micro.dev/v4/codec/grpc"
|
||||
"go-micro.dev/v4/codec/json"
|
||||
"go-micro.dev/v4/codec/jsonrpc"
|
||||
"go-micro.dev/v4/codec/proto"
|
||||
"go-micro.dev/v4/codec/protorpc"
|
||||
"go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/transport"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -50,7 +50,7 @@ type readWriteCloser struct {
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultContentType = "application/protobuf"
|
||||
DefaultContentType = "application/json"
|
||||
|
||||
DefaultCodecs = map[string]codec.NewCodec{
|
||||
"application/grpc": grpc.NewCodec,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/asim/go-micro/v3/codec"
|
||||
"go-micro.dev/v4/codec"
|
||||
)
|
||||
|
||||
type rpcRequest struct {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/asim/go-micro/v3/codec"
|
||||
"github.com/asim/go-micro/v3/transport"
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/transport"
|
||||
)
|
||||
|
||||
type rpcResponse struct {
|
||||
|
||||
@@ -2,10 +2,11 @@ package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/asim/go-micro/v3/codec"
|
||||
"go-micro.dev/v4/codec"
|
||||
)
|
||||
|
||||
// Implements the streamer interface
|
||||
@@ -93,6 +94,7 @@ func (r *rpcStream) Recv(msg interface{}) error {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
r.err = err
|
||||
|
||||
r.Unlock()
|
||||
return err
|
||||
}
|
||||
@@ -132,6 +134,10 @@ func (r *rpcStream) Error() error {
|
||||
return r.err
|
||||
}
|
||||
|
||||
func (r *rpcStream) CloseSend() error {
|
||||
return errors.New("streamer not implemented")
|
||||
}
|
||||
|
||||
func (r *rpcStream) Close() error {
|
||||
r.Lock()
|
||||
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package client
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
// CallFunc represents the individual call func
|
||||
|
||||
+16
-16
@@ -7,23 +7,23 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/asim/go-micro/v3/auth"
|
||||
"github.com/asim/go-micro/v3/broker"
|
||||
"github.com/asim/go-micro/v3/cache"
|
||||
"github.com/asim/go-micro/v3/client"
|
||||
"github.com/asim/go-micro/v3/config"
|
||||
"github.com/asim/go-micro/v3/debug/profile"
|
||||
"github.com/asim/go-micro/v3/debug/profile/http"
|
||||
"github.com/asim/go-micro/v3/debug/profile/pprof"
|
||||
"github.com/asim/go-micro/v3/debug/trace"
|
||||
"github.com/asim/go-micro/v3/logger"
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"github.com/asim/go-micro/v3/runtime"
|
||||
"github.com/asim/go-micro/v3/selector"
|
||||
"github.com/asim/go-micro/v3/server"
|
||||
"github.com/asim/go-micro/v3/store"
|
||||
"github.com/asim/go-micro/v3/transport"
|
||||
"github.com/urfave/cli/v2"
|
||||
"go-micro.dev/v4/auth"
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/cache"
|
||||
"go-micro.dev/v4/client"
|
||||
"go-micro.dev/v4/config"
|
||||
"go-micro.dev/v4/debug/profile"
|
||||
"go-micro.dev/v4/debug/profile/http"
|
||||
"go-micro.dev/v4/debug/profile/pprof"
|
||||
"go-micro.dev/v4/debug/trace"
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/runtime"
|
||||
"go-micro.dev/v4/selector"
|
||||
"go-micro.dev/v4/server"
|
||||
"go-micro.dev/v4/store"
|
||||
"go-micro.dev/v4/transport"
|
||||
)
|
||||
|
||||
type Cmd interface {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
_build
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
# ignore go build and test outputs
|
||||
coverage.txt
|
||||
coverage.out
|
||||
|
||||
# ignore locally built binaries
|
||||
gomu
|
||||
dist
|
||||
@@ -1,389 +0,0 @@
|
||||
# Gomu
|
||||
|
||||
Gomu is a helper tool for developing [Go Micro][1] projects.
|
||||
|
||||
## Getting Started
|
||||
|
||||
[Download][2] and install **Go**. Version `1.16` or higher is required.
|
||||
|
||||
Installation is done by using the [`go install`][3] command.
|
||||
|
||||
```bash
|
||||
go install github.com/asim/go-micro/cmd/gomu@latest
|
||||
```
|
||||
|
||||
Let's create a new service using the `new` command.
|
||||
|
||||
```bash
|
||||
gomu new service helloworld
|
||||
```
|
||||
|
||||
Follow the on-screen instructions. Next, we can run the program.
|
||||
|
||||
```bash
|
||||
cd helloworld
|
||||
make proto tidy
|
||||
gomu run
|
||||
```
|
||||
|
||||
Finally we can call the service.
|
||||
|
||||
```bash
|
||||
gomu call helloworld Helloworld.Call '{"name": "John"}'
|
||||
```
|
||||
|
||||
That's all you need to know to get started. Refer to the [Go Micro][1]
|
||||
documentation for more info on developing services.
|
||||
|
||||
## Dependencies
|
||||
|
||||
You will need protoc-gen-micro for code generation
|
||||
|
||||
* [protobuf][4]
|
||||
* [protoc-gen-go][5]
|
||||
* [protoc-gen-micro][6]
|
||||
|
||||
```bash
|
||||
# Download latest proto release
|
||||
# https://github.com/protocolbuffers/protobuf/releases
|
||||
go get -u google.golang.org/protobuf/proto
|
||||
go install github.com/golang/protobuf/protoc-gen-go@latest
|
||||
go install github.com/asim/go-micro/cmd/protoc-gen-micro/v3@latest
|
||||
```
|
||||
|
||||
## Creating A Service
|
||||
|
||||
To create a new service, use the `gomu new service` command.
|
||||
|
||||
```bash
|
||||
$ gomu new service helloworld
|
||||
creating service helloworld
|
||||
|
||||
download protoc zip packages (protoc-$VERSION-$PLATFORM.zip) and install:
|
||||
|
||||
visit https://github.com/protocolbuffers/protobuf/releases/latest
|
||||
|
||||
download protobuf for go-micro:
|
||||
|
||||
go get -u google.golang.org/protobuf/proto
|
||||
go install github.com/golang/protobuf/protoc-gen-go@latest
|
||||
go install github.com/asim/go-micro/cmd/protoc-gen-micro/v3@latest
|
||||
|
||||
compile the proto file helloworld.proto:
|
||||
|
||||
cd helloworld
|
||||
make proto tidy
|
||||
```
|
||||
|
||||
To create a new function, use the `gomu new function` command. Functions differ
|
||||
from services in that they exit after returning.
|
||||
|
||||
```bash
|
||||
$ gomu new function helloworld
|
||||
creating function helloworld
|
||||
|
||||
download protoc zip packages (protoc-$VERSION-$PLATFORM.zip) and install:
|
||||
|
||||
visit https://github.com/protocolbuffers/protobuf/releases/latest
|
||||
|
||||
download protobuf for go-micro:
|
||||
|
||||
go get -u google.golang.org/protobuf/proto
|
||||
go install github.com/golang/protobuf/protoc-gen-go@latest
|
||||
go install github.com/asim/go-micro/cmd/protoc-gen-micro/v3@latest
|
||||
|
||||
compile the proto file helloworld.proto:
|
||||
|
||||
cd helloworld
|
||||
make proto tidy
|
||||
```
|
||||
|
||||
### Jaeger
|
||||
|
||||
To create a new service with [Jaeger][7] integration, pass the `--jaeger` flag
|
||||
to the `gomu new service` or `gomu new function` commands. You may configure
|
||||
the Jaeger client using [environment variables][8].
|
||||
|
||||
```bash
|
||||
gomu new service --jaeger helloworld
|
||||
```
|
||||
|
||||
You may invoke `trace.NewSpan(context.Context).Finish()` to nest spans. For
|
||||
example, consider the following handler implementing a greeter.
|
||||
|
||||
`handler/helloworld.go`
|
||||
|
||||
```go
|
||||
package helloworld
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
log "github.com/asim/go-micro/v3/logger"
|
||||
|
||||
"helloworld/greeter"
|
||||
pb "helloworld/proto"
|
||||
)
|
||||
|
||||
type Helloworld struct{}
|
||||
|
||||
func (e *Helloworld) Call(ctx context.Context, req pb.CallRequest, rsp *pb.CallResponse) error {
|
||||
log.Infof("Received Helloworld.Call request: %v", req)
|
||||
rsp.Msg = greeter.Greet(ctx, req.Name)
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
`greeter/greeter.go`
|
||||
|
||||
```go
|
||||
package greeter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/asim/go-micro/cmd/gomu/debug/trace"
|
||||
)
|
||||
|
||||
func Greet(ctx context.Context, name string) string {
|
||||
defer trace.NewSpan(ctx).Finish()
|
||||
return fmt.Sprint("Hello " + name)
|
||||
}
|
||||
```
|
||||
|
||||
### Skaffold
|
||||
|
||||
To create a new service with [Skaffold][9] files, pass the `--skaffold` flag to
|
||||
the `gomu new service` or `gomu new function` commands.
|
||||
|
||||
```bash
|
||||
gomu new service --skaffold helloworld
|
||||
```
|
||||
|
||||
## Running A Service
|
||||
|
||||
To run a service, use the `gomu run` command to build and run your service
|
||||
continuously.
|
||||
|
||||
```bash
|
||||
$ gomu run
|
||||
2021-08-20 14:05:54 file=v3@v3.5.2/service.go:199 level=info Starting [service] helloworld
|
||||
2021-08-20 14:05:54 file=server/rpc_server.go:820 level=info Transport [http] Listening on [::]:34531
|
||||
2021-08-20 14:05:54 file=server/rpc_server.go:840 level=info Broker [http] Connected to 127.0.0.1:44975
|
||||
2021-08-20 14:05:54 file=server/rpc_server.go:654 level=info Registry [mdns] Registering node: helloworld-45f43a6f-5fc0-4b0d-af73-e4a10c36ef54
|
||||
```
|
||||
|
||||
### With Docker
|
||||
|
||||
To run a service with Docker, build the Docker image and run the Docker
|
||||
container.
|
||||
|
||||
```bash
|
||||
$ make docker
|
||||
$ docker run helloworld:latest
|
||||
2021-08-20 12:07:31 file=v3@v3.5.2/service.go:199 level=info Starting [service] helloworld
|
||||
2021-08-20 12:07:31 file=server/rpc_server.go:820 level=info Transport [http] Listening on [::]:36037
|
||||
2021-08-20 12:07:31 file=server/rpc_server.go:840 level=info Broker [http] Connected to 127.0.0.1:46157
|
||||
2021-08-20 12:07:31 file=server/rpc_server.go:654 level=info Registry [mdns] Registering node: helloworld-31f58714-72f5-4d12-b2eb-98f66aea7a34
|
||||
```
|
||||
|
||||
### With Skaffold
|
||||
|
||||
When you've created your service using the `--skaffold` flag, you may run the
|
||||
Skaffold pipeline using the `skaffold` command.
|
||||
|
||||
```bash
|
||||
skaffold dev
|
||||
```
|
||||
|
||||
## Creating A Client
|
||||
|
||||
To create a new client, use the `gomu new client` command. The name is the
|
||||
service you'd like to create a client project for.
|
||||
|
||||
```bash
|
||||
$ gomu new client helloworld
|
||||
creating client helloworld
|
||||
cd helloworld-client
|
||||
make tidy
|
||||
```
|
||||
|
||||
You may optionally pass the fully qualified package name of the service you'd
|
||||
like to create a client project for.
|
||||
|
||||
```bash
|
||||
$ gomu new client github.com/auditemarlow/helloworld
|
||||
creating client helloworld
|
||||
cd helloworld-client
|
||||
make tidy
|
||||
```
|
||||
|
||||
## Running A Client
|
||||
|
||||
To run a client, use the `gomu run` command to build and run your client
|
||||
continuously.
|
||||
|
||||
```bash
|
||||
$ gomu run
|
||||
2021-09-03 12:52:23 file=helloworld-client/main.go:33 level=info msg:"Hello John"
|
||||
```
|
||||
|
||||
## Generating Files
|
||||
|
||||
To generate Go Micro project template files after the fact, use the `gomu
|
||||
generate` command. It will place the generated files in the current working
|
||||
directory.
|
||||
|
||||
```bash
|
||||
$ gomu generate skaffold
|
||||
skaffold project template files generated
|
||||
```
|
||||
|
||||
## Listing Services
|
||||
|
||||
To list services, use the `gomu services` command.
|
||||
|
||||
```bash
|
||||
$ gomu services
|
||||
helloworld
|
||||
```
|
||||
|
||||
## Describing A Service
|
||||
|
||||
To describe a service, use the `gomu describe service` command.
|
||||
|
||||
```bash
|
||||
$ gomu describe service helloworld
|
||||
{
|
||||
"name": "helloworld",
|
||||
"version": "latest",
|
||||
"metadata": null,
|
||||
"endpoints": [
|
||||
{
|
||||
"name": "Helloworld.Call",
|
||||
"request": {
|
||||
"name": "CallRequest",
|
||||
"type": "CallRequest",
|
||||
"values": [
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string",
|
||||
"values": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"response": {
|
||||
"name": "CallResponse",
|
||||
"type": "CallResponse",
|
||||
"values": [
|
||||
{
|
||||
"name": "msg",
|
||||
"type": "string",
|
||||
"values": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"nodes": [
|
||||
{
|
||||
"id": "helloworld-9660f06a-d608-43d9-9f44-e264ff63c554",
|
||||
"address": "172.26.165.161:45059",
|
||||
"metadata": {
|
||||
"broker": "http",
|
||||
"protocol": "mucp",
|
||||
"registry": "mdns",
|
||||
"server": "mucp",
|
||||
"transport": "http"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
You may pass the `--format=yaml` flag to output a YAML formatted object.
|
||||
|
||||
```bash
|
||||
$ gomu describe service --format=yaml helloworld
|
||||
name: helloworld
|
||||
version: latest
|
||||
metadata: {}
|
||||
endpoints:
|
||||
- name: Helloworld.Call
|
||||
request:
|
||||
name: CallRequest
|
||||
type: CallRequest
|
||||
values:
|
||||
- name: name
|
||||
type: string
|
||||
values: []
|
||||
response:
|
||||
name: CallResponse
|
||||
type: CallResponse
|
||||
values:
|
||||
- name: msg
|
||||
type: string
|
||||
values: []
|
||||
nodes:
|
||||
- id: helloworld-9660f06a-d608-43d9-9f44-e264ff63c554
|
||||
address: 172.26.165.161:45059
|
||||
metadata:
|
||||
broker: http
|
||||
protocol: mucp
|
||||
registry: mdns
|
||||
server: mucp
|
||||
transport: http
|
||||
```
|
||||
|
||||
## Calling A Service
|
||||
|
||||
To call a service, use the `gomu call` command. This will send a single request
|
||||
and expect a single response.
|
||||
|
||||
```bash
|
||||
$ gomu call helloworld Helloworld.Call '{"name": "John"}'
|
||||
{"msg":"Hello John"}
|
||||
```
|
||||
|
||||
To call a service's server stream, use the `gomu stream server` command. This
|
||||
will send a single request and expect a stream of responses.
|
||||
|
||||
```bash
|
||||
$ gomu stream server helloworld Helloworld.ServerStream '{"count": 10}'
|
||||
{"count":0}
|
||||
{"count":1}
|
||||
{"count":2}
|
||||
{"count":3}
|
||||
{"count":4}
|
||||
{"count":5}
|
||||
{"count":6}
|
||||
{"count":7}
|
||||
{"count":8}
|
||||
{"count":9}
|
||||
```
|
||||
|
||||
To call a service's bidirectional stream, use the `gomu stream bidi` command.
|
||||
This will send a stream of requests and expect a stream of responses.
|
||||
|
||||
```bash
|
||||
$ gomu stream bidi helloworld Helloworld.BidiStream '{"stroke": 1}' '{"stroke": 2}' '{"stroke": 3}'
|
||||
{"stroke":1}
|
||||
{"stroke":2}
|
||||
{"stroke":3}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This software is published under the [MIT license][10].
|
||||
|
||||
[1]: https://github.com/asim/go-micro
|
||||
[2]: https://golang.org/dl/
|
||||
[3]: https://golang.org/cmd/go/#hdr-Compile_and_install_packages_and_dependencies
|
||||
[4]: https://grpc.io/docs/protoc-installation/
|
||||
[5]: https://micro.mu/github.com/golang/protobuf/protoc-gen-go
|
||||
[6]: https://github.com/asim/go-micro/tree/master/cmd/protoc-gen-micro
|
||||
[7]: https://www.jaegertracing.io/
|
||||
[8]: https://github.com/jaegertracing/jaeger-client-go#environment-variables
|
||||
[9]: https://skaffold.dev/
|
||||
[10]: LICENSE
|
||||
@@ -1,63 +0,0 @@
|
||||
package call
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/cmd/gomu/cmd"
|
||||
"github.com/asim/go-micro/v3"
|
||||
"github.com/asim/go-micro/v3/client"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd.Register(&cli.Command{
|
||||
Name: "call",
|
||||
Usage: "Call a service, e.g. " + cmd.App().Name + " call helloworld Helloworld.Call '{\"name\": \"John\"}'",
|
||||
Action: RunCall,
|
||||
})
|
||||
}
|
||||
|
||||
// RunCall calls a service endpoint and prints its response. Exits on error.
|
||||
func RunCall(ctx *cli.Context) error {
|
||||
args := ctx.Args().Slice()
|
||||
if len(args) < 2 {
|
||||
return cli.ShowSubcommandHelp(ctx)
|
||||
}
|
||||
|
||||
service := args[0]
|
||||
endpoint := args[1]
|
||||
req := strings.Join(args[2:], " ")
|
||||
if len(req) == 0 {
|
||||
req = `{}`
|
||||
}
|
||||
|
||||
d := json.NewDecoder(strings.NewReader(req))
|
||||
d.UseNumber()
|
||||
|
||||
var creq map[string]interface{}
|
||||
if err := d.Decode(&creq); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srv := micro.NewService()
|
||||
srv.Init()
|
||||
c := srv.Client()
|
||||
|
||||
request := c.NewRequest(service, endpoint, creq, client.WithContentType("application/json"))
|
||||
var response map[string]interface{}
|
||||
|
||||
if err := c.Call(context.Background(), request, &response); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(b))
|
||||
return nil
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/call"
|
||||
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/describe"
|
||||
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/generate"
|
||||
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/new"
|
||||
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/run"
|
||||
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/services"
|
||||
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli/stream"
|
||||
)
|
||||
@@ -1,30 +0,0 @@
|
||||
package describe
|
||||
|
||||
import (
|
||||
"github.com/asim/go-micro/cmd/gomu/cmd"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var flags []cli.Flag = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "format",
|
||||
Value: "json",
|
||||
Usage: "output a formatted description, e.g. json or yaml",
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd.Register(&cli.Command{
|
||||
Name: "describe",
|
||||
Usage: "Describe a resource",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "service",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Describe a service resource, e.g. " + cmd.App().Name + " describe service helloworld",
|
||||
Action: Service,
|
||||
Flags: flags,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package describe
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/asim/go-micro/cmd/gomu/cmd"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Service fetches information for a service from the registry and prints it in
|
||||
// either JSON or YAML, depending on the format flag passed. Exits on error.
|
||||
func Service(ctx *cli.Context) error {
|
||||
args := ctx.Args().Slice()
|
||||
if len(args) < 1 {
|
||||
return cli.ShowSubcommandHelp(ctx)
|
||||
}
|
||||
if ctx.String("format") != "json" && ctx.String("format") != "yaml" {
|
||||
return cli.ShowSubcommandHelp(ctx)
|
||||
}
|
||||
|
||||
r := *cmd.DefaultOptions().Registry
|
||||
srvs, err := r.GetService(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(srvs) == 0 {
|
||||
return fmt.Errorf("service %s not found", args[0])
|
||||
}
|
||||
|
||||
for _, srv := range srvs {
|
||||
var b []byte
|
||||
var err error
|
||||
if ctx.String("format") == "json" {
|
||||
b, err = json.MarshalIndent(srv, "", " ")
|
||||
} else if ctx.String("format") == "yaml" {
|
||||
b, err = yaml.Marshal(srv)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/cmd/gomu/cmd"
|
||||
"github.com/asim/go-micro/cmd/gomu/generator"
|
||||
tmpl "github.com/asim/go-micro/cmd/gomu/generator/template"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd.Register(&cli.Command{
|
||||
Name: "generate",
|
||||
Usage: "Generate project template files after the fact",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "kubernetes",
|
||||
Usage: "Generate Kubernetes resource template files",
|
||||
Action: Kubernetes,
|
||||
},
|
||||
{
|
||||
Name: "skaffold",
|
||||
Usage: "Generate Skaffold template files",
|
||||
Action: Skaffold,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Kubernetes generates Kubernetes resource template files in the current
|
||||
// working directory. Exits on error.
|
||||
func Kubernetes(ctx *cli.Context) error {
|
||||
service, err := getService()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vendor, err := getServiceVendor(service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g := generator.New(
|
||||
generator.Service(service),
|
||||
generator.Vendor(vendor),
|
||||
generator.Directory("."),
|
||||
generator.Client(strings.HasSuffix(service, "-client")),
|
||||
)
|
||||
|
||||
files := []generator.File{
|
||||
{"plugins.go", tmpl.Plugins},
|
||||
{"resources/clusterrole.yaml", tmpl.KubernetesClusterRole},
|
||||
{"resources/configmap.yaml", tmpl.KubernetesEnv},
|
||||
{"resources/deployment.yaml", tmpl.KubernetesDeployment},
|
||||
{"resources/rolebinding.yaml", tmpl.KubernetesRoleBinding},
|
||||
}
|
||||
|
||||
g.Generate(files)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Skaffold generates Skaffold template files in the current working directory.
|
||||
// Exits on error.
|
||||
func Skaffold(ctx *cli.Context) error {
|
||||
service, err := getService()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vendor, err := getServiceVendor(service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
g := generator.New(
|
||||
generator.Service(service),
|
||||
generator.Vendor(vendor),
|
||||
generator.Directory("."),
|
||||
generator.Client(strings.HasSuffix(service, "-client")),
|
||||
generator.Skaffold(true),
|
||||
)
|
||||
|
||||
files := []generator.File{
|
||||
{".dockerignore", tmpl.DockerIgnore},
|
||||
{"go.mod", tmpl.Module},
|
||||
{"plugins.go", tmpl.Plugins},
|
||||
{"resources/clusterrole.yaml", tmpl.KubernetesClusterRole},
|
||||
{"resources/configmap.yaml", tmpl.KubernetesEnv},
|
||||
{"resources/deployment.yaml", tmpl.KubernetesDeployment},
|
||||
{"resources/rolebinding.yaml", tmpl.KubernetesRoleBinding},
|
||||
{"skaffold.yaml", tmpl.SkaffoldCFG},
|
||||
}
|
||||
|
||||
if err := g.Generate(files); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("skaffold project template files generated")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getService() (string, error) {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return dir[strings.LastIndex(dir, "/")+1:], nil
|
||||
}
|
||||
|
||||
func getServiceVendor(s string) (string, error) {
|
||||
f, err := os.Open("go.mod")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
line := ""
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
if strings.HasPrefix(scanner.Text(), "module ") {
|
||||
line = scanner.Text()
|
||||
break
|
||||
|
||||
}
|
||||
}
|
||||
if line == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
module := line[strings.LastIndex(line, " ")+1:]
|
||||
if module == s {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return module[:strings.LastIndex(module, "/")] + "/", nil
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
package new
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/cmd/gomu/cmd"
|
||||
"github.com/asim/go-micro/cmd/gomu/generator"
|
||||
tmpl "github.com/asim/go-micro/cmd/gomu/generator/template"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var flags []cli.Flag = []cli.Flag{
|
||||
&cli.BoolFlag{
|
||||
Name: "jaeger",
|
||||
Usage: "Generate Jaeger tracer files",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "kubernetes",
|
||||
Usage: "Generate Kubernetes resource files",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "skaffold",
|
||||
Usage: "Generate Skaffold files",
|
||||
},
|
||||
}
|
||||
|
||||
// NewCommand returns a new new cli command.
|
||||
func init() {
|
||||
cmd.Register(&cli.Command{
|
||||
Name: "new",
|
||||
Usage: "Create a project template",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "client",
|
||||
Usage: "Create a client template, e.g. " + cmd.App().Name + " new client [github.com/auditemarlow/]helloworld",
|
||||
Action: Client,
|
||||
Flags: flags,
|
||||
},
|
||||
{
|
||||
Name: "function",
|
||||
Usage: "Create a function template, e.g. " + cmd.App().Name + " new function [github.com/auditemarlow/]helloworld",
|
||||
Action: Function,
|
||||
Flags: flags,
|
||||
},
|
||||
{
|
||||
Name: "service",
|
||||
Usage: "Create a service template, e.g. " + cmd.App().Name + " new service [github.com/auditemarlow/]helloworld",
|
||||
Action: Service,
|
||||
Flags: flags,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func Client(ctx *cli.Context) error {
|
||||
return createProject(ctx, "client")
|
||||
}
|
||||
|
||||
// Function creates a new function project template. Exits on error.
|
||||
func Function(ctx *cli.Context) error {
|
||||
return createProject(ctx, "function")
|
||||
}
|
||||
|
||||
// Service creates a new service project template. Exits on error.
|
||||
func Service(ctx *cli.Context) error {
|
||||
return createProject(ctx, "service")
|
||||
}
|
||||
|
||||
func createProject(ctx *cli.Context, pt string) error {
|
||||
arg := ctx.Args().First()
|
||||
if len(arg) == 0 {
|
||||
return cli.ShowSubcommandHelp(ctx)
|
||||
}
|
||||
|
||||
client := pt == "client"
|
||||
name, vendor := getNameAndVendor(arg)
|
||||
|
||||
dir := name
|
||||
if client {
|
||||
dir += "-client"
|
||||
}
|
||||
|
||||
if path.IsAbs(dir) {
|
||||
fmt.Println("must provide a relative path as service name")
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := os.Stat(dir); !os.IsNotExist(err) {
|
||||
return fmt.Errorf("%s already exists", dir)
|
||||
}
|
||||
|
||||
fmt.Printf("creating %s %s\n", pt, name)
|
||||
|
||||
g := generator.New(
|
||||
generator.Service(name),
|
||||
generator.Vendor(vendor),
|
||||
generator.Directory(dir),
|
||||
generator.Client(client),
|
||||
generator.Jaeger(ctx.Bool("jaeger")),
|
||||
generator.Skaffold(ctx.Bool("skaffold")),
|
||||
)
|
||||
|
||||
files := []generator.File{
|
||||
{".dockerignore", tmpl.DockerIgnore},
|
||||
{".gitignore", tmpl.GitIgnore},
|
||||
{"Dockerfile", tmpl.Dockerfile},
|
||||
{"Makefile", tmpl.Makefile},
|
||||
{"go.mod", tmpl.Module},
|
||||
}
|
||||
|
||||
switch pt {
|
||||
case "client":
|
||||
files = append(files, []generator.File{
|
||||
{"main.go", tmpl.MainCLT},
|
||||
}...)
|
||||
case "function":
|
||||
files = append(files, []generator.File{
|
||||
{"handler/" + name + ".go", tmpl.HandlerFNC},
|
||||
{"main.go", tmpl.MainFNC},
|
||||
{"proto/" + name + ".proto", tmpl.ProtoFNC},
|
||||
}...)
|
||||
case "service":
|
||||
files = append(files, []generator.File{
|
||||
{"handler/" + name + ".go", tmpl.HandlerSRV},
|
||||
{"main.go", tmpl.MainSRV},
|
||||
{"proto/" + name + ".proto", tmpl.ProtoSRV},
|
||||
}...)
|
||||
default:
|
||||
return fmt.Errorf("%s project type not supported", pt)
|
||||
}
|
||||
|
||||
if ctx.Bool("kubernetes") || ctx.Bool("skaffold") {
|
||||
files = append(files, []generator.File{
|
||||
{"plugins.go", tmpl.Plugins},
|
||||
{"resources/clusterrole.yaml", tmpl.KubernetesClusterRole},
|
||||
{"resources/configmap.yaml", tmpl.KubernetesEnv},
|
||||
{"resources/deployment.yaml", tmpl.KubernetesDeployment},
|
||||
{"resources/rolebinding.yaml", tmpl.KubernetesRoleBinding},
|
||||
}...)
|
||||
}
|
||||
|
||||
if ctx.Bool("skaffold") {
|
||||
files = append(files, []generator.File{
|
||||
{"skaffold.yaml", tmpl.SkaffoldCFG},
|
||||
}...)
|
||||
}
|
||||
|
||||
if err := g.Generate(files); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var comments []string
|
||||
if client {
|
||||
comments = clientComments(name, dir)
|
||||
} else {
|
||||
comments = protoComments(name, dir)
|
||||
}
|
||||
|
||||
for _, comment := range comments {
|
||||
fmt.Println(comment)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func clientComments(name, dir string) []string {
|
||||
return []string{
|
||||
"cd " + dir,
|
||||
"make tidy\n",
|
||||
}
|
||||
}
|
||||
|
||||
func protoComments(name, dir string) []string {
|
||||
return []string{
|
||||
"\ndownload protoc zip packages (protoc-$VERSION-$PLATFORM.zip) and install:\n",
|
||||
"visit https://github.com/protocolbuffers/protobuf/releases/latest",
|
||||
"\ndownload protobuf for go-micro:\n",
|
||||
"go get -u google.golang.org/protobuf/proto",
|
||||
"go install github.com/golang/protobuf/protoc-gen-go@latest",
|
||||
"go install github.com/asim/go-micro/cmd/protoc-gen-micro/v3@latest",
|
||||
"\ncompile the proto file " + name + ".proto:\n",
|
||||
"cd " + dir,
|
||||
"make proto tidy\n",
|
||||
}
|
||||
}
|
||||
|
||||
func getNameAndVendor(s string) (string, string) {
|
||||
var n string
|
||||
var v string
|
||||
|
||||
if i := strings.LastIndex(s, "/"); i == -1 {
|
||||
n = s
|
||||
v = ""
|
||||
} else {
|
||||
n = s[i+1:]
|
||||
v = s[:i+1]
|
||||
}
|
||||
|
||||
return n, v
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
package run
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/cmd/gomu/cmd"
|
||||
"github.com/asim/go-micro/v3/runtime"
|
||||
"github.com/asim/go-micro/v3/runtime/local/git"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultRetries = 3
|
||||
|
||||
flags []cli.Flag = []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "command",
|
||||
Usage: "command to execute",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "args",
|
||||
Usage: "command arguments",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "type",
|
||||
Usage: "the type of service to operate on",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd.Register(&cli.Command{
|
||||
Name: "run",
|
||||
Usage: "Build and run a service continuously, e.g. gomu run [github.com/auditemarlow/helloworld]",
|
||||
Flags: flags,
|
||||
Action: Run,
|
||||
})
|
||||
}
|
||||
|
||||
// Run runs a service and watches the project directory for change events. On
|
||||
// write, the service is restarted. Exits on error.
|
||||
func Run(ctx *cli.Context) error {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
source, err := git.ParseSourceLocal(wd, ctx.Args().First())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
svc := &runtime.Service{
|
||||
Name: source.RuntimeName(),
|
||||
Source: source.RuntimeSource(),
|
||||
Version: source.Ref,
|
||||
Metadata: make(map[string]string),
|
||||
}
|
||||
|
||||
typ := ctx.String("type")
|
||||
command := strings.TrimSpace(ctx.String("command"))
|
||||
args := strings.TrimSpace(ctx.String("args"))
|
||||
|
||||
r := *cmd.DefaultCmd.Options().Runtime
|
||||
|
||||
var retries = DefaultRetries
|
||||
if ctx.IsSet("retries") {
|
||||
retries = ctx.Int("retries")
|
||||
}
|
||||
|
||||
opts := []runtime.CreateOption{
|
||||
runtime.WithOutput(os.Stdout),
|
||||
runtime.WithRetries(retries),
|
||||
runtime.CreateType(typ),
|
||||
}
|
||||
|
||||
if len(command) > 0 {
|
||||
opts = append(opts, runtime.WithCommand(command))
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
opts = append(opts, runtime.WithArgs(args))
|
||||
}
|
||||
|
||||
if err := r.Create(svc, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
done := make(chan bool)
|
||||
if r.String() == "local" {
|
||||
sig := make(chan os.Signal)
|
||||
signal.Notify(sig, os.Interrupt)
|
||||
go func() {
|
||||
<-sig
|
||||
r.Delete(svc)
|
||||
done <- true
|
||||
}()
|
||||
}
|
||||
|
||||
if source.Local {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
defer watcher.Close()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-watcher.Events:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||
r.Update(svc)
|
||||
}
|
||||
if event.Op&fsnotify.Create == fsnotify.Create {
|
||||
watcher.Add(event.Name)
|
||||
}
|
||||
if event.Op&fsnotify.Remove == fsnotify.Remove {
|
||||
watcher.Remove(event.Name)
|
||||
}
|
||||
case err, ok := <-watcher.Errors:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
fmt.Println("ERROR", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
var files []string
|
||||
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
files = append(files, path)
|
||||
return nil
|
||||
})
|
||||
|
||||
for _, file := range files {
|
||||
if err := watcher.Add(file); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if r.String() == "local" {
|
||||
<-done
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/asim/go-micro/cmd/gomu/cmd"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd.Register(&cli.Command{
|
||||
Name: "services",
|
||||
Usage: "List services in the registry",
|
||||
Action: List,
|
||||
})
|
||||
}
|
||||
|
||||
// List fetches running services from the registry and lists them. Exits on
|
||||
// error.
|
||||
func List(ctx *cli.Context) error {
|
||||
r := *cmd.DefaultOptions().Registry
|
||||
srvs, err := r.ListServices()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var services []string
|
||||
for _, srv := range srvs {
|
||||
services = append(services, srv.Name)
|
||||
}
|
||||
|
||||
sort.Strings(services)
|
||||
for _, srv := range services {
|
||||
fmt.Println(srv)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/v3"
|
||||
"github.com/asim/go-micro/v3/client"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Bidirectional streams client requests and prints the server stream responses
|
||||
// it receives. Exits on error.
|
||||
func Bidirectional(ctx *cli.Context) error {
|
||||
args := ctx.Args().Slice()
|
||||
if len(args) < 2 {
|
||||
return cli.ShowSubcommandHelp(ctx)
|
||||
}
|
||||
|
||||
service := args[0]
|
||||
endpoint := args[1]
|
||||
requests := args[2:]
|
||||
|
||||
srv := micro.NewService()
|
||||
srv.Init()
|
||||
c := srv.Client()
|
||||
|
||||
var r interface{}
|
||||
request := c.NewRequest(service, endpoint, r, client.WithContentType("application/json"))
|
||||
var rsp map[string]interface{}
|
||||
stream, err := c.Stream(ctx.Context, request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, req := range requests {
|
||||
d := json.NewDecoder(strings.NewReader(req))
|
||||
d.UseNumber()
|
||||
|
||||
var creq map[string]interface{}
|
||||
if err := d.Decode(&creq); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := stream.Send(creq); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := stream.Recv(&rsp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(rsp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
if stream.Error() != nil {
|
||||
return stream.Error()
|
||||
}
|
||||
if err := stream.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/v3"
|
||||
"github.com/asim/go-micro/v3/client"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
// Server sends a single client request and prints the server stream responses
|
||||
// it receives. Exits on error.
|
||||
func Server(ctx *cli.Context) error {
|
||||
args := ctx.Args().Slice()
|
||||
if len(args) < 2 {
|
||||
return cli.ShowSubcommandHelp(ctx)
|
||||
}
|
||||
|
||||
service := args[0]
|
||||
endpoint := args[1]
|
||||
req := strings.Join(args[2:], " ")
|
||||
if len(req) == 0 {
|
||||
req = `{}`
|
||||
}
|
||||
|
||||
d := json.NewDecoder(strings.NewReader(req))
|
||||
d.UseNumber()
|
||||
|
||||
var creq map[string]interface{}
|
||||
if err := d.Decode(&creq); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srv := micro.NewService()
|
||||
srv.Init()
|
||||
c := srv.Client()
|
||||
|
||||
var r interface{}
|
||||
request := c.NewRequest(service, endpoint, r, client.WithContentType("application/json"))
|
||||
|
||||
stream, err := c.Stream(context.Background(), request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := stream.Send(creq); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for stream.Error() == nil {
|
||||
rsp := &map[string]interface{}{}
|
||||
err := stream.Recv(rsp)
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := json.Marshal(rsp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
if stream.Error() != nil {
|
||||
return stream.Error()
|
||||
}
|
||||
if err := stream.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package stream
|
||||
|
||||
import (
|
||||
"github.com/asim/go-micro/cmd/gomu/cmd"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd.Register(&cli.Command{
|
||||
Name: "stream",
|
||||
Usage: "Create a service stream",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "bidi",
|
||||
Aliases: []string{"b"},
|
||||
Usage: "Create a bidirectional service stream, e.g. " + cmd.App().Name + " stream bidirectional helloworld Helloworld.PingPong '{\"stroke\": 1}' '{\"stroke\": 2}'",
|
||||
Action: Bidirectional,
|
||||
},
|
||||
{
|
||||
Name: "server",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "Create a server service stream, e.g. " + cmd.App().Name + " stream server helloworld Helloworld.ServerStream '{\"count\": 10}'",
|
||||
Action: Server,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
mcmd "github.com/asim/go-micro/v3/cmd"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultCmd is the default, unmodified root command.
|
||||
DefaultCmd Cmd = NewCmd()
|
||||
|
||||
name string = "gomu"
|
||||
description string = "The Go Micro CLI tool"
|
||||
version string = "latest"
|
||||
)
|
||||
|
||||
// Cmd is the interface that wraps the cli app.
|
||||
//
|
||||
// Cmd embeds the Cmd interface from the github.com/asim/go-micro/v3/cmd
|
||||
// package and adds a Run method.
|
||||
//
|
||||
// Run runs the cli app within this command and exits on error.
|
||||
type Cmd interface {
|
||||
mcmd.Cmd
|
||||
Run() error
|
||||
}
|
||||
|
||||
type cmd struct {
|
||||
app *cli.App
|
||||
opts mcmd.Options
|
||||
}
|
||||
|
||||
// App returns the cli app within this command.
|
||||
func (c *cmd) App() *cli.App {
|
||||
return c.app
|
||||
}
|
||||
|
||||
// Options returns the options set within this command.
|
||||
func (c *cmd) Options() mcmd.Options {
|
||||
return c.opts
|
||||
}
|
||||
|
||||
// Init adds options, parses flags and exits on error.
|
||||
func (c *cmd) Init(opts ...mcmd.Option) error {
|
||||
return mcmd.Init(opts...)
|
||||
}
|
||||
|
||||
// Run runs the cli app within this command and exits on error.
|
||||
func (c *cmd) Run() error {
|
||||
return c.app.Run(os.Args)
|
||||
}
|
||||
|
||||
// DefaultOptions returns the options passed to the default command.
|
||||
func DefaultOptions() mcmd.Options {
|
||||
return DefaultCmd.Options()
|
||||
}
|
||||
|
||||
// App returns the cli app within the default command.
|
||||
func App() *cli.App {
|
||||
return DefaultCmd.App()
|
||||
}
|
||||
|
||||
// Register appends commands to the default app.
|
||||
func Register(cmds ...*cli.Command) {
|
||||
app := DefaultCmd.App()
|
||||
app.Commands = append(app.Commands, cmds...)
|
||||
}
|
||||
|
||||
// Run runs the cli app within the default command. On error, it prints the
|
||||
// error message and exits.
|
||||
func Run() {
|
||||
if err := DefaultCmd.Run(); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// NewCmd returns a new command.
|
||||
func NewCmd(opts ...mcmd.Option) Cmd {
|
||||
options := mcmd.DefaultOptions()
|
||||
|
||||
// Clear the name, version and description parameters from the default
|
||||
// options so the options passed may override them.
|
||||
options.Name = ""
|
||||
options.Version = ""
|
||||
options.Description = ""
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
if len(options.Name) == 0 {
|
||||
options.Name = name
|
||||
}
|
||||
if len(options.Description) == 0 {
|
||||
options.Description = description
|
||||
}
|
||||
if len(options.Version) == 0 {
|
||||
options.Version = version
|
||||
}
|
||||
|
||||
c := new(cmd)
|
||||
c.opts = options
|
||||
c.app = cli.NewApp()
|
||||
c.app.Name = c.opts.Name
|
||||
c.app.Usage = c.opts.Description
|
||||
c.app.Version = c.opts.Version
|
||||
c.app.Flags = mcmd.DefaultFlags
|
||||
|
||||
if len(options.Version) == 0 {
|
||||
c.app.HideVersion = true
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package jaeger
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
jaegercfg "github.com/uber/jaeger-client-go/config"
|
||||
)
|
||||
|
||||
// NewTracer returns a new Jaeger tracer based on the current configuration,
|
||||
// using the given options, and a closer func that can be used to flush buffers
|
||||
// before shutdown.
|
||||
func NewTracer(opts ...Option) (opentracing.Tracer, io.Closer, error) {
|
||||
options := newOptions(opts...)
|
||||
|
||||
cfg := &jaegercfg.Configuration{}
|
||||
if options.FromEnv {
|
||||
c, err := jaegercfg.FromEnv()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cfg = c
|
||||
}
|
||||
|
||||
if options.Name != "" {
|
||||
cfg.ServiceName = options.Name
|
||||
}
|
||||
|
||||
var jOptions []jaegercfg.Option
|
||||
if options.Logger != nil {
|
||||
jOptions = append(jOptions, jaegercfg.Logger(options.Logger))
|
||||
}
|
||||
if options.Metrics != nil {
|
||||
jOptions = append(jOptions, jaegercfg.Metrics(options.Metrics))
|
||||
}
|
||||
|
||||
tracer, closer, err := cfg.NewTracer(jOptions...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if options.GlobalTracer {
|
||||
opentracing.SetGlobalTracer(tracer)
|
||||
}
|
||||
|
||||
return tracer, closer, nil
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package jaeger
|
||||
|
||||
import (
|
||||
"github.com/uber/jaeger-client-go"
|
||||
"github.com/uber/jaeger-lib/metrics"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultLogger is the default Jaeger logger.
|
||||
DefaultLogger = jaeger.StdLogger
|
||||
|
||||
// DefaultMetrics is the default Jaeger metrics factory.
|
||||
DefaultMetrics = metrics.NullFactory
|
||||
)
|
||||
|
||||
// Options represents the options passed to the Jaeger tracer.
|
||||
type Options struct {
|
||||
Name string
|
||||
FromEnv bool
|
||||
GlobalTracer bool
|
||||
Logger jaeger.Logger
|
||||
Metrics metrics.Factory
|
||||
}
|
||||
|
||||
// Option manipulates the passed Options struct.
|
||||
type Option func(o *Options)
|
||||
|
||||
func newOptions(opts ...Option) Options {
|
||||
options := Options{
|
||||
Logger: DefaultLogger,
|
||||
Metrics: DefaultMetrics,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
// Name sets the service name for the Jaeger tracer.
|
||||
func Name(s string) Option {
|
||||
return func(o *Options) {
|
||||
o.Name = s
|
||||
}
|
||||
}
|
||||
|
||||
// FromEnv determines whether the Jaeger tracer configuration should use
|
||||
// environment variables.
|
||||
func FromEnv(e bool) Option {
|
||||
return func(o *Options) {
|
||||
o.FromEnv = e
|
||||
}
|
||||
}
|
||||
|
||||
// GlobalTracer determines whether the Jaeger tracer should be set as the
|
||||
// global tracer.
|
||||
func GlobalTracer(e bool) Option {
|
||||
return func(o *Options) {
|
||||
o.GlobalTracer = e
|
||||
}
|
||||
}
|
||||
|
||||
// Logger sets the logger for the Jaeger tracer.
|
||||
func Logger(l jaeger.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = l
|
||||
}
|
||||
}
|
||||
|
||||
// Metrics sets the metrics factory for the Jaeger tracer.
|
||||
func Metrics(m metrics.Factory) Option {
|
||||
return func(o *Options) {
|
||||
o.Metrics = m
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package trace
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
)
|
||||
|
||||
// NewSpan accepts a context and returns an OpenTracing span. Can be used to
|
||||
// nest spans.
|
||||
func NewSpan(ctx context.Context) opentracing.Span {
|
||||
pc := make([]uintptr, 10) // at least 1 entry needed
|
||||
runtime.Callers(2, pc)
|
||||
span := opentracing.StartSpan(
|
||||
runtime.FuncForPC(pc[0]).Name(),
|
||||
opentracing.ChildOf(opentracing.SpanFromContext(ctx).Context()),
|
||||
)
|
||||
return span
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package generator
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Generator is the interface that generates project template files.
|
||||
//
|
||||
// Generate accepts a list of files and generates them based on their template.
|
||||
type Generator interface {
|
||||
Generate([]File) error
|
||||
}
|
||||
|
||||
type generator struct {
|
||||
opts Options
|
||||
}
|
||||
|
||||
// File represents a file to generate.
|
||||
type File struct {
|
||||
// Path specifies where the file will reside.
|
||||
Path string
|
||||
// Template is the template used to generate the file.
|
||||
Template string
|
||||
}
|
||||
|
||||
// Generate generates project template files.
|
||||
func (g *generator) Generate(files []File) error {
|
||||
for _, file := range files {
|
||||
fp := filepath.Join(g.opts.Directory, file.Path)
|
||||
dir := filepath.Dir(fp)
|
||||
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
f, err := os.Create(fp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fn := template.FuncMap{
|
||||
"dehyphen": func(s string) string {
|
||||
return strings.ReplaceAll(s, "-", "")
|
||||
},
|
||||
"lower": strings.ToLower,
|
||||
"title": func(s string) string {
|
||||
return strings.ReplaceAll(strings.Title(s), "-", "")
|
||||
},
|
||||
}
|
||||
t, err := template.New(fp).Funcs(fn).Parse(file.Template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = t.Execute(f, g.opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// New returns a new generator struct.
|
||||
func New(opts ...Option) Generator {
|
||||
var options Options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &generator{
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package generator
|
||||
|
||||
// Options represents the options for the generator.
|
||||
type Options struct {
|
||||
// Service is the name of the service the generator will generate files
|
||||
// for.
|
||||
Service string
|
||||
// Vendor is the service vendor.
|
||||
Vendor string
|
||||
// Directory is the directory where the files will be generated to.
|
||||
Directory string
|
||||
|
||||
// Client determines whether or not the project is a client project.
|
||||
Client bool
|
||||
// Jaeger determines whether or not Jaeger integration is enabled.
|
||||
Jaeger bool
|
||||
// Jaeger determines whether or not Skaffold integration is enabled.
|
||||
Skaffold bool
|
||||
}
|
||||
|
||||
// Option manipulates the Options passed.
|
||||
type Option func(o *Options)
|
||||
|
||||
// Service sets the service name.
|
||||
func Service(s string) Option {
|
||||
return func(o *Options) {
|
||||
o.Service = s
|
||||
}
|
||||
}
|
||||
|
||||
// Vendor sets the service vendor.
|
||||
func Vendor(v string) Option {
|
||||
return func(o *Options) {
|
||||
o.Vendor = v
|
||||
}
|
||||
}
|
||||
|
||||
// Directory sets the directory in which files are generated.
|
||||
func Directory(d string) Option {
|
||||
return func(o *Options) {
|
||||
o.Directory = d
|
||||
}
|
||||
}
|
||||
|
||||
// Client sets whether or not the project is a client project.
|
||||
func Client(c bool) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
}
|
||||
}
|
||||
|
||||
// Jaeger sets whether or not Jaeger integration is enabled.
|
||||
func Jaeger(j bool) Option {
|
||||
return func(o *Options) {
|
||||
o.Jaeger = j
|
||||
}
|
||||
}
|
||||
|
||||
// Skaffold sets whether or not Skaffold integration is enabled.
|
||||
func Skaffold(s bool) Option {
|
||||
return func(o *Options) {
|
||||
o.Skaffold = s
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package template
|
||||
|
||||
// Dockerfile is the Dockerfile template used for new projects.
|
||||
var Dockerfile = `FROM golang:alpine AS builder
|
||||
ENV CGO_ENABLED=0 GOOS=linux
|
||||
WORKDIR /go/src/{{.Service}}{{if .Client}}-client{{end}}
|
||||
RUN apk --update --no-cache add ca-certificates gcc libtool make musl-dev protoc
|
||||
COPY {{if not .Client}}Makefile {{end}}go.mod go.sum ./
|
||||
RUN {{if not .Client}}make init && {{end}}go mod download
|
||||
COPY . .
|
||||
RUN make {{if not .Client}}proto {{end}}tidy build
|
||||
|
||||
FROM scratch
|
||||
COPY --from=builder /etc/ssl/certs /etc/ssl/certs
|
||||
COPY --from=builder /go/src/{{.Service}}{{if .Client}}-client{{end}}/{{.Service}}{{if .Client}}-client{{end}} /{{.Service}}{{if .Client}}-client{{end}}
|
||||
ENTRYPOINT ["/{{.Service}}{{if .Client}}-client{{end}}"]
|
||||
CMD []
|
||||
`
|
||||
|
||||
// DockerIgnore is the .dockerignore template used for new projects.
|
||||
var DockerIgnore = `.gitignore
|
||||
Dockerfile{{if .Skaffold}}
|
||||
resources/
|
||||
skaffold.yaml{{end}}
|
||||
`
|
||||
@@ -1,6 +0,0 @@
|
||||
package template
|
||||
|
||||
// GitIgnore is the .gitignore template used for new projects.
|
||||
var GitIgnore = `# don't commit the service binary to vcs
|
||||
{{.Service}}{{if .Client}}-client{{end}}
|
||||
`
|
||||
@@ -1,89 +0,0 @@
|
||||
package template
|
||||
|
||||
// HandlerFNC is the handler template used for new function projects.
|
||||
var HandlerFNC = `package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
log "github.com/asim/go-micro/v3/logger"
|
||||
|
||||
pb "{{.Vendor}}{{.Service}}/proto"
|
||||
)
|
||||
|
||||
type {{title .Service}} struct{}
|
||||
|
||||
func (e *{{title .Service}}) Call(ctx context.Context, req *pb.CallRequest, rsp *pb.CallResponse) error {
|
||||
log.Infof("Received {{title .Service}}.Call request: %v", req)
|
||||
rsp.Msg = "Hello " + req.Name
|
||||
return nil
|
||||
}
|
||||
`
|
||||
|
||||
// HandlerSRV is the handler template used for new service projects.
|
||||
var HandlerSRV = `package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
log "github.com/asim/go-micro/v3/logger"
|
||||
|
||||
pb "{{.Vendor}}{{.Service}}/proto"
|
||||
)
|
||||
|
||||
type {{title .Service}} struct{}
|
||||
|
||||
func (e *{{title .Service}}) Call(ctx context.Context, req *pb.CallRequest, rsp *pb.CallResponse) error {
|
||||
log.Infof("Received {{title .Service}}.Call request: %v", req)
|
||||
rsp.Msg = "Hello " + req.Name
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *{{title .Service}}) ClientStream(ctx context.Context, stream pb.{{title .Service}}_ClientStreamStream) error {
|
||||
var count int64
|
||||
for {
|
||||
req, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
log.Infof("Got %v pings total", count)
|
||||
return stream.SendMsg(&pb.ClientStreamResponse{Count: count})
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("Got ping %v", req.Stroke)
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
func (e *{{title .Service}}) ServerStream(ctx context.Context, req *pb.ServerStreamRequest, stream pb.{{title .Service}}_ServerStreamStream) error {
|
||||
log.Infof("Received {{title .Service}}.ServerStream request: %v", req)
|
||||
for i := 0; i < int(req.Count); i++ {
|
||||
log.Infof("Sending %d", i)
|
||||
if err := stream.Send(&pb.ServerStreamResponse{
|
||||
Count: int64(i),
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
time.Sleep(time.Millisecond * 250)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *{{title .Service}}) BidiStream(ctx context.Context, stream pb.{{title .Service}}_BidiStreamStream) error {
|
||||
for {
|
||||
req, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("Got ping %v", req.Stroke)
|
||||
if err := stream.Send(&pb.BidiStreamResponse{Stroke: req.Stroke}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
@@ -1,78 +0,0 @@
|
||||
package template
|
||||
|
||||
// KubernetesEnv is a Kubernetes configmap manifest template used for
|
||||
// environment variables in new projects.
|
||||
var KubernetesEnv = `---
|
||||
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{.Service}}{{if .Client}}-client{{end}}-env
|
||||
data:
|
||||
MICRO_REGISTRY: kubernetes
|
||||
`
|
||||
|
||||
// KubernetesClusterRole is a Kubernetes cluster role manifest template
|
||||
// required for the Kubernetes registry plugin to function correctly.
|
||||
var KubernetesClusterRole = `---
|
||||
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: micro-registry
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
verbs:
|
||||
- list
|
||||
- patch
|
||||
- watch
|
||||
`
|
||||
|
||||
// KubernetesRoleBinding is a Kubernetes role binding manifest template
|
||||
// required for the Kubernetes registry plugin to function correctly.
|
||||
var KubernetesRoleBinding = `---
|
||||
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: micro-registry
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: micro-registry
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: default
|
||||
`
|
||||
|
||||
// KubernetesDeployment is a Kubernetes deployment manifest template used for
|
||||
// new projects.
|
||||
var KubernetesDeployment = `---
|
||||
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{.Service}}{{if .Client}}-client{{end}}
|
||||
labels:
|
||||
app: {{.Service}}{{if .Client}}-client{{end}}
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{.Service}}{{if .Client}}-client{{end}}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{.Service}}{{if .Client}}-client{{end}}
|
||||
spec:
|
||||
containers:
|
||||
- name: {{.Service}}{{if .Client}}-client{{end}}
|
||||
image: {{.Service}}{{if .Client}}-client{{end}}:latest
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{.Service}}{{if .Client}}-client{{end}}-env
|
||||
`
|
||||
@@ -1,144 +0,0 @@
|
||||
package template
|
||||
|
||||
// MainCLT is the main template used for new client projects.
|
||||
var MainCLT = `package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
pb "{{.Vendor}}{{lower .Service}}/proto"
|
||||
|
||||
"github.com/asim/go-micro/v3"
|
||||
log "github.com/asim/go-micro/v3/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
service = "{{lower .Service}}"
|
||||
version = "latest"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create service
|
||||
srv := micro.NewService()
|
||||
srv.Init()
|
||||
|
||||
// Create client
|
||||
c := pb.NewHelloworldService(service, srv.Client())
|
||||
|
||||
for {
|
||||
// Call service
|
||||
rsp, err := c.Call(context.Background(), &pb.CallRequest{Name: "John"})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Info(rsp)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// MainFNC is the main template used for new function projects.
|
||||
var MainFNC = `package main
|
||||
|
||||
import (
|
||||
"{{.Vendor}}{{.Service}}/handler"
|
||||
|
||||
{{if .Jaeger}} ot "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
|
||||
{{end}} "github.com/asim/go-micro/v3"
|
||||
log "github.com/asim/go-micro/v3/logger"{{if .Jaeger}}
|
||||
|
||||
"github.com/asim/go-micro/cmd/gomu/debug/trace/jaeger"{{end}}
|
||||
)
|
||||
|
||||
var (
|
||||
service = "{{lower .Service}}"
|
||||
version = "latest"
|
||||
)
|
||||
|
||||
func main() {
|
||||
{{if .Jaeger}} // Create tracer
|
||||
tracer, closer, err := jaeger.NewTracer(
|
||||
jaeger.Name(service),
|
||||
jaeger.FromEnv(true),
|
||||
jaeger.GlobalTracer(true),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer closer.Close()
|
||||
|
||||
{{end}} // Create function
|
||||
fnc := micro.NewFunction(
|
||||
micro.Name(service),
|
||||
micro.Version(version),
|
||||
{{if .Jaeger}} micro.WrapCall(ot.NewCallWrapper(tracer)),
|
||||
micro.WrapClient(ot.NewClientWrapper(tracer)),
|
||||
micro.WrapHandler(ot.NewHandlerWrapper(tracer)),
|
||||
micro.WrapSubscriber(ot.NewSubscriberWrapper(tracer)),
|
||||
{{end}} )
|
||||
fnc.Init()
|
||||
|
||||
// Handle function
|
||||
fnc.Handle(new(handler.{{title .Service}}))
|
||||
|
||||
// Run function
|
||||
if err := fnc.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
// MainSRV is the main template used for new service projects.
|
||||
var MainSRV = `package main
|
||||
|
||||
import (
|
||||
"{{.Vendor}}{{.Service}}/handler"
|
||||
pb "{{.Vendor}}{{.Service}}/proto"
|
||||
|
||||
{{if .Jaeger}} ot "github.com/asim/go-micro/plugins/wrapper/trace/opentracing/v3"
|
||||
{{end}} "github.com/asim/go-micro/v3"
|
||||
log "github.com/asim/go-micro/v3/logger"{{if .Jaeger}}
|
||||
|
||||
"github.com/asim/go-micro/cmd/gomu/debug/trace/jaeger"{{end}}
|
||||
)
|
||||
|
||||
var (
|
||||
service = "{{lower .Service}}"
|
||||
version = "latest"
|
||||
)
|
||||
|
||||
func main() {
|
||||
{{if .Jaeger}} // Create tracer
|
||||
tracer, closer, err := jaeger.NewTracer(
|
||||
jaeger.Name(service),
|
||||
jaeger.FromEnv(true),
|
||||
jaeger.GlobalTracer(true),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer closer.Close()
|
||||
|
||||
{{end}} // Create service
|
||||
srv := micro.NewService(
|
||||
micro.Name(service),
|
||||
micro.Version(version),
|
||||
{{if .Jaeger}} micro.WrapCall(ot.NewCallWrapper(tracer)),
|
||||
micro.WrapClient(ot.NewClientWrapper(tracer)),
|
||||
micro.WrapHandler(ot.NewHandlerWrapper(tracer)),
|
||||
micro.WrapSubscriber(ot.NewSubscriberWrapper(tracer)),
|
||||
{{end}} )
|
||||
srv.Init()
|
||||
|
||||
// Register handler
|
||||
pb.Register{{title .Service}}Handler(srv.Server(), new(handler.{{title .Service}}))
|
||||
|
||||
// Run service
|
||||
if err := srv.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
`
|
||||
@@ -1,31 +0,0 @@
|
||||
package template
|
||||
|
||||
// Makefile is the Makefile template used for new projects.
|
||||
var Makefile = `GOPATH:=$(shell go env GOPATH)
|
||||
|
||||
.PHONY: init
|
||||
init:
|
||||
@go get -u google.golang.org/protobuf/proto
|
||||
@go install github.com/golang/protobuf/protoc-gen-go@latest
|
||||
@go install github.com/asim/go-micro/cmd/protoc-gen-micro/v3@latest
|
||||
|
||||
.PHONY: proto
|
||||
proto:
|
||||
@protoc --proto_path=. --micro_out=. --go_out=:. proto/{{.Service}}.proto
|
||||
|
||||
.PHONY: tidy
|
||||
tidy:
|
||||
@go mod tidy
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
@go build -o {{.Service}}{{if .Client}}-client{{end}} *.go
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
@go test -v ./... -cover
|
||||
|
||||
.PHONY: docker
|
||||
docker:
|
||||
@docker build -t {{.Service}}{{if .Client}}-client{{end}}:latest .
|
||||
`
|
||||
@@ -1,17 +0,0 @@
|
||||
package template
|
||||
|
||||
// Module is the go.mod template used for new projects.
|
||||
var Module = `module {{.Vendor}}{{.Service}}{{if .Client}}-client{{end}}
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/asim/go-micro/v3 v3.5.2
|
||||
)
|
||||
|
||||
// This can be removed once etcd becomes go gettable, version 3.4 and 3.5 is not,
|
||||
// see https://github.com/etcd-io/etcd/issues/11154 and https://github.com/etcd-io/etcd/issues/11931.
|
||||
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0{{if .Vendor}}{{if not .Skaffold}}
|
||||
|
||||
replace {{.Vendor}}{{lower .Service}} => ../{{lower .Service}}{{end}}{{end}}
|
||||
`
|
||||
@@ -1,9 +0,0 @@
|
||||
package template
|
||||
|
||||
// Plugins is the plugins template used for new projects.
|
||||
var Plugins = `package main
|
||||
|
||||
import (
|
||||
_ "github.com/asim/go-micro/plugins/registry/kubernetes/v3"
|
||||
)
|
||||
`
|
||||
@@ -1,68 +0,0 @@
|
||||
package template
|
||||
|
||||
// ProtoFNC is the .proto file template used for new function projects.
|
||||
var ProtoFNC = `syntax = "proto3";
|
||||
|
||||
package {{dehyphen .Service}};
|
||||
|
||||
option go_package = "./proto;{{dehyphen .Service}}";
|
||||
|
||||
service {{title .Service}} {
|
||||
rpc Call(CallRequest) returns (CallResponse) {}
|
||||
}
|
||||
|
||||
message CallRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message CallResponse {
|
||||
string msg = 1;
|
||||
}
|
||||
`
|
||||
|
||||
// ProtoSRV is the .proto file template used for new service projects.
|
||||
var ProtoSRV = `syntax = "proto3";
|
||||
|
||||
package {{dehyphen .Service}};
|
||||
|
||||
option go_package = "./proto;{{dehyphen .Service}}";
|
||||
|
||||
service {{title .Service}} {
|
||||
rpc Call(CallRequest) returns (CallResponse) {}
|
||||
rpc ClientStream(stream ClientStreamRequest) returns (ClientStreamResponse) {}
|
||||
rpc ServerStream(ServerStreamRequest) returns (stream ServerStreamResponse) {}
|
||||
rpc BidiStream(stream BidiStreamRequest) returns (stream BidiStreamResponse) {}
|
||||
}
|
||||
|
||||
message CallRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message CallResponse {
|
||||
string msg = 1;
|
||||
}
|
||||
|
||||
message ClientStreamRequest {
|
||||
int64 stroke = 1;
|
||||
}
|
||||
|
||||
message ClientStreamResponse {
|
||||
int64 count = 1;
|
||||
}
|
||||
|
||||
message ServerStreamRequest {
|
||||
int64 count = 1;
|
||||
}
|
||||
|
||||
message ServerStreamResponse {
|
||||
int64 count = 1;
|
||||
}
|
||||
|
||||
message BidiStreamRequest {
|
||||
int64 stroke = 1;
|
||||
}
|
||||
|
||||
message BidiStreamResponse {
|
||||
int64 stroke = 1;
|
||||
}
|
||||
`
|
||||
@@ -1,17 +0,0 @@
|
||||
package template
|
||||
|
||||
// SkaffoldCFG is the Skaffold config template used for new projects.
|
||||
var SkaffoldCFG = `---
|
||||
|
||||
apiVersion: skaffold/v2beta21
|
||||
kind: Config
|
||||
metadata:
|
||||
name: {{.Service}}{{if .Client}}-client{{end}}
|
||||
build:
|
||||
artifacts:
|
||||
- image: {{.Service}}{{if .Client}}-client{{end}}
|
||||
deploy:
|
||||
kubectl:
|
||||
manifests:
|
||||
- resources/*.yaml
|
||||
`
|
||||
@@ -1,14 +0,0 @@
|
||||
module github.com/asim/go-micro/cmd/gomu
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/HdrHistogram/hdrhistogram-go v1.1.2 // indirect
|
||||
github.com/asim/go-micro/v3 v3.6.1-0.20210831082736-088ccb50019c
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/opentracing/opentracing-go v1.2.0
|
||||
github.com/uber/jaeger-client-go v2.29.1+incompatible
|
||||
github.com/uber/jaeger-lib v2.4.1+incompatible
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
@@ -1,12 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/asim/go-micro/cmd/gomu/cmd"
|
||||
|
||||
// register commands
|
||||
_ "github.com/asim/go-micro/cmd/gomu/cmd/cli"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cmd.Run()
|
||||
}
|
||||
+13
-13
@@ -3,19 +3,19 @@ package cmd
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/asim/go-micro/v3/auth"
|
||||
"github.com/asim/go-micro/v3/broker"
|
||||
"github.com/asim/go-micro/v3/cache"
|
||||
"github.com/asim/go-micro/v3/client"
|
||||
"github.com/asim/go-micro/v3/config"
|
||||
"github.com/asim/go-micro/v3/debug/profile"
|
||||
"github.com/asim/go-micro/v3/debug/trace"
|
||||
"github.com/asim/go-micro/v3/registry"
|
||||
"github.com/asim/go-micro/v3/runtime"
|
||||
"github.com/asim/go-micro/v3/selector"
|
||||
"github.com/asim/go-micro/v3/server"
|
||||
"github.com/asim/go-micro/v3/store"
|
||||
"github.com/asim/go-micro/v3/transport"
|
||||
"go-micro.dev/v4/auth"
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/cache"
|
||||
"go-micro.dev/v4/client"
|
||||
"go-micro.dev/v4/config"
|
||||
"go-micro.dev/v4/debug/profile"
|
||||
"go-micro.dev/v4/debug/trace"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/runtime"
|
||||
"go-micro.dev/v4/selector"
|
||||
"go-micro.dev/v4/server"
|
||||
"go-micro.dev/v4/store"
|
||||
"go-micro.dev/v4/transport"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
|
||||
@@ -5,7 +5,7 @@ This is protobuf code generation for go-micro. We use protoc-gen-micro to reduce
|
||||
## Install
|
||||
|
||||
```
|
||||
go install github.com/asim/go-micro/cmd/protoc-gen-micro/v3@latest
|
||||
go install go-micro.dev/v4/cmd/protoc-gen-micro@v4
|
||||
```
|
||||
|
||||
Also required:
|
||||
@@ -20,6 +20,9 @@ Define your service as `greeter.proto`
|
||||
```
|
||||
syntax = "proto3";
|
||||
|
||||
package greeter;
|
||||
option go_package = "/proto;greeter";
|
||||
|
||||
service Greeter {
|
||||
rpc Hello(Request) returns (Response) {}
|
||||
}
|
||||
@@ -36,7 +39,7 @@ message Response {
|
||||
Generate the code
|
||||
|
||||
```
|
||||
protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. greeter.proto
|
||||
protoc --proto_path=. --micro_out=. --go_out=. greeter.proto
|
||||
```
|
||||
|
||||
Your output result should be:
|
||||
@@ -80,7 +83,7 @@ If you see an error about `protoc-gen-micro` not being found or executable, it's
|
||||
Alternative specify the Go plugin paths as arguments to the `protoc` command
|
||||
|
||||
```
|
||||
protoc --plugin=protoc-gen-go=$GOPATH/bin/protoc-gen-go --plugin=protoc-gen-micro=$GOPATH/bin/protoc-gen-micro --proto_path=$GOPATH/src:. --micro_out=. --go_out=. greeter.proto
|
||||
protoc --plugin=protoc-gen-go=$GOPATH/bin/protoc-gen-go --plugin=protoc-gen-micro=$GOPATH/bin/protoc-gen-micro --proto_path=. --micro_out=. --go_out=. greeter.proto
|
||||
```
|
||||
|
||||
### Endpoint
|
||||
@@ -95,6 +98,9 @@ Usage:
|
||||
```diff
|
||||
syntax = "proto3";
|
||||
|
||||
package greeter;
|
||||
option go_package = "/proto;greeter";
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
|
||||
service Greeter {
|
||||
@@ -112,7 +118,7 @@ message Response {
|
||||
}
|
||||
```
|
||||
|
||||
The proto generates a `RegisterGreeterHandler` function with a [api.Endpoint](https://godoc.org/github.com/asim/go-micro/v3/api#Endpoint).
|
||||
The proto generates a `RegisterGreeterHandler` function with a [api.Endpoint](https://godoc.org/go-micro.dev/v3/api#Endpoint).
|
||||
|
||||
```diff
|
||||
func RegisterGreeterHandler(s server.Server, hdlr GreeterHandler, opts ...server.HandlerOption) error {
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
|
||||
import (
|
||||
context "context"
|
||||
api "github.com/asim/go-micro/v3/api"
|
||||
client "github.com/asim/go-micro/v3/client"
|
||||
server "github.com/asim/go-micro/v3/server"
|
||||
api "go-micro.dev/v4/api"
|
||||
client "go-micro.dev/v4/client"
|
||||
server "go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
||||
@@ -305,7 +305,7 @@ func (d *FileDescriptor) goPackageOption() (impPath GoImportPath, pkg GoPackageN
|
||||
}
|
||||
|
||||
// goFileName returns the output name for the generated Go file.
|
||||
func (d *FileDescriptor) goFileName(pathType pathType) string {
|
||||
func (d *FileDescriptor) goFileName(pathType pathType, moduleRoot string) string {
|
||||
name := *d.Name
|
||||
if ext := path.Ext(name); ext == ".proto" || ext == ".protodevel" {
|
||||
name = name[:len(name)-len(ext)]
|
||||
@@ -319,9 +319,18 @@ func (d *FileDescriptor) goFileName(pathType pathType) string {
|
||||
// Does the file have a "go_package" option?
|
||||
// If it does, it may override the filename.
|
||||
if impPath, _, ok := d.goPackageOption(); ok && impPath != "" {
|
||||
// Replace the existing dirname with the declared import path.
|
||||
_, name = path.Split(name)
|
||||
name = path.Join(string(impPath), name)
|
||||
if pathType == pathModuleRoot && moduleRoot != "" {
|
||||
root := moduleRoot
|
||||
if !strings.HasSuffix(root, "/") {
|
||||
root = root + "/"
|
||||
}
|
||||
name = strings.TrimPrefix(name, root)
|
||||
} else {
|
||||
// Replace the existing dirname with the declared import path.
|
||||
_, name = path.Split(name)
|
||||
name = path.Join(string(impPath), name)
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
@@ -405,6 +414,7 @@ type Generator struct {
|
||||
PackageImportPath string // Go import path of the package we're generating code for
|
||||
ImportPrefix string // String to prefix to imported package file names.
|
||||
ImportMap map[string]string // Mapping from .proto file name to import path
|
||||
ModuleRoot string // Mapping from the module prefix
|
||||
|
||||
Pkg map[string]string // The names under which we import support packages
|
||||
|
||||
@@ -429,6 +439,7 @@ type pathType int
|
||||
const (
|
||||
pathTypeImport pathType = iota
|
||||
pathTypeSourceRelative
|
||||
pathModuleRoot
|
||||
)
|
||||
|
||||
// New creates a new generator and allocates the request and response protobufs.
|
||||
@@ -475,11 +486,20 @@ func (g *Generator) CommandLineParameters(parameter string) {
|
||||
g.ImportPrefix = v
|
||||
case "import_path":
|
||||
g.PackageImportPath = v
|
||||
case "module":
|
||||
if g.pathType == pathTypeSourceRelative {
|
||||
g.Fail(fmt.Sprintf(`Cannot set module=%q after paths=source_relative`, v))
|
||||
}
|
||||
g.pathType = pathModuleRoot
|
||||
g.ModuleRoot = v
|
||||
case "paths":
|
||||
switch v {
|
||||
case "import":
|
||||
g.pathType = pathTypeImport
|
||||
case "source_relative":
|
||||
if g.pathType == pathModuleRoot {
|
||||
g.Fail("Cannot set paths=source_relative after setting module=<module_root>")
|
||||
}
|
||||
g.pathType = pathTypeSourceRelative
|
||||
default:
|
||||
g.Fail(fmt.Sprintf(`Unknown path type %q: want "import" or "source_relative".`, v))
|
||||
@@ -1069,7 +1089,7 @@ func (g *Generator) GenerateAllFiles() {
|
||||
if !g.writeOutput {
|
||||
continue
|
||||
}
|
||||
fname := file.goFileName(g.pathType)
|
||||
fname := file.goFileName(g.pathType, g.ModuleRoot)
|
||||
g.Response.File = append(g.Response.File, &plugin.CodeGeneratorResponse_File{
|
||||
Name: proto.String(fname),
|
||||
Content: proto.String(g.String()),
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
module github.com/asim/go-micro/cmd/protoc-gen-micro/v3
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/asim/go-micro/v3 v3.6.0
|
||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8
|
||||
google.golang.org/protobuf v1.27.1
|
||||
)
|
||||
@@ -49,11 +49,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/asim/go-micro/cmd/protoc-gen-micro/v3/generator"
|
||||
_ "github.com/asim/go-micro/cmd/protoc-gen-micro/v3/plugin/micro"
|
||||
"go-micro.dev/v4/cmd/protoc-gen-micro/generator"
|
||||
_ "go-micro.dev/v4/cmd/protoc-gen-micro/plugin/micro"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
@@ -63,7 +63,7 @@ func main() {
|
||||
// report failure.
|
||||
g := generator.New()
|
||||
|
||||
data, err := ioutil.ReadAll(os.Stdin)
|
||||
data, err := io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
g.Error(err, "reading input")
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/cmd/protoc-gen-micro/v3/generator"
|
||||
"go-micro.dev/v4/cmd/protoc-gen-micro/generator"
|
||||
options "google.golang.org/genproto/googleapis/api/annotations"
|
||||
"google.golang.org/protobuf/proto"
|
||||
pb "google.golang.org/protobuf/types/descriptorpb"
|
||||
@@ -15,10 +15,10 @@ import (
|
||||
// Paths for packages used by code generated in this file,
|
||||
// relative to the import_prefix of the generator.Generator.
|
||||
const (
|
||||
apiPkgPath = "github.com/asim/go-micro/v3/api"
|
||||
apiPkgPath = "go-micro.dev/v4/api"
|
||||
contextPkgPath = "context"
|
||||
clientPkgPath = "github.com/asim/go-micro/v3/client"
|
||||
serverPkgPath = "github.com/asim/go-micro/v3/server"
|
||||
clientPkgPath = "go-micro.dev/v4/client"
|
||||
serverPkgPath = "go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -131,7 +131,8 @@ func (g *micro) generateService(file *generator.FileDescriptor, service *pb.Serv
|
||||
|
||||
origServName := service.GetName()
|
||||
serviceName := strings.ToLower(service.GetName())
|
||||
if pkg := file.GetPackage(); pkg != "" {
|
||||
pkg := file.GetPackage()
|
||||
if pkg != "" {
|
||||
serviceName = pkg
|
||||
}
|
||||
servName := generator.CamelCase(origServName)
|
||||
@@ -209,7 +210,7 @@ func (g *micro) generateService(file *generator.FileDescriptor, service *pb.Serv
|
||||
descExpr = fmt.Sprintf("&%s.Streams[%d]", serviceDescVar, streamIndex)
|
||||
streamIndex++
|
||||
}
|
||||
g.generateClientMethod(serviceName, servName, serviceDescVar, method, descExpr)
|
||||
g.generateClientMethod(pkg, serviceName, servName, serviceDescVar, method, descExpr)
|
||||
}
|
||||
|
||||
g.P("// Server API for ", servName, " service")
|
||||
@@ -331,8 +332,12 @@ func (g *micro) generateClientSignature(servName string, method *pb.MethodDescri
|
||||
return fmt.Sprintf("%s(ctx %s.Context%s, opts ...%s.CallOption) (%s, error)", methName, contextPkg, reqArg, clientPkg, respName)
|
||||
}
|
||||
|
||||
func (g *micro) generateClientMethod(reqServ, servName, serviceDescVar string, method *pb.MethodDescriptorProto, descExpr string) {
|
||||
func (g *micro) generateClientMethod(pkg, reqServ, servName, serviceDescVar string, method *pb.MethodDescriptorProto, descExpr string) {
|
||||
reqMethod := fmt.Sprintf("%s.%s", servName, method.GetName())
|
||||
useGrpc := g.gen.Param["use_grpc"]
|
||||
if useGrpc != "" {
|
||||
reqMethod = fmt.Sprintf("/%s.%s/%s", pkg, servName, method.GetName())
|
||||
}
|
||||
methName := generator.CamelCase(method.GetName())
|
||||
inType := g.typeName(method.GetInputType())
|
||||
outType := g.typeName(method.GetOutputType())
|
||||
@@ -363,6 +368,8 @@ func (g *micro) generateClientMethod(reqServ, servName, serviceDescVar string, m
|
||||
|
||||
if !method.GetClientStreaming() {
|
||||
g.P("if err := stream.Send(in); err != nil { return nil, err }")
|
||||
// TODO: currently only grpc support CloseSend
|
||||
// g.P("if err := stream.CloseSend(); err != nil { return nil, err }")
|
||||
}
|
||||
|
||||
g.P("return &", streamType, "{stream}, nil")
|
||||
@@ -377,6 +384,7 @@ func (g *micro) generateClientMethod(reqServ, servName, serviceDescVar string, m
|
||||
g.P("Context() context.Context")
|
||||
g.P("SendMsg(interface{}) error")
|
||||
g.P("RecvMsg(interface{}) error")
|
||||
g.P("CloseSend() error")
|
||||
g.P("Close() error")
|
||||
|
||||
if genSend {
|
||||
@@ -393,6 +401,11 @@ func (g *micro) generateClientMethod(reqServ, servName, serviceDescVar string, m
|
||||
g.P("}")
|
||||
g.P()
|
||||
|
||||
g.P("func (x *", streamType, ") CloseSend() error {")
|
||||
g.P("return x.stream.CloseSend()")
|
||||
g.P("}")
|
||||
g.P()
|
||||
|
||||
g.P("func (x *", streamType, ") Close() error {")
|
||||
g.P("return x.stream.Close()")
|
||||
g.P("}")
|
||||
|
||||
@@ -4,9 +4,8 @@ package bytes
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/asim/go-micro/v3/codec"
|
||||
"go-micro.dev/v4/codec"
|
||||
)
|
||||
|
||||
type Codec struct {
|
||||
@@ -24,7 +23,7 @@ func (c *Codec) ReadHeader(m *codec.Message, t codec.MessageType) error {
|
||||
|
||||
func (c *Codec) ReadBody(b interface{}) error {
|
||||
// read bytes
|
||||
buf, err := ioutil.ReadAll(c.Conn)
|
||||
buf, err := io.ReadAll(c.Conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package bytes
|
||||
|
||||
import (
|
||||
"github.com/asim/go-micro/v3/codec"
|
||||
"go-micro.dev/v4/codec"
|
||||
)
|
||||
|
||||
type Marshaler struct{}
|
||||
@@ -27,8 +27,10 @@ func (n Marshaler) Unmarshal(d []byte, v interface{}) error {
|
||||
switch ve := v.(type) {
|
||||
case *[]byte:
|
||||
*ve = d
|
||||
return nil
|
||||
case *Message:
|
||||
ve.Body = d
|
||||
return nil
|
||||
}
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,8 +8,8 @@ import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/asim/go-micro/v3/codec"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"go-micro.dev/v4/codec"
|
||||
)
|
||||
|
||||
type Codec struct {
|
||||
|
||||
+1
-1
@@ -5,9 +5,9 @@ import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/asim/go-micro/v3/codec"
|
||||
"github.com/golang/protobuf/jsonpb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"go-micro.dev/v4/codec"
|
||||
)
|
||||
|
||||
type Codec struct {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user