Compare commits
122 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
718ae42808 | ||
|
2413cbcd80 | ||
|
9c820445a4 | ||
|
c44fd63301 | ||
|
d9a699ae6f | ||
|
4495ca3839 | ||
|
0b0eee41d0 | ||
|
e18f8defde | ||
|
7abdc68049 | ||
|
c90e1ccb99 | ||
|
991142cd57 | ||
|
5a5b1b8f6e | ||
|
58bc4c103f | ||
|
88817dc53f | ||
|
ef04331b86 | ||
|
67215ae5da | ||
|
f120452d28 | ||
|
740cfab8d0 | ||
|
f6b8045dd5 | ||
|
b776fbb766 | ||
|
a42de29f67 | ||
|
0f6d09af33 | ||
|
2dd5109eee | ||
|
e609095ba4 | ||
|
4843f09afa | ||
|
f9eddf1e6f | ||
|
f19308f1e6 | ||
|
8f0c2e0412 | ||
|
bf0e46dc0d | ||
|
15975d2903 | ||
|
9f2f0e3cea | ||
|
151bcf0ea1 | ||
|
dc0fbfc3c0 | ||
|
e607485c6b | ||
70d0029658 | |||
a606813fdf | |||
|
750267b308 | ||
|
7ce0305db4 | ||
|
c39591af0e | ||
|
fedc6be3e6 | ||
|
cb1679fd8d | ||
|
c0a676bfa9 | ||
|
cb4e376c64 | ||
|
c2c8182a5b | ||
|
01cb146e0d | ||
|
d0d729a789 | ||
|
113d87d855 | ||
|
56df10f68b | ||
|
3a5428fb36 | ||
|
178a3b3d8e | ||
|
de34f259ba | ||
|
81b68a1d7f | ||
|
1a600810a7 | ||
|
94127ae1aa | ||
|
cd2ac648ff | ||
|
e613b0c205 | ||
|
57dacf1831 | ||
|
8986b3135f | ||
|
6dd3ea1853 | ||
|
2c66e94045 | ||
|
c1ff3ceee4 | ||
|
b13604fb4b | ||
|
057adb2b2e | ||
|
7bd6d1b549 | ||
|
37988b596d | ||
|
9eb45dac82 | ||
|
59b13aef22 | ||
|
1e496938b7 | ||
|
fbc1d523d7 | ||
|
11795071fb | ||
|
c7e8a2aeb9 | ||
|
cb1c1afc84 | ||
|
3fc7d9ea50 | ||
|
abc2ace409 | ||
|
243d43df92 | ||
|
9c2b882008 | ||
|
4370f03e04 | ||
|
a3b962f37b | ||
|
a894b4f354 | ||
|
fc379f2d2c | ||
|
dcf4fed6a3 | ||
|
117376a922 | ||
|
380d9790e6 | ||
|
0baea58938 | ||
|
edb0fe4b16 | ||
|
eae32176c4 | ||
|
bc751c55fb | ||
|
91f2af91de | ||
|
3adce58eb2 | ||
|
bb01b3ed78 | ||
|
c3ea25225c | ||
|
beffa625f8 | ||
|
0d85e35da0 | ||
|
4074cce397 | ||
|
000431f489 | ||
|
e16420fdbd | ||
|
52d8d26018 | ||
|
6649012af3 | ||
|
6b5dcbf814 | ||
|
34381213e7 | ||
|
767292906a | ||
|
e1ecd728c5 | ||
|
f1b6709722 | ||
|
4030ccc27b | ||
|
2e67e23a23 | ||
|
be229438bc | ||
e1709026e4 | |||
|
d250ac736f | ||
|
6719f8d655 | ||
|
d7929ef8f3 | ||
|
04404441a4 | ||
|
b806e7bdf5 | ||
|
2720c6f28e | ||
|
cdf0f14d58 | ||
|
679c5f0ccd | ||
|
873bfcc73c | ||
|
7884e889f4 | ||
|
b1c49a0ddc | ||
|
318367cd71 | ||
|
2d09e74b0e | ||
|
3e90d32f29 | ||
|
fca89e06ef |
@@ -1,9 +1,11 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
notifications:
|
||||
slack:
|
||||
secure: aEvhLbhujaGaKSrOokiG3//PaVHTIrc3fBpoRbCRqfZpyq6WREoapJJhF+tIpWWOwaC9GmChbD6aHo/jMUgwKXVyPSaNjiEL87YzUUpL8B2zslNp1rgfTg/LrzthOx3Q1TYwpaAl3to0fuHUVFX4yMeC2vuThq7WSXgMMxFCtbc=
|
||||
cache:
|
||||
directories:
|
||||
- $GOPATH/pkg/mod
|
||||
|
@@ -13,18 +13,19 @@ import (
|
||||
)
|
||||
|
||||
type natsBroker struct {
|
||||
sync.Once
|
||||
sync.RWMutex
|
||||
addrs []string
|
||||
conn *nats.Conn
|
||||
opts broker.Options
|
||||
nopts nats.Options
|
||||
drain bool
|
||||
addrs []string
|
||||
conn *nats.Conn
|
||||
opts broker.Options
|
||||
nopts nats.Options
|
||||
drain bool
|
||||
closeCh chan (error)
|
||||
}
|
||||
|
||||
type subscriber struct {
|
||||
s *nats.Subscription
|
||||
opts broker.SubscribeOptions
|
||||
drain bool
|
||||
s *nats.Subscription
|
||||
opts broker.SubscribeOptions
|
||||
}
|
||||
|
||||
type publication struct {
|
||||
@@ -54,9 +55,6 @@ func (s *subscriber) Topic() string {
|
||||
}
|
||||
|
||||
func (s *subscriber) Unsubscribe() error {
|
||||
if s.drain {
|
||||
return s.s.Drain()
|
||||
}
|
||||
return s.s.Unsubscribe()
|
||||
}
|
||||
|
||||
@@ -122,20 +120,17 @@ func (n *natsBroker) Connect() error {
|
||||
|
||||
func (n *natsBroker) Disconnect() error {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
if n.drain {
|
||||
n.conn.Drain()
|
||||
} else {
|
||||
n.conn.Close()
|
||||
return <-n.closeCh
|
||||
}
|
||||
n.RUnlock()
|
||||
n.conn.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *natsBroker) Init(opts ...broker.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&n.opts)
|
||||
}
|
||||
n.addrs = setAddrs(n.opts.Addrs)
|
||||
n.setOption(opts...)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -167,11 +162,6 @@ func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...bro
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
var drain bool
|
||||
if _, ok := opt.Context.Value(drainSubscriptionKey{}).(bool); ok {
|
||||
drain = true
|
||||
}
|
||||
|
||||
fn := func(msg *nats.Msg) {
|
||||
var m broker.Message
|
||||
if err := n.opts.Codec.Unmarshal(msg.Data, &m); err != nil {
|
||||
@@ -193,7 +183,7 @@ func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...bro
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &subscriber{s: sub, opts: opt, drain: drain}, nil
|
||||
return &subscriber{s: sub, opts: opt}, nil
|
||||
}
|
||||
|
||||
func (n *natsBroker) String() string {
|
||||
@@ -207,39 +197,59 @@ func NewBroker(opts ...broker.Option) broker.Broker {
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
n := &natsBroker{
|
||||
opts: options,
|
||||
}
|
||||
n.setOption(opts...)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func (n *natsBroker) setOption(opts ...broker.Option) {
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
o(&n.opts)
|
||||
}
|
||||
|
||||
natsOpts := nats.GetDefaultOptions()
|
||||
if n, ok := options.Context.Value(optionsKey{}).(nats.Options); ok {
|
||||
natsOpts = n
|
||||
}
|
||||
n.Once.Do(func() {
|
||||
n.nopts = nats.GetDefaultOptions()
|
||||
})
|
||||
|
||||
var drain bool
|
||||
if _, ok := options.Context.Value(drainSubscriptionKey{}).(bool); ok {
|
||||
drain = true
|
||||
if nopts, ok := n.opts.Context.Value(optionsKey{}).(nats.Options); ok {
|
||||
n.nopts = nopts
|
||||
}
|
||||
|
||||
// broker.Options have higher priority than nats.Options
|
||||
// only if Addrs, Secure or TLSConfig were not set through a broker.Option
|
||||
// we read them from nats.Option
|
||||
if len(options.Addrs) == 0 {
|
||||
options.Addrs = natsOpts.Servers
|
||||
if len(n.opts.Addrs) == 0 {
|
||||
n.opts.Addrs = n.nopts.Servers
|
||||
}
|
||||
|
||||
if !options.Secure {
|
||||
options.Secure = natsOpts.Secure
|
||||
if !n.opts.Secure {
|
||||
n.opts.Secure = n.nopts.Secure
|
||||
}
|
||||
|
||||
if options.TLSConfig == nil {
|
||||
options.TLSConfig = natsOpts.TLSConfig
|
||||
if n.opts.TLSConfig == nil {
|
||||
n.opts.TLSConfig = n.nopts.TLSConfig
|
||||
}
|
||||
n.addrs = setAddrs(n.opts.Addrs)
|
||||
|
||||
return &natsBroker{
|
||||
opts: options,
|
||||
nopts: natsOpts,
|
||||
addrs: setAddrs(options.Addrs),
|
||||
drain: drain,
|
||||
if n.opts.Context.Value(drainConnectionKey{}) != nil {
|
||||
n.drain = true
|
||||
n.closeCh = make(chan error)
|
||||
n.nopts.ClosedCB = n.onClose
|
||||
n.nopts.AsyncErrorCB = n.onAsyncError
|
||||
}
|
||||
}
|
||||
|
||||
func (n *natsBroker) onClose(conn *nats.Conn) {
|
||||
n.closeCh <- nil
|
||||
}
|
||||
|
||||
func (n *natsBroker) onAsyncError(conn *nats.Conn, sub *nats.Subscription, err error) {
|
||||
// There are kinds of different async error nats might callback, but we are interested
|
||||
// in ErrDrainTimeout only here.
|
||||
if err == nats.ErrDrainTimeout {
|
||||
n.closeCh <- err
|
||||
}
|
||||
}
|
||||
|
@@ -7,7 +7,6 @@ import (
|
||||
|
||||
type optionsKey struct{}
|
||||
type drainConnectionKey struct{}
|
||||
type drainSubscriptionKey struct{}
|
||||
|
||||
// Options accepts nats.Options
|
||||
func Options(opts nats.Options) broker.Option {
|
||||
@@ -16,10 +15,5 @@ func Options(opts nats.Options) broker.Option {
|
||||
|
||||
// DrainConnection will drain subscription on close
|
||||
func DrainConnection() broker.Option {
|
||||
return setBrokerOption(drainConnectionKey{}, true)
|
||||
}
|
||||
|
||||
// DrainSubscription will drain pending messages when unsubscribe
|
||||
func DrainSubscription() broker.SubscribeOption {
|
||||
return setSubscribeOption(drainSubscriptionKey{}, true)
|
||||
return setBrokerOption(drainConnectionKey{}, struct{}{})
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/micro/go-micro/registry"
|
||||
"github.com/micro/go-micro/transport"
|
||||
|
||||
"github.com/micro/go-micro/util/buf"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/encoding"
|
||||
@@ -73,10 +72,11 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele
|
||||
|
||||
// get next nodes from the selector
|
||||
next, err := g.opts.Selector.Select(service, opts.SelectOptions...)
|
||||
if err != nil && err == selector.ErrNotFound {
|
||||
return nil, errors.NotFound("go.micro.client", err.Error())
|
||||
} else if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.client", err.Error())
|
||||
if err != nil {
|
||||
if err == selector.ErrNotFound {
|
||||
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
|
||||
}
|
||||
return nil, errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
|
||||
}
|
||||
|
||||
return next, nil
|
||||
@@ -350,15 +350,17 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface
|
||||
|
||||
// select next node
|
||||
node, err := next()
|
||||
if err != nil && err == selector.ErrNotFound {
|
||||
return errors.NotFound("go.micro.client", err.Error())
|
||||
} else if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
service := req.Service()
|
||||
if err != nil {
|
||||
if err == selector.ErrNotFound {
|
||||
return errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
|
||||
}
|
||||
return errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
|
||||
}
|
||||
|
||||
// make the call
|
||||
err = gcall(ctx, node, req, rsp, callOpts)
|
||||
g.opts.Selector.Mark(req.Service(), node, err)
|
||||
g.opts.Selector.Mark(service, node, err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -429,14 +431,16 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli
|
||||
}
|
||||
|
||||
node, err := next()
|
||||
if err != nil && err == selector.ErrNotFound {
|
||||
return nil, errors.NotFound("go.micro.client", err.Error())
|
||||
} else if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.client", err.Error())
|
||||
service := req.Service()
|
||||
if err != nil {
|
||||
if err == selector.ErrNotFound {
|
||||
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
|
||||
}
|
||||
return nil, errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
|
||||
}
|
||||
|
||||
stream, err := g.stream(ctx, node, req, callOpts)
|
||||
g.opts.Selector.Mark(req.Service(), node, err)
|
||||
g.opts.Selector.Mark(service, node, err)
|
||||
return stream, err
|
||||
}
|
||||
|
||||
@@ -486,14 +490,13 @@ func (g *grpcClient) Publish(ctx context.Context, p client.Message, opts ...clie
|
||||
}
|
||||
md["Content-Type"] = p.ContentType()
|
||||
|
||||
cf, err := g.newCodec(p.ContentType())
|
||||
cf, err := g.newGRPCCodec(p.ContentType())
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
|
||||
b := buf.New(nil)
|
||||
|
||||
if err := cf(b).Write(&codec.Message{Type: codec.Event}, p.Payload()); err != nil {
|
||||
b, err := cf.Marshal(p.Payload())
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
|
||||
@@ -503,7 +506,7 @@ func (g *grpcClient) Publish(ctx context.Context, p client.Message, opts ...clie
|
||||
|
||||
return g.opts.Broker.Publish(p.Topic(), &broker.Message{
|
||||
Header: md,
|
||||
Body: b.Bytes(),
|
||||
Body: b,
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -96,19 +96,14 @@ func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request,
|
||||
}
|
||||
}
|
||||
|
||||
var grr error
|
||||
c, err := r.pool.Get(address, transport.WithTimeout(opts.DialTimeout))
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", "connection error: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
// defer execution of release
|
||||
r.pool.Release(c, grr)
|
||||
}()
|
||||
|
||||
seq := atomic.LoadUint64(&r.seq)
|
||||
atomic.AddUint64(&r.seq, 1)
|
||||
codec := newRpcCodec(msg, c, cf)
|
||||
codec := newRpcCodec(msg, c, cf, "")
|
||||
|
||||
rsp := &rpcResponse{
|
||||
socket: c,
|
||||
@@ -116,15 +111,19 @@ func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request,
|
||||
}
|
||||
|
||||
stream := &rpcStream{
|
||||
id: fmt.Sprintf("%v", seq),
|
||||
context: ctx,
|
||||
request: req,
|
||||
response: rsp,
|
||||
codec: codec,
|
||||
closed: make(chan bool),
|
||||
id: fmt.Sprintf("%v", seq),
|
||||
release: func(err error) { r.pool.Release(c, err) },
|
||||
sendEOS: false,
|
||||
}
|
||||
// close the stream on exiting this function
|
||||
defer stream.Close()
|
||||
|
||||
// wait for error response
|
||||
ch := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
@@ -150,14 +149,26 @@ func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request,
|
||||
ch <- nil
|
||||
}()
|
||||
|
||||
var grr error
|
||||
|
||||
select {
|
||||
case err := <-ch:
|
||||
grr = err
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
grr = ctx.Err()
|
||||
return errors.Timeout("go.micro.client", fmt.Sprintf("%v", ctx.Err()))
|
||||
grr = errors.Timeout("go.micro.client", fmt.Sprintf("%v", ctx.Err()))
|
||||
}
|
||||
|
||||
// set the stream error
|
||||
if grr != nil {
|
||||
stream.Lock()
|
||||
stream.err = grr
|
||||
stream.Unlock()
|
||||
|
||||
return grr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request, opts CallOptions) (Stream, error) {
|
||||
@@ -201,12 +212,18 @@ func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request
|
||||
dOpts = append(dOpts, transport.WithTimeout(opts.DialTimeout))
|
||||
}
|
||||
|
||||
c, err := r.opts.Transport.Dial(address, dOpts...)
|
||||
c, err := r.pool.Get(address, dOpts...)
|
||||
if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.client", "connection error: %v", err)
|
||||
}
|
||||
|
||||
codec := newRpcCodec(msg, c, cf)
|
||||
// increment the sequence number
|
||||
seq := atomic.LoadUint64(&r.seq)
|
||||
atomic.AddUint64(&r.seq, 1)
|
||||
id := fmt.Sprintf("%v", seq)
|
||||
|
||||
// create codec with stream id
|
||||
codec := newRpcCodec(msg, c, cf, id)
|
||||
|
||||
rsp := &rpcResponse{
|
||||
socket: c,
|
||||
@@ -219,16 +236,24 @@ func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request
|
||||
}
|
||||
|
||||
stream := &rpcStream{
|
||||
id: id,
|
||||
context: ctx,
|
||||
request: req,
|
||||
response: rsp,
|
||||
closed: make(chan bool),
|
||||
codec: codec,
|
||||
// used to close the stream
|
||||
closed: make(chan bool),
|
||||
// signal the end of stream,
|
||||
sendEOS: true,
|
||||
// release func
|
||||
release: func(err error) { r.pool.Release(c, err) },
|
||||
}
|
||||
|
||||
// wait for error response
|
||||
ch := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
// send the first message
|
||||
ch <- stream.Send(req.Body())
|
||||
}()
|
||||
|
||||
@@ -242,6 +267,12 @@ func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request
|
||||
}
|
||||
|
||||
if grr != nil {
|
||||
// set the error
|
||||
stream.Lock()
|
||||
stream.err = grr
|
||||
stream.Unlock()
|
||||
|
||||
// close the stream
|
||||
stream.Close()
|
||||
return nil, grr
|
||||
}
|
||||
@@ -312,10 +343,11 @@ func (r *rpcClient) next(request Request, opts CallOptions) (selector.Next, erro
|
||||
|
||||
// get next nodes from the selector
|
||||
next, err := r.opts.Selector.Select(service, opts.SelectOptions...)
|
||||
if err != nil && err == selector.ErrNotFound {
|
||||
return nil, errors.NotFound("go.micro.client", "service %s: %v", service, err.Error())
|
||||
} else if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.client", "error selecting %s node: %v", service, err.Error())
|
||||
if err != nil {
|
||||
if err == selector.ErrNotFound {
|
||||
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
|
||||
}
|
||||
return nil, errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
|
||||
}
|
||||
|
||||
return next, nil
|
||||
@@ -375,15 +407,17 @@ func (r *rpcClient) Call(ctx context.Context, request Request, response interfac
|
||||
|
||||
// select next node
|
||||
node, err := next()
|
||||
if err != nil && err == selector.ErrNotFound {
|
||||
return errors.NotFound("go.micro.client", "service %s: %v", request.Service(), err.Error())
|
||||
} else if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", "error getting next %s node: %v", request.Service(), err.Error())
|
||||
service := request.Service()
|
||||
if err != nil {
|
||||
if err == selector.ErrNotFound {
|
||||
return errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
|
||||
}
|
||||
return errors.InternalServerError("go.micro.client", "error getting next %s node: %s", service, err.Error())
|
||||
}
|
||||
|
||||
// make the call
|
||||
err = rcall(ctx, node, request, response, callOpts)
|
||||
r.opts.Selector.Mark(request.Service(), node, err)
|
||||
r.opts.Selector.Mark(service, node, err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -452,14 +486,16 @@ func (r *rpcClient) Stream(ctx context.Context, request Request, opts ...CallOpt
|
||||
}
|
||||
|
||||
node, err := next()
|
||||
if err != nil && err == selector.ErrNotFound {
|
||||
return nil, errors.NotFound("go.micro.client", "service %s: %v", request.Service(), err.Error())
|
||||
} else if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.client", "error getting next %s node: %v", request.Service(), err.Error())
|
||||
service := request.Service()
|
||||
if err != nil {
|
||||
if err == selector.ErrNotFound {
|
||||
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
|
||||
}
|
||||
return nil, errors.InternalServerError("go.micro.client", "error getting next %s node: %s", service, err.Error())
|
||||
}
|
||||
|
||||
stream, err := r.stream(ctx, node, request, callOpts)
|
||||
r.opts.Selector.Mark(request.Service(), node, err)
|
||||
r.opts.Selector.Mark(service, node, err)
|
||||
return stream, err
|
||||
}
|
||||
|
||||
|
@@ -39,6 +39,9 @@ type rpcCodec struct {
|
||||
|
||||
req *transport.Message
|
||||
buf *readWriteCloser
|
||||
|
||||
// signify if its a stream
|
||||
stream string
|
||||
}
|
||||
|
||||
type readWriteCloser struct {
|
||||
@@ -113,7 +116,7 @@ func getHeaders(m *codec.Message) {
|
||||
}
|
||||
}
|
||||
|
||||
func setHeaders(m *codec.Message) {
|
||||
func setHeaders(m *codec.Message, stream string) {
|
||||
set := func(hdr, v string) {
|
||||
if len(v) == 0 {
|
||||
return
|
||||
@@ -126,6 +129,11 @@ func setHeaders(m *codec.Message) {
|
||||
set("Micro-Service", m.Target)
|
||||
set("Micro-Method", m.Method)
|
||||
set("Micro-Endpoint", m.Endpoint)
|
||||
set("Micro-Error", m.Error)
|
||||
|
||||
if len(stream) > 0 {
|
||||
set("Micro-Stream", stream)
|
||||
}
|
||||
}
|
||||
|
||||
// setupProtocol sets up the old protocol
|
||||
@@ -149,7 +157,7 @@ func setupProtocol(msg *transport.Message, node *registry.Node) codec.NewCodec {
|
||||
return defaultCodecs[msg.Header["Content-Type"]]
|
||||
}
|
||||
|
||||
func newRpcCodec(req *transport.Message, client transport.Client, c codec.NewCodec) codec.Codec {
|
||||
func newRpcCodec(req *transport.Message, client transport.Client, c codec.NewCodec, stream string) codec.Codec {
|
||||
rwc := &readWriteCloser{
|
||||
wbuf: bytes.NewBuffer(nil),
|
||||
rbuf: bytes.NewBuffer(nil),
|
||||
@@ -159,6 +167,7 @@ func newRpcCodec(req *transport.Message, client transport.Client, c codec.NewCod
|
||||
client: client,
|
||||
codec: c(rwc),
|
||||
req: req,
|
||||
stream: stream,
|
||||
}
|
||||
return r
|
||||
}
|
||||
@@ -177,7 +186,7 @@ func (c *rpcCodec) Write(m *codec.Message, body interface{}) error {
|
||||
}
|
||||
|
||||
// set the mucp headers
|
||||
setHeaders(m)
|
||||
setHeaders(m, c.stream)
|
||||
|
||||
// if body is bytes Frame don't encode
|
||||
if body != nil {
|
||||
@@ -240,6 +249,12 @@ func (c *rpcCodec) ReadHeader(m *codec.Message, r codec.MessageType) error {
|
||||
|
||||
func (c *rpcCodec) ReadBody(b interface{}) error {
|
||||
// read body
|
||||
// read raw data
|
||||
if v, ok := b.(*raw.Frame); ok {
|
||||
v.Data = c.buf.rbuf.Bytes()
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := c.codec.ReadBody(b); err != nil {
|
||||
return errors.InternalServerError("go.micro.client.codec", err.Error())
|
||||
}
|
||||
|
@@ -18,6 +18,12 @@ type rpcStream struct {
|
||||
response Response
|
||||
codec codec.Codec
|
||||
context context.Context
|
||||
|
||||
// signal whether we should send EOS
|
||||
sendEOS bool
|
||||
|
||||
// release releases the connection back to the pool
|
||||
release func(err error)
|
||||
}
|
||||
|
||||
func (r *rpcStream) isClosed() bool {
|
||||
@@ -120,6 +126,26 @@ func (r *rpcStream) Close() error {
|
||||
return nil
|
||||
default:
|
||||
close(r.closed)
|
||||
return r.codec.Close()
|
||||
|
||||
// send the end of stream message
|
||||
if r.sendEOS {
|
||||
// no need to check for error
|
||||
r.codec.Write(&codec.Message{
|
||||
Id: r.id,
|
||||
Target: r.request.Service(),
|
||||
Method: r.request.Method(),
|
||||
Endpoint: r.request.Endpoint(),
|
||||
Type: codec.Error,
|
||||
Error: lastStreamResponseError,
|
||||
}, nil)
|
||||
}
|
||||
|
||||
err := r.codec.Close()
|
||||
|
||||
// release the connection
|
||||
r.release(r.Error())
|
||||
|
||||
// return the codec error
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@@ -51,6 +51,9 @@ func (c *registrySelector) Select(service string, opts ...SelectOption) (Next, e
|
||||
// if that fails go directly to the registry
|
||||
services, err := c.rc.GetService(service)
|
||||
if err != nil {
|
||||
if err == registry.ErrNotFound {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@@ -9,9 +9,9 @@ import (
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/client/selector"
|
||||
"github.com/micro/go-micro/network/router"
|
||||
pb "github.com/micro/go-micro/network/router/proto"
|
||||
"github.com/micro/go-micro/registry"
|
||||
"github.com/micro/go-micro/router"
|
||||
pb "github.com/micro/go-micro/router/proto"
|
||||
)
|
||||
|
||||
type routerSelector struct {
|
||||
|
@@ -42,6 +42,7 @@ import (
|
||||
tgrpc "github.com/micro/go-micro/transport/grpc"
|
||||
thttp "github.com/micro/go-micro/transport/http"
|
||||
tmem "github.com/micro/go-micro/transport/memory"
|
||||
"github.com/micro/go-micro/transport/quic"
|
||||
)
|
||||
|
||||
type Cmd interface {
|
||||
@@ -211,6 +212,7 @@ var (
|
||||
"memory": tmem.NewTransport,
|
||||
"http": thttp.NewTransport,
|
||||
"grpc": tgrpc.NewTransport,
|
||||
"quic": quic.NewTransport,
|
||||
}
|
||||
|
||||
// used for default selection as the fall back
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -8,10 +9,15 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/config/source/env"
|
||||
"github.com/micro/go-micro/config/source/file"
|
||||
)
|
||||
|
||||
var (
|
||||
sep = string(os.PathSeparator)
|
||||
)
|
||||
|
||||
func createFileForIssue18(t *testing.T, content string) *os.File {
|
||||
data := []byte(content)
|
||||
path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano()))
|
||||
@@ -116,3 +122,57 @@ func TestConfigMerge(t *testing.T) {
|
||||
actualHost)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileChange(t *testing.T) {
|
||||
// create a temp file
|
||||
fileName := uuid.New().String() + "testWatcher.json"
|
||||
f, err := os.OpenFile("."+sep+fileName, os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
defer f.Close()
|
||||
defer os.Remove("." + sep + fileName)
|
||||
|
||||
// load the file
|
||||
if err := Load(file.NewSource(
|
||||
file.WithPath("." + sep + fileName),
|
||||
)); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// watch changes
|
||||
watcher, err := Watch()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
changeTimes := 0
|
||||
go func() {
|
||||
for {
|
||||
v, err := watcher.Next()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
changeTimes++
|
||||
t.Logf("file change,%s", string(v.Bytes()))
|
||||
}
|
||||
}()
|
||||
|
||||
content := map[int]string{}
|
||||
// change the file
|
||||
for i := 0; i < 5; i++ {
|
||||
content[i] = time.Now().String()
|
||||
bytes, _ := json.Marshal(content)
|
||||
f.Truncate(0)
|
||||
f.Seek(0, 0)
|
||||
if _, err := f.Write(bytes); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
if changeTimes != 4 {
|
||||
t.Error(fmt.Errorf("watcher error: change times %d is not enough", changeTimes))
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,5 @@
|
||||
//+build !linux
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
|
72
config/source/file/watcher_linux.go
Normal file
72
config/source/file/watcher_linux.go
Normal file
@@ -0,0 +1,72 @@
|
||||
//+build linux
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/micro/go-micro/config/source"
|
||||
)
|
||||
|
||||
type watcher struct {
|
||||
f *file
|
||||
|
||||
fw *fsnotify.Watcher
|
||||
exit chan bool
|
||||
}
|
||||
|
||||
func newWatcher(f *file) (source.Watcher, error) {
|
||||
fw, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fw.Add(f.path)
|
||||
|
||||
return &watcher{
|
||||
f: f,
|
||||
fw: fw,
|
||||
exit: make(chan bool),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *watcher) Next() (*source.ChangeSet, error) {
|
||||
// is it closed?
|
||||
select {
|
||||
case <-w.exit:
|
||||
return nil, errors.New("watcher stopped")
|
||||
default:
|
||||
}
|
||||
|
||||
// try get the event
|
||||
select {
|
||||
case event, _ := <-w.fw.Events:
|
||||
if event.Op == fsnotify.Rename {
|
||||
// check existence of file, and add watch again
|
||||
_, err := os.Stat(event.Name)
|
||||
if err == nil || os.IsExist(err) {
|
||||
w.fw.Add(event.Name)
|
||||
}
|
||||
}
|
||||
|
||||
c, err := w.f.Read()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// add path again for the event bug of fsnotify
|
||||
w.fw.Add(w.f.path)
|
||||
|
||||
return c, nil
|
||||
case err := <-w.fw.Errors:
|
||||
return nil, err
|
||||
case <-w.exit:
|
||||
return nil, errors.New("watcher stopped")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) Stop() error {
|
||||
return w.fw.Close()
|
||||
}
|
@@ -27,7 +27,7 @@ Specify source with data
|
||||
|
||||
```go
|
||||
memorySource := memory.NewSource(
|
||||
memory.WithData(data),
|
||||
memory.WithJSON(data),
|
||||
)
|
||||
```
|
||||
|
||||
|
@@ -18,6 +18,7 @@ type memory struct {
|
||||
func (s *memory) Read() (*source.ChangeSet, error) {
|
||||
s.RLock()
|
||||
cs := &source.ChangeSet{
|
||||
Format: s.ChangeSet.Format,
|
||||
Timestamp: s.ChangeSet.Timestamp,
|
||||
Data: s.ChangeSet.Data,
|
||||
Checksum: s.ChangeSet.Checksum,
|
||||
|
41
debug/handler/debug.go
Normal file
41
debug/handler/debug.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
proto "github.com/micro/go-micro/debug/proto"
|
||||
)
|
||||
|
||||
type Debug struct {
|
||||
proto.DebugHandler
|
||||
started int64
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultHandler = newDebug()
|
||||
)
|
||||
|
||||
func newDebug() *Debug {
|
||||
return &Debug{
|
||||
started: time.Now().Unix(),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Debug) Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error {
|
||||
rsp.Status = "ok"
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Debug) Stats(ctx context.Context, req *proto.StatsRequest, rsp *proto.StatsResponse) error {
|
||||
var mstat runtime.MemStats
|
||||
runtime.ReadMemStats(&mstat)
|
||||
|
||||
rsp.Started = uint64(d.started)
|
||||
rsp.Uptime = uint64(time.Now().Unix() - d.started)
|
||||
rsp.Memory = mstat.Alloc
|
||||
rsp.Gc = mstat.PauseTotalNs
|
||||
rsp.Threads = uint64(runtime.NumGoroutine())
|
||||
return nil
|
||||
}
|
108
debug/proto/debug.micro.go
Normal file
108
debug/proto/debug.micro.go
Normal file
@@ -0,0 +1,108 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: micro/go-micro/debug/proto/debug.proto
|
||||
|
||||
package debug
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
import (
|
||||
context "context"
|
||||
client "github.com/micro/go-micro/client"
|
||||
server "github.com/micro/go-micro/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 Debug service
|
||||
|
||||
type DebugService interface {
|
||||
Health(ctx context.Context, in *HealthRequest, opts ...client.CallOption) (*HealthResponse, error)
|
||||
Stats(ctx context.Context, in *StatsRequest, opts ...client.CallOption) (*StatsResponse, error)
|
||||
}
|
||||
|
||||
type debugService struct {
|
||||
c client.Client
|
||||
name string
|
||||
}
|
||||
|
||||
func NewDebugService(name string, c client.Client) DebugService {
|
||||
if c == nil {
|
||||
c = client.NewClient()
|
||||
}
|
||||
if len(name) == 0 {
|
||||
name = "debug"
|
||||
}
|
||||
return &debugService{
|
||||
c: c,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *debugService) Health(ctx context.Context, in *HealthRequest, opts ...client.CallOption) (*HealthResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Debug.Health", in)
|
||||
out := new(HealthResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *debugService) Stats(ctx context.Context, in *StatsRequest, opts ...client.CallOption) (*StatsResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Debug.Stats", in)
|
||||
out := new(StatsResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for Debug service
|
||||
|
||||
type DebugHandler interface {
|
||||
Health(context.Context, *HealthRequest, *HealthResponse) error
|
||||
Stats(context.Context, *StatsRequest, *StatsResponse) error
|
||||
}
|
||||
|
||||
func RegisterDebugHandler(s server.Server, hdlr DebugHandler, opts ...server.HandlerOption) error {
|
||||
type debug interface {
|
||||
Health(ctx context.Context, in *HealthRequest, out *HealthResponse) error
|
||||
Stats(ctx context.Context, in *StatsRequest, out *StatsResponse) error
|
||||
}
|
||||
type Debug struct {
|
||||
debug
|
||||
}
|
||||
h := &debugHandler{hdlr}
|
||||
return s.Handle(s.NewHandler(&Debug{h}, opts...))
|
||||
}
|
||||
|
||||
type debugHandler struct {
|
||||
DebugHandler
|
||||
}
|
||||
|
||||
func (h *debugHandler) Health(ctx context.Context, in *HealthRequest, out *HealthResponse) error {
|
||||
return h.DebugHandler.Health(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *debugHandler) Stats(ctx context.Context, in *StatsRequest, out *StatsResponse) error {
|
||||
return h.DebugHandler.Stats(ctx, in, out)
|
||||
}
|
336
debug/proto/debug.pb.go
Normal file
336
debug/proto/debug.pb.go
Normal file
@@ -0,0 +1,336 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: micro/go-micro/debug/proto/debug.proto
|
||||
|
||||
package debug
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
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
|
||||
|
||||
type HealthRequest struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *HealthRequest) Reset() { *m = HealthRequest{} }
|
||||
func (m *HealthRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*HealthRequest) ProtoMessage() {}
|
||||
func (*HealthRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f25415e61bccfa1f, []int{0}
|
||||
}
|
||||
|
||||
func (m *HealthRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HealthRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *HealthRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_HealthRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *HealthRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_HealthRequest.Merge(m, src)
|
||||
}
|
||||
func (m *HealthRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_HealthRequest.Size(m)
|
||||
}
|
||||
func (m *HealthRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_HealthRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_HealthRequest proto.InternalMessageInfo
|
||||
|
||||
type HealthResponse struct {
|
||||
// default: ok
|
||||
Status string `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *HealthResponse) Reset() { *m = HealthResponse{} }
|
||||
func (m *HealthResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*HealthResponse) ProtoMessage() {}
|
||||
func (*HealthResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f25415e61bccfa1f, []int{1}
|
||||
}
|
||||
|
||||
func (m *HealthResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HealthResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *HealthResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_HealthResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *HealthResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_HealthResponse.Merge(m, src)
|
||||
}
|
||||
func (m *HealthResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_HealthResponse.Size(m)
|
||||
}
|
||||
func (m *HealthResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_HealthResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_HealthResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *HealthResponse) GetStatus() string {
|
||||
if m != nil {
|
||||
return m.Status
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type StatsRequest struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *StatsRequest) Reset() { *m = StatsRequest{} }
|
||||
func (m *StatsRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*StatsRequest) ProtoMessage() {}
|
||||
func (*StatsRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f25415e61bccfa1f, []int{2}
|
||||
}
|
||||
|
||||
func (m *StatsRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StatsRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *StatsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_StatsRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *StatsRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_StatsRequest.Merge(m, src)
|
||||
}
|
||||
func (m *StatsRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_StatsRequest.Size(m)
|
||||
}
|
||||
func (m *StatsRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_StatsRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_StatsRequest proto.InternalMessageInfo
|
||||
|
||||
type StatsResponse struct {
|
||||
// unix timestamp
|
||||
Started uint64 `protobuf:"varint,1,opt,name=started,proto3" json:"started,omitempty"`
|
||||
// in seconds
|
||||
Uptime uint64 `protobuf:"varint,2,opt,name=uptime,proto3" json:"uptime,omitempty"`
|
||||
// in bytes
|
||||
Memory uint64 `protobuf:"varint,3,opt,name=memory,proto3" json:"memory,omitempty"`
|
||||
// num threads
|
||||
Threads uint64 `protobuf:"varint,4,opt,name=threads,proto3" json:"threads,omitempty"`
|
||||
// total gc in nanoseconds
|
||||
Gc uint64 `protobuf:"varint,5,opt,name=gc,proto3" json:"gc,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *StatsResponse) Reset() { *m = StatsResponse{} }
|
||||
func (m *StatsResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*StatsResponse) ProtoMessage() {}
|
||||
func (*StatsResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_f25415e61bccfa1f, []int{3}
|
||||
}
|
||||
|
||||
func (m *StatsResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StatsResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *StatsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_StatsResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *StatsResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_StatsResponse.Merge(m, src)
|
||||
}
|
||||
func (m *StatsResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_StatsResponse.Size(m)
|
||||
}
|
||||
func (m *StatsResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_StatsResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_StatsResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *StatsResponse) GetStarted() uint64 {
|
||||
if m != nil {
|
||||
return m.Started
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *StatsResponse) GetUptime() uint64 {
|
||||
if m != nil {
|
||||
return m.Uptime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *StatsResponse) GetMemory() uint64 {
|
||||
if m != nil {
|
||||
return m.Memory
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *StatsResponse) GetThreads() uint64 {
|
||||
if m != nil {
|
||||
return m.Threads
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *StatsResponse) GetGc() uint64 {
|
||||
if m != nil {
|
||||
return m.Gc
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*HealthRequest)(nil), "HealthRequest")
|
||||
proto.RegisterType((*HealthResponse)(nil), "HealthResponse")
|
||||
proto.RegisterType((*StatsRequest)(nil), "StatsRequest")
|
||||
proto.RegisterType((*StatsResponse)(nil), "StatsResponse")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("micro/go-micro/debug/proto/debug.proto", fileDescriptor_f25415e61bccfa1f)
|
||||
}
|
||||
|
||||
var fileDescriptor_f25415e61bccfa1f = []byte{
|
||||
// 230 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0x41, 0x4b, 0xc4, 0x30,
|
||||
0x10, 0x85, 0xb7, 0x75, 0x5b, 0x71, 0xb0, 0x59, 0xc8, 0x41, 0xc2, 0x9e, 0x24, 0x07, 0x29, 0x88,
|
||||
0x59, 0xd0, 0xbf, 0xe0, 0xc1, 0x73, 0xbd, 0x0b, 0xd9, 0x76, 0xe8, 0x16, 0xac, 0xa9, 0x99, 0xe9,
|
||||
0xc1, 0xb3, 0x7f, 0x5c, 0x9a, 0xa4, 0x60, 0x6f, 0xef, 0xbd, 0xf0, 0x1e, 0xf9, 0x06, 0x1e, 0xc6,
|
||||
0xa1, 0xf5, 0xee, 0xd4, 0xbb, 0xa7, 0x28, 0x3a, 0x3c, 0xcf, 0xfd, 0x69, 0xf2, 0x8e, 0x93, 0x36,
|
||||
0x41, 0xeb, 0x03, 0x54, 0x6f, 0x68, 0x3f, 0xf9, 0xd2, 0xe0, 0xf7, 0x8c, 0xc4, 0xba, 0x06, 0xb1,
|
||||
0x06, 0x34, 0xb9, 0x2f, 0x42, 0x79, 0x07, 0x25, 0xb1, 0xe5, 0x99, 0x54, 0x76, 0x9f, 0xd5, 0x37,
|
||||
0x4d, 0x72, 0x5a, 0xc0, 0xed, 0x3b, 0x5b, 0xa6, 0xb5, 0xf9, 0x9b, 0x41, 0x95, 0x82, 0xd4, 0x54,
|
||||
0x70, 0x4d, 0x6c, 0x3d, 0x63, 0x17, 0xaa, 0xfb, 0x66, 0xb5, 0xcb, 0xe6, 0x3c, 0xf1, 0x30, 0xa2,
|
||||
0xca, 0xc3, 0x43, 0x72, 0x4b, 0x3e, 0xe2, 0xe8, 0xfc, 0x8f, 0xba, 0x8a, 0x79, 0x74, 0xcb, 0x12,
|
||||
0x5f, 0x3c, 0xda, 0x8e, 0xd4, 0x3e, 0x2e, 0x25, 0x2b, 0x05, 0xe4, 0x7d, 0xab, 0x8a, 0x10, 0xe6,
|
||||
0x7d, 0xfb, 0xfc, 0x01, 0xc5, 0xeb, 0xc2, 0x27, 0x1f, 0xa1, 0x8c, 0x20, 0x52, 0x98, 0x0d, 0xe2,
|
||||
0xf1, 0x60, 0xb6, 0x84, 0x7a, 0x27, 0x6b, 0x28, 0xc2, 0xd7, 0x65, 0x65, 0xfe, 0x33, 0x1d, 0x85,
|
||||
0xd9, 0x10, 0xe9, 0xdd, 0xb9, 0x0c, 0x77, 0x7b, 0xf9, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xb9,
|
||||
0x5f, 0xf7, 0x61, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
// DebugClient is the client API for Debug service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type DebugClient interface {
|
||||
Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error)
|
||||
Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error)
|
||||
}
|
||||
|
||||
type debugClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewDebugClient(cc *grpc.ClientConn) DebugClient {
|
||||
return &debugClient{cc}
|
||||
}
|
||||
|
||||
func (c *debugClient) Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error) {
|
||||
out := new(HealthResponse)
|
||||
err := c.cc.Invoke(ctx, "/Debug/Health", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *debugClient) Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error) {
|
||||
out := new(StatsResponse)
|
||||
err := c.cc.Invoke(ctx, "/Debug/Stats", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DebugServer is the server API for Debug service.
|
||||
type DebugServer interface {
|
||||
Health(context.Context, *HealthRequest) (*HealthResponse, error)
|
||||
Stats(context.Context, *StatsRequest) (*StatsResponse, error)
|
||||
}
|
||||
|
||||
func RegisterDebugServer(s *grpc.Server, srv DebugServer) {
|
||||
s.RegisterService(&_Debug_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Debug_Health_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HealthRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DebugServer).Health(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/Debug/Health",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DebugServer).Health(ctx, req.(*HealthRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Debug_Stats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StatsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DebugServer).Stats(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/Debug/Stats",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DebugServer).Stats(ctx, req.(*StatsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Debug_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "Debug",
|
||||
HandlerType: (*DebugServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Health",
|
||||
Handler: _Debug_Health_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Stats",
|
||||
Handler: _Debug_Stats_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "micro/go-micro/debug/proto/debug.proto",
|
||||
}
|
@@ -1,13 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
// This is commented out due to import cycles.
|
||||
// But its what we expect the RPC service to
|
||||
// return.
|
||||
//
|
||||
// service Debug {
|
||||
// rpc Health(HealthRequest) returns (HealthResponse) {}
|
||||
// rpc Stats(StatsRequest) returns (StatsResponse) {}
|
||||
// }
|
||||
service Debug {
|
||||
rpc Health(HealthRequest) returns (HealthResponse) {}
|
||||
rpc Stats(StatsRequest) returns (StatsResponse) {}
|
||||
}
|
||||
|
||||
message HealthRequest {
|
||||
}
|
@@ -5,8 +5,8 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
proto "github.com/micro/go-micro/debug/proto"
|
||||
"github.com/micro/go-micro/registry/memory"
|
||||
proto "github.com/micro/go-micro/server/debug/proto"
|
||||
)
|
||||
|
||||
func TestFunction(t *testing.T) {
|
||||
|
48
go.mod
48
go.mod
@@ -3,8 +3,9 @@ module github.com/micro/go-micro
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.41.0 // indirect
|
||||
cloud.google.com/go v0.44.0 // indirect
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect
|
||||
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect
|
||||
github.com/armon/go-radix v1.0.0 // indirect
|
||||
@@ -14,17 +15,17 @@ require (
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
|
||||
github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/fsouza/go-dockerclient v1.4.1
|
||||
github.com/fsouza/go-dockerclient v1.4.2
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/gliderlabs/ssh v0.2.2 // indirect
|
||||
github.com/go-kit/kit v0.9.0 // indirect
|
||||
github.com/go-log/log v0.1.0
|
||||
github.com/go-playground/locales v0.12.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.16.0 // indirect
|
||||
github.com/golang/protobuf v1.3.2
|
||||
github.com/google/go-cmp v0.3.1 // indirect
|
||||
github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70 // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/handlers v1.4.1
|
||||
github.com/gorilla/mux v1.7.3 // indirect
|
||||
github.com/gorilla/handlers v1.4.2
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/hashicorp/consul/api v1.1.0
|
||||
github.com/hashicorp/go-immutable-radix v1.1.0 // indirect
|
||||
@@ -33,26 +34,28 @@ require (
|
||||
github.com/hashicorp/go-rootcerts v1.0.1 // indirect
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||
github.com/hashicorp/go-version v1.2.0 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.3 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0
|
||||
github.com/hashicorp/mdns v1.0.1 // indirect
|
||||
github.com/hashicorp/memberlist v0.1.4
|
||||
github.com/hashicorp/serf v0.8.3 // indirect
|
||||
github.com/imdario/mergo v0.3.7
|
||||
github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1
|
||||
github.com/json-iterator/go v1.1.6
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c // indirect
|
||||
github.com/json-iterator/go v1.1.7
|
||||
github.com/kisielk/errcheck v1.2.0 // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/kr/pty v1.1.8 // indirect
|
||||
github.com/leodido/go-urn v1.1.0 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031
|
||||
github.com/lucas-clemente/quic-go v0.12.0
|
||||
github.com/mattn/go-colorable v0.1.2 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.4 // indirect
|
||||
github.com/micro/cli v0.2.0
|
||||
github.com/micro/mdns v0.2.0
|
||||
github.com/micro/mdns v0.3.0
|
||||
github.com/miekg/dns v1.1.15 // indirect
|
||||
github.com/mitchellh/gox v1.0.1 // indirect
|
||||
github.com/mitchellh/hashstructure v1.0.0
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||
github.com/nats-io/nats.go v1.8.1
|
||||
github.com/nats-io/nkeys v0.1.0 // indirect
|
||||
github.com/nlopes/slack v0.5.0
|
||||
@@ -61,24 +64,17 @@ require (
|
||||
github.com/onsi/gomega v1.5.0 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/posener/complete v1.2.1 // indirect
|
||||
github.com/prometheus/common v0.6.0 // indirect
|
||||
github.com/prometheus/procfs v0.0.3 // indirect
|
||||
github.com/prometheus/client_golang v1.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2 // indirect
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
||||
golang.org/x/exp v0.0.0-20190627132806-fd42eb6b336f // indirect
|
||||
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9 // indirect
|
||||
golang.org/x/mobile v0.0.0-20190711165009-e47acb2ca7f9 // indirect
|
||||
golang.org/x/mod v0.1.0 // indirect
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7
|
||||
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 // indirect
|
||||
golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 // indirect
|
||||
google.golang.org/grpc v1.22.0
|
||||
gopkg.in/go-playground/validator.v9 v9.29.0
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.1 // indirect
|
||||
gopkg.in/src-d/go-git.v4 v4.12.0
|
||||
golang.org/x/mobile v0.0.0-20190806162312-597adff16ade // indirect
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80
|
||||
golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e // indirect
|
||||
golang.org/x/tools v0.0.0-20190809145639-6d4652c779c4 // indirect
|
||||
google.golang.org/grpc v1.22.1
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||
gopkg.in/telegram-bot-api.v4 v4.6.4
|
||||
honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b // indirect
|
||||
honnef.co/go/tools v0.0.1-2019.2.2 // indirect
|
||||
)
|
||||
|
66
go.sum
66
go.sum
@@ -3,15 +3,22 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro=
|
||||
cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg=
|
||||
cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg=
|
||||
cloud.google.com/go v0.44.0/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/Microsoft/go-winio v0.4.13/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
@@ -26,6 +33,7 @@ github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
|
||||
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
@@ -43,8 +51,12 @@ github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
|
||||
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16 h1:dmUn0SuGx7unKFwxyeQ/oLUHhEfZosEDrpmYM+6MTuc=
|
||||
github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b h1:+Ga+YpCDpcY1fln6GI0fiiirpqHGcob5/Vk3oKNuGdU=
|
||||
github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
@@ -61,6 +73,8 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsouza/go-dockerclient v1.4.1 h1:W7wuJ3IB48WYZv/UBk9dCTIb9oX805+L9KIm65HcUYs=
|
||||
github.com/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6VKyZvJ99hDjB0qs=
|
||||
github.com/fsouza/go-dockerclient v1.4.2 h1:dl6GfIWS5Qn4C6OfSnnoe6YuOV8lvKAE8W/YD1Q7udo=
|
||||
github.com/fsouza/go-dockerclient v1.4.2/go.mod h1:COunfLZrsdwX/j3YVDAG8gIw3KutrI0x1+vGEJ5zxdI=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
@@ -96,9 +110,12 @@ github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -108,6 +125,8 @@ github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZs
|
||||
github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/handlers v1.4.1 h1:BHvcRGJe/TrL+OqFxoKQGddTgeibiOjaBssV5a/N9sw=
|
||||
github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
@@ -150,6 +169,8 @@ github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCO
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
|
||||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
@@ -174,12 +195,16 @@ github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1 h1:lnrOS18wZBYrzdD
|
||||
github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1/go.mod h1:DFXrEwSRX0p/aSvxE21319menCBFeQO0jXpRj7LEZUA=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
|
||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c h1:VAx3LRNjVNvjtgO7KFRuT/3aye/0zJvwn01rHSfoolo=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
@@ -197,6 +222,8 @@ github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031 h1:wjcGvg
|
||||
github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031/go.mod h1:lb5aAxL68VvhZ00e7yYuQVK/9FLggtYy4qo7oI5qzqA=
|
||||
github.com/lucas-clemente/quic-go v0.11.2 h1:Mop0ac3zALaBR3wGs6j8OYe/tcFvFsxTUFMkE/7yUOI=
|
||||
github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=
|
||||
github.com/lucas-clemente/quic-go v0.12.0 h1:dYHUyB50gEQlK3KqytmNySzuyzAcaQ3iuI2ZReAfVrE=
|
||||
github.com/lucas-clemente/quic-go v0.12.0/go.mod h1:UXJJPE4RfFef/xPO5wQm0tITK8gNfqwTxjbE7s3Vb8s=
|
||||
github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI=
|
||||
github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA=
|
||||
github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||
@@ -204,6 +231,8 @@ github.com/marten-seemann/qtls v0.2.4 h1:mCJ6i1jAqcsm9XODrSGvXECodoAb1STta+TkxJC
|
||||
github.com/marten-seemann/qtls v0.2.4/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||
github.com/marten-seemann/qtls v0.3.1 h1:ySYIvhFjFY2JsNHY6VACvomMEDy3EvdPA6yciUFAiHw=
|
||||
github.com/marten-seemann/qtls v0.3.1/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||
github.com/marten-seemann/qtls v0.3.2 h1:O7awy4bHEzSX/K3h+fZig3/Vo03s/RxlxgsAk9sYamI=
|
||||
github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
@@ -219,6 +248,8 @@ github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478 h1:L6jnZZ763dMLlvst8P
|
||||
github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc=
|
||||
github.com/micro/mdns v0.2.0 h1:/+/n2PSiJURrXsBIGtfCz0hex/XYKqVsn51GAGdFrOE=
|
||||
github.com/micro/mdns v0.2.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc=
|
||||
github.com/micro/mdns v0.3.0 h1:bYycYe+98AXR3s8Nq5qvt6C573uFTDPIYzJemWON0QE=
|
||||
github.com/micro/mdns v0.3.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.3 h1:1g0r1IvskvgL8rR+AcHzUA+oFmGcQlaIm4IqakufeMM=
|
||||
github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
@@ -241,11 +272,14 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ=
|
||||
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
|
||||
github.com/nats-io/nkeys v0.0.2 h1:+qM7QpgXnvDDixitZtQUBDY9w/s9mu1ghS+JIbsrx6M=
|
||||
@@ -282,6 +316,7 @@ github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DK
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
@@ -301,6 +336,7 @@ github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAm
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
|
||||
@@ -339,9 +375,11 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190627132806-fd42eb6b336f/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190618124811-92942e4437e2/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -350,6 +388,7 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190607214518-6fa95d984e88/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20190711165009-e47acb2ca7f9/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mobile v0.0.0-20190806162312-597adff16ade/go.mod h1:AlhUtkH4DA4asiFC5RgK7ZKmauvtkAVcy9L0epCzlWo=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -375,6 +414,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwL
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -408,6 +449,12 @@ golang.org/x/sys v0.0.0-20190621062556-bf70e4678053/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ=
|
||||
golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M=
|
||||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e h1:TsjK5I7fXk8f2FQrgu6NS7i5Qih3knl2FL1htyguLRE=
|
||||
golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -429,12 +476,19 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
|
||||
golang.org/x/tools v0.0.0-20190530171427-2b03ca6e44eb/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190620191750-1fa568393b23/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190710184609-286818132824/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
golang.org/x/tools v0.0.0-20190807201305-8be58fba6352/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190809145639-6d4652c779c4/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -452,12 +506,17 @@ google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dT
|
||||
google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||
google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 h1:5pOB7se0B2+IssELuQUs6uoBgYJenkU2AQlvopc2sRw=
|
||||
google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64 h1:iKtrH9Y8mcbADOP0YFaEMth7OfuHY9xHOwNj4znpM1A=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw=
|
||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM=
|
||||
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -465,18 +524,24 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.0 h1:5ofssLNYgAA/inWn6rTZ4juWpRJUwEnXc1LG2IeXwgQ=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.1 h1:omN5CrMrMcQ+4I8bJ0wEhOBPanIRWzFC953IiXKdYzo=
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.1 h1:OkK1DmefDy1Z6Veu82wdNj/cLpYORhdX4qdaYCPwc7s=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git.v4 v4.11.0 h1:cJwWgJ0DXifrNrXM6RGN1Y2yR60Rr1zQ9Q5DX5S9qgU=
|
||||
gopkg.in/src-d/go-git.v4 v4.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk=
|
||||
gopkg.in/src-d/go-git.v4 v4.12.0 h1:CKgvBCJCcdfNnyXPYI4Cp8PaDDAmAPEN0CtfEdEAbd8=
|
||||
gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
||||
gopkg.in/telegram-bot-api.v4 v4.6.4 h1:hpHWhzn4jTCsAJZZ2loNKfy2QWyPDRJVl3aTFXeMW8g=
|
||||
gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
@@ -491,4 +556,5 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b/go.mod h1:JlmFZigtG9vBVR3QGIQ9g/Usz4BzH+Xm6Z8iHQWRYUw=
|
||||
honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
318
monitor/default.go
Normal file
318
monitor/default.go
Normal file
@@ -0,0 +1,318 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
pb "github.com/micro/go-micro/debug/proto"
|
||||
"github.com/micro/go-micro/registry"
|
||||
"github.com/micro/go-micro/registry/cache"
|
||||
)
|
||||
|
||||
type monitor struct {
|
||||
options Options
|
||||
|
||||
exit chan bool
|
||||
registry cache.Cache
|
||||
client client.Client
|
||||
|
||||
sync.RWMutex
|
||||
running bool
|
||||
services map[string]*Status
|
||||
}
|
||||
|
||||
// check provides binary running/failed status.
|
||||
// In the event Debug.Health cannot be called on a service we reap the node.
|
||||
func (m *monitor) check(service string) (*Status, error) {
|
||||
services, err := m.registry.GetService(service)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create debug client
|
||||
debug := pb.NewDebugService(service, m.client)
|
||||
|
||||
var status *Status
|
||||
var gerr error
|
||||
|
||||
// iterate through multiple versions of a service
|
||||
for _, service := range services {
|
||||
for _, node := range service.Nodes {
|
||||
// TODO: checks that are not just RPC based
|
||||
// TODO: better matching of the protocol
|
||||
// TODO: maybe everything has to be a go-micro service?
|
||||
if node.Metadata["server"] != m.client.String() {
|
||||
continue
|
||||
}
|
||||
|
||||
rsp, err := debug.Health(
|
||||
context.Background(),
|
||||
// empty health request
|
||||
&pb.HealthRequest{},
|
||||
// call this specific node
|
||||
client.WithAddress(node.Address),
|
||||
// retry in the event of failure
|
||||
client.WithRetries(3),
|
||||
)
|
||||
if err != nil {
|
||||
// reap the dead node
|
||||
m.registry.Deregister(®istry.Service{
|
||||
Name: service.Name,
|
||||
Version: service.Version,
|
||||
Nodes: []*registry.Node{node},
|
||||
})
|
||||
|
||||
// save the error
|
||||
gerr = err
|
||||
continue
|
||||
}
|
||||
|
||||
// expecting ok response status
|
||||
if rsp.Status != "ok" {
|
||||
gerr = errors.New(rsp.Status)
|
||||
continue
|
||||
}
|
||||
|
||||
// no error set status
|
||||
status = &Status{
|
||||
Code: StatusRunning,
|
||||
Info: "running",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we got the success case return it
|
||||
if status != nil {
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// if gerr is not nil return it
|
||||
if gerr != nil {
|
||||
return &Status{
|
||||
Code: StatusFailed,
|
||||
Info: "not running",
|
||||
Error: gerr.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// otherwise unknown status
|
||||
return &Status{
|
||||
Code: StatusUnknown,
|
||||
Info: "unknown status",
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *monitor) reap() {
|
||||
services, err := m.registry.ListServices()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
serviceMap := make(map[string]bool)
|
||||
for _, service := range services {
|
||||
serviceMap[service.Name] = true
|
||||
}
|
||||
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
// range over our watched services
|
||||
for service, _ := range m.services {
|
||||
// check if the service exists in the registry
|
||||
if !serviceMap[service] {
|
||||
// if not, delete it in our status map
|
||||
delete(m.services, service)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *monitor) run() {
|
||||
// check the status every tick
|
||||
t := time.NewTicker(time.Minute)
|
||||
defer t.Stop()
|
||||
|
||||
// reap dead services
|
||||
t2 := time.NewTicker(time.Hour)
|
||||
defer t2.Stop()
|
||||
|
||||
// list the known services
|
||||
services, _ := m.registry.ListServices()
|
||||
|
||||
// create a check chan of same length
|
||||
check := make(chan string, len(services))
|
||||
|
||||
// front-load the services to watch
|
||||
for _, service := range services {
|
||||
check <- service.Name
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
// exit if we're told to
|
||||
case <-m.exit:
|
||||
return
|
||||
// check a service when told to
|
||||
case service := <-check:
|
||||
// check the status
|
||||
status, err := m.check(service)
|
||||
if err != nil {
|
||||
status = &Status{
|
||||
Code: StatusUnknown,
|
||||
Info: "unknown status",
|
||||
}
|
||||
}
|
||||
|
||||
// save the status
|
||||
m.Lock()
|
||||
m.services[service] = status
|
||||
m.Unlock()
|
||||
// on the tick interval get all services and issue a check
|
||||
case <-t.C:
|
||||
// create a list of services
|
||||
serviceMap := make(map[string]bool)
|
||||
|
||||
m.RLock()
|
||||
for service, _ := range m.services {
|
||||
serviceMap[service] = true
|
||||
}
|
||||
m.RUnlock()
|
||||
|
||||
go func() {
|
||||
// check the status of all watched services
|
||||
for service, _ := range serviceMap {
|
||||
select {
|
||||
case <-m.exit:
|
||||
return
|
||||
case check <- service:
|
||||
default:
|
||||
// barf if we block
|
||||
}
|
||||
}
|
||||
|
||||
// list services
|
||||
services, _ := m.registry.ListServices()
|
||||
|
||||
for _, service := range services {
|
||||
// start watching the service
|
||||
if ok := serviceMap[service.Name]; !ok {
|
||||
m.Watch(service.Name)
|
||||
}
|
||||
}
|
||||
}()
|
||||
case <-t2.C:
|
||||
// reap any dead/non-existent services
|
||||
m.reap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *monitor) Reap(service string) error {
|
||||
services, err := m.registry.GetService(service)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
delete(m.services, service)
|
||||
for _, service := range services {
|
||||
m.registry.Deregister(service)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *monitor) Status(service string) (Status, error) {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
if status, ok := m.services[service]; ok {
|
||||
return *status, nil
|
||||
}
|
||||
return Status{}, ErrNotWatching
|
||||
}
|
||||
|
||||
func (m *monitor) Watch(service string) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
// check if we're watching
|
||||
if _, ok := m.services[service]; ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// get the status
|
||||
status, err := m.check(service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the status
|
||||
m.services[service] = status
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *monitor) Run() error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if m.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
// reset the exit channel
|
||||
m.exit = make(chan bool)
|
||||
// setup a new cache
|
||||
m.registry = cache.New(m.options.Registry)
|
||||
|
||||
// start running
|
||||
go m.run()
|
||||
|
||||
// set to running
|
||||
m.running = true
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *monitor) Stop() error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if !m.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
select {
|
||||
case <-m.exit:
|
||||
return nil
|
||||
default:
|
||||
close(m.exit)
|
||||
for s, _ := range m.services {
|
||||
delete(m.services, s)
|
||||
}
|
||||
m.registry.Stop()
|
||||
m.running = false
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func newMonitor(opts ...Option) Monitor {
|
||||
options := Options{
|
||||
Client: client.DefaultClient,
|
||||
Registry: registry.DefaultRegistry,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &monitor{
|
||||
options: options,
|
||||
exit: make(chan bool),
|
||||
client: options.Client,
|
||||
registry: cache.New(options.Registry),
|
||||
services: make(map[string]*Status),
|
||||
}
|
||||
}
|
37
monitor/default_test.go
Normal file
37
monitor/default_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMonitor(t *testing.T) {
|
||||
// create new monitor
|
||||
m := NewMonitor()
|
||||
|
||||
if err := m.Run(); err != nil {
|
||||
t.Fatalf("failed to stop monitor: %v", err)
|
||||
}
|
||||
|
||||
services := []string{"foo", "bar", "baz"}
|
||||
|
||||
for _, service := range services {
|
||||
_, err := m.Status(service)
|
||||
if err == nil {
|
||||
t.Fatal("expected status error for unknown service")
|
||||
}
|
||||
|
||||
if err := m.Watch(service); err == nil {
|
||||
t.Fatal("expected watch error for unknown service")
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// 1. start a service
|
||||
// 2. watch service
|
||||
// 3. get service status
|
||||
}
|
||||
|
||||
// stop monitor
|
||||
if err := m.Stop(); err != nil {
|
||||
t.Fatalf("failed to stop monitor: %v", err)
|
||||
}
|
||||
}
|
43
monitor/monitor.go
Normal file
43
monitor/monitor.go
Normal file
@@ -0,0 +1,43 @@
|
||||
// Package monitor monitors service health
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
StatusUnknown StatusCode = iota
|
||||
StatusRunning
|
||||
StatusFailed
|
||||
)
|
||||
|
||||
type StatusCode int
|
||||
|
||||
// Monitor monitors a service and reaps dead instances
|
||||
type Monitor interface {
|
||||
// Reap a service and stop monitoring
|
||||
Reap(service string) error
|
||||
// Status of the service
|
||||
Status(service string) (Status, error)
|
||||
// Watch starts watching the service
|
||||
Watch(service string) error
|
||||
// Run the monitor to watch all services
|
||||
Run() error
|
||||
// Stop monitoring
|
||||
Stop() error
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
Code StatusCode
|
||||
Info string
|
||||
Error string
|
||||
}
|
||||
|
||||
var (
|
||||
ErrNotWatching = errors.New("not watching")
|
||||
)
|
||||
|
||||
// NewMonitor returns a new monitor
|
||||
func NewMonitor(opts ...Option) Monitor {
|
||||
return newMonitor(opts...)
|
||||
}
|
25
monitor/options.go
Normal file
25
monitor/options.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/registry"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Client client.Client
|
||||
Registry registry.Registry
|
||||
}
|
||||
|
||||
type Option func(*Options)
|
||||
|
||||
func Client(c client.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
}
|
||||
}
|
||||
|
||||
func Registry(r registry.Registry) Option {
|
||||
return func(o *Options) {
|
||||
o.Registry = r
|
||||
}
|
||||
}
|
2
network/network.go
Normal file
2
network/network.go
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package network is for creating internetworks
|
||||
package network
|
@@ -1,337 +0,0 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/network/link"
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
// tun represents a network tunnel
|
||||
type tun struct {
|
||||
// the link on top of which we build a tunnel
|
||||
link link.Link
|
||||
|
||||
sync.RWMutex
|
||||
|
||||
// to indicate if we're connected or not
|
||||
connected bool
|
||||
|
||||
// the send channel for all messages
|
||||
send chan *message
|
||||
|
||||
// close channel
|
||||
closed chan bool
|
||||
|
||||
// a map of sockets based on Micro-Tunnel-Id
|
||||
sockets map[string]*socket
|
||||
}
|
||||
|
||||
// create new tunnel on top of a link
|
||||
func newTunnel(link link.Link) *tun {
|
||||
return &tun{
|
||||
link: link,
|
||||
send: make(chan *message, 128),
|
||||
closed: make(chan bool),
|
||||
sockets: make(map[string]*socket),
|
||||
}
|
||||
}
|
||||
|
||||
// getSocket returns a socket from the internal socket map.
|
||||
// It does this based on the Micro-Tunnel-Id and Micro-Tunnel-Session
|
||||
func (t *tun) getSocket(id, session string) (*socket, bool) {
|
||||
// get the socket
|
||||
t.RLock()
|
||||
s, ok := t.sockets[id+session]
|
||||
t.RUnlock()
|
||||
return s, ok
|
||||
}
|
||||
|
||||
// newSocket creates a new socket and saves it
|
||||
func (t *tun) newSocket(id, session string) (*socket, bool) {
|
||||
// hash the id
|
||||
h := sha256.New()
|
||||
h.Write([]byte(id))
|
||||
id = fmt.Sprintf("%x", h.Sum(nil))
|
||||
|
||||
// new socket
|
||||
s := &socket{
|
||||
id: id,
|
||||
session: session,
|
||||
closed: make(chan bool),
|
||||
recv: make(chan *message, 128),
|
||||
send: t.send,
|
||||
wait: make(chan bool),
|
||||
}
|
||||
|
||||
// save socket
|
||||
t.Lock()
|
||||
_, ok := t.sockets[id+session]
|
||||
if ok {
|
||||
// socket already exists
|
||||
t.Unlock()
|
||||
return nil, false
|
||||
}
|
||||
t.sockets[id+session] = s
|
||||
t.Unlock()
|
||||
|
||||
// return socket
|
||||
return s, true
|
||||
}
|
||||
|
||||
// TODO: use tunnel id as part of the session
|
||||
func (t *tun) newSession() string {
|
||||
return uuid.New().String()
|
||||
}
|
||||
|
||||
// process outgoing messages sent by all local sockets
|
||||
func (t *tun) process() {
|
||||
// manage the send buffer
|
||||
// all pseudo sockets throw everything down this
|
||||
for {
|
||||
select {
|
||||
case msg := <-t.send:
|
||||
nmsg := &transport.Message{
|
||||
Header: msg.data.Header,
|
||||
Body: msg.data.Body,
|
||||
}
|
||||
|
||||
// set the tunnel id on the outgoing message
|
||||
nmsg.Header["Micro-Tunnel-Id"] = msg.id
|
||||
|
||||
// set the session id
|
||||
nmsg.Header["Micro-Tunnel-Session"] = msg.session
|
||||
|
||||
// send the message via the interface
|
||||
if err := t.link.Send(nmsg); err != nil {
|
||||
// no op
|
||||
// TODO: do something
|
||||
}
|
||||
case <-t.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process incoming messages
|
||||
func (t *tun) listen() {
|
||||
for {
|
||||
// process anything via the net interface
|
||||
msg := new(transport.Message)
|
||||
err := t.link.Recv(msg)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// first check Micro-Tunnel
|
||||
switch msg.Header["Micro-Tunnel"] {
|
||||
case "connect":
|
||||
// assuming new connection
|
||||
// TODO: do something with this
|
||||
continue
|
||||
case "close":
|
||||
// assuming connection closed
|
||||
// TODO: do something with this
|
||||
continue
|
||||
}
|
||||
|
||||
// the tunnel id
|
||||
id := msg.Header["Micro-Tunnel-Id"]
|
||||
|
||||
// the session id
|
||||
session := msg.Header["Micro-Tunnel-Session"]
|
||||
|
||||
// if the session id is blank there's nothing we can do
|
||||
// TODO: check this is the case, is there any reason
|
||||
// why we'd have a blank session? Is the tunnel
|
||||
// used for some other purpose?
|
||||
if len(id) == 0 || len(session) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// get the socket based on the tunnel id and session
|
||||
// this could be something we dialed in which case
|
||||
// we have a session for it otherwise its a listener
|
||||
s, exists := t.getSocket(id, session)
|
||||
if !exists {
|
||||
// try get it based on just the tunnel id
|
||||
// the assumption here is that a listener
|
||||
// has no session but its set a listener session
|
||||
s, exists = t.getSocket(id, "listener")
|
||||
if !exists {
|
||||
// drop it, we don't care about
|
||||
// messages we don't know about
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// is the socket closed?
|
||||
select {
|
||||
case <-s.closed:
|
||||
// closed
|
||||
delete(t.sockets, id)
|
||||
continue
|
||||
default:
|
||||
// process
|
||||
}
|
||||
|
||||
// is the socket new?
|
||||
select {
|
||||
// if its new the socket is actually blocked waiting
|
||||
// for a connection. so we check if its waiting.
|
||||
case <-s.wait:
|
||||
// if its waiting e.g its new then we close it
|
||||
default:
|
||||
// set remote address of the socket
|
||||
s.remote = msg.Header["Remote"]
|
||||
close(s.wait)
|
||||
}
|
||||
|
||||
// construct a new transport message
|
||||
tmsg := &transport.Message{
|
||||
Header: msg.Header,
|
||||
Body: msg.Body,
|
||||
}
|
||||
|
||||
// construct the internal message
|
||||
imsg := &message{
|
||||
id: id,
|
||||
session: session,
|
||||
data: tmsg,
|
||||
}
|
||||
|
||||
// append to recv backlog
|
||||
// we don't block if we can't pass it on
|
||||
select {
|
||||
case s.recv <- imsg:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *tun) connect() error {
|
||||
return t.link.Send(&transport.Message{
|
||||
Header: map[string]string{
|
||||
"Micro-Tunnel": "connect",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (t *tun) close() error {
|
||||
return t.link.Send(&transport.Message{
|
||||
Header: map[string]string{
|
||||
"Micro-Tunnel": "close",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Close the tunnel
|
||||
func (t *tun) Close() error {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
if !t.connected {
|
||||
return nil
|
||||
}
|
||||
|
||||
select {
|
||||
case <-t.closed:
|
||||
return nil
|
||||
default:
|
||||
// close all the sockets
|
||||
for _, s := range t.sockets {
|
||||
s.Close()
|
||||
}
|
||||
// close the connection
|
||||
close(t.closed)
|
||||
t.connected = false
|
||||
|
||||
// send a close message
|
||||
// we don't close the link
|
||||
// just the tunnel
|
||||
return t.close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Connect the tunnel
|
||||
func (t *tun) Connect() error {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
// already connected
|
||||
if t.connected {
|
||||
return nil
|
||||
}
|
||||
|
||||
// send the connect message
|
||||
if err := t.connect(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set as connected
|
||||
t.connected = true
|
||||
// create new close channel
|
||||
t.closed = make(chan bool)
|
||||
|
||||
// process messages to be sent
|
||||
go t.process()
|
||||
// process incoming messages
|
||||
go t.listen()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dial an address
|
||||
func (t *tun) Dial(addr string) (Conn, error) {
|
||||
c, ok := t.newSocket(addr, t.newSession())
|
||||
if !ok {
|
||||
return nil, errors.New("error dialing " + addr)
|
||||
}
|
||||
// set remote
|
||||
c.remote = addr
|
||||
// set local
|
||||
c.local = t.link.Local()
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Accept a connection on the address
|
||||
func (t *tun) Listen(addr string) (Listener, error) {
|
||||
// create a new socket by hashing the address
|
||||
c, ok := t.newSocket(addr, "listener")
|
||||
if !ok {
|
||||
return nil, errors.New("already listening on " + addr)
|
||||
}
|
||||
|
||||
// set remote. it will be replaced by the first message received
|
||||
c.remote = t.link.Remote()
|
||||
// set local
|
||||
c.local = addr
|
||||
|
||||
tl := &tunListener{
|
||||
addr: addr,
|
||||
// the accept channel
|
||||
accept: make(chan *socket, 128),
|
||||
// the channel to close
|
||||
closed: make(chan bool),
|
||||
// the connection
|
||||
conn: c,
|
||||
// the listener socket
|
||||
socket: c,
|
||||
}
|
||||
|
||||
// this kicks off the internal message processor
|
||||
// for the listener so it can create pseudo sockets
|
||||
// per session if they do not exist or pass messages
|
||||
// to the existign sessions
|
||||
go tl.process()
|
||||
|
||||
// return the listener
|
||||
return tl, nil
|
||||
}
|
@@ -1,113 +0,0 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/network/link"
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
// testAccept will accept connections on the transport, create a new link and tunnel on top
|
||||
func testAccept(t *testing.T, l transport.Listener, wait chan bool) error {
|
||||
// accept new connections on the transport
|
||||
// establish a link and tunnel
|
||||
return l.Accept(func(s transport.Socket) {
|
||||
// convert the socket into a link
|
||||
li := link.NewLink(
|
||||
link.Socket(s),
|
||||
)
|
||||
|
||||
// connect the link e.g start internal buffers
|
||||
if err := li.Connect(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// create a new tunnel
|
||||
tun := NewTunnel(li)
|
||||
|
||||
// connect the tunnel
|
||||
if err := tun.Connect(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// listen on some virtual address
|
||||
tl, err := tun.Listen("test-tunnel")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
// accept a connection
|
||||
c, err := tl.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// get a message
|
||||
for {
|
||||
m := new(transport.Message)
|
||||
if err := c.Recv(m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
close(wait)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// testSend will create a new link to an address and then a tunnel on top
|
||||
func testSend(t *testing.T, addr string) {
|
||||
// create a new link
|
||||
l := link.NewLink(
|
||||
link.Address(addr),
|
||||
)
|
||||
|
||||
// connect the link, this includes dialing
|
||||
if err := l.Connect(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// create a tunnel on the link
|
||||
tun := NewTunnel(l)
|
||||
|
||||
// connect the tunnel with the remote side
|
||||
if err := tun.Connect(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// dial a new session
|
||||
c, err := tun.Dial("test-tunnel")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
m := transport.Message{
|
||||
Header: map[string]string{
|
||||
"test": "header",
|
||||
},
|
||||
}
|
||||
if err := c.Send(&m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTunnel(t *testing.T) {
|
||||
// create a new listener
|
||||
tr := transport.NewTransport()
|
||||
l, err := tr.Listen(":0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
wait := make(chan bool)
|
||||
|
||||
// start accepting connections
|
||||
go testAccept(t, l, wait)
|
||||
|
||||
// send a message
|
||||
testSend(t, l.Addr())
|
||||
|
||||
// wait until message is received
|
||||
<-wait
|
||||
}
|
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/micro/go-micro/client/grpc"
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/network/proxy"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
|
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/errors"
|
||||
"github.com/micro/go-micro/network/proxy"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
|
@@ -12,8 +12,8 @@ import (
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/codec/bytes"
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/network/proxy"
|
||||
"github.com/micro/go-micro/network/router"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/router"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
|
||||
@@ -99,14 +99,14 @@ func (p *Proxy) getRoute(service string) ([]string, error) {
|
||||
p.Routes[service] = make(map[uint64]router.Route)
|
||||
p.Unlock()
|
||||
|
||||
// if the router is broken return error
|
||||
if status := p.Router.Status(); status.Code == router.Error {
|
||||
return nil, status.Error
|
||||
}
|
||||
|
||||
// lookup the routes in the router
|
||||
results, err := p.Router.Lookup(router.NewQuery(router.QueryService(service)))
|
||||
if err != nil {
|
||||
// check the status of the router
|
||||
if status := p.Router.Status(); status.Code == router.Error {
|
||||
return nil, status.Error
|
||||
}
|
||||
// otherwise return the error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -220,6 +220,23 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server
|
||||
// create new request with raw bytes body
|
||||
creq := p.Client.NewRequest(service, endpoint, &bytes.Frame{body}, client.WithContentType(req.ContentType()))
|
||||
|
||||
// not a stream so make a client.Call request
|
||||
if !req.Stream() {
|
||||
crsp := new(bytes.Frame)
|
||||
|
||||
// make a call to the backend
|
||||
if err := p.Client.Call(ctx, creq, crsp, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// write the response
|
||||
if err := rsp.Write(crsp.Data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// create new stream
|
||||
stream, err := p.Client.Stream(ctx, creq, opts...)
|
||||
if err != nil {
|
||||
@@ -227,7 +244,7 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
// create client request read loop
|
||||
// create client request read loop if streaming
|
||||
go readLoop(req, stream)
|
||||
|
||||
// get raw response
|
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/network/router"
|
||||
"github.com/micro/go-micro/router"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
|
15
registry/cache/rcache.go
vendored
15
registry/cache/rcache.go
vendored
@@ -325,18 +325,27 @@ func (c *cache) run(service string) {
|
||||
// watch loops the next event and calls update
|
||||
// it returns if there's an error
|
||||
func (c *cache) watch(w registry.Watcher) error {
|
||||
defer w.Stop()
|
||||
// used to stop the watch
|
||||
stop := make(chan bool)
|
||||
|
||||
// manage this loop
|
||||
go func() {
|
||||
defer w.Stop()
|
||||
|
||||
select {
|
||||
// wait for exit
|
||||
<-c.exit
|
||||
w.Stop()
|
||||
case <-c.exit:
|
||||
return
|
||||
// we've been stopped
|
||||
case <-stop:
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
res, err := w.Next()
|
||||
if err != nil {
|
||||
close(stop)
|
||||
return err
|
||||
}
|
||||
c.update(res)
|
||||
|
@@ -13,14 +13,17 @@ import (
|
||||
|
||||
consul "github.com/hashicorp/consul/api"
|
||||
"github.com/micro/go-micro/registry"
|
||||
mnet "github.com/micro/go-micro/util/net"
|
||||
hash "github.com/mitchellh/hashstructure"
|
||||
)
|
||||
|
||||
type consulRegistry struct {
|
||||
Address string
|
||||
Client *consul.Client
|
||||
Address []string
|
||||
opts registry.Options
|
||||
|
||||
client *consul.Client
|
||||
config *consul.Config
|
||||
|
||||
// connect enabled
|
||||
connect bool
|
||||
|
||||
@@ -95,24 +98,33 @@ func configure(c *consulRegistry, opts ...registry.Option) {
|
||||
}
|
||||
|
||||
// check if there are any addrs
|
||||
if len(c.opts.Addrs) > 0 {
|
||||
addr, port, err := net.SplitHostPort(c.opts.Addrs[0])
|
||||
var addrs []string
|
||||
|
||||
// iterate the options addresses
|
||||
for _, address := range c.opts.Addrs {
|
||||
// check we have a port
|
||||
addr, port, err := net.SplitHostPort(address)
|
||||
if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
|
||||
port = "8500"
|
||||
addr = c.opts.Addrs[0]
|
||||
config.Address = fmt.Sprintf("%s:%s", addr, port)
|
||||
addr = address
|
||||
addrs = append(addrs, fmt.Sprintf("%s:%s", addr, port))
|
||||
} else if err == nil {
|
||||
config.Address = fmt.Sprintf("%s:%s", addr, port)
|
||||
addrs = append(addrs, fmt.Sprintf("%s:%s", addr, port))
|
||||
}
|
||||
}
|
||||
|
||||
// set the addrs
|
||||
if len(addrs) > 0 {
|
||||
c.Address = addrs
|
||||
config.Address = c.Address[0]
|
||||
}
|
||||
|
||||
if config.HttpClient == nil {
|
||||
config.HttpClient = new(http.Client)
|
||||
}
|
||||
|
||||
// requires secure connection?
|
||||
if c.opts.Secure || c.opts.TLSConfig != nil {
|
||||
|
||||
config.Scheme = "https"
|
||||
// We're going to support InsecureSkipVerify
|
||||
config.HttpClient.Transport = newTransport(c.opts.TLSConfig)
|
||||
@@ -123,12 +135,14 @@ func configure(c *consulRegistry, opts ...registry.Option) {
|
||||
config.HttpClient.Timeout = c.opts.Timeout
|
||||
}
|
||||
|
||||
// create the client
|
||||
client, _ := consul.NewClient(config)
|
||||
// set the config
|
||||
c.config = config
|
||||
|
||||
// set address/client
|
||||
c.Address = config.Address
|
||||
c.Client = client
|
||||
// remove client
|
||||
c.client = nil
|
||||
|
||||
// setup the client
|
||||
c.Client()
|
||||
}
|
||||
|
||||
func (c *consulRegistry) Init(opts ...registry.Option) error {
|
||||
@@ -148,7 +162,7 @@ func (c *consulRegistry) Deregister(s *registry.Service) error {
|
||||
c.Unlock()
|
||||
|
||||
node := s.Nodes[0]
|
||||
return c.Client.Agent().ServiceDeregister(node.Id)
|
||||
return c.Client().Agent().ServiceDeregister(node.Id)
|
||||
}
|
||||
|
||||
func (c *consulRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
|
||||
@@ -193,7 +207,7 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register
|
||||
if time.Since(lastChecked) <= getDeregisterTTL(regInterval) {
|
||||
return nil
|
||||
}
|
||||
services, _, err := c.Client.Health().Checks(s.Name, c.queryOptions)
|
||||
services, _, err := c.Client().Health().Checks(s.Name, c.queryOptions)
|
||||
if err == nil {
|
||||
for _, v := range services {
|
||||
if v.ServiceID == node.Id {
|
||||
@@ -204,7 +218,7 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register
|
||||
} else {
|
||||
// if the err is nil we're all good, bail out
|
||||
// if not, we don't know what the state is, so full re-register
|
||||
if err := c.Client.Agent().PassTTL("service:"+node.Id, ""); err == nil {
|
||||
if err := c.Client().Agent().PassTTL("service:"+node.Id, ""); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -237,6 +251,9 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register
|
||||
}
|
||||
|
||||
host, pt, _ := net.SplitHostPort(node.Address)
|
||||
if host == "" {
|
||||
host = node.Address
|
||||
}
|
||||
port, _ := strconv.Atoi(pt)
|
||||
|
||||
// register the service
|
||||
@@ -256,7 +273,7 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.Client.Agent().ServiceRegister(asr); err != nil {
|
||||
if err := c.Client().Agent().ServiceRegister(asr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -272,7 +289,7 @@ func (c *consulRegistry) Register(s *registry.Service, opts ...registry.Register
|
||||
}
|
||||
|
||||
// pass the healthcheck
|
||||
return c.Client.Agent().PassTTL("service:"+node.Id, "")
|
||||
return c.Client().Agent().PassTTL("service:"+node.Id, "")
|
||||
}
|
||||
|
||||
func (c *consulRegistry) GetService(name string) ([]*registry.Service, error) {
|
||||
@@ -281,9 +298,9 @@ func (c *consulRegistry) GetService(name string) ([]*registry.Service, error) {
|
||||
|
||||
// if we're connect enabled only get connect services
|
||||
if c.connect {
|
||||
rsp, _, err = c.Client.Health().Connect(name, "", false, c.queryOptions)
|
||||
rsp, _, err = c.Client().Health().Connect(name, "", false, c.queryOptions)
|
||||
} else {
|
||||
rsp, _, err = c.Client.Health().Service(name, "", false, c.queryOptions)
|
||||
rsp, _, err = c.Client().Health().Service(name, "", false, c.queryOptions)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -338,7 +355,7 @@ func (c *consulRegistry) GetService(name string) ([]*registry.Service, error) {
|
||||
|
||||
svc.Nodes = append(svc.Nodes, ®istry.Node{
|
||||
Id: id,
|
||||
Address: fmt.Sprintf("%s:%d", address, s.Service.Port),
|
||||
Address: mnet.HostPort(address, s.Service.Port),
|
||||
Metadata: decodeMetadata(s.Service.Tags),
|
||||
})
|
||||
}
|
||||
@@ -351,7 +368,7 @@ func (c *consulRegistry) GetService(name string) ([]*registry.Service, error) {
|
||||
}
|
||||
|
||||
func (c *consulRegistry) ListServices() ([]*registry.Service, error) {
|
||||
rsp, _, err := c.Client.Catalog().Services(c.queryOptions)
|
||||
rsp, _, err := c.Client().Catalog().Services(c.queryOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -377,6 +394,36 @@ func (c *consulRegistry) Options() registry.Options {
|
||||
return c.opts
|
||||
}
|
||||
|
||||
func (c *consulRegistry) Client() *consul.Client {
|
||||
if c.client != nil {
|
||||
return c.client
|
||||
}
|
||||
|
||||
for _, addr := range c.Address {
|
||||
// set the address
|
||||
c.config.Address = addr
|
||||
|
||||
// create a new client
|
||||
tmpClient, _ := consul.NewClient(c.config)
|
||||
|
||||
// test the client
|
||||
_, err := tmpClient.Agent().Host()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// set the client
|
||||
c.client = tmpClient
|
||||
return c.client
|
||||
}
|
||||
|
||||
// set the default
|
||||
c.client, _ = consul.NewClient(c.config)
|
||||
|
||||
// return the client
|
||||
return c.client
|
||||
}
|
||||
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
cr := &consulRegistry{
|
||||
opts: registry.Options{},
|
||||
|
@@ -50,22 +50,24 @@ func newConsulTestRegistry(r *mockRegistry) (*consulRegistry, func()) {
|
||||
}
|
||||
cfg := consul.DefaultConfig()
|
||||
cfg.Address = l.Addr().String()
|
||||
cl, _ := consul.NewClient(cfg)
|
||||
|
||||
go newMockServer(r, l)
|
||||
|
||||
return &consulRegistry{
|
||||
Address: cfg.Address,
|
||||
Client: cl,
|
||||
opts: registry.Options{},
|
||||
register: make(map[string]uint64),
|
||||
lastChecked: make(map[string]time.Time),
|
||||
queryOptions: &consul.QueryOptions{
|
||||
AllowStale: true,
|
||||
},
|
||||
}, func() {
|
||||
l.Close()
|
||||
}
|
||||
var cr = &consulRegistry{
|
||||
config: cfg,
|
||||
Address: []string{cfg.Address},
|
||||
opts: registry.Options{},
|
||||
register: make(map[string]uint64),
|
||||
lastChecked: make(map[string]time.Time),
|
||||
queryOptions: &consul.QueryOptions{
|
||||
AllowStale: true,
|
||||
},
|
||||
}
|
||||
cr.Client()
|
||||
|
||||
return cr, func() {
|
||||
l.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func newServiceList(svc []*consul.ServiceEntry) []byte {
|
||||
|
@@ -45,7 +45,7 @@ func newConsulWatcher(cr *consulRegistry, opts ...registry.WatchOption) (registr
|
||||
}
|
||||
|
||||
wp.Handler = cw.handle
|
||||
go wp.RunWithClientAndLogger(cr.Client, log.New(os.Stderr, "", log.LstdFlags))
|
||||
go wp.RunWithClientAndLogger(cr.Client(), log.New(os.Stderr, "", log.LstdFlags))
|
||||
cw.wp = wp
|
||||
|
||||
return cw, nil
|
||||
@@ -209,7 +209,7 @@ func (cw *consulWatcher) handle(idx uint64, data interface{}) {
|
||||
})
|
||||
if err == nil {
|
||||
wp.Handler = cw.serviceHandler
|
||||
go wp.RunWithClientAndLogger(cw.r.Client, log.New(os.Stderr, "", log.LstdFlags))
|
||||
go wp.RunWithClientAndLogger(cw.r.Client(), log.New(os.Stderr, "", log.LstdFlags))
|
||||
cw.watchers[service] = wp
|
||||
cw.next <- ®istry.Result{Action: "create", Service: ®istry.Service{Name: service}}
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ var (
|
||||
DefaultRegistry = NewRegistry()
|
||||
|
||||
// Not found error when GetService is called
|
||||
ErrNotFound = errors.New("not found")
|
||||
ErrNotFound = errors.New("service not found")
|
||||
// Watcher stopped error when watcher is stopped
|
||||
ErrWatcherStopped = errors.New("watcher stopped")
|
||||
)
|
||||
|
@@ -43,10 +43,9 @@ var (
|
||||
// router implements default router
|
||||
type router struct {
|
||||
sync.RWMutex
|
||||
// embed the table
|
||||
table *table
|
||||
opts Options
|
||||
status Status
|
||||
table *table
|
||||
exit chan struct{}
|
||||
errChan chan error
|
||||
eventChan chan *Event
|
||||
@@ -67,33 +66,41 @@ func newRouter(opts ...Option) Router {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
r := &router{
|
||||
table: newTable(),
|
||||
// set initial status to Stopped
|
||||
status := Status{Code: Stopped, Error: nil}
|
||||
|
||||
return &router{
|
||||
opts: options,
|
||||
status: Status{Code: Stopped, Error: nil},
|
||||
status: status,
|
||||
table: newTable(),
|
||||
advertWg: &sync.WaitGroup{},
|
||||
wg: &sync.WaitGroup{},
|
||||
subscribers: make(map[string]chan *Advert),
|
||||
}
|
||||
|
||||
go r.run()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Init initializes router with given options
|
||||
func (r *router) Init(opts ...Option) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
for _, o := range opts {
|
||||
o(&r.opts)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Options returns router options
|
||||
func (r *router) Options() Options {
|
||||
return r.opts
|
||||
r.Lock()
|
||||
opts := r.opts
|
||||
r.Unlock()
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
// Table returns routing table
|
||||
func (r *router) Table() Table {
|
||||
return r.table
|
||||
}
|
||||
@@ -177,10 +184,24 @@ func (r *router) watchRegistry(w registry.Watcher) error {
|
||||
// wait in the background for the router to stop
|
||||
// when the router stops, stop the watcher and exit
|
||||
r.wg.Add(1)
|
||||
|
||||
exit := make(chan bool)
|
||||
|
||||
defer func() {
|
||||
// close the exit channel when the go routine finishes
|
||||
close(exit)
|
||||
r.wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer r.wg.Done()
|
||||
<-r.exit
|
||||
w.Stop()
|
||||
defer w.Stop()
|
||||
|
||||
select {
|
||||
case <-r.exit:
|
||||
return
|
||||
case <-exit:
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
var watchErr error
|
||||
@@ -208,10 +229,23 @@ func (r *router) watchTable(w Watcher) error {
|
||||
// wait in the background for the router to stop
|
||||
// when the router stops, stop the watcher and exit
|
||||
r.wg.Add(1)
|
||||
exit := make(chan bool)
|
||||
|
||||
defer func() {
|
||||
// close the exit channel when the go routine finishes
|
||||
close(exit)
|
||||
r.wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
defer r.wg.Done()
|
||||
<-r.exit
|
||||
w.Stop()
|
||||
defer w.Stop()
|
||||
|
||||
select {
|
||||
case <-r.exit:
|
||||
return
|
||||
case <-exit:
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
var watchErr error
|
||||
@@ -275,6 +309,7 @@ func (r *router) publishAdvert(advType AdvertType, events []*Event) {
|
||||
func (r *router) advertiseTable() error {
|
||||
// create table advertisement ticker
|
||||
ticker := time.NewTicker(AdvertiseTableTick)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
@@ -324,6 +359,8 @@ type routeAdvert struct {
|
||||
func (r *router) advertiseEvents() error {
|
||||
// ticker to periodically scan event for advertising
|
||||
ticker := time.NewTicker(AdvertiseEventsTick)
|
||||
defer ticker.Stop()
|
||||
|
||||
// advertMap is a map of advert events
|
||||
advertMap := make(map[uint64]*routeAdvert)
|
||||
|
||||
@@ -426,7 +463,6 @@ func (r *router) advertiseEvents() error {
|
||||
// update event penalty and recorded timestamp
|
||||
advert.lastUpdate = time.Now()
|
||||
advert.penalty += penalty
|
||||
|
||||
case <-r.exit:
|
||||
// first wait for the advertiser to finish
|
||||
r.advertWg.Wait()
|
||||
@@ -446,11 +482,12 @@ func (r *router) watchErrors() {
|
||||
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
// if the router is not stopped, stop it
|
||||
if r.status.Code != Stopped {
|
||||
// notify all goroutines to finish
|
||||
close(r.exit)
|
||||
|
||||
// drain the advertise channel only if advertising
|
||||
// drain the advertise channel only if the router is advertising
|
||||
if r.status.Code == Advertising {
|
||||
// drain the event channel
|
||||
for range r.eventChan {
|
||||
@@ -466,69 +503,67 @@ func (r *router) watchErrors() {
|
||||
}
|
||||
}
|
||||
|
||||
// Run runs the router.
|
||||
func (r *router) run() {
|
||||
// Start starts the router
|
||||
func (r *router) Start() error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
switch r.status.Code {
|
||||
case Stopped, Error:
|
||||
// add all local service routes into the routing table
|
||||
if err := r.manageRegistryRoutes(r.opts.Registry, "create"); err != nil {
|
||||
r.status = Status{Code: Error, Error: fmt.Errorf("failed adding registry routes: %s", err)}
|
||||
return
|
||||
}
|
||||
|
||||
// add default gateway into routing table
|
||||
if r.opts.Gateway != "" {
|
||||
// note, the only non-default value is the gateway
|
||||
route := Route{
|
||||
Service: "*",
|
||||
Address: "*",
|
||||
Gateway: r.opts.Gateway,
|
||||
Network: "*",
|
||||
Metric: DefaultLocalMetric,
|
||||
}
|
||||
if err := r.table.Create(route); err != nil {
|
||||
r.status = Status{Code: Error, Error: fmt.Errorf("failed adding default gateway route: %s", err)}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// create error and exit channels
|
||||
r.errChan = make(chan error, 1)
|
||||
r.exit = make(chan struct{})
|
||||
|
||||
// registry watcher
|
||||
regWatcher, err := r.opts.Registry.Watch()
|
||||
if err != nil {
|
||||
r.status = Status{Code: Error, Error: fmt.Errorf("failed creating registry watcher: %v", err)}
|
||||
return
|
||||
}
|
||||
|
||||
r.wg.Add(1)
|
||||
go func() {
|
||||
defer r.wg.Done()
|
||||
select {
|
||||
case r.errChan <- r.watchRegistry(regWatcher):
|
||||
case <-r.exit:
|
||||
}
|
||||
}()
|
||||
|
||||
// watch for errors and cleanup
|
||||
r.wg.Add(1)
|
||||
go func() {
|
||||
defer r.wg.Done()
|
||||
r.watchErrors()
|
||||
}()
|
||||
|
||||
// mark router as Running and set its Error to nil
|
||||
r.status = Status{Code: Running, Error: nil}
|
||||
|
||||
return
|
||||
// add all local service routes into the routing table
|
||||
if err := r.manageRegistryRoutes(r.opts.Registry, "create"); err != nil {
|
||||
e := fmt.Errorf("failed adding registry routes: %s", err)
|
||||
r.status = Status{Code: Error, Error: e}
|
||||
return e
|
||||
}
|
||||
|
||||
return
|
||||
// add default gateway into routing table
|
||||
if r.opts.Gateway != "" {
|
||||
// note, the only non-default value is the gateway
|
||||
route := Route{
|
||||
Service: "*",
|
||||
Address: "*",
|
||||
Gateway: r.opts.Gateway,
|
||||
Network: "*",
|
||||
Metric: DefaultLocalMetric,
|
||||
}
|
||||
if err := r.table.Create(route); err != nil {
|
||||
e := fmt.Errorf("failed adding default gateway route: %s", err)
|
||||
r.status = Status{Code: Error, Error: e}
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
// create error and exit channels
|
||||
r.errChan = make(chan error, 1)
|
||||
r.exit = make(chan struct{})
|
||||
|
||||
// registry watcher
|
||||
regWatcher, err := r.opts.Registry.Watch()
|
||||
if err != nil {
|
||||
e := fmt.Errorf("failed creating registry watcher: %v", err)
|
||||
r.status = Status{Code: Error, Error: e}
|
||||
return e
|
||||
}
|
||||
|
||||
r.wg.Add(1)
|
||||
go func() {
|
||||
defer r.wg.Done()
|
||||
select {
|
||||
case r.errChan <- r.watchRegistry(regWatcher):
|
||||
case <-r.exit:
|
||||
}
|
||||
}()
|
||||
|
||||
// watch for errors and cleanup
|
||||
r.wg.Add(1)
|
||||
go func() {
|
||||
defer r.wg.Done()
|
||||
r.watchErrors()
|
||||
}()
|
||||
|
||||
// mark router as Running
|
||||
r.status = Status{Code: Running, Error: nil}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Advertise stars advertising the routes to the network and returns the advertisements channel to consume from.
|
||||
@@ -549,6 +584,7 @@ func (r *router) Advertise() (<-chan *Advert, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed listing routes: %s", err)
|
||||
}
|
||||
|
||||
// collect all the added routes before we attempt to add default gateway
|
||||
events := make([]*Event, len(routes))
|
||||
for i, route := range routes {
|
180
router/handler/router.go
Normal file
180
router/handler/router.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/errors"
|
||||
"github.com/micro/go-micro/router"
|
||||
pb "github.com/micro/go-micro/router/proto"
|
||||
)
|
||||
|
||||
// Router implements router handler
|
||||
type Router struct {
|
||||
Router router.Router
|
||||
}
|
||||
|
||||
// Lookup looks up routes in the routing table and returns them
|
||||
func (r *Router) Lookup(ctx context.Context, req *pb.LookupRequest, resp *pb.LookupResponse) error {
|
||||
query := router.NewQuery(
|
||||
router.QueryService(req.Query.Service),
|
||||
)
|
||||
|
||||
routes, err := r.Router.Lookup(query)
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "failed to lookup routes: %v", err)
|
||||
}
|
||||
|
||||
var respRoutes []*pb.Route
|
||||
for _, route := range routes {
|
||||
respRoute := &pb.Route{
|
||||
Service: route.Service,
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Link: route.Link,
|
||||
Metric: int64(route.Metric),
|
||||
}
|
||||
respRoutes = append(respRoutes, respRoute)
|
||||
}
|
||||
|
||||
resp.Routes = respRoutes
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Advertise(ctx context.Context, req *pb.Request, stream pb.Router_AdvertiseStream) error {
|
||||
advertChan, err := r.Router.Advertise()
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "failed to get adverts: %v", err)
|
||||
}
|
||||
|
||||
for advert := range advertChan {
|
||||
var events []*pb.Event
|
||||
for _, event := range advert.Events {
|
||||
route := &pb.Route{
|
||||
Service: event.Route.Service,
|
||||
Address: event.Route.Address,
|
||||
Gateway: event.Route.Gateway,
|
||||
Network: event.Route.Network,
|
||||
Link: event.Route.Link,
|
||||
Metric: int64(event.Route.Metric),
|
||||
}
|
||||
e := &pb.Event{
|
||||
Type: pb.EventType(event.Type),
|
||||
Timestamp: event.Timestamp.UnixNano(),
|
||||
Route: route,
|
||||
}
|
||||
events = append(events, e)
|
||||
}
|
||||
|
||||
advert := &pb.Advert{
|
||||
Id: advert.Id,
|
||||
Type: pb.AdvertType(advert.Type),
|
||||
Timestamp: advert.Timestamp.UnixNano(),
|
||||
Events: events,
|
||||
}
|
||||
|
||||
// send the advert
|
||||
err := stream.Send(advert)
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "error sending message %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Process(ctx context.Context, req *pb.Advert, rsp *pb.ProcessResponse) error {
|
||||
events := make([]*router.Event, len(req.Events))
|
||||
for i, event := range req.Events {
|
||||
route := router.Route{
|
||||
Service: event.Route.Service,
|
||||
Address: event.Route.Address,
|
||||
Gateway: event.Route.Gateway,
|
||||
Network: event.Route.Network,
|
||||
Link: event.Route.Link,
|
||||
Metric: int(event.Route.Metric),
|
||||
}
|
||||
|
||||
events[i] = &router.Event{
|
||||
Type: router.EventType(event.Type),
|
||||
Timestamp: time.Unix(0, event.Timestamp),
|
||||
Route: route,
|
||||
}
|
||||
}
|
||||
|
||||
advert := &router.Advert{
|
||||
Id: req.Id,
|
||||
Type: router.AdvertType(req.Type),
|
||||
Timestamp: time.Unix(0, req.Timestamp),
|
||||
TTL: time.Duration(req.Ttl),
|
||||
Events: events,
|
||||
}
|
||||
|
||||
if err := r.Router.Process(advert); err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "error publishing advert: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Status(ctx context.Context, req *pb.Request, rsp *pb.StatusResponse) error {
|
||||
status := r.Router.Status()
|
||||
|
||||
rsp.Status = &pb.Status{
|
||||
Code: status.Code.String(),
|
||||
}
|
||||
|
||||
if status.Error != nil {
|
||||
rsp.Status.Error = status.Error.Error()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Watch streans routing table events
|
||||
func (r *Router) Watch(ctx context.Context, req *pb.WatchRequest, stream pb.Router_WatchStream) error {
|
||||
watcher, err := r.Router.Watch()
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "failed creating event watcher: %v", err)
|
||||
}
|
||||
|
||||
defer stream.Close()
|
||||
|
||||
for {
|
||||
event, err := watcher.Next()
|
||||
if err == router.ErrWatcherStopped {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "error watching events: %v", err)
|
||||
}
|
||||
|
||||
route := &pb.Route{
|
||||
Service: event.Route.Service,
|
||||
Address: event.Route.Address,
|
||||
Gateway: event.Route.Gateway,
|
||||
Network: event.Route.Network,
|
||||
Link: event.Route.Link,
|
||||
Metric: int64(event.Route.Metric),
|
||||
}
|
||||
|
||||
tableEvent := &pb.Event{
|
||||
Type: pb.EventType(event.Type),
|
||||
Timestamp: event.Timestamp.UnixNano(),
|
||||
Route: route,
|
||||
}
|
||||
|
||||
if err := stream.Send(tableEvent); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
114
router/handler/table.go
Normal file
114
router/handler/table.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/errors"
|
||||
"github.com/micro/go-micro/router"
|
||||
pb "github.com/micro/go-micro/router/proto"
|
||||
)
|
||||
|
||||
type Table struct {
|
||||
Router router.Router
|
||||
}
|
||||
|
||||
func (t *Table) Create(ctx context.Context, route *pb.Route, resp *pb.CreateResponse) error {
|
||||
err := t.Router.Table().Create(router.Route{
|
||||
Service: route.Service,
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Link: route.Link,
|
||||
Metric: int(route.Metric),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "failed to create route: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Table) Update(ctx context.Context, route *pb.Route, resp *pb.UpdateResponse) error {
|
||||
err := t.Router.Table().Update(router.Route{
|
||||
Service: route.Service,
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Link: route.Link,
|
||||
Metric: int(route.Metric),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "failed to update route: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Table) Delete(ctx context.Context, route *pb.Route, resp *pb.DeleteResponse) error {
|
||||
err := t.Router.Table().Delete(router.Route{
|
||||
Service: route.Service,
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Link: route.Link,
|
||||
Metric: int(route.Metric),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "failed to delete route: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// List returns all routes in the routing table
|
||||
func (t *Table) List(ctx context.Context, req *pb.Request, resp *pb.ListResponse) error {
|
||||
routes, err := t.Router.Table().List()
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "failed to list routes: %s", err)
|
||||
}
|
||||
|
||||
var respRoutes []*pb.Route
|
||||
for _, route := range routes {
|
||||
respRoute := &pb.Route{
|
||||
Service: route.Service,
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Link: route.Link,
|
||||
Metric: int64(route.Metric),
|
||||
}
|
||||
respRoutes = append(respRoutes, respRoute)
|
||||
}
|
||||
|
||||
resp.Routes = respRoutes
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Table) Query(ctx context.Context, req *pb.QueryRequest, resp *pb.QueryResponse) error {
|
||||
query := router.NewQuery(
|
||||
router.QueryService(req.Query.Service),
|
||||
)
|
||||
|
||||
routes, err := t.Router.Table().Query(query)
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.router", "failed to lookup routes: %s", err)
|
||||
}
|
||||
|
||||
var respRoutes []*pb.Route
|
||||
for _, route := range routes {
|
||||
respRoute := &pb.Route{
|
||||
Service: route.Service,
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Link: route.Link,
|
||||
Metric: int64(route.Metric),
|
||||
}
|
||||
respRoutes = append(respRoutes, respRoute)
|
||||
}
|
||||
|
||||
resp.Routes = respRoutes
|
||||
|
||||
return nil
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: go-micro/network/router/proto/router.proto
|
||||
// source: micro/go-micro/router/proto/router.proto
|
||||
|
||||
package go_micro_router
|
||||
|
||||
@@ -36,7 +36,7 @@ var _ server.Option
|
||||
type RouterService interface {
|
||||
Lookup(ctx context.Context, in *LookupRequest, opts ...client.CallOption) (*LookupResponse, error)
|
||||
Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Router_WatchService, error)
|
||||
Advertise(ctx context.Context, in *AdvertiseRequest, opts ...client.CallOption) (Router_AdvertiseService, error)
|
||||
Advertise(ctx context.Context, in *Request, opts ...client.CallOption) (Router_AdvertiseService, error)
|
||||
Process(ctx context.Context, in *Advert, opts ...client.CallOption) (*ProcessResponse, error)
|
||||
Status(ctx context.Context, in *Request, opts ...client.CallOption) (*StatusResponse, error)
|
||||
}
|
||||
@@ -113,8 +113,8 @@ func (x *routerServiceWatch) Recv() (*Event, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *routerService) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...client.CallOption) (Router_AdvertiseService, error) {
|
||||
req := c.c.NewRequest(c.name, "Router.Advertise", &AdvertiseRequest{})
|
||||
func (c *routerService) Advertise(ctx context.Context, in *Request, opts ...client.CallOption) (Router_AdvertiseService, error) {
|
||||
req := c.c.NewRequest(c.name, "Router.Advertise", &Request{})
|
||||
stream, err := c.c.Stream(ctx, req, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -182,7 +182,7 @@ func (c *routerService) Status(ctx context.Context, in *Request, opts ...client.
|
||||
type RouterHandler interface {
|
||||
Lookup(context.Context, *LookupRequest, *LookupResponse) error
|
||||
Watch(context.Context, *WatchRequest, Router_WatchStream) error
|
||||
Advertise(context.Context, *AdvertiseRequest, Router_AdvertiseStream) error
|
||||
Advertise(context.Context, *Request, Router_AdvertiseStream) error
|
||||
Process(context.Context, *Advert, *ProcessResponse) error
|
||||
Status(context.Context, *Request, *StatusResponse) error
|
||||
}
|
||||
@@ -246,7 +246,7 @@ func (x *routerWatchStream) Send(m *Event) error {
|
||||
}
|
||||
|
||||
func (h *routerHandler) Advertise(ctx context.Context, stream server.Stream) error {
|
||||
m := new(AdvertiseRequest)
|
||||
m := new(Request)
|
||||
if err := stream.Recv(m); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -294,8 +294,8 @@ type TableService interface {
|
||||
Create(ctx context.Context, in *Route, opts ...client.CallOption) (*CreateResponse, error)
|
||||
Delete(ctx context.Context, in *Route, opts ...client.CallOption) (*DeleteResponse, error)
|
||||
Update(ctx context.Context, in *Route, opts ...client.CallOption) (*UpdateResponse, error)
|
||||
Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error)
|
||||
List(ctx context.Context, in *Request, opts ...client.CallOption) (*ListResponse, error)
|
||||
Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error)
|
||||
}
|
||||
|
||||
type tableService struct {
|
||||
@@ -346,9 +346,9 @@ func (c *tableService) Update(ctx context.Context, in *Route, opts ...client.Cal
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *tableService) Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Table.Query", in)
|
||||
out := new(QueryResponse)
|
||||
func (c *tableService) List(ctx context.Context, in *Request, opts ...client.CallOption) (*ListResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Table.List", in)
|
||||
out := new(ListResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -356,9 +356,9 @@ func (c *tableService) Query(ctx context.Context, in *QueryRequest, opts ...clie
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *tableService) List(ctx context.Context, in *Request, opts ...client.CallOption) (*ListResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Table.List", in)
|
||||
out := new(ListResponse)
|
||||
func (c *tableService) Query(ctx context.Context, in *QueryRequest, opts ...client.CallOption) (*QueryResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Table.Query", in)
|
||||
out := new(QueryResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -372,8 +372,8 @@ type TableHandler interface {
|
||||
Create(context.Context, *Route, *CreateResponse) error
|
||||
Delete(context.Context, *Route, *DeleteResponse) error
|
||||
Update(context.Context, *Route, *UpdateResponse) error
|
||||
Query(context.Context, *QueryRequest, *QueryResponse) error
|
||||
List(context.Context, *Request, *ListResponse) error
|
||||
Query(context.Context, *QueryRequest, *QueryResponse) error
|
||||
}
|
||||
|
||||
func RegisterTableHandler(s server.Server, hdlr TableHandler, opts ...server.HandlerOption) error {
|
||||
@@ -381,8 +381,8 @@ func RegisterTableHandler(s server.Server, hdlr TableHandler, opts ...server.Han
|
||||
Create(ctx context.Context, in *Route, out *CreateResponse) error
|
||||
Delete(ctx context.Context, in *Route, out *DeleteResponse) error
|
||||
Update(ctx context.Context, in *Route, out *UpdateResponse) error
|
||||
Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error
|
||||
List(ctx context.Context, in *Request, out *ListResponse) error
|
||||
Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error
|
||||
}
|
||||
type Table struct {
|
||||
table
|
||||
@@ -407,10 +407,10 @@ func (h *tableHandler) Update(ctx context.Context, in *Route, out *UpdateRespons
|
||||
return h.TableHandler.Update(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *tableHandler) Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error {
|
||||
return h.TableHandler.Query(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *tableHandler) List(ctx context.Context, in *Request, out *ListResponse) error {
|
||||
return h.TableHandler.List(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *tableHandler) Query(ctx context.Context, in *QueryRequest, out *QueryResponse) error {
|
||||
return h.TableHandler.Query(ctx, in, out)
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: go-micro/network/router/proto/router.proto
|
||||
// source: micro/go-micro/router/proto/router.proto
|
||||
|
||||
package go_micro_router
|
||||
|
||||
@@ -45,7 +45,7 @@ func (x AdvertType) String() string {
|
||||
}
|
||||
|
||||
func (AdvertType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{0}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{0}
|
||||
}
|
||||
|
||||
// EventType defines the type of event
|
||||
@@ -74,7 +74,7 @@ func (x EventType) String() string {
|
||||
}
|
||||
|
||||
func (EventType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{1}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{1}
|
||||
}
|
||||
|
||||
// Empty request
|
||||
@@ -88,7 +88,7 @@ func (m *Request) Reset() { *m = Request{} }
|
||||
func (m *Request) String() string { return proto.CompactTextString(m) }
|
||||
func (*Request) ProtoMessage() {}
|
||||
func (*Request) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{0}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{0}
|
||||
}
|
||||
|
||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
||||
@@ -121,7 +121,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} }
|
||||
func (m *ListResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListResponse) ProtoMessage() {}
|
||||
func (*ListResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{1}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{1}
|
||||
}
|
||||
|
||||
func (m *ListResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -161,7 +161,7 @@ func (m *LookupRequest) Reset() { *m = LookupRequest{} }
|
||||
func (m *LookupRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*LookupRequest) ProtoMessage() {}
|
||||
func (*LookupRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{2}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{2}
|
||||
}
|
||||
|
||||
func (m *LookupRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -201,7 +201,7 @@ func (m *LookupResponse) Reset() { *m = LookupResponse{} }
|
||||
func (m *LookupResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*LookupResponse) ProtoMessage() {}
|
||||
func (*LookupResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{3}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{3}
|
||||
}
|
||||
|
||||
func (m *LookupResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -240,7 +240,7 @@ func (m *QueryRequest) Reset() { *m = QueryRequest{} }
|
||||
func (m *QueryRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*QueryRequest) ProtoMessage() {}
|
||||
func (*QueryRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{4}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{4}
|
||||
}
|
||||
|
||||
func (m *QueryRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -279,7 +279,7 @@ func (m *QueryResponse) Reset() { *m = QueryResponse{} }
|
||||
func (m *QueryResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*QueryResponse) ProtoMessage() {}
|
||||
func (*QueryResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{5}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{5}
|
||||
}
|
||||
|
||||
func (m *QueryResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -318,7 +318,7 @@ func (m *WatchRequest) Reset() { *m = WatchRequest{} }
|
||||
func (m *WatchRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*WatchRequest) ProtoMessage() {}
|
||||
func (*WatchRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{6}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{6}
|
||||
}
|
||||
|
||||
func (m *WatchRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -339,38 +339,6 @@ func (m *WatchRequest) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_WatchRequest proto.InternalMessageInfo
|
||||
|
||||
// AdvertiseRequest request a stream of Adverts
|
||||
type AdvertiseRequest struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *AdvertiseRequest) Reset() { *m = AdvertiseRequest{} }
|
||||
func (m *AdvertiseRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*AdvertiseRequest) ProtoMessage() {}
|
||||
func (*AdvertiseRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{7}
|
||||
}
|
||||
|
||||
func (m *AdvertiseRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_AdvertiseRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *AdvertiseRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_AdvertiseRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *AdvertiseRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_AdvertiseRequest.Merge(m, src)
|
||||
}
|
||||
func (m *AdvertiseRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_AdvertiseRequest.Size(m)
|
||||
}
|
||||
func (m *AdvertiseRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_AdvertiseRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_AdvertiseRequest proto.InternalMessageInfo
|
||||
|
||||
// Advert is router advertsement streamed by Watch
|
||||
type Advert struct {
|
||||
// id of the advertising router
|
||||
@@ -392,7 +360,7 @@ func (m *Advert) Reset() { *m = Advert{} }
|
||||
func (m *Advert) String() string { return proto.CompactTextString(m) }
|
||||
func (*Advert) ProtoMessage() {}
|
||||
func (*Advert) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{8}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{7}
|
||||
}
|
||||
|
||||
func (m *Advert) XXX_Unmarshal(b []byte) error {
|
||||
@@ -459,7 +427,7 @@ func (m *ProcessResponse) Reset() { *m = ProcessResponse{} }
|
||||
func (m *ProcessResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ProcessResponse) ProtoMessage() {}
|
||||
func (*ProcessResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{9}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{8}
|
||||
}
|
||||
|
||||
func (m *ProcessResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -491,7 +459,7 @@ func (m *CreateResponse) Reset() { *m = CreateResponse{} }
|
||||
func (m *CreateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateResponse) ProtoMessage() {}
|
||||
func (*CreateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{10}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{9}
|
||||
}
|
||||
|
||||
func (m *CreateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -523,7 +491,7 @@ func (m *DeleteResponse) Reset() { *m = DeleteResponse{} }
|
||||
func (m *DeleteResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteResponse) ProtoMessage() {}
|
||||
func (*DeleteResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{11}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{10}
|
||||
}
|
||||
|
||||
func (m *DeleteResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -555,7 +523,7 @@ func (m *UpdateResponse) Reset() { *m = UpdateResponse{} }
|
||||
func (m *UpdateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateResponse) ProtoMessage() {}
|
||||
func (*UpdateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{12}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{11}
|
||||
}
|
||||
|
||||
func (m *UpdateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -593,7 +561,7 @@ func (m *Event) Reset() { *m = Event{} }
|
||||
func (m *Event) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event) ProtoMessage() {}
|
||||
func (*Event) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{13}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{12}
|
||||
}
|
||||
|
||||
func (m *Event) XXX_Unmarshal(b []byte) error {
|
||||
@@ -652,7 +620,7 @@ func (m *Query) Reset() { *m = Query{} }
|
||||
func (m *Query) String() string { return proto.CompactTextString(m) }
|
||||
func (*Query) ProtoMessage() {}
|
||||
func (*Query) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{14}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{13}
|
||||
}
|
||||
|
||||
func (m *Query) XXX_Unmarshal(b []byte) error {
|
||||
@@ -717,7 +685,7 @@ func (m *Route) Reset() { *m = Route{} }
|
||||
func (m *Route) String() string { return proto.CompactTextString(m) }
|
||||
func (*Route) ProtoMessage() {}
|
||||
func (*Route) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{15}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{14}
|
||||
}
|
||||
|
||||
func (m *Route) XXX_Unmarshal(b []byte) error {
|
||||
@@ -792,7 +760,7 @@ func (m *Status) Reset() { *m = Status{} }
|
||||
func (m *Status) String() string { return proto.CompactTextString(m) }
|
||||
func (*Status) ProtoMessage() {}
|
||||
func (*Status) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{16}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{15}
|
||||
}
|
||||
|
||||
func (m *Status) XXX_Unmarshal(b []byte) error {
|
||||
@@ -838,7 +806,7 @@ func (m *StatusResponse) Reset() { *m = StatusResponse{} }
|
||||
func (m *StatusResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*StatusResponse) ProtoMessage() {}
|
||||
func (*StatusResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_fc08514fc6dadd29, []int{17}
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{16}
|
||||
}
|
||||
|
||||
func (m *StatusResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -876,7 +844,6 @@ func init() {
|
||||
proto.RegisterType((*QueryRequest)(nil), "go.micro.router.QueryRequest")
|
||||
proto.RegisterType((*QueryResponse)(nil), "go.micro.router.QueryResponse")
|
||||
proto.RegisterType((*WatchRequest)(nil), "go.micro.router.WatchRequest")
|
||||
proto.RegisterType((*AdvertiseRequest)(nil), "go.micro.router.AdvertiseRequest")
|
||||
proto.RegisterType((*Advert)(nil), "go.micro.router.Advert")
|
||||
proto.RegisterType((*ProcessResponse)(nil), "go.micro.router.ProcessResponse")
|
||||
proto.RegisterType((*CreateResponse)(nil), "go.micro.router.CreateResponse")
|
||||
@@ -890,55 +857,55 @@ func init() {
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("go-micro/network/router/proto/router.proto", fileDescriptor_fc08514fc6dadd29)
|
||||
proto.RegisterFile("micro/go-micro/router/proto/router.proto", fileDescriptor_6a36eee0b1adf739)
|
||||
}
|
||||
|
||||
var fileDescriptor_fc08514fc6dadd29 = []byte{
|
||||
// 702 bytes of a gzipped FileDescriptorProto
|
||||
var fileDescriptor_6a36eee0b1adf739 = []byte{
|
||||
// 689 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xcd, 0x4e, 0xdb, 0x40,
|
||||
0x10, 0xb6, 0x93, 0xd8, 0xc8, 0xd3, 0x60, 0xdc, 0x51, 0x05, 0x56, 0x5a, 0x68, 0xea, 0x13, 0x42,
|
||||
0xd4, 0xa9, 0xd2, 0x6b, 0xff, 0x52, 0x4a, 0x55, 0x09, 0x0e, 0xad, 0x0b, 0xea, 0xd9, 0xd8, 0x2b,
|
||||
0x6a, 0x91, 0x78, 0xcd, 0xee, 0x06, 0x94, 0x73, 0x1f, 0xa3, 0x4f, 0xd0, 0xe7, 0xea, 0x33, 0xf4,
|
||||
0x5e, 0x79, 0x77, 0x1d, 0x92, 0x18, 0x23, 0xc1, 0xc9, 0x3b, 0x7f, 0xdf, 0xec, 0xcc, 0xce, 0x37,
|
||||
0x86, 0xbd, 0x73, 0xfa, 0x72, 0x92, 0x25, 0x8c, 0x0e, 0x72, 0x22, 0xae, 0x29, 0xbb, 0x18, 0x30,
|
||||
0x3a, 0x15, 0x84, 0x0d, 0x0a, 0x46, 0x05, 0xd5, 0x42, 0x28, 0x05, 0xdc, 0x38, 0xa7, 0xa1, 0xf4,
|
||||
0x0d, 0x95, 0x3a, 0x70, 0x60, 0x2d, 0x22, 0x97, 0x53, 0xc2, 0x45, 0xf0, 0x0e, 0xba, 0xc7, 0x19,
|
||||
0x17, 0x11, 0xe1, 0x05, 0xcd, 0x39, 0xc1, 0x10, 0x6c, 0xe9, 0xc4, 0x7d, 0xb3, 0xdf, 0xde, 0x7d,
|
||||
0x34, 0xdc, 0x0c, 0x57, 0x82, 0xc3, 0xa8, 0xfc, 0x44, 0xda, 0x2b, 0x78, 0x0b, 0xeb, 0xc7, 0x94,
|
||||
0x5e, 0x4c, 0x0b, 0x0d, 0x88, 0xfb, 0x60, 0x5d, 0x4e, 0x09, 0x9b, 0xf9, 0x66, 0xdf, 0xbc, 0x35,
|
||||
0xfe, 0x5b, 0x69, 0x8d, 0x94, 0x53, 0xf0, 0x01, 0xdc, 0x2a, 0xfc, 0x81, 0x17, 0x78, 0x03, 0x5d,
|
||||
0x85, 0xf8, 0xa0, 0xfc, 0xef, 0x61, 0x5d, 0x47, 0x3f, 0x30, 0xbd, 0x0b, 0xdd, 0x1f, 0xb1, 0x48,
|
||||
0x7e, 0x56, 0xfd, 0x44, 0xf0, 0x46, 0xe9, 0x15, 0x61, 0x22, 0xe3, 0xa4, 0xd2, 0xfd, 0x31, 0xc1,
|
||||
0x56, 0x4a, 0x74, 0xa1, 0x95, 0xa5, 0xf2, 0x6a, 0x4e, 0xd4, 0xca, 0x52, 0x1c, 0x40, 0x47, 0xcc,
|
||||
0x0a, 0xe2, 0xb7, 0xfa, 0xe6, 0xae, 0x3b, 0x7c, 0x5a, 0x4b, 0xa6, 0xc2, 0x4e, 0x66, 0x05, 0x89,
|
||||
0xa4, 0x23, 0x3e, 0x03, 0x47, 0x64, 0x13, 0xc2, 0x45, 0x3c, 0x29, 0xfc, 0x76, 0xdf, 0xdc, 0x6d,
|
||||
0x47, 0x37, 0x0a, 0xf4, 0xa0, 0x2d, 0xc4, 0xd8, 0xef, 0x48, 0x7d, 0x79, 0x2c, 0xeb, 0x21, 0x57,
|
||||
0x24, 0x17, 0xdc, 0xb7, 0x1a, 0xea, 0x39, 0x2c, 0xcd, 0x91, 0xf6, 0x0a, 0x1e, 0xc3, 0xc6, 0x57,
|
||||
0x46, 0x13, 0xc2, 0x79, 0xd5, 0x92, 0xc0, 0x03, 0xf7, 0x80, 0x91, 0x58, 0x90, 0x45, 0xcd, 0x27,
|
||||
0x32, 0x26, 0xcb, 0x9a, 0xd3, 0x22, 0x5d, 0xf4, 0xf9, 0x65, 0x82, 0x25, 0xa1, 0x31, 0xd4, 0x35,
|
||||
0x9a, 0xb2, 0xc6, 0xde, 0xed, 0x17, 0x68, 0x2a, 0xb1, 0xb5, 0x5a, 0xe2, 0x3e, 0x58, 0x32, 0x4e,
|
||||
0x16, 0xdf, 0xfc, 0x3e, 0xca, 0x29, 0x38, 0x05, 0x4b, 0xbe, 0x2f, 0xfa, 0xb0, 0xc6, 0x09, 0xbb,
|
||||
0xca, 0x12, 0xa2, 0xbb, 0x5f, 0x89, 0xa5, 0xe5, 0x3c, 0x16, 0xe4, 0x3a, 0x9e, 0xc9, 0x64, 0x4e,
|
||||
0x54, 0x89, 0xa5, 0x45, 0x93, 0x4b, 0x26, 0x73, 0xa2, 0x4a, 0x0c, 0x7e, 0x9b, 0x60, 0xc9, 0x3c,
|
||||
0x77, 0xe3, 0xc6, 0x69, 0xca, 0x08, 0xe7, 0x15, 0xae, 0x16, 0x17, 0x33, 0xb6, 0x1b, 0x33, 0x76,
|
||||
0x96, 0x32, 0x22, 0x42, 0x67, 0x9c, 0xe5, 0x17, 0xbe, 0x25, 0xd5, 0xf2, 0x8c, 0x9b, 0x60, 0x4f,
|
||||
0x88, 0x60, 0x59, 0xe2, 0xdb, 0xb2, 0x4b, 0x5a, 0x0a, 0x86, 0x60, 0x7f, 0x17, 0xb1, 0x98, 0xf2,
|
||||
0x32, 0x2a, 0xa1, 0x69, 0x75, 0x35, 0x79, 0xc6, 0x27, 0x60, 0x11, 0xc6, 0x28, 0xd3, 0xb7, 0x52,
|
||||
0x42, 0x30, 0x02, 0x57, 0xc5, 0xcc, 0x99, 0x30, 0x00, 0x9b, 0x4b, 0x8d, 0x66, 0xd2, 0x56, 0xad,
|
||||
0xd3, 0x3a, 0x40, 0xbb, 0xed, 0x0d, 0x01, 0x6e, 0xc6, 0x15, 0x11, 0x5c, 0x25, 0x8d, 0xf2, 0x9c,
|
||||
0x4e, 0xf3, 0x84, 0x78, 0x06, 0x7a, 0xd0, 0x55, 0x3a, 0x35, 0x2b, 0x9e, 0xb9, 0x37, 0x00, 0x67,
|
||||
0xfe, 0xfc, 0x08, 0x60, 0xab, 0x41, 0xf3, 0x8c, 0xf2, 0xac, 0x46, 0xcc, 0x33, 0xcb, 0xb3, 0x0e,
|
||||
0x68, 0x0d, 0xff, 0xb5, 0xc0, 0x96, 0x9d, 0x67, 0x78, 0x04, 0xb6, 0xda, 0x1d, 0xb8, 0x53, 0xbb,
|
||||
0xda, 0xd2, 0x4e, 0xea, 0x3d, 0x6f, 0xb4, 0xeb, 0x61, 0x35, 0xf0, 0x23, 0x58, 0x92, 0xc7, 0xb8,
|
||||
0x5d, 0xf3, 0x5d, 0xe4, 0x77, 0xaf, 0x81, 0x3f, 0x81, 0xf1, 0xca, 0xc4, 0x23, 0x70, 0xe6, 0xdc,
|
||||
0xc7, 0x17, 0x0d, 0x5c, 0xbe, 0xd9, 0x0b, 0xbd, 0xad, 0x06, 0x17, 0x09, 0xf6, 0x19, 0xd6, 0x34,
|
||||
0x11, 0xb1, 0xc9, 0xaf, 0xd7, 0xaf, 0x19, 0x56, 0xb9, 0x6b, 0xe0, 0xe1, 0x7c, 0x18, 0xfc, 0x3a,
|
||||
0x55, 0x1a, 0xfb, 0xb3, 0x3c, 0x0b, 0x81, 0x31, 0xfc, 0xdb, 0x02, 0xeb, 0x24, 0x3e, 0x1b, 0x13,
|
||||
0x3c, 0xa8, 0x5e, 0x09, 0x1b, 0xb8, 0x77, 0x0b, 0xdc, 0xca, 0xfe, 0x30, 0x4a, 0x10, 0xf5, 0xbc,
|
||||
0xf7, 0x00, 0x59, 0x59, 0x39, 0x12, 0x44, 0xcd, 0xc5, 0x3d, 0x40, 0x56, 0xb6, 0x94, 0x81, 0x5f,
|
||||
0xaa, 0x0d, 0xb1, 0xdd, 0xf0, 0xa7, 0xd0, 0x3d, 0xda, 0x69, 0x32, 0xcf, 0x91, 0x46, 0xd0, 0x29,
|
||||
0x7f, 0xa5, 0x77, 0xf4, 0xb9, 0x9e, 0x62, 0xf1, 0xdf, 0x1b, 0x18, 0x67, 0xb6, 0xfc, 0x61, 0xbf,
|
||||
0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff, 0xa6, 0xfc, 0x65, 0xca, 0xde, 0x07, 0x00, 0x00,
|
||||
0x10, 0xb6, 0x93, 0xd8, 0x28, 0xd3, 0x10, 0xdc, 0x51, 0x05, 0x56, 0x5a, 0x20, 0xf2, 0x29, 0x42,
|
||||
0xd4, 0xa9, 0xd2, 0x6b, 0xff, 0x02, 0xa5, 0xaa, 0x54, 0x0e, 0xad, 0x0b, 0xea, 0xd9, 0xd8, 0x23,
|
||||
0x6a, 0x91, 0xd8, 0x66, 0x77, 0x03, 0xca, 0xb9, 0x8f, 0xd1, 0x27, 0xe8, 0x73, 0xf5, 0xda, 0x87,
|
||||
0xa8, 0xbc, 0xbb, 0x0e, 0x21, 0xc6, 0x48, 0x70, 0xf2, 0xce, 0xdf, 0x37, 0xff, 0x63, 0x18, 0x4c,
|
||||
0x93, 0x88, 0x65, 0xc3, 0xf3, 0xec, 0xa5, 0x7a, 0xb0, 0x6c, 0x26, 0x88, 0x0d, 0x73, 0x96, 0x89,
|
||||
0x92, 0xf0, 0x25, 0x81, 0x1b, 0xe7, 0x99, 0x2f, 0x75, 0x7c, 0xc5, 0xf6, 0xda, 0xb0, 0x16, 0xd0,
|
||||
0xe5, 0x8c, 0xb8, 0xf0, 0xde, 0x41, 0xe7, 0x38, 0xe1, 0x22, 0x20, 0x9e, 0x67, 0x29, 0x27, 0xf4,
|
||||
0xc1, 0x96, 0x4a, 0xdc, 0x35, 0xfb, 0xcd, 0xc1, 0x93, 0xd1, 0xa6, 0xbf, 0x62, 0xec, 0x07, 0xc5,
|
||||
0x27, 0xd0, 0x5a, 0xde, 0x5b, 0x58, 0x3f, 0xce, 0xb2, 0x8b, 0x59, 0xae, 0x01, 0x71, 0x1f, 0xac,
|
||||
0xcb, 0x19, 0xb1, 0xb9, 0x6b, 0xf6, 0xcd, 0x3b, 0xed, 0xbf, 0x15, 0xd2, 0x40, 0x29, 0x79, 0x1f,
|
||||
0xa0, 0x5b, 0x9a, 0x3f, 0x32, 0x80, 0x37, 0xd0, 0x51, 0x88, 0x8f, 0xf2, 0xff, 0x1e, 0xd6, 0xb5,
|
||||
0xf5, 0x23, 0xdd, 0x77, 0xa1, 0xf3, 0x23, 0x14, 0xd1, 0xcf, 0xb2, 0x9e, 0x7f, 0x4c, 0xb0, 0xc7,
|
||||
0xf1, 0x15, 0x31, 0x81, 0x5d, 0x68, 0x24, 0xb1, 0x0c, 0xa3, 0x1d, 0x34, 0x92, 0x18, 0x87, 0xd0,
|
||||
0x12, 0xf3, 0x9c, 0xdc, 0x46, 0xdf, 0x1c, 0x74, 0x47, 0xcf, 0x2b, 0xc0, 0xca, 0xec, 0x64, 0x9e,
|
||||
0x53, 0x20, 0x15, 0xf1, 0x05, 0xb4, 0x45, 0x32, 0x25, 0x2e, 0xc2, 0x69, 0xee, 0x36, 0xfb, 0xe6,
|
||||
0xa0, 0x19, 0xdc, 0x30, 0xd0, 0x81, 0xa6, 0x10, 0x13, 0xb7, 0x25, 0xf9, 0xc5, 0xb3, 0x88, 0x9d,
|
||||
0xae, 0x28, 0x15, 0xdc, 0xb5, 0x6a, 0x62, 0x3f, 0x2a, 0xc4, 0x81, 0xd6, 0xf2, 0x9e, 0xc2, 0xc6,
|
||||
0x57, 0x96, 0x45, 0xc4, 0x79, 0x99, 0xbe, 0xe7, 0x40, 0xf7, 0x90, 0x51, 0x28, 0x68, 0x99, 0xf3,
|
||||
0x91, 0x26, 0x74, 0x9b, 0x73, 0x9a, 0xc7, 0xcb, 0x3a, 0xbf, 0x4c, 0xb0, 0x24, 0x34, 0xfa, 0x3a,
|
||||
0x47, 0x53, 0xe6, 0xd8, 0xbb, 0x3b, 0x80, 0xba, 0x14, 0x1b, 0xab, 0x29, 0xee, 0x83, 0x25, 0xed,
|
||||
0x64, 0xf2, 0xf5, 0xbd, 0x50, 0x4a, 0xde, 0x29, 0x58, 0xb2, 0x97, 0xe8, 0xc2, 0x1a, 0x27, 0x76,
|
||||
0x95, 0x44, 0xa4, 0xab, 0x5f, 0x92, 0x85, 0xe4, 0x3c, 0x14, 0x74, 0x1d, 0xce, 0xa5, 0xb3, 0x76,
|
||||
0x50, 0x92, 0x85, 0x24, 0x25, 0x71, 0x9d, 0xb1, 0x0b, 0xe9, 0xac, 0x1d, 0x94, 0xa4, 0xf7, 0xdb,
|
||||
0x04, 0x4b, 0xfa, 0xb9, 0x1f, 0x37, 0x8c, 0x63, 0x46, 0x9c, 0x97, 0xb8, 0x9a, 0x5c, 0xf6, 0xd8,
|
||||
0xac, 0xf5, 0xd8, 0xba, 0xe5, 0x11, 0x11, 0x5a, 0x93, 0x24, 0xbd, 0x70, 0x2d, 0xc9, 0x96, 0x6f,
|
||||
0xdc, 0x04, 0x7b, 0x4a, 0x82, 0x25, 0x91, 0x6b, 0xcb, 0x2a, 0x69, 0xca, 0x1b, 0x81, 0xfd, 0x5d,
|
||||
0x84, 0x62, 0xc6, 0x0b, 0xab, 0x28, 0x8b, 0xcb, 0xd0, 0xe4, 0x1b, 0x9f, 0x81, 0x45, 0x8c, 0x65,
|
||||
0x4c, 0x47, 0xa5, 0x08, 0x6f, 0x0c, 0x5d, 0x65, 0xb3, 0x98, 0xfa, 0x21, 0xd8, 0x5c, 0x72, 0xf4,
|
||||
0xd6, 0x6c, 0x55, 0x2a, 0xad, 0x0d, 0xb4, 0xda, 0xde, 0x08, 0xe0, 0x66, 0x5c, 0x11, 0xa1, 0xab,
|
||||
0xa8, 0x71, 0x9a, 0x66, 0xb3, 0x34, 0x22, 0xc7, 0x40, 0x07, 0x3a, 0x8a, 0xa7, 0x66, 0xc5, 0x31,
|
||||
0xf7, 0x86, 0xd0, 0x5e, 0xb4, 0x1f, 0x01, 0x6c, 0x35, 0x68, 0x8e, 0x51, 0xbc, 0xd5, 0x88, 0x39,
|
||||
0x66, 0xf1, 0xd6, 0x06, 0x8d, 0xd1, 0xbf, 0x06, 0xd8, 0xb2, 0xf2, 0x0c, 0xbf, 0x80, 0xad, 0xee,
|
||||
0x04, 0xee, 0x54, 0x42, 0xbb, 0x75, 0x7f, 0x7a, 0xbb, 0xb5, 0x72, 0x3d, 0xac, 0x06, 0x1e, 0x80,
|
||||
0x25, 0x77, 0x16, 0xb7, 0x2b, 0xba, 0xcb, 0xbb, 0xdc, 0xab, 0xd9, 0x1f, 0xcf, 0x78, 0x65, 0xe2,
|
||||
0x01, 0xb4, 0x55, 0x7a, 0x09, 0x27, 0x74, 0xab, 0x83, 0xa9, 0x21, 0xb6, 0x6a, 0xb6, 0x5c, 0x62,
|
||||
0x7c, 0x82, 0x35, 0xbd, 0x7f, 0x58, 0xa7, 0xd7, 0xeb, 0x57, 0x04, 0xab, 0x2b, 0x6b, 0xe0, 0xd1,
|
||||
0x62, 0x06, 0xea, 0x03, 0xd9, 0xad, 0xeb, 0xe8, 0x02, 0x66, 0xf4, 0xb7, 0x01, 0xd6, 0x49, 0x78,
|
||||
0x36, 0x21, 0x3c, 0x2c, 0x9b, 0x83, 0x35, 0x2b, 0x77, 0x07, 0xdc, 0xca, 0xd9, 0x30, 0x0a, 0x10,
|
||||
0xd5, 0xd5, 0x07, 0x80, 0xac, 0x5c, 0x1a, 0x09, 0xa2, 0xc6, 0xe1, 0x01, 0x20, 0x2b, 0xc7, 0xc9,
|
||||
0xc0, 0x31, 0xb4, 0x8a, 0x7f, 0xdc, 0x3d, 0xd5, 0xa9, 0x0e, 0xc2, 0xf2, 0x4f, 0xd1, 0x33, 0xf0,
|
||||
0x73, 0x79, 0x5b, 0xb6, 0x6b, 0xfe, 0x27, 0x1a, 0x68, 0xa7, 0x4e, 0x5c, 0x22, 0x9d, 0xd9, 0xf2,
|
||||
0x9f, 0xfc, 0xfa, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8c, 0xd0, 0xc0, 0x27, 0xbf, 0x07, 0x00,
|
||||
0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -955,7 +922,7 @@ const _ = grpc.SupportPackageIsVersion4
|
||||
type RouterClient interface {
|
||||
Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error)
|
||||
Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Router_WatchClient, error)
|
||||
Advertise(ctx context.Context, in *AdvertiseRequest, opts ...grpc.CallOption) (Router_AdvertiseClient, error)
|
||||
Advertise(ctx context.Context, in *Request, opts ...grpc.CallOption) (Router_AdvertiseClient, error)
|
||||
Process(ctx context.Context, in *Advert, opts ...grpc.CallOption) (*ProcessResponse, error)
|
||||
Status(ctx context.Context, in *Request, opts ...grpc.CallOption) (*StatusResponse, error)
|
||||
}
|
||||
@@ -1009,7 +976,7 @@ func (x *routerWatchClient) Recv() (*Event, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *routerClient) Advertise(ctx context.Context, in *AdvertiseRequest, opts ...grpc.CallOption) (Router_AdvertiseClient, error) {
|
||||
func (c *routerClient) Advertise(ctx context.Context, in *Request, opts ...grpc.CallOption) (Router_AdvertiseClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_Router_serviceDesc.Streams[1], "/go.micro.router.Router/Advertise", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1063,7 +1030,7 @@ func (c *routerClient) Status(ctx context.Context, in *Request, opts ...grpc.Cal
|
||||
type RouterServer interface {
|
||||
Lookup(context.Context, *LookupRequest) (*LookupResponse, error)
|
||||
Watch(*WatchRequest, Router_WatchServer) error
|
||||
Advertise(*AdvertiseRequest, Router_AdvertiseServer) error
|
||||
Advertise(*Request, Router_AdvertiseServer) error
|
||||
Process(context.Context, *Advert) (*ProcessResponse, error)
|
||||
Status(context.Context, *Request) (*StatusResponse, error)
|
||||
}
|
||||
@@ -1112,7 +1079,7 @@ func (x *routerWatchServer) Send(m *Event) error {
|
||||
}
|
||||
|
||||
func _Router_Advertise_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(AdvertiseRequest)
|
||||
m := new(Request)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1197,7 +1164,7 @@ var _Router_serviceDesc = grpc.ServiceDesc{
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "go-micro/network/router/proto/router.proto",
|
||||
Metadata: "micro/go-micro/router/proto/router.proto",
|
||||
}
|
||||
|
||||
// TableClient is the client API for Table service.
|
||||
@@ -1207,8 +1174,8 @@ type TableClient interface {
|
||||
Create(ctx context.Context, in *Route, opts ...grpc.CallOption) (*CreateResponse, error)
|
||||
Delete(ctx context.Context, in *Route, opts ...grpc.CallOption) (*DeleteResponse, error)
|
||||
Update(ctx context.Context, in *Route, opts ...grpc.CallOption) (*UpdateResponse, error)
|
||||
Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error)
|
||||
List(ctx context.Context, in *Request, opts ...grpc.CallOption) (*ListResponse, error)
|
||||
Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error)
|
||||
}
|
||||
|
||||
type tableClient struct {
|
||||
@@ -1246,18 +1213,18 @@ func (c *tableClient) Update(ctx context.Context, in *Route, opts ...grpc.CallOp
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *tableClient) Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) {
|
||||
out := new(QueryResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.router.Table/Query", in, out, opts...)
|
||||
func (c *tableClient) List(ctx context.Context, in *Request, opts ...grpc.CallOption) (*ListResponse, error) {
|
||||
out := new(ListResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.router.Table/List", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *tableClient) List(ctx context.Context, in *Request, opts ...grpc.CallOption) (*ListResponse, error) {
|
||||
out := new(ListResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.router.Table/List", in, out, opts...)
|
||||
func (c *tableClient) Query(ctx context.Context, in *QueryRequest, opts ...grpc.CallOption) (*QueryResponse, error) {
|
||||
out := new(QueryResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.router.Table/Query", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1269,8 +1236,8 @@ type TableServer interface {
|
||||
Create(context.Context, *Route) (*CreateResponse, error)
|
||||
Delete(context.Context, *Route) (*DeleteResponse, error)
|
||||
Update(context.Context, *Route) (*UpdateResponse, error)
|
||||
Query(context.Context, *QueryRequest) (*QueryResponse, error)
|
||||
List(context.Context, *Request) (*ListResponse, error)
|
||||
Query(context.Context, *QueryRequest) (*QueryResponse, error)
|
||||
}
|
||||
|
||||
func RegisterTableServer(s *grpc.Server, srv TableServer) {
|
||||
@@ -1331,24 +1298,6 @@ func _Table_Update_Handler(srv interface{}, ctx context.Context, dec func(interf
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Table_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(QueryRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TableServer).Query(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.router.Table/Query",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TableServer).Query(ctx, req.(*QueryRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Table_List_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Request)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -1367,6 +1316,24 @@ func _Table_List_Handler(srv interface{}, ctx context.Context, dec func(interfac
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Table_Query_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(QueryRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TableServer).Query(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.router.Table/Query",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TableServer).Query(ctx, req.(*QueryRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Table_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "go.micro.router.Table",
|
||||
HandlerType: (*TableServer)(nil),
|
||||
@@ -1383,15 +1350,15 @@ var _Table_serviceDesc = grpc.ServiceDesc{
|
||||
MethodName: "Update",
|
||||
Handler: _Table_Update_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Query",
|
||||
Handler: _Table_Query_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "List",
|
||||
Handler: _Table_List_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Query",
|
||||
Handler: _Table_Query_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "go-micro/network/router/proto/router.proto",
|
||||
Metadata: "micro/go-micro/router/proto/router.proto",
|
||||
}
|
@@ -11,7 +11,7 @@ service Router {
|
||||
rpc Status(Request) returns (StatusResponse) {};
|
||||
}
|
||||
|
||||
service Table {
|
||||
service Table {
|
||||
rpc Create(Route) returns (CreateResponse) {};
|
||||
rpc Delete(Route) returns (DeleteResponse) {};
|
||||
rpc Update(Route) returns (UpdateResponse) {};
|
@@ -21,6 +21,8 @@ type Router interface {
|
||||
Lookup(Query) ([]Route, error)
|
||||
// Watch returns a watcher which tracks updates to the routing table
|
||||
Watch(opts ...WatchOption) (Watcher, error)
|
||||
// Start starts the router
|
||||
Start() error
|
||||
// Status returns router status
|
||||
Status() Status
|
||||
// Stop stops the router
|
||||
@@ -76,10 +78,15 @@ func (s StatusCode) String() string {
|
||||
|
||||
// Status is router status
|
||||
type Status struct {
|
||||
// Error is router error
|
||||
Error error
|
||||
// Code defines router status
|
||||
Code StatusCode
|
||||
// Error contains error description
|
||||
Error error
|
||||
}
|
||||
|
||||
// String returns human readable status
|
||||
func (s Status) String() string {
|
||||
return s.Code.String()
|
||||
}
|
||||
|
||||
// AdvertType is route advertisement type
|
@@ -9,8 +9,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/network/router"
|
||||
pb "github.com/micro/go-micro/network/router/proto"
|
||||
"github.com/micro/go-micro/router"
|
||||
pb "github.com/micro/go-micro/router/proto"
|
||||
)
|
||||
|
||||
type svc struct {
|
||||
@@ -43,9 +43,16 @@ func NewRouter(opts ...router.Option) router.Router {
|
||||
cli = options.Client
|
||||
}
|
||||
|
||||
// set the status to Stopped
|
||||
status := &router.Status{
|
||||
Code: router.Stopped,
|
||||
Error: nil,
|
||||
}
|
||||
|
||||
// NOTE: should we have Client/Service option in router.Options?
|
||||
s := &svc{
|
||||
opts: options,
|
||||
status: status,
|
||||
router: pb.NewRouterService(router.DefaultName, cli),
|
||||
}
|
||||
|
||||
@@ -63,21 +70,43 @@ func NewRouter(opts ...router.Option) router.Router {
|
||||
|
||||
// Init initializes router with given options
|
||||
func (s *svc) Init(opts ...router.Option) error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
for _, o := range opts {
|
||||
o(&s.opts)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Options returns router options
|
||||
func (s *svc) Options() router.Options {
|
||||
return s.opts
|
||||
s.Lock()
|
||||
opts := s.opts
|
||||
s.Unlock()
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
// Table returns routing table
|
||||
func (s *svc) Table() router.Table {
|
||||
return s.table
|
||||
}
|
||||
|
||||
// Start starts the service
|
||||
func (s *svc) Start() error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
s.status = &router.Status{
|
||||
Code: router.Running,
|
||||
Error: nil,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *svc) advertiseEvents(advertChan chan *router.Advert, stream pb.Router_AdvertiseService) error {
|
||||
go func() {
|
||||
<-s.exit
|
||||
@@ -140,12 +169,9 @@ func (s *svc) Advertise() (<-chan *router.Advert, error) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
// get the status
|
||||
status := s.Status()
|
||||
|
||||
switch status.Code {
|
||||
switch s.status.Code {
|
||||
case router.Running, router.Advertising:
|
||||
stream, err := s.router.Advertise(context.Background(), &pb.AdvertiseRequest{}, s.callOpts...)
|
||||
stream, err := s.router.Advertise(context.Background(), &pb.Request{}, s.callOpts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed getting advert stream: %s", err)
|
||||
}
|
||||
@@ -154,15 +180,7 @@ func (s *svc) Advertise() (<-chan *router.Advert, error) {
|
||||
go s.advertiseEvents(advertChan, stream)
|
||||
return advertChan, nil
|
||||
case router.Stopped:
|
||||
// check if our router is stopped
|
||||
select {
|
||||
case <-s.exit:
|
||||
s.exit = make(chan bool)
|
||||
// call advertise again
|
||||
return s.Advertise()
|
||||
default:
|
||||
return nil, fmt.Errorf("not running")
|
||||
}
|
||||
return nil, fmt.Errorf("not running")
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("error: %s", s.status.Error)
|
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/network/router"
|
||||
pb "github.com/micro/go-micro/network/router/proto"
|
||||
"github.com/micro/go-micro/router"
|
||||
pb "github.com/micro/go-micro/router/proto"
|
||||
)
|
||||
|
||||
type table struct {
|
@@ -5,8 +5,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/network/router"
|
||||
pb "github.com/micro/go-micro/network/router/proto"
|
||||
"github.com/micro/go-micro/router"
|
||||
pb "github.com/micro/go-micro/router/proto"
|
||||
)
|
||||
|
||||
type watcher struct {
|
@@ -160,13 +160,23 @@ func (t *table) Watch(opts ...WatchOption) (Watcher, error) {
|
||||
}
|
||||
|
||||
w := &tableWatcher{
|
||||
id: uuid.New().String(),
|
||||
opts: wopts,
|
||||
resChan: make(chan *Event, 10),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
// when the watcher is stopped delete it
|
||||
go func() {
|
||||
<-w.done
|
||||
t.Lock()
|
||||
delete(t.watchers, w.id)
|
||||
t.Unlock()
|
||||
}()
|
||||
|
||||
// save the watcher
|
||||
t.Lock()
|
||||
t.watchers[uuid.New().String()] = w
|
||||
t.watchers[w.id] = w
|
||||
t.Unlock()
|
||||
|
||||
return w, nil
|
@@ -72,6 +72,7 @@ func WatchService(s string) WatchOption {
|
||||
|
||||
type tableWatcher struct {
|
||||
sync.RWMutex
|
||||
id string
|
||||
opts WatchOptions
|
||||
resChan chan *Event
|
||||
done chan struct{}
|
@@ -1,9 +0,0 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/server/debug"
|
||||
)
|
||||
|
||||
func registerDebugHandler(s Server) {
|
||||
s.Handle(s.NewHandler(&debug.Debug{s.Options().DebugHandler}, InternalHandler(true)))
|
||||
}
|
@@ -1,55 +0,0 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"context"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
proto "github.com/micro/go-micro/server/debug/proto"
|
||||
)
|
||||
|
||||
// The debug handler represents an internal server handler
|
||||
// used to determine health, status and env info about
|
||||
// a service node. It's akin to Google's /statusz, /healthz,
|
||||
// and /varz
|
||||
type Handler interface {
|
||||
Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error
|
||||
Stats(ctx context.Context, req *proto.StatsRequest, rsp *proto.StatsResponse) error
|
||||
}
|
||||
|
||||
// Our own internal handler
|
||||
type debug struct {
|
||||
started int64
|
||||
}
|
||||
|
||||
// We use this to wrap any debug handlers so we preserve the signature Debug.{Method}
|
||||
type Debug struct {
|
||||
Handler
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultHandler Handler = newDebug()
|
||||
)
|
||||
|
||||
func newDebug() *debug {
|
||||
return &debug{
|
||||
started: time.Now().Unix(),
|
||||
}
|
||||
}
|
||||
|
||||
func (d *debug) Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error {
|
||||
rsp.Status = "ok"
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *debug) Stats(ctx context.Context, req *proto.StatsRequest, rsp *proto.StatsResponse) error {
|
||||
var mstat runtime.MemStats
|
||||
runtime.ReadMemStats(&mstat)
|
||||
|
||||
rsp.Started = uint64(d.started)
|
||||
rsp.Uptime = uint64(time.Now().Unix() - d.started)
|
||||
rsp.Memory = mstat.Alloc
|
||||
rsp.Gc = mstat.PauseTotalNs
|
||||
rsp.Threads = uint64(runtime.NumGoroutine())
|
||||
return nil
|
||||
}
|
@@ -1,100 +0,0 @@
|
||||
// Code generated by protoc-gen-go.
|
||||
// source: github.com/micro/go-micro/server/debug/proto/debug.proto
|
||||
// DO NOT EDIT!
|
||||
|
||||
/*
|
||||
Package debug is a generated protocol buffer package.
|
||||
|
||||
It is generated from these files:
|
||||
github.com/micro/go-micro/server/debug/proto/debug.proto
|
||||
|
||||
It has these top-level messages:
|
||||
HealthRequest
|
||||
HealthResponse
|
||||
StatsRequest
|
||||
StatsResponse
|
||||
*/
|
||||
package debug
|
||||
|
||||
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
|
||||
|
||||
type HealthRequest struct {
|
||||
}
|
||||
|
||||
func (m *HealthRequest) Reset() { *m = HealthRequest{} }
|
||||
func (m *HealthRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*HealthRequest) ProtoMessage() {}
|
||||
func (*HealthRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
|
||||
|
||||
type HealthResponse struct {
|
||||
// default: ok
|
||||
Status string `protobuf:"bytes,1,opt,name=status" json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (m *HealthResponse) Reset() { *m = HealthResponse{} }
|
||||
func (m *HealthResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*HealthResponse) ProtoMessage() {}
|
||||
func (*HealthResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
|
||||
|
||||
type StatsRequest struct {
|
||||
}
|
||||
|
||||
func (m *StatsRequest) Reset() { *m = StatsRequest{} }
|
||||
func (m *StatsRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*StatsRequest) ProtoMessage() {}
|
||||
func (*StatsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
|
||||
|
||||
type StatsResponse struct {
|
||||
// unix timestamp
|
||||
Started uint64 `protobuf:"varint,1,opt,name=started" json:"started,omitempty"`
|
||||
// in seconds
|
||||
Uptime uint64 `protobuf:"varint,2,opt,name=uptime" json:"uptime,omitempty"`
|
||||
// in bytes
|
||||
Memory uint64 `protobuf:"varint,3,opt,name=memory" json:"memory,omitempty"`
|
||||
// num threads
|
||||
Threads uint64 `protobuf:"varint,4,opt,name=threads" json:"threads,omitempty"`
|
||||
// in nanoseconds
|
||||
Gc uint64 `protobuf:"varint,5,opt,name=gc" json:"gc,omitempty"`
|
||||
}
|
||||
|
||||
func (m *StatsResponse) Reset() { *m = StatsResponse{} }
|
||||
func (m *StatsResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*StatsResponse) ProtoMessage() {}
|
||||
func (*StatsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*HealthRequest)(nil), "HealthRequest")
|
||||
proto.RegisterType((*HealthResponse)(nil), "HealthResponse")
|
||||
proto.RegisterType((*StatsRequest)(nil), "StatsRequest")
|
||||
proto.RegisterType((*StatsResponse)(nil), "StatsResponse")
|
||||
}
|
||||
|
||||
var fileDescriptor0 = []byte{
|
||||
// 201 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x34, 0x8f, 0xbd, 0x6e, 0x83, 0x30,
|
||||
0x14, 0x85, 0x05, 0xa5, 0x54, 0xbd, 0x2a, 0x54, 0x62, 0xa8, 0x3c, 0x56, 0x4c, 0x2c, 0xc5, 0x43,
|
||||
0x97, 0x3e, 0x42, 0x67, 0xf2, 0x04, 0xfc, 0x5c, 0x19, 0xa4, 0x38, 0x26, 0xbe, 0xd7, 0x91, 0x32,
|
||||
0xe7, 0xc5, 0x03, 0xb6, 0xd9, 0xce, 0xf7, 0xd9, 0xe7, 0x48, 0x17, 0xfe, 0xd4, 0xc2, 0xb3, 0x1b,
|
||||
0xda, 0xd1, 0x68, 0xa9, 0x97, 0xd1, 0x1a, 0xa9, 0xcc, 0x4f, 0x08, 0x84, 0xf6, 0x86, 0x56, 0x4e,
|
||||
0x38, 0x38, 0x25, 0x57, 0x6b, 0xd8, 0x84, 0xdc, 0xfa, 0x5c, 0x7f, 0x42, 0xf1, 0x8f, 0xfd, 0x99,
|
||||
0xe7, 0x0e, 0xaf, 0x0e, 0x89, 0xeb, 0x06, 0xca, 0x43, 0xd0, 0x6a, 0x2e, 0x84, 0xd5, 0x17, 0xe4,
|
||||
0xc4, 0x3d, 0x3b, 0x12, 0xc9, 0x77, 0xd2, 0xbc, 0x77, 0x91, 0xea, 0x12, 0x3e, 0x4e, 0x5b, 0xa2,
|
||||
0xa3, 0xf9, 0x48, 0xa0, 0x88, 0x22, 0x36, 0x05, 0xbc, 0x6d, 0x7f, 0x2d, 0xe3, 0xe4, 0xab, 0x59,
|
||||
0x77, 0xe0, 0xbe, 0xe9, 0x56, 0x5e, 0x34, 0x8a, 0xd4, 0x3f, 0x44, 0xda, 0xbd, 0x46, 0x6d, 0xec,
|
||||
0x5d, 0xbc, 0x04, 0x1f, 0x68, 0x5f, 0xe2, 0xd9, 0x62, 0x3f, 0x91, 0xc8, 0xc2, 0x52, 0xc4, 0xaa,
|
||||
0x84, 0x54, 0x8d, 0xe2, 0xd5, 0xcb, 0x2d, 0x0d, 0xb9, 0xbf, 0xeb, 0xf7, 0x19, 0x00, 0x00, 0xff,
|
||||
0xff, 0xc6, 0x75, 0x51, 0x35, 0x13, 0x01, 0x00, 0x00,
|
||||
}
|
@@ -20,10 +20,6 @@ func extractValue(v reflect.Type, d int) *registry.Value {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
if len(v.Name()) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
arg := ®istry.Value{
|
||||
Name: v.Name(),
|
||||
Type: v.Name(),
|
||||
@@ -65,10 +61,6 @@ func extractValue(v reflect.Type, d int) *registry.Value {
|
||||
p = p.Elem()
|
||||
}
|
||||
arg.Type = "[]" + p.Name()
|
||||
val := extractValue(v.Elem(), d+1)
|
||||
if val != nil {
|
||||
arg.Values = append(arg.Values, val)
|
||||
}
|
||||
}
|
||||
|
||||
return arg
|
||||
|
@@ -1,10 +0,0 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/server"
|
||||
"github.com/micro/go-micro/server/debug"
|
||||
)
|
||||
|
||||
func registerDebugHandler(s server.Server) {
|
||||
s.Handle(s.NewHandler(&debug.Debug{s.Options().DebugHandler}, server.InternalHandler(true)))
|
||||
}
|
@@ -56,10 +56,6 @@ func extractValue(v reflect.Type, d int) *registry.Value {
|
||||
p = p.Elem()
|
||||
}
|
||||
arg.Type = "[]" + p.Name()
|
||||
val := extractValue(v.Elem(), d+1)
|
||||
if val != nil {
|
||||
arg.Values = append(arg.Values, val)
|
||||
}
|
||||
}
|
||||
|
||||
return arg
|
||||
|
@@ -271,12 +271,12 @@ func (g *grpcServer) handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
g.rpc.mu.Unlock()
|
||||
|
||||
if service == nil {
|
||||
return status.New(codes.Unimplemented, fmt.Sprintf("unknown service %v", service)).Err()
|
||||
return status.New(codes.Unimplemented, fmt.Sprintf("unknown service %s", serviceName)).Err()
|
||||
}
|
||||
|
||||
mtype := service.method[methodName]
|
||||
if mtype == nil {
|
||||
return status.New(codes.Unimplemented, fmt.Sprintf("unknown service %v", service)).Err()
|
||||
return status.New(codes.Unimplemented, fmt.Sprintf("unknown service %s.%s", serviceName, methodName)).Err()
|
||||
}
|
||||
|
||||
// process unary
|
||||
@@ -700,7 +700,6 @@ func (g *grpcServer) Deregister() error {
|
||||
}
|
||||
|
||||
func (g *grpcServer) Start() error {
|
||||
registerDebugHandler(g)
|
||||
config := g.opts
|
||||
|
||||
// micro: config.Transport.Listen(config.Address)
|
||||
@@ -719,10 +718,10 @@ func (g *grpcServer) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
baddr := strings.Join(config.Broker.Options().Addrs, ",")
|
||||
baddr := config.Broker.Address()
|
||||
bname := config.Broker.String()
|
||||
|
||||
log.Logf("Broker [%s] Listening on %s", bname, baddr)
|
||||
log.Logf("Broker [%s] Connected to %s", bname, baddr)
|
||||
|
||||
// announce self to the world
|
||||
if err := g.Register(); err != nil {
|
||||
|
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/registry"
|
||||
"github.com/micro/go-micro/server"
|
||||
"github.com/micro/go-micro/server/debug"
|
||||
"github.com/micro/go-micro/transport"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
@@ -89,10 +88,6 @@ func newOptions(opt ...server.Option) server.Options {
|
||||
opts.Transport = transport.DefaultTransport
|
||||
}
|
||||
|
||||
if opts.DebugHandler == nil {
|
||||
opts.DebugHandler = debug.DefaultHandler
|
||||
}
|
||||
|
||||
if len(opts.Address) == 0 {
|
||||
opts.Address = server.DefaultAddress
|
||||
}
|
||||
|
@@ -1,18 +1,15 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/micro/go-micro/broker"
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/metadata"
|
||||
"github.com/micro/go-micro/registry"
|
||||
"github.com/micro/go-micro/server"
|
||||
"github.com/micro/go-micro/util/buf"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -175,7 +172,7 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
|
||||
msg.Header["Content-Type"] = defaultContentType
|
||||
ct = defaultContentType
|
||||
}
|
||||
cf, err := g.newCodec(ct)
|
||||
cf, err := g.newGRPCCodec(ct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -205,15 +202,7 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
|
||||
req = req.Elem()
|
||||
}
|
||||
|
||||
b := buf.New(bytes.NewBuffer(msg.Body))
|
||||
co := cf(b)
|
||||
defer co.Close()
|
||||
|
||||
if err := co.ReadHeader(&codec.Message{}, codec.Event); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := co.ReadBody(req.Interface()); err != nil {
|
||||
if err := cf.Unmarshal(msg.Body, req.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/micro/go-micro/broker"
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/registry"
|
||||
"github.com/micro/go-micro/server/debug"
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
@@ -36,9 +35,6 @@ type Options struct {
|
||||
// The router for requests
|
||||
Router Router
|
||||
|
||||
// Debug Handler which can be set by a user
|
||||
DebugHandler debug.Handler
|
||||
|
||||
// Other options for implementations of the interface
|
||||
// can be stored in a context
|
||||
Context context.Context
|
||||
@@ -66,10 +62,6 @@ func newOptions(opt ...Option) Options {
|
||||
opts.Transport = transport.DefaultTransport
|
||||
}
|
||||
|
||||
if opts.DebugHandler == nil {
|
||||
opts.DebugHandler = debug.DefaultHandler
|
||||
}
|
||||
|
||||
if opts.RegisterCheck == nil {
|
||||
opts.RegisterCheck = DefaultRegisterCheck
|
||||
}
|
||||
@@ -156,13 +148,6 @@ func Transport(t transport.Transport) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// DebugHandler for this server
|
||||
func DebugHandler(d debug.Handler) Option {
|
||||
return func(o *Options) {
|
||||
o.DebugHandler = d
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata associated with the server
|
||||
func Metadata(md map[string]string) Option {
|
||||
return func(o *Options) {
|
||||
|
@@ -154,11 +154,10 @@ func setupProtocol(msg *transport.Message) codec.NewCodec {
|
||||
|
||||
func newRpcCodec(req *transport.Message, socket transport.Socket, c codec.NewCodec) codec.Codec {
|
||||
rwc := &readWriteCloser{
|
||||
rbuf: bytes.NewBuffer(req.Body),
|
||||
rbuf: bytes.NewBuffer(nil),
|
||||
wbuf: bytes.NewBuffer(nil),
|
||||
}
|
||||
r := &rpcCodec{
|
||||
first: true,
|
||||
buf: rwc,
|
||||
codec: c(rwc),
|
||||
req: req,
|
||||
@@ -174,33 +173,27 @@ func (c *rpcCodec) ReadHeader(r *codec.Message, t codec.MessageType) error {
|
||||
Body: c.req.Body,
|
||||
}
|
||||
|
||||
// if its a follow on request read it
|
||||
if !c.first {
|
||||
var tm transport.Message
|
||||
var tm transport.Message
|
||||
|
||||
// read off the socket
|
||||
if err := c.socket.Recv(&tm); err != nil {
|
||||
return err
|
||||
}
|
||||
// reset the read buffer
|
||||
c.buf.rbuf.Reset()
|
||||
// read off the socket
|
||||
if err := c.socket.Recv(&tm); err != nil {
|
||||
return err
|
||||
}
|
||||
// reset the read buffer
|
||||
c.buf.rbuf.Reset()
|
||||
|
||||
// write the body to the buffer
|
||||
if _, err := c.buf.rbuf.Write(tm.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the message header
|
||||
m.Header = tm.Header
|
||||
// set the message body
|
||||
m.Body = tm.Body
|
||||
|
||||
// set req
|
||||
c.req = &tm
|
||||
// write the body to the buffer
|
||||
if _, err := c.buf.rbuf.Write(tm.Body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// no longer first read
|
||||
c.first = false
|
||||
// set the message header
|
||||
m.Header = tm.Header
|
||||
// set the message body
|
||||
m.Body = tm.Body
|
||||
|
||||
// set req
|
||||
c.req = &tm
|
||||
|
||||
// set some internal things
|
||||
getHeaders(&m)
|
||||
|
@@ -16,6 +16,7 @@ type rpcRequest struct {
|
||||
body []byte
|
||||
rawBody interface{}
|
||||
stream bool
|
||||
first bool
|
||||
}
|
||||
|
||||
type rpcMessage struct {
|
||||
@@ -54,9 +55,9 @@ func (r *rpcRequest) Body() interface{} {
|
||||
|
||||
func (r *rpcRequest) Read() ([]byte, error) {
|
||||
// got a body
|
||||
if r.body != nil {
|
||||
if r.first {
|
||||
b := r.body
|
||||
r.body = nil
|
||||
r.first = false
|
||||
return b, nil
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/micro/go-micro/util/addr"
|
||||
log "github.com/micro/go-micro/util/log"
|
||||
mnet "github.com/micro/go-micro/util/net"
|
||||
"github.com/micro/go-micro/util/socket"
|
||||
)
|
||||
|
||||
type rpcServer struct {
|
||||
@@ -70,23 +71,99 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
}
|
||||
}()
|
||||
|
||||
// multiplex the streams on a single socket by Micro-Stream
|
||||
var mtx sync.RWMutex
|
||||
sockets := make(map[string]*socket.Socket)
|
||||
|
||||
for {
|
||||
var msg transport.Message
|
||||
if err := sock.Recv(&msg); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// use Micro-Stream as the stream identifier
|
||||
// in the event its blank we'll always process
|
||||
// on the same socket
|
||||
id := msg.Header["Micro-Stream"]
|
||||
|
||||
// if there's no stream id then its a standard request
|
||||
// use the Micro-Id
|
||||
if len(id) == 0 {
|
||||
id = msg.Header["Micro-Id"]
|
||||
}
|
||||
|
||||
// add to wait group if "wait" is opt-in
|
||||
if s.wg != nil {
|
||||
s.wg.Add(1)
|
||||
}
|
||||
|
||||
// check we have an existing socket
|
||||
mtx.RLock()
|
||||
psock, ok := sockets[id]
|
||||
mtx.RUnlock()
|
||||
|
||||
// got the socket
|
||||
if ok {
|
||||
// accept the message
|
||||
if err := psock.Accept(&msg); err != nil {
|
||||
// delete the socket
|
||||
mtx.Lock()
|
||||
delete(sockets, id)
|
||||
mtx.Unlock()
|
||||
}
|
||||
|
||||
// done(1)
|
||||
if s.wg != nil {
|
||||
s.wg.Done()
|
||||
}
|
||||
|
||||
// continue to the next message
|
||||
continue
|
||||
}
|
||||
|
||||
// no socket was found
|
||||
psock = socket.New()
|
||||
psock.SetLocal(sock.Local())
|
||||
psock.SetRemote(sock.Remote())
|
||||
|
||||
// load the socket
|
||||
psock.Accept(&msg)
|
||||
|
||||
// save a new socket
|
||||
mtx.Lock()
|
||||
sockets[id] = psock
|
||||
mtx.Unlock()
|
||||
|
||||
// process the outbound messages from the socket
|
||||
go func(id string, psock *socket.Socket) {
|
||||
defer psock.Close()
|
||||
|
||||
for {
|
||||
// get the message from our internal handler/stream
|
||||
m := new(transport.Message)
|
||||
if err := psock.Process(m); err != nil {
|
||||
// delete the socket
|
||||
mtx.Lock()
|
||||
delete(sockets, id)
|
||||
mtx.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
// send the message back over the socket
|
||||
if err := sock.Send(m); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}(id, psock)
|
||||
|
||||
// now walk the usual path
|
||||
|
||||
// we use this Timeout header to set a server deadline
|
||||
to := msg.Header["Timeout"]
|
||||
// we use this Content-Type header to identify the codec needed
|
||||
ct := msg.Header["Content-Type"]
|
||||
|
||||
// strip our headers
|
||||
// copy the message headers
|
||||
hdr := make(map[string]string)
|
||||
for k, v := range msg.Header {
|
||||
hdr[k] = v
|
||||
@@ -96,17 +173,17 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
hdr["Local"] = sock.Local()
|
||||
hdr["Remote"] = sock.Remote()
|
||||
|
||||
// create new context
|
||||
// create new context with the metadata
|
||||
ctx := metadata.NewContext(context.Background(), hdr)
|
||||
|
||||
// set the timeout if we have it
|
||||
// set the timeout from the header if we have it
|
||||
if len(to) > 0 {
|
||||
if n, err := strconv.ParseUint(to, 10, 64); err == nil {
|
||||
ctx, _ = context.WithTimeout(ctx, time.Duration(n))
|
||||
}
|
||||
}
|
||||
|
||||
// no content type
|
||||
// if there's no content type default it
|
||||
if len(ct) == 0 {
|
||||
msg.Header["Content-Type"] = DefaultContentType
|
||||
ct = DefaultContentType
|
||||
@@ -133,7 +210,13 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
}
|
||||
}
|
||||
|
||||
rcodec := newRpcCodec(&msg, sock, cf)
|
||||
rcodec := newRpcCodec(&msg, psock, cf)
|
||||
|
||||
// check stream id
|
||||
var stream bool
|
||||
if v := getHeader("Micro-Stream", msg.Header); len(v) > 0 {
|
||||
stream = true
|
||||
}
|
||||
|
||||
// internal request
|
||||
request := &rpcRequest{
|
||||
@@ -144,14 +227,14 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
codec: rcodec,
|
||||
header: msg.Header,
|
||||
body: msg.Body,
|
||||
socket: sock,
|
||||
stream: true,
|
||||
socket: psock,
|
||||
stream: stream,
|
||||
}
|
||||
|
||||
// internal response
|
||||
response := &rpcResponse{
|
||||
header: make(map[string]string),
|
||||
socket: sock,
|
||||
socket: psock,
|
||||
codec: rcodec,
|
||||
}
|
||||
|
||||
@@ -174,25 +257,34 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
r = rpcRouter{handler}
|
||||
}
|
||||
|
||||
// serve the actual request using the request router
|
||||
if err := r.ServeRequest(ctx, request, response); err != nil {
|
||||
// write an error response
|
||||
err = rcodec.Write(&codec.Message{
|
||||
Header: msg.Header,
|
||||
Error: err.Error(),
|
||||
Type: codec.Error,
|
||||
}, nil)
|
||||
// could not write the error response
|
||||
if err != nil {
|
||||
log.Logf("rpc: unable to write error response: %v", err)
|
||||
// serve the request in a go routine as this may be a stream
|
||||
go func(id string, psock *socket.Socket) {
|
||||
// serve the actual request using the request router
|
||||
if err := r.ServeRequest(ctx, request, response); err != nil {
|
||||
// write an error response
|
||||
err = rcodec.Write(&codec.Message{
|
||||
Header: msg.Header,
|
||||
Error: err.Error(),
|
||||
Type: codec.Error,
|
||||
}, nil)
|
||||
|
||||
// could not write the error response
|
||||
if err != nil {
|
||||
log.Logf("rpc: unable to write error response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
mtx.Lock()
|
||||
delete(sockets, id)
|
||||
mtx.Unlock()
|
||||
|
||||
// once done serving signal we're done
|
||||
if s.wg != nil {
|
||||
s.wg.Done()
|
||||
}
|
||||
return
|
||||
}
|
||||
}(id, psock)
|
||||
|
||||
// done
|
||||
// signal we're done
|
||||
if s.wg != nil {
|
||||
s.wg.Done()
|
||||
}
|
||||
@@ -315,10 +407,15 @@ func (s *rpcServer) Register() error {
|
||||
md[k] = v
|
||||
}
|
||||
|
||||
// mq-rpc(eg. nats) doesn't need the port. its addr is queue name.
|
||||
if port != "" {
|
||||
addr = mnet.HostPort(addr, port)
|
||||
}
|
||||
|
||||
// register service
|
||||
node := ®istry.Node{
|
||||
Id: config.Name + "-" + config.Id,
|
||||
Address: mnet.HostPort(addr, port),
|
||||
Address: addr,
|
||||
Metadata: md,
|
||||
}
|
||||
|
||||
@@ -447,9 +544,14 @@ func (s *rpcServer) Deregister() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// mq-rpc(eg. nats) doesn't need the port. its addr is queue name.
|
||||
if port != "" {
|
||||
addr = mnet.HostPort(addr, port)
|
||||
}
|
||||
|
||||
node := ®istry.Node{
|
||||
Id: config.Name + "-" + config.Id,
|
||||
Address: mnet.HostPort(addr, port),
|
||||
Address: addr,
|
||||
}
|
||||
|
||||
service := ®istry.Service{
|
||||
@@ -485,7 +587,6 @@ func (s *rpcServer) Deregister() error {
|
||||
}
|
||||
|
||||
func (s *rpcServer) Start() error {
|
||||
registerDebugHandler(s)
|
||||
config := s.Options()
|
||||
|
||||
// start listening on the transport
|
||||
|
@@ -2,6 +2,8 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/micro/go-micro/codec"
|
||||
@@ -59,6 +61,20 @@ func (r *rpcStream) Recv(msg interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// check the error
|
||||
if len(req.Error) > 0 {
|
||||
// Check the client closed the stream
|
||||
switch req.Error {
|
||||
case lastStreamResponseError.Error():
|
||||
// discard body
|
||||
r.codec.ReadBody(nil)
|
||||
r.err = io.EOF
|
||||
return io.EOF
|
||||
default:
|
||||
return errors.New(req.Error)
|
||||
}
|
||||
}
|
||||
|
||||
// we need to stay up to date with sequence numbers
|
||||
r.id = req.Id
|
||||
if err := r.codec.ReadBody(msg); err != nil {
|
||||
|
@@ -142,6 +142,11 @@ func NewServer(opt ...Option) Server {
|
||||
return newRpcServer(opt...)
|
||||
}
|
||||
|
||||
// NewRouter returns a new router
|
||||
func NewRouter() *router {
|
||||
return newRpcRouter()
|
||||
}
|
||||
|
||||
// NewSubscriber creates a new subscriber interface with the given topic
|
||||
// and handler using the default server
|
||||
func NewSubscriber(topic string, h interface{}, opts ...SubscriberOption) Subscriber {
|
||||
|
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/config/cmd"
|
||||
"github.com/micro/go-micro/debug/handler"
|
||||
"github.com/micro/go-micro/metadata"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
@@ -113,6 +114,14 @@ func (s *service) Stop() error {
|
||||
}
|
||||
|
||||
func (s *service) Run() error {
|
||||
// register the debug handler
|
||||
s.opts.Server.Handle(
|
||||
s.opts.Server.NewHandler(
|
||||
handler.DefaultHandler,
|
||||
server.InternalHandler(true),
|
||||
),
|
||||
)
|
||||
|
||||
if err := s.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
220
service/options.go
Normal file
220
service/options.go
Normal file
@@ -0,0 +1,220 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/broker"
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/registry"
|
||||
"github.com/micro/go-micro/server"
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Broker broker.Broker
|
||||
Client client.Client
|
||||
Server server.Server
|
||||
Registry registry.Registry
|
||||
Transport transport.Transport
|
||||
|
||||
// Before and After funcs
|
||||
BeforeStart []func() error
|
||||
BeforeStop []func() error
|
||||
AfterStart []func() error
|
||||
AfterStop []func() error
|
||||
|
||||
// Other options for implementations of the interface
|
||||
// can be stored in a context
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
type Option func(*Options)
|
||||
|
||||
func newOptions(opts ...Option) Options {
|
||||
opt := Options{
|
||||
Broker: broker.DefaultBroker,
|
||||
Client: client.DefaultClient,
|
||||
Server: server.DefaultServer,
|
||||
Registry: registry.DefaultRegistry,
|
||||
Transport: transport.DefaultTransport,
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
return opt
|
||||
}
|
||||
|
||||
func Broker(b broker.Broker) Option {
|
||||
return func(o *Options) {
|
||||
o.Broker = b
|
||||
// Update Client and Server
|
||||
o.Client.Init(client.Broker(b))
|
||||
o.Server.Init(server.Broker(b))
|
||||
}
|
||||
}
|
||||
|
||||
func Client(c client.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
}
|
||||
}
|
||||
|
||||
// Context specifies a context for the service.
|
||||
// Can be used to signal shutdown of the service.
|
||||
// Can be used for extra option values.
|
||||
func Context(ctx context.Context) Option {
|
||||
return func(o *Options) {
|
||||
o.Context = ctx
|
||||
}
|
||||
}
|
||||
|
||||
func Server(s server.Server) Option {
|
||||
return func(o *Options) {
|
||||
o.Server = s
|
||||
}
|
||||
}
|
||||
|
||||
// Registry sets the registry for the service
|
||||
// and the underlying components
|
||||
func Registry(r registry.Registry) Option {
|
||||
return func(o *Options) {
|
||||
o.Registry = r
|
||||
// Update Client and Server
|
||||
o.Client.Init(client.Registry(r))
|
||||
o.Server.Init(server.Registry(r))
|
||||
// Update Broker
|
||||
o.Broker.Init(broker.Registry(r))
|
||||
}
|
||||
}
|
||||
|
||||
// Transport sets the transport for the service
|
||||
// and the underlying components
|
||||
func Transport(t transport.Transport) Option {
|
||||
return func(o *Options) {
|
||||
o.Transport = t
|
||||
// Update Client and Server
|
||||
o.Client.Init(client.Transport(t))
|
||||
o.Server.Init(server.Transport(t))
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience options
|
||||
|
||||
// Address sets the address of the server
|
||||
func Address(addr string) Option {
|
||||
return func(o *Options) {
|
||||
o.Server.Init(server.Address(addr))
|
||||
}
|
||||
}
|
||||
|
||||
// Name of the service
|
||||
func Name(n string) Option {
|
||||
return func(o *Options) {
|
||||
o.Server.Init(server.Name(n))
|
||||
}
|
||||
}
|
||||
|
||||
// Version of the service
|
||||
func Version(v string) Option {
|
||||
return func(o *Options) {
|
||||
o.Server.Init(server.Version(v))
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata associated with the service
|
||||
func Metadata(md map[string]string) Option {
|
||||
return func(o *Options) {
|
||||
o.Server.Init(server.Metadata(md))
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterTTL specifies the TTL to use when registering the service
|
||||
func RegisterTTL(t time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.Server.Init(server.RegisterTTL(t))
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterInterval specifies the interval on which to re-register
|
||||
func RegisterInterval(t time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.Server.Init(server.RegisterInterval(t))
|
||||
}
|
||||
}
|
||||
|
||||
// WrapClient is a convenience method for wrapping a Client with
|
||||
// some middleware component. A list of wrappers can be provided.
|
||||
// Wrappers are applied in reverse order so the last is executed first.
|
||||
func WrapClient(w ...client.Wrapper) Option {
|
||||
return func(o *Options) {
|
||||
// apply in reverse
|
||||
for i := len(w); i > 0; i-- {
|
||||
o.Client = w[i-1](o.Client)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WrapCall is a convenience method for wrapping a Client CallFunc
|
||||
func WrapCall(w ...client.CallWrapper) Option {
|
||||
return func(o *Options) {
|
||||
o.Client.Init(client.WrapCall(w...))
|
||||
}
|
||||
}
|
||||
|
||||
// WrapHandler adds a handler Wrapper to a list of options passed into the server
|
||||
func WrapHandler(w ...server.HandlerWrapper) Option {
|
||||
return func(o *Options) {
|
||||
var wrappers []server.Option
|
||||
|
||||
for _, wrap := range w {
|
||||
wrappers = append(wrappers, server.WrapHandler(wrap))
|
||||
}
|
||||
|
||||
// Init once
|
||||
o.Server.Init(wrappers...)
|
||||
}
|
||||
}
|
||||
|
||||
// WrapSubscriber adds a subscriber Wrapper to a list of options passed into the server
|
||||
func WrapSubscriber(w ...server.SubscriberWrapper) Option {
|
||||
return func(o *Options) {
|
||||
var wrappers []server.Option
|
||||
|
||||
for _, wrap := range w {
|
||||
wrappers = append(wrappers, server.WrapSubscriber(wrap))
|
||||
}
|
||||
|
||||
// Init once
|
||||
o.Server.Init(wrappers...)
|
||||
}
|
||||
}
|
||||
|
||||
// Before and Afters
|
||||
|
||||
func BeforeStart(fn func() error) Option {
|
||||
return func(o *Options) {
|
||||
o.BeforeStart = append(o.BeforeStart, fn)
|
||||
}
|
||||
}
|
||||
|
||||
func BeforeStop(fn func() error) Option {
|
||||
return func(o *Options) {
|
||||
o.BeforeStop = append(o.BeforeStop, fn)
|
||||
}
|
||||
}
|
||||
|
||||
func AfterStart(fn func() error) Option {
|
||||
return func(o *Options) {
|
||||
o.AfterStart = append(o.AfterStart, fn)
|
||||
}
|
||||
}
|
||||
|
||||
func AfterStop(fn func() error) Option {
|
||||
return func(o *Options) {
|
||||
o.AfterStop = append(o.AfterStop, fn)
|
||||
}
|
||||
}
|
@@ -1,2 +1,16 @@
|
||||
// Package service encapsulates the client, server and other interfaces to provide a complete micro service.
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
Init(...Option)
|
||||
Options() Options
|
||||
Client() client.Client
|
||||
Server() server.Server
|
||||
Run() error
|
||||
String() string
|
||||
}
|
||||
|
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
glog "github.com/go-log/log"
|
||||
"github.com/micro/go-micro/client"
|
||||
proto "github.com/micro/go-micro/debug/proto"
|
||||
"github.com/micro/go-micro/registry/memory"
|
||||
proto "github.com/micro/go-micro/server/debug/proto"
|
||||
"github.com/micro/go-micro/util/log"
|
||||
)
|
||||
|
||||
|
@@ -2,6 +2,7 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
@@ -24,6 +25,10 @@ type memorySocket struct {
|
||||
|
||||
local string
|
||||
remote string
|
||||
|
||||
// for send/recv transport.Timeout
|
||||
timeout time.Duration
|
||||
ctx context.Context
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
@@ -33,11 +38,13 @@ type memoryClient struct {
|
||||
}
|
||||
|
||||
type memoryListener struct {
|
||||
addr string
|
||||
exit chan bool
|
||||
conn chan *memorySocket
|
||||
opts transport.ListenOptions
|
||||
addr string
|
||||
exit chan bool
|
||||
conn chan *memorySocket
|
||||
lopts transport.ListenOptions
|
||||
topts transport.Options
|
||||
sync.RWMutex
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
type memoryTransport struct {
|
||||
@@ -49,7 +56,17 @@ type memoryTransport struct {
|
||||
func (ms *memorySocket) Recv(m *transport.Message) error {
|
||||
ms.RLock()
|
||||
defer ms.RUnlock()
|
||||
|
||||
ctx := ms.ctx
|
||||
if ms.timeout > 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ms.ctx, ms.timeout)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-ms.exit:
|
||||
return errors.New("connection closed")
|
||||
case <-ms.lexit:
|
||||
@@ -71,7 +88,17 @@ func (ms *memorySocket) Remote() string {
|
||||
func (ms *memorySocket) Send(m *transport.Message) error {
|
||||
ms.RLock()
|
||||
defer ms.RUnlock()
|
||||
|
||||
ctx := ms.ctx
|
||||
if ms.timeout > 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ms.ctx, ms.timeout)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-ms.exit:
|
||||
return errors.New("connection closed")
|
||||
case <-ms.lexit:
|
||||
@@ -116,12 +143,14 @@ func (m *memoryListener) Accept(fn func(transport.Socket)) error {
|
||||
return nil
|
||||
case c := <-m.conn:
|
||||
go fn(&memorySocket{
|
||||
lexit: c.lexit,
|
||||
exit: c.exit,
|
||||
send: c.recv,
|
||||
recv: c.send,
|
||||
local: c.Remote(),
|
||||
remote: c.Local(),
|
||||
lexit: c.lexit,
|
||||
exit: c.exit,
|
||||
send: c.recv,
|
||||
recv: c.send,
|
||||
local: c.Remote(),
|
||||
remote: c.Local(),
|
||||
timeout: m.topts.Timeout,
|
||||
ctx: m.topts.Context,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -143,12 +172,14 @@ func (m *memoryTransport) Dial(addr string, opts ...transport.DialOption) (trans
|
||||
|
||||
client := &memoryClient{
|
||||
&memorySocket{
|
||||
send: make(chan *transport.Message),
|
||||
recv: make(chan *transport.Message),
|
||||
exit: make(chan bool),
|
||||
lexit: listener.exit,
|
||||
local: addr,
|
||||
remote: addr,
|
||||
send: make(chan *transport.Message),
|
||||
recv: make(chan *transport.Message),
|
||||
exit: make(chan bool),
|
||||
lexit: listener.exit,
|
||||
local: addr,
|
||||
remote: addr,
|
||||
timeout: m.opts.Timeout,
|
||||
ctx: m.opts.Context,
|
||||
},
|
||||
options,
|
||||
}
|
||||
@@ -196,10 +227,12 @@ func (m *memoryTransport) Listen(addr string, opts ...transport.ListenOption) (t
|
||||
}
|
||||
|
||||
listener := &memoryListener{
|
||||
opts: options,
|
||||
addr: addr,
|
||||
conn: make(chan *memorySocket),
|
||||
exit: make(chan bool),
|
||||
lopts: options,
|
||||
topts: m.opts,
|
||||
addr: addr,
|
||||
conn: make(chan *memorySocket),
|
||||
exit: make(chan bool),
|
||||
ctx: m.opts.Context,
|
||||
}
|
||||
|
||||
m.listeners[addr] = listener
|
||||
@@ -223,12 +256,18 @@ func (m *memoryTransport) String() string {
|
||||
}
|
||||
|
||||
func NewTransport(opts ...transport.Option) transport.Transport {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
var options transport.Options
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
if options.Context == nil {
|
||||
options.Context = context.Background()
|
||||
}
|
||||
|
||||
return &memoryTransport{
|
||||
opts: options,
|
||||
listeners: make(map[string]*memoryListener),
|
||||
|
@@ -113,7 +113,7 @@ func (q *quicTransport) Dial(addr string, opts ...transport.DialOption) (transpo
|
||||
NextProtos: []string{"http/1.1"},
|
||||
}
|
||||
}
|
||||
s, err := quic.DialAddr(addr, config, nil)
|
||||
s, err := quic.DialAddr(addr, config, &quic.Config{KeepAlive: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -156,7 +156,7 @@ func (q *quicTransport) Listen(addr string, opts ...transport.ListenOption) (tra
|
||||
}
|
||||
}
|
||||
|
||||
l, err := quic.ListenAddr(addr, config, nil)
|
||||
l, err := quic.ListenAddr(addr, config, &quic.Config{KeepAlive: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
593
tunnel/default.go
Normal file
593
tunnel/default.go
Normal file
@@ -0,0 +1,593 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/transport"
|
||||
"github.com/micro/go-micro/util/log"
|
||||
)
|
||||
|
||||
var (
|
||||
// KeepAliveTime defines time interval we send keepalive messages to outbound links
|
||||
KeepAliveTime = 30 * time.Second
|
||||
// ReconnectTime defines time interval we periodically attempt to reconnect dead links
|
||||
ReconnectTime = 5 * time.Second
|
||||
)
|
||||
|
||||
// tun represents a network tunnel
|
||||
type tun struct {
|
||||
options Options
|
||||
|
||||
sync.RWMutex
|
||||
|
||||
// tunnel token
|
||||
token string
|
||||
|
||||
// to indicate if we're connected or not
|
||||
connected bool
|
||||
|
||||
// the send channel for all messages
|
||||
send chan *message
|
||||
|
||||
// close channel
|
||||
closed chan bool
|
||||
|
||||
// a map of sockets based on Micro-Tunnel-Id
|
||||
sockets map[string]*socket
|
||||
|
||||
// outbound links
|
||||
links map[string]*link
|
||||
|
||||
// listener
|
||||
listener transport.Listener
|
||||
}
|
||||
|
||||
type link struct {
|
||||
transport.Socket
|
||||
id string
|
||||
loopback bool
|
||||
lastKeepAlive time.Time
|
||||
}
|
||||
|
||||
// create new tunnel on top of a link
|
||||
func newTunnel(opts ...Option) *tun {
|
||||
options := DefaultOptions()
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &tun{
|
||||
options: options,
|
||||
token: uuid.New().String(),
|
||||
send: make(chan *message, 128),
|
||||
closed: make(chan bool),
|
||||
sockets: make(map[string]*socket),
|
||||
links: make(map[string]*link),
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes tunnel options
|
||||
func (t *tun) Init(opts ...Option) error {
|
||||
for _, o := range opts {
|
||||
o(&t.options)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getSocket returns a socket from the internal socket map.
|
||||
// It does this based on the Micro-Tunnel-Id and Micro-Tunnel-Session
|
||||
func (t *tun) getSocket(id, session string) (*socket, bool) {
|
||||
// get the socket
|
||||
t.RLock()
|
||||
s, ok := t.sockets[id+session]
|
||||
t.RUnlock()
|
||||
return s, ok
|
||||
}
|
||||
|
||||
// newSocket creates a new socket and saves it
|
||||
func (t *tun) newSocket(id, session string) (*socket, bool) {
|
||||
// hash the id
|
||||
h := sha256.New()
|
||||
h.Write([]byte(id))
|
||||
id = fmt.Sprintf("%x", h.Sum(nil))
|
||||
|
||||
// new socket
|
||||
s := &socket{
|
||||
id: id,
|
||||
session: session,
|
||||
closed: make(chan bool),
|
||||
recv: make(chan *message, 128),
|
||||
send: t.send,
|
||||
wait: make(chan bool),
|
||||
}
|
||||
|
||||
// save socket
|
||||
t.Lock()
|
||||
_, ok := t.sockets[id+session]
|
||||
if ok {
|
||||
// socket already exists
|
||||
t.Unlock()
|
||||
return nil, false
|
||||
}
|
||||
|
||||
t.sockets[id+session] = s
|
||||
t.Unlock()
|
||||
|
||||
// return socket
|
||||
return s, true
|
||||
}
|
||||
|
||||
// TODO: use tunnel id as part of the session
|
||||
func (t *tun) newSession() string {
|
||||
return uuid.New().String()
|
||||
}
|
||||
|
||||
// monitor monitors outbound links and attempts to reconnect to the failed ones
|
||||
func (t *tun) monitor() {
|
||||
reconnect := time.NewTicker(ReconnectTime)
|
||||
defer reconnect.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-t.closed:
|
||||
return
|
||||
case <-reconnect.C:
|
||||
for _, node := range t.options.Nodes {
|
||||
t.Lock()
|
||||
if _, ok := t.links[node]; !ok {
|
||||
link, err := t.setupLink(node)
|
||||
if err != nil {
|
||||
log.Debugf("Tunnel failed to setup node link to %s: %v", node, err)
|
||||
t.Unlock()
|
||||
continue
|
||||
}
|
||||
t.links[node] = link
|
||||
}
|
||||
t.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process outgoing messages sent by all local sockets
|
||||
func (t *tun) process() {
|
||||
// manage the send buffer
|
||||
// all pseudo sockets throw everything down this
|
||||
for {
|
||||
select {
|
||||
case msg := <-t.send:
|
||||
newMsg := &transport.Message{
|
||||
Header: make(map[string]string),
|
||||
Body: msg.data.Body,
|
||||
}
|
||||
|
||||
for k, v := range msg.data.Header {
|
||||
newMsg.Header[k] = v
|
||||
}
|
||||
|
||||
// set the tunnel id on the outgoing message
|
||||
newMsg.Header["Micro-Tunnel-Id"] = msg.id
|
||||
|
||||
// set the session id
|
||||
newMsg.Header["Micro-Tunnel-Session"] = msg.session
|
||||
|
||||
// set the tunnel token
|
||||
newMsg.Header["Micro-Tunnel-Token"] = t.token
|
||||
|
||||
// send the message via the interface
|
||||
t.Lock()
|
||||
if len(t.links) == 0 {
|
||||
log.Debugf("No links to send to")
|
||||
}
|
||||
for node, link := range t.links {
|
||||
if link.loopback && msg.outbound {
|
||||
continue
|
||||
}
|
||||
log.Debugf("Sending %+v to %s", newMsg, node)
|
||||
if err := link.Send(newMsg); err != nil {
|
||||
log.Debugf("Tunnel error sending %+v to %s: %v", newMsg, node, err)
|
||||
delete(t.links, node)
|
||||
continue
|
||||
}
|
||||
}
|
||||
t.Unlock()
|
||||
case <-t.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// process incoming messages
|
||||
func (t *tun) listen(link *link) {
|
||||
for {
|
||||
// process anything via the net interface
|
||||
msg := new(transport.Message)
|
||||
err := link.Recv(msg)
|
||||
if err != nil {
|
||||
log.Debugf("Tunnel link %s receive error: %#v", link.Remote(), err)
|
||||
t.Lock()
|
||||
delete(t.links, link.Remote())
|
||||
t.Unlock()
|
||||
return
|
||||
}
|
||||
|
||||
switch msg.Header["Micro-Tunnel"] {
|
||||
case "connect":
|
||||
log.Debugf("Tunnel link %s received connect message", link.Remote())
|
||||
// check the Micro-Tunnel-Token
|
||||
token, ok := msg.Header["Micro-Tunnel-Token"]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// are we connecting to ourselves?
|
||||
if token == t.token {
|
||||
link.loopback = true
|
||||
}
|
||||
continue
|
||||
case "close":
|
||||
log.Debugf("Tunnel link %s closing connection", link.Remote())
|
||||
// TODO: handle the close message
|
||||
// maybe report io.EOF or kill the link
|
||||
continue
|
||||
case "keepalive":
|
||||
log.Debugf("Tunnel link %s received keepalive", link.Remote())
|
||||
link.lastKeepAlive = time.Now()
|
||||
continue
|
||||
}
|
||||
|
||||
// the tunnel id
|
||||
id := msg.Header["Micro-Tunnel-Id"]
|
||||
delete(msg.Header, "Micro-Tunnel-Id")
|
||||
|
||||
// the session id
|
||||
session := msg.Header["Micro-Tunnel-Session"]
|
||||
delete(msg.Header, "Micro-Tunnel-Session")
|
||||
|
||||
// if the session id is blank there's nothing we can do
|
||||
// TODO: check this is the case, is there any reason
|
||||
// why we'd have a blank session? Is the tunnel
|
||||
// used for some other purpose?
|
||||
if len(id) == 0 || len(session) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var s *socket
|
||||
var exists bool
|
||||
|
||||
log.Debugf("Received %+v from %s", msg, link.Remote())
|
||||
|
||||
switch {
|
||||
case link.loopback:
|
||||
s, exists = t.getSocket(id, "listener")
|
||||
default:
|
||||
// get the socket based on the tunnel id and session
|
||||
// this could be something we dialed in which case
|
||||
// we have a session for it otherwise its a listener
|
||||
s, exists = t.getSocket(id, session)
|
||||
if !exists {
|
||||
// try get it based on just the tunnel id
|
||||
// the assumption here is that a listener
|
||||
// has no session but its set a listener session
|
||||
s, exists = t.getSocket(id, "listener")
|
||||
}
|
||||
}
|
||||
// bail if no socket has been found
|
||||
if !exists {
|
||||
log.Debugf("Tunnel skipping no socket exists")
|
||||
// drop it, we don't care about
|
||||
// messages we don't know about
|
||||
continue
|
||||
}
|
||||
log.Debugf("Tunnel using socket %s %s", s.id, s.session)
|
||||
|
||||
// is the socket closed?
|
||||
select {
|
||||
case <-s.closed:
|
||||
// closed
|
||||
delete(t.sockets, id)
|
||||
continue
|
||||
default:
|
||||
// process
|
||||
}
|
||||
|
||||
// is the socket new?
|
||||
select {
|
||||
// if its new the socket is actually blocked waiting
|
||||
// for a connection. so we check if its waiting.
|
||||
case <-s.wait:
|
||||
// if its waiting e.g its new then we close it
|
||||
default:
|
||||
// set remote address of the socket
|
||||
s.remote = msg.Header["Remote"]
|
||||
close(s.wait)
|
||||
}
|
||||
|
||||
// construct a new transport message
|
||||
tmsg := &transport.Message{
|
||||
Header: msg.Header,
|
||||
Body: msg.Body,
|
||||
}
|
||||
|
||||
// construct the internal message
|
||||
imsg := &message{
|
||||
id: id,
|
||||
session: session,
|
||||
data: tmsg,
|
||||
}
|
||||
|
||||
// append to recv backlog
|
||||
// we don't block if we can't pass it on
|
||||
select {
|
||||
case s.recv <- imsg:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// keepalive periodically sends keepalive messages to link
|
||||
func (t *tun) keepalive(link *link) {
|
||||
keepalive := time.NewTicker(KeepAliveTime)
|
||||
defer keepalive.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-t.closed:
|
||||
return
|
||||
case <-keepalive.C:
|
||||
// send keepalive message
|
||||
log.Debugf("Tunnel sending keepalive to link: %v", link.Remote())
|
||||
if err := link.Send(&transport.Message{
|
||||
Header: map[string]string{
|
||||
"Micro-Tunnel": "keepalive",
|
||||
"Micro-Tunnel-Token": t.token,
|
||||
},
|
||||
}); err != nil {
|
||||
log.Debugf("Error sending keepalive to link %v: %v", link.Remote(), err)
|
||||
t.Lock()
|
||||
delete(t.links, link.Remote())
|
||||
t.Unlock()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setupLink connects to node and returns link if successful
|
||||
// It returns error if the link failed to be established
|
||||
func (t *tun) setupLink(node string) (*link, error) {
|
||||
log.Debugf("Tunnel dialing %s", node)
|
||||
c, err := t.options.Transport.Dial(node)
|
||||
if err != nil {
|
||||
log.Debugf("Tunnel failed to connect to %s: %v", node, err)
|
||||
return nil, err
|
||||
}
|
||||
log.Debugf("Tunnel connected to %s", node)
|
||||
|
||||
if err := c.Send(&transport.Message{
|
||||
Header: map[string]string{
|
||||
"Micro-Tunnel": "connect",
|
||||
"Micro-Tunnel-Token": t.token,
|
||||
},
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// save the link
|
||||
id := uuid.New().String()
|
||||
link := &link{
|
||||
Socket: c,
|
||||
id: id,
|
||||
}
|
||||
t.links[node] = link
|
||||
|
||||
// process incoming messages
|
||||
go t.listen(link)
|
||||
|
||||
// start keepalive monitor
|
||||
go t.keepalive(link)
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
// connect the tunnel to all the nodes and listen for incoming tunnel connections
|
||||
func (t *tun) connect() error {
|
||||
l, err := t.options.Transport.Listen(t.options.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// save the listener
|
||||
t.listener = l
|
||||
|
||||
go func() {
|
||||
// accept inbound connections
|
||||
err := l.Accept(func(sock transport.Socket) {
|
||||
log.Debugf("Tunnel accepted connection from %s", sock.Remote())
|
||||
// save the link
|
||||
id := uuid.New().String()
|
||||
t.Lock()
|
||||
link := &link{
|
||||
Socket: sock,
|
||||
id: id,
|
||||
}
|
||||
t.links[sock.Remote()] = link
|
||||
t.Unlock()
|
||||
|
||||
// delete the link
|
||||
defer func() {
|
||||
log.Debugf("Tunnel deleting connection from %s", sock.Remote())
|
||||
t.Lock()
|
||||
delete(t.links, sock.Remote())
|
||||
t.Unlock()
|
||||
}()
|
||||
|
||||
// listen for inbound messages
|
||||
t.listen(link)
|
||||
})
|
||||
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
// still connected but the tunnel died
|
||||
if err != nil && t.connected {
|
||||
log.Logf("Tunnel listener died: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
for _, node := range t.options.Nodes {
|
||||
// skip zero length nodes
|
||||
if len(node) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// connect to node and return link
|
||||
link, err := t.setupLink(node)
|
||||
if err != nil {
|
||||
log.Debugf("Tunnel failed to establish node link to %s: %v", node, err)
|
||||
continue
|
||||
}
|
||||
// save the link
|
||||
t.links[node] = link
|
||||
}
|
||||
|
||||
// process outbound messages to be sent
|
||||
// process sends to all links
|
||||
go t.process()
|
||||
|
||||
// monitor links
|
||||
go t.monitor()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Connect the tunnel
|
||||
func (t *tun) Connect() error {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
// already connected
|
||||
if t.connected {
|
||||
return nil
|
||||
}
|
||||
|
||||
// send the connect message
|
||||
if err := t.connect(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set as connected
|
||||
t.connected = true
|
||||
// create new close channel
|
||||
t.closed = make(chan bool)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *tun) close() error {
|
||||
// close all the links
|
||||
for node, link := range t.links {
|
||||
link.Send(&transport.Message{
|
||||
Header: map[string]string{
|
||||
"Micro-Tunnel": "close",
|
||||
"Micro-Tunnel-Token": t.token,
|
||||
},
|
||||
})
|
||||
link.Close()
|
||||
delete(t.links, node)
|
||||
}
|
||||
|
||||
// close the listener
|
||||
return t.listener.Close()
|
||||
}
|
||||
|
||||
// Close the tunnel
|
||||
func (t *tun) Close() error {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
if !t.connected {
|
||||
return nil
|
||||
}
|
||||
|
||||
select {
|
||||
case <-t.closed:
|
||||
return nil
|
||||
default:
|
||||
// close all the sockets
|
||||
for id, s := range t.sockets {
|
||||
s.Close()
|
||||
delete(t.sockets, id)
|
||||
}
|
||||
// close the connection
|
||||
close(t.closed)
|
||||
t.connected = false
|
||||
|
||||
// send a close message
|
||||
// we don't close the link
|
||||
// just the tunnel
|
||||
return t.close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dial an address
|
||||
func (t *tun) Dial(addr string) (Conn, error) {
|
||||
log.Debugf("Tunnel dialing %s", addr)
|
||||
c, ok := t.newSocket(addr, t.newSession())
|
||||
if !ok {
|
||||
return nil, errors.New("error dialing " + addr)
|
||||
}
|
||||
// set remote
|
||||
c.remote = addr
|
||||
// set local
|
||||
c.local = "local"
|
||||
// outbound socket
|
||||
c.outbound = true
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Accept a connection on the address
|
||||
func (t *tun) Listen(addr string) (Listener, error) {
|
||||
log.Debugf("Tunnel listening on %s", addr)
|
||||
// create a new socket by hashing the address
|
||||
c, ok := t.newSocket(addr, "listener")
|
||||
if !ok {
|
||||
return nil, errors.New("already listening on " + addr)
|
||||
}
|
||||
|
||||
// set remote. it will be replaced by the first message received
|
||||
c.remote = "remote"
|
||||
// set local
|
||||
c.local = addr
|
||||
|
||||
tl := &tunListener{
|
||||
addr: addr,
|
||||
// the accept channel
|
||||
accept: make(chan *socket, 128),
|
||||
// the channel to close
|
||||
closed: make(chan bool),
|
||||
// tunnel closed channel
|
||||
tunClosed: t.closed,
|
||||
// the connection
|
||||
conn: c,
|
||||
// the listener socket
|
||||
socket: c,
|
||||
}
|
||||
|
||||
// this kicks off the internal message processor
|
||||
// for the listener so it can create pseudo sockets
|
||||
// per session if they do not exist or pass messages
|
||||
// to the existign sessions
|
||||
go tl.process()
|
||||
|
||||
// return the listener
|
||||
return tl, nil
|
||||
}
|
@@ -2,6 +2,8 @@ package tunnel
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/micro/go-micro/util/log"
|
||||
)
|
||||
|
||||
type tunListener struct {
|
||||
@@ -11,6 +13,8 @@ type tunListener struct {
|
||||
accept chan *socket
|
||||
// the channel to close
|
||||
closed chan bool
|
||||
// the tunnel closed channel
|
||||
tunClosed chan bool
|
||||
// the connection
|
||||
conn Conn
|
||||
// the listener socket
|
||||
@@ -29,6 +33,7 @@ func (t *tunListener) process() {
|
||||
case m := <-t.socket.recv:
|
||||
// get a socket
|
||||
sock, ok := conns[m.session]
|
||||
log.Debugf("Tunnel listener received id %s session %s exists: %t", m.id, m.session, ok)
|
||||
if !ok {
|
||||
// create a new socket session
|
||||
sock = &socket{
|
||||
@@ -46,9 +51,6 @@ func (t *tunListener) process() {
|
||||
wait: make(chan bool),
|
||||
}
|
||||
|
||||
// first message
|
||||
sock.recv <- m
|
||||
|
||||
// save the socket
|
||||
conns[m.session] = sock
|
||||
|
||||
@@ -65,6 +67,7 @@ func (t *tunListener) process() {
|
||||
case <-sock.closed:
|
||||
delete(conns, m.session)
|
||||
case sock.recv <- m:
|
||||
log.Debugf("Tunnel listener sent to recv chan id %s session %s", m.id, m.session)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +77,7 @@ func (t *tunListener) Addr() string {
|
||||
return t.addr
|
||||
}
|
||||
|
||||
// Close closes tunnel listener
|
||||
func (t *tunListener) Close() error {
|
||||
select {
|
||||
case <-t.closed:
|
||||
@@ -90,6 +94,10 @@ func (t *tunListener) Accept() (Conn, error) {
|
||||
// if the socket is closed return
|
||||
case <-t.closed:
|
||||
return nil, io.EOF
|
||||
case <-t.tunClosed:
|
||||
// close the listener when the tunnel closes
|
||||
t.Close()
|
||||
return nil, io.EOF
|
||||
// wait for a new connection
|
||||
case c, ok := <-t.accept:
|
||||
if !ok {
|
63
tunnel/options.go
Normal file
63
tunnel/options.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/transport"
|
||||
"github.com/micro/go-micro/transport/quic"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultAddress is default tunnel bind address
|
||||
DefaultAddress = ":9096"
|
||||
)
|
||||
|
||||
type Option func(*Options)
|
||||
|
||||
// Options provides network configuration options
|
||||
type Options struct {
|
||||
// Id is tunnel id
|
||||
Id string
|
||||
// Address is tunnel address
|
||||
Address string
|
||||
// Nodes are remote nodes
|
||||
Nodes []string
|
||||
// Transport listens to incoming connections
|
||||
Transport transport.Transport
|
||||
}
|
||||
|
||||
// The tunnel id
|
||||
func Id(id string) Option {
|
||||
return func(o *Options) {
|
||||
o.Id = id
|
||||
}
|
||||
}
|
||||
|
||||
// The tunnel address
|
||||
func Address(a string) Option {
|
||||
return func(o *Options) {
|
||||
o.Address = a
|
||||
}
|
||||
}
|
||||
|
||||
// Nodes specify remote network nodes
|
||||
func Nodes(n ...string) Option {
|
||||
return func(o *Options) {
|
||||
o.Nodes = n
|
||||
}
|
||||
}
|
||||
|
||||
// Transport listens for incoming connections
|
||||
func Transport(t transport.Transport) Option {
|
||||
return func(o *Options) {
|
||||
o.Transport = t
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultOptions returns router default options
|
||||
func DefaultOptions() Options {
|
||||
return Options{
|
||||
Id: uuid.New().String(),
|
||||
Address: DefaultAddress,
|
||||
Transport: quic.NewTransport(),
|
||||
}
|
||||
}
|
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
|
||||
"github.com/micro/go-micro/transport"
|
||||
"github.com/micro/go-micro/util/log"
|
||||
)
|
||||
|
||||
// socket is our pseudo socket for transport.Socket
|
||||
@@ -24,6 +25,8 @@ type socket struct {
|
||||
recv chan *message
|
||||
// wait until we have a connection
|
||||
wait chan bool
|
||||
// outbound marks the socket as outbound
|
||||
outbound bool
|
||||
}
|
||||
|
||||
// message is sent over the send channel
|
||||
@@ -32,6 +35,8 @@ type message struct {
|
||||
id string
|
||||
// the session id
|
||||
session string
|
||||
// outbound marks the message as outbound
|
||||
outbound bool
|
||||
// transport data
|
||||
data *transport.Message
|
||||
}
|
||||
@@ -59,8 +64,26 @@ func (s *socket) Send(m *transport.Message) error {
|
||||
default:
|
||||
// no op
|
||||
}
|
||||
|
||||
// make copy
|
||||
data := &transport.Message{
|
||||
Header: make(map[string]string),
|
||||
Body: m.Body,
|
||||
}
|
||||
|
||||
for k, v := range m.Header {
|
||||
data.Header[k] = v
|
||||
}
|
||||
|
||||
// append to backlog
|
||||
s.send <- &message{id: s.id, session: s.session, data: m}
|
||||
msg := &message{
|
||||
id: s.id,
|
||||
session: s.session,
|
||||
outbound: s.outbound,
|
||||
data: data,
|
||||
}
|
||||
log.Debugf("Appending %+v to send backlog", msg)
|
||||
s.send <- msg
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -73,12 +96,14 @@ func (s *socket) Recv(m *transport.Message) error {
|
||||
}
|
||||
// recv from backlog
|
||||
msg := <-s.recv
|
||||
log.Debugf("Received %+v from recv backlog", msg)
|
||||
// set message
|
||||
*m = *msg.data
|
||||
// return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the socket
|
||||
func (s *socket) Close() error {
|
||||
select {
|
||||
case <-s.closed:
|
30
tunnel/transport/listener.go
Normal file
30
tunnel/transport/listener.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package transport
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/transport"
|
||||
"github.com/micro/go-micro/tunnel"
|
||||
)
|
||||
|
||||
type tunListener struct {
|
||||
l tunnel.Listener
|
||||
}
|
||||
|
||||
func (t *tunListener) Addr() string {
|
||||
return t.l.Addr()
|
||||
}
|
||||
|
||||
func (t *tunListener) Close() error {
|
||||
return t.l.Close()
|
||||
}
|
||||
|
||||
func (t *tunListener) Accept(fn func(socket transport.Socket)) error {
|
||||
for {
|
||||
// accept connection
|
||||
c, err := t.l.Accept()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// execute the function
|
||||
go fn(c)
|
||||
}
|
||||
}
|
113
tunnel/transport/transport.go
Normal file
113
tunnel/transport/transport.go
Normal file
@@ -0,0 +1,113 @@
|
||||
// Package transport provides a tunnel transport
|
||||
package transport
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/transport"
|
||||
"github.com/micro/go-micro/tunnel"
|
||||
)
|
||||
|
||||
type tunTransport struct {
|
||||
options transport.Options
|
||||
|
||||
tunnel tunnel.Tunnel
|
||||
}
|
||||
|
||||
type tunnelKey struct{}
|
||||
|
||||
type transportKey struct{}
|
||||
|
||||
func (t *tunTransport) Init(opts ...transport.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&t.options)
|
||||
}
|
||||
|
||||
// close the existing tunnel
|
||||
if t.tunnel != nil {
|
||||
t.tunnel.Close()
|
||||
}
|
||||
|
||||
// get the tunnel
|
||||
tun, ok := t.options.Context.Value(tunnelKey{}).(tunnel.Tunnel)
|
||||
if !ok {
|
||||
tun = tunnel.NewTunnel()
|
||||
}
|
||||
|
||||
// get the transport
|
||||
tr, ok := t.options.Context.Value(transportKey{}).(transport.Transport)
|
||||
if ok {
|
||||
tun.Init(tunnel.Transport(tr))
|
||||
}
|
||||
|
||||
// set the tunnel
|
||||
t.tunnel = tun
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *tunTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) {
|
||||
if err := t.tunnel.Connect(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c, err := t.tunnel.Dial(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (t *tunTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) {
|
||||
if err := t.tunnel.Connect(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l, err := t.tunnel.Listen(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &tunListener{l}, nil
|
||||
}
|
||||
|
||||
func (t *tunTransport) Options() transport.Options {
|
||||
return t.options
|
||||
}
|
||||
|
||||
func (t *tunTransport) String() string {
|
||||
return "tunnel"
|
||||
}
|
||||
|
||||
// NewTransport honours the initialiser used in
|
||||
func NewTransport(opts ...transport.Option) transport.Transport {
|
||||
t := &tunTransport{
|
||||
options: transport.Options{},
|
||||
}
|
||||
|
||||
// initialise
|
||||
t.Init(opts...)
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// WithTransport sets the internal tunnel
|
||||
func WithTunnel(t tunnel.Tunnel) transport.Option {
|
||||
return func(o *transport.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, tunnelKey{}, t)
|
||||
}
|
||||
}
|
||||
|
||||
// WithTransport sets the internal transport
|
||||
func WithTransport(t transport.Transport) transport.Option {
|
||||
return func(o *transport.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, transportKey{}, t)
|
||||
}
|
||||
}
|
@@ -2,7 +2,6 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/network/link"
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
@@ -11,6 +10,7 @@ import (
|
||||
// and Micro-Tunnel-Session header. The tunnel id is a hash of
|
||||
// the address being requested.
|
||||
type Tunnel interface {
|
||||
Init(opts ...Option) error
|
||||
// Connect connects the tunnel
|
||||
Connect() error
|
||||
// Close closes the tunnel
|
||||
@@ -38,7 +38,7 @@ type Conn interface {
|
||||
transport.Socket
|
||||
}
|
||||
|
||||
// NewTunnel creates a new tunnel on top of a link
|
||||
func NewTunnel(l link.Link) Tunnel {
|
||||
return newTunnel(l)
|
||||
// NewTunnel creates a new tunnel
|
||||
func NewTunnel(opts ...Option) Tunnel {
|
||||
return newTunnel(opts...)
|
||||
}
|
300
tunnel/tunnel_test.go
Normal file
300
tunnel/tunnel_test.go
Normal file
@@ -0,0 +1,300 @@
|
||||
package tunnel
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
// testAccept will accept connections on the transport, create a new link and tunnel on top
|
||||
func testAccept(t *testing.T, tun Tunnel, wait chan bool, wg *sync.WaitGroup) {
|
||||
// listen on some virtual address
|
||||
tl, err := tun.Listen("test-tunnel")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// receiver ready; notify sender
|
||||
wait <- true
|
||||
|
||||
// accept a connection
|
||||
c, err := tl.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// get a message
|
||||
for {
|
||||
// accept the message
|
||||
m := new(transport.Message)
|
||||
if err := c.Recv(m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if v := m.Header["test"]; v != "send" {
|
||||
t.Fatalf("Accept side expected test:send header. Received: %s", v)
|
||||
}
|
||||
|
||||
// now respond
|
||||
m.Header["test"] = "accept"
|
||||
if err := c.Send(m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// testSend will create a new link to an address and then a tunnel on top
|
||||
func testSend(t *testing.T, tun Tunnel, wait chan bool, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
// wait for the listener to get ready
|
||||
<-wait
|
||||
|
||||
// dial a new session
|
||||
c, err := tun.Dial("test-tunnel")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
m := transport.Message{
|
||||
Header: map[string]string{
|
||||
"test": "send",
|
||||
},
|
||||
}
|
||||
|
||||
// send the message
|
||||
if err := c.Send(&m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// now wait for the response
|
||||
mr := new(transport.Message)
|
||||
if err := c.Recv(mr); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if v := mr.Header["test"]; v != "accept" {
|
||||
t.Fatalf("Message not received from accepted side. Received: %s", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTunnel(t *testing.T) {
|
||||
// create a new tunnel client
|
||||
tunA := NewTunnel(
|
||||
Address("127.0.0.1:9096"),
|
||||
Nodes("127.0.0.1:9097"),
|
||||
)
|
||||
|
||||
// create a new tunnel server
|
||||
tunB := NewTunnel(
|
||||
Address("127.0.0.1:9097"),
|
||||
)
|
||||
|
||||
// start tunB
|
||||
err := tunB.Connect()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer tunB.Close()
|
||||
|
||||
// start tunA
|
||||
err = tunA.Connect()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer tunA.Close()
|
||||
|
||||
wait := make(chan bool)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(1)
|
||||
// start the listener
|
||||
go testAccept(t, tunB, wait, &wg)
|
||||
|
||||
wg.Add(1)
|
||||
// start the client
|
||||
go testSend(t, tunA, wait, &wg)
|
||||
|
||||
// wait until done
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestLoopbackTunnel(t *testing.T) {
|
||||
// create a new tunnel
|
||||
tun := NewTunnel(
|
||||
Address("127.0.0.1:9096"),
|
||||
Nodes("127.0.0.1:9096"),
|
||||
)
|
||||
|
||||
// start tunnel
|
||||
err := tun.Connect()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer tun.Close()
|
||||
|
||||
wait := make(chan bool)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(1)
|
||||
// start the listener
|
||||
go testAccept(t, tun, wait, &wg)
|
||||
|
||||
wg.Add(1)
|
||||
// start the client
|
||||
go testSend(t, tun, wait, &wg)
|
||||
|
||||
// wait until done
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func testBrokenTunAccept(t *testing.T, tun Tunnel, wait chan bool, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
// listen on some virtual address
|
||||
tl, err := tun.Listen("test-tunnel")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// receiver ready; notify sender
|
||||
wait <- true
|
||||
|
||||
// accept a connection
|
||||
c, err := tl.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// accept the message and close the tunnel
|
||||
// we do this to simulate loss of network connection
|
||||
m := new(transport.Message)
|
||||
if err := c.Recv(m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tun.Close()
|
||||
|
||||
// re-start tunnel
|
||||
err = tun.Connect()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer tun.Close()
|
||||
|
||||
// listen on some virtual address
|
||||
tl, err = tun.Listen("test-tunnel")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// receiver ready; notify sender
|
||||
wait <- true
|
||||
|
||||
// accept a connection
|
||||
c, err = tl.Accept()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// accept the message
|
||||
m = new(transport.Message)
|
||||
if err := c.Recv(m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// notify sender we have received the message
|
||||
<-wait
|
||||
}
|
||||
|
||||
func testBrokenTunSend(t *testing.T, tun Tunnel, wait chan bool, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
|
||||
// wait for the listener to get ready
|
||||
<-wait
|
||||
|
||||
// dial a new session
|
||||
c, err := tun.Dial("test-tunnel")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Close()
|
||||
|
||||
m := transport.Message{
|
||||
Header: map[string]string{
|
||||
"test": "send",
|
||||
},
|
||||
}
|
||||
|
||||
// send the message
|
||||
if err := c.Send(&m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// wait for the listener to get ready
|
||||
<-wait
|
||||
|
||||
// give it time to reconnect
|
||||
time.Sleep(2 * ReconnectTime)
|
||||
|
||||
// send the message
|
||||
if err := c.Send(&m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// wait for the listener to receive the message
|
||||
// c.Send merely enqueues the message to the link send queue and returns
|
||||
// in order to verify it was received we wait for the listener to tell us
|
||||
wait <- true
|
||||
}
|
||||
|
||||
func TestReconnectTunnel(t *testing.T) {
|
||||
// create a new tunnel client
|
||||
tunA := NewTunnel(
|
||||
Address("127.0.0.1:9096"),
|
||||
Nodes("127.0.0.1:9097"),
|
||||
)
|
||||
|
||||
// create a new tunnel server
|
||||
tunB := NewTunnel(
|
||||
Address("127.0.0.1:9097"),
|
||||
)
|
||||
|
||||
// start tunnel
|
||||
err := tunB.Connect()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// we manually override the tunnel.ReconnectTime value here
|
||||
// this is so that we make the reconnects faster than the default 5s
|
||||
ReconnectTime = 200 * time.Millisecond
|
||||
|
||||
// start tunnel
|
||||
err = tunA.Connect()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wait := make(chan bool)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(1)
|
||||
// start tunnel listener
|
||||
go testBrokenTunAccept(t, tunB, wait, &wg)
|
||||
|
||||
wg.Add(1)
|
||||
// start tunnel sender
|
||||
go testBrokenTunSend(t, tunA, wait, &wg)
|
||||
|
||||
// wait until done
|
||||
wg.Wait()
|
||||
}
|
40
util/io/io.go
Normal file
40
util/io/io.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// Package io is for io management
|
||||
package io
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
type rwc struct {
|
||||
socket transport.Socket
|
||||
}
|
||||
|
||||
func (r *rwc) Read(p []byte) (n int, err error) {
|
||||
m := new(transport.Message)
|
||||
if err := r.socket.Recv(m); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
copy(p, m.Body)
|
||||
return len(m.Body), nil
|
||||
}
|
||||
|
||||
func (r *rwc) Write(p []byte) (n int, err error) {
|
||||
err = r.socket.Send(&transport.Message{
|
||||
Body: p,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (r *rwc) Close() error {
|
||||
return r.socket.Close()
|
||||
}
|
||||
|
||||
// NewRWC returns a new ReadWriteCloser
|
||||
func NewRWC(sock transport.Socket) io.ReadWriteCloser {
|
||||
return &rwc{sock}
|
||||
}
|
@@ -12,20 +12,36 @@ import (
|
||||
type Level int
|
||||
|
||||
const (
|
||||
trace Level = iota
|
||||
debug
|
||||
info
|
||||
fatal
|
||||
LevelFatal Level = iota
|
||||
LevelInfo
|
||||
LevelWarn
|
||||
LevelDebug
|
||||
LevelTrace
|
||||
)
|
||||
|
||||
var (
|
||||
// the local logger
|
||||
logger log.Logger = golog.New()
|
||||
|
||||
// default log level is debug
|
||||
level = info
|
||||
// default log level is info
|
||||
level = LevelInfo
|
||||
)
|
||||
|
||||
func init() {
|
||||
switch os.Getenv("MICRO_LOG_LEVEL") {
|
||||
case "debug":
|
||||
level = LevelDebug
|
||||
case "info":
|
||||
level = LevelInfo
|
||||
case "trace":
|
||||
level = LevelTrace
|
||||
case "fatal":
|
||||
level = LevelFatal
|
||||
case "warn":
|
||||
level = LevelWarn
|
||||
}
|
||||
}
|
||||
|
||||
// Log makes use of github.com/go-log/log.Log
|
||||
func Log(v ...interface{}) {
|
||||
logger.Log(v...)
|
||||
@@ -38,7 +54,7 @@ func Logf(format string, v ...interface{}) {
|
||||
|
||||
// WithLevel logs with the level specified
|
||||
func WithLevel(l Level, v ...interface{}) {
|
||||
if l < level {
|
||||
if l > level {
|
||||
return
|
||||
}
|
||||
Log(v...)
|
||||
@@ -46,7 +62,7 @@ func WithLevel(l Level, v ...interface{}) {
|
||||
|
||||
// WithLevel logs with the level specified
|
||||
func WithLevelf(l Level, format string, v ...interface{}) {
|
||||
if l < level {
|
||||
if l > level {
|
||||
return
|
||||
}
|
||||
Logf(format, v...)
|
||||
@@ -54,43 +70,53 @@ func WithLevelf(l Level, format string, v ...interface{}) {
|
||||
|
||||
// Trace provides trace level logging
|
||||
func Trace(v ...interface{}) {
|
||||
WithLevel(trace, v...)
|
||||
WithLevel(LevelTrace, v...)
|
||||
}
|
||||
|
||||
// Tracef provides trace level logging
|
||||
func Tracef(format string, v ...interface{}) {
|
||||
WithLevelf(trace, format, v...)
|
||||
WithLevelf(LevelTrace, format, v...)
|
||||
}
|
||||
|
||||
// Debug provides debug level logging
|
||||
func Debug(v ...interface{}) {
|
||||
WithLevel(debug, v...)
|
||||
WithLevel(LevelDebug, v...)
|
||||
}
|
||||
|
||||
// Debugf provides debug level logging
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
WithLevelf(debug, format, v...)
|
||||
WithLevelf(LevelDebug, format, v...)
|
||||
}
|
||||
|
||||
// Info provides info level logging
|
||||
func Info(v ...interface{}) {
|
||||
WithLevel(info, v...)
|
||||
WithLevel(LevelInfo, v...)
|
||||
}
|
||||
|
||||
// Infof provides info level logging
|
||||
func Infof(format string, v ...interface{}) {
|
||||
WithLevelf(info, format, v...)
|
||||
WithLevelf(LevelInfo, format, v...)
|
||||
}
|
||||
|
||||
// Warn provides warn level logging
|
||||
func Warn(v ...interface{}) {
|
||||
WithLevel(LevelWarn, v...)
|
||||
}
|
||||
|
||||
// Warnf provides warn level logging
|
||||
func Warnf(format string, v ...interface{}) {
|
||||
WithLevelf(LevelWarn, format, v...)
|
||||
}
|
||||
|
||||
// Fatal logs with Log and then exits with os.Exit(1)
|
||||
func Fatal(v ...interface{}) {
|
||||
WithLevel(fatal, v...)
|
||||
WithLevel(LevelFatal, v...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalf logs with Logf and then exits with os.Exit(1)
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
WithLevelf(fatal, format, v...)
|
||||
WithLevelf(LevelFatal, format, v...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
47
util/mux/mux.go
Normal file
47
util/mux/mux.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// Package mux provides proxy muxing
|
||||
package mux
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/micro/go-micro/debug/handler"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
|
||||
// Server is a proxy muxer that incudes the use of the DefaultHandler
|
||||
type Server struct {
|
||||
// name of service
|
||||
Name string
|
||||
// Proxy handler
|
||||
Proxy proxy.Proxy
|
||||
}
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
func (s *Server) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error {
|
||||
if req.Service() == s.Name {
|
||||
return server.DefaultRouter.ServeRequest(ctx, req, rsp)
|
||||
}
|
||||
return s.Proxy.ServeRequest(ctx, req, rsp)
|
||||
}
|
||||
|
||||
func New(name string, p proxy.Proxy) *Server {
|
||||
// only register this once
|
||||
once.Do(func() {
|
||||
server.DefaultRouter.Handle(
|
||||
server.DefaultRouter.NewHandler(
|
||||
handler.DefaultHandler,
|
||||
server.InternalHandler(true),
|
||||
),
|
||||
)
|
||||
})
|
||||
|
||||
return &Server{
|
||||
Name: name,
|
||||
Proxy: p,
|
||||
}
|
||||
}
|
@@ -14,6 +14,13 @@ func HostPort(addr string, port interface{}) string {
|
||||
if strings.Count(addr, ":") > 0 {
|
||||
host = fmt.Sprintf("[%s]", addr)
|
||||
}
|
||||
// when port is blank or 0, host is a queue name
|
||||
if v, ok := port.(string); ok && v == "" {
|
||||
return host
|
||||
} else if v, ok := port.(int); ok && v == 0 && net.ParseIP(host) == nil {
|
||||
return host
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s:%v", host, port)
|
||||
}
|
||||
|
||||
|
@@ -18,4 +18,9 @@ func TestListen(t *testing.T) {
|
||||
}
|
||||
defer l.Close()
|
||||
}
|
||||
|
||||
// TODO nats case test
|
||||
// natsAddr := "_INBOX.bID2CMRvlNp0vt4tgNBHWf"
|
||||
// Expect addr DO NOT has extra ":" at the end!
|
||||
|
||||
}
|
||||
|
137
util/socket/socket.go
Normal file
137
util/socket/socket.go
Normal file
@@ -0,0 +1,137 @@
|
||||
// Package socket provides a pseudo socket
|
||||
package socket
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
// Socket is our pseudo socket for transport.Socket
|
||||
type Socket struct {
|
||||
// closed
|
||||
closed chan bool
|
||||
// remote addr
|
||||
remote string
|
||||
// local addr
|
||||
local string
|
||||
// send chan
|
||||
send chan *transport.Message
|
||||
// recv chan
|
||||
recv chan *transport.Message
|
||||
}
|
||||
|
||||
func (s *Socket) SetLocal(l string) {
|
||||
s.local = l
|
||||
}
|
||||
|
||||
func (s *Socket) SetRemote(r string) {
|
||||
s.remote = r
|
||||
}
|
||||
|
||||
// Accept passes a message to the socket which will be processed by the call to Recv
|
||||
func (s *Socket) Accept(m *transport.Message) error {
|
||||
select {
|
||||
case <-s.closed:
|
||||
return io.EOF
|
||||
case s.recv <- m:
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Process takes the next message off the send queue created by a call to Send
|
||||
func (s *Socket) Process(m *transport.Message) error {
|
||||
select {
|
||||
case <-s.closed:
|
||||
return io.EOF
|
||||
case msg := <-s.send:
|
||||
*m = *msg
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Socket) Remote() string {
|
||||
return s.remote
|
||||
}
|
||||
|
||||
func (s *Socket) Local() string {
|
||||
return s.local
|
||||
}
|
||||
|
||||
func (s *Socket) Send(m *transport.Message) error {
|
||||
select {
|
||||
case <-s.closed:
|
||||
return io.EOF
|
||||
default:
|
||||
// no op
|
||||
}
|
||||
|
||||
// make copy
|
||||
msg := &transport.Message{
|
||||
Header: make(map[string]string),
|
||||
Body: make([]byte, len(m.Body)),
|
||||
}
|
||||
|
||||
// copy headers
|
||||
for k, v := range m.Header {
|
||||
msg.Header[k] = v
|
||||
}
|
||||
|
||||
// copy body
|
||||
copy(msg.Body, m.Body)
|
||||
|
||||
// send a message
|
||||
select {
|
||||
case s.send <- msg:
|
||||
case <-s.closed:
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Socket) Recv(m *transport.Message) error {
|
||||
select {
|
||||
case <-s.closed:
|
||||
return io.EOF
|
||||
default:
|
||||
// no op
|
||||
}
|
||||
|
||||
// receive a message
|
||||
select {
|
||||
case msg := <-s.recv:
|
||||
// set message
|
||||
*m = *msg
|
||||
case <-s.closed:
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
// return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes the socket
|
||||
func (s *Socket) Close() error {
|
||||
select {
|
||||
case <-s.closed:
|
||||
// no op
|
||||
default:
|
||||
close(s.closed)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// New returns a new pseudo socket which can be used in the place of a transport socket.
|
||||
// Messages are sent to the socket via Accept and receives from the socket via Process.
|
||||
// SetLocal/SetRemote should be called before using the socket.
|
||||
func New() *Socket {
|
||||
return &Socket{
|
||||
closed: make(chan bool),
|
||||
local: "local",
|
||||
remote: "remote",
|
||||
send: make(chan *transport.Message, 128),
|
||||
recv: make(chan *transport.Message, 128),
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user