mirror of
https://github.com/go-micro/go-micro.git
synced 2025-11-06 08:29:15 +02:00
Add examples
This commit is contained in:
@@ -72,6 +72,10 @@ See the [docs](https://github.com/micro/micro/tree/master/docs/v2) for detailed
|
|||||||
|
|
||||||
See [cmd/protoc-gen-micro](https://github.com/micro/go-micro/tree/master/cmd/protoc-gen-micro) for protobuf code generation.
|
See [cmd/protoc-gen-micro](https://github.com/micro/go-micro/tree/master/cmd/protoc-gen-micro) for protobuf code generation.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
See [examples](https://github.com/micro/go-micro/tree/master/examples) directory for usage examples.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Go Micro is Apache 2.0 licensed.
|
Go Micro is Apache 2.0 licensed.
|
||||||
|
|||||||
51
examples/.github/workflows/tests.yml
vendored
Normal file
51
examples/.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
name: Run tests
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
test:
|
||||||
|
name: Test repo
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
|
||||||
|
- name: Set up Go 1.13
|
||||||
|
uses: actions/setup-go@v1
|
||||||
|
with:
|
||||||
|
go-version: 1.13
|
||||||
|
id: go
|
||||||
|
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get dependencies
|
||||||
|
run: |
|
||||||
|
go get -v -t -d ./...
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
id: tests
|
||||||
|
env:
|
||||||
|
IN_TRAVIS_CI: yes
|
||||||
|
run: go test -v ./...
|
||||||
|
|
||||||
|
- name: Notify of test failure
|
||||||
|
if: failure()
|
||||||
|
uses: rtCamp/action-slack-notify@v2.0.0
|
||||||
|
env:
|
||||||
|
SLACK_CHANNEL: build
|
||||||
|
SLACK_COLOR: '#BF280A'
|
||||||
|
SLACK_ICON: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
|
||||||
|
SLACK_TITLE: Tests Failed
|
||||||
|
SLACK_USERNAME: GitHub Actions
|
||||||
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||||
|
|
||||||
|
- name: Notify of test success
|
||||||
|
if: success()
|
||||||
|
uses: rtCamp/action-slack-notify@v2.0.0
|
||||||
|
env:
|
||||||
|
SLACK_CHANNEL: build
|
||||||
|
SLACK_COLOR: '#1FAD2B'
|
||||||
|
SLACK_ICON: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
|
||||||
|
SLACK_TITLE: Tests Passed
|
||||||
|
SLACK_USERNAME: GitHub Actions
|
||||||
|
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||||
|
|
||||||
191
examples/LICENSE
Normal file
191
examples/LICENSE
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
Copyright 2015 Asim Aslam.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
63
examples/README.md
Normal file
63
examples/README.md
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
# Examples
|
||||||
|
|
||||||
|
This is a repository for micro examples. Feel free to contribute.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- [api](api) - Provides API usage examples
|
||||||
|
- [booking](booking) - A booking.com demo application
|
||||||
|
- [broker](broker) - A example of using Broker for Publish and Subscribing.
|
||||||
|
- [client](client) - Usage of the Client package to call a service.
|
||||||
|
- [command](command) - An example of bot commands as micro services
|
||||||
|
- [config](config) - Using Go Config for dynamic config
|
||||||
|
- [event](event) - Using the API Gateway event handler
|
||||||
|
- [filter](filter) - Filter nodes of a service when requesting
|
||||||
|
- [flags](flags) - Using command line flags with a service
|
||||||
|
- [form](form) - How to parse a form behind the micro api
|
||||||
|
- [function](function) - Example of using Function programming model
|
||||||
|
- [getip](getip) - Get the local and remote ip from metadata
|
||||||
|
- [graceful](graceful) - Demonstrates graceful shutdown of a service
|
||||||
|
- [greeter](greeter) - A complete greeter example (includes python, ruby examples)
|
||||||
|
- [heartbeat](heartbeat) - Make services heartbeat with discovery for high availability
|
||||||
|
- [helloworld](helloworld) - Hello world using micro
|
||||||
|
- [kubernetes](kubernetes) - Examples of using the k8s registry and grpc
|
||||||
|
- [metadata](metadata) - Extracting metadata from context of a request
|
||||||
|
- [mocking](mocking) - Demonstrate mocking helloworld service
|
||||||
|
- [noproto](noproto) - Use micro without protobuf or code generation, only go types
|
||||||
|
- [options](options) - Setting options in the go-micro framework
|
||||||
|
- [plugins](plugins) - How to use plugins
|
||||||
|
- [pubsub](pubsub) - Example of using pubsub at the client/server level
|
||||||
|
- [grpc](grpc) - Examples of how to use [go-micro/service/grpc](https://github.com/micro/go-micro/service/grpc)
|
||||||
|
- [redirect](redirect) - An example of how to http redirect using an API service
|
||||||
|
- [roundrobin](roundrobin) - A stateful client wrapper for true round robin of requests
|
||||||
|
- [secure](secure) - Demonstrates use of transport secure option for self signed certs
|
||||||
|
- [server](server) - Use of the Server package directly to server requests.
|
||||||
|
- [service](service) - Example of the top level Service in go-micro.
|
||||||
|
- [sharding](sharding) - An example of how to shard requests or use session affinity
|
||||||
|
- [shutdown](shutdown) - Demonstrates graceful shutdown via context cancellation
|
||||||
|
- [stream](stream) - An example of a streaming service and client
|
||||||
|
- [template](template) - Api, web and srv service templates generated with the 'micro new' command
|
||||||
|
- [tunnel](tunnel) - How to use connection tunneling with the tunnel package
|
||||||
|
- [waitgroup](waitgroup) - Demonstrates how to use a waitgroup with a service
|
||||||
|
- [wrapper](wrapper) - A simple example of using a log wrapper
|
||||||
|
|
||||||
|
## Community
|
||||||
|
|
||||||
|
Find contributions from the community via the [explorer](https://micro.mu/projects/)
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Install [protoc](https://github.com/google/protobuf) for your environment. Then:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# install protoc-gen-go
|
||||||
|
go get github.com/golang/protobuf/{proto,protoc-gen-go}
|
||||||
|
# install protoc-gen-micro
|
||||||
|
go get github.com/micro/micro/v2/cmd/protoc-gen-micro@master
|
||||||
|
```
|
||||||
|
|
||||||
|
To recompile any proto after changes:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. path/to/proto
|
||||||
|
```
|
||||||
1
examples/_config.yml
Normal file
1
examples/_config.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
theme: jekyll-theme-architect
|
||||||
57
examples/api/README.md
Normal file
57
examples/api/README.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# API
|
||||||
|
|
||||||
|
This repo contains examples for using the micro api.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The [micro api](https://github.com/micro/micro/tree/master/api) is an API gateway which serves HTTP and routes dynamically based on service discovery.
|
||||||
|
|
||||||
|
The micro api by default serves the namespace go.micro.api. Our service names include this plus a unique name e.g go.micro.api.example.
|
||||||
|
You can change the namespace via the flag `--namespace=`.
|
||||||
|
|
||||||
|
The micro api has a number of different handlers which lets you define what kind of API services you want. See examples below. The handler
|
||||||
|
can be set via the flag `--handler=`. The default handler is "rpc".
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- api - an rpc handler that provides the entire http headers and request
|
||||||
|
- proxy - use the api as a http reverse proxy
|
||||||
|
- rpc - make an rpc request to a go-micro app
|
||||||
|
- meta - specify which handler to use via configuration in code
|
||||||
|
|
||||||
|
## Request Mapping
|
||||||
|
|
||||||
|
### API/RPC
|
||||||
|
|
||||||
|
Micro maps http paths to rpc services. The mapping table can be seen below.
|
||||||
|
|
||||||
|
The default namespace for the api is **go.micro.api** but you can set your own namespace via `--namespace`.
|
||||||
|
|
||||||
|
URLs are mapped as follows:
|
||||||
|
|
||||||
|
Path | Service | Method
|
||||||
|
---- | ---- | ----
|
||||||
|
/foo/bar | go.micro.api.foo | Foo.Bar
|
||||||
|
/foo/bar/baz | go.micro.api.foo | Bar.Baz
|
||||||
|
/foo/bar/baz/cat | go.micro.api.foo.bar | Baz.Cat
|
||||||
|
|
||||||
|
Versioned API URLs can easily be mapped to service names:
|
||||||
|
|
||||||
|
Path | Service | Method
|
||||||
|
---- | ---- | ----
|
||||||
|
/foo/bar | go.micro.api.foo | Foo.Bar
|
||||||
|
/v1/foo/bar | go.micro.api.v1.foo | Foo.Bar
|
||||||
|
/v1/foo/bar/baz | go.micro.api.v1.foo | Bar.Baz
|
||||||
|
/v2/foo/bar | go.micro.api.v2.foo | Foo.Bar
|
||||||
|
/v2/foo/bar/baz | go.micro.api.v2.foo | Bar.Baz
|
||||||
|
|
||||||
|
### Proxy Mapping
|
||||||
|
|
||||||
|
Starting the API with `--handler=http` will reverse proxy requests to backend services within the served API namespace (default: go.micro.api).
|
||||||
|
|
||||||
|
Example
|
||||||
|
|
||||||
|
Path | Service | Service Path
|
||||||
|
--- | --- | ---
|
||||||
|
/greeter | go.micro.api.greeter | /greeter
|
||||||
|
/greeter/:name | go.micro.api.greeter | /greeter/:name
|
||||||
58
examples/api/api/README.md
Normal file
58
examples/api/api/README.md
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# API
|
||||||
|
|
||||||
|
This example makes use of the "api" handler.
|
||||||
|
|
||||||
|
The api expects you use the [api.Request/Response](https://github.com/micro/go-api/blob/master/proto/api.proto) protos.
|
||||||
|
|
||||||
|
The micro api request handler gives you full control over the http request and response while still leveraging RPC and
|
||||||
|
any transport plugins that use other protocols beyond http in your stack such as grpc, nats, kafka.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the micro API
|
||||||
|
|
||||||
|
```
|
||||||
|
micro api --handler=api
|
||||||
|
```
|
||||||
|
|
||||||
|
Run this example
|
||||||
|
|
||||||
|
```
|
||||||
|
go run api.go
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Calling the service
|
||||||
|
|
||||||
|
Make a GET request to /example/call which will call go.micro.api.example Example.Call
|
||||||
|
|
||||||
|
```
|
||||||
|
curl "http://localhost:8080/example/call?name=john"
|
||||||
|
```
|
||||||
|
|
||||||
|
Make a POST request to /example/foo/bar which will call go.micro.api.example Foo.Bar
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -H 'Content-Type: application/json' -d '{}' http://localhost:8080/example/foo/bar
|
||||||
|
```
|
||||||
|
|
||||||
|
## Set Namespace
|
||||||
|
|
||||||
|
Run the micro API with custom namespace
|
||||||
|
|
||||||
|
```
|
||||||
|
micro api --handler=api --namespace=com.foobar.api
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
```
|
||||||
|
MICRO_API_NAMESPACE=com.foobar.api micro api --handler=api
|
||||||
|
```
|
||||||
|
|
||||||
|
Set service name with the namespace
|
||||||
|
|
||||||
|
```
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("com.foobar.api.example"),
|
||||||
|
)
|
||||||
|
```
|
||||||
91
examples/api/api/api.go
Normal file
91
examples/api/api/api.go
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
proto "github.com/micro/examples/api/api/proto"
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
api "github.com/micro/go-micro/v2/api/proto"
|
||||||
|
"github.com/micro/go-micro/v2/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Example struct{}
|
||||||
|
|
||||||
|
type Foo struct{}
|
||||||
|
|
||||||
|
// Example.Call is a method which will be served by http request /example/call
|
||||||
|
// In the event we see /[service]/[method] the [service] is used as part of the method
|
||||||
|
// E.g /example/call goes to go.micro.api.example Example.Call
|
||||||
|
func (e *Example) Call(ctx context.Context, req *api.Request, rsp *api.Response) error {
|
||||||
|
log.Print("Received Example.Call request")
|
||||||
|
|
||||||
|
// parse values from the get request
|
||||||
|
name, ok := req.Get["name"]
|
||||||
|
|
||||||
|
if !ok || len(name.Values) == 0 {
|
||||||
|
return errors.BadRequest("go.micro.api.example", "no content")
|
||||||
|
}
|
||||||
|
|
||||||
|
// set response status
|
||||||
|
rsp.StatusCode = 200
|
||||||
|
|
||||||
|
// respond with some json
|
||||||
|
b, _ := json.Marshal(map[string]string{
|
||||||
|
"message": "got your request " + strings.Join(name.Values, " "),
|
||||||
|
})
|
||||||
|
|
||||||
|
// set json body
|
||||||
|
rsp.Body = string(b)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Foo.Bar is a method which will be served by http request /example/foo/bar
|
||||||
|
// Because Foo is not the same as the service name it is mapped beyond /example/
|
||||||
|
func (f *Foo) Bar(ctx context.Context, req *api.Request, rsp *api.Response) error {
|
||||||
|
log.Print("Received Foo.Bar request")
|
||||||
|
|
||||||
|
// check method
|
||||||
|
if req.Method != "POST" {
|
||||||
|
return errors.BadRequest("go.micro.api.example", "require post")
|
||||||
|
}
|
||||||
|
|
||||||
|
// let's make sure we get json
|
||||||
|
ct, ok := req.Header["Content-Type"]
|
||||||
|
if !ok || len(ct.Values) == 0 {
|
||||||
|
return errors.BadRequest("go.micro.api.example", "need content-type")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ct.Values[0] != "application/json" {
|
||||||
|
return errors.BadRequest("go.micro.api.example", "expect application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse body
|
||||||
|
var body map[string]interface{}
|
||||||
|
json.Unmarshal([]byte(req.Body), &body)
|
||||||
|
|
||||||
|
// do something with parsed body
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("go.micro.api.example"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
// register example handler
|
||||||
|
proto.RegisterExampleHandler(service.Server(), new(Example))
|
||||||
|
|
||||||
|
// register foo handler
|
||||||
|
proto.RegisterFooHandler(service.Server(), new(Foo))
|
||||||
|
|
||||||
|
if err := service.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
151
examples/api/api/proto/api.micro.go
Normal file
151
examples/api/api/proto/api.micro.go
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||||
|
// source: proto/api.proto
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
fmt "fmt"
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
|
proto1 "github.com/micro/go-micro/v2/api/proto"
|
||||||
|
math "math"
|
||||||
|
)
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
client "github.com/micro/go-micro/v2/client"
|
||||||
|
server "github.com/micro/go-micro/v2/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ client.Option
|
||||||
|
var _ server.Option
|
||||||
|
|
||||||
|
// Client API for Example service
|
||||||
|
|
||||||
|
type ExampleService interface {
|
||||||
|
Call(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type exampleService struct {
|
||||||
|
c client.Client
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExampleService(name string, c client.Client) ExampleService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(name) == 0 {
|
||||||
|
name = "example"
|
||||||
|
}
|
||||||
|
return &exampleService{
|
||||||
|
c: c,
|
||||||
|
name: name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *exampleService) Call(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.Response, error) {
|
||||||
|
req := c.c.NewRequest(c.name, "Example.Call", in)
|
||||||
|
out := new(proto1.Response)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Example service
|
||||||
|
|
||||||
|
type ExampleHandler interface {
|
||||||
|
Call(context.Context, *proto1.Request, *proto1.Response) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterExampleHandler(s server.Server, hdlr ExampleHandler, opts ...server.HandlerOption) error {
|
||||||
|
type example interface {
|
||||||
|
Call(ctx context.Context, in *proto1.Request, out *proto1.Response) error
|
||||||
|
}
|
||||||
|
type Example struct {
|
||||||
|
example
|
||||||
|
}
|
||||||
|
h := &exampleHandler{hdlr}
|
||||||
|
return s.Handle(s.NewHandler(&Example{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type exampleHandler struct {
|
||||||
|
ExampleHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *exampleHandler) Call(ctx context.Context, in *proto1.Request, out *proto1.Response) error {
|
||||||
|
return h.ExampleHandler.Call(ctx, in, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client API for Foo service
|
||||||
|
|
||||||
|
type FooService interface {
|
||||||
|
Bar(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fooService struct {
|
||||||
|
c client.Client
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFooService(name string, c client.Client) FooService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(name) == 0 {
|
||||||
|
name = "foo"
|
||||||
|
}
|
||||||
|
return &fooService{
|
||||||
|
c: c,
|
||||||
|
name: name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fooService) Bar(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.Response, error) {
|
||||||
|
req := c.c.NewRequest(c.name, "Foo.Bar", in)
|
||||||
|
out := new(proto1.Response)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Foo service
|
||||||
|
|
||||||
|
type FooHandler interface {
|
||||||
|
Bar(context.Context, *proto1.Request, *proto1.Response) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterFooHandler(s server.Server, hdlr FooHandler, opts ...server.HandlerOption) error {
|
||||||
|
type foo interface {
|
||||||
|
Bar(ctx context.Context, in *proto1.Request, out *proto1.Response) error
|
||||||
|
}
|
||||||
|
type Foo struct {
|
||||||
|
foo
|
||||||
|
}
|
||||||
|
h := &fooHandler{hdlr}
|
||||||
|
return s.Handle(s.NewHandler(&Foo{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type fooHandler struct {
|
||||||
|
FooHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *fooHandler) Bar(ctx context.Context, in *proto1.Request, out *proto1.Response) error {
|
||||||
|
return h.FooHandler.Bar(ctx, in, out)
|
||||||
|
}
|
||||||
37
examples/api/api/proto/api.pb.go
Normal file
37
examples/api/api/proto/api.pb.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: proto/api.proto
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
fmt "fmt"
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
|
_ "github.com/micro/go-micro/v2/api/proto"
|
||||||
|
math "math"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("proto/api.proto", fileDescriptor_ecf0878b123623e2) }
|
||||||
|
|
||||||
|
var fileDescriptor_ecf0878b123623e2 = []byte{
|
||||||
|
// 135 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2f, 0x28, 0xca, 0x2f,
|
||||||
|
0xc9, 0xd7, 0x4f, 0x2c, 0xc8, 0xd4, 0x03, 0xb3, 0xa4, 0x74, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93,
|
||||||
|
0xf4, 0x92, 0xf3, 0x73, 0xf5, 0x73, 0x33, 0x93, 0x8b, 0xf2, 0xf5, 0xd3, 0xf3, 0x75, 0x21, 0x8c,
|
||||||
|
0xc4, 0x82, 0x4c, 0x7d, 0x34, 0xe5, 0x46, 0x66, 0x5c, 0xec, 0xae, 0x15, 0x89, 0xb9, 0x05, 0x39,
|
||||||
|
0xa9, 0x42, 0xda, 0x5c, 0x2c, 0xce, 0x89, 0x39, 0x39, 0x42, 0xfc, 0x7a, 0xe9, 0xf9, 0x7a, 0x20,
|
||||||
|
0x15, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x52, 0x02, 0x08, 0x81, 0xe2, 0x82, 0xfc, 0xbc,
|
||||||
|
0xe2, 0x54, 0x25, 0x06, 0x23, 0x43, 0x2e, 0x66, 0xb7, 0xfc, 0x7c, 0x21, 0x2d, 0x2e, 0x66, 0xa7,
|
||||||
|
0xc4, 0x22, 0xa2, 0xb4, 0x24, 0xb1, 0x81, 0x6d, 0x34, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xf4,
|
||||||
|
0x92, 0x9f, 0xad, 0xb3, 0x00, 0x00, 0x00,
|
||||||
|
}
|
||||||
11
examples/api/api/proto/api.proto
Normal file
11
examples/api/api/proto/api.proto
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
import "github.com/micro/go-micro/v2/api/proto/api.proto";
|
||||||
|
|
||||||
|
service Example {
|
||||||
|
rpc Call(go.api.Request) returns(go.api.Response) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
service Foo {
|
||||||
|
rpc Bar(go.api.Request) returns(go.api.Response) {};
|
||||||
|
}
|
||||||
31
examples/api/meta/README.md
Normal file
31
examples/api/meta/README.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Meta API
|
||||||
|
|
||||||
|
This example makes use of the micro API metadata handler.
|
||||||
|
|
||||||
|
This will allow us to write standard go-micro services and set the handler/endpoint via service discovery metadata.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the micro API
|
||||||
|
|
||||||
|
```
|
||||||
|
micro api
|
||||||
|
```
|
||||||
|
|
||||||
|
Run this example. Note endpoint metadata when registering the handler
|
||||||
|
|
||||||
|
```
|
||||||
|
go run meta.go
|
||||||
|
```
|
||||||
|
|
||||||
|
Make a POST request to /example which will call go.micro.api.example Example.Call
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -H 'Content-Type: application/json' -d '{"name": "john"}' "http://localhost:8080/example"
|
||||||
|
```
|
||||||
|
|
||||||
|
Make a POST request to /foo/bar which will call go.micro.api.example Foo.Bar
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -H 'Content-Type: application/json' -d '{}' http://localhost:8080/foo/bar
|
||||||
|
```
|
||||||
78
examples/api/meta/meta.go
Normal file
78
examples/api/meta/meta.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
proto "github.com/micro/examples/api/rpc/proto"
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
"github.com/micro/go-micro/v2/api"
|
||||||
|
rapi "github.com/micro/go-micro/v2/api/handler/api"
|
||||||
|
"github.com/micro/go-micro/v2/api/handler/rpc"
|
||||||
|
"github.com/micro/go-micro/v2/errors"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Example struct{}
|
||||||
|
|
||||||
|
type Foo struct{}
|
||||||
|
|
||||||
|
// Example.Call is a method which will be served by http request /example/call
|
||||||
|
// In the event we see /[service]/[method] the [service] is used as part of the method
|
||||||
|
// E.g /example/call goes to go.micro.api.example Example.Call
|
||||||
|
func (e *Example) Call(ctx context.Context, req *proto.CallRequest, rsp *proto.CallResponse) error {
|
||||||
|
log.Print("Received Example.Call request")
|
||||||
|
|
||||||
|
if len(req.Name) == 0 {
|
||||||
|
return errors.BadRequest("go.micro.api.example", "no content")
|
||||||
|
}
|
||||||
|
|
||||||
|
rsp.Message = "got your request " + req.Name
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Foo.Bar is a method which will be served by http request /example/foo/bar
|
||||||
|
// Because Foo is not the same as the service name it is mapped beyond /example/
|
||||||
|
func (f *Foo) Bar(ctx context.Context, req *proto.EmptyRequest, rsp *proto.EmptyResponse) error {
|
||||||
|
log.Print("Received Foo.Bar request")
|
||||||
|
|
||||||
|
// noop
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("go.micro.api.example"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
// register example handler
|
||||||
|
proto.RegisterExampleHandler(service.Server(), new(Example), api.WithEndpoint(&api.Endpoint{
|
||||||
|
// The RPC method
|
||||||
|
Name: "Example.Call",
|
||||||
|
// The HTTP paths. This can be a POSIX regex
|
||||||
|
Path: []string{"/example"},
|
||||||
|
// The HTTP Methods for this endpoint
|
||||||
|
Method: []string{"POST"},
|
||||||
|
// The API handler to use
|
||||||
|
Handler: rpc.Handler,
|
||||||
|
}))
|
||||||
|
|
||||||
|
// register foo handler
|
||||||
|
proto.RegisterFooHandler(service.Server(), new(Foo), api.WithEndpoint(&api.Endpoint{
|
||||||
|
// The RPC method
|
||||||
|
Name: "Foo.Bar",
|
||||||
|
// The HTTP paths. This can be a POSIX regex
|
||||||
|
Path: []string{"/foo/bar"},
|
||||||
|
// The HTTP Methods for this endpoint
|
||||||
|
Method: []string{"POST"},
|
||||||
|
// The API handler to use
|
||||||
|
Handler: rapi.Handler,
|
||||||
|
}))
|
||||||
|
|
||||||
|
if err := service.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
160
examples/api/meta/proto/api.micro.go
Normal file
160
examples/api/meta/proto/api.micro.go
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/api/meta/proto/api.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package api is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/api/meta/proto/api.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
CallRequest
|
||||||
|
CallResponse
|
||||||
|
EmptyRequest
|
||||||
|
EmptyResponse
|
||||||
|
*/
|
||||||
|
package api
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
client "github.com/micro/go-micro/v2/client"
|
||||||
|
server "github.com/micro/go-micro/v2/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ client.Option
|
||||||
|
var _ server.Option
|
||||||
|
|
||||||
|
// Client API for Example service
|
||||||
|
|
||||||
|
type ExampleService interface {
|
||||||
|
Call(ctx context.Context, in *CallRequest, opts ...client.CallOption) (*CallResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type exampleService struct {
|
||||||
|
c client.Client
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExampleService(serviceName string, c client.Client) ExampleService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(serviceName) == 0 {
|
||||||
|
serviceName = "example"
|
||||||
|
}
|
||||||
|
return &exampleService{
|
||||||
|
c: c,
|
||||||
|
serviceName: serviceName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *exampleService) Call(ctx context.Context, in *CallRequest, opts ...client.CallOption) (*CallResponse, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Example.Call", in)
|
||||||
|
out := new(CallResponse)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Example service
|
||||||
|
|
||||||
|
type ExampleHandler interface {
|
||||||
|
Call(context.Context, *CallRequest, *CallResponse) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterExampleHandler(s server.Server, hdlr ExampleHandler, opts ...server.HandlerOption) {
|
||||||
|
type example interface {
|
||||||
|
Call(ctx context.Context, in *CallRequest, out *CallResponse) error
|
||||||
|
}
|
||||||
|
type Example struct {
|
||||||
|
example
|
||||||
|
}
|
||||||
|
h := &exampleHandler{hdlr}
|
||||||
|
s.Handle(s.NewHandler(&Example{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type exampleHandler struct {
|
||||||
|
ExampleHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *exampleHandler) Call(ctx context.Context, in *CallRequest, out *CallResponse) error {
|
||||||
|
return h.ExampleHandler.Call(ctx, in, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client API for Foo service
|
||||||
|
|
||||||
|
type FooService interface {
|
||||||
|
Bar(ctx context.Context, in *EmptyRequest, opts ...client.CallOption) (*EmptyResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fooService struct {
|
||||||
|
c client.Client
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFooService(serviceName string, c client.Client) FooService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(serviceName) == 0 {
|
||||||
|
serviceName = "foo"
|
||||||
|
}
|
||||||
|
return &fooService{
|
||||||
|
c: c,
|
||||||
|
serviceName: serviceName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fooService) Bar(ctx context.Context, in *EmptyRequest, opts ...client.CallOption) (*EmptyResponse, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Foo.Bar", in)
|
||||||
|
out := new(EmptyResponse)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Foo service
|
||||||
|
|
||||||
|
type FooHandler interface {
|
||||||
|
Bar(context.Context, *EmptyRequest, *EmptyResponse) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterFooHandler(s server.Server, hdlr FooHandler, opts ...server.HandlerOption) {
|
||||||
|
type foo interface {
|
||||||
|
Bar(ctx context.Context, in *EmptyRequest, out *EmptyResponse) error
|
||||||
|
}
|
||||||
|
type Foo struct {
|
||||||
|
foo
|
||||||
|
}
|
||||||
|
h := &fooHandler{hdlr}
|
||||||
|
s.Handle(s.NewHandler(&Foo{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type fooHandler struct {
|
||||||
|
FooHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *fooHandler) Bar(ctx context.Context, in *EmptyRequest, out *EmptyResponse) error {
|
||||||
|
return h.FooHandler.Bar(ctx, in, out)
|
||||||
|
}
|
||||||
246
examples/api/meta/proto/api.pb.go
Normal file
246
examples/api/meta/proto/api.pb.go
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/api/meta/proto/api.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package api is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/api/meta/proto/api.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
CallRequest
|
||||||
|
CallResponse
|
||||||
|
EmptyRequest
|
||||||
|
EmptyResponse
|
||||||
|
*/
|
||||||
|
package api
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "golang.org/x/net/context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
type CallRequest struct {
|
||||||
|
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *CallRequest) Reset() { *m = CallRequest{} }
|
||||||
|
func (m *CallRequest) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*CallRequest) ProtoMessage() {}
|
||||||
|
func (*CallRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
|
||||||
|
func (m *CallRequest) GetName() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type CallResponse struct {
|
||||||
|
Message string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *CallResponse) Reset() { *m = CallResponse{} }
|
||||||
|
func (m *CallResponse) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*CallResponse) ProtoMessage() {}
|
||||||
|
func (*CallResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||||
|
|
||||||
|
func (m *CallResponse) GetMessage() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Message
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmptyRequest struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *EmptyRequest) Reset() { *m = EmptyRequest{} }
|
||||||
|
func (m *EmptyRequest) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*EmptyRequest) ProtoMessage() {}
|
||||||
|
func (*EmptyRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||||
|
|
||||||
|
type EmptyResponse struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *EmptyResponse) Reset() { *m = EmptyResponse{} }
|
||||||
|
func (m *EmptyResponse) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*EmptyResponse) ProtoMessage() {}
|
||||||
|
func (*EmptyResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*CallRequest)(nil), "CallRequest")
|
||||||
|
proto.RegisterType((*CallResponse)(nil), "CallResponse")
|
||||||
|
proto.RegisterType((*EmptyRequest)(nil), "EmptyRequest")
|
||||||
|
proto.RegisterType((*EmptyResponse)(nil), "EmptyResponse")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ grpc.ClientConn
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
const _ = grpc.SupportPackageIsVersion4
|
||||||
|
|
||||||
|
// Client API for Example service
|
||||||
|
|
||||||
|
type ExampleClient interface {
|
||||||
|
Call(ctx context.Context, in *CallRequest, opts ...grpc.CallOption) (*CallResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type exampleClient struct {
|
||||||
|
cc *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExampleClient(cc *grpc.ClientConn) ExampleClient {
|
||||||
|
return &exampleClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *exampleClient) Call(ctx context.Context, in *CallRequest, opts ...grpc.CallOption) (*CallResponse, error) {
|
||||||
|
out := new(CallResponse)
|
||||||
|
err := grpc.Invoke(ctx, "/Example/Call", in, out, c.cc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Example service
|
||||||
|
|
||||||
|
type ExampleServer interface {
|
||||||
|
Call(context.Context, *CallRequest) (*CallResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterExampleServer(s *grpc.Server, srv ExampleServer) {
|
||||||
|
s.RegisterService(&_Example_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Example_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(CallRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(ExampleServer).Call(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/Example/Call",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(ExampleServer).Call(ctx, req.(*CallRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _Example_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "Example",
|
||||||
|
HandlerType: (*ExampleServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "Call",
|
||||||
|
Handler: _Example_Call_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "github.com/micro/examples/api/meta/proto/api.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client API for Foo service
|
||||||
|
|
||||||
|
type FooClient interface {
|
||||||
|
Bar(ctx context.Context, in *EmptyRequest, opts ...grpc.CallOption) (*EmptyResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fooClient struct {
|
||||||
|
cc *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFooClient(cc *grpc.ClientConn) FooClient {
|
||||||
|
return &fooClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fooClient) Bar(ctx context.Context, in *EmptyRequest, opts ...grpc.CallOption) (*EmptyResponse, error) {
|
||||||
|
out := new(EmptyResponse)
|
||||||
|
err := grpc.Invoke(ctx, "/Foo/Bar", in, out, c.cc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Foo service
|
||||||
|
|
||||||
|
type FooServer interface {
|
||||||
|
Bar(context.Context, *EmptyRequest) (*EmptyResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterFooServer(s *grpc.Server, srv FooServer) {
|
||||||
|
s.RegisterService(&_Foo_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Foo_Bar_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(EmptyRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(FooServer).Bar(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/Foo/Bar",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(FooServer).Bar(ctx, req.(*EmptyRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _Foo_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "Foo",
|
||||||
|
HandlerType: (*FooServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "Bar",
|
||||||
|
Handler: _Foo_Bar_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "github.com/micro/examples/api/meta/proto/api.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("github.com/micro/examples/api/meta/proto/api.proto", fileDescriptor0) }
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 203 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x8f, 0xd1, 0x6a, 0x83, 0x30,
|
||||||
|
0x14, 0x86, 0x75, 0xca, 0x64, 0x67, 0xea, 0x20, 0x57, 0xe2, 0xd5, 0x16, 0xd8, 0xf0, 0x66, 0xc9,
|
||||||
|
0x70, 0x6f, 0xd0, 0x62, 0x1f, 0xc0, 0x37, 0x88, 0x72, 0xb0, 0x82, 0x31, 0xa9, 0x89, 0xd0, 0xbe,
|
||||||
|
0x7d, 0x31, 0x5a, 0xb0, 0x77, 0xff, 0x07, 0x7f, 0xbe, 0x3f, 0x07, 0xca, 0xae, 0xb7, 0xe7, 0xb9,
|
||||||
|
0x61, 0xad, 0x92, 0x5c, 0xf6, 0xed, 0xa4, 0x38, 0x5e, 0x85, 0xd4, 0x03, 0x1a, 0x2e, 0x74, 0xcf,
|
||||||
|
0x25, 0x5a, 0xc1, 0xf5, 0xa4, 0xac, 0x5a, 0x90, 0xb9, 0x44, 0xbf, 0xe0, 0xfd, 0x28, 0x86, 0xa1,
|
||||||
|
0xc6, 0xcb, 0x8c, 0xc6, 0x12, 0x02, 0xe1, 0x28, 0x24, 0x66, 0xfe, 0xa7, 0x5f, 0xbc, 0xd5, 0x2e,
|
||||||
|
0xd3, 0x02, 0xe2, 0xb5, 0x62, 0xb4, 0x1a, 0x0d, 0x92, 0x0c, 0x22, 0x89, 0xc6, 0x88, 0x0e, 0xb3,
|
||||||
|
0x17, 0x57, 0x7b, 0x20, 0x4d, 0x21, 0xae, 0xa4, 0xb6, 0xb7, 0xcd, 0x46, 0x3f, 0x20, 0xd9, 0x78,
|
||||||
|
0x7d, 0x5a, 0xfe, 0x41, 0x54, 0xad, 0x5f, 0x22, 0xdf, 0x10, 0x2e, 0x56, 0x12, 0xb3, 0xdd, 0x7e,
|
||||||
|
0x9e, 0xb0, 0xfd, 0x14, 0xf5, 0xca, 0x5f, 0x08, 0x4e, 0x4a, 0x91, 0x1f, 0x08, 0x0e, 0x62, 0x22,
|
||||||
|
0x09, 0xdb, 0xfb, 0xf3, 0x94, 0x3d, 0xe9, 0xa9, 0xd7, 0xbc, 0xba, 0xab, 0xfe, 0xef, 0x01, 0x00,
|
||||||
|
0x00, 0xff, 0xff, 0x14, 0x42, 0xb8, 0x1d, 0x0b, 0x01, 0x00, 0x00,
|
||||||
|
}
|
||||||
23
examples/api/meta/proto/api.proto
Normal file
23
examples/api/meta/proto/api.proto
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
service Example {
|
||||||
|
rpc Call(CallRequest) returns(CallResponse) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
service Foo {
|
||||||
|
rpc Bar(EmptyRequest) returns(EmptyResponse) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
message CallRequest {
|
||||||
|
string name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CallResponse {
|
||||||
|
string message = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message EmptyRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message EmptyResponse {
|
||||||
|
}
|
||||||
32
examples/api/proxy/README.md
Normal file
32
examples/api/proxy/README.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Proxy API
|
||||||
|
|
||||||
|
This is an example of using the micro api as a http proxy.
|
||||||
|
|
||||||
|
Using the api as a http proxy gives you complete control over what languages or libraries to use
|
||||||
|
at the API layer. In this case we're using go-web to easily register http services.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run micro api with http proxy handler
|
||||||
|
|
||||||
|
```
|
||||||
|
micro api --handler=http
|
||||||
|
```
|
||||||
|
|
||||||
|
Run this proxy service
|
||||||
|
|
||||||
|
```
|
||||||
|
go run proxy.go
|
||||||
|
```
|
||||||
|
|
||||||
|
Make a GET request to /example/call which will call go.micro.api.example Example.Call
|
||||||
|
|
||||||
|
```
|
||||||
|
curl "http://localhost:8080/example/call?name=john"
|
||||||
|
```
|
||||||
|
|
||||||
|
Make a POST request to /example/foo/bar which will call go.micro.api.example Foo.Bar
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -H 'Content-Type: application/json' -d '{}' http://localhost:8080/example/foo/bar
|
||||||
|
```
|
||||||
84
examples/api/proxy/proxy.go
Normal file
84
examples/api/proxy/proxy.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2/errors"
|
||||||
|
"github.com/micro/go-micro/v2/web"
|
||||||
|
)
|
||||||
|
|
||||||
|
// exampleCall will handle /example/call
|
||||||
|
func exampleCall(w http.ResponseWriter, r *http.Request) {
|
||||||
|
r.ParseForm()
|
||||||
|
// get name
|
||||||
|
name := r.Form.Get("name")
|
||||||
|
|
||||||
|
if len(name) == 0 {
|
||||||
|
http.Error(
|
||||||
|
w,
|
||||||
|
errors.BadRequest("go.micro.api.example", "no content").Error(),
|
||||||
|
400,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// marshal response
|
||||||
|
b, _ := json.Marshal(map[string]interface{}{
|
||||||
|
"message": "got your message " + name,
|
||||||
|
})
|
||||||
|
|
||||||
|
// write response
|
||||||
|
w.Write(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// exampleFooBar will handle /example/foo/bar
|
||||||
|
func exampleFooBar(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != "POST" {
|
||||||
|
http.Error(
|
||||||
|
w,
|
||||||
|
errors.BadRequest("go.micro.api.example", "require post").Error(),
|
||||||
|
400,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.Header.Get("Content-Type")) == 0 {
|
||||||
|
http.Error(
|
||||||
|
w,
|
||||||
|
errors.BadRequest("go.micro.api.example", "need content-type").Error(),
|
||||||
|
400,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Header.Get("Content-Type") != "application/json" {
|
||||||
|
http.Error(
|
||||||
|
w,
|
||||||
|
errors.BadRequest("go.micro.api.example", "expect application/json").Error(),
|
||||||
|
400,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// we're using go-web for convenience since it registers with discovery
|
||||||
|
service := web.NewService(
|
||||||
|
web.Name("go.micro.api.example"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.HandleFunc("/example/call", exampleCall)
|
||||||
|
service.HandleFunc("/example/foo/bar", exampleFooBar)
|
||||||
|
|
||||||
|
if err := service.Init(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := service.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
33
examples/api/rpc/README.md
Normal file
33
examples/api/rpc/README.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# RPC API
|
||||||
|
|
||||||
|
This example makes use of the micro API with the RPC handler.
|
||||||
|
|
||||||
|
The api in this mode lets you serve http while routing to standard go-micro services via RPC.
|
||||||
|
|
||||||
|
The micro api with rpc handler only supports POST method and expects content-type of application/json or application/protobuf.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the micro API with the rpc handler
|
||||||
|
|
||||||
|
```
|
||||||
|
micro api --handler=rpc
|
||||||
|
```
|
||||||
|
|
||||||
|
Run this example
|
||||||
|
|
||||||
|
```
|
||||||
|
go run rpc.go
|
||||||
|
```
|
||||||
|
|
||||||
|
Make a POST request to /example/call which will call go.micro.api.example Example.Call
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -H 'Content-Type: application/json' -d '{"name": "john"}' "http://localhost:8080/example/call"
|
||||||
|
```
|
||||||
|
|
||||||
|
Make a POST request to /example/foo/bar which will call go.micro.api.example Foo.Bar
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -H 'Content-Type: application/json' -d '{}' http://localhost:8080/example/foo/bar
|
||||||
|
```
|
||||||
160
examples/api/rpc/proto/api.micro.go
Normal file
160
examples/api/rpc/proto/api.micro.go
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/api/rpc/proto/api.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package api is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/api/rpc/proto/api.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
CallRequest
|
||||||
|
CallResponse
|
||||||
|
EmptyRequest
|
||||||
|
EmptyResponse
|
||||||
|
*/
|
||||||
|
package api
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
client "github.com/micro/go-micro/v2/client"
|
||||||
|
server "github.com/micro/go-micro/v2/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ client.Option
|
||||||
|
var _ server.Option
|
||||||
|
|
||||||
|
// Client API for Example service
|
||||||
|
|
||||||
|
type ExampleService interface {
|
||||||
|
Call(ctx context.Context, in *CallRequest, opts ...client.CallOption) (*CallResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type exampleService struct {
|
||||||
|
c client.Client
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExampleService(serviceName string, c client.Client) ExampleService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(serviceName) == 0 {
|
||||||
|
serviceName = "example"
|
||||||
|
}
|
||||||
|
return &exampleService{
|
||||||
|
c: c,
|
||||||
|
serviceName: serviceName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *exampleService) Call(ctx context.Context, in *CallRequest, opts ...client.CallOption) (*CallResponse, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Example.Call", in)
|
||||||
|
out := new(CallResponse)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Example service
|
||||||
|
|
||||||
|
type ExampleHandler interface {
|
||||||
|
Call(context.Context, *CallRequest, *CallResponse) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterExampleHandler(s server.Server, hdlr ExampleHandler, opts ...server.HandlerOption) {
|
||||||
|
type example interface {
|
||||||
|
Call(ctx context.Context, in *CallRequest, out *CallResponse) error
|
||||||
|
}
|
||||||
|
type Example struct {
|
||||||
|
example
|
||||||
|
}
|
||||||
|
h := &exampleHandler{hdlr}
|
||||||
|
s.Handle(s.NewHandler(&Example{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type exampleHandler struct {
|
||||||
|
ExampleHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *exampleHandler) Call(ctx context.Context, in *CallRequest, out *CallResponse) error {
|
||||||
|
return h.ExampleHandler.Call(ctx, in, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client API for Foo service
|
||||||
|
|
||||||
|
type FooService interface {
|
||||||
|
Bar(ctx context.Context, in *EmptyRequest, opts ...client.CallOption) (*EmptyResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fooService struct {
|
||||||
|
c client.Client
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFooService(serviceName string, c client.Client) FooService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(serviceName) == 0 {
|
||||||
|
serviceName = "foo"
|
||||||
|
}
|
||||||
|
return &fooService{
|
||||||
|
c: c,
|
||||||
|
serviceName: serviceName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fooService) Bar(ctx context.Context, in *EmptyRequest, opts ...client.CallOption) (*EmptyResponse, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Foo.Bar", in)
|
||||||
|
out := new(EmptyResponse)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Foo service
|
||||||
|
|
||||||
|
type FooHandler interface {
|
||||||
|
Bar(context.Context, *EmptyRequest, *EmptyResponse) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterFooHandler(s server.Server, hdlr FooHandler, opts ...server.HandlerOption) {
|
||||||
|
type foo interface {
|
||||||
|
Bar(ctx context.Context, in *EmptyRequest, out *EmptyResponse) error
|
||||||
|
}
|
||||||
|
type Foo struct {
|
||||||
|
foo
|
||||||
|
}
|
||||||
|
h := &fooHandler{hdlr}
|
||||||
|
s.Handle(s.NewHandler(&Foo{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type fooHandler struct {
|
||||||
|
FooHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *fooHandler) Bar(ctx context.Context, in *EmptyRequest, out *EmptyResponse) error {
|
||||||
|
return h.FooHandler.Bar(ctx, in, out)
|
||||||
|
}
|
||||||
246
examples/api/rpc/proto/api.pb.go
Normal file
246
examples/api/rpc/proto/api.pb.go
Normal file
@@ -0,0 +1,246 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/api/rpc/proto/api.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package api is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/api/rpc/proto/api.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
CallRequest
|
||||||
|
CallResponse
|
||||||
|
EmptyRequest
|
||||||
|
EmptyResponse
|
||||||
|
*/
|
||||||
|
package api
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "golang.org/x/net/context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
type CallRequest struct {
|
||||||
|
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *CallRequest) Reset() { *m = CallRequest{} }
|
||||||
|
func (m *CallRequest) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*CallRequest) ProtoMessage() {}
|
||||||
|
func (*CallRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
|
||||||
|
func (m *CallRequest) GetName() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type CallResponse struct {
|
||||||
|
Message string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *CallResponse) Reset() { *m = CallResponse{} }
|
||||||
|
func (m *CallResponse) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*CallResponse) ProtoMessage() {}
|
||||||
|
func (*CallResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||||
|
|
||||||
|
func (m *CallResponse) GetMessage() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Message
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmptyRequest struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *EmptyRequest) Reset() { *m = EmptyRequest{} }
|
||||||
|
func (m *EmptyRequest) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*EmptyRequest) ProtoMessage() {}
|
||||||
|
func (*EmptyRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||||
|
|
||||||
|
type EmptyResponse struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *EmptyResponse) Reset() { *m = EmptyResponse{} }
|
||||||
|
func (m *EmptyResponse) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*EmptyResponse) ProtoMessage() {}
|
||||||
|
func (*EmptyResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*CallRequest)(nil), "CallRequest")
|
||||||
|
proto.RegisterType((*CallResponse)(nil), "CallResponse")
|
||||||
|
proto.RegisterType((*EmptyRequest)(nil), "EmptyRequest")
|
||||||
|
proto.RegisterType((*EmptyResponse)(nil), "EmptyResponse")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ grpc.ClientConn
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
const _ = grpc.SupportPackageIsVersion4
|
||||||
|
|
||||||
|
// Client API for Example service
|
||||||
|
|
||||||
|
type ExampleClient interface {
|
||||||
|
Call(ctx context.Context, in *CallRequest, opts ...grpc.CallOption) (*CallResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type exampleClient struct {
|
||||||
|
cc *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewExampleClient(cc *grpc.ClientConn) ExampleClient {
|
||||||
|
return &exampleClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *exampleClient) Call(ctx context.Context, in *CallRequest, opts ...grpc.CallOption) (*CallResponse, error) {
|
||||||
|
out := new(CallResponse)
|
||||||
|
err := grpc.Invoke(ctx, "/Example/Call", in, out, c.cc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Example service
|
||||||
|
|
||||||
|
type ExampleServer interface {
|
||||||
|
Call(context.Context, *CallRequest) (*CallResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterExampleServer(s *grpc.Server, srv ExampleServer) {
|
||||||
|
s.RegisterService(&_Example_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Example_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(CallRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(ExampleServer).Call(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/Example/Call",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(ExampleServer).Call(ctx, req.(*CallRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _Example_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "Example",
|
||||||
|
HandlerType: (*ExampleServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "Call",
|
||||||
|
Handler: _Example_Call_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "github.com/micro/examples/api/rpc/proto/api.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client API for Foo service
|
||||||
|
|
||||||
|
type FooClient interface {
|
||||||
|
Bar(ctx context.Context, in *EmptyRequest, opts ...grpc.CallOption) (*EmptyResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type fooClient struct {
|
||||||
|
cc *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFooClient(cc *grpc.ClientConn) FooClient {
|
||||||
|
return &fooClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fooClient) Bar(ctx context.Context, in *EmptyRequest, opts ...grpc.CallOption) (*EmptyResponse, error) {
|
||||||
|
out := new(EmptyResponse)
|
||||||
|
err := grpc.Invoke(ctx, "/Foo/Bar", in, out, c.cc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Foo service
|
||||||
|
|
||||||
|
type FooServer interface {
|
||||||
|
Bar(context.Context, *EmptyRequest) (*EmptyResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterFooServer(s *grpc.Server, srv FooServer) {
|
||||||
|
s.RegisterService(&_Foo_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Foo_Bar_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(EmptyRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(FooServer).Bar(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/Foo/Bar",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(FooServer).Bar(ctx, req.(*EmptyRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _Foo_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "Foo",
|
||||||
|
HandlerType: (*FooServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "Bar",
|
||||||
|
Handler: _Foo_Bar_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "github.com/micro/examples/api/rpc/proto/api.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("github.com/micro/examples/api/rpc/proto/api.proto", fileDescriptor0) }
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 203 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x8f, 0x51, 0x6a, 0x84, 0x30,
|
||||||
|
0x14, 0x45, 0xb5, 0x4a, 0xa5, 0xaf, 0x6a, 0x21, 0x5f, 0xe2, 0x57, 0x1b, 0x68, 0xf1, 0xa7, 0x49,
|
||||||
|
0x6b, 0x77, 0xd0, 0x62, 0x17, 0xe0, 0x0e, 0xa2, 0x3c, 0xac, 0x60, 0x4c, 0x9a, 0x44, 0x98, 0xd9,
|
||||||
|
0xfd, 0x60, 0x74, 0xc0, 0xf9, 0xbb, 0x07, 0x6e, 0xce, 0xcd, 0x83, 0xcf, 0x61, 0x74, 0x7f, 0x4b,
|
||||||
|
0xc7, 0x7a, 0x25, 0xb9, 0x1c, 0x7b, 0xa3, 0x38, 0x9e, 0x84, 0xd4, 0x13, 0x5a, 0x2e, 0xf4, 0xc8,
|
||||||
|
0x8d, 0xee, 0xb9, 0x36, 0xca, 0xa9, 0x95, 0x98, 0x4f, 0xf4, 0x05, 0x1e, 0x7f, 0xc4, 0x34, 0xb5,
|
||||||
|
0xf8, 0xbf, 0xa0, 0x75, 0x84, 0x40, 0x3c, 0x0b, 0x89, 0x45, 0xf8, 0x1c, 0x56, 0x0f, 0xad, 0xcf,
|
||||||
|
0xb4, 0x82, 0x74, 0xab, 0x58, 0xad, 0x66, 0x8b, 0xa4, 0x80, 0x44, 0xa2, 0xb5, 0x62, 0xc0, 0xe2,
|
||||||
|
0xce, 0xd7, 0xae, 0x48, 0x73, 0x48, 0x1b, 0xa9, 0xdd, 0x79, 0xb7, 0xd1, 0x27, 0xc8, 0x76, 0xde,
|
||||||
|
0x9e, 0xd6, 0x1f, 0x90, 0x34, 0xdb, 0x8f, 0xc8, 0x2b, 0xc4, 0xab, 0x95, 0xa4, 0xec, 0xb0, 0x5f,
|
||||||
|
0x66, 0xec, 0x38, 0x45, 0x83, 0xfa, 0x1d, 0xa2, 0x5f, 0xa5, 0xc8, 0x1b, 0x44, 0xdf, 0xc2, 0x90,
|
||||||
|
0x8c, 0x1d, 0xfd, 0x65, 0xce, 0x6e, 0xf4, 0x34, 0xe8, 0xee, 0xfd, 0x55, 0x5f, 0x97, 0x00, 0x00,
|
||||||
|
0x00, 0xff, 0xff, 0x81, 0x2d, 0x74, 0x3d, 0x0a, 0x01, 0x00, 0x00,
|
||||||
|
}
|
||||||
23
examples/api/rpc/proto/api.proto
Normal file
23
examples/api/rpc/proto/api.proto
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
service Example {
|
||||||
|
rpc Call(CallRequest) returns(CallResponse) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
service Foo {
|
||||||
|
rpc Bar(EmptyRequest) returns(EmptyResponse) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
message CallRequest {
|
||||||
|
string name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CallResponse {
|
||||||
|
string message = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message EmptyRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message EmptyResponse {
|
||||||
|
}
|
||||||
57
examples/api/rpc/rpc.go
Normal file
57
examples/api/rpc/rpc.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
proto "github.com/micro/examples/api/rpc/proto"
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
"github.com/micro/go-micro/v2/errors"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Example struct{}
|
||||||
|
|
||||||
|
type Foo struct{}
|
||||||
|
|
||||||
|
// Example.Call is a method which will be served by http request /example/call
|
||||||
|
// In the event we see /[service]/[method] the [service] is used as part of the method
|
||||||
|
// E.g /example/call goes to go.micro.api.example Example.Call
|
||||||
|
func (e *Example) Call(ctx context.Context, req *proto.CallRequest, rsp *proto.CallResponse) error {
|
||||||
|
log.Print("Received Example.Call request")
|
||||||
|
|
||||||
|
if len(req.Name) == 0 {
|
||||||
|
return errors.BadRequest("go.micro.api.example", "no content")
|
||||||
|
}
|
||||||
|
|
||||||
|
rsp.Message = "got your request " + req.Name
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Foo.Bar is a method which will be served by http request /example/foo/bar
|
||||||
|
// Because Foo is not the same as the service name it is mapped beyond /example/
|
||||||
|
func (f *Foo) Bar(ctx context.Context, req *proto.EmptyRequest, rsp *proto.EmptyResponse) error {
|
||||||
|
log.Print("Received Foo.Bar request")
|
||||||
|
|
||||||
|
// noop
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("go.micro.api.example"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
// register example handler
|
||||||
|
proto.RegisterExampleHandler(service.Server(), new(Example))
|
||||||
|
|
||||||
|
// register foo handler
|
||||||
|
proto.RegisterFooHandler(service.Server(), new(Foo))
|
||||||
|
|
||||||
|
if err := service.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
22
examples/booking/Makefile
Normal file
22
examples/booking/Makefile
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
.PHONY: proto data build
|
||||||
|
|
||||||
|
proto:
|
||||||
|
for d in api srv; do \
|
||||||
|
for f in $$d/**/proto/*.proto; do \
|
||||||
|
protoc --proto_path=${GOPATH}/src:. --micro_out=. --go_out=. $$f; \
|
||||||
|
echo compiled: $$f; \
|
||||||
|
done \
|
||||||
|
done
|
||||||
|
|
||||||
|
lint:
|
||||||
|
./bin/lint.sh
|
||||||
|
|
||||||
|
build:
|
||||||
|
./bin/build.sh
|
||||||
|
|
||||||
|
data:
|
||||||
|
go-bindata -o data/bindata.go -pkg data data/*.json
|
||||||
|
|
||||||
|
run:
|
||||||
|
docker-compose build
|
||||||
|
docker-compose up
|
||||||
107
examples/booking/README.md
Normal file
107
examples/booking/README.md
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# Booking.com Example
|
||||||
|
|
||||||
|
This is [@harlow](https://github.com/harlow)'s [go-micro-services](https://github.com/harlow/go-micro-services) example converted to use Micro.
|
||||||
|
|
||||||
|
His README (with required changes):
|
||||||
|
|
||||||
|
The API Endpoint accepts HTTP requests at `localhost:8080` and then spawns a number of RPC requests to the backend services.
|
||||||
|
|
||||||
|
_Note:_ Data for each of the services is stored in JSON flat files under the `/data/` directory. In reality each of the services could choose their own specialty datastore. The Geo service for example could use PostGis or any other database specializing in geospacial queries.
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
Docker is required for running the services https://docs.docker.com/engine/installation.
|
||||||
|
|
||||||
|
Protobuf v3 are required:
|
||||||
|
|
||||||
|
$ brew install protobuf
|
||||||
|
|
||||||
|
Install the protoc-gen libraries and other dependencies:
|
||||||
|
|
||||||
|
$ go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
|
||||||
|
$ go get -u github.com/micro/protoc-gen-micro
|
||||||
|
$ go get -u github.com/micro/go-micro
|
||||||
|
$ go get -u github.com/hailocab/go-geoindex
|
||||||
|
|
||||||
|
Clone the repository:
|
||||||
|
|
||||||
|
$ git clone git@github.com:micro/micro.git
|
||||||
|
|
||||||
|
Change to examples dir
|
||||||
|
|
||||||
|
$ cd micro/examples/booking
|
||||||
|
|
||||||
|
### Protobufs
|
||||||
|
|
||||||
|
If changes are made to the Protocol Buffer files use the Makefile to regenerate:
|
||||||
|
|
||||||
|
$ make proto
|
||||||
|
|
||||||
|
### Run
|
||||||
|
|
||||||
|
To make the demo as straigforward as possible; [Docker Compose](https://docs.docker.com/compose/) is used to run all the services at once (In a production environment each of the services would be run (and scaled) independently).
|
||||||
|
|
||||||
|
$ make build
|
||||||
|
$ make run
|
||||||
|
|
||||||
|
Curl the endpoint with an invalid auth token:
|
||||||
|
|
||||||
|
$ curl -H 'Content-Type: application/json' \
|
||||||
|
-H "Authorization: Bearer INVALID_TOKEN" \
|
||||||
|
-d '{"inDate": "2015-04-09"}' \
|
||||||
|
http://localhost:8080/hotel/rates
|
||||||
|
|
||||||
|
{"id":"api.hotel.rates","code":401,"detail":"Unauthorized","status":"Unauthorized"}
|
||||||
|
|
||||||
|
Curl the endpoint without checkin or checkout dates:
|
||||||
|
|
||||||
|
$ curl -H 'Content-Type: application/json' \
|
||||||
|
-H "Authorization: Bearer VALID_TOKEN" \
|
||||||
|
-d '{"inDate": "2015-04-09"}' \
|
||||||
|
http://localhost:8080/hotel/rates
|
||||||
|
|
||||||
|
{"id":"api.hotel.rates","code":400,"detail":"Please specify inDate/outDate params","status":"Bad Request"}
|
||||||
|
|
||||||
|
Curl the API endpoint with a valid auth token:
|
||||||
|
|
||||||
|
$ curl -H 'Content-Type: application/json' \
|
||||||
|
-H "Authorization: Bearer VALID_TOKEN" \
|
||||||
|
-d '{"inDate": "2015-04-09", "outDate": "2015-04-10"}' \
|
||||||
|
http://localhost:8080/hotel/rates
|
||||||
|
|
||||||
|
The JSON response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"hotels": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"name": "Clift Hotel",
|
||||||
|
"phoneNumber": "(415) 775-4700",
|
||||||
|
"description": "A 6-minute walk from Union Square and 4 minutes from a Muni Metro station, this luxury hotel designed by Philippe Starck features an artsy furniture collection in the lobby, including work by Salvador Dali.",
|
||||||
|
"address": {
|
||||||
|
"streetNumber": "495",
|
||||||
|
"streetName": "Geary St",
|
||||||
|
"city": "San Francisco",
|
||||||
|
"state": "CA",
|
||||||
|
"country": "United States",
|
||||||
|
"postalCode": "94102"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"ratePlans": [
|
||||||
|
{
|
||||||
|
"hotelId": 1,
|
||||||
|
"code": "RACK",
|
||||||
|
"inDate": "2015-04-09",
|
||||||
|
"outDate": "2015-04-10",
|
||||||
|
"roomType": {
|
||||||
|
"bookableRate": 109,
|
||||||
|
"totalRate": 109,
|
||||||
|
"totalRateInclusive": 123.17,
|
||||||
|
"code": "KNG"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
4
examples/booking/api/hotel/Dockerfile
Normal file
4
examples/booking/api/hotel/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM alpine:3.2
|
||||||
|
ADD . /app
|
||||||
|
WORKDIR /app
|
||||||
|
ENTRYPOINT [ "/app/hotel" ]
|
||||||
192
examples/booking/api/hotel/main.go
Normal file
192
examples/booking/api/hotel/main.go
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
|
_ "expvar"
|
||||||
|
|
||||||
|
"net/http"
|
||||||
|
_ "net/http/pprof"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/trace"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/micro/examples/booking/api/hotel/proto"
|
||||||
|
"github.com/micro/examples/booking/srv/auth/proto"
|
||||||
|
"github.com/micro/examples/booking/srv/geo/proto"
|
||||||
|
"github.com/micro/examples/booking/srv/profile/proto"
|
||||||
|
"github.com/micro/examples/booking/srv/rate/proto"
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
"github.com/micro/go-micro/v2/client"
|
||||||
|
merr "github.com/micro/go-micro/v2/errors"
|
||||||
|
"github.com/micro/go-micro/v2/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
BASIC_SCHEMA string = "Basic "
|
||||||
|
BEARER_SCHEMA string = "Bearer "
|
||||||
|
)
|
||||||
|
|
||||||
|
type profileResults struct {
|
||||||
|
hotels []*profile.Hotel
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type rateResults struct {
|
||||||
|
ratePlans []*rate.RatePlan
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Hotel struct {
|
||||||
|
Client client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Hotel) Rates(ctx context.Context, req *hotel.Request, rsp *hotel.Response) error {
|
||||||
|
// tracing
|
||||||
|
tr := trace.New("api.v1", "Hotel.Rates")
|
||||||
|
defer tr.Finish()
|
||||||
|
|
||||||
|
// context
|
||||||
|
ctx = trace.NewContext(ctx, tr)
|
||||||
|
|
||||||
|
md, ok := metadata.FromContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
md = metadata.Metadata{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a unique request id to context
|
||||||
|
traceID := uuid.New()
|
||||||
|
// make copy
|
||||||
|
tmd := metadata.Metadata{}
|
||||||
|
for k, v := range md {
|
||||||
|
tmd[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
tmd["traceID"] = traceID.String()
|
||||||
|
tmd["fromName"] = "api.v1"
|
||||||
|
ctx = metadata.NewContext(ctx, tmd)
|
||||||
|
|
||||||
|
// token from request headers
|
||||||
|
token, err := getToken(md)
|
||||||
|
if err != nil {
|
||||||
|
return merr.Forbidden("api.hotel.rates", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify token w/ auth service
|
||||||
|
authClient := auth.NewAuthService("go.micro.srv.auth", s.Client)
|
||||||
|
if _, err = authClient.VerifyToken(ctx, &auth.Request{AuthToken: token}); err != nil {
|
||||||
|
return merr.Unauthorized("api.hotel.rates", "Unauthorized")
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkin and checkout date query params
|
||||||
|
inDate, outDate := req.InDate, req.OutDate
|
||||||
|
if inDate == "" || outDate == "" {
|
||||||
|
return merr.BadRequest("api.hotel.rates", "Please specify inDate/outDate params")
|
||||||
|
}
|
||||||
|
|
||||||
|
// finds nearby hotels
|
||||||
|
// TODO(hw): use lat/lon from request params
|
||||||
|
geoClient := geo.NewGeoService("go.micro.srv.geo", s.Client)
|
||||||
|
nearby, err := geoClient.Nearby(ctx, &geo.Request{
|
||||||
|
Lat: 51.502973,
|
||||||
|
Lon: -0.114723,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return merr.InternalServerError("api.hotel.rates", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// make requests for profiles and rates
|
||||||
|
profileCh := getHotelProfiles(s.Client, ctx, nearby.HotelIds)
|
||||||
|
rateCh := getRatePlans(s.Client, ctx, nearby.HotelIds, inDate, outDate)
|
||||||
|
|
||||||
|
// wait on profiles reply
|
||||||
|
profileReply := <-profileCh
|
||||||
|
if err := profileReply.err; err != nil {
|
||||||
|
return merr.InternalServerError("api.hotel.rates", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait on rates reply
|
||||||
|
rateReply := <-rateCh
|
||||||
|
if err := rateReply.err; err != nil {
|
||||||
|
return merr.InternalServerError("api.hotel.rates", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
rsp.Hotels = profileReply.hotels
|
||||||
|
rsp.RatePlans = rateReply.ratePlans
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getToken(md metadata.Metadata) (string, error) {
|
||||||
|
// Grab the raw Authorization header
|
||||||
|
authHeader := md["Authorization"]
|
||||||
|
if authHeader == "" {
|
||||||
|
return "", errors.New("Authorization header required")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Confirm the request is sending Basic Authentication credentials.
|
||||||
|
if !strings.HasPrefix(authHeader, BASIC_SCHEMA) && !strings.HasPrefix(authHeader, BEARER_SCHEMA) {
|
||||||
|
return "", errors.New("Authorization requires Basic/Bearer scheme")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the token from the request header
|
||||||
|
// The first six characters are skipped - e.g. "Basic ".
|
||||||
|
if strings.HasPrefix(authHeader, BASIC_SCHEMA) {
|
||||||
|
str, err := base64.StdEncoding.DecodeString(authHeader[len(BASIC_SCHEMA):])
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.New("Base64 encoding issue")
|
||||||
|
}
|
||||||
|
creds := strings.Split(string(str), ":")
|
||||||
|
return creds[0], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return authHeader[len(BEARER_SCHEMA):], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRatePlans(c client.Client, ctx context.Context, hotelIDs []string, inDate string, outDate string) chan rateResults {
|
||||||
|
rateClient := rate.NewRateService("go.micro.srv.rate", c)
|
||||||
|
ch := make(chan rateResults, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
res, err := rateClient.GetRates(ctx, &rate.Request{
|
||||||
|
HotelIds: hotelIDs,
|
||||||
|
InDate: inDate,
|
||||||
|
OutDate: outDate,
|
||||||
|
})
|
||||||
|
ch <- rateResults{res.RatePlans, err}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
func getHotelProfiles(c client.Client, ctx context.Context, hotelIDs []string) chan profileResults {
|
||||||
|
profileClient := profile.NewProfileService("go.micro.srv.profile", c)
|
||||||
|
ch := make(chan profileResults, 1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
res, err := profileClient.GetProfiles(ctx, &profile.Request{
|
||||||
|
HotelIds: hotelIDs,
|
||||||
|
Locale: "en",
|
||||||
|
})
|
||||||
|
ch <- profileResults{res.Hotels, err}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return ch
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// trace library patched for demo purposes.
|
||||||
|
// https://github.com/golang/net/blob/master/trace/trace.go#L94
|
||||||
|
trace.AuthRequest = func(req *http.Request) (any, sensitive bool) {
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("go.micro.api.hotel"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.Init()
|
||||||
|
hotel.RegisterHotelHandler(service.Server(), &Hotel{service.Client()})
|
||||||
|
service.Run()
|
||||||
|
}
|
||||||
101
examples/booking/api/hotel/proto/hotel.micro.go
Normal file
101
examples/booking/api/hotel/proto/hotel.micro.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/booking/api/hotel/proto/hotel.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package hotel is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/booking/api/hotel/proto/hotel.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Request
|
||||||
|
Response
|
||||||
|
*/
|
||||||
|
package hotel
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
import _ "github.com/micro/examples/booking/srv/profile/proto"
|
||||||
|
import _ "github.com/micro/examples/booking/srv/rate/proto"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
client "github.com/micro/go-micro/v2/client"
|
||||||
|
server "github.com/micro/go-micro/v2/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ client.Option
|
||||||
|
var _ server.Option
|
||||||
|
|
||||||
|
// Client API for Hotel service
|
||||||
|
|
||||||
|
type HotelService interface {
|
||||||
|
Rates(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type hotelService struct {
|
||||||
|
c client.Client
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHotelService(serviceName string, c client.Client) HotelService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(serviceName) == 0 {
|
||||||
|
serviceName = "hotel"
|
||||||
|
}
|
||||||
|
return &hotelService{
|
||||||
|
c: c,
|
||||||
|
serviceName: serviceName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *hotelService) Rates(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Hotel.Rates", in)
|
||||||
|
out := new(Response)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Hotel service
|
||||||
|
|
||||||
|
type HotelHandler interface {
|
||||||
|
Rates(context.Context, *Request, *Response) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterHotelHandler(s server.Server, hdlr HotelHandler, opts ...server.HandlerOption) {
|
||||||
|
type hotel interface {
|
||||||
|
Rates(ctx context.Context, in *Request, out *Response) error
|
||||||
|
}
|
||||||
|
type Hotel struct {
|
||||||
|
hotel
|
||||||
|
}
|
||||||
|
h := &hotelHandler{hdlr}
|
||||||
|
s.Handle(s.NewHandler(&Hotel{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type hotelHandler struct {
|
||||||
|
HotelHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hotelHandler) Rates(ctx context.Context, in *Request, out *Response) error {
|
||||||
|
return h.HotelHandler.Rates(ctx, in, out)
|
||||||
|
}
|
||||||
185
examples/booking/api/hotel/proto/hotel.pb.go
Normal file
185
examples/booking/api/hotel/proto/hotel.pb.go
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/booking/api/hotel/proto/hotel.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package hotel is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/booking/api/hotel/proto/hotel.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Request
|
||||||
|
Response
|
||||||
|
*/
|
||||||
|
package hotel
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
import profile "github.com/micro/examples/booking/srv/profile/proto"
|
||||||
|
import rate "github.com/micro/examples/booking/srv/rate/proto"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "golang.org/x/net/context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
InDate string `protobuf:"bytes,1,opt,name=inDate" json:"inDate,omitempty"`
|
||||||
|
OutDate string `protobuf:"bytes,2,opt,name=outDate" json:"outDate,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Request) Reset() { *m = Request{} }
|
||||||
|
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Request) ProtoMessage() {}
|
||||||
|
func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
|
||||||
|
func (m *Request) GetInDate() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.InDate
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Request) GetOutDate() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.OutDate
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Hotels []*profile.Hotel `protobuf:"bytes,1,rep,name=hotels" json:"hotels,omitempty"`
|
||||||
|
RatePlans []*rate.RatePlan `protobuf:"bytes,2,rep,name=ratePlans" json:"ratePlans,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Response) Reset() { *m = Response{} }
|
||||||
|
func (m *Response) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Response) ProtoMessage() {}
|
||||||
|
func (*Response) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||||
|
|
||||||
|
func (m *Response) GetHotels() []*profile.Hotel {
|
||||||
|
if m != nil {
|
||||||
|
return m.Hotels
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Response) GetRatePlans() []*rate.RatePlan {
|
||||||
|
if m != nil {
|
||||||
|
return m.RatePlans
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Request)(nil), "hotel.Request")
|
||||||
|
proto.RegisterType((*Response)(nil), "hotel.Response")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ grpc.ClientConn
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
const _ = grpc.SupportPackageIsVersion4
|
||||||
|
|
||||||
|
// Client API for Hotel service
|
||||||
|
|
||||||
|
type HotelClient interface {
|
||||||
|
Rates(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type hotelClient struct {
|
||||||
|
cc *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHotelClient(cc *grpc.ClientConn) HotelClient {
|
||||||
|
return &hotelClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *hotelClient) Rates(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
|
||||||
|
out := new(Response)
|
||||||
|
err := grpc.Invoke(ctx, "/hotel.Hotel/Rates", in, out, c.cc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Hotel service
|
||||||
|
|
||||||
|
type HotelServer interface {
|
||||||
|
Rates(context.Context, *Request) (*Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterHotelServer(s *grpc.Server, srv HotelServer) {
|
||||||
|
s.RegisterService(&_Hotel_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Hotel_Rates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(Request)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(HotelServer).Rates(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/hotel.Hotel/Rates",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(HotelServer).Rates(ctx, req.(*Request))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _Hotel_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "hotel.Hotel",
|
||||||
|
HandlerType: (*HotelServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "Rates",
|
||||||
|
Handler: _Hotel_Rates_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "github.com/micro/examples/booking/api/hotel/proto/hotel.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterFile("github.com/micro/examples/booking/api/hotel/proto/hotel.proto", fileDescriptor0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 246 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x50, 0xc1, 0x4a, 0xc3, 0x40,
|
||||||
|
0x10, 0x35, 0x95, 0xa4, 0x76, 0x84, 0x0a, 0x7b, 0x90, 0x90, 0x53, 0xc9, 0x41, 0x8a, 0x48, 0x16,
|
||||||
|
0xda, 0x63, 0xf1, 0x20, 0x78, 0xf0, 0x28, 0xfb, 0x05, 0x6e, 0xca, 0xd8, 0x2c, 0x26, 0x99, 0x98,
|
||||||
|
0xdd, 0x88, 0x9f, 0x2f, 0x3b, 0xbb, 0xd1, 0xa3, 0xbd, 0xbd, 0x37, 0x6f, 0xde, 0xdb, 0x37, 0x0b,
|
||||||
|
0x8f, 0x27, 0xe3, 0x9a, 0xa9, 0xae, 0x8e, 0xd4, 0xc9, 0xce, 0x1c, 0x47, 0x92, 0xf8, 0xad, 0xbb,
|
||||||
|
0xa1, 0x45, 0x2b, 0x6b, 0xa2, 0x0f, 0xd3, 0x9f, 0xa4, 0x1e, 0x8c, 0x6c, 0xc8, 0x61, 0x2b, 0x87,
|
||||||
|
0x91, 0x1c, 0x05, 0x5c, 0x31, 0x16, 0x29, 0x93, 0xe2, 0xe9, 0xff, 0x14, 0x3b, 0x7e, 0x79, 0xff,
|
||||||
|
0xbb, 0x69, 0x31, 0xe6, 0x44, 0x16, 0x92, 0x8a, 0xc3, 0x79, 0x11, 0xa3, 0x76, 0xb3, 0xdf, 0xc3,
|
||||||
|
0x60, 0x2e, 0x0f, 0xb0, 0x54, 0xf8, 0x39, 0xa1, 0x75, 0xe2, 0x16, 0x32, 0xd3, 0x3f, 0x6b, 0x87,
|
||||||
|
0x79, 0xb2, 0x49, 0xb6, 0x2b, 0x15, 0x99, 0xc8, 0x61, 0x49, 0x93, 0x63, 0x61, 0xc1, 0xc2, 0x4c,
|
||||||
|
0xcb, 0x37, 0xb8, 0x52, 0x68, 0x07, 0xea, 0x2d, 0x8a, 0x3b, 0xc8, 0xf8, 0x22, 0x9b, 0x27, 0x9b,
|
||||||
|
0xcb, 0xed, 0xf5, 0x6e, 0x5d, 0xcd, 0x2d, 0x5f, 0xfc, 0x58, 0x45, 0x55, 0x3c, 0xc0, 0xca, 0x3f,
|
||||||
|
0xff, 0xda, 0xea, 0xde, 0xe6, 0x8b, 0xb8, 0xca, 0x85, 0x54, 0x1c, 0xab, 0xbf, 0x85, 0xdd, 0x1e,
|
||||||
|
0x52, 0xb6, 0x8b, 0x7b, 0x48, 0xbd, 0x6e, 0xc5, 0xba, 0x0a, 0xbf, 0x18, 0x5b, 0x17, 0x37, 0xbf,
|
||||||
|
0x3c, 0x14, 0x29, 0x2f, 0xea, 0x8c, 0x4f, 0xdb, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x11, 0xa3,
|
||||||
|
0x5e, 0xbd, 0xa2, 0x01, 0x00, 0x00,
|
||||||
|
}
|
||||||
20
examples/booking/api/hotel/proto/hotel.proto
Normal file
20
examples/booking/api/hotel/proto/hotel.proto
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package hotel;
|
||||||
|
|
||||||
|
import "github.com/micro/examples/booking/srv/profile/proto/profile.proto";
|
||||||
|
import "github.com/micro/examples/booking/srv/rate/proto/rate.proto";
|
||||||
|
|
||||||
|
service Hotel {
|
||||||
|
rpc Rates(Request) returns (Response) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
message Request {
|
||||||
|
string inDate = 1;
|
||||||
|
string outDate = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Response {
|
||||||
|
repeated profile.Hotel hotels = 1;
|
||||||
|
repeated rate.RatePlan ratePlans = 2;
|
||||||
|
}
|
||||||
15
examples/booking/bin/build.sh
Executable file
15
examples/booking/bin/build.sh
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
dir=`pwd`
|
||||||
|
|
||||||
|
build() {
|
||||||
|
for d in $(ls ./$1); do
|
||||||
|
echo "building $1/$d"
|
||||||
|
pushd $dir/$1/$d >/dev/null
|
||||||
|
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w'
|
||||||
|
popd >/dev/null
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
build api
|
||||||
|
build srv
|
||||||
16
examples/booking/bin/lint.sh
Executable file
16
examples/booking/bin/lint.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
dir=`pwd`
|
||||||
|
|
||||||
|
check() {
|
||||||
|
for d in $(ls ./$1); do
|
||||||
|
echo "verifying $1/$d"
|
||||||
|
pushd $dir/$1/$d >/dev/null
|
||||||
|
go fmt
|
||||||
|
golint
|
||||||
|
popd >/dev/null
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
check api
|
||||||
|
check srv
|
||||||
306
examples/booking/data/bindata.go
Normal file
306
examples/booking/data/bindata.go
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
// Code generated by go-bindata.
|
||||||
|
// sources:
|
||||||
|
// data/customers.json
|
||||||
|
// data/locations.json
|
||||||
|
// data/profiles.json
|
||||||
|
// data/rates.json
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func bindataRead(data []byte, name string) ([]byte, error) {
|
||||||
|
gz, err := gzip.NewReader(bytes.NewBuffer(data))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
_, err = io.Copy(&buf, gz)
|
||||||
|
clErr := gz.Close()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Read %q: %v", name, err)
|
||||||
|
}
|
||||||
|
if clErr != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type asset struct {
|
||||||
|
bytes []byte
|
||||||
|
info os.FileInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type bindataFileInfo struct {
|
||||||
|
name string
|
||||||
|
size int64
|
||||||
|
mode os.FileMode
|
||||||
|
modTime time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fi bindataFileInfo) Name() string {
|
||||||
|
return fi.name
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) Size() int64 {
|
||||||
|
return fi.size
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) Mode() os.FileMode {
|
||||||
|
return fi.mode
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) ModTime() time.Time {
|
||||||
|
return fi.modTime
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) IsDir() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
func (fi bindataFileInfo) Sys() interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dataCustomersJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x8a\xe6\x52\x00\x82\x6a\x30\x09\x02\x4a\x99\x29\x4a\x56\x0a\x86\x3a\x08\x81\xc4\xd2\x92\x8c\x90\xfc\xec\xd4\x3c\xa0\xb8\x52\x98\xa3\x8f\xa7\x4b\x7c\x88\xbf\xb7\xab\x9f\x12\x58\x49\x2d\x57\x2c\x17\x20\x00\x00\xff\xff\x2b\x28\xf3\x0d\x44\x00\x00\x00")
|
||||||
|
|
||||||
|
func dataCustomersJsonBytes() ([]byte, error) {
|
||||||
|
return bindataRead(
|
||||||
|
_dataCustomersJson,
|
||||||
|
"data/customers.json",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataCustomersJson() (*asset, error) {
|
||||||
|
bytes, err := dataCustomersJsonBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := bindataFileInfo{name: "data/customers.json", size: 68, mode: os.FileMode(420), modTime: time.Unix(1445724030, 0)}
|
||||||
|
a := &asset{bytes: bytes, info: info}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dataLocationsJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x8a\xe6\x52\x00\x82\x6a\x30\x09\x02\x4a\x19\xf9\x25\xa9\x39\x9e\x29\x4a\x56\x0a\x4a\x86\x4a\x3a\x08\xf1\x9c\xc4\x12\xa0\x98\xa9\xa1\x9e\xa9\x81\x91\xa5\xb9\x31\xb2\x4c\x7e\x1e\x50\x46\xd7\x40\xcf\xd0\xd0\xc4\xdc\xc8\x18\x2c\x51\xab\x83\xc7\x5c\x23\x1a\x99\x6b\x4c\x23\x73\x4d\x68\x64\xae\x29\x8d\xcc\x35\xa3\xc0\x5c\xae\x58\x2e\x40\x00\x00\x00\xff\xff\xab\x3a\x0e\xb4\x13\x02\x00\x00")
|
||||||
|
|
||||||
|
func dataLocationsJsonBytes() ([]byte, error) {
|
||||||
|
return bindataRead(
|
||||||
|
_dataLocationsJson,
|
||||||
|
"data/locations.json",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataLocationsJson() (*asset, error) {
|
||||||
|
bytes, err := dataLocationsJsonBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := bindataFileInfo{name: "data/locations.json", size: 531, mode: os.FileMode(420), modTime: time.Unix(1456591447, 0)}
|
||||||
|
a := &asset{bytes: bytes, info: info}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dataProfilesJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xd4\x56\xdd\x6e\x2b\x35\x10\xbe\xef\x53\x8c\x72\x05\x52\xb6\x4a\xb2\xbb\x6d\xc2\x5d\xd2\x43\x7b\x90\x08\xaa\x4e\x02\x08\x10\x17\xb3\xf6\x24\x6b\xea\xb5\x83\xed\x3d\x39\x11\x3a\x12\xaf\xc1\xeb\xf1\x24\x8c\x37\x29\x49\xdb\xfc\x94\x5c\x95\x5c\x54\xdd\xf5\xec\x78\x3c\xdf\xe7\x6f\xbe\x5f\x2e\x80\x7f\x7f\x34\x7f\xe3\xaf\xa5\x64\xeb\x2b\x68\x75\x5b\xed\xed\x2b\x83\x15\xc5\x97\x37\x5a\xcd\x02\xbc\xb7\x81\xf4\xee\xf2\xa2\xb4\x86\xbe\xab\xab\x82\x5c\x8c\xfa\x22\xeb\xe6\x5f\xc2\xf5\x75\x9e\x64\xd7\x9d\xce\x6e\xa0\x24\x2f\x9c\x5a\x04\x65\x4d\x0c\x1c\xc2\x55\x52\x29\x53\x07\x82\x25\xea\x07\x98\x39\x5b\xc1\xf7\x86\x57\x61\xf2\x7b\x8d\x8e\x00\x8d\x84\x0c\xd6\x31\x7e\xbd\x8e\x30\xae\x8d\x82\x31\x05\x67\xc1\x07\x8c\xc9\xda\x10\x4a\xe5\x41\xd7\x9f\x6a\xb7\x82\x32\xd6\x07\xbc\x97\x9a\x1b\x92\x50\xac\xe0\xbe\x54\x5a\x2d\x16\x04\x93\x80\x4e\xf0\x46\x84\xa1\x76\x9c\x11\x0d\xa0\x0b\x7e\x05\xb3\xda\x19\x15\xdf\x81\xb0\x5a\x93\x88\x59\x41\x19\xce\x4b\xa0\x6d\x51\xac\xda\xfc\x24\x74\x2d\x95\x99\xc3\xd2\xba\x87\x98\x76\x82\xfa\x23\x4a\xeb\xe0\x1d\x6a\x75\xb9\x7b\x50\x94\x92\xd3\x7b\x3e\xe4\xb6\xb1\xcd\x82\x0f\x8e\x28\x6c\x7b\x95\x0d\xf2\x9d\xef\x76\x43\x36\x2d\xbf\x23\xe4\x23\x4d\xc2\xf3\x28\xa1\xc2\x2a\xae\x4f\xf8\x08\xb7\x0e\x8d\x50\x5e\xd8\x97\xa9\x30\xac\x81\x1b\xbe\xf8\xde\xd6\x26\xb8\x26\x05\x77\x3c\x70\x9f\x26\x31\xd8\x3f\x8f\x5b\x58\x4e\xa2\x6f\xac\x6c\xf2\x0c\xb2\x6e\xa7\xd7\xfa\x37\xe2\x73\xf3\xdf\xe7\xf6\x7e\x0a\xf5\xf6\x51\xe8\x47\x38\x54\xf1\x21\x1a\x5d\x27\x79\x7a\x94\x46\xdf\x72\xa7\x19\xa8\x88\x25\x14\xda\x8a\x0d\x91\x22\x74\x3f\x91\x2b\x10\x46\x35\x19\x84\x1b\x32\x81\x1c\xcc\x18\xaf\xb8\x34\x64\xdc\x37\xbc\xe1\x86\x1b\xf9\xc8\x1b\x7e\x46\xe8\xf6\x8e\x13\xf3\x3c\xb0\xbb\xfd\xee\x71\xb0\x53\x27\xdf\x14\xd4\xe9\x6b\xa1\x4e\xf7\x41\xdd\xe8\x04\xfc\x4c\x21\xe0\x49\x98\xf3\x2c\x4d\xfa\x79\x9e\x1f\x55\x8b\xf4\x25\x28\x11\xc9\x7b\xbb\x24\xad\xf9\x50\xb1\x95\x20\xb0\xd0\x94\x08\x64\x94\xf9\x4e\xa3\xe3\xc3\xcb\x46\x47\x46\xc3\x0f\x53\x70\xa8\xf4\x33\xd5\x28\xd5\x62\x03\xfd\xe0\xa9\xd2\x3c\x51\x22\x61\xab\x42\x19\x8a\xe1\xf3\x32\x09\x24\x4a\xd6\x05\x39\x6f\xe4\x40\x85\x72\x23\x23\xc1\xd6\xa2\x24\x7f\x1e\x3d\xf2\x13\x52\x90\xf3\x36\xff\x4b\x76\x64\x87\xd9\xf1\x83\xe2\xa4\x74\x92\x1e\xbd\xeb\x7e\x92\x1e\x1f\x26\xd3\x88\xe5\x92\x2b\x77\x0c\x9e\x09\x1b\x48\x1b\x6c\x46\xb8\x82\x91\x53\x72\x4e\xf0\x51\xd1\xd2\xc7\x3b\x9e\xae\xa5\xc2\x6f\x69\x74\xab\x4c\xec\x1e\x6a\x78\xa7\xb8\xf1\x4a\x84\x86\x36\x08\xd9\x7e\xda\xdd\x92\x63\x65\x1e\xd5\x4a\xc7\xa1\x70\x1e\xe4\xfd\xe3\x88\x8f\x95\xf7\x0d\x07\xdf\x10\xea\xf9\x6b\x51\xcf\xf7\xa1\x7e\x5f\x5a\x32\xea\xd3\xab\x3d\xc4\x55\xd2\x4d\xfb\x47\xc5\xdf\x0a\x8c\xe5\x6f\x66\xf5\x94\x95\x9c\x9c\xb6\xfc\x68\x88\x6f\x6a\x61\x5d\x69\xad\x6c\x47\x4d\xef\xbc\xc4\x11\x0f\xaa\x82\x6b\xfc\x45\x65\x03\x8f\x8b\x78\xd1\x09\x4a\xe4\xcb\xcf\xed\xe0\xcd\x2a\x34\x2b\x70\x71\xd2\x54\xb5\x57\xcc\x19\xe3\x1b\xae\x58\x2e\xc1\x81\x20\x4d\x85\x53\x41\xb1\x5a\x78\x76\x0d\xd4\x54\xd6\x1d\xe4\x1d\x7f\x09\xdf\x84\xbf\xff\xfc\xcb\x1f\x66\x15\xef\xcd\x5b\x2a\x01\x77\x8e\x4d\x0a\x0c\x2b\xe2\x07\x06\x79\x1c\x37\x82\xf7\xc8\x42\x67\xf8\x5c\x81\xbd\x48\x71\x1e\xe7\xae\x3a\x27\xa6\xd0\xd7\x52\xbe\x2d\xc7\x31\x68\x5d\xbc\x92\x73\x57\xfb\x38\x37\x2d\xa3\xf1\xbb\x84\x0f\x34\x67\x60\xff\x9b\xfd\xe8\xf5\xb3\x24\xeb\x1c\x15\x9e\x6d\x6a\xc6\x88\xea\x0a\xa6\x3c\x8f\xdc\xda\x47\x64\xbd\x24\xc2\xc9\xee\x31\xeb\x67\xc0\xde\xd9\x3f\xac\xf8\x63\x5c\xc4\x80\x35\x63\x27\xb6\x66\x89\xb2\x33\x18\xa3\x7b\xe0\xf9\x25\x1f\xc5\x87\x5f\x3d\xa9\xb5\x0d\x37\x6c\x33\xd9\xbe\x18\x85\xcc\x67\xf9\x1b\x0a\x76\x34\x3c\x72\x9e\xb8\x9c\x3b\x74\x92\x0c\x3b\x9b\xb1\xe5\x6f\x0c\x6d\x6c\x4f\x1b\xee\x51\x8c\xe2\x98\x7c\x14\xac\x86\xb0\x4d\x01\xbb\x9b\x3c\x9e\x21\xd6\xc3\x08\x38\x13\x7d\xd2\x99\x6e\xa7\x77\x62\x9e\xb1\xdb\x79\x53\x1c\x7b\x46\xb1\x8b\x5f\x2f\xfe\x09\x00\x00\xff\xff\xf8\xbe\x11\x38\x1c\x0d\x00\x00")
|
||||||
|
|
||||||
|
func dataProfilesJsonBytes() ([]byte, error) {
|
||||||
|
return bindataRead(
|
||||||
|
_dataProfilesJson,
|
||||||
|
"data/profiles.json",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataProfilesJson() (*asset, error) {
|
||||||
|
bytes, err := dataProfilesJsonBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := bindataFileInfo{name: "data/profiles.json", size: 3356, mode: os.FileMode(420), modTime: time.Unix(1456591428, 0)}
|
||||||
|
a := &asset{bytes: bytes, info: info}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var _dataRatesJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x8a\xe6\x52\x00\x82\x6a\x30\x09\x02\x4a\x19\xf9\x25\xa9\x39\x9e\x29\x4a\x56\x0a\x4a\x86\x4a\x3a\x08\xf1\xe4\xfc\x94\x54\x90\x60\x90\xa3\xb3\x37\xb2\x78\x66\x9e\x4b\x62\x09\x58\xc6\xc8\xc0\xd0\x54\xd7\xc0\x44\xd7\xc0\x12\x59\x3e\xbf\xb4\x04\x5d\x81\xa1\x01\xb2\x82\xa2\xfc\xfc\xdc\x90\xca\x02\x90\x0a\x84\x33\x80\xe2\x49\xf9\xf9\xd9\x89\x49\x39\xa9\x41\x10\xdd\x86\x06\x96\x7a\x06\x06\x3a\xc8\x2a\x60\x4e\xf2\xf6\x73\x57\x42\x91\x48\x49\x2d\x4e\x2e\xca\x2c\x28\xc9\xcc\xcf\x03\xcb\x67\xe6\xa5\x2b\x14\x67\x56\xa5\xa6\x28\x24\xa5\xa6\xa0\x2a\x2d\xc9\x2f\x49\xcc\xc1\x6d\x05\x5c\xda\x33\x2f\x39\xa7\xb4\x38\xb3\x0c\xac\xce\xc8\x58\xcf\xd0\x1c\xae\xac\x96\x0b\x42\xc6\x72\x01\x02\x00\x00\xff\xff\xe0\xd7\xdf\xfa\x4d\x01\x00\x00")
|
||||||
|
|
||||||
|
func dataRatesJsonBytes() ([]byte, error) {
|
||||||
|
return bindataRead(
|
||||||
|
_dataRatesJson,
|
||||||
|
"data/rates.json",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataRatesJson() (*asset, error) {
|
||||||
|
bytes, err := dataRatesJsonBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
info := bindataFileInfo{name: "data/rates.json", size: 333, mode: os.FileMode(420), modTime: time.Unix(1456591432, 0)}
|
||||||
|
a := &asset{bytes: bytes, info: info}
|
||||||
|
return a, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Asset loads and returns the asset for the given name.
|
||||||
|
// It returns an error if the asset could not be found or
|
||||||
|
// could not be loaded.
|
||||||
|
func Asset(name string) ([]byte, error) {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
if f, ok := _bindata[cannonicalName]; ok {
|
||||||
|
a, err := f()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
|
||||||
|
}
|
||||||
|
return a.bytes, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("Asset %s not found", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustAsset is like Asset but panics when Asset would return an error.
|
||||||
|
// It simplifies safe initialization of global variables.
|
||||||
|
func MustAsset(name string) []byte {
|
||||||
|
a, err := Asset(name)
|
||||||
|
if err != nil {
|
||||||
|
panic("asset: Asset(" + name + "): " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetInfo loads and returns the asset info for the given name.
|
||||||
|
// It returns an error if the asset could not be found or
|
||||||
|
// could not be loaded.
|
||||||
|
func AssetInfo(name string) (os.FileInfo, error) {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
if f, ok := _bindata[cannonicalName]; ok {
|
||||||
|
a, err := f()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
|
||||||
|
}
|
||||||
|
return a.info, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("AssetInfo %s not found", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetNames returns the names of the assets.
|
||||||
|
func AssetNames() []string {
|
||||||
|
names := make([]string, 0, len(_bindata))
|
||||||
|
for name := range _bindata {
|
||||||
|
names = append(names, name)
|
||||||
|
}
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
// _bindata is a table, holding each asset generator, mapped to its name.
|
||||||
|
var _bindata = map[string]func() (*asset, error){
|
||||||
|
"data/customers.json": dataCustomersJson,
|
||||||
|
"data/locations.json": dataLocationsJson,
|
||||||
|
"data/profiles.json": dataProfilesJson,
|
||||||
|
"data/rates.json": dataRatesJson,
|
||||||
|
}
|
||||||
|
|
||||||
|
// AssetDir returns the file names below a certain
|
||||||
|
// directory embedded in the file by go-bindata.
|
||||||
|
// For example if you run go-bindata on data/... and data contains the
|
||||||
|
// following hierarchy:
|
||||||
|
// data/
|
||||||
|
// foo.txt
|
||||||
|
// img/
|
||||||
|
// a.png
|
||||||
|
// b.png
|
||||||
|
// then AssetDir("data") would return []string{"foo.txt", "img"}
|
||||||
|
// AssetDir("data/img") would return []string{"a.png", "b.png"}
|
||||||
|
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
|
||||||
|
// AssetDir("") will return []string{"data"}.
|
||||||
|
func AssetDir(name string) ([]string, error) {
|
||||||
|
node := _bintree
|
||||||
|
if len(name) != 0 {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
pathList := strings.Split(cannonicalName, "/")
|
||||||
|
for _, p := range pathList {
|
||||||
|
node = node.Children[p]
|
||||||
|
if node == nil {
|
||||||
|
return nil, fmt.Errorf("Asset %s not found", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if node.Func != nil {
|
||||||
|
return nil, fmt.Errorf("Asset %s not found", name)
|
||||||
|
}
|
||||||
|
rv := make([]string, 0, len(node.Children))
|
||||||
|
for childName := range node.Children {
|
||||||
|
rv = append(rv, childName)
|
||||||
|
}
|
||||||
|
return rv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type bintree struct {
|
||||||
|
Func func() (*asset, error)
|
||||||
|
Children map[string]*bintree
|
||||||
|
}
|
||||||
|
|
||||||
|
var _bintree = &bintree{nil, map[string]*bintree{
|
||||||
|
"data": &bintree{nil, map[string]*bintree{
|
||||||
|
"customers.json": &bintree{dataCustomersJson, map[string]*bintree{}},
|
||||||
|
"locations.json": &bintree{dataLocationsJson, map[string]*bintree{}},
|
||||||
|
"profiles.json": &bintree{dataProfilesJson, map[string]*bintree{}},
|
||||||
|
"rates.json": &bintree{dataRatesJson, map[string]*bintree{}},
|
||||||
|
}},
|
||||||
|
}}
|
||||||
|
|
||||||
|
// RestoreAsset restores an asset under the given directory
|
||||||
|
func RestoreAsset(dir, name string) error {
|
||||||
|
data, err := Asset(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info, err := AssetInfo(name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RestoreAssets restores an asset under the given directory recursively
|
||||||
|
func RestoreAssets(dir, name string) error {
|
||||||
|
children, err := AssetDir(name)
|
||||||
|
// File
|
||||||
|
if err != nil {
|
||||||
|
return RestoreAsset(dir, name)
|
||||||
|
}
|
||||||
|
// Dir
|
||||||
|
for _, child := range children {
|
||||||
|
err = RestoreAssets(dir, filepath.Join(name, child))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func _filePath(dir, name string) string {
|
||||||
|
cannonicalName := strings.Replace(name, "\\", "/", -1)
|
||||||
|
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
|
||||||
|
}
|
||||||
6
examples/booking/data/customers.json
Normal file
6
examples/booking/data/customers.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"authToken": "VALID_TOKEN"
|
||||||
|
}
|
||||||
|
]
|
||||||
32
examples/booking/data/locations.json
Normal file
32
examples/booking/data/locations.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"hotelId": "1",
|
||||||
|
"lat": 51.502973,
|
||||||
|
"lon": -0.114723
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hotelId": "2",
|
||||||
|
"lat": 51.502973,
|
||||||
|
"lon": -0.114723
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hotelId": "3",
|
||||||
|
"lat": 51.502973,
|
||||||
|
"lon": -0.114723
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hotelId": "4",
|
||||||
|
"lat": 51.502973,
|
||||||
|
"lon": -0.114723
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hotelId": "5",
|
||||||
|
"lat": 51.502973,
|
||||||
|
"lon": -0.114723
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"hotelId": "6",
|
||||||
|
"lat": 51.502973,
|
||||||
|
"lon": -0.114723
|
||||||
|
}
|
||||||
|
]
|
||||||
87
examples/booking/data/profiles.json
Normal file
87
examples/booking/data/profiles.json
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"name": "Clift Hotel",
|
||||||
|
"phoneNumber": "(415) 775-4700",
|
||||||
|
"description": "A 6-minute walk from Union Square and 4 minutes from a Muni Metro station, this luxury hotel designed by Philippe Starck features an artsy furniture collection in the lobby, including work by Salvador Dali.",
|
||||||
|
"address": {
|
||||||
|
"streetNumber": "495",
|
||||||
|
"streetName": "Geary St",
|
||||||
|
"city": "San Francisco",
|
||||||
|
"state": "CA",
|
||||||
|
"country": "United States",
|
||||||
|
"postalCode": "94102"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2",
|
||||||
|
"name": "W San Francisco",
|
||||||
|
"phoneNumber": "(415) 777-5300",
|
||||||
|
"description": "Less than a block from the Yerba Buena Center for the Arts, this trendy hotel is a 12-minute walk from Union Square.",
|
||||||
|
"address": {
|
||||||
|
"streetNumber": "181",
|
||||||
|
"streetName": "3rd St",
|
||||||
|
"city": "San Francisco",
|
||||||
|
"state": "CA",
|
||||||
|
"country": "United States",
|
||||||
|
"postalCode": "94103"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3",
|
||||||
|
"name": "Hotel Zetta",
|
||||||
|
"phoneNumber": "(415) 543-8555",
|
||||||
|
"description": "A 3-minute walk from the Powell Street cable-car turnaround and BART rail station, this hip hotel 9 minutes from Union Square combines high-tech lodging with artsy touches.",
|
||||||
|
"address": {
|
||||||
|
"streetNumber": "55",
|
||||||
|
"streetName": "5th St",
|
||||||
|
"city": "San Francisco",
|
||||||
|
"state": "CA",
|
||||||
|
"country": "United States",
|
||||||
|
"postalCode": "94103"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4",
|
||||||
|
"name": "Hotel Vitale",
|
||||||
|
"phoneNumber": "(415) 278-3700",
|
||||||
|
"description": "This waterfront hotel with Bay Bridge views is 3 blocks from the Financial District and a 4-minute walk from the Ferry Building.",
|
||||||
|
"address": {
|
||||||
|
"streetNumber": "8",
|
||||||
|
"streetName": "Mission St",
|
||||||
|
"city": "San Francisco",
|
||||||
|
"state": "CA",
|
||||||
|
"country": "United States",
|
||||||
|
"postalCode": "94105"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5",
|
||||||
|
"name": "Phoenix Hotel",
|
||||||
|
"phoneNumber": "(415) 776-1380",
|
||||||
|
"description": "Located in the Tenderloin neighborhood, a 10-minute walk from a BART rail station, this retro motor lodge has hosted many rock musicians and other celebrities since the 1950s. It’s a 4-minute walk from the historic Great American Music Hall nightclub.",
|
||||||
|
"address": {
|
||||||
|
"streetNumber": "601",
|
||||||
|
"streetName": "Eddy St",
|
||||||
|
"city": "San Francisco",
|
||||||
|
"state": "CA",
|
||||||
|
"country": "United States",
|
||||||
|
"postalCode": "94109"
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6",
|
||||||
|
"name": "The St. Regis San Francisco",
|
||||||
|
"phoneNumber": "(415) 284-4000",
|
||||||
|
"description": "St. Regis Museum Tower is a 42-story, 484 ft skyscraper in the South of Market district of San Francisco, California, adjacent to Yerba Buena Gardens, Moscone Center, PacBell Building and the San Francisco Museum of Modern Art.",
|
||||||
|
"address": {
|
||||||
|
"streetNumber": "125",
|
||||||
|
"streetName": "3rd",
|
||||||
|
"city": "San Francisco",
|
||||||
|
"state": "CA",
|
||||||
|
"country": "United States",
|
||||||
|
"postalCode": "94109"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
15
examples/booking/data/rates.json
Normal file
15
examples/booking/data/rates.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"hotelId": "1",
|
||||||
|
"code": "RACK",
|
||||||
|
"inDate": "2015-04-09",
|
||||||
|
"outDate": "2015-04-10",
|
||||||
|
"roomType": {
|
||||||
|
"bookableRate": 109.00,
|
||||||
|
"code": "KNG",
|
||||||
|
"description": "King sized bed",
|
||||||
|
"totalRate": 109.00,
|
||||||
|
"totalRateInclusive": 123.17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
45
examples/booking/docker-compose.yml
Normal file
45
examples/booking/docker-compose.yml
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
consul:
|
||||||
|
command: -server -bootstrap -rejoin
|
||||||
|
image: progrium/consul:latest
|
||||||
|
ports:
|
||||||
|
- "8300:8300"
|
||||||
|
- "8400:8400"
|
||||||
|
- "8500:8500"
|
||||||
|
- "8600:53/udp"
|
||||||
|
micro:
|
||||||
|
command: --registry_address=consul:8500 api --handler=rpc
|
||||||
|
image: microhq/micro:latest
|
||||||
|
links:
|
||||||
|
- consul
|
||||||
|
- api
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
api:
|
||||||
|
build: ./api/hotel
|
||||||
|
command: --registry_address=consul:8500
|
||||||
|
links:
|
||||||
|
- consul
|
||||||
|
- auth
|
||||||
|
- geo
|
||||||
|
- profile
|
||||||
|
- rate
|
||||||
|
auth:
|
||||||
|
build: ./srv/auth
|
||||||
|
command: --registry_address=consul:8500
|
||||||
|
links:
|
||||||
|
- consul
|
||||||
|
geo:
|
||||||
|
build: ./srv/geo
|
||||||
|
command: --registry_address=consul:8500
|
||||||
|
links:
|
||||||
|
- consul
|
||||||
|
profile:
|
||||||
|
build: ./srv/profile
|
||||||
|
command: --registry_address=consul:8500
|
||||||
|
links:
|
||||||
|
- consul
|
||||||
|
rate:
|
||||||
|
build: ./srv/rate
|
||||||
|
command: --registry_address=consul:8500
|
||||||
|
links:
|
||||||
|
- consul
|
||||||
4
examples/booking/srv/auth/Dockerfile
Normal file
4
examples/booking/srv/auth/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM alpine:3.2
|
||||||
|
ADD . /app
|
||||||
|
WORKDIR /app
|
||||||
|
ENTRYPOINT [ "/app/auth" ]
|
||||||
70
examples/booking/srv/auth/main.go
Normal file
70
examples/booking/srv/auth/main.go
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/micro/examples/booking/data"
|
||||||
|
"github.com/micro/examples/booking/srv/auth/proto"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
"golang.org/x/net/trace"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
"github.com/micro/go-micro/v2/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Auth struct {
|
||||||
|
customers map[string]*auth.Customer
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyToken returns a customer from authentication token.
|
||||||
|
func (s *Auth) VerifyToken(ctx context.Context, req *auth.Request, rsp *auth.Result) error {
|
||||||
|
md, _ := metadata.FromContext(ctx)
|
||||||
|
traceID := md["traceID"]
|
||||||
|
|
||||||
|
if tr, ok := trace.FromContext(ctx); ok {
|
||||||
|
tr.LazyPrintf("traceID %s", traceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
customer := s.customers[req.AuthToken]
|
||||||
|
if customer == nil {
|
||||||
|
return errors.New("Invalid Token")
|
||||||
|
}
|
||||||
|
|
||||||
|
rsp.Customer = customer
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadCustomers loads customers from a JSON file.
|
||||||
|
func loadCustomerData(path string) map[string]*auth.Customer {
|
||||||
|
file := data.MustAsset(path)
|
||||||
|
customers := []*auth.Customer{}
|
||||||
|
|
||||||
|
// unmarshal JSON
|
||||||
|
if err := json.Unmarshal(file, &customers); err != nil {
|
||||||
|
log.Fatalf("Failed to unmarshal json: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create customer lookup map
|
||||||
|
cache := make(map[string]*auth.Customer)
|
||||||
|
for _, c := range customers {
|
||||||
|
cache[c.AuthToken] = c
|
||||||
|
}
|
||||||
|
return cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("go.micro.srv.auth"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
auth.RegisterAuthHandler(service.Server(), &Auth{
|
||||||
|
customers: loadCustomerData("data/customers.json"),
|
||||||
|
})
|
||||||
|
|
||||||
|
service.Run()
|
||||||
|
}
|
||||||
100
examples/booking/srv/auth/proto/auth.micro.go
Normal file
100
examples/booking/srv/auth/proto/auth.micro.go
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/booking/srv/auth/proto/auth.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package auth is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/booking/srv/auth/proto/auth.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Request
|
||||||
|
Result
|
||||||
|
Customer
|
||||||
|
*/
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
client "github.com/micro/go-micro/v2/client"
|
||||||
|
server "github.com/micro/go-micro/v2/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ client.Option
|
||||||
|
var _ server.Option
|
||||||
|
|
||||||
|
// Client API for Auth service
|
||||||
|
|
||||||
|
type AuthService interface {
|
||||||
|
VerifyToken(ctx context.Context, in *Request, opts ...client.CallOption) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type authService struct {
|
||||||
|
c client.Client
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAuthService(serviceName string, c client.Client) AuthService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(serviceName) == 0 {
|
||||||
|
serviceName = "auth"
|
||||||
|
}
|
||||||
|
return &authService{
|
||||||
|
c: c,
|
||||||
|
serviceName: serviceName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *authService) VerifyToken(ctx context.Context, in *Request, opts ...client.CallOption) (*Result, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Auth.VerifyToken", in)
|
||||||
|
out := new(Result)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Auth service
|
||||||
|
|
||||||
|
type AuthHandler interface {
|
||||||
|
VerifyToken(context.Context, *Request, *Result) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterAuthHandler(s server.Server, hdlr AuthHandler, opts ...server.HandlerOption) {
|
||||||
|
type auth interface {
|
||||||
|
VerifyToken(ctx context.Context, in *Request, out *Result) error
|
||||||
|
}
|
||||||
|
type Auth struct {
|
||||||
|
auth
|
||||||
|
}
|
||||||
|
h := &authHandler{hdlr}
|
||||||
|
s.Handle(s.NewHandler(&Auth{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type authHandler struct {
|
||||||
|
AuthHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *authHandler) VerifyToken(ctx context.Context, in *Request, out *Result) error {
|
||||||
|
return h.AuthHandler.VerifyToken(ctx, in, out)
|
||||||
|
}
|
||||||
191
examples/booking/srv/auth/proto/auth.pb.go
Normal file
191
examples/booking/srv/auth/proto/auth.pb.go
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/booking/srv/auth/proto/auth.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package auth is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/booking/srv/auth/proto/auth.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Request
|
||||||
|
Result
|
||||||
|
Customer
|
||||||
|
*/
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "golang.org/x/net/context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
AuthToken string `protobuf:"bytes,1,opt,name=authToken" json:"authToken,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Request) Reset() { *m = Request{} }
|
||||||
|
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Request) ProtoMessage() {}
|
||||||
|
func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
|
||||||
|
func (m *Request) GetAuthToken() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.AuthToken
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
Customer *Customer `protobuf:"bytes,1,opt,name=customer" json:"customer,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Result) Reset() { *m = Result{} }
|
||||||
|
func (m *Result) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Result) ProtoMessage() {}
|
||||||
|
func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||||
|
|
||||||
|
func (m *Result) GetCustomer() *Customer {
|
||||||
|
if m != nil {
|
||||||
|
return m.Customer
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Customer struct {
|
||||||
|
Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
|
||||||
|
AuthToken string `protobuf:"bytes,2,opt,name=authToken" json:"authToken,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Customer) Reset() { *m = Customer{} }
|
||||||
|
func (m *Customer) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Customer) ProtoMessage() {}
|
||||||
|
func (*Customer) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||||
|
|
||||||
|
func (m *Customer) GetId() int32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Id
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Customer) GetAuthToken() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.AuthToken
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Request)(nil), "auth.Request")
|
||||||
|
proto.RegisterType((*Result)(nil), "auth.Result")
|
||||||
|
proto.RegisterType((*Customer)(nil), "auth.Customer")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ grpc.ClientConn
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
const _ = grpc.SupportPackageIsVersion4
|
||||||
|
|
||||||
|
// Client API for Auth service
|
||||||
|
|
||||||
|
type AuthClient interface {
|
||||||
|
VerifyToken(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type authClient struct {
|
||||||
|
cc *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAuthClient(cc *grpc.ClientConn) AuthClient {
|
||||||
|
return &authClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *authClient) VerifyToken(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error) {
|
||||||
|
out := new(Result)
|
||||||
|
err := grpc.Invoke(ctx, "/auth.Auth/VerifyToken", in, out, c.cc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Auth service
|
||||||
|
|
||||||
|
type AuthServer interface {
|
||||||
|
VerifyToken(context.Context, *Request) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterAuthServer(s *grpc.Server, srv AuthServer) {
|
||||||
|
s.RegisterService(&_Auth_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Auth_VerifyToken_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(Request)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(AuthServer).VerifyToken(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/auth.Auth/VerifyToken",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(AuthServer).VerifyToken(ctx, req.(*Request))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _Auth_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "auth.Auth",
|
||||||
|
HandlerType: (*AuthServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "VerifyToken",
|
||||||
|
Handler: _Auth_VerifyToken_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "github.com/micro/examples/booking/srv/auth/proto/auth.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterFile("github.com/micro/examples/booking/srv/auth/proto/auth.proto", fileDescriptor0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 213 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xb2, 0x4e, 0xcf, 0x2c, 0xc9,
|
||||||
|
0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0xcf, 0xcd, 0x4c, 0x2e, 0xca, 0xd7, 0x4f, 0xad, 0x48,
|
||||||
|
0xcc, 0x2d, 0xc8, 0x49, 0x2d, 0xd6, 0x4f, 0xca, 0xcf, 0xcf, 0xce, 0xcc, 0x4b, 0xd7, 0x2f, 0x2e,
|
||||||
|
0x2a, 0xd3, 0x4f, 0x2c, 0x2d, 0xc9, 0xd0, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0x07, 0x33, 0xf5, 0xc0,
|
||||||
|
0x4c, 0x21, 0x16, 0x10, 0x5b, 0x49, 0x9d, 0x8b, 0x3d, 0x28, 0xb5, 0xb0, 0x34, 0xb5, 0xb8, 0x44,
|
||||||
|
0x48, 0x86, 0x8b, 0x13, 0x24, 0x14, 0x92, 0x9f, 0x9d, 0x9a, 0x27, 0xc1, 0xa8, 0xc0, 0xa8, 0xc1,
|
||||||
|
0x19, 0x84, 0x10, 0x50, 0x32, 0xe1, 0x62, 0x0b, 0x4a, 0x2d, 0x2e, 0xcd, 0x29, 0x11, 0xd2, 0xe2,
|
||||||
|
0xe2, 0x48, 0x2e, 0x2d, 0x2e, 0xc9, 0xcf, 0x4d, 0x2d, 0x02, 0x2b, 0xe3, 0x36, 0xe2, 0xd3, 0x03,
|
||||||
|
0x9b, 0xeb, 0x0c, 0x15, 0x0d, 0x82, 0xcb, 0x2b, 0x59, 0x70, 0x71, 0xc0, 0x44, 0x85, 0xf8, 0xb8,
|
||||||
|
0x98, 0x32, 0x53, 0xc0, 0x3a, 0x58, 0x83, 0x98, 0x32, 0x53, 0x50, 0xed, 0x63, 0x42, 0xb3, 0xcf,
|
||||||
|
0xc8, 0x84, 0x8b, 0xc5, 0xb1, 0xb4, 0x24, 0x43, 0x48, 0x87, 0x8b, 0x3b, 0x2c, 0xb5, 0x28, 0x33,
|
||||||
|
0xad, 0x12, 0x2c, 0x2c, 0xc4, 0x0b, 0xb1, 0x0a, 0xea, 0x66, 0x29, 0x1e, 0x18, 0x17, 0xe4, 0x32,
|
||||||
|
0x25, 0x86, 0x24, 0x36, 0xb0, 0xdf, 0x8c, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd7, 0x57, 0xa9,
|
||||||
|
0xd9, 0x1a, 0x01, 0x00, 0x00,
|
||||||
|
}
|
||||||
20
examples/booking/srv/auth/proto/auth.proto
Normal file
20
examples/booking/srv/auth/proto/auth.proto
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package auth;
|
||||||
|
|
||||||
|
service Auth {
|
||||||
|
rpc VerifyToken(Request) returns (Result) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Request {
|
||||||
|
string authToken = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Result {
|
||||||
|
Customer customer = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Customer {
|
||||||
|
int32 id = 1;
|
||||||
|
string authToken = 2;
|
||||||
|
}
|
||||||
4
examples/booking/srv/geo/Dockerfile
Normal file
4
examples/booking/srv/geo/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM alpine:3.2
|
||||||
|
ADD . /app
|
||||||
|
WORKDIR /app
|
||||||
|
ENTRYPOINT [ "/app/geo" ]
|
||||||
95
examples/booking/srv/geo/main.go
Normal file
95
examples/booking/srv/geo/main.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hailocab/go-geoindex"
|
||||||
|
"github.com/micro/examples/booking/data"
|
||||||
|
"github.com/micro/examples/booking/srv/geo/proto"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
"golang.org/x/net/trace"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
"github.com/micro/go-micro/v2/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxSearchRadius = 10
|
||||||
|
maxSearchResults = 5
|
||||||
|
)
|
||||||
|
|
||||||
|
type point struct {
|
||||||
|
Pid string `json:"hotelId"`
|
||||||
|
Plat float64 `json:"lat"`
|
||||||
|
Plon float64 `json:"lon"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement Point interface
|
||||||
|
func (p *point) Lat() float64 { return p.Plat }
|
||||||
|
func (p *point) Lon() float64 { return p.Plon }
|
||||||
|
func (p *point) Id() string { return p.Pid }
|
||||||
|
|
||||||
|
type Geo struct {
|
||||||
|
index *geoindex.ClusteringIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nearby returns all hotels within a given distance.
|
||||||
|
func (s *Geo) Nearby(ctx context.Context, req *geo.Request, rsp *geo.Result) error {
|
||||||
|
md, _ := metadata.FromContext(ctx)
|
||||||
|
traceID := md["traceID"]
|
||||||
|
|
||||||
|
if tr, ok := trace.FromContext(ctx); ok {
|
||||||
|
tr.LazyPrintf("traceID %s", traceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create center point for query
|
||||||
|
center := &geoindex.GeoPoint{
|
||||||
|
Pid: "",
|
||||||
|
Plat: float64(req.Lat),
|
||||||
|
Plon: float64(req.Lon),
|
||||||
|
}
|
||||||
|
|
||||||
|
// find points around center point
|
||||||
|
points := s.index.KNearest(center, maxSearchResults, geoindex.Km(maxSearchRadius), func(p geoindex.Point) bool {
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, p := range points {
|
||||||
|
rsp.HotelIds = append(rsp.HotelIds, p.Id())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// newGeoIndex returns a geo index with points loaded
|
||||||
|
func newGeoIndex(path string) *geoindex.ClusteringIndex {
|
||||||
|
file := data.MustAsset(path)
|
||||||
|
|
||||||
|
// unmarshal json points
|
||||||
|
var points []*point
|
||||||
|
if err := json.Unmarshal(file, &points); err != nil {
|
||||||
|
log.Fatalf("Failed to load hotels: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add points to index
|
||||||
|
index := geoindex.NewClusteringIndex()
|
||||||
|
for _, point := range points {
|
||||||
|
index.Add(point)
|
||||||
|
}
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("go.micro.srv.geo"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
geo.RegisterGeoHandler(service.Server(), &Geo{
|
||||||
|
index: newGeoIndex("data/locations.json"),
|
||||||
|
})
|
||||||
|
|
||||||
|
service.Run()
|
||||||
|
}
|
||||||
101
examples/booking/srv/geo/proto/geo.micro.go
Normal file
101
examples/booking/srv/geo/proto/geo.micro.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/booking/srv/geo/proto/geo.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package geo is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/booking/srv/geo/proto/geo.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Request
|
||||||
|
Result
|
||||||
|
*/
|
||||||
|
package geo
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
client "github.com/micro/go-micro/v2/client"
|
||||||
|
server "github.com/micro/go-micro/v2/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ client.Option
|
||||||
|
var _ server.Option
|
||||||
|
|
||||||
|
// Client API for Geo service
|
||||||
|
|
||||||
|
type GeoService interface {
|
||||||
|
// Finds the hotels contained nearby the current lat/lon.
|
||||||
|
Nearby(ctx context.Context, in *Request, opts ...client.CallOption) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type geoService struct {
|
||||||
|
c client.Client
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGeoService(serviceName string, c client.Client) GeoService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(serviceName) == 0 {
|
||||||
|
serviceName = "geo"
|
||||||
|
}
|
||||||
|
return &geoService{
|
||||||
|
c: c,
|
||||||
|
serviceName: serviceName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *geoService) Nearby(ctx context.Context, in *Request, opts ...client.CallOption) (*Result, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Geo.Nearby", in)
|
||||||
|
out := new(Result)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Geo service
|
||||||
|
|
||||||
|
type GeoHandler interface {
|
||||||
|
// Finds the hotels contained nearby the current lat/lon.
|
||||||
|
Nearby(context.Context, *Request, *Result) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterGeoHandler(s server.Server, hdlr GeoHandler, opts ...server.HandlerOption) {
|
||||||
|
type geo interface {
|
||||||
|
Nearby(ctx context.Context, in *Request, out *Result) error
|
||||||
|
}
|
||||||
|
type Geo struct {
|
||||||
|
geo
|
||||||
|
}
|
||||||
|
h := &geoHandler{hdlr}
|
||||||
|
s.Handle(s.NewHandler(&Geo{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type geoHandler struct {
|
||||||
|
GeoHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *geoHandler) Nearby(ctx context.Context, in *Request, out *Result) error {
|
||||||
|
return h.GeoHandler.Nearby(ctx, in, out)
|
||||||
|
}
|
||||||
174
examples/booking/srv/geo/proto/geo.pb.go
Normal file
174
examples/booking/srv/geo/proto/geo.pb.go
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/booking/srv/geo/proto/geo.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package geo is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/booking/srv/geo/proto/geo.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Request
|
||||||
|
Result
|
||||||
|
*/
|
||||||
|
package geo
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "golang.org/x/net/context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// The latitude and longitude of the current location.
|
||||||
|
type Request struct {
|
||||||
|
Lat float32 `protobuf:"fixed32,1,opt,name=lat" json:"lat,omitempty"`
|
||||||
|
Lon float32 `protobuf:"fixed32,2,opt,name=lon" json:"lon,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Request) Reset() { *m = Request{} }
|
||||||
|
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Request) ProtoMessage() {}
|
||||||
|
func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
|
||||||
|
func (m *Request) GetLat() float32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Lat
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Request) GetLon() float32 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Lon
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
HotelIds []string `protobuf:"bytes,1,rep,name=hotelIds" json:"hotelIds,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Result) Reset() { *m = Result{} }
|
||||||
|
func (m *Result) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Result) ProtoMessage() {}
|
||||||
|
func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||||
|
|
||||||
|
func (m *Result) GetHotelIds() []string {
|
||||||
|
if m != nil {
|
||||||
|
return m.HotelIds
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Request)(nil), "geo.Request")
|
||||||
|
proto.RegisterType((*Result)(nil), "geo.Result")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ grpc.ClientConn
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
const _ = grpc.SupportPackageIsVersion4
|
||||||
|
|
||||||
|
// Client API for Geo service
|
||||||
|
|
||||||
|
type GeoClient interface {
|
||||||
|
// Finds the hotels contained nearby the current lat/lon.
|
||||||
|
Nearby(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type geoClient struct {
|
||||||
|
cc *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGeoClient(cc *grpc.ClientConn) GeoClient {
|
||||||
|
return &geoClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *geoClient) Nearby(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error) {
|
||||||
|
out := new(Result)
|
||||||
|
err := grpc.Invoke(ctx, "/geo.Geo/Nearby", in, out, c.cc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Geo service
|
||||||
|
|
||||||
|
type GeoServer interface {
|
||||||
|
// Finds the hotels contained nearby the current lat/lon.
|
||||||
|
Nearby(context.Context, *Request) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterGeoServer(s *grpc.Server, srv GeoServer) {
|
||||||
|
s.RegisterService(&_Geo_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Geo_Nearby_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(Request)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(GeoServer).Nearby(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/geo.Geo/Nearby",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(GeoServer).Nearby(ctx, req.(*Request))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _Geo_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "geo.Geo",
|
||||||
|
HandlerType: (*GeoServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "Nearby",
|
||||||
|
Handler: _Geo_Nearby_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "github.com/micro/examples/booking/srv/geo/proto/geo.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterFile("github.com/micro/examples/booking/srv/geo/proto/geo.proto", fileDescriptor0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 184 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x3c, 0x8e, 0xb1, 0xae, 0x82, 0x30,
|
||||||
|
0x14, 0x86, 0x03, 0x4d, 0xb8, 0xf7, 0x9e, 0xeb, 0x60, 0x3a, 0x11, 0x26, 0x82, 0x0e, 0xc4, 0x44,
|
||||||
|
0x9a, 0xe8, 0xe4, 0x13, 0x18, 0x17, 0x87, 0xbe, 0x01, 0xc5, 0x93, 0x42, 0x2c, 0x1c, 0x6c, 0x8b,
|
||||||
|
0xd1, 0xb7, 0x37, 0x25, 0xc4, 0xed, 0xfb, 0xbf, 0xe1, 0x7c, 0x07, 0x4e, 0xba, 0xf3, 0xed, 0xa4,
|
||||||
|
0xaa, 0x86, 0x7a, 0xd1, 0x77, 0x8d, 0x25, 0x81, 0xaf, 0xba, 0x1f, 0x0d, 0x3a, 0xa1, 0x88, 0xee,
|
||||||
|
0xdd, 0xa0, 0x85, 0xb3, 0x4f, 0xa1, 0x91, 0xc4, 0x68, 0xc9, 0x53, 0xa0, 0x6a, 0x26, 0xce, 0x34,
|
||||||
|
0x52, 0xb1, 0x87, 0x1f, 0x89, 0x8f, 0x09, 0x9d, 0xe7, 0x6b, 0x60, 0xa6, 0xf6, 0x69, 0x94, 0x47,
|
||||||
|
0x65, 0x2c, 0x03, 0xce, 0x86, 0x86, 0x34, 0x5e, 0x0c, 0x0d, 0xc5, 0x16, 0x12, 0x89, 0x6e, 0x32,
|
||||||
|
0x9e, 0x67, 0xf0, 0xdb, 0x92, 0x47, 0x73, 0xb9, 0xb9, 0x34, 0xca, 0x59, 0xf9, 0x27, 0xbf, 0xfb,
|
||||||
|
0xb0, 0x03, 0x76, 0x46, 0xe2, 0x1b, 0x48, 0xae, 0x58, 0x5b, 0xf5, 0xe6, 0xab, 0x2a, 0x64, 0x97,
|
||||||
|
0x50, 0xf6, 0xbf, 0xac, 0x70, 0x47, 0x25, 0xf3, 0x33, 0xc7, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||||
|
0x39, 0xe5, 0x14, 0x38, 0xc9, 0x00, 0x00, 0x00,
|
||||||
|
}
|
||||||
18
examples/booking/srv/geo/proto/geo.proto
Normal file
18
examples/booking/srv/geo/proto/geo.proto
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package geo;
|
||||||
|
|
||||||
|
service Geo {
|
||||||
|
// Finds the hotels contained nearby the current lat/lon.
|
||||||
|
rpc Nearby(Request) returns (Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The latitude and longitude of the current location.
|
||||||
|
message Request {
|
||||||
|
float lat = 1;
|
||||||
|
float lon = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Result {
|
||||||
|
repeated string hotelIds = 1;
|
||||||
|
}
|
||||||
4
examples/booking/srv/profile/Dockerfile
Normal file
4
examples/booking/srv/profile/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM alpine:3.2
|
||||||
|
ADD . /app
|
||||||
|
WORKDIR /app
|
||||||
|
ENTRYPOINT [ "/app/profile" ]
|
||||||
64
examples/booking/srv/profile/main.go
Normal file
64
examples/booking/srv/profile/main.go
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/micro/examples/booking/data"
|
||||||
|
"github.com/micro/examples/booking/srv/profile/proto"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
"golang.org/x/net/trace"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
"github.com/micro/go-micro/v2/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Profile struct {
|
||||||
|
hotels map[string]*profile.Hotel
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetProfiles returns hotel profiles for requested IDs
|
||||||
|
func (s *Profile) GetProfiles(ctx context.Context, req *profile.Request, rsp *profile.Result) error {
|
||||||
|
md, _ := metadata.FromContext(ctx)
|
||||||
|
traceID := md["traceID"]
|
||||||
|
if tr, ok := trace.FromContext(ctx); ok {
|
||||||
|
tr.LazyPrintf("traceID %s", traceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, i := range req.HotelIds {
|
||||||
|
rsp.Hotels = append(rsp.Hotels, s.hotels[i])
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadProfiles loads hotel profiles from a JSON file.
|
||||||
|
func loadProfiles(path string) map[string]*profile.Hotel {
|
||||||
|
file := data.MustAsset(path)
|
||||||
|
|
||||||
|
// unmarshal json profiles
|
||||||
|
hotels := []*profile.Hotel{}
|
||||||
|
if err := json.Unmarshal(file, &hotels); err != nil {
|
||||||
|
log.Fatalf("Failed to load json: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
profiles := make(map[string]*profile.Hotel)
|
||||||
|
for _, hotel := range hotels {
|
||||||
|
profiles[hotel.Id] = hotel
|
||||||
|
}
|
||||||
|
return profiles
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("go.micro.srv.profile"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
profile.RegisterProfileHandler(service.Server(), &Profile{
|
||||||
|
hotels: loadProfiles("data/profiles.json"),
|
||||||
|
})
|
||||||
|
|
||||||
|
service.Run()
|
||||||
|
}
|
||||||
102
examples/booking/srv/profile/proto/profile.micro.go
Normal file
102
examples/booking/srv/profile/proto/profile.micro.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/booking/srv/profile/proto/profile.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package profile is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/booking/srv/profile/proto/profile.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Request
|
||||||
|
Result
|
||||||
|
Hotel
|
||||||
|
Address
|
||||||
|
Image
|
||||||
|
*/
|
||||||
|
package profile
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
client "github.com/micro/go-micro/v2/client"
|
||||||
|
server "github.com/micro/go-micro/v2/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ client.Option
|
||||||
|
var _ server.Option
|
||||||
|
|
||||||
|
// Client API for Profile service
|
||||||
|
|
||||||
|
type ProfileService interface {
|
||||||
|
GetProfiles(ctx context.Context, in *Request, opts ...client.CallOption) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type profileService struct {
|
||||||
|
c client.Client
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProfileService(serviceName string, c client.Client) ProfileService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(serviceName) == 0 {
|
||||||
|
serviceName = "profile"
|
||||||
|
}
|
||||||
|
return &profileService{
|
||||||
|
c: c,
|
||||||
|
serviceName: serviceName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *profileService) GetProfiles(ctx context.Context, in *Request, opts ...client.CallOption) (*Result, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Profile.GetProfiles", in)
|
||||||
|
out := new(Result)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Profile service
|
||||||
|
|
||||||
|
type ProfileHandler interface {
|
||||||
|
GetProfiles(context.Context, *Request, *Result) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterProfileHandler(s server.Server, hdlr ProfileHandler, opts ...server.HandlerOption) {
|
||||||
|
type profile interface {
|
||||||
|
GetProfiles(ctx context.Context, in *Request, out *Result) error
|
||||||
|
}
|
||||||
|
type Profile struct {
|
||||||
|
profile
|
||||||
|
}
|
||||||
|
h := &profileHandler{hdlr}
|
||||||
|
s.Handle(s.NewHandler(&Profile{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type profileHandler struct {
|
||||||
|
ProfileHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *profileHandler) GetProfiles(ctx context.Context, in *Request, out *Result) error {
|
||||||
|
return h.ProfileHandler.GetProfiles(ctx, in, out)
|
||||||
|
}
|
||||||
326
examples/booking/srv/profile/proto/profile.pb.go
Normal file
326
examples/booking/srv/profile/proto/profile.pb.go
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/booking/srv/profile/proto/profile.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package profile is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/booking/srv/profile/proto/profile.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Request
|
||||||
|
Result
|
||||||
|
Hotel
|
||||||
|
Address
|
||||||
|
Image
|
||||||
|
*/
|
||||||
|
package profile
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "golang.org/x/net/context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
HotelIds []string `protobuf:"bytes,1,rep,name=hotelIds" json:"hotelIds,omitempty"`
|
||||||
|
Locale string `protobuf:"bytes,2,opt,name=locale" json:"locale,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Request) Reset() { *m = Request{} }
|
||||||
|
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Request) ProtoMessage() {}
|
||||||
|
func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
|
||||||
|
func (m *Request) GetHotelIds() []string {
|
||||||
|
if m != nil {
|
||||||
|
return m.HotelIds
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Request) GetLocale() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Locale
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
Hotels []*Hotel `protobuf:"bytes,1,rep,name=hotels" json:"hotels,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Result) Reset() { *m = Result{} }
|
||||||
|
func (m *Result) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Result) ProtoMessage() {}
|
||||||
|
func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||||
|
|
||||||
|
func (m *Result) GetHotels() []*Hotel {
|
||||||
|
if m != nil {
|
||||||
|
return m.Hotels
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Hotel struct {
|
||||||
|
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
|
||||||
|
Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
|
||||||
|
PhoneNumber string `protobuf:"bytes,3,opt,name=phoneNumber" json:"phoneNumber,omitempty"`
|
||||||
|
Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"`
|
||||||
|
Address *Address `protobuf:"bytes,5,opt,name=address" json:"address,omitempty"`
|
||||||
|
Images []*Image `protobuf:"bytes,6,rep,name=images" json:"images,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Hotel) Reset() { *m = Hotel{} }
|
||||||
|
func (m *Hotel) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Hotel) ProtoMessage() {}
|
||||||
|
func (*Hotel) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||||
|
|
||||||
|
func (m *Hotel) GetId() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Id
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Hotel) GetName() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Hotel) GetPhoneNumber() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.PhoneNumber
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Hotel) GetDescription() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Description
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Hotel) GetAddress() *Address {
|
||||||
|
if m != nil {
|
||||||
|
return m.Address
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Hotel) GetImages() []*Image {
|
||||||
|
if m != nil {
|
||||||
|
return m.Images
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Address struct {
|
||||||
|
StreetNumber string `protobuf:"bytes,1,opt,name=streetNumber" json:"streetNumber,omitempty"`
|
||||||
|
StreetName string `protobuf:"bytes,2,opt,name=streetName" json:"streetName,omitempty"`
|
||||||
|
City string `protobuf:"bytes,3,opt,name=city" json:"city,omitempty"`
|
||||||
|
State string `protobuf:"bytes,4,opt,name=state" json:"state,omitempty"`
|
||||||
|
Country string `protobuf:"bytes,5,opt,name=country" json:"country,omitempty"`
|
||||||
|
PostalCode string `protobuf:"bytes,6,opt,name=postalCode" json:"postalCode,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Address) Reset() { *m = Address{} }
|
||||||
|
func (m *Address) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Address) ProtoMessage() {}
|
||||||
|
func (*Address) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||||
|
|
||||||
|
func (m *Address) GetStreetNumber() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.StreetNumber
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Address) GetStreetName() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.StreetName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Address) GetCity() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.City
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Address) GetState() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.State
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Address) GetCountry() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Country
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Address) GetPostalCode() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.PostalCode
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
Url string `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"`
|
||||||
|
Default bool `protobuf:"varint,2,opt,name=default" json:"default,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Image) Reset() { *m = Image{} }
|
||||||
|
func (m *Image) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Image) ProtoMessage() {}
|
||||||
|
func (*Image) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
|
||||||
|
|
||||||
|
func (m *Image) GetUrl() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Url
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Image) GetDefault() bool {
|
||||||
|
if m != nil {
|
||||||
|
return m.Default
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Request)(nil), "profile.Request")
|
||||||
|
proto.RegisterType((*Result)(nil), "profile.Result")
|
||||||
|
proto.RegisterType((*Hotel)(nil), "profile.Hotel")
|
||||||
|
proto.RegisterType((*Address)(nil), "profile.Address")
|
||||||
|
proto.RegisterType((*Image)(nil), "profile.Image")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ grpc.ClientConn
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
const _ = grpc.SupportPackageIsVersion4
|
||||||
|
|
||||||
|
// Client API for Profile service
|
||||||
|
|
||||||
|
type ProfileClient interface {
|
||||||
|
GetProfiles(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type profileClient struct {
|
||||||
|
cc *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewProfileClient(cc *grpc.ClientConn) ProfileClient {
|
||||||
|
return &profileClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *profileClient) GetProfiles(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error) {
|
||||||
|
out := new(Result)
|
||||||
|
err := grpc.Invoke(ctx, "/profile.Profile/GetProfiles", in, out, c.cc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Profile service
|
||||||
|
|
||||||
|
type ProfileServer interface {
|
||||||
|
GetProfiles(context.Context, *Request) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterProfileServer(s *grpc.Server, srv ProfileServer) {
|
||||||
|
s.RegisterService(&_Profile_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Profile_GetProfiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(Request)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(ProfileServer).GetProfiles(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/profile.Profile/GetProfiles",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(ProfileServer).GetProfiles(ctx, req.(*Request))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _Profile_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "profile.Profile",
|
||||||
|
HandlerType: (*ProfileServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "GetProfiles",
|
||||||
|
Handler: _Profile_GetProfiles_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "github.com/micro/examples/booking/srv/profile/proto/profile.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterFile("github.com/micro/examples/booking/srv/profile/proto/profile.proto", fileDescriptor0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 397 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x5c, 0x92, 0xc1, 0x6e, 0xd4, 0x30,
|
||||||
|
0x10, 0x86, 0x95, 0xdd, 0x6e, 0xd2, 0x9d, 0x45, 0xa5, 0x1a, 0x21, 0x64, 0xf5, 0x80, 0x56, 0x39,
|
||||||
|
0xa0, 0x15, 0x87, 0x4d, 0xb5, 0x3d, 0x22, 0x0e, 0x15, 0x07, 0xe8, 0x05, 0x21, 0xbf, 0x81, 0x13,
|
||||||
|
0x4f, 0x77, 0x2d, 0x9c, 0x38, 0xd8, 0x0e, 0xa2, 0x8f, 0xc5, 0x33, 0xf0, 0x62, 0xc8, 0x8e, 0xd3,
|
||||||
|
0x0d, 0x3d, 0x79, 0xfe, 0x6f, 0xc6, 0x9e, 0xf9, 0xad, 0x81, 0xfb, 0xa3, 0xf2, 0xa7, 0xa1, 0xde,
|
||||||
|
0x37, 0xa6, 0xad, 0x5a, 0xd5, 0x58, 0x53, 0xd1, 0x6f, 0xd1, 0xf6, 0x9a, 0x5c, 0x55, 0x1b, 0xf3,
|
||||||
|
0x43, 0x75, 0xc7, 0xca, 0xd9, 0x5f, 0x55, 0x6f, 0xcd, 0xa3, 0xd2, 0x14, 0x4e, 0x6f, 0x26, 0xb5,
|
||||||
|
0x8f, 0x0a, 0x8b, 0x24, 0xcb, 0x4f, 0x50, 0x70, 0xfa, 0x39, 0x90, 0xf3, 0x78, 0x03, 0x97, 0x27,
|
||||||
|
0xe3, 0x49, 0x3f, 0x48, 0xc7, 0xb2, 0xed, 0x72, 0xb7, 0xe6, 0xcf, 0x1a, 0xdf, 0x42, 0xae, 0x4d,
|
||||||
|
0x23, 0x34, 0xb1, 0xc5, 0x36, 0xdb, 0xad, 0x79, 0x52, 0xe5, 0x2d, 0xe4, 0x9c, 0xdc, 0xa0, 0x3d,
|
||||||
|
0xbe, 0x87, 0x3c, 0x56, 0x8f, 0x77, 0x37, 0x87, 0xab, 0xfd, 0xd4, 0xf1, 0x6b, 0xc0, 0x3c, 0x65,
|
||||||
|
0xcb, 0xbf, 0x19, 0xac, 0x22, 0xc1, 0x2b, 0x58, 0x28, 0xc9, 0xb2, 0xf8, 0xde, 0x42, 0x49, 0x44,
|
||||||
|
0xb8, 0xe8, 0x44, 0x3b, 0x75, 0x88, 0x31, 0x6e, 0x61, 0xd3, 0x9f, 0x4c, 0x47, 0xdf, 0x86, 0xb6,
|
||||||
|
0x26, 0xcb, 0x96, 0x31, 0x35, 0x47, 0xa1, 0x42, 0x92, 0x6b, 0xac, 0xea, 0xbd, 0x32, 0x1d, 0xbb,
|
||||||
|
0x18, 0x2b, 0x66, 0x08, 0x3f, 0x40, 0x21, 0xa4, 0xb4, 0xe4, 0x1c, 0x5b, 0x6d, 0xb3, 0xdd, 0xe6,
|
||||||
|
0x70, 0xfd, 0x3c, 0xda, 0xfd, 0xc8, 0xf9, 0x54, 0x10, 0x5c, 0xa8, 0x56, 0x1c, 0xc9, 0xb1, 0xfc,
|
||||||
|
0x85, 0x8b, 0x87, 0x80, 0x79, 0xca, 0x96, 0x7f, 0x32, 0x28, 0xd2, 0x65, 0x2c, 0xe1, 0x95, 0xf3,
|
||||||
|
0x96, 0xc8, 0xa7, 0x21, 0x47, 0x47, 0xff, 0x31, 0x7c, 0x07, 0x90, 0xf4, 0xd9, 0xe1, 0x8c, 0x04,
|
||||||
|
0xef, 0x8d, 0xf2, 0x4f, 0xc9, 0x60, 0x8c, 0xf1, 0x0d, 0xac, 0x9c, 0x17, 0x9e, 0x92, 0xa7, 0x51,
|
||||||
|
0x20, 0x83, 0xa2, 0x31, 0x43, 0xe7, 0xed, 0x53, 0x74, 0xb3, 0xe6, 0x93, 0x0c, 0x3d, 0x7a, 0xe3,
|
||||||
|
0xbc, 0xd0, 0x9f, 0x8d, 0x24, 0x96, 0x8f, 0x3d, 0xce, 0xa4, 0xbc, 0x83, 0x55, 0x34, 0x81, 0xd7,
|
||||||
|
0xb0, 0x1c, 0xac, 0x4e, 0x73, 0x86, 0x30, 0x3c, 0x2a, 0xe9, 0x51, 0x0c, 0xda, 0xc7, 0xd9, 0x2e,
|
||||||
|
0xf9, 0x24, 0x0f, 0x1f, 0xa1, 0xf8, 0x3e, 0xfe, 0x00, 0xde, 0xc2, 0xe6, 0x0b, 0xf9, 0xa4, 0x1c,
|
||||||
|
0x9e, 0x7f, 0x31, 0x2d, 0xd0, 0xcd, 0xeb, 0x19, 0x09, 0x3b, 0x51, 0xe7, 0x71, 0xd9, 0xee, 0xfe,
|
||||||
|
0x05, 0x00, 0x00, 0xff, 0xff, 0xf1, 0x00, 0x45, 0x96, 0xb1, 0x02, 0x00, 0x00,
|
||||||
|
}
|
||||||
39
examples/booking/srv/profile/proto/profile.proto
Normal file
39
examples/booking/srv/profile/proto/profile.proto
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package profile;
|
||||||
|
|
||||||
|
service Profile {
|
||||||
|
rpc GetProfiles(Request) returns (Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
message Request {
|
||||||
|
repeated string hotelIds = 1;
|
||||||
|
string locale = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Result {
|
||||||
|
repeated Hotel hotels = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Hotel {
|
||||||
|
string id = 1;
|
||||||
|
string name = 2;
|
||||||
|
string phoneNumber = 3;
|
||||||
|
string description = 4;
|
||||||
|
Address address = 5;
|
||||||
|
repeated Image images = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Address {
|
||||||
|
string streetNumber = 1;
|
||||||
|
string streetName = 2;
|
||||||
|
string city = 3;
|
||||||
|
string state = 4;
|
||||||
|
string country = 5;
|
||||||
|
string postalCode = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Image {
|
||||||
|
string url = 1;
|
||||||
|
bool default = 2;
|
||||||
|
}
|
||||||
4
examples/booking/srv/rate/Dockerfile
Normal file
4
examples/booking/srv/rate/Dockerfile
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
FROM alpine:3.2
|
||||||
|
ADD . /app
|
||||||
|
WORKDIR /app
|
||||||
|
ENTRYPOINT [ "/app/rate" ]
|
||||||
82
examples/booking/srv/rate/main.go
Normal file
82
examples/booking/srv/rate/main.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/micro/examples/booking/data"
|
||||||
|
"github.com/micro/examples/booking/srv/rate/proto"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
"golang.org/x/net/trace"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
"github.com/micro/go-micro/v2/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
type stay struct {
|
||||||
|
HotelID string
|
||||||
|
InDate string
|
||||||
|
OutDate string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Rate struct {
|
||||||
|
rateTable map[stay]*rate.RatePlan
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRates gets rates for hotels for specific date range.
|
||||||
|
func (s *Rate) GetRates(ctx context.Context, req *rate.Request, rsp *rate.Result) error {
|
||||||
|
md, _ := metadata.FromContext(ctx)
|
||||||
|
traceID := md["traceID"]
|
||||||
|
|
||||||
|
if tr, ok := trace.FromContext(ctx); ok {
|
||||||
|
tr.LazyPrintf("traceID %s", traceID)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, hotelID := range req.HotelIds {
|
||||||
|
stay := stay{
|
||||||
|
HotelID: hotelID,
|
||||||
|
InDate: req.InDate,
|
||||||
|
OutDate: req.OutDate,
|
||||||
|
}
|
||||||
|
if s.rateTable[stay] != nil {
|
||||||
|
rsp.RatePlans = append(rsp.RatePlans, s.rateTable[stay])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadRates loads rate codes from JSON file.
|
||||||
|
func loadRateTable(path string) map[stay]*rate.RatePlan {
|
||||||
|
file := data.MustAsset("data/rates.json")
|
||||||
|
|
||||||
|
rates := []*rate.RatePlan{}
|
||||||
|
if err := json.Unmarshal(file, &rates); err != nil {
|
||||||
|
log.Fatalf("Failed to load json: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rateTable := make(map[stay]*rate.RatePlan)
|
||||||
|
for _, ratePlan := range rates {
|
||||||
|
stay := stay{
|
||||||
|
HotelID: ratePlan.HotelId,
|
||||||
|
InDate: ratePlan.InDate,
|
||||||
|
OutDate: ratePlan.OutDate,
|
||||||
|
}
|
||||||
|
rateTable[stay] = ratePlan
|
||||||
|
}
|
||||||
|
return rateTable
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("go.micro.srv.rate"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
rate.RegisterRateHandler(service.Server(), &Rate{
|
||||||
|
rateTable: loadRateTable("data/rates.json"),
|
||||||
|
})
|
||||||
|
|
||||||
|
service.Run()
|
||||||
|
}
|
||||||
103
examples/booking/srv/rate/proto/rate.micro.go
Normal file
103
examples/booking/srv/rate/proto/rate.micro.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/booking/srv/rate/proto/rate.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package rate is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/booking/srv/rate/proto/rate.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Request
|
||||||
|
Result
|
||||||
|
RatePlan
|
||||||
|
RoomType
|
||||||
|
*/
|
||||||
|
package rate
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
client "github.com/micro/go-micro/v2/client"
|
||||||
|
server "github.com/micro/go-micro/v2/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ client.Option
|
||||||
|
var _ server.Option
|
||||||
|
|
||||||
|
// Client API for Rate service
|
||||||
|
|
||||||
|
type RateService interface {
|
||||||
|
// GetRates returns rate codes for hotels for a given date range
|
||||||
|
GetRates(ctx context.Context, in *Request, opts ...client.CallOption) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type rateService struct {
|
||||||
|
c client.Client
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRateService(serviceName string, c client.Client) RateService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(serviceName) == 0 {
|
||||||
|
serviceName = "rate"
|
||||||
|
}
|
||||||
|
return &rateService{
|
||||||
|
c: c,
|
||||||
|
serviceName: serviceName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *rateService) GetRates(ctx context.Context, in *Request, opts ...client.CallOption) (*Result, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Rate.GetRates", in)
|
||||||
|
out := new(Result)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Rate service
|
||||||
|
|
||||||
|
type RateHandler interface {
|
||||||
|
// GetRates returns rate codes for hotels for a given date range
|
||||||
|
GetRates(context.Context, *Request, *Result) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterRateHandler(s server.Server, hdlr RateHandler, opts ...server.HandlerOption) {
|
||||||
|
type rate interface {
|
||||||
|
GetRates(ctx context.Context, in *Request, out *Result) error
|
||||||
|
}
|
||||||
|
type Rate struct {
|
||||||
|
rate
|
||||||
|
}
|
||||||
|
h := &rateHandler{hdlr}
|
||||||
|
s.Handle(s.NewHandler(&Rate{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type rateHandler struct {
|
||||||
|
RateHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *rateHandler) GetRates(ctx context.Context, in *Request, out *Result) error {
|
||||||
|
return h.RateHandler.GetRates(ctx, in, out)
|
||||||
|
}
|
||||||
299
examples/booking/srv/rate/proto/rate.pb.go
Normal file
299
examples/booking/srv/rate/proto/rate.pb.go
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/booking/srv/rate/proto/rate.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package rate is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/booking/srv/rate/proto/rate.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Request
|
||||||
|
Result
|
||||||
|
RatePlan
|
||||||
|
RoomType
|
||||||
|
*/
|
||||||
|
package rate
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "golang.org/x/net/context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
HotelIds []string `protobuf:"bytes,1,rep,name=hotelIds" json:"hotelIds,omitempty"`
|
||||||
|
InDate string `protobuf:"bytes,2,opt,name=inDate" json:"inDate,omitempty"`
|
||||||
|
OutDate string `protobuf:"bytes,3,opt,name=outDate" json:"outDate,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Request) Reset() { *m = Request{} }
|
||||||
|
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Request) ProtoMessage() {}
|
||||||
|
func (*Request) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
|
||||||
|
func (m *Request) GetHotelIds() []string {
|
||||||
|
if m != nil {
|
||||||
|
return m.HotelIds
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Request) GetInDate() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.InDate
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Request) GetOutDate() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.OutDate
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
RatePlans []*RatePlan `protobuf:"bytes,1,rep,name=ratePlans" json:"ratePlans,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Result) Reset() { *m = Result{} }
|
||||||
|
func (m *Result) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Result) ProtoMessage() {}
|
||||||
|
func (*Result) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||||
|
|
||||||
|
func (m *Result) GetRatePlans() []*RatePlan {
|
||||||
|
if m != nil {
|
||||||
|
return m.RatePlans
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type RatePlan struct {
|
||||||
|
HotelId string `protobuf:"bytes,1,opt,name=hotelId" json:"hotelId,omitempty"`
|
||||||
|
Code string `protobuf:"bytes,2,opt,name=code" json:"code,omitempty"`
|
||||||
|
InDate string `protobuf:"bytes,3,opt,name=inDate" json:"inDate,omitempty"`
|
||||||
|
OutDate string `protobuf:"bytes,4,opt,name=outDate" json:"outDate,omitempty"`
|
||||||
|
RoomType *RoomType `protobuf:"bytes,5,opt,name=roomType" json:"roomType,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RatePlan) Reset() { *m = RatePlan{} }
|
||||||
|
func (m *RatePlan) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*RatePlan) ProtoMessage() {}
|
||||||
|
func (*RatePlan) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||||
|
|
||||||
|
func (m *RatePlan) GetHotelId() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.HotelId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RatePlan) GetCode() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Code
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RatePlan) GetInDate() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.InDate
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RatePlan) GetOutDate() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.OutDate
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RatePlan) GetRoomType() *RoomType {
|
||||||
|
if m != nil {
|
||||||
|
return m.RoomType
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoomType struct {
|
||||||
|
BookableRate float64 `protobuf:"fixed64,1,opt,name=bookableRate" json:"bookableRate,omitempty"`
|
||||||
|
TotalRate float64 `protobuf:"fixed64,2,opt,name=totalRate" json:"totalRate,omitempty"`
|
||||||
|
TotalRateInclusive float64 `protobuf:"fixed64,3,opt,name=totalRateInclusive" json:"totalRateInclusive,omitempty"`
|
||||||
|
Code string `protobuf:"bytes,4,opt,name=code" json:"code,omitempty"`
|
||||||
|
Currency string `protobuf:"bytes,5,opt,name=currency" json:"currency,omitempty"`
|
||||||
|
RoomDescription string `protobuf:"bytes,6,opt,name=roomDescription" json:"roomDescription,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RoomType) Reset() { *m = RoomType{} }
|
||||||
|
func (m *RoomType) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*RoomType) ProtoMessage() {}
|
||||||
|
func (*RoomType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||||
|
|
||||||
|
func (m *RoomType) GetBookableRate() float64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.BookableRate
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RoomType) GetTotalRate() float64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.TotalRate
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RoomType) GetTotalRateInclusive() float64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.TotalRateInclusive
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RoomType) GetCode() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Code
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RoomType) GetCurrency() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Currency
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *RoomType) GetRoomDescription() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.RoomDescription
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Request)(nil), "rate.Request")
|
||||||
|
proto.RegisterType((*Result)(nil), "rate.Result")
|
||||||
|
proto.RegisterType((*RatePlan)(nil), "rate.RatePlan")
|
||||||
|
proto.RegisterType((*RoomType)(nil), "rate.RoomType")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ grpc.ClientConn
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
const _ = grpc.SupportPackageIsVersion4
|
||||||
|
|
||||||
|
// Client API for Rate service
|
||||||
|
|
||||||
|
type RateClient interface {
|
||||||
|
// GetRates returns rate codes for hotels for a given date range
|
||||||
|
GetRates(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type rateClient struct {
|
||||||
|
cc *grpc.ClientConn
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRateClient(cc *grpc.ClientConn) RateClient {
|
||||||
|
return &rateClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *rateClient) GetRates(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Result, error) {
|
||||||
|
out := new(Result)
|
||||||
|
err := grpc.Invoke(ctx, "/rate.Rate/GetRates", in, out, c.cc, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Rate service
|
||||||
|
|
||||||
|
type RateServer interface {
|
||||||
|
// GetRates returns rate codes for hotels for a given date range
|
||||||
|
GetRates(context.Context, *Request) (*Result, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterRateServer(s *grpc.Server, srv RateServer) {
|
||||||
|
s.RegisterService(&_Rate_serviceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _Rate_GetRates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(Request)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(RateServer).GetRates(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/rate.Rate/GetRates",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(RateServer).GetRates(ctx, req.(*Request))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
var _Rate_serviceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "rate.Rate",
|
||||||
|
HandlerType: (*RateServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "GetRates",
|
||||||
|
Handler: _Rate_GetRates_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "github.com/micro/examples/booking/srv/rate/proto/rate.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterFile("github.com/micro/examples/booking/srv/rate/proto/rate.proto", fileDescriptor0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 351 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0x4f, 0x4b, 0xfb, 0x30,
|
||||||
|
0x18, 0xc7, 0xc9, 0x6f, 0xfd, 0x75, 0xed, 0xe3, 0x54, 0x78, 0x0e, 0x52, 0x86, 0x87, 0xd1, 0x8b,
|
||||||
|
0x43, 0xa4, 0x85, 0x09, 0x5e, 0xbc, 0x0e, 0x64, 0x37, 0x09, 0x82, 0xe7, 0xb6, 0x0b, 0x5b, 0x31,
|
||||||
|
0x6d, 0x6a, 0x92, 0x0e, 0xf7, 0x46, 0x7c, 0x69, 0xbe, 0x1e, 0x49, 0x9a, 0x76, 0x9b, 0xe8, 0xed,
|
||||||
|
0xfb, 0x27, 0x3c, 0xfd, 0xe4, 0x69, 0xe0, 0x71, 0x53, 0xea, 0x6d, 0x9b, 0x27, 0x85, 0xa8, 0xd2,
|
||||||
|
0xaa, 0x2c, 0xa4, 0x48, 0xd9, 0x47, 0x56, 0x35, 0x9c, 0xa9, 0x34, 0x17, 0xe2, 0xad, 0xac, 0x37,
|
||||||
|
0xa9, 0x92, 0xbb, 0x54, 0x66, 0x9a, 0xa5, 0x8d, 0x14, 0x5a, 0x58, 0x99, 0x58, 0x89, 0x9e, 0xd1,
|
||||||
|
0xf1, 0x2b, 0x8c, 0x29, 0x7b, 0x6f, 0x99, 0xd2, 0x38, 0x85, 0x60, 0x2b, 0x34, 0xe3, 0xab, 0xb5,
|
||||||
|
0x8a, 0xc8, 0x6c, 0x34, 0x0f, 0xe9, 0xe0, 0xf1, 0x0a, 0xfc, 0xb2, 0x5e, 0x66, 0x9a, 0x45, 0xff,
|
||||||
|
0x66, 0x64, 0x1e, 0x52, 0xe7, 0x30, 0x82, 0xb1, 0x68, 0xb5, 0x2d, 0x46, 0xb6, 0xe8, 0x6d, 0xfc,
|
||||||
|
0x00, 0x3e, 0x65, 0xaa, 0xe5, 0x1a, 0xef, 0x20, 0x34, 0x9f, 0x7a, 0xe6, 0x59, 0xdd, 0x0d, 0x3e,
|
||||||
|
0x5b, 0x5c, 0x24, 0x16, 0x84, 0xba, 0x98, 0x1e, 0x0e, 0xc4, 0x9f, 0x04, 0x82, 0x3e, 0x37, 0xe3,
|
||||||
|
0x1d, 0x42, 0x44, 0xba, 0xf1, 0xce, 0x22, 0x82, 0x57, 0x88, 0x75, 0x8f, 0x63, 0xf5, 0x11, 0xe4,
|
||||||
|
0xe8, 0x2f, 0x48, 0xef, 0x04, 0x12, 0x6f, 0x21, 0x90, 0x42, 0x54, 0x2f, 0xfb, 0x86, 0x45, 0xff,
|
||||||
|
0x67, 0xe4, 0x88, 0xcc, 0xa5, 0x74, 0xe8, 0xe3, 0x2f, 0x03, 0xe6, 0x0c, 0xc6, 0x30, 0x31, 0x1b,
|
||||||
|
0xce, 0x72, 0xce, 0x0c, 0xac, 0xa5, 0x23, 0xf4, 0x24, 0xc3, 0x6b, 0x08, 0xb5, 0xd0, 0x19, 0xa7,
|
||||||
|
0xfd, 0xda, 0x08, 0x3d, 0x04, 0x98, 0x00, 0x0e, 0x66, 0x55, 0x17, 0xbc, 0x55, 0xe5, 0xae, 0x03,
|
||||||
|
0x27, 0xf4, 0x97, 0x66, 0xb8, 0xb0, 0x77, 0x74, 0xe1, 0x29, 0x04, 0x45, 0x2b, 0x25, 0xab, 0x8b,
|
||||||
|
0xbd, 0xc5, 0x0f, 0xe9, 0xe0, 0x71, 0x0e, 0x97, 0x06, 0x7d, 0xc9, 0x54, 0x21, 0xcb, 0x46, 0x97,
|
||||||
|
0xa2, 0x8e, 0x7c, 0x7b, 0xe4, 0x67, 0xbc, 0x48, 0xc1, 0xb3, 0x44, 0x37, 0x10, 0x3c, 0x31, 0x6d,
|
||||||
|
0xa4, 0xc2, 0x73, 0xb7, 0x86, 0xee, 0x69, 0x4c, 0x27, 0xbd, 0x35, 0x3f, 0x34, 0xf7, 0xed, 0x03,
|
||||||
|
0xba, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xef, 0x8a, 0xc6, 0x91, 0x7f, 0x02, 0x00, 0x00,
|
||||||
|
}
|
||||||
35
examples/booking/srv/rate/proto/rate.proto
Normal file
35
examples/booking/srv/rate/proto/rate.proto
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package rate;
|
||||||
|
|
||||||
|
service Rate {
|
||||||
|
// GetRates returns rate codes for hotels for a given date range
|
||||||
|
rpc GetRates(Request) returns (Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
message Request {
|
||||||
|
repeated string hotelIds = 1;
|
||||||
|
string inDate = 2;
|
||||||
|
string outDate = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Result {
|
||||||
|
repeated RatePlan ratePlans = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RatePlan {
|
||||||
|
string hotelId = 1;
|
||||||
|
string code = 2;
|
||||||
|
string inDate = 3;
|
||||||
|
string outDate = 4;
|
||||||
|
RoomType roomType = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message RoomType {
|
||||||
|
double bookableRate = 1;
|
||||||
|
double totalRate = 2;
|
||||||
|
double totalRateInclusive = 3;
|
||||||
|
string code = 4;
|
||||||
|
string currency = 5;
|
||||||
|
string roomDescription = 6;
|
||||||
|
}
|
||||||
9
examples/broker/README.md
Normal file
9
examples/broker/README.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# Broker
|
||||||
|
|
||||||
|
The [broker](https://godoc.org/github.com/micro/go-micro/broker#Broker) is an interface for PubSub.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- main.go - uns pub-sub as two go routines for 10 seconds.
|
||||||
|
- producer - publishes messages to the broker every second
|
||||||
|
- consumer - consumes any messages sent by the producer
|
||||||
51
examples/broker/consumer/consumer.go
Normal file
51
examples/broker/consumer/consumer.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2/broker"
|
||||||
|
"github.com/micro/go-micro/v2/config/cmd"
|
||||||
|
// To enable rabbitmq plugin uncomment
|
||||||
|
//_ "github.com/micro/go-plugins/broker/rabbitmq"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
topic = "go.micro.topic.foo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Example of a shared subscription which receives a subset of messages
|
||||||
|
func sharedSub() {
|
||||||
|
_, err := broker.Subscribe(topic, func(p broker.Event) error {
|
||||||
|
fmt.Println("[sub] received message:", string(p.Message().Body), "header", p.Message().Header)
|
||||||
|
return nil
|
||||||
|
}, broker.Queue("consumer"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example of a subscription which receives all the messages
|
||||||
|
func sub() {
|
||||||
|
_, err := broker.Subscribe(topic, func(p broker.Event) error {
|
||||||
|
fmt.Println("[sub] received message:", string(p.Message().Body), "header", p.Message().Header)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Init()
|
||||||
|
|
||||||
|
if err := broker.Init(); err != nil {
|
||||||
|
log.Fatalf("Broker Init error: %v", err)
|
||||||
|
}
|
||||||
|
if err := broker.Connect(); err != nil {
|
||||||
|
log.Fatalf("Broker Connect error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sub()
|
||||||
|
select {}
|
||||||
|
}
|
||||||
59
examples/broker/main.go
Normal file
59
examples/broker/main.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2/broker"
|
||||||
|
"github.com/micro/go-micro/v2/config/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
topic = "go.micro.topic.foo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func pub() {
|
||||||
|
tick := time.NewTicker(time.Second)
|
||||||
|
i := 0
|
||||||
|
for _ = range tick.C {
|
||||||
|
msg := &broker.Message{
|
||||||
|
Header: map[string]string{
|
||||||
|
"id": fmt.Sprintf("%d", i),
|
||||||
|
},
|
||||||
|
Body: []byte(fmt.Sprintf("%d: %s", i, time.Now().String())),
|
||||||
|
}
|
||||||
|
if err := broker.Publish(topic, msg); err != nil {
|
||||||
|
log.Printf("[pub] failed: %v", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("[pub] pubbed message:", string(msg.Body))
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sub() {
|
||||||
|
_, err := broker.Subscribe(topic, func(p broker.Event) error {
|
||||||
|
fmt.Println("[sub] received message:", string(p.Message().Body), "header", p.Message().Header)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Init()
|
||||||
|
|
||||||
|
if err := broker.Init(); err != nil {
|
||||||
|
log.Fatalf("Broker Init error: %v", err)
|
||||||
|
}
|
||||||
|
if err := broker.Connect(); err != nil {
|
||||||
|
log.Fatalf("Broker Connect error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go pub()
|
||||||
|
go sub()
|
||||||
|
|
||||||
|
<-time.After(time.Second * 10)
|
||||||
|
}
|
||||||
49
examples/broker/producer/producer.go
Normal file
49
examples/broker/producer/producer.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2/broker"
|
||||||
|
"github.com/micro/go-micro/v2/config/cmd"
|
||||||
|
// To enable rabbitmq plugin uncomment
|
||||||
|
//_ "github.com/micro/go-plugins/broker/rabbitmq"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
topic = "go.micro.topic.foo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func pub() {
|
||||||
|
tick := time.NewTicker(time.Second)
|
||||||
|
i := 0
|
||||||
|
for _ = range tick.C {
|
||||||
|
msg := &broker.Message{
|
||||||
|
Header: map[string]string{
|
||||||
|
"id": fmt.Sprintf("%d", i),
|
||||||
|
},
|
||||||
|
Body: []byte(fmt.Sprintf("%d: %s", i, time.Now().String())),
|
||||||
|
}
|
||||||
|
if err := broker.Publish(topic, msg); err != nil {
|
||||||
|
log.Printf("[pub] failed: %v", err)
|
||||||
|
} else {
|
||||||
|
fmt.Println("[pub] pubbed message:", string(msg.Body))
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Init()
|
||||||
|
|
||||||
|
if err := broker.Init(); err != nil {
|
||||||
|
log.Fatalf("Broker Init error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := broker.Connect(); err != nil {
|
||||||
|
log.Fatalf("Broker Connect error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub()
|
||||||
|
}
|
||||||
12
examples/client/README.md
Normal file
12
examples/client/README.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Client
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- main.go - calls each of the go.micro.srv.example handlers and includes the use of the streaming handler
|
||||||
|
- codegen - demonstrates how to use code generation to remove boilerplate code
|
||||||
|
- dc_filter - shows how to use Select filters inside a call wrapper for filtering to the local DC
|
||||||
|
- dc_selector - is the same as dc_filter but as a Selector implementation itself
|
||||||
|
- pub - publishes messages using the Publish method. By default encoding in protobuf
|
||||||
|
- selector - shows how to write and load your own Selector
|
||||||
|
- wrapper - provides examples for how to use client Wrappers (middleware)
|
||||||
|
|
||||||
150
examples/client/codegen/README.md
Normal file
150
examples/client/codegen/README.md
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
# Code Generation [Experimental]
|
||||||
|
|
||||||
|
We're experimenting with code generation to reduce the amount of boiler plate code written.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Going from this
|
||||||
|
```golang
|
||||||
|
req := client.NewRequest("go.micro.srv.example", "Example.Call", &example.Request{
|
||||||
|
Name: "John",
|
||||||
|
})
|
||||||
|
|
||||||
|
rsp := &example.Response{}
|
||||||
|
|
||||||
|
if err := client.Call(context.Background(), req, rsp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To
|
||||||
|
|
||||||
|
```golang
|
||||||
|
rsp, err := cl.Call(context.Background(), &example.Request{Name: "John"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generation of stub code for the example service
|
||||||
|
|
||||||
|
```shell
|
||||||
|
go get github.com/micro/protobuf/protoc-gen-go
|
||||||
|
cd examples/server/proto/example
|
||||||
|
protoc --go_out=plugins=micro:. example.proto
|
||||||
|
```
|
||||||
|
|
||||||
|
Look at examples/server/proto/example/example.pb.go
|
||||||
|
to see the generated code.
|
||||||
|
|
||||||
|
## Guide
|
||||||
|
|
||||||
|
### Download the protoc-gen-go code
|
||||||
|
|
||||||
|
```shell
|
||||||
|
go get github.com/micro/protobuf/protoc-gen-go
|
||||||
|
```
|
||||||
|
|
||||||
|
### Define your proto service.
|
||||||
|
|
||||||
|
hello.proto
|
||||||
|
```shell
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
// package name is used as the service name for discovery
|
||||||
|
// if service name is not passed in when initialising the
|
||||||
|
// client
|
||||||
|
package go.micro.srv.greeter;
|
||||||
|
|
||||||
|
service Say {
|
||||||
|
rpc Hello(Request) returns (Response) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Request {
|
||||||
|
optional string name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Response {
|
||||||
|
optional string msg = 1;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note: Remember to set package name in the proto, it's used to generate
|
||||||
|
the service for discovery.**
|
||||||
|
|
||||||
|
### Generate code
|
||||||
|
|
||||||
|
```shell
|
||||||
|
protoc --go_out=plugins=micro:. hello.proto
|
||||||
|
```
|
||||||
|
|
||||||
|
### Generated code
|
||||||
|
|
||||||
|
```shell
|
||||||
|
// Client API for Say service
|
||||||
|
|
||||||
|
type SayClient interface {
|
||||||
|
Hello(ctx context.Context, in *Request) (*Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type sayClient struct {
|
||||||
|
c client.Client
|
||||||
|
serviceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSayClient(serviceName string, c client.Client) SayClient {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(serviceName) == 0 {
|
||||||
|
serviceName = "go.micro.srv.greeter"
|
||||||
|
}
|
||||||
|
return &sayClient{
|
||||||
|
c: c,
|
||||||
|
serviceName: serviceName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *sayClient) Hello(ctx context.Context, in *Request) (*Response, error) {
|
||||||
|
req := c.c.NewRequest(c.serviceName, "Say.Hello", in)
|
||||||
|
out := new(Response)
|
||||||
|
err := c.c.Call(ctx, req, out)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Say service
|
||||||
|
|
||||||
|
type SayHandler interface {
|
||||||
|
Hello(context.Context, *Request, *Response) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterSayHandler(s server.Server, hdlr SayHandler) {
|
||||||
|
s.Handle(s.NewHandler(hdlr))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use the client
|
||||||
|
```golang
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
"github.com/micro/go-micro/v2/client"
|
||||||
|
hello "path/to/hello/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cl := hello.NewSayClient("go.micro.srv.greeter", client.DefaultClient)
|
||||||
|
// alternative initialisation
|
||||||
|
// cl := hello.NewSayClient("", nil)
|
||||||
|
|
||||||
|
rsp, err := cl.Hello(contex.Background(), &hello.Request{"Name": "John"})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
79
examples/client/codegen/codegen.go
Normal file
79
examples/client/codegen/codegen.go
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
example "github.com/micro/examples/server/proto/example"
|
||||||
|
"github.com/micro/go-micro/v2/config/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
cl = example.NewExampleService("go.micro.srv.example", nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
func call(i int) {
|
||||||
|
rsp, err := cl.Call(context.Background(), &example.Request{Name: "John"})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("call err: ", err, rsp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println("Call:", i, "rsp:", rsp.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func stream(i int) {
|
||||||
|
stream, err := cl.Stream(context.Background(), &example.StreamingRequest{Count: int64(i)})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
rsp, err := stream.Recv()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Println("Stream: rsp:", rsp.Count)
|
||||||
|
}
|
||||||
|
if err := stream.Close(); err != nil {
|
||||||
|
fmt.Println("stream close err:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pingPong(i int) {
|
||||||
|
stream, err := cl.PingPong(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if err := stream.Send(&example.Ping{Stroke: int64(j)}); err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rsp, err := stream.Recv()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("recv err", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Printf("Sent ping %v got pong %v\n", j, rsp.Stroke)
|
||||||
|
}
|
||||||
|
if err := stream.Close(); err != nil {
|
||||||
|
fmt.Println("stream close err:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Init()
|
||||||
|
|
||||||
|
fmt.Println("\n--- Call example ---")
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
call(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("\n--- Streamer example ---")
|
||||||
|
stream(10)
|
||||||
|
|
||||||
|
fmt.Println("\n--- Ping Pong example ---")
|
||||||
|
pingPong(10)
|
||||||
|
}
|
||||||
88
examples/client/dc_filter/dc_filter.go
Normal file
88
examples/client/dc_filter/dc_filter.go
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2/client"
|
||||||
|
"github.com/micro/go-micro/v2/client/selector"
|
||||||
|
"github.com/micro/go-micro/v2/config/cmd"
|
||||||
|
"github.com/micro/go-micro/v2/metadata"
|
||||||
|
"github.com/micro/go-micro/v2/registry"
|
||||||
|
|
||||||
|
example "github.com/micro/examples/server/proto/example"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Wrapper that creates a Datacenter Selector Option
|
||||||
|
type dcWrapper struct {
|
||||||
|
client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dc *dcWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
||||||
|
md, _ := metadata.FromContext(ctx)
|
||||||
|
|
||||||
|
filter := func(services []*registry.Service) []*registry.Service {
|
||||||
|
for _, service := range services {
|
||||||
|
var nodes []*registry.Node
|
||||||
|
for _, node := range service.Nodes {
|
||||||
|
if node.Metadata["datacenter"] == md["datacenter"] {
|
||||||
|
nodes = append(nodes, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
service.Nodes = nodes
|
||||||
|
}
|
||||||
|
return services
|
||||||
|
}
|
||||||
|
|
||||||
|
callOptions := append(opts, client.WithSelectOption(
|
||||||
|
selector.WithFilter(filter),
|
||||||
|
))
|
||||||
|
|
||||||
|
fmt.Printf("[DC Wrapper] filtering for datacenter %s\n", md["datacenter"])
|
||||||
|
return dc.Client.Call(ctx, req, rsp, callOptions...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDCWrapper(c client.Client) client.Client {
|
||||||
|
return &dcWrapper{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func call(i int) {
|
||||||
|
// Create new request to service go.micro.srv.example, method Example.Call
|
||||||
|
req := client.NewRequest("go.micro.srv.example", "Example.Call", &example.Request{
|
||||||
|
Name: "John",
|
||||||
|
})
|
||||||
|
|
||||||
|
// create context with metadata
|
||||||
|
ctx := metadata.NewContext(context.Background(), map[string]string{
|
||||||
|
"datacenter": "local",
|
||||||
|
})
|
||||||
|
|
||||||
|
rsp := &example.Response{}
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
if err := client.Call(ctx, req, rsp); err != nil {
|
||||||
|
fmt.Println("call err: ", err, rsp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Call:", i, "rsp:", rsp.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Init()
|
||||||
|
|
||||||
|
client.DefaultClient = client.NewClient(
|
||||||
|
client.Wrap(NewDCWrapper),
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Println("\n--- Call example ---")
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
call(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
134
examples/client/dc_selector/dc_selector.go
Normal file
134
examples/client/dc_selector/dc_selector.go
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2/client"
|
||||||
|
"github.com/micro/go-micro/v2/client/selector"
|
||||||
|
"github.com/micro/go-micro/v2/config/cmd"
|
||||||
|
"github.com/micro/go-micro/v2/registry"
|
||||||
|
|
||||||
|
example "github.com/micro/examples/server/proto/example"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Built in random hashed node selector
|
||||||
|
type dcSelector struct {
|
||||||
|
opts selector.Options
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
datacenter = "local"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *dcSelector) Init(opts ...selector.Option) error {
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&n.opts)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *dcSelector) Options() selector.Options {
|
||||||
|
return n.opts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *dcSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) {
|
||||||
|
services, err := n.opts.Registry.GetService(service)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(services) == 0 {
|
||||||
|
return nil, selector.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodes []*registry.Node
|
||||||
|
|
||||||
|
// Filter the nodes for datacenter
|
||||||
|
for _, service := range services {
|
||||||
|
for _, node := range service.Nodes {
|
||||||
|
if node.Metadata["datacenter"] == datacenter {
|
||||||
|
nodes = append(nodes, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(nodes) == 0 {
|
||||||
|
return nil, selector.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
var i int
|
||||||
|
var mtx sync.Mutex
|
||||||
|
|
||||||
|
return func() (*registry.Node, error) {
|
||||||
|
mtx.Lock()
|
||||||
|
defer mtx.Unlock()
|
||||||
|
i++
|
||||||
|
return nodes[i%len(nodes)], nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *dcSelector) Mark(service string, node *registry.Node, err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *dcSelector) Reset(service string) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *dcSelector) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *dcSelector) String() string {
|
||||||
|
return "dc"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a new first node selector
|
||||||
|
func DCSelector(opts ...selector.Option) selector.Selector {
|
||||||
|
var sopts selector.Options
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&sopts)
|
||||||
|
}
|
||||||
|
if sopts.Registry == nil {
|
||||||
|
sopts.Registry = registry.DefaultRegistry
|
||||||
|
}
|
||||||
|
return &dcSelector{sopts}
|
||||||
|
}
|
||||||
|
|
||||||
|
func call(i int) {
|
||||||
|
// Create new request to service go.micro.srv.example, method Example.Call
|
||||||
|
req := client.NewRequest("go.micro.srv.example", "Example.Call", &example.Request{
|
||||||
|
Name: "John",
|
||||||
|
})
|
||||||
|
|
||||||
|
rsp := &example.Response{}
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
if err := client.Call(context.Background(), req, rsp); err != nil {
|
||||||
|
fmt.Println("call err: ", err, rsp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Call:", i, "rsp:", rsp.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Init()
|
||||||
|
|
||||||
|
client.DefaultClient = client.NewClient(
|
||||||
|
client.Selector(DCSelector()),
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Println("\n--- Call example ---")
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
call(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
139
examples/client/main.go
Normal file
139
examples/client/main.go
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
example "github.com/micro/examples/server/proto/example"
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
"github.com/micro/go-micro/v2/client"
|
||||||
|
"github.com/micro/go-micro/v2/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
|
// publishes a message
|
||||||
|
func pub(p micro.Publisher) {
|
||||||
|
msg := &example.Message{
|
||||||
|
Say: "This is an async message",
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.Publish(context.TODO(), msg); err != nil {
|
||||||
|
fmt.Println("pub err: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Published: %v\n", msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func call(i int, c client.Client) {
|
||||||
|
// Create new request to service go.micro.srv.example, method Example.Call
|
||||||
|
req := c.NewRequest("go.micro.srv.example", "Example.Call", &example.Request{
|
||||||
|
Name: "John",
|
||||||
|
})
|
||||||
|
|
||||||
|
// create context with metadata
|
||||||
|
ctx := metadata.NewContext(context.Background(), map[string]string{
|
||||||
|
"X-User-Id": "john",
|
||||||
|
"X-From-Id": "script",
|
||||||
|
})
|
||||||
|
|
||||||
|
rsp := &example.Response{}
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
if err := c.Call(ctx, req, rsp); err != nil {
|
||||||
|
fmt.Println("call err: ", err, rsp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Call:", i, "rsp:", rsp.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func stream(i int, c client.Client) {
|
||||||
|
// Create new request to service go.micro.srv.example, method Example.Call
|
||||||
|
// Request can be empty as its actually ignored and merely used to call the handler
|
||||||
|
req := c.NewRequest("go.micro.srv.example", "Example.Stream", &example.StreamingRequest{})
|
||||||
|
|
||||||
|
stream, err := c.Stream(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := stream.Send(&example.StreamingRequest{Count: int64(i)}); err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for stream.Error() == nil {
|
||||||
|
rsp := &example.StreamingResponse{}
|
||||||
|
err := stream.Recv(rsp)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("recv err", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Println("Stream: rsp:", rsp.Count)
|
||||||
|
}
|
||||||
|
|
||||||
|
if stream.Error() != nil {
|
||||||
|
fmt.Println("stream err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := stream.Close(); err != nil {
|
||||||
|
fmt.Println("stream close err:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pingPong(i int, c client.Client) {
|
||||||
|
// Create new request to service go.micro.srv.example, method Example.Call
|
||||||
|
// Request can be empty as its actually ignored and merely used to call the handler
|
||||||
|
req := c.NewRequest("go.micro.srv.example", "Example.PingPong", &example.StreamingRequest{})
|
||||||
|
|
||||||
|
stream, err := c.Stream(context.Background(), req)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for j := 0; j < i; j++ {
|
||||||
|
if err := stream.Send(&example.Ping{Stroke: int64(j + 1)}); err != nil {
|
||||||
|
fmt.Println("err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rsp := &example.Pong{}
|
||||||
|
err := stream.Recv(rsp)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("recv err", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
fmt.Printf("Sent ping %v got pong %v\n", j+1, rsp.Stroke)
|
||||||
|
}
|
||||||
|
|
||||||
|
if stream.Error() != nil {
|
||||||
|
fmt.Println("stream err:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := stream.Close(); err != nil {
|
||||||
|
fmt.Println("stream close err:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService()
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
p := micro.NewPublisher("topic.example", service.Client())
|
||||||
|
|
||||||
|
fmt.Println("\n--- Publisher example ---")
|
||||||
|
pub(p)
|
||||||
|
|
||||||
|
fmt.Println("\n--- Call example ---")
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
call(i, service.Client())
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("\n--- Streamer example ---")
|
||||||
|
stream(10, service.Client())
|
||||||
|
|
||||||
|
fmt.Println("\n--- Ping Pong example ---")
|
||||||
|
pingPong(10, service.Client())
|
||||||
|
|
||||||
|
}
|
||||||
36
examples/client/pub/pub.go
Normal file
36
examples/client/pub/pub.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
example "github.com/micro/examples/server/proto/example"
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// publishes a message
|
||||||
|
func pub(i int, p micro.Publisher) {
|
||||||
|
msg := &example.Message{
|
||||||
|
Say: fmt.Sprintf("This is an async message %d", i),
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.Publish(context.TODO(), msg); err != nil {
|
||||||
|
fmt.Println("pub err: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Published %d: %v\n", i, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService()
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
p := micro.NewPublisher("example", service.Client())
|
||||||
|
|
||||||
|
fmt.Println("\n--- Publisher example ---")
|
||||||
|
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
pub(i, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
124
examples/client/selector/selector.go
Normal file
124
examples/client/selector/selector.go
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
example "github.com/micro/examples/server/proto/example"
|
||||||
|
"github.com/micro/go-micro/v2/client"
|
||||||
|
"github.com/micro/go-micro/v2/client/selector"
|
||||||
|
"github.com/micro/go-micro/v2/config/cmd"
|
||||||
|
"github.com/micro/go-micro/v2/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Built in random hashed node selector
|
||||||
|
type firstNodeSelector struct {
|
||||||
|
opts selector.Options
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *firstNodeSelector) Init(opts ...selector.Option) error {
|
||||||
|
for _, o := range opts {
|
||||||
|
o(&n.opts)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *firstNodeSelector) Options() selector.Options {
|
||||||
|
return n.opts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *firstNodeSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) {
|
||||||
|
services, err := n.opts.Registry.GetService(service)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(services) == 0 {
|
||||||
|
return nil, selector.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
var sopts selector.SelectOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&sopts)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, filter := range sopts.Filters {
|
||||||
|
services = filter(services)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(services) == 0 {
|
||||||
|
return nil, selector.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(services[0].Nodes) == 0 {
|
||||||
|
return nil, selector.ErrNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
return func() (*registry.Node, error) {
|
||||||
|
return services[0].Nodes[0], nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *firstNodeSelector) Mark(service string, node *registry.Node, err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *firstNodeSelector) Reset(service string) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *firstNodeSelector) Close() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *firstNodeSelector) String() string {
|
||||||
|
return "first"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a new first node selector
|
||||||
|
func FirstNodeSelector(opts ...selector.Option) selector.Selector {
|
||||||
|
var sopts selector.Options
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&sopts)
|
||||||
|
}
|
||||||
|
if sopts.Registry == nil {
|
||||||
|
sopts.Registry = registry.DefaultRegistry
|
||||||
|
}
|
||||||
|
return &firstNodeSelector{sopts}
|
||||||
|
}
|
||||||
|
|
||||||
|
func call(i int) {
|
||||||
|
// Create new request to service go.micro.srv.example, method Example.Call
|
||||||
|
req := client.NewRequest("go.micro.srv.example", "Example.Call", &example.Request{
|
||||||
|
Name: "John",
|
||||||
|
})
|
||||||
|
|
||||||
|
rsp := &example.Response{}
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
if err := client.Call(context.Background(), req, rsp); err != nil {
|
||||||
|
fmt.Println("call err: ", err, rsp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Call:", i, "rsp:", rsp.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Init()
|
||||||
|
|
||||||
|
client.DefaultClient = client.NewClient(
|
||||||
|
client.Selector(FirstNodeSelector()),
|
||||||
|
)
|
||||||
|
|
||||||
|
fmt.Println("\n--- Call example ---")
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
call(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
110
examples/client/wrapper/wrapper.go
Normal file
110
examples/client/wrapper/wrapper.go
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
example "github.com/micro/examples/server/proto/example"
|
||||||
|
"github.com/micro/go-micro/v2/client"
|
||||||
|
"github.com/micro/go-micro/v2/config/cmd"
|
||||||
|
"github.com/micro/go-micro/v2/metadata"
|
||||||
|
"github.com/micro/go-micro/v2/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// wrapper example code
|
||||||
|
|
||||||
|
// log wrapper logs every time a request is made
|
||||||
|
type logWrapper struct {
|
||||||
|
client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *logWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
||||||
|
md, _ := metadata.FromContext(ctx)
|
||||||
|
fmt.Printf("[Log Wrapper] ctx: %v service: %s method: %s\n", md, req.Service(), req.Endpoint())
|
||||||
|
return l.Client.Call(ctx, req, rsp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// trace wrapper attaches a unique trace ID - timestamp
|
||||||
|
type traceWrapper struct {
|
||||||
|
client.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *traceWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
||||||
|
ctx = metadata.NewContext(ctx, map[string]string{
|
||||||
|
"X-Trace-Id": fmt.Sprintf("%d", time.Now().Unix()),
|
||||||
|
})
|
||||||
|
return t.Client.Call(ctx, req, rsp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements client.Wrapper as logWrapper
|
||||||
|
func logWrap(c client.Client) client.Client {
|
||||||
|
return &logWrapper{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements client.Wrapper as traceWrapper
|
||||||
|
func traceWrap(c client.Client) client.Client {
|
||||||
|
return &traceWrapper{c}
|
||||||
|
}
|
||||||
|
|
||||||
|
func metricsWrap(cf client.CallFunc) client.CallFunc {
|
||||||
|
return func(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error {
|
||||||
|
t := time.Now()
|
||||||
|
err := cf(ctx, node, req, rsp, opts)
|
||||||
|
fmt.Printf("[Metrics Wrapper] called: %v %s.%s duration: %v\n", node, req.Service(), req.Endpoint(), time.Since(t))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func call(i int) {
|
||||||
|
// Create new request to service go.micro.srv.example, method Example.Call
|
||||||
|
req := client.NewRequest("go.micro.srv.example", "Example.Call", &example.Request{
|
||||||
|
Name: "John",
|
||||||
|
})
|
||||||
|
|
||||||
|
// create context with metadata
|
||||||
|
ctx := metadata.NewContext(context.Background(), map[string]string{
|
||||||
|
"X-User-Id": "john",
|
||||||
|
"X-From-Id": "script",
|
||||||
|
})
|
||||||
|
|
||||||
|
rsp := &example.Response{}
|
||||||
|
|
||||||
|
// Call service
|
||||||
|
if err := client.Call(ctx, req, rsp); err != nil {
|
||||||
|
fmt.Println("call err: ", err, rsp)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Call:", i, "rsp:", rsp.Msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cmd.Init()
|
||||||
|
|
||||||
|
fmt.Println("\n--- Log Wrapper example ---")
|
||||||
|
|
||||||
|
// Wrap the default client
|
||||||
|
client.DefaultClient = logWrap(client.DefaultClient)
|
||||||
|
|
||||||
|
call(0)
|
||||||
|
|
||||||
|
fmt.Println("\n--- Log+Trace Wrapper example ---")
|
||||||
|
|
||||||
|
// Wrap using client.Wrap option
|
||||||
|
client.DefaultClient = client.NewClient(
|
||||||
|
client.Wrap(traceWrap),
|
||||||
|
client.Wrap(logWrap),
|
||||||
|
)
|
||||||
|
|
||||||
|
call(1)
|
||||||
|
|
||||||
|
fmt.Println("\n--- Metrics Wrapper example ---")
|
||||||
|
|
||||||
|
// Wrap using client.Wrap option
|
||||||
|
client.DefaultClient = client.NewClient(
|
||||||
|
client.WrapCall(metricsWrap),
|
||||||
|
)
|
||||||
|
|
||||||
|
call(2)
|
||||||
|
}
|
||||||
19
examples/command/README.md
Normal file
19
examples/command/README.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Command
|
||||||
|
|
||||||
|
This is an example of a bot command as a microservice
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- main.go - is the main definition of the service and handler
|
||||||
|
|
||||||
|
## Run the example
|
||||||
|
|
||||||
|
Run the service
|
||||||
|
|
||||||
|
```shell
|
||||||
|
go run main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
## Call the service
|
||||||
|
|
||||||
|
Run the [bot](https://micro.mu/docs/bot.html) and send message `command`
|
||||||
42
examples/command/main.go
Normal file
42
examples/command/main.go
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"context"
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
|
||||||
|
proto "github.com/micro/go-micro/v2/agent/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Command struct{}
|
||||||
|
|
||||||
|
// Help returns the command usage
|
||||||
|
func (c *Command) Help(ctx context.Context, req *proto.HelpRequest, rsp *proto.HelpResponse) error {
|
||||||
|
rsp.Usage = "command"
|
||||||
|
rsp.Description = "This is an example bot command as a micro service"
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exec executes the command
|
||||||
|
func (c *Command) Exec(ctx context.Context, req *proto.ExecRequest, rsp *proto.ExecResponse) error {
|
||||||
|
rsp.Result = []byte(strings.Join(req.Args, " "))
|
||||||
|
// rsp.Error could be set to return an error instead
|
||||||
|
// the function error would only be used for service level issues
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("go.micro.bot.command"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
proto.RegisterCommandHandler(service.Server(), new(Command))
|
||||||
|
|
||||||
|
if err := service.Run(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
4
examples/config/README.md
Normal file
4
examples/config/README.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Go Config
|
||||||
|
|
||||||
|
This example demonstrates how to use Go Config for dynamic configuration.
|
||||||
|
|
||||||
12
examples/config/file/config.json
Normal file
12
examples/config/file/config.json
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"hosts": {
|
||||||
|
"database": {
|
||||||
|
"address": "10.0.0.1",
|
||||||
|
"port": 3306
|
||||||
|
},
|
||||||
|
"cache": {
|
||||||
|
"address": "10.0.0.2",
|
||||||
|
"port": 6379
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
34
examples/config/file/main.go
Normal file
34
examples/config/file/main.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2/config"
|
||||||
|
"github.com/micro/go-micro/v2/config/source/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// load the config from a file source
|
||||||
|
if err := config.Load(file.NewSource(
|
||||||
|
file.WithPath("./config.json"),
|
||||||
|
)); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// define our own host type
|
||||||
|
type Host struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var host Host
|
||||||
|
|
||||||
|
// read a database host
|
||||||
|
if err := config.Get("hosts", "database").Scan(&host); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(host.Address, host.Port)
|
||||||
|
}
|
||||||
43
examples/config/grpc/README.md
Normal file
43
examples/config/grpc/README.md
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
# gRPC Config Server
|
||||||
|
|
||||||
|
This is an example implementation of a grpc config server
|
||||||
|
|
||||||
|
## Get Started
|
||||||
|
|
||||||
|
### Run Server
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go run srv/main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Client
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go run client/main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
### Edit Config
|
||||||
|
|
||||||
|
Change values in srv/conf/micro.yml
|
||||||
|
|
||||||
|
```bash
|
||||||
|
micro:
|
||||||
|
name: Micro
|
||||||
|
version: 1.0.0
|
||||||
|
message: hello
|
||||||
|
```
|
||||||
|
|
||||||
|
to
|
||||||
|
|
||||||
|
```bash
|
||||||
|
micro:
|
||||||
|
name: Micro
|
||||||
|
version: 1.0.0
|
||||||
|
message: hello john
|
||||||
|
```
|
||||||
|
|
||||||
|
The output from watching config after an edit
|
||||||
|
|
||||||
|
```bash
|
||||||
|
2019/04/28 10:57:15 Watch changes: {"message":"hello john","name":"Micro","version":"1.0.0"}
|
||||||
|
```
|
||||||
58
examples/config/grpc/client/main.go
Normal file
58
examples/config/grpc/client/main.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/micro/go-micro/v2/config"
|
||||||
|
"github.com/micro/go-micro/v2/util/log"
|
||||||
|
grpcConfig "github.com/micro/go-plugins/config/source/grpc/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Micro struct {
|
||||||
|
Info
|
||||||
|
}
|
||||||
|
|
||||||
|
type Info struct {
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
Age int `json:"age,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// create new source
|
||||||
|
source := grpcConfig.NewSource(
|
||||||
|
grpcConfig.WithAddress("127.0.0.1:8600"),
|
||||||
|
grpcConfig.WithPath("/micro"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// create new config
|
||||||
|
conf, _ := config.NewConfig()
|
||||||
|
|
||||||
|
// load the source into config
|
||||||
|
if err := conf.Load(source); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
configs := &Micro{}
|
||||||
|
if err := conf.Scan(configs); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Logf("Read config: %s", string(conf.Bytes()))
|
||||||
|
|
||||||
|
// watch the config for changes
|
||||||
|
watcher, err := conf.Watch()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Logf("Watching for changes ...")
|
||||||
|
|
||||||
|
for {
|
||||||
|
v, err := watcher.Next()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Logf("Watching for changes: %v", string(v.Bytes()))
|
||||||
|
}
|
||||||
|
}
|
||||||
4
examples/config/grpc/srv/conf/extra.yml
Normal file
4
examples/config/grpc/srv/conf/extra.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
other:
|
||||||
|
name: Extra
|
||||||
|
version: 1.0.0
|
||||||
|
message: Ugh this sucks
|
||||||
4
examples/config/grpc/srv/conf/micro.yml
Normal file
4
examples/config/grpc/srv/conf/micro.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
micro:
|
||||||
|
name: Micro
|
||||||
|
version: 1.0.0
|
||||||
|
message: hello
|
||||||
4
examples/config/grpc/srv/conf/other.yml
Normal file
4
examples/config/grpc/srv/conf/other.yml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
other:
|
||||||
|
name: badBoy
|
||||||
|
version: 1.0.0
|
||||||
|
hi: Ah
|
||||||
130
examples/config/grpc/srv/main.go
Normal file
130
examples/config/grpc/srv/main.go
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/md5"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2/config"
|
||||||
|
"github.com/micro/go-micro/v2/config/source/file"
|
||||||
|
"github.com/micro/go-micro/v2/util/log"
|
||||||
|
proto "github.com/micro/go-plugins/config/source/grpc/v2/proto"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mux sync.RWMutex
|
||||||
|
configMaps = make(map[string]*proto.ChangeSet)
|
||||||
|
apps = []string{"micro", "extra"}
|
||||||
|
)
|
||||||
|
|
||||||
|
type Service struct{}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// load config files
|
||||||
|
err := loadConfigFile()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// new service
|
||||||
|
service := grpc.NewServer()
|
||||||
|
proto.RegisterSourceServer(service, new(Service))
|
||||||
|
ts, err := net.Listen("tcp", ":8600")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Logf("configServer started")
|
||||||
|
err = service.Serve(ts)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) Read(ctx context.Context, req *proto.ReadRequest) (rsp *proto.ReadResponse, err error) {
|
||||||
|
appName := parsePath(req.Path)
|
||||||
|
switch appName {
|
||||||
|
case "micro", "extra":
|
||||||
|
rsp = &proto.ReadResponse{
|
||||||
|
ChangeSet: getConfig(appName),
|
||||||
|
}
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("[Read] the first path is invalid")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) Watch(req *proto.WatchRequest, server proto.Source_WatchServer) (err error) {
|
||||||
|
appName := parsePath(req.Path)
|
||||||
|
rsp := &proto.WatchResponse{
|
||||||
|
ChangeSet: getConfig(appName),
|
||||||
|
}
|
||||||
|
if err = server.Send(rsp); err != nil {
|
||||||
|
log.Logf("[Watch] watch files error,%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadConfigFile() (err error) {
|
||||||
|
for _, app := range apps {
|
||||||
|
if err := config.Load(file.NewSource(
|
||||||
|
file.WithPath("./conf/" + app + ".yml"),
|
||||||
|
)); err != nil {
|
||||||
|
log.Fatalf("[loadConfigFile] load files error,%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// watch changes
|
||||||
|
watcher, err := config.Watch()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("[loadConfigFile] start watching files error,%s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
v, err := watcher.Next()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("[loadConfigFile] watch files error,%s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Logf("[loadConfigFile] file change, %s", string(v.Bytes()))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getConfig(appName string) *proto.ChangeSet {
|
||||||
|
bytes := config.Get(appName).Bytes()
|
||||||
|
|
||||||
|
log.Logf("[getConfig] appName,%s", string(bytes))
|
||||||
|
return &proto.ChangeSet{
|
||||||
|
Data: bytes,
|
||||||
|
Checksum: fmt.Sprintf("%x", md5.Sum(bytes)),
|
||||||
|
Format: "yml",
|
||||||
|
Source: "file",
|
||||||
|
Timestamp: time.Now().Unix()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parsePath(path string) (appName string) {
|
||||||
|
paths := strings.Split(path, "/")
|
||||||
|
|
||||||
|
if paths[0] == "" && len(paths) > 1 {
|
||||||
|
return paths[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths[0]
|
||||||
|
}
|
||||||
14
examples/config/modify/README.md
Normal file
14
examples/config/modify/README.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# Modify Config
|
||||||
|
|
||||||
|
This is an example of modifying config in a file.
|
||||||
|
|
||||||
|
Note: We currently only support setting values in memory, not passing down to the source.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
- example.conf is a toml file format
|
||||||
|
- modify.go - loads, modifies and writes back the file
|
||||||
|
|
||||||
|
```
|
||||||
|
go run modify.go
|
||||||
|
```
|
||||||
47
examples/config/modify/example.conf
Normal file
47
examples/config/modify/example.conf
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# This is a TOML document. Boom.
|
||||||
|
|
||||||
|
title = "TOML Example"
|
||||||
|
|
||||||
|
[owner]
|
||||||
|
name = "Tom Preston-Werner"
|
||||||
|
organization = "GitHub"
|
||||||
|
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
|
||||||
|
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
|
||||||
|
|
||||||
|
[database]
|
||||||
|
server = "192.168.1.1"
|
||||||
|
ports = [ 8001, 8001, 8002 ]
|
||||||
|
connection_max = 5000
|
||||||
|
enabled = true
|
||||||
|
|
||||||
|
[servers]
|
||||||
|
|
||||||
|
# You can indent as you please. Tabs or spaces. TOML don't care.
|
||||||
|
[servers.alpha]
|
||||||
|
ip = "10.0.0.1"
|
||||||
|
dc = "eqdc10"
|
||||||
|
|
||||||
|
[servers.beta]
|
||||||
|
ip = "10.0.0.2"
|
||||||
|
dc = "eqdc10"
|
||||||
|
country = "中国" # This should be parsed as UTF-8
|
||||||
|
|
||||||
|
[clients]
|
||||||
|
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
|
||||||
|
|
||||||
|
# Line breaks are OK when inside arrays
|
||||||
|
hosts = [
|
||||||
|
"alpha",
|
||||||
|
"omega"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Products
|
||||||
|
|
||||||
|
[[products]]
|
||||||
|
name = "Hammer"
|
||||||
|
sku = 738594937
|
||||||
|
|
||||||
|
[[products]]
|
||||||
|
name = "Nail"
|
||||||
|
sku = 284758393
|
||||||
|
color = "gray"
|
||||||
60
examples/config/modify/modify.go
Normal file
60
examples/config/modify/modify.go
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2/config"
|
||||||
|
"github.com/micro/go-micro/v2/config/encoder/toml"
|
||||||
|
"github.com/micro/go-micro/v2/config/source"
|
||||||
|
"github.com/micro/go-micro/v2/config/source/file"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// new toml encoder
|
||||||
|
t := toml.NewEncoder()
|
||||||
|
|
||||||
|
// create a new config
|
||||||
|
c, err := config.NewConfig(
|
||||||
|
config.WithSource(
|
||||||
|
// create a new file source
|
||||||
|
file.NewSource(
|
||||||
|
// path of file
|
||||||
|
file.WithPath("./example.conf"),
|
||||||
|
// specify the toml encoder
|
||||||
|
source.WithEncoder(t),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the config
|
||||||
|
if err := c.Load(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// set a value
|
||||||
|
c.Set("foo", "bar")
|
||||||
|
|
||||||
|
// now the hacks begin
|
||||||
|
vals := c.Map()
|
||||||
|
|
||||||
|
// encode
|
||||||
|
v, err := t.Encode(vals)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the file
|
||||||
|
if err := ioutil.WriteFile("./example.conf", v, 0644); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("wrote update to example.conf")
|
||||||
|
}
|
||||||
71
examples/event/README.md
Normal file
71
examples/event/README.md
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# Event
|
||||||
|
|
||||||
|
This is an example of using the micro API as an event gateway with the event handler
|
||||||
|
|
||||||
|
A http request is formatted as an [event](https://github.com/micro/go-api/blob/master/proto/api.proto#L28L39) and published on the go-micro message broker.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- srv - A service which subscribes to events
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the micro api with the event handler set and with a namespace which used as part of the topic name
|
||||||
|
|
||||||
|
```
|
||||||
|
micro api --handler=event --namespace=go.micro.evt
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the service
|
||||||
|
|
||||||
|
```
|
||||||
|
go run srv/main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
### Event format
|
||||||
|
|
||||||
|
On the receiving end the message will be formatted like so:
|
||||||
|
|
||||||
|
```
|
||||||
|
// A HTTP event as RPC
|
||||||
|
message Event {
|
||||||
|
// e.g login
|
||||||
|
string name = 1;
|
||||||
|
// uuid
|
||||||
|
string id = 2;
|
||||||
|
// unix timestamp of event
|
||||||
|
int64 timestamp = 3;
|
||||||
|
// event headers
|
||||||
|
map<string, Pair> header = 4;
|
||||||
|
// the event data
|
||||||
|
string data = 5;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Publish Event
|
||||||
|
|
||||||
|
Publishing an event is as simple as making a http post request
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -d '{"name": "john"}' http://localhost:8080/user/login
|
||||||
|
```
|
||||||
|
|
||||||
|
This request will be published to the topic `go.micro.evt.user` with event name `login`
|
||||||
|
|
||||||
|
### Receiving Event
|
||||||
|
|
||||||
|
A subscriber should be registered with the service for topic `go.micro.evt.user`
|
||||||
|
|
||||||
|
The subscriber should take the proto.Event type. See srv/main.go for the code.
|
||||||
|
|
||||||
|
The event received will look like the following
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
name: "user.login",
|
||||||
|
id: "go.micro.evt.user-user.login-693116e7-f20c-11e7-96c7-f40f242f6897",
|
||||||
|
timestamp:1515152077,
|
||||||
|
header: {...},
|
||||||
|
data: {"name": "john"}
|
||||||
|
}
|
||||||
|
```
|
||||||
33
examples/event/srv/main.go
Normal file
33
examples/event/srv/main.go
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
proto "github.com/micro/go-micro/v2/api/proto"
|
||||||
|
"github.com/micro/go-micro/v2/util/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// All methods of Event will be executed when a message is received
|
||||||
|
type Event struct{}
|
||||||
|
|
||||||
|
// Method can be of any name
|
||||||
|
func (e *Event) Process(ctx context.Context, event *proto.Event) error {
|
||||||
|
log.Logf("Received event %+v\n", event)
|
||||||
|
// do something with event
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("user"),
|
||||||
|
)
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
// register subscriber
|
||||||
|
micro.RegisterSubscriber("go.micro.evt.user", service.Server(), new(Event))
|
||||||
|
|
||||||
|
if err := service.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
28
examples/event/srv/proto/pubsub.micro.go
Normal file
28
examples/event/srv/proto/pubsub.micro.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/event/srv/proto/pubsub.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package pubsub is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/event/srv/proto/pubsub.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Event
|
||||||
|
*/
|
||||||
|
package pubsub
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
85
examples/event/srv/proto/pubsub.pb.go
Normal file
85
examples/event/srv/proto/pubsub.pb.go
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: github.com/micro/examples/event/srv/proto/pubsub.proto
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package pubsub is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
github.com/micro/examples/event/srv/proto/pubsub.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
Event
|
||||||
|
*/
|
||||||
|
package pubsub
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
|
||||||
|
|
||||||
|
// Example message
|
||||||
|
type Event struct {
|
||||||
|
// unique id
|
||||||
|
Id string `protobuf:"bytes,1,opt,name=id" json:"id,omitempty"`
|
||||||
|
// unix timestamp
|
||||||
|
Timestamp int64 `protobuf:"varint,2,opt,name=timestamp" json:"timestamp,omitempty"`
|
||||||
|
// message
|
||||||
|
Message string `protobuf:"bytes,3,opt,name=message" json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Event) Reset() { *m = Event{} }
|
||||||
|
func (m *Event) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Event) ProtoMessage() {}
|
||||||
|
func (*Event) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||||
|
|
||||||
|
func (m *Event) GetId() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Id
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Event) GetTimestamp() int64 {
|
||||||
|
if m != nil {
|
||||||
|
return m.Timestamp
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Event) GetMessage() string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Message
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterType((*Event)(nil), "Event")
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
proto.RegisterFile("github.com/micro/examples/event/srv/proto/pubsub.proto", fileDescriptor0)
|
||||||
|
}
|
||||||
|
|
||||||
|
var fileDescriptor0 = []byte{
|
||||||
|
// 143 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x4b, 0xcf, 0x2c, 0xc9,
|
||||||
|
0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0xcf, 0xcd, 0x4c, 0x2e, 0xca, 0xd7, 0x4f, 0xad, 0x48,
|
||||||
|
0xcc, 0x2d, 0xc8, 0x49, 0x2d, 0xd6, 0x4f, 0x2d, 0x4b, 0xcd, 0x2b, 0xd1, 0x2f, 0x2e, 0x2a, 0xd3,
|
||||||
|
0x2f, 0x28, 0xca, 0x2f, 0xc9, 0xd7, 0x2f, 0x28, 0x4d, 0x2a, 0x2e, 0x4d, 0xd2, 0x03, 0x73, 0x94,
|
||||||
|
0xfc, 0xb9, 0x58, 0x5d, 0x41, 0xf2, 0x42, 0x7c, 0x5c, 0x4c, 0x99, 0x29, 0x12, 0x8c, 0x0a, 0x8c,
|
||||||
|
0x1a, 0x9c, 0x41, 0x4c, 0x99, 0x29, 0x42, 0x32, 0x5c, 0x9c, 0x25, 0x99, 0xb9, 0xa9, 0xc5, 0x25,
|
||||||
|
0x89, 0xb9, 0x05, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xcc, 0x41, 0x08, 0x01, 0x21, 0x09, 0x2e, 0xf6,
|
||||||
|
0xdc, 0xd4, 0xe2, 0xe2, 0xc4, 0xf4, 0x54, 0x09, 0x66, 0xb0, 0x16, 0x18, 0x37, 0x89, 0x0d, 0x6c,
|
||||||
|
0xae, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x89, 0xbc, 0xdb, 0x74, 0x91, 0x00, 0x00, 0x00,
|
||||||
|
}
|
||||||
11
examples/event/srv/proto/pubsub.proto
Normal file
11
examples/event/srv/proto/pubsub.proto
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
// Example message
|
||||||
|
message Event {
|
||||||
|
// unique id
|
||||||
|
string id = 1;
|
||||||
|
// unix timestamp
|
||||||
|
int64 timestamp = 2;
|
||||||
|
// message
|
||||||
|
string message = 3;
|
||||||
|
}
|
||||||
15
examples/filter/README.md
Normal file
15
examples/filter/README.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Filter
|
||||||
|
|
||||||
|
Filter demonstrates how to filter requests in the client
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
// Run the service example
|
||||||
|
go run ../service/main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
// Run the client
|
||||||
|
go run main.go
|
||||||
|
```
|
||||||
32
examples/filter/main.go
Normal file
32
examples/filter/main.go
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/micro/examples/filter/version"
|
||||||
|
proto "github.com/micro/examples/service/proto"
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService()
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
greeter := proto.NewGreeterService("greeter", service.Client())
|
||||||
|
|
||||||
|
rsp, err := greeter.Hello(
|
||||||
|
// provide a context
|
||||||
|
context.TODO(),
|
||||||
|
// provide the request
|
||||||
|
&proto.Request{Name: "John"},
|
||||||
|
// set the filter
|
||||||
|
version.Filter("latest"),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(rsp.Greeting)
|
||||||
|
}
|
||||||
25
examples/filter/version/version.go
Normal file
25
examples/filter/version/version.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Package version provides a way of calling a version of a service
|
||||||
|
package version
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/micro/go-micro/v2/client"
|
||||||
|
"github.com/micro/go-micro/v2/client/selector"
|
||||||
|
"github.com/micro/go-micro/v2/registry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Filter will filter the version of the service
|
||||||
|
func Filter(v string) client.CallOption {
|
||||||
|
filter := func(services []*registry.Service) []*registry.Service {
|
||||||
|
var filtered []*registry.Service
|
||||||
|
|
||||||
|
for _, service := range services {
|
||||||
|
if service.Version == v {
|
||||||
|
filtered = append(filtered, service)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filtered
|
||||||
|
}
|
||||||
|
|
||||||
|
return client.WithSelectOption(selector.WithFilter(filter))
|
||||||
|
}
|
||||||
11
examples/flags/README.md
Normal file
11
examples/flags/README.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Flags
|
||||||
|
|
||||||
|
This is an example of using command line flags
|
||||||
|
|
||||||
|
## Run the example
|
||||||
|
|
||||||
|
```shell
|
||||||
|
go run main.go --string_flag="a string" --int_flag=10 --bool_flag=true
|
||||||
|
```
|
||||||
|
|
||||||
|
And that's all there is to it.
|
||||||
51
examples/flags/main.go
Normal file
51
examples/flags/main.go
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/micro/cli/v2"
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
// Add runtime flags
|
||||||
|
// We could do this below too
|
||||||
|
micro.Flags(
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "string_flag",
|
||||||
|
Usage: "This is a string flag",
|
||||||
|
},
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "int_flag",
|
||||||
|
Usage: "This is an int flag",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "bool_flag",
|
||||||
|
Usage: "This is a bool flag",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Init will parse the command line flags. Any flags set will
|
||||||
|
// override the above settings. Options defined here will
|
||||||
|
// override anything set on the command line.
|
||||||
|
service.Init(
|
||||||
|
// Add runtime action
|
||||||
|
// We could actually do this above
|
||||||
|
micro.Action(func(c *cli.Context) error {
|
||||||
|
fmt.Printf("The string flag is: %s\n", c.String("string_flag"))
|
||||||
|
fmt.Printf("The int flag is: %d\n", c.Int("int_flag"))
|
||||||
|
fmt.Printf("The bool flag is: %t\n", c.Bool("bool_flag"))
|
||||||
|
// let's just exit because
|
||||||
|
os.Exit(0)
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Run the server
|
||||||
|
if err := service.Run(); err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
36
examples/form/README.md
Normal file
36
examples/form/README.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# Form
|
||||||
|
|
||||||
|
This rudimentary example demonstrates how to access a form and multipart form when writing API services
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- web - is the web front end with the form
|
||||||
|
- api - is the api service
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the micro api
|
||||||
|
|
||||||
|
```
|
||||||
|
micro api --handler=api
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the micro web
|
||||||
|
|
||||||
|
```
|
||||||
|
micro web
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the api service
|
||||||
|
|
||||||
|
```
|
||||||
|
go run api/main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the web service
|
||||||
|
|
||||||
|
```
|
||||||
|
go run web/main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
Browse to localhost:8082/form
|
||||||
54
examples/form/api/main.go
Normal file
54
examples/form/api/main.go
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"mime"
|
||||||
|
"mime/multipart"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
proto "github.com/micro/examples/form/api/proto"
|
||||||
|
"github.com/micro/go-micro/v2"
|
||||||
|
api "github.com/micro/go-micro/v2/api/proto"
|
||||||
|
"github.com/micro/go-micro/v2/util/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Form struct{}
|
||||||
|
|
||||||
|
func (f *Form) Submit(ctx context.Context, req *api.Request, rsp *api.Response) error {
|
||||||
|
rsp.Body = fmt.Sprintf("got your values %+v", req.Post)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Form) Multipart(ctx context.Context, req *api.Request, rsp *api.Response) error {
|
||||||
|
ct := strings.Join(req.Header["Content-Type"].Values, ",")
|
||||||
|
mt, p, err := mime.ParseMediaType(ct)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(mt, "multipart/") {
|
||||||
|
return fmt.Errorf("%v does not contain multipart", mt)
|
||||||
|
}
|
||||||
|
r := multipart.NewReader(bytes.NewReader([]byte(req.Body)), p["boundary"])
|
||||||
|
form, err := r.ReadForm(32 << 20)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rsp.Body = fmt.Sprintf("got your values %+v", form)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
service := micro.NewService(
|
||||||
|
micro.Name("go.micro.api.form"),
|
||||||
|
)
|
||||||
|
|
||||||
|
service.Init()
|
||||||
|
|
||||||
|
proto.RegisterFormHandler(service.Server(), new(Form))
|
||||||
|
|
||||||
|
if err := service.Run(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
113
examples/form/api/proto/api.micro.go
Normal file
113
examples/form/api/proto/api.micro.go
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||||
|
// source: proto/api.proto
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
fmt "fmt"
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
|
proto1 "github.com/micro/go-micro/v2/api/proto"
|
||||||
|
math "math"
|
||||||
|
)
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
client "github.com/micro/go-micro/v2/client"
|
||||||
|
server "github.com/micro/go-micro/v2/server"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ context.Context
|
||||||
|
var _ client.Option
|
||||||
|
var _ server.Option
|
||||||
|
|
||||||
|
// Client API for Form service
|
||||||
|
|
||||||
|
type FormService interface {
|
||||||
|
// regular form
|
||||||
|
Submit(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.Response, error)
|
||||||
|
// multipart form
|
||||||
|
Multipart(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type formService struct {
|
||||||
|
c client.Client
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewFormService(name string, c client.Client) FormService {
|
||||||
|
if c == nil {
|
||||||
|
c = client.NewClient()
|
||||||
|
}
|
||||||
|
if len(name) == 0 {
|
||||||
|
name = "form"
|
||||||
|
}
|
||||||
|
return &formService{
|
||||||
|
c: c,
|
||||||
|
name: name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *formService) Submit(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.Response, error) {
|
||||||
|
req := c.c.NewRequest(c.name, "Form.Submit", in)
|
||||||
|
out := new(proto1.Response)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *formService) Multipart(ctx context.Context, in *proto1.Request, opts ...client.CallOption) (*proto1.Response, error) {
|
||||||
|
req := c.c.NewRequest(c.name, "Form.Multipart", in)
|
||||||
|
out := new(proto1.Response)
|
||||||
|
err := c.c.Call(ctx, req, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Server API for Form service
|
||||||
|
|
||||||
|
type FormHandler interface {
|
||||||
|
// regular form
|
||||||
|
Submit(context.Context, *proto1.Request, *proto1.Response) error
|
||||||
|
// multipart form
|
||||||
|
Multipart(context.Context, *proto1.Request, *proto1.Response) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterFormHandler(s server.Server, hdlr FormHandler, opts ...server.HandlerOption) error {
|
||||||
|
type form interface {
|
||||||
|
Submit(ctx context.Context, in *proto1.Request, out *proto1.Response) error
|
||||||
|
Multipart(ctx context.Context, in *proto1.Request, out *proto1.Response) error
|
||||||
|
}
|
||||||
|
type Form struct {
|
||||||
|
form
|
||||||
|
}
|
||||||
|
h := &formHandler{hdlr}
|
||||||
|
return s.Handle(s.NewHandler(&Form{h}, opts...))
|
||||||
|
}
|
||||||
|
|
||||||
|
type formHandler struct {
|
||||||
|
FormHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *formHandler) Submit(ctx context.Context, in *proto1.Request, out *proto1.Response) error {
|
||||||
|
return h.FormHandler.Submit(ctx, in, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *formHandler) Multipart(ctx context.Context, in *proto1.Request, out *proto1.Response) error {
|
||||||
|
return h.FormHandler.Multipart(ctx, in, out)
|
||||||
|
}
|
||||||
37
examples/form/api/proto/api.pb.go
Normal file
37
examples/form/api/proto/api.pb.go
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// source: proto/api.proto
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
fmt "fmt"
|
||||||
|
proto "github.com/golang/protobuf/proto"
|
||||||
|
_ "github.com/micro/go-micro/v2/api/proto"
|
||||||
|
math "math"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the proto package it is being compiled against.
|
||||||
|
// A compilation error at this line likely means your copy of the
|
||||||
|
// proto package needs to be updated.
|
||||||
|
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||||
|
|
||||||
|
func init() { proto.RegisterFile("proto/api.proto", fileDescriptor_ecf0878b123623e2) }
|
||||||
|
|
||||||
|
var fileDescriptor_ecf0878b123623e2 = []byte{
|
||||||
|
// 132 bytes of a gzipped FileDescriptorProto
|
||||||
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x2f, 0x28, 0xca, 0x2f,
|
||||||
|
0xc9, 0xd7, 0x4f, 0x2c, 0xc8, 0xd4, 0x03, 0xb3, 0xa4, 0x74, 0xd3, 0x33, 0x4b, 0x32, 0x4a, 0x93,
|
||||||
|
0xf4, 0x92, 0xf3, 0x73, 0xf5, 0x73, 0x33, 0x93, 0x8b, 0xf2, 0xf5, 0xd3, 0xf3, 0x75, 0x21, 0x8c,
|
||||||
|
0xc4, 0x82, 0x4c, 0x7d, 0x34, 0xe5, 0x46, 0xe9, 0x5c, 0x2c, 0x6e, 0xf9, 0x45, 0xb9, 0x42, 0xba,
|
||||||
|
0x5c, 0x6c, 0xc1, 0xa5, 0x49, 0xb9, 0x99, 0x25, 0x42, 0xfc, 0x7a, 0xe9, 0xf9, 0x7a, 0x20, 0x05,
|
||||||
|
0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x52, 0x02, 0x08, 0x81, 0xe2, 0x82, 0xfc, 0xbc, 0xe2,
|
||||||
|
0x54, 0x25, 0x06, 0x21, 0x03, 0x2e, 0x4e, 0xdf, 0xd2, 0x9c, 0x92, 0xcc, 0x82, 0xc4, 0x22, 0xe2,
|
||||||
|
0x74, 0x24, 0xb1, 0x81, 0xed, 0x33, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x7e, 0x4f, 0x39, 0x8c,
|
||||||
|
0xb1, 0x00, 0x00, 0x00,
|
||||||
|
}
|
||||||
10
examples/form/api/proto/api.proto
Normal file
10
examples/form/api/proto/api.proto
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
import "github.com/micro/go-micro/v2/api/proto/api.proto";
|
||||||
|
|
||||||
|
service Form {
|
||||||
|
// regular form
|
||||||
|
rpc Submit(go.api.Request) returns (go.api.Response) {};
|
||||||
|
// multipart form
|
||||||
|
rpc Multipart(go.api.Request) returns (go.api.Response) {};
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user