1
0
mirror of https://github.com/go-micro/go-micro.git synced 2024-11-24 08:02:32 +02:00

Add examples

This commit is contained in:
Asim Aslam 2020-12-26 15:17:20 +00:00
parent 273bab5dd7
commit a34c70de0e
320 changed files with 20803 additions and 0 deletions

View File

@ -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.
## Examples
See [examples](https://github.com/micro/go-micro/tree/master/examples) directory for usage examples.
## License
Go Micro is Apache 2.0 licensed.

51
examples/.github/workflows/tests.yml vendored Normal file
View 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
View 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
View 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
View File

@ -0,0 +1 @@
theme: jekyll-theme-architect

57
examples/api/README.md Normal file
View 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

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

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

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

View 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) {};
}

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

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

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

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

View 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
```

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

View 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
```

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

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

View 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
View 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
View 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
View 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"
}
}
]
}
```

View File

@ -0,0 +1,4 @@
FROM alpine:3.2
ADD . /app
WORKDIR /app
ENTRYPOINT [ "/app/hotel" ]

View 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()
}

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

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

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

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

View File

@ -0,0 +1,6 @@
[
{
"id": 1,
"authToken": "VALID_TOKEN"
}
]

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

View 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"
}
}
]

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

View 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

View File

@ -0,0 +1,4 @@
FROM alpine:3.2
ADD . /app
WORKDIR /app
ENTRYPOINT [ "/app/auth" ]

View 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()
}

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

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

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

View File

@ -0,0 +1,4 @@
FROM alpine:3.2
ADD . /app
WORKDIR /app
ENTRYPOINT [ "/app/geo" ]

View 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()
}

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

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

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

View File

@ -0,0 +1,4 @@
FROM alpine:3.2
ADD . /app
WORKDIR /app
ENTRYPOINT [ "/app/profile" ]

View 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()
}

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

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

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

View File

@ -0,0 +1,4 @@
FROM alpine:3.2
ADD . /app
WORKDIR /app
ENTRYPOINT [ "/app/rate" ]

View 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()
}

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

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

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

View 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

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

View 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
View 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)

View 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)
}
}
```

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

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

View 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
View 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())
}

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

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

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

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

View File

@ -0,0 +1,4 @@
# Go Config
This example demonstrates how to use Go Config for dynamic configuration.

View File

@ -0,0 +1,12 @@
{
"hosts": {
"database": {
"address": "10.0.0.1",
"port": 3306
},
"cache": {
"address": "10.0.0.2",
"port": 6379
}
}
}

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

View 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"}
```

View 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()))
}
}

View File

@ -0,0 +1,4 @@
other:
name: Extra
version: 1.0.0
message: Ugh this sucks

View File

@ -0,0 +1,4 @@
micro:
name: Micro
version: 1.0.0
message: hello

View File

@ -0,0 +1,4 @@
other:
name: badBoy
version: 1.0.0
hi: Ah

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

View 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
```

View 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"

View 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
View 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"}
}
```

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

View 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

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

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

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

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

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

View 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