Add wrapper implementation

This commit is contained in:
Asim 2015-11-26 20:36:42 +00:00
parent 4fa909a3c7
commit fb172df0ce
4 changed files with 144 additions and 3 deletions

View File

@ -12,6 +12,7 @@ type options struct {
broker broker.Broker
registry registry.Registry
transport transport.Transport
wrappers []Wrapper
}
// Broker to be used for pub/sub
@ -48,3 +49,10 @@ func Transport(t transport.Transport) Option {
o.transport = t
}
}
// Adds a Wrapper to a list of options passed into the client
func Wrap(w Wrapper) Option {
return func(o *options) {
o.wrappers = append(o.wrappers, w)
}
}

View File

@ -23,6 +23,8 @@ type rpcClient struct {
}
func newRpcClient(opt ...Option) Client {
var once sync.Once
opts := options{
codecs: make(map[string]CodecFunc),
}
@ -43,12 +45,19 @@ func newRpcClient(opt ...Option) Client {
opts.broker = broker.DefaultBroker
}
var once sync.Once
return &rpcClient{
rc := &rpcClient{
once: once,
opts: opts,
}
c := Client(rc)
// wrap in reverse
for i := len(opts.wrappers); i > 0; i-- {
c = opts.wrappers[i-1](c)
}
return c
}
func (r *rpcClient) codecFunc(contentType string) (codecFunc, error) {

37
client/wrapper.go Normal file
View File

@ -0,0 +1,37 @@
/*
Wrapper is a type of middleware for the go-micro client. It allows
the client to be "wrapped" so that requests and responses can be intercepted
to perform extra requirements such as auth, tracing, monitoring, logging, etc.
Example usage:
import (
"log"
"github.com/micro/go-micro/client"
)
type LogWrapper struct {
client.Client
}
func (l *LogWrapper) Call(ctx context.Context, req Request, rsp interface{}) error {
log.Println("Making request to service " + req.Service() + " method " + req.Method())
return w.Client.Call(ctx, req, rsp)
}
func Wrapper(c client.Client) client.Client {
return &LogWrapper{c}
}
func main() {
c := client.NewClient(client.Wrap(Wrapper))
}
*/
package client
// Wrapper wraps a client and returns a client
type Wrapper func(Client) Client

View File

@ -0,0 +1,87 @@
/*
An example of how to use client.Wrapper as middleware
*/
package main
import (
"fmt"
"time"
"github.com/micro/go-micro/client"
"github.com/micro/go-micro/cmd"
c "github.com/micro/go-micro/context"
example "github.com/micro/go-micro/examples/server/proto/example"
"golang.org/x/net/context"
)
// 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{}) error {
md, _ := c.GetMetadata(ctx)
fmt.Printf("[Log Wrapper] ctx: %v service: %s method: %s\n", md, req.Service(), req.Method())
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{}) error {
ctx = c.WithMetadata(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}
}
// Calls the example service
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 := c.WithMetadata(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
}
}
func main() {
cmd.Init()
// Wrap the default client
client.DefaultClient = logWrap(client.DefaultClient)
call(0)
// Wrap using client.Wrap option
client.DefaultClient = client.NewClient(
client.Wrap(traceWrap),
client.Wrap(logWrap),
)
call(1)
}