Make command internal

This commit is contained in:
Asim 2016-01-02 00:38:57 +00:00
parent 59a667130c
commit 1f1bc27421
8 changed files with 329 additions and 131 deletions

159
README.md
View File

@ -27,7 +27,7 @@ By default go-micro only provides a single implementation of each interface. Plu
## Prerequisites ## Prerequisites
Consul is the default discovery mechanism provided in go-micro. Discovery is however pluggable. Consul is the default discovery mechanism provided in go-micro. Discovery is however pluggable so you can used etcd, kubernetes, zookeeper, etc.
### Install Consul ### Install Consul
[https://www.consul.io/intro/getting-started/install.html](https://www.consul.io/intro/getting-started/install.html) [https://www.consul.io/intro/getting-started/install.html](https://www.consul.io/intro/getting-started/install.html)
@ -41,104 +41,141 @@ $ consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul
### Run Service ### Run Service
``` ```
$ go run examples/server/main.go --logtostderr $ go run examples/service/main.go --logtostderr
I1108 11:08:19.926071 11358 server.go:96] Starting server go.micro.srv.example id go.micro.srv.example-04de4cf0-8609-11e5-bf3a-68a86d0d36b6 I0102 00:22:26.413467 12018 rpc_server.go:297] Listening on [::]:62492
I1108 11:08:19.926407 11358 rpc_server.go:233] Listening on [::]:54080 I0102 00:22:26.413803 12018 http_broker.go:115] Broker Listening on [::]:62493
I1108 11:08:19.926500 11358 http_broker.go:80] Broker Listening on [::]:54081 I0102 00:22:26.414009 12018 rpc_server.go:212] Registering node: greeter-e6b2fc6f-b0e6-11e5-a42f-68a86d0d36b6
I1108 11:08:19.926632 11358 rpc_server.go:158] Registering node: go.micro.srv.example-04de4cf0-8609-11e5-bf3a-68a86d0d36b6
``` ```
### Test Service ### Test Service
``` ```
$ go run examples/client/main.go $ go run examples/service/main.go --client
go.micro.srv.example-59b6e0ab-0300-11e5-b696-68a86d0d36b6: Hello John Hello John
``` ```
## Writing a service ## Writing a service
### Create request/response proto ### Create request/response proto
`go-micro/examples/server/proto/example/example.proto`: `go-micro/examples/service/proto/greeter.proto`:
``` ```
syntax = "proto3"; syntax = "proto3";
message Request { service Greeter {
rpc Hello(HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string name = 1; string name = 1;
} }
message Response { message HelloResponse {
string msg = 1; string greeting = 2;
} }
``` ```
Compile proto `protoc -I$GOPATH/src --go_out=$GOPATH/src $GOPATH/src/github.com/micro/go-micro/examples/server/proto/example/example.proto` ### Install protobuf for code generation
### Create request handler We use a protobuf plugin for code generation. This is completely optional. Look at [examples/server](https://github.com/micro/go-micro/blob/master/examples/server/main.go)
`go-micro/examples/server/handler/example.go`: and [examples/client](https://github.com/micro/go-micro/blob/master/examples/client/main.go) for examples without code generation.
```go ```shell
package handler go get github.com/micro/protobuf
import (
log "github.com/golang/glog"
c "github.com/micro/go-micro/context"
example "github.com/micro/go-micro/examples/server/proto/example"
"github.com/micro/go-micro/server"
"golang.org/x/net/context"
)
type Example struct{}
func (e *Example) Call(ctx context.Context, req *example.Request, rsp *example.Response) error {
md, _ := c.GetMetadata(ctx)
log.Infof("Received Example.Call request with metadata: %v", md)
rsp.Msg = server.Options().Id + ": Hello " + req.Name
return nil
}
``` ```
### Init server Compile proto `protoc -I$GOPATH/src --go_out=plugins=micro:$GOPATH/src $GOPATH/src/github.com/micro/go-micro/examples/service/proto/greeter.proto`
`go-micro/examples/server/main.go`:
### Define the service
`go-micro/examples/service/main.go`:
```go ```go
package main package main
import ( import (
log "github.com/golang/glog" "fmt"
"github.com/micro/go-micro/cmd"
"github.com/micro/go-micro/examples/server/handler" micro "github.com/micro/go-micro"
"github.com/micro/go-micro/server" proto "github.com/micro/go-micro/examples/service/proto"
"golang.org/x/net/context"
) )
type Greeter struct{}
func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
rsp.Greeting = "Hello " + req.Name
return nil
}
func main() { func main() {
// optionally setup command line usage // Create a new service. Optionally include some options here.
cmd.Init() service := micro.NewService(
micro.Name("greeter"),
// Initialise Server micro.Version("latest"),
server.Init( micro.Metadata(map[string]string{
server.Name("go.micro.srv.example"), "type": "helloworld",
}),
) )
// Register Handlers // Init will parse the command line flags. Any flags set will
server.Handle( // override the above settings. Options defined here will
server.NewHandler( // override anything set on the command line.
new(handler.Example), service.Init()
),
)
// Run server // Register handler
if err := server.Run(); err != nil { proto.RegisterGreeterHandler(service.Server(), new(Greeter))
log.Fatal(err)
// Run the server
if err := service.Run(); err != nil {
fmt.Println(err)
} }
} }
``` ```
### Run service ### Run service
``` ```
$ go run examples/server/main.go --logtostderr go run examples/service/main.go --logtostderr
I1108 11:08:19.926071 11358 server.go:96] Starting server go.micro.srv.example id go.micro.srv.example-04de4cf0-8609-11e5-bf3a-68a86d0d36b6 I0102 00:22:26.413467 12018 rpc_server.go:297] Listening on [::]:62492
I1108 11:08:19.926407 11358 rpc_server.go:233] Listening on [::]:54080 I0102 00:22:26.413803 12018 http_broker.go:115] Broker Listening on [::]:62493
I1108 11:08:19.926500 11358 http_broker.go:80] Broker Listening on [::]:54081 I0102 00:22:26.414009 12018 rpc_server.go:212] Registering node: greeter-e6b2fc6f-b0e6-11e5-a42f-68a86d0d36b6
I1108 11:08:19.926632 11358 rpc_server.go:158] Registering node: go.micro.srv.example-04de4cf0-8609-11e5-bf3a-68a86d0d36b6 ```
### Define a client
`client.go`
```go
package main
import (
"fmt"
micro "github.com/micro/go-micro"
proto "github.com/micro/go-micro/examples/service/proto"
"golang.org/x/net/context"
)
func main() {
// Create a new service. Optionally include some options here.
service := micro.NewService(micro.Name("greeter.client"))
// Create new greeter client
greeter := proto.NewGreeterClient("greeter", service.Client())
// Call the greeter
rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{Name: "John"})
if err != nil {
fmt.Println(err)
}
// Print response
fmt.Println(rsp.Greeting)
}
```
### Run the client
```shell
go run client.go
Hello John
``` ```

View File

@ -57,7 +57,6 @@ var (
cli.StringFlag{ cli.StringFlag{
Name: "server_address", Name: "server_address",
EnvVar: "MICRO_SERVER_ADDRESS", EnvVar: "MICRO_SERVER_ADDRESS",
Value: ":0",
Usage: "Bind address for the server. 127.0.0.1:8080", Usage: "Bind address for the server. 127.0.0.1:8080",
}, },
cli.StringFlag{ cli.StringFlag{
@ -74,7 +73,6 @@ var (
cli.StringFlag{ cli.StringFlag{
Name: "broker", Name: "broker",
EnvVar: "MICRO_BROKER", EnvVar: "MICRO_BROKER",
Value: "http",
Usage: "Broker for pub/sub. http, nats, rabbitmq", Usage: "Broker for pub/sub. http, nats, rabbitmq",
}, },
cli.StringFlag{ cli.StringFlag{
@ -85,7 +83,6 @@ var (
cli.StringFlag{ cli.StringFlag{
Name: "registry", Name: "registry",
EnvVar: "MICRO_REGISTRY", EnvVar: "MICRO_REGISTRY",
Value: "consul",
Usage: "Registry for discovery. memory, consul, etcd, kubernetes", Usage: "Registry for discovery. memory, consul, etcd, kubernetes",
}, },
cli.StringFlag{ cli.StringFlag{
@ -96,13 +93,11 @@ var (
cli.StringFlag{ cli.StringFlag{
Name: "selector", Name: "selector",
EnvVar: "MICRO_SELECTOR", EnvVar: "MICRO_SELECTOR",
Value: "selector",
Usage: "Selector used to pick nodes for querying. random, roundrobin, blacklist", Usage: "Selector used to pick nodes for querying. random, roundrobin, blacklist",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "transport", Name: "transport",
EnvVar: "MICRO_TRANSPORT", EnvVar: "MICRO_TRANSPORT",
Value: "http",
Usage: "Transport mechanism used; http, rabbitmq, nats", Usage: "Transport mechanism used; http, rabbitmq, nats",
}, },
cli.StringFlag{ cli.StringFlag{
@ -170,6 +165,13 @@ func init() {
func newCmd(opts ...Option) Cmd { func newCmd(opts ...Option) Cmd {
options := Options{ options := Options{
Broker: &broker.DefaultBroker,
Client: &client.DefaultClient,
Registry: &registry.DefaultRegistry,
Server: &server.DefaultServer,
Selector: &selector.DefaultSelector,
Transport: &transport.DefaultTransport,
Brokers: DefaultBrokers, Brokers: DefaultBrokers,
Registries: DefaultRegistries, Registries: DefaultRegistries,
Selectors: DefaultSelectors, Selectors: DefaultSelectors,
@ -221,22 +223,63 @@ func (c *cmd) Before(ctx *cli.Context) error {
flag.Set("v", ctx.String("v")) flag.Set("v", ctx.String("v"))
flag.Parse() flag.Parse()
// If flags are set then use them otherwise do nothing
var serverOpts []server.Option
var clientOpts []client.Option
// Set the broker
if len(ctx.String("broker")) > 0 {
if b, ok := c.opts.Brokers[ctx.String("broker")]; ok { if b, ok := c.opts.Brokers[ctx.String("broker")]; ok {
broker.DefaultBroker = b(strings.Split(ctx.String("broker_address"), ",")) n := b(strings.Split(ctx.String("broker_address"), ","))
c.opts.Broker = &n
} else {
return fmt.Errorf("Broker %s not found", ctx.String("broker"))
} }
serverOpts = append(serverOpts, server.Broker(*c.opts.Broker))
clientOpts = append(clientOpts, client.Broker(*c.opts.Broker))
}
// Set the registry
if len(ctx.String("registry")) > 0 {
if r, ok := c.opts.Registries[ctx.String("registry")]; ok { if r, ok := c.opts.Registries[ctx.String("registry")]; ok {
registry.DefaultRegistry = r(strings.Split(ctx.String("registry_address"), ",")) n := r(strings.Split(ctx.String("registry_address"), ","))
c.opts.Registry = &n
} else {
return fmt.Errorf("Registry %s not found", ctx.String("registry"))
} }
serverOpts = append(serverOpts, server.Registry(*c.opts.Registry))
clientOpts = append(clientOpts, client.Registry(*c.opts.Registry))
}
// Set the selector
if len(ctx.String("selector")) > 0 {
if s, ok := c.opts.Selectors[ctx.String("selector")]; ok { if s, ok := c.opts.Selectors[ctx.String("selector")]; ok {
selector.DefaultSelector = s(selector.Registry(registry.DefaultRegistry)) n := s(selector.Registry(*c.opts.Registry))
c.opts.Selector = &n
} else {
return fmt.Errorf("Selector %s not found", ctx.String("selector"))
} }
// No server option here. Should there be?
clientOpts = append(clientOpts, client.Selector(*c.opts.Selector))
}
// Set the transport
if len(ctx.String("transport")) > 0 {
if t, ok := c.opts.Transports[ctx.String("transport")]; ok { if t, ok := c.opts.Transports[ctx.String("transport")]; ok {
transport.DefaultTransport = t(strings.Split(ctx.String("transport_address"), ",")) n := t(strings.Split(ctx.String("transport_address"), ","))
c.opts.Transport = &n
} else {
return fmt.Errorf("Transport %s not found", ctx.String("transport"))
} }
serverOpts = append(serverOpts, server.Transport(*c.opts.Transport))
clientOpts = append(clientOpts, client.Transport(*c.opts.Transport))
}
// Parse the server options
metadata := make(map[string]string) metadata := make(map[string]string)
for _, d := range ctx.StringSlice("server_metadata") { for _, d := range ctx.StringSlice("server_metadata") {
var key, val string var key, val string
@ -248,16 +291,40 @@ func (c *cmd) Before(ctx *cli.Context) error {
metadata[key] = val metadata[key] = val
} }
server.DefaultServer = server.NewServer( if len(metadata) > 0 {
server.Name(ctx.String("server_name")), serverOpts = append(serverOpts, server.Metadata(metadata))
server.Version(ctx.String("server_version")), }
server.Id(ctx.String("server_id")),
server.Address(ctx.String("server_address")),
server.Advertise(ctx.String("server_advertise")),
server.Metadata(metadata),
)
client.DefaultClient = client.NewClient() if len(ctx.String("server_name")) > 0 {
serverOpts = append(serverOpts, server.Name(ctx.String("server_name")))
}
if len(ctx.String("server_version")) > 0 {
serverOpts = append(serverOpts, server.Version(ctx.String("server_version")))
}
if len(ctx.String("server_id")) > 0 {
serverOpts = append(serverOpts, server.Id(ctx.String("server_id")))
}
if len(ctx.String("server_address")) > 0 {
serverOpts = append(serverOpts, server.Address(ctx.String("server_address")))
}
if len(ctx.String("server_advertise")) > 0 {
serverOpts = append(serverOpts, server.Advertise(ctx.String("server_advertise")))
}
// We have some command line opts for the server.
// Lets set it up
if len(serverOpts) > 0 {
(*c.opts.Server).Init(serverOpts...)
}
// Use an init option?
if len(clientOpts) > 0 {
*c.opts.Client = client.NewClient(clientOpts...)
}
return nil return nil
} }

View File

@ -2,59 +2,113 @@ package cmd
import ( import (
"github.com/micro/go-micro/broker" "github.com/micro/go-micro/broker"
"github.com/micro/go-micro/client"
"github.com/micro/go-micro/registry" "github.com/micro/go-micro/registry"
"github.com/micro/go-micro/selector" "github.com/micro/go-micro/selector"
"github.com/micro/go-micro/server"
"github.com/micro/go-micro/transport" "github.com/micro/go-micro/transport"
) )
type Options struct { type Options struct {
// For the Command Line itself
Name string Name string
Description string Description string
Version string Version string
// We need pointers to things so we can swap them out if needed.
Broker *broker.Broker
Registry *registry.Registry
Selector *selector.Selector
Transport *transport.Transport
Client *client.Client
Server *server.Server
Brokers map[string]func([]string, ...broker.Option) broker.Broker Brokers map[string]func([]string, ...broker.Option) broker.Broker
Registries map[string]func([]string, ...registry.Option) registry.Registry Registries map[string]func([]string, ...registry.Option) registry.Registry
Selectors map[string]func(...selector.Option) selector.Selector Selectors map[string]func(...selector.Option) selector.Selector
Transports map[string]func([]string, ...transport.Option) transport.Transport Transports map[string]func([]string, ...transport.Option) transport.Transport
} }
// Command line Name
func Name(n string) Option { func Name(n string) Option {
return func(o *Options) { return func(o *Options) {
o.Name = n o.Name = n
} }
} }
// Command line Description
func Description(d string) Option { func Description(d string) Option {
return func(o *Options) { return func(o *Options) {
o.Description = d o.Description = d
} }
} }
// Command line Version
func Version(v string) Option { func Version(v string) Option {
return func(o *Options) { return func(o *Options) {
o.Version = v o.Version = v
} }
} }
func Broker(name string, b func([]string, ...broker.Option) broker.Broker) Option { func Broker(b *broker.Broker) Option {
return func(o *Options) {
o.Broker = b
}
}
func Selector(s *selector.Selector) Option {
return func(o *Options) {
o.Selector = s
}
}
func Registry(r *registry.Registry) Option {
return func(o *Options) {
o.Registry = r
}
}
func Transport(t *transport.Transport) Option {
return func(o *Options) {
o.Transport = t
}
}
func Client(c *client.Client) Option {
return func(o *Options) {
o.Client = c
}
}
func Server(s *server.Server) Option {
return func(o *Options) {
o.Server = s
}
}
// New broker func
func NewBroker(name string, b func([]string, ...broker.Option) broker.Broker) Option {
return func(o *Options) { return func(o *Options) {
o.Brokers[name] = b o.Brokers[name] = b
} }
} }
func Registry(name string, r func([]string, ...registry.Option) registry.Registry) Option { // New registry func
func NewRegistry(name string, r func([]string, ...registry.Option) registry.Registry) Option {
return func(o *Options) { return func(o *Options) {
o.Registries[name] = r o.Registries[name] = r
} }
} }
func Selector(name string, s func(...selector.Option) selector.Selector) Option { // New selector func
func NewSelector(name string, s func(...selector.Option) selector.Selector) Option {
return func(o *Options) { return func(o *Options) {
o.Selectors[name] = s o.Selectors[name] = s
} }
} }
func Transport(name string, t func([]string, ...transport.Option) transport.Transport) Option { // New transport func
func NewTransport(name string, t func([]string, ...transport.Option) transport.Transport) Option {
return func(o *Options) { return func(o *Options) {
o.Transports[name] = t o.Transports[name] = t
} }

View File

@ -6,40 +6,12 @@ import (
"github.com/micro/go-micro/examples/server/handler" "github.com/micro/go-micro/examples/server/handler"
"github.com/micro/go-micro/examples/server/subscriber" "github.com/micro/go-micro/examples/server/subscriber"
"github.com/micro/go-micro/server" "github.com/micro/go-micro/server"
"golang.org/x/net/context"
) )
func logWrapper(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
log.Infof("[Log Wrapper] Before serving request method: %v", req.Method())
err := fn(ctx, req, rsp)
log.Infof("[Log Wrapper] After serving request")
return err
}
}
func logSubWrapper(fn server.SubscriberFunc) server.SubscriberFunc {
return func(ctx context.Context, req server.Publication) error {
log.Infof("[Log Sub Wrapper] Before serving publication topic: %v", req.Topic())
err := fn(ctx, req)
log.Infof("[Log Sub Wrapper] After serving publication")
return err
}
}
func main() { func main() {
// optionally setup command line usage // optionally setup command line usage
cmd.Init() cmd.Init()
md := server.DefaultOptions().Metadata
md["datacenter"] = "local"
server.DefaultServer = server.NewServer(
server.WrapHandler(logWrapper),
server.WrapSubscriber(logSubWrapper),
server.Metadata(md),
)
// Initialise Server // Initialise Server
server.Init( server.Init(
server.Name("go.micro.srv.example"), server.Name("go.micro.srv.example"),

View File

@ -0,0 +1,78 @@
package main
import (
log "github.com/golang/glog"
"github.com/micro/go-micro/cmd"
"github.com/micro/go-micro/examples/server/handler"
"github.com/micro/go-micro/examples/server/subscriber"
"github.com/micro/go-micro/server"
"golang.org/x/net/context"
)
func logWrapper(fn server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
log.Infof("[Log Wrapper] Before serving request method: %v", req.Method())
err := fn(ctx, req, rsp)
log.Infof("[Log Wrapper] After serving request")
return err
}
}
func logSubWrapper(fn server.SubscriberFunc) server.SubscriberFunc {
return func(ctx context.Context, req server.Publication) error {
log.Infof("[Log Sub Wrapper] Before serving publication topic: %v", req.Topic())
err := fn(ctx, req)
log.Infof("[Log Sub Wrapper] After serving publication")
return err
}
}
func main() {
// optionally setup command line usage
cmd.Init()
md := server.DefaultOptions().Metadata
md["datacenter"] = "local"
server.DefaultServer = server.NewServer(
server.WrapHandler(logWrapper),
server.WrapSubscriber(logSubWrapper),
server.Metadata(md),
)
// Initialise Server
server.Init(
server.Name("go.micro.srv.example"),
)
// Register Handlers
server.Handle(
server.NewHandler(
new(handler.Example),
),
)
// Register Subscribers
if err := server.Subscribe(
server.NewSubscriber(
"topic.go.micro.srv.example",
new(subscriber.Example),
),
); err != nil {
log.Fatal(err)
}
if err := server.Subscribe(
server.NewSubscriber(
"topic.go.micro.srv.example",
subscriber.Handler,
),
); err != nil {
log.Fatal(err)
}
// Run server
if err := server.Run(); err != nil {
log.Fatal(err)
}
}

View File

@ -28,6 +28,7 @@ type Options struct {
func newOptions(opts ...Option) Options { func newOptions(opts ...Option) Options {
opt := Options{ opt := Options{
Broker: broker.DefaultBroker, Broker: broker.DefaultBroker,
Cmd: cmd.DefaultCmd,
Client: client.DefaultClient, Client: client.DefaultClient,
Server: server.DefaultServer, Server: server.DefaultServer,
Registry: registry.DefaultRegistry, Registry: registry.DefaultRegistry,
@ -39,14 +40,6 @@ func newOptions(opts ...Option) Options {
o(&opt) o(&opt)
} }
// New Command
if opt.Cmd == nil {
opt.Cmd = cmd.NewCmd(
cmd.Name(opt.Server.Options().Name),
cmd.Version(opt.Server.Options().Version),
)
}
return opt return opt
} }

View File

@ -110,9 +110,6 @@ func (s *rpcServer) Init(opts ...Option) {
for _, opt := range opts { for _, opt := range opts {
opt(&s.opts) opt(&s.opts)
} }
if len(s.opts.Id) == 0 {
s.opts.Id = s.opts.Name + "-" + DefaultId
}
s.Unlock() s.Unlock()
} }
@ -187,7 +184,7 @@ func (s *rpcServer) Register() error {
// register service // register service
node := &registry.Node{ node := &registry.Node{
Id: config.Id, Id: config.Name + "-" + config.Id,
Address: addr, Address: addr,
Port: port, Port: port,
Metadata: config.Metadata, Metadata: config.Metadata,
@ -260,7 +257,7 @@ func (s *rpcServer) Deregister() error {
} }
node := &registry.Node{ node := &registry.Node{
Id: config.Id, Id: config.Name + "-" + config.Id,
Address: addr, Address: addr,
Port: port, Port: port,
} }

View File

@ -31,13 +31,13 @@ func newService(opts ...Option) Service {
} }
func (s *service) Init(opts ...Option) { func (s *service) Init(opts ...Option) {
// Initialise the command flags, overriding new service
s.opts.Cmd.Init() s.opts.Cmd.Init()
// Update any options to override command flags
for _, o := range opts { for _, o := range opts {
o(&s.opts) o(&s.opts)
} }
s = newService(opts...).(*service)
} }
func (s *service) Cmd() cmd.Cmd { func (s *service) Cmd() cmd.Cmd {