commit
f933457cc1
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,7 @@
|
||||
# Develop tools
|
||||
/.vscode/
|
||||
/.idea/
|
||||
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
|
@ -32,5 +32,5 @@ Go Micro把分布式系统的各种细节抽象出来。下面是它的主要特
|
||||
|
||||
## 快速上手
|
||||
|
||||
更多关于架构、安装的资料可以查看[文档](https://micro.mu/docs/go-micro_cn.html)。
|
||||
更多关于架构、安装的资料可以查看[文档](https://micro.mu/docs/cn/)。
|
||||
|
||||
|
@ -30,6 +30,7 @@ var (
|
||||
"application/proto": protoCodec{},
|
||||
"application/protobuf": protoCodec{},
|
||||
"application/octet-stream": protoCodec{},
|
||||
"application/grpc": protoCodec{},
|
||||
"application/grpc+json": jsonCodec{},
|
||||
"application/grpc+proto": protoCodec{},
|
||||
"application/grpc+bytes": bytesCodec{},
|
||||
|
@ -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", "service %s not found: %v", service, 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", "service %s not found: %v", req.Service(), 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", "service %s not found: %v", req.Service(), 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,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -31,37 +31,37 @@ var _ context.Context
|
||||
var _ client.Option
|
||||
var _ server.Option
|
||||
|
||||
// Client API for Micro service
|
||||
// Client API for Client service
|
||||
|
||||
type MicroService interface {
|
||||
type ClientService interface {
|
||||
// Call allows a single request to be made
|
||||
Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
|
||||
// Stream is a bidirectional stream
|
||||
Stream(ctx context.Context, opts ...client.CallOption) (Micro_StreamService, error)
|
||||
Stream(ctx context.Context, opts ...client.CallOption) (Client_StreamService, error)
|
||||
// Publish publishes a message and returns an empty Message
|
||||
Publish(ctx context.Context, in *Message, opts ...client.CallOption) (*Message, error)
|
||||
}
|
||||
|
||||
type microService struct {
|
||||
type clientService struct {
|
||||
c client.Client
|
||||
name string
|
||||
}
|
||||
|
||||
func NewMicroService(name string, c client.Client) MicroService {
|
||||
func NewClientService(name string, c client.Client) ClientService {
|
||||
if c == nil {
|
||||
c = client.NewClient()
|
||||
}
|
||||
if len(name) == 0 {
|
||||
name = "go.micro.client"
|
||||
}
|
||||
return µService{
|
||||
return &clientService{
|
||||
c: c,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *microService) Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
|
||||
req := c.c.NewRequest(c.name, "Micro.Call", in)
|
||||
func (c *clientService) Call(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
|
||||
req := c.c.NewRequest(c.name, "Client.Call", in)
|
||||
out := new(Response)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
@ -70,16 +70,16 @@ func (c *microService) Call(ctx context.Context, in *Request, opts ...client.Cal
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *microService) Stream(ctx context.Context, opts ...client.CallOption) (Micro_StreamService, error) {
|
||||
req := c.c.NewRequest(c.name, "Micro.Stream", &Request{})
|
||||
func (c *clientService) Stream(ctx context.Context, opts ...client.CallOption) (Client_StreamService, error) {
|
||||
req := c.c.NewRequest(c.name, "Client.Stream", &Request{})
|
||||
stream, err := c.c.Stream(ctx, req, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return µServiceStream{stream}, nil
|
||||
return &clientServiceStream{stream}, nil
|
||||
}
|
||||
|
||||
type Micro_StreamService interface {
|
||||
type Client_StreamService interface {
|
||||
SendMsg(interface{}) error
|
||||
RecvMsg(interface{}) error
|
||||
Close() error
|
||||
@ -87,27 +87,27 @@ type Micro_StreamService interface {
|
||||
Recv() (*Response, error)
|
||||
}
|
||||
|
||||
type microServiceStream struct {
|
||||
type clientServiceStream struct {
|
||||
stream client.Stream
|
||||
}
|
||||
|
||||
func (x *microServiceStream) Close() error {
|
||||
func (x *clientServiceStream) Close() error {
|
||||
return x.stream.Close()
|
||||
}
|
||||
|
||||
func (x *microServiceStream) SendMsg(m interface{}) error {
|
||||
func (x *clientServiceStream) SendMsg(m interface{}) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (x *microServiceStream) RecvMsg(m interface{}) error {
|
||||
func (x *clientServiceStream) RecvMsg(m interface{}) error {
|
||||
return x.stream.Recv(m)
|
||||
}
|
||||
|
||||
func (x *microServiceStream) Send(m *Request) error {
|
||||
func (x *clientServiceStream) Send(m *Request) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (x *microServiceStream) Recv() (*Response, error) {
|
||||
func (x *clientServiceStream) Recv() (*Response, error) {
|
||||
m := new(Response)
|
||||
err := x.stream.Recv(m)
|
||||
if err != nil {
|
||||
@ -116,8 +116,8 @@ func (x *microServiceStream) Recv() (*Response, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *microService) Publish(ctx context.Context, in *Message, opts ...client.CallOption) (*Message, error) {
|
||||
req := c.c.NewRequest(c.name, "Micro.Publish", in)
|
||||
func (c *clientService) Publish(ctx context.Context, in *Message, opts ...client.CallOption) (*Message, error) {
|
||||
req := c.c.NewRequest(c.name, "Client.Publish", in)
|
||||
out := new(Message)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
@ -126,43 +126,43 @@ func (c *microService) Publish(ctx context.Context, in *Message, opts ...client.
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for Micro service
|
||||
// Server API for Client service
|
||||
|
||||
type MicroHandler interface {
|
||||
type ClientHandler interface {
|
||||
// Call allows a single request to be made
|
||||
Call(context.Context, *Request, *Response) error
|
||||
// Stream is a bidirectional stream
|
||||
Stream(context.Context, Micro_StreamStream) error
|
||||
Stream(context.Context, Client_StreamStream) error
|
||||
// Publish publishes a message and returns an empty Message
|
||||
Publish(context.Context, *Message, *Message) error
|
||||
}
|
||||
|
||||
func RegisterMicroHandler(s server.Server, hdlr MicroHandler, opts ...server.HandlerOption) error {
|
||||
type micro interface {
|
||||
func RegisterClientHandler(s server.Server, hdlr ClientHandler, opts ...server.HandlerOption) error {
|
||||
type client interface {
|
||||
Call(ctx context.Context, in *Request, out *Response) error
|
||||
Stream(ctx context.Context, stream server.Stream) error
|
||||
Publish(ctx context.Context, in *Message, out *Message) error
|
||||
}
|
||||
type Micro struct {
|
||||
micro
|
||||
type Client struct {
|
||||
client
|
||||
}
|
||||
h := µHandler{hdlr}
|
||||
return s.Handle(s.NewHandler(&Micro{h}, opts...))
|
||||
h := &clientHandler{hdlr}
|
||||
return s.Handle(s.NewHandler(&Client{h}, opts...))
|
||||
}
|
||||
|
||||
type microHandler struct {
|
||||
MicroHandler
|
||||
type clientHandler struct {
|
||||
ClientHandler
|
||||
}
|
||||
|
||||
func (h *microHandler) Call(ctx context.Context, in *Request, out *Response) error {
|
||||
return h.MicroHandler.Call(ctx, in, out)
|
||||
func (h *clientHandler) Call(ctx context.Context, in *Request, out *Response) error {
|
||||
return h.ClientHandler.Call(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *microHandler) Stream(ctx context.Context, stream server.Stream) error {
|
||||
return h.MicroHandler.Stream(ctx, µStreamStream{stream})
|
||||
func (h *clientHandler) Stream(ctx context.Context, stream server.Stream) error {
|
||||
return h.ClientHandler.Stream(ctx, &clientStreamStream{stream})
|
||||
}
|
||||
|
||||
type Micro_StreamStream interface {
|
||||
type Client_StreamStream interface {
|
||||
SendMsg(interface{}) error
|
||||
RecvMsg(interface{}) error
|
||||
Close() error
|
||||
@ -170,27 +170,27 @@ type Micro_StreamStream interface {
|
||||
Recv() (*Request, error)
|
||||
}
|
||||
|
||||
type microStreamStream struct {
|
||||
type clientStreamStream struct {
|
||||
stream server.Stream
|
||||
}
|
||||
|
||||
func (x *microStreamStream) Close() error {
|
||||
func (x *clientStreamStream) Close() error {
|
||||
return x.stream.Close()
|
||||
}
|
||||
|
||||
func (x *microStreamStream) SendMsg(m interface{}) error {
|
||||
func (x *clientStreamStream) SendMsg(m interface{}) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (x *microStreamStream) RecvMsg(m interface{}) error {
|
||||
func (x *clientStreamStream) RecvMsg(m interface{}) error {
|
||||
return x.stream.Recv(m)
|
||||
}
|
||||
|
||||
func (x *microStreamStream) Send(m *Response) error {
|
||||
func (x *clientStreamStream) Send(m *Response) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (x *microStreamStream) Recv() (*Request, error) {
|
||||
func (x *clientStreamStream) Recv() (*Request, error) {
|
||||
m := new(Request)
|
||||
if err := x.stream.Recv(m); err != nil {
|
||||
return nil, err
|
||||
@ -198,6 +198,6 @@ func (x *microStreamStream) Recv() (*Request, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (h *microHandler) Publish(ctx context.Context, in *Message, out *Message) error {
|
||||
return h.MicroHandler.Publish(ctx, in, out)
|
||||
func (h *clientHandler) Publish(ctx context.Context, in *Message, out *Message) error {
|
||||
return h.ClientHandler.Publish(ctx, in, out)
|
||||
}
|
||||
|
@ -191,23 +191,23 @@ func init() {
|
||||
|
||||
var fileDescriptor_7d733ae29171347b = []byte{
|
||||
// 270 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x91, 0x3f, 0x4f, 0xc3, 0x30,
|
||||
0x10, 0xc5, 0xeb, 0xfe, 0x4b, 0x39, 0x2a, 0x21, 0x9d, 0x18, 0x4c, 0x06, 0x54, 0x32, 0x65, 0xc1,
|
||||
0x45, 0x30, 0x23, 0x86, 0xce, 0x95, 0x50, 0x40, 0xac, 0x28, 0x71, 0x4f, 0xc1, 0x52, 0x6a, 0x9b,
|
||||
0xd8, 0xad, 0x94, 0xef, 0xc8, 0x87, 0x42, 0x38, 0x29, 0x45, 0xd0, 0x2e, 0x6c, 0xf7, 0xee, 0x67,
|
||||
0xbd, 0x3b, 0xbf, 0x83, 0x74, 0xad, 0x64, 0x6d, 0xe6, 0xa5, 0xb9, 0x6e, 0x0b, 0x59, 0x29, 0xd2,
|
||||
0x7e, 0x6e, 0x6b, 0xe3, 0x77, 0x42, 0x04, 0x81, 0x67, 0xa5, 0x11, 0xe1, 0x8d, 0x68, 0xdb, 0xc9,
|
||||
0x16, 0xa2, 0x8c, 0xde, 0x37, 0xe4, 0x3c, 0x72, 0x88, 0x1c, 0xd5, 0x5b, 0x25, 0x89, 0xb3, 0x19,
|
||||
0x4b, 0x4f, 0xb2, 0x9d, 0xc4, 0x18, 0x26, 0xa4, 0x57, 0xd6, 0x28, 0xed, 0x79, 0x3f, 0xa0, 0x6f,
|
||||
0x8d, 0x57, 0x30, 0x95, 0x46, 0x7b, 0xd2, 0xfe, 0xd5, 0x37, 0x96, 0xf8, 0x20, 0xf0, 0xd3, 0xae,
|
||||
0xf7, 0xdc, 0x58, 0x42, 0x84, 0x61, 0x61, 0x56, 0x0d, 0x1f, 0xce, 0x58, 0x3a, 0xcd, 0x42, 0x9d,
|
||||
0x5c, 0xc2, 0x24, 0x23, 0x67, 0x8d, 0x76, 0x7b, 0xce, 0x7e, 0xf0, 0x17, 0x88, 0x96, 0xe4, 0x5c,
|
||||
0x5e, 0x12, 0x9e, 0xc3, 0xc8, 0x1b, 0xab, 0x64, 0xb7, 0x55, 0x2b, 0xfe, 0xcc, 0xed, 0x1f, 0x9f,
|
||||
0x3b, 0xd8, 0xfb, 0xde, 0x7e, 0x30, 0x18, 0x2d, 0xbf, 0x02, 0xc0, 0x7b, 0x18, 0x2e, 0xf2, 0xaa,
|
||||
0x42, 0x2e, 0x7e, 0x65, 0x22, 0xba, 0x40, 0xe2, 0x8b, 0x03, 0xa4, 0x5d, 0x39, 0xe9, 0xe1, 0x02,
|
||||
0xc6, 0x4f, 0xbe, 0xa6, 0x7c, 0xfd, 0x4f, 0x83, 0x94, 0xdd, 0x30, 0x7c, 0x80, 0xe8, 0x71, 0x53,
|
||||
0x54, 0xca, 0xbd, 0x1d, 0x70, 0xe9, 0xfe, 0x1f, 0x1f, 0x25, 0x49, 0xaf, 0x18, 0x87, 0xb3, 0xde,
|
||||
0x7d, 0x06, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x63, 0x94, 0x1a, 0x02, 0x02, 0x00, 0x00,
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x91, 0x41, 0x4b, 0xc3, 0x40,
|
||||
0x10, 0x85, 0xbb, 0x6d, 0x4c, 0xea, 0x58, 0x10, 0x06, 0x0f, 0x6b, 0x0e, 0x52, 0x73, 0xca, 0xc5,
|
||||
0x54, 0xf4, 0x2c, 0x1e, 0x72, 0x16, 0x24, 0x8a, 0x57, 0x49, 0xb6, 0x43, 0x5c, 0x48, 0x77, 0xd7,
|
||||
0xec, 0xb6, 0x90, 0x1f, 0xe9, 0x7f, 0x12, 0x36, 0xa9, 0x15, 0x6d, 0x2f, 0xbd, 0xcd, 0x9b, 0x6f,
|
||||
0x79, 0x33, 0xfb, 0x06, 0xd2, 0x95, 0x14, 0xad, 0x5e, 0xd4, 0xfa, 0xa6, 0x2f, 0x44, 0x23, 0x49,
|
||||
0xb9, 0x85, 0x69, 0xb5, 0xdb, 0x8a, 0xcc, 0x0b, 0x3c, 0xaf, 0x75, 0xe6, 0xdf, 0x64, 0x7d, 0x3b,
|
||||
0xd9, 0x40, 0x54, 0xd0, 0xe7, 0x9a, 0xac, 0x43, 0x0e, 0x91, 0xa5, 0x76, 0x23, 0x05, 0x71, 0x36,
|
||||
0x67, 0xe9, 0x69, 0xb1, 0x95, 0x18, 0xc3, 0x94, 0xd4, 0xd2, 0x68, 0xa9, 0x1c, 0x1f, 0x7b, 0xf4,
|
||||
0xa3, 0xf1, 0x1a, 0x66, 0x42, 0x2b, 0x47, 0xca, 0xbd, 0xbb, 0xce, 0x10, 0x9f, 0x78, 0x7e, 0x36,
|
||||
0xf4, 0x5e, 0x3b, 0x43, 0x88, 0x10, 0x54, 0x7a, 0xd9, 0xf1, 0x60, 0xce, 0xd2, 0x59, 0xe1, 0xeb,
|
||||
0xe4, 0x0a, 0xa6, 0x05, 0x59, 0xa3, 0x95, 0xdd, 0x71, 0xf6, 0x8b, 0xbf, 0x41, 0xf4, 0x44, 0xd6,
|
||||
0x96, 0x35, 0xe1, 0x05, 0x9c, 0x38, 0x6d, 0xa4, 0x18, 0xb6, 0xea, 0xc5, 0xbf, 0xb9, 0xe3, 0xc3,
|
||||
0x73, 0x27, 0x3b, 0xdf, 0xbb, 0x2f, 0x06, 0x61, 0xee, 0xbf, 0x8e, 0x0f, 0x10, 0xe4, 0x65, 0xd3,
|
||||
0x20, 0xcf, 0xfe, 0x84, 0x92, 0x0d, 0x89, 0xc4, 0x97, 0x7b, 0x48, 0xbf, 0x73, 0x32, 0xc2, 0x1c,
|
||||
0xc2, 0x17, 0xd7, 0x52, 0xb9, 0x3a, 0xd2, 0x20, 0x65, 0xb7, 0x0c, 0x1f, 0x21, 0x7a, 0x5e, 0x57,
|
||||
0x8d, 0xb4, 0x1f, 0x7b, 0x5c, 0x86, 0x00, 0xe2, 0x83, 0x24, 0x19, 0x55, 0xa1, 0xbf, 0xeb, 0xfd,
|
||||
0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x76, 0x1f, 0x51, 0x03, 0x02, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@ -218,59 +218,59 @@ var _ grpc.ClientConn
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// MicroClient is the client API for Micro service.
|
||||
// ClientClient is the client API for Client service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type MicroClient interface {
|
||||
type ClientClient interface {
|
||||
// Call allows a single request to be made
|
||||
Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
|
||||
// Stream is a bidirectional stream
|
||||
Stream(ctx context.Context, opts ...grpc.CallOption) (Micro_StreamClient, error)
|
||||
Stream(ctx context.Context, opts ...grpc.CallOption) (Client_StreamClient, error)
|
||||
// Publish publishes a message and returns an empty Message
|
||||
Publish(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error)
|
||||
}
|
||||
|
||||
type microClient struct {
|
||||
type clientClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewMicroClient(cc *grpc.ClientConn) MicroClient {
|
||||
return µClient{cc}
|
||||
func NewClientClient(cc *grpc.ClientConn) ClientClient {
|
||||
return &clientClient{cc}
|
||||
}
|
||||
|
||||
func (c *microClient) Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
|
||||
func (c *clientClient) Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) {
|
||||
out := new(Response)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.client.Micro/Call", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.client.Client/Call", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *microClient) Stream(ctx context.Context, opts ...grpc.CallOption) (Micro_StreamClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_Micro_serviceDesc.Streams[0], "/go.micro.client.Micro/Stream", opts...)
|
||||
func (c *clientClient) Stream(ctx context.Context, opts ...grpc.CallOption) (Client_StreamClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_Client_serviceDesc.Streams[0], "/go.micro.client.Client/Stream", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := µStreamClient{stream}
|
||||
x := &clientStreamClient{stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type Micro_StreamClient interface {
|
||||
type Client_StreamClient interface {
|
||||
Send(*Request) error
|
||||
Recv() (*Response, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type microStreamClient struct {
|
||||
type clientStreamClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *microStreamClient) Send(m *Request) error {
|
||||
func (x *clientStreamClient) Send(m *Request) error {
|
||||
return x.ClientStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *microStreamClient) Recv() (*Response, error) {
|
||||
func (x *clientStreamClient) Recv() (*Response, error) {
|
||||
m := new(Response)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
@ -278,66 +278,66 @@ func (x *microStreamClient) Recv() (*Response, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *microClient) Publish(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error) {
|
||||
func (c *clientClient) Publish(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error) {
|
||||
out := new(Message)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.client.Micro/Publish", in, out, opts...)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.client.Client/Publish", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// MicroServer is the server API for Micro service.
|
||||
type MicroServer interface {
|
||||
// ClientServer is the server API for Client service.
|
||||
type ClientServer interface {
|
||||
// Call allows a single request to be made
|
||||
Call(context.Context, *Request) (*Response, error)
|
||||
// Stream is a bidirectional stream
|
||||
Stream(Micro_StreamServer) error
|
||||
Stream(Client_StreamServer) error
|
||||
// Publish publishes a message and returns an empty Message
|
||||
Publish(context.Context, *Message) (*Message, error)
|
||||
}
|
||||
|
||||
func RegisterMicroServer(s *grpc.Server, srv MicroServer) {
|
||||
s.RegisterService(&_Micro_serviceDesc, srv)
|
||||
func RegisterClientServer(s *grpc.Server, srv ClientServer) {
|
||||
s.RegisterService(&_Client_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Micro_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
func _Client_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Request)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(MicroServer).Call(ctx, in)
|
||||
return srv.(ClientServer).Call(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.client.Micro/Call",
|
||||
FullMethod: "/go.micro.client.Client/Call",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MicroServer).Call(ctx, req.(*Request))
|
||||
return srv.(ClientServer).Call(ctx, req.(*Request))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Micro_Stream_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(MicroServer).Stream(µStreamServer{stream})
|
||||
func _Client_Stream_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(ClientServer).Stream(&clientStreamServer{stream})
|
||||
}
|
||||
|
||||
type Micro_StreamServer interface {
|
||||
type Client_StreamServer interface {
|
||||
Send(*Response) error
|
||||
Recv() (*Request, error)
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type microStreamServer struct {
|
||||
type clientStreamServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *microStreamServer) Send(m *Response) error {
|
||||
func (x *clientStreamServer) Send(m *Response) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *microStreamServer) Recv() (*Request, error) {
|
||||
func (x *clientStreamServer) Recv() (*Request, error) {
|
||||
m := new(Request)
|
||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
@ -345,41 +345,41 @@ func (x *microStreamServer) Recv() (*Request, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func _Micro_Publish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
func _Client_Publish_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Message)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(MicroServer).Publish(ctx, in)
|
||||
return srv.(ClientServer).Publish(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.client.Micro/Publish",
|
||||
FullMethod: "/go.micro.client.Client/Publish",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MicroServer).Publish(ctx, req.(*Message))
|
||||
return srv.(ClientServer).Publish(ctx, req.(*Message))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Micro_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "go.micro.client.Micro",
|
||||
HandlerType: (*MicroServer)(nil),
|
||||
var _Client_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "go.micro.client.Client",
|
||||
HandlerType: (*ClientServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Call",
|
||||
Handler: _Micro_Call_Handler,
|
||||
Handler: _Client_Call_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Publish",
|
||||
Handler: _Micro_Publish_Handler,
|
||||
Handler: _Client_Publish_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "Stream",
|
||||
Handler: _Micro_Stream_Handler,
|
||||
Handler: _Client_Stream_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
|
@ -2,8 +2,8 @@ syntax = "proto3";
|
||||
|
||||
package go.micro.client;
|
||||
|
||||
// Micro is the micro client interface
|
||||
service Micro {
|
||||
// Client is the micro client interface
|
||||
service Client {
|
||||
// Call allows a single request to be made
|
||||
rpc Call(Request) returns (Response) {};
|
||||
// Stream is a bidirectional stream
|
||||
|
@ -96,19 +96,22 @@ 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))
|
||||
dOpts := []transport.DialOption{
|
||||
transport.WithStream(),
|
||||
}
|
||||
|
||||
if opts.DialTimeout >= 0 {
|
||||
dOpts = append(dOpts, transport.WithTimeout(opts.DialTimeout))
|
||||
}
|
||||
|
||||
c, err := r.pool.Get(address, dOpts...)
|
||||
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 +119,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 +157,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) {
|
||||
@ -206,7 +225,13 @@ func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request
|
||||
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 +244,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) { c.Close() },
|
||||
}
|
||||
|
||||
// wait for error response
|
||||
ch := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
// send the first message
|
||||
ch <- stream.Send(req.Body())
|
||||
}()
|
||||
|
||||
@ -242,6 +275,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 +351,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 +415,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 +494,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
|
||||
}
|
||||
|
||||
|
@ -89,9 +89,22 @@ func (c *Codec) Write(m *codec.Message, b interface{}) error {
|
||||
m.Header[":authority"] = m.Target
|
||||
m.Header["content-type"] = c.ContentType
|
||||
case codec.Response:
|
||||
m.Header["Trailer"] = "grpc-status, grpc-message"
|
||||
m.Header["Trailer"] = "grpc-status" //, grpc-message"
|
||||
m.Header["content-type"] = c.ContentType
|
||||
m.Header[":status"] = "200"
|
||||
m.Header["grpc-status"] = "0"
|
||||
m.Header["grpc-message"] = ""
|
||||
// m.Header["grpc-message"] = ""
|
||||
case codec.Error:
|
||||
m.Header["Trailer"] = "grpc-status, grpc-message"
|
||||
// micro end of stream
|
||||
if m.Error == "EOS" {
|
||||
m.Header["grpc-status"] = "0"
|
||||
} else {
|
||||
m.Header["grpc-message"] = m.Error
|
||||
m.Header["grpc-status"] = "13"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// marshal content
|
||||
|
@ -30,6 +30,7 @@ import (
|
||||
"github.com/micro/go-micro/registry/gossip"
|
||||
"github.com/micro/go-micro/registry/mdns"
|
||||
rmem "github.com/micro/go-micro/registry/memory"
|
||||
regSrv "github.com/micro/go-micro/registry/service"
|
||||
|
||||
// selectors
|
||||
"github.com/micro/go-micro/client/selector"
|
||||
@ -95,11 +96,13 @@ var (
|
||||
cli.IntFlag{
|
||||
Name: "register_ttl",
|
||||
EnvVar: "MICRO_REGISTER_TTL",
|
||||
Value: 60,
|
||||
Usage: "Register TTL in seconds",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "register_interval",
|
||||
EnvVar: "MICRO_REGISTER_INTERVAL",
|
||||
Value: 30,
|
||||
Usage: "Register interval in seconds",
|
||||
},
|
||||
cli.StringFlag{
|
||||
@ -188,10 +191,12 @@ var (
|
||||
}
|
||||
|
||||
DefaultRegistries = map[string]func(...registry.Option) registry.Registry{
|
||||
"consul": consul.NewRegistry,
|
||||
"gossip": gossip.NewRegistry,
|
||||
"mdns": mdns.NewRegistry,
|
||||
"memory": rmem.NewRegistry,
|
||||
"go.micro.registry": regSrv.NewRegistry,
|
||||
"service": regSrv.NewRegistry,
|
||||
"consul": consul.NewRegistry,
|
||||
"gossip": gossip.NewRegistry,
|
||||
"mdns": mdns.NewRegistry,
|
||||
"memory": rmem.NewRegistry,
|
||||
}
|
||||
|
||||
DefaultSelectors = map[string]func(...selector.Option) selector.Selector{
|
||||
@ -417,11 +422,11 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
serverOpts = append(serverOpts, server.Advertise(ctx.String("server_advertise")))
|
||||
}
|
||||
|
||||
if ttl := time.Duration(ctx.GlobalInt("register_ttl")); ttl > 0 {
|
||||
if ttl := time.Duration(ctx.GlobalInt("register_ttl")); ttl >= 0 {
|
||||
serverOpts = append(serverOpts, server.RegisterTTL(ttl*time.Second))
|
||||
}
|
||||
|
||||
if val := time.Duration(ctx.GlobalInt("register_interval")); val > 0 {
|
||||
if val := time.Duration(ctx.GlobalInt("register_interval")); val >= 0 {
|
||||
serverOpts = append(serverOpts, server.RegisterInterval(val*time.Second))
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,10 @@ import (
|
||||
"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()))
|
||||
|
@ -44,6 +44,6 @@ Load the source into config
|
||||
// Create new config
|
||||
conf := config.NewConfig()
|
||||
|
||||
// Load file source
|
||||
// Load consul source
|
||||
conf.Load(consulSource)
|
||||
```
|
||||
|
@ -1,7 +1,6 @@
|
||||
package consul
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/api"
|
||||
@ -80,7 +79,7 @@ func (w *watcher) Next() (*source.ChangeSet, error) {
|
||||
case cs := <-w.ch:
|
||||
return cs, nil
|
||||
case <-w.exit:
|
||||
return nil, errors.New("watcher stopped")
|
||||
return nil, source.ErrWatcherStopped
|
||||
}
|
||||
}
|
||||
|
||||
|
2
config/source/env/README.md
vendored
2
config/source/env/README.md
vendored
@ -91,6 +91,6 @@ Load the source into config
|
||||
// Create new config
|
||||
conf := config.NewConfig()
|
||||
|
||||
// Load file source
|
||||
// Load env source
|
||||
conf.Load(src)
|
||||
```
|
||||
|
6
config/source/env/env_test.go
vendored
6
config/source/env/env_test.go
vendored
@ -86,8 +86,8 @@ func TestEnvvar_Prefixes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestEnvvar_WatchNextNoOpsUntilStop(t *testing.T) {
|
||||
source := NewSource(WithStrippedPrefix("GOMICRO_"))
|
||||
w, err := source.Watch()
|
||||
src := NewSource(WithStrippedPrefix("GOMICRO_"))
|
||||
w, err := src.Watch()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@ -97,7 +97,7 @@ func TestEnvvar_WatchNextNoOpsUntilStop(t *testing.T) {
|
||||
w.Stop()
|
||||
}()
|
||||
|
||||
if _, err := w.Next(); err.Error() != "watcher stopped" {
|
||||
if _, err := w.Next(); err != source.ErrWatcherStopped {
|
||||
t.Errorf("expected watcher stopped error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
4
config/source/env/watcher.go
vendored
4
config/source/env/watcher.go
vendored
@ -1,8 +1,6 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/micro/go-micro/config/source"
|
||||
)
|
||||
|
||||
@ -13,7 +11,7 @@ type watcher struct {
|
||||
func (w *watcher) Next() (*source.ChangeSet, error) {
|
||||
<-w.exit
|
||||
|
||||
return nil, errors.New("watcher stopped")
|
||||
return nil, source.ErrWatcherStopped
|
||||
}
|
||||
|
||||
func (w *watcher) Stop() error {
|
||||
|
@ -1,7 +1,8 @@
|
||||
//+build !linux
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
@ -34,7 +35,7 @@ func (w *watcher) Next() (*source.ChangeSet, error) {
|
||||
// is it closed?
|
||||
select {
|
||||
case <-w.exit:
|
||||
return nil, errors.New("watcher stopped")
|
||||
return nil, source.ErrWatcherStopped
|
||||
default:
|
||||
}
|
||||
|
||||
@ -57,7 +58,7 @@ func (w *watcher) Next() (*source.ChangeSet, error) {
|
||||
case err := <-w.fw.Errors:
|
||||
return nil, err
|
||||
case <-w.exit:
|
||||
return nil, errors.New("watcher stopped")
|
||||
return nil, source.ErrWatcherStopped
|
||||
}
|
||||
}
|
||||
|
||||
|
71
config/source/file/watcher_linux.go
Normal file
71
config/source/file/watcher_linux.go
Normal file
@ -0,0 +1,71 @@
|
||||
//+build linux
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"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, source.ErrWatcherStopped
|
||||
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, source.ErrWatcherStopped
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) Stop() error {
|
||||
return w.fw.Close()
|
||||
}
|
@ -42,6 +42,6 @@ Load the source into config
|
||||
// Create new config
|
||||
conf := config.NewConfig()
|
||||
|
||||
// Load file source
|
||||
// Load flag source
|
||||
conf.Load(flagSource)
|
||||
```
|
||||
|
@ -12,13 +12,14 @@ var (
|
||||
dbpw = flag.String("database-password", "", "db pw")
|
||||
)
|
||||
|
||||
func init() {
|
||||
func initTestFlags() {
|
||||
flag.Set("database-host", "localhost")
|
||||
flag.Set("database-password", "some-password")
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func TestFlagsrc_Read(t *testing.T) {
|
||||
initTestFlags()
|
||||
source := NewSource()
|
||||
c, err := source.Read()
|
||||
if err != nil {
|
||||
@ -46,6 +47,7 @@ func TestFlagsrc_Read(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFlagsrc_ReadAll(t *testing.T) {
|
||||
initTestFlags()
|
||||
source := NewSource(IncludeUnset(true))
|
||||
c, err := source.Read()
|
||||
if err != nil {
|
||||
|
@ -39,6 +39,6 @@ Load the source into config
|
||||
// Create new config
|
||||
conf := config.NewConfig()
|
||||
|
||||
// Load file source
|
||||
// Load memory source
|
||||
conf.Load(memorySource)
|
||||
```
|
||||
|
@ -2,9 +2,15 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrWatcherStopped is returned when source watcher has been stopped
|
||||
ErrWatcherStopped = errors.New("watcher stopped")
|
||||
)
|
||||
|
||||
// Source is the source from which config is loaded
|
||||
type Source interface {
|
||||
Read() (*ChangeSet, error)
|
||||
|
12
go.mod
12
go.mod
@ -3,7 +3,7 @@ module github.com/micro/go-micro
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.43.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
|
||||
@ -22,6 +22,7 @@ require (
|
||||
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.2
|
||||
@ -48,12 +49,10 @@ require (
|
||||
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
|
||||
@ -69,9 +68,8 @@ require (
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
||||
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-20190804053845-51ab0e2deafa // indirect
|
||||
golang.org/x/tools v0.0.0-20190807201305-8be58fba6352 // indirect
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64 // indirect
|
||||
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
|
||||
|
8
go.sum
8
go.sum
@ -4,6 +4,7 @@ cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSR
|
||||
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=
|
||||
@ -109,6 +110,7 @@ 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=
|
||||
@ -246,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=
|
||||
@ -449,6 +453,8 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
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=
|
||||
@ -477,10 +483,12 @@ golang.org/x/tools v0.0.0-20190710184609-286818132824/go.mod h1:jcCCGcm9btYwXyDq
|
||||
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=
|
||||
|
@ -24,6 +24,22 @@ type monitor struct {
|
||||
services map[string]*Status
|
||||
}
|
||||
|
||||
func (m *monitor) Check(service string) error {
|
||||
status, err := m.check(service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Lock()
|
||||
m.services[service] = status
|
||||
m.Unlock()
|
||||
|
||||
if status.Code != StatusRunning {
|
||||
return errors.New(status.Info)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@ -41,6 +57,17 @@ func (m *monitor) check(service string) (*Status, 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
|
||||
}
|
||||
// check the transport matches
|
||||
if node.Metadata["transport"] != m.client.Options().Transport.String() {
|
||||
continue
|
||||
}
|
||||
|
||||
rsp, err := debug.Health(
|
||||
context.Background(),
|
||||
// empty health request
|
||||
|
@ -17,6 +17,8 @@ type StatusCode int
|
||||
type Monitor interface {
|
||||
// Reap a service and stop monitoring
|
||||
Reap(service string) error
|
||||
// Check the status of the service now
|
||||
Check(service string) error
|
||||
// Status of the service
|
||||
Status(service string) (Status, error)
|
||||
// Watch starts watching the service
|
||||
|
892
network/default.go
Normal file
892
network/default.go
Normal file
@ -0,0 +1,892 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/micro/go-micro/client"
|
||||
rtr "github.com/micro/go-micro/client/selector/router"
|
||||
pbNet "github.com/micro/go-micro/network/proto"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/router"
|
||||
pbRtr "github.com/micro/go-micro/router/proto"
|
||||
"github.com/micro/go-micro/server"
|
||||
"github.com/micro/go-micro/transport"
|
||||
"github.com/micro/go-micro/tunnel"
|
||||
tun "github.com/micro/go-micro/tunnel/transport"
|
||||
"github.com/micro/go-micro/util/log"
|
||||
)
|
||||
|
||||
var (
|
||||
// NetworkChannel is the name of the tunnel channel for passing network messages
|
||||
NetworkChannel = "network"
|
||||
// ControlChannel is the name of the tunnel channel for passing control message
|
||||
ControlChannel = "control"
|
||||
// DefaultLink is default network link
|
||||
DefaultLink = "network"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrClientNotFound is returned when client for tunnel channel could not be found
|
||||
ErrClientNotFound = errors.New("client not found")
|
||||
)
|
||||
|
||||
// network implements Network interface
|
||||
type network struct {
|
||||
// node is network node
|
||||
*node
|
||||
// options configure the network
|
||||
options Options
|
||||
// rtr is network router
|
||||
router router.Router
|
||||
// prx is network proxy
|
||||
proxy proxy.Proxy
|
||||
// tun is network tunnel
|
||||
tunnel tunnel.Tunnel
|
||||
// server is network server
|
||||
server server.Server
|
||||
// client is network client
|
||||
client client.Client
|
||||
|
||||
// tunClient is a map of tunnel clients keyed over tunnel channel names
|
||||
tunClient map[string]transport.Client
|
||||
|
||||
sync.RWMutex
|
||||
// connected marks the network as connected
|
||||
connected bool
|
||||
// closed closes the network
|
||||
closed chan bool
|
||||
}
|
||||
|
||||
// newNetwork returns a new network node
|
||||
func newNetwork(opts ...Option) Network {
|
||||
options := DefaultOptions()
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// init tunnel address to the network bind address
|
||||
options.Tunnel.Init(
|
||||
tunnel.Address(options.Address),
|
||||
tunnel.Nodes(options.Peers...),
|
||||
)
|
||||
|
||||
// init router Id to the network id
|
||||
options.Router.Init(
|
||||
router.Id(options.Id),
|
||||
)
|
||||
|
||||
// create tunnel client with tunnel transport
|
||||
tunTransport := tun.NewTransport(
|
||||
tun.WithTunnel(options.Tunnel),
|
||||
)
|
||||
|
||||
// set the address to advertise
|
||||
address := options.Address
|
||||
if len(options.Advertise) > 0 {
|
||||
address = options.Advertise
|
||||
}
|
||||
|
||||
// server is network server
|
||||
server := server.NewServer(
|
||||
server.Id(options.Id),
|
||||
server.Address(options.Id),
|
||||
server.Advertise(address),
|
||||
server.Name(options.Name),
|
||||
server.Transport(tunTransport),
|
||||
)
|
||||
|
||||
// client is network client
|
||||
client := client.NewClient(
|
||||
client.Transport(tunTransport),
|
||||
client.Selector(
|
||||
rtr.NewSelector(
|
||||
rtr.WithRouter(options.Router),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
network := &network{
|
||||
node: &node{
|
||||
id: options.Id,
|
||||
address: address,
|
||||
peers: make(map[string]*node),
|
||||
},
|
||||
options: options,
|
||||
router: options.Router,
|
||||
proxy: options.Proxy,
|
||||
tunnel: options.Tunnel,
|
||||
server: server,
|
||||
client: client,
|
||||
tunClient: make(map[string]transport.Client),
|
||||
}
|
||||
|
||||
network.node.network = network
|
||||
|
||||
return network
|
||||
}
|
||||
|
||||
// Options returns network options
|
||||
func (n *network) Options() Options {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
|
||||
options := n.options
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
// Name returns network name
|
||||
func (n *network) Name() string {
|
||||
return n.options.Name
|
||||
}
|
||||
|
||||
// resolveNodes resolves network nodes to addresses
|
||||
func (n *network) resolveNodes() ([]string, error) {
|
||||
// resolve the network address to network nodes
|
||||
records, err := n.options.Resolver.Resolve(n.options.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nodeMap := make(map[string]bool)
|
||||
|
||||
// collect network node addresses
|
||||
var nodes []string
|
||||
for _, record := range records {
|
||||
nodes = append(nodes, record.Address)
|
||||
nodeMap[record.Address] = true
|
||||
}
|
||||
|
||||
// append seed nodes if we have them
|
||||
for _, node := range n.options.Peers {
|
||||
if _, ok := nodeMap[node]; !ok {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
}
|
||||
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
// resolve continuously resolves network nodes and initializes network tunnel with resolved addresses
|
||||
func (n *network) resolve() {
|
||||
resolve := time.NewTicker(ResolveTime)
|
||||
defer resolve.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-n.closed:
|
||||
return
|
||||
case <-resolve.C:
|
||||
nodes, err := n.resolveNodes()
|
||||
if err != nil {
|
||||
log.Debugf("Network failed to resolve nodes: %v", err)
|
||||
continue
|
||||
}
|
||||
// initialize the tunnel
|
||||
n.tunnel.Init(
|
||||
tunnel.Nodes(nodes...),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleNetConn handles network announcement messages
|
||||
func (n *network) handleNetConn(sess tunnel.Session, msg chan *transport.Message) {
|
||||
for {
|
||||
m := new(transport.Message)
|
||||
if err := sess.Recv(m); err != nil {
|
||||
log.Debugf("Network tunnel [%s] receive error: %v", NetworkChannel, err)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case msg <- m:
|
||||
case <-n.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// acceptNetConn accepts connections from NetworkChannel
|
||||
func (n *network) acceptNetConn(l tunnel.Listener, recv chan *transport.Message) {
|
||||
for {
|
||||
// accept a connection
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
// TODO: handle this
|
||||
log.Debugf("Network tunnel [%s] accept error: %v", NetworkChannel, err)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-n.closed:
|
||||
return
|
||||
default:
|
||||
// go handle NetworkChannel connection
|
||||
go n.handleNetConn(conn, recv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// processNetChan processes messages received on NetworkChannel
|
||||
func (n *network) processNetChan(client transport.Client, listener tunnel.Listener) {
|
||||
// receive network message queue
|
||||
recv := make(chan *transport.Message, 128)
|
||||
|
||||
// accept NetworkChannel connections
|
||||
go n.acceptNetConn(listener, recv)
|
||||
|
||||
for {
|
||||
select {
|
||||
case m := <-recv:
|
||||
// switch on type of message and take action
|
||||
switch m.Header["Micro-Method"] {
|
||||
case "connect":
|
||||
// mark the time the message has been received
|
||||
now := time.Now()
|
||||
pbNetConnect := &pbNet.Connect{}
|
||||
if err := proto.Unmarshal(m.Body, pbNetConnect); err != nil {
|
||||
log.Debugf("Network tunnel [%s] connect unmarshal error: %v", NetworkChannel, err)
|
||||
continue
|
||||
}
|
||||
// don't process your own messages
|
||||
if pbNetConnect.Node.Id == n.options.Id {
|
||||
continue
|
||||
}
|
||||
log.Debugf("Network received connect message from: %s", pbNetConnect.Node.Id)
|
||||
peer := &node{
|
||||
id: pbNetConnect.Node.Id,
|
||||
address: pbNetConnect.Node.Address,
|
||||
peers: make(map[string]*node),
|
||||
lastSeen: now,
|
||||
}
|
||||
if err := n.node.AddPeer(peer); err == ErrPeerExists {
|
||||
log.Debugf("Network peer exists, refreshing: %s", peer.id)
|
||||
// update lastSeen time for the existing node
|
||||
if err := n.RefreshPeer(peer.id, now); err != nil {
|
||||
log.Debugf("Network failed refreshing peer %s: %v", peer.id, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// get node peers down to MaxDepth encoded in protobuf
|
||||
msg := PeersToProto(n.node, MaxDepth)
|
||||
// advertise yourself to the network
|
||||
if err := n.sendMsg("peer", msg, NetworkChannel); err != nil {
|
||||
log.Debugf("Network failed to advertise peers: %v", err)
|
||||
}
|
||||
// advertise all the routes when a new node has connected
|
||||
if err := n.router.Solicit(); err != nil {
|
||||
log.Debugf("Network failed to solicit routes: %s", err)
|
||||
}
|
||||
case "peer":
|
||||
// mark the time the message has been received
|
||||
now := time.Now()
|
||||
pbNetPeer := &pbNet.Peer{}
|
||||
if err := proto.Unmarshal(m.Body, pbNetPeer); err != nil {
|
||||
log.Debugf("Network tunnel [%s] peer unmarshal error: %v", NetworkChannel, err)
|
||||
continue
|
||||
}
|
||||
// don't process your own messages
|
||||
if pbNetPeer.Node.Id == n.options.Id {
|
||||
continue
|
||||
}
|
||||
log.Debugf("Network received peer message from: %s", pbNetPeer.Node.Id)
|
||||
peer := &node{
|
||||
id: pbNetPeer.Node.Id,
|
||||
address: pbNetPeer.Node.Address,
|
||||
peers: make(map[string]*node),
|
||||
lastSeen: now,
|
||||
}
|
||||
if err := n.node.AddPeer(peer); err == nil {
|
||||
// send a solicit message when discovering new peer
|
||||
msg := &pbRtr.Solicit{
|
||||
Id: n.options.Id,
|
||||
}
|
||||
if err := n.sendMsg("solicit", msg, ControlChannel); err != nil {
|
||||
log.Debugf("Network failed to send solicit message: %s", err)
|
||||
}
|
||||
continue
|
||||
// we're expecting any error to be ErrPeerExists
|
||||
} else if err != ErrPeerExists {
|
||||
log.Debugf("Network got error adding peer %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("Network peer exists, refreshing: %s", pbNetPeer.Node.Id)
|
||||
// update lastSeen time for the peer
|
||||
if err := n.RefreshPeer(pbNetPeer.Node.Id, now); err != nil {
|
||||
log.Debugf("Network failed refreshing peer %s: %v", pbNetPeer.Node.Id, err)
|
||||
}
|
||||
|
||||
// NOTE: we don't unpack MaxDepth toplogy
|
||||
peer = UnpackPeerTopology(pbNetPeer, now, MaxDepth-1)
|
||||
log.Debugf("Network updating topology of node: %s", n.node.id)
|
||||
if err := n.node.UpdatePeer(peer); err != nil {
|
||||
log.Debugf("Network failed to update peers: %v", err)
|
||||
}
|
||||
case "close":
|
||||
pbNetClose := &pbNet.Close{}
|
||||
if err := proto.Unmarshal(m.Body, pbNetClose); err != nil {
|
||||
log.Debugf("Network tunnel [%s] close unmarshal error: %v", NetworkChannel, err)
|
||||
continue
|
||||
}
|
||||
// don't process your own messages
|
||||
if pbNetClose.Node.Id == n.options.Id {
|
||||
continue
|
||||
}
|
||||
log.Debugf("Network received close message from: %s", pbNetClose.Node.Id)
|
||||
peer := &node{
|
||||
id: pbNetClose.Node.Id,
|
||||
address: pbNetClose.Node.Address,
|
||||
}
|
||||
if err := n.DeletePeerNode(peer.id); err != nil {
|
||||
log.Debugf("Network failed to delete node %s routes: %v", peer.id, err)
|
||||
}
|
||||
if err := n.prunePeerRoutes(peer); err != nil {
|
||||
log.Debugf("Network failed pruning peer %s routes: %v", peer.id, err)
|
||||
}
|
||||
}
|
||||
case <-n.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sendMsg sends a message to the tunnel channel
|
||||
func (n *network) sendMsg(method string, msg proto.Message, channel string) error {
|
||||
body, err := proto.Marshal(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// create transport message and chuck it down the pipe
|
||||
m := transport.Message{
|
||||
Header: map[string]string{
|
||||
"Micro-Method": method,
|
||||
},
|
||||
Body: body,
|
||||
}
|
||||
|
||||
// check if the channel client is initialized
|
||||
n.RLock()
|
||||
client, ok := n.tunClient[channel]
|
||||
if !ok || client == nil {
|
||||
n.RUnlock()
|
||||
return ErrClientNotFound
|
||||
}
|
||||
n.RUnlock()
|
||||
|
||||
log.Debugf("Network sending %s message from: %s", method, n.options.Id)
|
||||
if err := client.Send(&m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// announce announces node peers to the network
|
||||
func (n *network) announce(client transport.Client) {
|
||||
announce := time.NewTicker(AnnounceTime)
|
||||
defer announce.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-n.closed:
|
||||
return
|
||||
case <-announce.C:
|
||||
msg := PeersToProto(n.node, MaxDepth)
|
||||
// advertise yourself to the network
|
||||
if err := n.sendMsg("peer", msg, NetworkChannel); err != nil {
|
||||
log.Debugf("Network failed to advertise peers: %v", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pruneRoutes prunes routes return by given query
|
||||
func (n *network) pruneRoutes(q router.Query) error {
|
||||
routes, err := n.router.Table().Query(q)
|
||||
if err != nil && err != router.ErrRouteNotFound {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, route := range routes {
|
||||
if err := n.router.Table().Delete(route); err != nil && err != router.ErrRouteNotFound {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// pruneNodeRoutes prunes routes that were either originated by or routable via given node
|
||||
func (n *network) prunePeerRoutes(peer *node) error {
|
||||
// lookup all routes originated by router
|
||||
q := router.NewQuery(
|
||||
router.QueryRouter(peer.id),
|
||||
)
|
||||
if err := n.pruneRoutes(q); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// lookup all routes routable via gw
|
||||
q = router.NewQuery(
|
||||
router.QueryGateway(peer.id),
|
||||
)
|
||||
if err := n.pruneRoutes(q); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// prune deltes node peers that have not been seen for longer than PruneTime seconds
|
||||
// prune also removes all the routes either originated by or routable by the stale nodes
|
||||
func (n *network) prune() {
|
||||
prune := time.NewTicker(PruneTime)
|
||||
defer prune.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-n.closed:
|
||||
return
|
||||
case <-prune.C:
|
||||
pruned := n.PruneStalePeerNodes(PruneTime)
|
||||
for id, peer := range pruned {
|
||||
log.Debugf("Network peer exceeded prune time: %s", id)
|
||||
if err := n.prunePeerRoutes(peer); err != nil {
|
||||
log.Debugf("Network failed pruning peer %s routes: %v", id, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleCtrlConn handles ControlChannel connections
|
||||
func (n *network) handleCtrlConn(sess tunnel.Session, msg chan *transport.Message) {
|
||||
for {
|
||||
m := new(transport.Message)
|
||||
if err := sess.Recv(m); err != nil {
|
||||
// TODO: should we bail here?
|
||||
log.Debugf("Network tunnel advert receive error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case msg <- m:
|
||||
case <-n.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// acceptCtrlConn accepts connections from ControlChannel
|
||||
func (n *network) acceptCtrlConn(l tunnel.Listener, recv chan *transport.Message) {
|
||||
for {
|
||||
// accept a connection
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
// TODO: handle this
|
||||
log.Debugf("Network tunnel [%s] accept error: %v", ControlChannel, err)
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case <-n.closed:
|
||||
return
|
||||
default:
|
||||
// go handle ControlChannel connection
|
||||
go n.handleCtrlConn(conn, recv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setRouteMetric calculates metric of the route and updates it in place
|
||||
// - Local route metric is 1
|
||||
// - Routes with ID of adjacent nodes are 10
|
||||
// - Routes by peers of the advertiser are 100
|
||||
// - Routes beyond your neighbourhood are 1000
|
||||
func (n *network) setRouteMetric(route *router.Route) {
|
||||
// we are the origin of the route
|
||||
if route.Router == n.options.Id {
|
||||
route.Metric = 1
|
||||
return
|
||||
}
|
||||
|
||||
// check if the route origin is our peer
|
||||
if _, ok := n.peers[route.Router]; ok {
|
||||
route.Metric = 10
|
||||
return
|
||||
}
|
||||
|
||||
// check if the route origin is the peer of our peer
|
||||
for _, peer := range n.peers {
|
||||
for id := range peer.peers {
|
||||
if route.Router == id {
|
||||
route.Metric = 100
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the origin of the route is beyond our neighbourhood
|
||||
route.Metric = 1000
|
||||
}
|
||||
|
||||
// processCtrlChan processes messages received on ControlChannel
|
||||
func (n *network) processCtrlChan(client transport.Client, listener tunnel.Listener) {
|
||||
// receive control message queue
|
||||
recv := make(chan *transport.Message, 128)
|
||||
|
||||
// accept ControlChannel cconnections
|
||||
go n.acceptCtrlConn(listener, recv)
|
||||
|
||||
for {
|
||||
select {
|
||||
case m := <-recv:
|
||||
// switch on type of message and take action
|
||||
switch m.Header["Micro-Method"] {
|
||||
case "advert":
|
||||
pbRtrAdvert := &pbRtr.Advert{}
|
||||
if err := proto.Unmarshal(m.Body, pbRtrAdvert); err != nil {
|
||||
log.Debugf("Network fail to unmarshal advert message: %v", err)
|
||||
continue
|
||||
}
|
||||
// don't process your own messages
|
||||
if pbRtrAdvert.Id == n.options.Id {
|
||||
continue
|
||||
}
|
||||
log.Debugf("Network received advert message from: %s", pbRtrAdvert.Id)
|
||||
// loookup advertising node in our peer topology
|
||||
advertNode := n.node.GetPeerNode(pbRtrAdvert.Id)
|
||||
if advertNode == nil {
|
||||
// if we can't find the node in our topology (MaxDepth) we skipp prcessing adverts
|
||||
log.Debugf("Network skipping advert message from unknown peer: %s", pbRtrAdvert.Id)
|
||||
continue
|
||||
}
|
||||
|
||||
var events []*router.Event
|
||||
for _, event := range pbRtrAdvert.Events {
|
||||
// we know the advertising node is not the origin of the route
|
||||
if pbRtrAdvert.Id != event.Route.Router {
|
||||
// if the origin router is not the advertising node peer
|
||||
// we can't rule out potential routing loops so we bail here
|
||||
if peer := advertNode.GetPeerNode(event.Route.Router); peer == nil {
|
||||
log.Debugf("Network skipping advert message from peer: %s", pbRtrAdvert.Id)
|
||||
continue
|
||||
}
|
||||
}
|
||||
route := router.Route{
|
||||
Service: event.Route.Service,
|
||||
Address: event.Route.Address,
|
||||
Gateway: event.Route.Gateway,
|
||||
Network: event.Route.Network,
|
||||
Router: event.Route.Router,
|
||||
Link: event.Route.Link,
|
||||
Metric: int(event.Route.Metric),
|
||||
}
|
||||
// set the route metric
|
||||
n.node.RLock()
|
||||
n.setRouteMetric(&route)
|
||||
n.node.RUnlock()
|
||||
// throw away metric bigger than 1000
|
||||
if route.Metric > 1000 {
|
||||
log.Debugf("Network route metric %d dropping node: %s", route.Metric, route.Router)
|
||||
continue
|
||||
}
|
||||
// create router event
|
||||
e := &router.Event{
|
||||
Type: router.EventType(event.Type),
|
||||
Timestamp: time.Unix(0, pbRtrAdvert.Timestamp),
|
||||
Route: route,
|
||||
}
|
||||
events = append(events, e)
|
||||
}
|
||||
// if no events are eligible for processing continue
|
||||
if len(events) == 0 {
|
||||
log.Debugf("Network no events to be processed by router: %s", n.options.Id)
|
||||
continue
|
||||
}
|
||||
// create an advert and process it
|
||||
advert := &router.Advert{
|
||||
Id: pbRtrAdvert.Id,
|
||||
Type: router.AdvertType(pbRtrAdvert.Type),
|
||||
Timestamp: time.Unix(0, pbRtrAdvert.Timestamp),
|
||||
TTL: time.Duration(pbRtrAdvert.Ttl),
|
||||
Events: events,
|
||||
}
|
||||
|
||||
log.Debugf("Network router %s processing advert: %s", n.Id(), advert.Id)
|
||||
if err := n.router.Process(advert); err != nil {
|
||||
log.Debugf("Network failed to process advert %s: %v", advert.Id, err)
|
||||
}
|
||||
case "solicit":
|
||||
pbRtrSolicit := &pbRtr.Solicit{}
|
||||
if err := proto.Unmarshal(m.Body, pbRtrSolicit); err != nil {
|
||||
log.Debugf("Network fail to unmarshal solicit message: %v", err)
|
||||
continue
|
||||
}
|
||||
log.Debugf("Network received solicit message from: %s", pbRtrSolicit.Id)
|
||||
// ignore solicitation when requested by you
|
||||
if pbRtrSolicit.Id == n.options.Id {
|
||||
continue
|
||||
}
|
||||
log.Debugf("Network router flushing routes for: %s", pbRtrSolicit.Id)
|
||||
// advertise all the routes when a new node has connected
|
||||
if err := n.router.Solicit(); err != nil {
|
||||
log.Debugf("Network failed to solicit routes: %s", err)
|
||||
}
|
||||
}
|
||||
case <-n.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// advertise advertises routes to the network
|
||||
func (n *network) advertise(client transport.Client, advertChan <-chan *router.Advert) {
|
||||
hasher := fnv.New64()
|
||||
for {
|
||||
select {
|
||||
// process local adverts and randomly fire them at other nodes
|
||||
case advert := <-advertChan:
|
||||
// create a proto advert
|
||||
var events []*pbRtr.Event
|
||||
for _, event := range advert.Events {
|
||||
// the routes service address
|
||||
address := event.Route.Address
|
||||
|
||||
// only hash the address if we're advertising our own local routes
|
||||
if event.Route.Router == advert.Id {
|
||||
// hash the service before advertising it
|
||||
hasher.Reset()
|
||||
hasher.Write([]byte(event.Route.Address + n.node.id))
|
||||
address = fmt.Sprintf("%d", hasher.Sum64())
|
||||
}
|
||||
|
||||
// NOTE: we override Gateway, Link and Address here
|
||||
// TODO: should we avoid overriding gateway?
|
||||
route := &pbRtr.Route{
|
||||
Service: event.Route.Service,
|
||||
Address: address,
|
||||
Gateway: n.node.id,
|
||||
Network: event.Route.Network,
|
||||
Router: event.Route.Router,
|
||||
Link: DefaultLink,
|
||||
Metric: int64(event.Route.Metric),
|
||||
}
|
||||
e := &pbRtr.Event{
|
||||
Type: pbRtr.EventType(event.Type),
|
||||
Timestamp: event.Timestamp.UnixNano(),
|
||||
Route: route,
|
||||
}
|
||||
events = append(events, e)
|
||||
}
|
||||
msg := &pbRtr.Advert{
|
||||
Id: advert.Id,
|
||||
Type: pbRtr.AdvertType(advert.Type),
|
||||
Timestamp: advert.Timestamp.UnixNano(),
|
||||
Events: events,
|
||||
}
|
||||
if err := n.sendMsg("advert", msg, ControlChannel); err != nil {
|
||||
log.Debugf("Network failed to advertise routes: %v", err)
|
||||
continue
|
||||
}
|
||||
case <-n.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connect connects the network
|
||||
func (n *network) Connect() error {
|
||||
n.Lock()
|
||||
// return if already connected
|
||||
if n.connected {
|
||||
n.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// try to resolve network nodes
|
||||
nodes, err := n.resolveNodes()
|
||||
if err != nil {
|
||||
log.Debugf("Network failed to resolve nodes: %v", err)
|
||||
}
|
||||
|
||||
// connect network tunnel
|
||||
if err := n.tunnel.Connect(); err != nil {
|
||||
n.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// set our internal node address
|
||||
// if advertise address is not set
|
||||
if len(n.options.Advertise) == 0 {
|
||||
n.node.address = n.tunnel.Address()
|
||||
n.server.Init(server.Advertise(n.tunnel.Address()))
|
||||
}
|
||||
|
||||
// initialize the tunnel to resolved nodes
|
||||
n.tunnel.Init(
|
||||
tunnel.Nodes(nodes...),
|
||||
)
|
||||
|
||||
// dial into ControlChannel to send route adverts
|
||||
ctrlClient, err := n.tunnel.Dial(ControlChannel, tunnel.DialMulticast())
|
||||
if err != nil {
|
||||
n.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
n.tunClient[ControlChannel] = ctrlClient
|
||||
|
||||
// listen on ControlChannel
|
||||
ctrlListener, err := n.tunnel.Listen(ControlChannel)
|
||||
if err != nil {
|
||||
n.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// dial into NetworkChannel to send network messages
|
||||
netClient, err := n.tunnel.Dial(NetworkChannel, tunnel.DialMulticast())
|
||||
if err != nil {
|
||||
n.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
n.tunClient[NetworkChannel] = netClient
|
||||
|
||||
// listen on NetworkChannel
|
||||
netListener, err := n.tunnel.Listen(NetworkChannel)
|
||||
if err != nil {
|
||||
n.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// create closed channel
|
||||
n.closed = make(chan bool)
|
||||
|
||||
// start the router
|
||||
if err := n.options.Router.Start(); err != nil {
|
||||
n.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// start advertising routes
|
||||
advertChan, err := n.options.Router.Advertise()
|
||||
if err != nil {
|
||||
n.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
// start the server
|
||||
if err := n.server.Start(); err != nil {
|
||||
n.Unlock()
|
||||
return err
|
||||
}
|
||||
n.Unlock()
|
||||
|
||||
// send connect message to NetworkChannel
|
||||
// NOTE: in theory we could do this as soon as
|
||||
// Dial to NetworkChannel succeeds, but instead
|
||||
// we initialize all other node resources first
|
||||
msg := &pbNet.Connect{
|
||||
Node: &pbNet.Node{
|
||||
Id: n.node.id,
|
||||
Address: n.node.address,
|
||||
},
|
||||
}
|
||||
if err := n.sendMsg("connect", msg, NetworkChannel); err != nil {
|
||||
log.Debugf("Network failed to send connect message: %s", err)
|
||||
}
|
||||
|
||||
// go resolving network nodes
|
||||
go n.resolve()
|
||||
// broadcast peers
|
||||
go n.announce(netClient)
|
||||
// prune stale nodes
|
||||
go n.prune()
|
||||
// listen to network messages
|
||||
go n.processNetChan(netClient, netListener)
|
||||
// advertise service routes
|
||||
go n.advertise(ctrlClient, advertChan)
|
||||
// accept and process routes
|
||||
go n.processCtrlChan(ctrlClient, ctrlListener)
|
||||
|
||||
n.Lock()
|
||||
n.connected = true
|
||||
n.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *network) close() error {
|
||||
// stop the server
|
||||
if err := n.server.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// stop the router
|
||||
if err := n.router.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// close the tunnel
|
||||
if err := n.tunnel.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes network connection
|
||||
func (n *network) Close() error {
|
||||
n.Lock()
|
||||
|
||||
if !n.connected {
|
||||
n.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
select {
|
||||
case <-n.closed:
|
||||
n.Unlock()
|
||||
return nil
|
||||
default:
|
||||
// TODO: send close message to the network channel
|
||||
close(n.closed)
|
||||
// set connected to false
|
||||
n.connected = false
|
||||
|
||||
// unlock the lock otherwise we'll deadlock sending the close
|
||||
n.Unlock()
|
||||
|
||||
msg := &pbNet.Close{
|
||||
Node: &pbNet.Node{
|
||||
Id: n.node.id,
|
||||
Address: n.node.address,
|
||||
},
|
||||
}
|
||||
if err := n.sendMsg("close", msg, NetworkChannel); err != nil {
|
||||
log.Debugf("Network failed to send close message: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
return n.close()
|
||||
}
|
||||
|
||||
// Client returns network client
|
||||
func (n *network) Client() client.Client {
|
||||
return n.client
|
||||
}
|
||||
|
||||
// Server returns network server
|
||||
func (n *network) Server() server.Server {
|
||||
return n.server
|
||||
}
|
145
network/handler/handler.go
Normal file
145
network/handler/handler.go
Normal file
@ -0,0 +1,145 @@
|
||||
// Package handler implements network RPC handler
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/errors"
|
||||
"github.com/micro/go-micro/network"
|
||||
pbNet "github.com/micro/go-micro/network/proto"
|
||||
pbRtr "github.com/micro/go-micro/router/proto"
|
||||
)
|
||||
|
||||
// Network implements network handler
|
||||
type Network struct {
|
||||
Network network.Network
|
||||
}
|
||||
|
||||
func flatten(n network.Node, visited map[string]bool) []network.Node {
|
||||
// if node is nil runaway
|
||||
if n == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// set visisted
|
||||
if visited == nil {
|
||||
visited = make(map[string]bool)
|
||||
}
|
||||
|
||||
// check if already visited
|
||||
if visited[n.Id()] == true {
|
||||
return nil
|
||||
}
|
||||
|
||||
// create new list of nodes
|
||||
var nodes []network.Node
|
||||
|
||||
// append the current node
|
||||
nodes = append(nodes, n)
|
||||
|
||||
// set to visited
|
||||
visited[n.Id()] = true
|
||||
|
||||
// visit the list of peers
|
||||
for _, node := range n.Peers() {
|
||||
nodes = append(nodes, flatten(node, visited)...)
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
// Nodes returns the list of nodes
|
||||
func (n *Network) Nodes(ctx context.Context, req *pbNet.NodesRequest, resp *pbNet.NodesResponse) error {
|
||||
depth := uint(req.Depth)
|
||||
if depth <= 0 || depth > network.MaxDepth {
|
||||
depth = network.MaxDepth
|
||||
}
|
||||
|
||||
// root node
|
||||
nodes := map[string]network.Node{}
|
||||
|
||||
// get peers encoded into protobuf
|
||||
peers := flatten(n.Network, nil)
|
||||
|
||||
// walk all the peers
|
||||
for _, peer := range peers {
|
||||
if peer == nil {
|
||||
continue
|
||||
}
|
||||
if _, ok := nodes[peer.Id()]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
// add to visited list
|
||||
nodes[n.Network.Id()] = peer
|
||||
|
||||
resp.Nodes = append(resp.Nodes, &pbNet.Node{
|
||||
Id: peer.Id(),
|
||||
Address: peer.Address(),
|
||||
})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Graph returns the network graph from this root node
|
||||
func (n *Network) Graph(ctx context.Context, req *pbNet.GraphRequest, resp *pbNet.GraphResponse) error {
|
||||
depth := uint(req.Depth)
|
||||
if depth <= 0 || depth > network.MaxDepth {
|
||||
depth = network.MaxDepth
|
||||
}
|
||||
|
||||
// get peers encoded into protobuf
|
||||
peers := network.PeersToProto(n.Network, depth)
|
||||
|
||||
// set the root node
|
||||
resp.Root = peers
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Routes returns a list of routing table routes
|
||||
func (n *Network) Routes(ctx context.Context, req *pbNet.RoutesRequest, resp *pbNet.RoutesResponse) error {
|
||||
routes, err := n.Network.Options().Router.Table().List()
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.network", "failed to list routes: %s", err)
|
||||
}
|
||||
|
||||
var respRoutes []*pbRtr.Route
|
||||
for _, route := range routes {
|
||||
respRoute := &pbRtr.Route{
|
||||
Service: route.Service,
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Router: route.Router,
|
||||
Link: route.Link,
|
||||
Metric: int64(route.Metric),
|
||||
}
|
||||
respRoutes = append(respRoutes, respRoute)
|
||||
}
|
||||
|
||||
resp.Routes = respRoutes
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Services returns a list of services based on the routing table
|
||||
func (n *Network) Services(ctx context.Context, req *pbNet.ServicesRequest, resp *pbNet.ServicesResponse) error {
|
||||
routes, err := n.Network.Options().Router.Table().List()
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.network", "failed to list services: %s", err)
|
||||
}
|
||||
|
||||
services := make(map[string]bool)
|
||||
|
||||
for _, route := range routes {
|
||||
if _, ok := services[route.Service]; ok {
|
||||
continue
|
||||
}
|
||||
services[route.Service] = true
|
||||
resp.Services = append(resp.Services, route.Service)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -1,288 +0,0 @@
|
||||
// Package link provides a measured transport.Socket link
|
||||
package link
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
type link struct {
|
||||
sync.RWMutex
|
||||
|
||||
// the link id
|
||||
id string
|
||||
|
||||
// the remote end to dial
|
||||
addr string
|
||||
|
||||
// channel used to close the link
|
||||
closed chan bool
|
||||
|
||||
// if its connected
|
||||
connected bool
|
||||
|
||||
// the transport to use
|
||||
transport transport.Transport
|
||||
|
||||
// the send queue to the socket
|
||||
sendQueue chan *transport.Message
|
||||
// the recv queue to the socket
|
||||
recvQueue chan *transport.Message
|
||||
|
||||
// the socket for this link
|
||||
socket transport.Socket
|
||||
|
||||
// determines the cost of the link
|
||||
// based on queue length and roundtrip
|
||||
length int
|
||||
weight int
|
||||
}
|
||||
|
||||
func newLink(options options.Options) *link {
|
||||
// default values
|
||||
var sock transport.Socket
|
||||
var addr string
|
||||
id := "local"
|
||||
tr := transport.DefaultTransport
|
||||
|
||||
lid, ok := options.Values().Get("link.id")
|
||||
if ok {
|
||||
id = lid.(string)
|
||||
}
|
||||
|
||||
laddr, ok := options.Values().Get("link.address")
|
||||
if ok {
|
||||
addr = laddr.(string)
|
||||
}
|
||||
|
||||
ltr, ok := options.Values().Get("link.transport")
|
||||
if ok {
|
||||
tr = ltr.(transport.Transport)
|
||||
}
|
||||
|
||||
lsock, ok := options.Values().Get("link.socket")
|
||||
if ok {
|
||||
sock = lsock.(transport.Socket)
|
||||
}
|
||||
|
||||
l := &link{
|
||||
// the remote end to dial
|
||||
addr: addr,
|
||||
// transport to dial link
|
||||
transport: tr,
|
||||
// the socket to use
|
||||
// this is nil if not specified
|
||||
socket: sock,
|
||||
// unique id assigned to the link
|
||||
id: id,
|
||||
// the closed channel used to close the conn
|
||||
closed: make(chan bool),
|
||||
// then send queue
|
||||
sendQueue: make(chan *transport.Message, 128),
|
||||
// the receive queue
|
||||
recvQueue: make(chan *transport.Message, 128),
|
||||
}
|
||||
|
||||
// return the link
|
||||
return l
|
||||
}
|
||||
|
||||
// link methods
|
||||
|
||||
// process processes messages on the send and receive queues.
|
||||
func (l *link) process() {
|
||||
go func() {
|
||||
for {
|
||||
m := new(transport.Message)
|
||||
if err := l.recv(m); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
select {
|
||||
case l.recvQueue <- m:
|
||||
case <-l.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// messages sent
|
||||
i := 0
|
||||
length := 0
|
||||
|
||||
for {
|
||||
select {
|
||||
case m := <-l.sendQueue:
|
||||
t := time.Now()
|
||||
|
||||
// send the message
|
||||
if err := l.send(m); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// get header size, body size and time taken
|
||||
hl := len(m.Header)
|
||||
bl := len(m.Body)
|
||||
d := time.Since(t)
|
||||
|
||||
// don't calculate on empty messages
|
||||
if hl == 0 && bl == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// increment sent
|
||||
i++
|
||||
|
||||
// time take to send some bits and bytes
|
||||
td := float64(hl+bl) / float64(d.Nanoseconds())
|
||||
// increase the scale
|
||||
td += 1
|
||||
|
||||
// judge the length
|
||||
length = int(td) / (length + int(td))
|
||||
|
||||
// every 10 messages update length
|
||||
if (i % 10) == 1 {
|
||||
// cost average the length
|
||||
// save it
|
||||
l.Lock()
|
||||
l.length = length
|
||||
l.Unlock()
|
||||
}
|
||||
case <-l.closed:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send a message over the link
|
||||
func (l *link) send(m *transport.Message) error {
|
||||
// TODO: measure time taken and calculate length/rate
|
||||
// send via the transport socket
|
||||
return l.socket.Send(m)
|
||||
}
|
||||
|
||||
// recv a message on the link
|
||||
func (l *link) recv(m *transport.Message) error {
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string)
|
||||
}
|
||||
// receive the transport message
|
||||
return l.socket.Recv(m)
|
||||
}
|
||||
|
||||
// Connect attempts to connect to an address and sets the socket
|
||||
func (l *link) Connect() error {
|
||||
l.Lock()
|
||||
if l.connected {
|
||||
l.Unlock()
|
||||
return nil
|
||||
}
|
||||
defer l.Unlock()
|
||||
|
||||
// replace closed
|
||||
l.closed = make(chan bool)
|
||||
|
||||
// assume existing socket
|
||||
if len(l.addr) == 0 {
|
||||
go l.process()
|
||||
return nil
|
||||
}
|
||||
|
||||
// dial the endpoint
|
||||
c, err := l.transport.Dial(l.addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the socket
|
||||
l.socket = c
|
||||
|
||||
// kick start the processing
|
||||
go l.process()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close the link
|
||||
func (l *link) Close() error {
|
||||
select {
|
||||
case <-l.closed:
|
||||
return nil
|
||||
default:
|
||||
close(l.closed)
|
||||
l.Lock()
|
||||
l.connected = false
|
||||
l.Unlock()
|
||||
return l.socket.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// returns the node id
|
||||
func (l *link) Id() string {
|
||||
l.RLock()
|
||||
defer l.RUnlock()
|
||||
return l.id
|
||||
}
|
||||
|
||||
// the remote ip of the link
|
||||
func (l *link) Remote() string {
|
||||
l.RLock()
|
||||
defer l.RUnlock()
|
||||
return l.socket.Remote()
|
||||
}
|
||||
|
||||
// the local ip of the link
|
||||
func (l *link) Local() string {
|
||||
l.RLock()
|
||||
defer l.RUnlock()
|
||||
return l.socket.Local()
|
||||
}
|
||||
|
||||
// length/rate of the link
|
||||
func (l *link) Length() int {
|
||||
l.RLock()
|
||||
defer l.RUnlock()
|
||||
return l.length
|
||||
}
|
||||
|
||||
// weight checks the size of the queues
|
||||
func (l *link) Weight() int {
|
||||
return len(l.sendQueue) + len(l.recvQueue)
|
||||
}
|
||||
|
||||
// Accept accepts a message on the socket
|
||||
func (l *link) Recv(m *transport.Message) error {
|
||||
select {
|
||||
case <-l.closed:
|
||||
return io.EOF
|
||||
case rm := <-l.recvQueue:
|
||||
*m = *rm
|
||||
return nil
|
||||
}
|
||||
// never reach
|
||||
return nil
|
||||
}
|
||||
|
||||
// Send sends a message on the socket immediately
|
||||
func (l *link) Send(m *transport.Message) error {
|
||||
select {
|
||||
case <-l.closed:
|
||||
return io.EOF
|
||||
case l.sendQueue <- m:
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *link) Status() string {
|
||||
select {
|
||||
case <-l.closed:
|
||||
return "closed"
|
||||
default:
|
||||
return "connected"
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
// Package link provides a measured link on top of a transport.Socket
|
||||
package link
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
// Link is a layer on top of a transport socket with the
|
||||
// buffering send and recv queue's with the ability to
|
||||
// measure the actual transport link and reconnect if
|
||||
// an address is specified.
|
||||
type Link interface {
|
||||
// provides the transport.Socket interface
|
||||
transport.Socket
|
||||
// Connect connects the link. It must be called first
|
||||
// if there's an expectation to create a new socket.
|
||||
Connect() error
|
||||
// Id of the link is "local" if not specified
|
||||
Id() string
|
||||
// Status of the link
|
||||
Status() string
|
||||
// Depth of the buffers
|
||||
Weight() int
|
||||
// Rate of the link
|
||||
Length() int
|
||||
}
|
||||
|
||||
var (
|
||||
ErrLinkClosed = errors.New("link closed")
|
||||
)
|
||||
|
||||
// NewLink creates a new link on top of a socket
|
||||
func NewLink(opts ...options.Option) Link {
|
||||
return newLink(options.NewOptions(opts...))
|
||||
}
|
||||
|
||||
// Sets the link id which otherwise defaults to "local"
|
||||
func Id(id string) options.Option {
|
||||
return options.WithValue("link.id", id)
|
||||
}
|
||||
|
||||
// The address to use for the link. Connect must be
|
||||
// called for this to be used, its otherwise unused.
|
||||
func Address(a string) options.Option {
|
||||
return options.WithValue("link.address", a)
|
||||
}
|
||||
|
||||
// The transport to use for the link where we
|
||||
// want to dial the connection first.
|
||||
func Transport(t transport.Transport) options.Option {
|
||||
return options.WithValue("link.transport", t)
|
||||
}
|
||||
|
||||
// Socket sets the socket to use instead of dialing.
|
||||
func Socket(s transport.Socket) options.Option {
|
||||
return options.WithValue("link.socket", s)
|
||||
}
|
@ -1,2 +1,58 @@
|
||||
// Package network is for creating internetworks
|
||||
package network
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultName is default network name
|
||||
DefaultName = "go.micro"
|
||||
// DefaultAddress is default network address
|
||||
DefaultAddress = ":0"
|
||||
// ResolveTime defines time interval to periodically resolve network nodes
|
||||
ResolveTime = 1 * time.Minute
|
||||
// AnnounceTime defines time interval to periodically announce node neighbours
|
||||
AnnounceTime = 30 * time.Second
|
||||
// PruneTime defines time interval to periodically check nodes that need to be pruned
|
||||
// due to their not announcing their presence within this time interval
|
||||
PruneTime = 90 * time.Second
|
||||
)
|
||||
|
||||
// Node is network node
|
||||
type Node interface {
|
||||
// Id is node id
|
||||
Id() string
|
||||
// Address is node bind address
|
||||
Address() string
|
||||
// Peers returns node peers
|
||||
Peers() []Node
|
||||
// Network is the network node is in
|
||||
Network() Network
|
||||
}
|
||||
|
||||
// Network is micro network
|
||||
type Network interface {
|
||||
// Node is network node
|
||||
Node
|
||||
// Options returns the network options
|
||||
Options() Options
|
||||
// Name of the network
|
||||
Name() string
|
||||
// Connect starts the resolver and tunnel server
|
||||
Connect() error
|
||||
// Close stops the tunnel and resolving
|
||||
Close() error
|
||||
// Client is micro client
|
||||
Client() client.Client
|
||||
// Server is micro server
|
||||
Server() server.Server
|
||||
}
|
||||
|
||||
// NewNetwork returns a new network interface
|
||||
func NewNetwork(opts ...Option) Network {
|
||||
return newNetwork(opts...)
|
||||
}
|
||||
|
366
network/node.go
Normal file
366
network/node.go
Normal file
@ -0,0 +1,366 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
pb "github.com/micro/go-micro/network/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
// MaxDepth defines max depth of peer topology
|
||||
MaxDepth uint = 3
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrPeerExists is returned when adding a peer which already exists
|
||||
ErrPeerExists = errors.New("peer already exists")
|
||||
// ErrPeerNotFound is returned when a peer could not be found in node topology
|
||||
ErrPeerNotFound = errors.New("peer not found")
|
||||
)
|
||||
|
||||
// node is network node
|
||||
type node struct {
|
||||
sync.RWMutex
|
||||
// id is node id
|
||||
id string
|
||||
// address is node address
|
||||
address string
|
||||
// peers are nodes with direct link to this node
|
||||
peers map[string]*node
|
||||
// network returns the node network
|
||||
network Network
|
||||
// lastSeen keeps track of node lifetime and updates
|
||||
lastSeen time.Time
|
||||
}
|
||||
|
||||
// Id is node ide
|
||||
func (n *node) Id() string {
|
||||
return n.id
|
||||
}
|
||||
|
||||
// Address returns node address
|
||||
func (n *node) Address() string {
|
||||
return n.address
|
||||
}
|
||||
|
||||
// Network returns node network
|
||||
func (n *node) Network() Network {
|
||||
return n.network
|
||||
}
|
||||
|
||||
// walk walks the node graph until some condition is met
|
||||
func (n *node) walk(until func(peer *node) bool, action func(parent, peer *node)) map[string]*node {
|
||||
// track the visited nodes
|
||||
visited := make(map[string]*node)
|
||||
// queue of the nodes to visit
|
||||
queue := list.New()
|
||||
|
||||
// push node to the back of queue
|
||||
queue.PushBack(n)
|
||||
// mark the node as visited
|
||||
visited[n.id] = n
|
||||
|
||||
// keep iterating over the queue until its empty
|
||||
for queue.Len() > 0 {
|
||||
// pop the node from the front of the queue
|
||||
qnode := queue.Front()
|
||||
if until(qnode.Value.(*node)) {
|
||||
return visited
|
||||
}
|
||||
// iterate through all of the node peers
|
||||
// mark the visited nodes; enqueue the non-visted
|
||||
for id, peer := range qnode.Value.(*node).peers {
|
||||
if _, ok := visited[id]; !ok {
|
||||
visited[id] = peer
|
||||
action(qnode.Value.(*node), peer)
|
||||
queue.PushBack(peer)
|
||||
}
|
||||
}
|
||||
// remove the node from the queue
|
||||
queue.Remove(qnode)
|
||||
}
|
||||
|
||||
return visited
|
||||
}
|
||||
|
||||
// AddPeer adds a new peer to node topology
|
||||
// It returns false if the peer already exists
|
||||
func (n *node) AddPeer(peer *node) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
if _, ok := n.peers[peer.id]; !ok {
|
||||
n.peers[peer.id] = peer
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrPeerExists
|
||||
}
|
||||
|
||||
// DeletePeer deletes a peer from node peers
|
||||
// It returns true if the peer has been deleted
|
||||
func (n *node) DeletePeer(id string) bool {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
delete(n.peers, id)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// UpdatePeer updates a peer if it already exists
|
||||
// It returns error if the peer does not exist
|
||||
func (n *node) UpdatePeer(peer *node) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
if _, ok := n.peers[peer.id]; ok {
|
||||
n.peers[peer.id] = peer
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrPeerNotFound
|
||||
}
|
||||
|
||||
// RefreshPeer updates node timestamp
|
||||
// It returns false if the peer has not been found.
|
||||
func (n *node) RefreshPeer(id string, now time.Time) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
peer, ok := n.peers[id]
|
||||
if !ok {
|
||||
return ErrPeerNotFound
|
||||
}
|
||||
|
||||
if peer.lastSeen.Before(now) {
|
||||
peer.lastSeen = now
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Nodes returns a slice of all nodes in the whole node topology
|
||||
func (n *node) Nodes() []Node {
|
||||
// we need to freeze the network graph here
|
||||
// otherwise we might get inconsisten results
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
|
||||
// NOTE: this should never be true
|
||||
untilNoMorePeers := func(node *node) bool {
|
||||
return node == nil
|
||||
}
|
||||
justWalk := func(parent, node *node) {}
|
||||
|
||||
visited := n.walk(untilNoMorePeers, justWalk)
|
||||
|
||||
var nodes []Node
|
||||
// collect all the nodes and return them
|
||||
for _, node := range visited {
|
||||
nodes = append(nodes, node)
|
||||
}
|
||||
|
||||
return nodes
|
||||
}
|
||||
|
||||
// GetPeerNode returns a node from node MaxDepth topology
|
||||
// It returns nil if the peer was not found
|
||||
func (n *node) GetPeerNode(id string) *node {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
|
||||
// get node topology up to MaxDepth
|
||||
top := n.Topology(MaxDepth)
|
||||
|
||||
untilFoundPeer := func(n *node) bool {
|
||||
return n.id == id
|
||||
}
|
||||
justWalk := func(paent, node *node) {}
|
||||
|
||||
visited := top.walk(untilFoundPeer, justWalk)
|
||||
|
||||
peerNode, ok := visited[id]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return peerNode
|
||||
}
|
||||
|
||||
// DeletePeerNode removes peer node from node topology
|
||||
func (n *node) DeletePeerNode(id string) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
untilNoMorePeers := func(node *node) bool {
|
||||
return node == nil
|
||||
}
|
||||
|
||||
deleted := make(map[string]*node)
|
||||
deletePeer := func(parent, node *node) {
|
||||
if node.id != n.id && node.id == id {
|
||||
delete(parent.peers, node.id)
|
||||
deleted[node.id] = node
|
||||
}
|
||||
}
|
||||
|
||||
n.walk(untilNoMorePeers, deletePeer)
|
||||
|
||||
if _, ok := deleted[id]; !ok {
|
||||
return ErrPeerNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PruneStalePeerNodes prune the peers that have not been seen for longer than given time
|
||||
// It returns a map of the the nodes that got pruned
|
||||
func (n *node) PruneStalePeerNodes(pruneTime time.Duration) map[string]*node {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
untilNoMorePeers := func(node *node) bool {
|
||||
return node == nil
|
||||
}
|
||||
|
||||
pruned := make(map[string]*node)
|
||||
pruneStalePeer := func(parent, node *node) {
|
||||
if node.id != n.id && time.Since(node.lastSeen) > PruneTime {
|
||||
delete(parent.peers, node.id)
|
||||
pruned[node.id] = node
|
||||
}
|
||||
}
|
||||
|
||||
n.walk(untilNoMorePeers, pruneStalePeer)
|
||||
|
||||
return pruned
|
||||
}
|
||||
|
||||
// Topology returns a copy of the node topology down to given depth
|
||||
// NOTE: the returned node is a node graph - not a single node
|
||||
func (n *node) Topology(depth uint) *node {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
|
||||
// make a copy of yourself
|
||||
node := &node{
|
||||
id: n.id,
|
||||
address: n.address,
|
||||
peers: make(map[string]*node),
|
||||
network: n.network,
|
||||
lastSeen: n.lastSeen,
|
||||
}
|
||||
|
||||
// return if we reach requested depth or we have no more peers
|
||||
if depth == 0 || len(n.peers) == 0 {
|
||||
return node
|
||||
}
|
||||
|
||||
// decrement the depth
|
||||
depth--
|
||||
|
||||
// iterate through our peers and update the node peers
|
||||
for _, peer := range n.peers {
|
||||
nodePeer := peer.Topology(depth)
|
||||
if _, ok := node.peers[nodePeer.id]; !ok {
|
||||
node.peers[nodePeer.id] = nodePeer
|
||||
}
|
||||
}
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
// Peers returns node peers up to MaxDepth
|
||||
func (n *node) Peers() []Node {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
|
||||
var peers []Node
|
||||
for _, nodePeer := range n.peers {
|
||||
peer := nodePeer.Topology(MaxDepth)
|
||||
peers = append(peers, peer)
|
||||
}
|
||||
|
||||
return peers
|
||||
}
|
||||
|
||||
// UnpackPeerTopology unpacks pb.Peer into node topology of given depth
|
||||
func UnpackPeerTopology(pbPeer *pb.Peer, lastSeen time.Time, depth uint) *node {
|
||||
peerNode := &node{
|
||||
id: pbPeer.Node.Id,
|
||||
address: pbPeer.Node.Address,
|
||||
peers: make(map[string]*node),
|
||||
lastSeen: lastSeen,
|
||||
}
|
||||
|
||||
// return if have either reached the depth or have no more peers
|
||||
if depth == 0 || len(pbPeer.Peers) == 0 {
|
||||
return peerNode
|
||||
}
|
||||
|
||||
// decrement the depth
|
||||
depth--
|
||||
|
||||
peers := make(map[string]*node)
|
||||
for _, pbPeer := range pbPeer.Peers {
|
||||
peer := UnpackPeerTopology(pbPeer, lastSeen, depth)
|
||||
peers[pbPeer.Node.Id] = peer
|
||||
}
|
||||
|
||||
peerNode.peers = peers
|
||||
|
||||
return peerNode
|
||||
}
|
||||
|
||||
func peerProtoTopology(peer Node, depth uint) *pb.Peer {
|
||||
node := &pb.Node{
|
||||
Id: peer.Id(),
|
||||
Address: peer.Address(),
|
||||
}
|
||||
|
||||
pbPeers := &pb.Peer{
|
||||
Node: node,
|
||||
Peers: make([]*pb.Peer, 0),
|
||||
}
|
||||
|
||||
// return if we reached the end of topology or depth
|
||||
if depth == 0 || len(peer.Peers()) == 0 {
|
||||
return pbPeers
|
||||
}
|
||||
|
||||
// decrement the depth
|
||||
depth--
|
||||
|
||||
// iterate through peers of peers aka pops
|
||||
for _, pop := range peer.Peers() {
|
||||
peer := peerProtoTopology(pop, depth)
|
||||
pbPeers.Peers = append(pbPeers.Peers, peer)
|
||||
}
|
||||
|
||||
return pbPeers
|
||||
}
|
||||
|
||||
// PeersToProto returns node peers graph encoded into protobuf
|
||||
func PeersToProto(node Node, depth uint) *pb.Peer {
|
||||
// network node aka root node
|
||||
pbNode := &pb.Node{
|
||||
Id: node.Id(),
|
||||
Address: node.Address(),
|
||||
}
|
||||
// we will build proto topology into this
|
||||
pbPeers := &pb.Peer{
|
||||
Node: pbNode,
|
||||
Peers: make([]*pb.Peer, 0),
|
||||
}
|
||||
|
||||
for _, peer := range node.Peers() {
|
||||
pbPeer := peerProtoTopology(peer, depth)
|
||||
pbPeers.Peers = append(pbPeers.Peers, pbPeer)
|
||||
}
|
||||
|
||||
return pbPeers
|
||||
}
|
319
network/node_test.go
Normal file
319
network/node_test.go
Normal file
@ -0,0 +1,319 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
pb "github.com/micro/go-micro/network/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
testNodeId = "testNode"
|
||||
testNodeAddress = "testAddress"
|
||||
testNodeNetName = "testNetwork"
|
||||
testNodePeerIds = []string{"peer1", "peer2", "peer3"}
|
||||
testPeerOfPeerIds = []string{"peer11", "peer12"}
|
||||
)
|
||||
|
||||
func testSetup() *node {
|
||||
testNode := &node{
|
||||
id: testNodeId,
|
||||
address: testNodeAddress,
|
||||
peers: make(map[string]*node),
|
||||
network: newNetwork(Name(testNodeNetName)),
|
||||
}
|
||||
|
||||
// add some peers to the node
|
||||
for _, id := range testNodePeerIds {
|
||||
testNode.peers[id] = &node{
|
||||
id: id,
|
||||
address: testNode.address + "-" + id,
|
||||
peers: make(map[string]*node),
|
||||
network: testNode.network,
|
||||
}
|
||||
}
|
||||
|
||||
// add peers to peer1
|
||||
// NOTE: these are peers of peers!
|
||||
for _, id := range testPeerOfPeerIds {
|
||||
testNode.peers["peer1"].peers[id] = &node{
|
||||
id: id,
|
||||
address: testNode.address + "-" + id,
|
||||
peers: make(map[string]*node),
|
||||
network: testNode.network,
|
||||
}
|
||||
}
|
||||
|
||||
// connect peer1 with peer2
|
||||
testNode.peers["peer1"].peers["peer2"] = testNode.peers["peer2"]
|
||||
// connect peer2 with peer3
|
||||
testNode.peers["peer2"].peers["peer3"] = testNode.peers["peer3"]
|
||||
|
||||
return testNode
|
||||
}
|
||||
|
||||
func TestNodeId(t *testing.T) {
|
||||
node := testSetup()
|
||||
if node.Id() != testNodeId {
|
||||
t.Errorf("Expected id: %s, found: %s", testNodeId, node.Id())
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeAddress(t *testing.T) {
|
||||
node := testSetup()
|
||||
if node.Address() != testNodeAddress {
|
||||
t.Errorf("Expected address: %s, found: %s", testNodeAddress, node.Address())
|
||||
}
|
||||
}
|
||||
func TestNodeNetwork(t *testing.T) {
|
||||
node := testSetup()
|
||||
if node.Network().Name() != testNodeNetName {
|
||||
t.Errorf("Expected network: %s, found: %s", testNodeNetName, node.Network().Name())
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodes(t *testing.T) {
|
||||
// single node
|
||||
single := &node{
|
||||
id: testNodeId,
|
||||
address: testNodeAddress,
|
||||
peers: make(map[string]*node),
|
||||
network: newNetwork(Name(testNodeNetName)),
|
||||
}
|
||||
// get all the nodes including yourself
|
||||
nodes := single.Nodes()
|
||||
nodeCount := 1
|
||||
|
||||
if len(nodes) != nodeCount {
|
||||
t.Errorf("Expected to find %d nodes, found: %d", nodeCount, len(nodes))
|
||||
}
|
||||
|
||||
// complicated node graph
|
||||
node := testSetup()
|
||||
// get all the nodes including yourself
|
||||
nodes = node.Nodes()
|
||||
|
||||
// compile a list of ids of all nodes in the network into map for easy indexing
|
||||
nodeIds := make(map[string]bool)
|
||||
// add yourself
|
||||
nodeIds[node.id] = true
|
||||
// add peer Ids
|
||||
for _, id := range testNodePeerIds {
|
||||
nodeIds[id] = true
|
||||
}
|
||||
// add peer1 peers i.e. peers of peer
|
||||
for _, id := range testPeerOfPeerIds {
|
||||
nodeIds[id] = true
|
||||
}
|
||||
|
||||
// we should return the correct number of nodes
|
||||
if len(nodes) != len(nodeIds) {
|
||||
t.Errorf("Expected %d nodes, found: %d", len(nodeIds), len(nodes))
|
||||
}
|
||||
|
||||
// iterate through the list of nodes and makes sure all have been returned
|
||||
for _, node := range nodes {
|
||||
if _, ok := nodeIds[node.Id()]; !ok {
|
||||
t.Errorf("Expected to find %s node", node.Id())
|
||||
}
|
||||
}
|
||||
|
||||
// this is a leaf node
|
||||
id := "peer11"
|
||||
if nodePeer := node.GetPeerNode(id); nodePeer == nil {
|
||||
t.Errorf("Expected to find %s node", id)
|
||||
}
|
||||
}
|
||||
|
||||
func collectPeerIds(peer Node, ids map[string]bool) map[string]bool {
|
||||
if len(peer.Peers()) == 0 {
|
||||
return ids
|
||||
}
|
||||
|
||||
// iterate through the whole graph
|
||||
for _, peer := range peer.Peers() {
|
||||
ids = collectPeerIds(peer, ids)
|
||||
if _, ok := ids[peer.Id()]; !ok {
|
||||
ids[peer.Id()] = true
|
||||
}
|
||||
}
|
||||
|
||||
return ids
|
||||
}
|
||||
|
||||
func TestPeers(t *testing.T) {
|
||||
// single node
|
||||
single := &node{
|
||||
id: testNodeId,
|
||||
address: testNodeAddress,
|
||||
peers: make(map[string]*node),
|
||||
network: newNetwork(Name(testNodeNetName)),
|
||||
}
|
||||
// get node peers
|
||||
peers := single.Peers()
|
||||
// there should be no peers
|
||||
peerCount := 0
|
||||
|
||||
if len(peers) != peerCount {
|
||||
t.Errorf("Expected to find %d nodes, found: %d", peerCount, len(peers))
|
||||
}
|
||||
|
||||
// complicated node graph
|
||||
node := testSetup()
|
||||
// list of ids of nodes of MaxDepth
|
||||
peerIds := make(map[string]bool)
|
||||
// add peer Ids
|
||||
for _, id := range testNodePeerIds {
|
||||
peerIds[id] = true
|
||||
}
|
||||
// add peers of peers to peerIds
|
||||
for _, id := range testPeerOfPeerIds {
|
||||
peerIds[id] = true
|
||||
}
|
||||
// get node peers
|
||||
peers = node.Peers()
|
||||
|
||||
// we will collect all returned Peer Ids into this map
|
||||
resPeerIds := make(map[string]bool)
|
||||
for _, peer := range peers {
|
||||
resPeerIds[peer.Id()] = true
|
||||
resPeerIds = collectPeerIds(peer, resPeerIds)
|
||||
}
|
||||
|
||||
// if correct, we must collect all peerIds
|
||||
if len(resPeerIds) != len(peerIds) {
|
||||
t.Errorf("Expected to find %d peers, found: %d", len(peerIds), len(resPeerIds))
|
||||
}
|
||||
|
||||
for id := range resPeerIds {
|
||||
if _, ok := peerIds[id]; !ok {
|
||||
t.Errorf("Expected to find %s peer", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeletePeerNode(t *testing.T) {
|
||||
// complicated node graph
|
||||
node := testSetup()
|
||||
|
||||
nodeCount := len(node.Nodes())
|
||||
|
||||
// should not find non-existent peer node
|
||||
if err := node.DeletePeerNode("foobar"); err != ErrPeerNotFound {
|
||||
t.Errorf("Expected: %v, got: %v", ErrPeerNotFound, err)
|
||||
}
|
||||
|
||||
// lets pick one of the peer1 peers
|
||||
if err := node.DeletePeerNode(testPeerOfPeerIds[0]); err != nil {
|
||||
t.Errorf("Error deleting peer node: %v", err)
|
||||
}
|
||||
|
||||
nodeDelCount := len(node.Nodes())
|
||||
|
||||
if nodeDelCount != nodeCount-1 {
|
||||
t.Errorf("Expected node count: %d, got: %d", nodeCount-1, nodeDelCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPruneStalePeerNodes(t *testing.T) {
|
||||
// complicated node graph
|
||||
node := testSetup()
|
||||
|
||||
nodes := node.Nodes()
|
||||
|
||||
pruneTime := 10 * time.Millisecond
|
||||
time.Sleep(pruneTime)
|
||||
|
||||
// should delete all nodes besides node
|
||||
pruned := node.PruneStalePeerNodes(pruneTime)
|
||||
|
||||
if len(pruned) != len(nodes)-1 {
|
||||
t.Errorf("Expected pruned node count: %d, got: %d", len(nodes)-1, len(pruned))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnpackPeerTopology(t *testing.T) {
|
||||
pbPeer := &pb.Peer{
|
||||
Node: &pb.Node{
|
||||
Id: "newPeer",
|
||||
Address: "newPeerAddress",
|
||||
},
|
||||
Peers: make([]*pb.Peer, 0),
|
||||
}
|
||||
// it should add pbPeer to the single node peers
|
||||
peer := UnpackPeerTopology(pbPeer, time.Now(), 5)
|
||||
if peer.id != pbPeer.Node.Id {
|
||||
t.Errorf("Expected peer id %s, found: %s", pbPeer.Node.Id, peer.id)
|
||||
}
|
||||
|
||||
node := testSetup()
|
||||
// build a simple topology to update node peer1
|
||||
peer1 := node.peers["peer1"]
|
||||
pbPeer1Node := &pb.Node{
|
||||
Id: peer1.id,
|
||||
Address: peer1.address,
|
||||
}
|
||||
|
||||
pbPeer111 := &pb.Peer{
|
||||
Node: &pb.Node{
|
||||
Id: "peer111",
|
||||
Address: "peer111Address",
|
||||
},
|
||||
Peers: make([]*pb.Peer, 0),
|
||||
}
|
||||
|
||||
pbPeer121 := &pb.Peer{
|
||||
Node: &pb.Node{
|
||||
Id: "peer121",
|
||||
Address: "peer121Address",
|
||||
},
|
||||
Peers: make([]*pb.Peer, 0),
|
||||
}
|
||||
// topology to update
|
||||
pbPeer1 := &pb.Peer{
|
||||
Node: pbPeer1Node,
|
||||
Peers: []*pb.Peer{pbPeer111, pbPeer121},
|
||||
}
|
||||
// unpack peer1 topology
|
||||
peer = UnpackPeerTopology(pbPeer1, time.Now(), 5)
|
||||
// make sure peer1 topology has been correctly updated
|
||||
newPeerIds := []string{pbPeer111.Node.Id, pbPeer121.Node.Id}
|
||||
for _, id := range newPeerIds {
|
||||
if _, ok := peer.peers[id]; !ok {
|
||||
t.Errorf("Expected %s to be a peer of %s", id, "peer1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPeersToProto(t *testing.T) {
|
||||
// single node
|
||||
single := &node{
|
||||
id: testNodeId,
|
||||
address: testNodeAddress,
|
||||
peers: make(map[string]*node),
|
||||
network: newNetwork(Name(testNodeNetName)),
|
||||
}
|
||||
topCount := 0
|
||||
|
||||
protoPeers := PeersToProto(single, 0)
|
||||
|
||||
if len(protoPeers.Peers) != topCount {
|
||||
t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoPeers.Peers))
|
||||
}
|
||||
|
||||
// complicated node graph
|
||||
node := testSetup()
|
||||
topCount = 3
|
||||
// list of ids of nodes of depth 1 i.e. node peers
|
||||
peerIds := make(map[string]bool)
|
||||
// add peer Ids
|
||||
for _, id := range testNodePeerIds {
|
||||
peerIds[id] = true
|
||||
}
|
||||
// depth 1 should give us immmediate neighbours only
|
||||
protoPeers = PeersToProto(node, 1)
|
||||
|
||||
if len(protoPeers.Peers) != topCount {
|
||||
t.Errorf("Expected to find %d nodes, found: %d", topCount, len(protoPeers.Peers))
|
||||
}
|
||||
}
|
111
network/options.go
Normal file
111
network/options.go
Normal file
@ -0,0 +1,111 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/network/resolver"
|
||||
"github.com/micro/go-micro/network/resolver/registry"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/proxy/mucp"
|
||||
"github.com/micro/go-micro/router"
|
||||
"github.com/micro/go-micro/tunnel"
|
||||
)
|
||||
|
||||
type Option func(*Options)
|
||||
|
||||
// Options configure network
|
||||
type Options struct {
|
||||
// Id of the node
|
||||
Id string
|
||||
// Name of the network
|
||||
Name string
|
||||
// Address to bind to
|
||||
Address string
|
||||
// Advertise sets the address to advertise
|
||||
Advertise string
|
||||
// Peers is a list of peers to connect to
|
||||
Peers []string
|
||||
// Tunnel is network tunnel
|
||||
Tunnel tunnel.Tunnel
|
||||
// Router is network router
|
||||
Router router.Router
|
||||
// Proxy is network proxy
|
||||
Proxy proxy.Proxy
|
||||
// Resolver is network resolver
|
||||
Resolver resolver.Resolver
|
||||
}
|
||||
|
||||
// Id sets the id of the network node
|
||||
func Id(id string) Option {
|
||||
return func(o *Options) {
|
||||
o.Id = id
|
||||
}
|
||||
}
|
||||
|
||||
// Name sets the network name
|
||||
func Name(n string) Option {
|
||||
return func(o *Options) {
|
||||
o.Name = n
|
||||
}
|
||||
}
|
||||
|
||||
// Address sets the network address
|
||||
func Address(a string) Option {
|
||||
return func(o *Options) {
|
||||
o.Address = a
|
||||
}
|
||||
}
|
||||
|
||||
// Advertise sets the address to advertise
|
||||
func Advertise(a string) Option {
|
||||
return func(o *Options) {
|
||||
o.Advertise = a
|
||||
}
|
||||
}
|
||||
|
||||
// Peers is a list of peers to connect to
|
||||
func Peers(n ...string) Option {
|
||||
return func(o *Options) {
|
||||
o.Peers = n
|
||||
}
|
||||
}
|
||||
|
||||
// Tunnel sets the network tunnel
|
||||
func Tunnel(t tunnel.Tunnel) Option {
|
||||
return func(o *Options) {
|
||||
o.Tunnel = t
|
||||
}
|
||||
}
|
||||
|
||||
// Router sets the network router
|
||||
func Router(r router.Router) Option {
|
||||
return func(o *Options) {
|
||||
o.Router = r
|
||||
}
|
||||
}
|
||||
|
||||
// Proxy sets the network proxy
|
||||
func Proxy(p proxy.Proxy) Option {
|
||||
return func(o *Options) {
|
||||
o.Proxy = p
|
||||
}
|
||||
}
|
||||
|
||||
// Resolver is the network resolver
|
||||
func Resolver(r resolver.Resolver) Option {
|
||||
return func(o *Options) {
|
||||
o.Resolver = r
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultOptions returns network default options
|
||||
func DefaultOptions() Options {
|
||||
return Options{
|
||||
Id: uuid.New().String(),
|
||||
Name: DefaultName,
|
||||
Address: DefaultAddress,
|
||||
Tunnel: tunnel.NewTunnel(),
|
||||
Router: router.DefaultRouter,
|
||||
Proxy: mucp.NewProxy(),
|
||||
Resolver: ®istry.Resolver{},
|
||||
}
|
||||
}
|
151
network/proto/network.micro.go
Normal file
151
network/proto/network.micro.go
Normal file
@ -0,0 +1,151 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: github.com/micro/go-micro/network/proto/network.proto
|
||||
|
||||
package go_micro_network
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
_ "github.com/micro/go-micro/router/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 Network service
|
||||
|
||||
type NetworkService interface {
|
||||
// Returns the entire network graph
|
||||
Graph(ctx context.Context, in *GraphRequest, opts ...client.CallOption) (*GraphResponse, error)
|
||||
// Returns a list of known nodes in the network
|
||||
Nodes(ctx context.Context, in *NodesRequest, opts ...client.CallOption) (*NodesResponse, error)
|
||||
// Returns a list of known routes in the network
|
||||
Routes(ctx context.Context, in *RoutesRequest, opts ...client.CallOption) (*RoutesResponse, error)
|
||||
// Returns a list of known services based on routes
|
||||
Services(ctx context.Context, in *ServicesRequest, opts ...client.CallOption) (*ServicesResponse, error)
|
||||
}
|
||||
|
||||
type networkService struct {
|
||||
c client.Client
|
||||
name string
|
||||
}
|
||||
|
||||
func NewNetworkService(name string, c client.Client) NetworkService {
|
||||
if c == nil {
|
||||
c = client.NewClient()
|
||||
}
|
||||
if len(name) == 0 {
|
||||
name = "go.micro.network"
|
||||
}
|
||||
return &networkService{
|
||||
c: c,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *networkService) Graph(ctx context.Context, in *GraphRequest, opts ...client.CallOption) (*GraphResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Network.Graph", in)
|
||||
out := new(GraphResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *networkService) Nodes(ctx context.Context, in *NodesRequest, opts ...client.CallOption) (*NodesResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Network.Nodes", in)
|
||||
out := new(NodesResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *networkService) Routes(ctx context.Context, in *RoutesRequest, opts ...client.CallOption) (*RoutesResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Network.Routes", in)
|
||||
out := new(RoutesResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *networkService) Services(ctx context.Context, in *ServicesRequest, opts ...client.CallOption) (*ServicesResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Network.Services", in)
|
||||
out := new(ServicesResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for Network service
|
||||
|
||||
type NetworkHandler interface {
|
||||
// Returns the entire network graph
|
||||
Graph(context.Context, *GraphRequest, *GraphResponse) error
|
||||
// Returns a list of known nodes in the network
|
||||
Nodes(context.Context, *NodesRequest, *NodesResponse) error
|
||||
// Returns a list of known routes in the network
|
||||
Routes(context.Context, *RoutesRequest, *RoutesResponse) error
|
||||
// Returns a list of known services based on routes
|
||||
Services(context.Context, *ServicesRequest, *ServicesResponse) error
|
||||
}
|
||||
|
||||
func RegisterNetworkHandler(s server.Server, hdlr NetworkHandler, opts ...server.HandlerOption) error {
|
||||
type network interface {
|
||||
Graph(ctx context.Context, in *GraphRequest, out *GraphResponse) error
|
||||
Nodes(ctx context.Context, in *NodesRequest, out *NodesResponse) error
|
||||
Routes(ctx context.Context, in *RoutesRequest, out *RoutesResponse) error
|
||||
Services(ctx context.Context, in *ServicesRequest, out *ServicesResponse) error
|
||||
}
|
||||
type Network struct {
|
||||
network
|
||||
}
|
||||
h := &networkHandler{hdlr}
|
||||
return s.Handle(s.NewHandler(&Network{h}, opts...))
|
||||
}
|
||||
|
||||
type networkHandler struct {
|
||||
NetworkHandler
|
||||
}
|
||||
|
||||
func (h *networkHandler) Graph(ctx context.Context, in *GraphRequest, out *GraphResponse) error {
|
||||
return h.NetworkHandler.Graph(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *networkHandler) Nodes(ctx context.Context, in *NodesRequest, out *NodesResponse) error {
|
||||
return h.NetworkHandler.Nodes(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *networkHandler) Routes(ctx context.Context, in *RoutesRequest, out *RoutesResponse) error {
|
||||
return h.NetworkHandler.Routes(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *networkHandler) Services(ctx context.Context, in *ServicesRequest, out *ServicesResponse) error {
|
||||
return h.NetworkHandler.Services(ctx, in, out)
|
||||
}
|
735
network/proto/network.pb.go
Normal file
735
network/proto/network.pb.go
Normal file
@ -0,0 +1,735 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: github.com/micro/go-micro/network/proto/network.proto
|
||||
|
||||
package go_micro_network
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
proto1 "github.com/micro/go-micro/router/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
|
||||
|
||||
// PeerRequest requests list of peers
|
||||
type NodesRequest struct {
|
||||
// node topology depth
|
||||
Depth uint32 `protobuf:"varint,1,opt,name=depth,proto3" json:"depth,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *NodesRequest) Reset() { *m = NodesRequest{} }
|
||||
func (m *NodesRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*NodesRequest) ProtoMessage() {}
|
||||
func (*NodesRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{0}
|
||||
}
|
||||
|
||||
func (m *NodesRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_NodesRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *NodesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_NodesRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *NodesRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_NodesRequest.Merge(m, src)
|
||||
}
|
||||
func (m *NodesRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_NodesRequest.Size(m)
|
||||
}
|
||||
func (m *NodesRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_NodesRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_NodesRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *NodesRequest) GetDepth() uint32 {
|
||||
if m != nil {
|
||||
return m.Depth
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// PeerResponse is returned by ListPeers
|
||||
type NodesResponse struct {
|
||||
// return peer topology
|
||||
Nodes []*Node `protobuf:"bytes,1,rep,name=nodes,proto3" json:"nodes,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *NodesResponse) Reset() { *m = NodesResponse{} }
|
||||
func (m *NodesResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*NodesResponse) ProtoMessage() {}
|
||||
func (*NodesResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{1}
|
||||
}
|
||||
|
||||
func (m *NodesResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_NodesResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *NodesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_NodesResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *NodesResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_NodesResponse.Merge(m, src)
|
||||
}
|
||||
func (m *NodesResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_NodesResponse.Size(m)
|
||||
}
|
||||
func (m *NodesResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_NodesResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_NodesResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *NodesResponse) GetNodes() []*Node {
|
||||
if m != nil {
|
||||
return m.Nodes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GraphRequest struct {
|
||||
// node topology depth
|
||||
Depth uint32 `protobuf:"varint,1,opt,name=depth,proto3" json:"depth,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *GraphRequest) Reset() { *m = GraphRequest{} }
|
||||
func (m *GraphRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*GraphRequest) ProtoMessage() {}
|
||||
func (*GraphRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{2}
|
||||
}
|
||||
|
||||
func (m *GraphRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_GraphRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *GraphRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_GraphRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *GraphRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_GraphRequest.Merge(m, src)
|
||||
}
|
||||
func (m *GraphRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_GraphRequest.Size(m)
|
||||
}
|
||||
func (m *GraphRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_GraphRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_GraphRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *GraphRequest) GetDepth() uint32 {
|
||||
if m != nil {
|
||||
return m.Depth
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type GraphResponse struct {
|
||||
Root *Peer `protobuf:"bytes,1,opt,name=root,proto3" json:"root,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *GraphResponse) Reset() { *m = GraphResponse{} }
|
||||
func (m *GraphResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*GraphResponse) ProtoMessage() {}
|
||||
func (*GraphResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{3}
|
||||
}
|
||||
|
||||
func (m *GraphResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_GraphResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *GraphResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_GraphResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *GraphResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_GraphResponse.Merge(m, src)
|
||||
}
|
||||
func (m *GraphResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_GraphResponse.Size(m)
|
||||
}
|
||||
func (m *GraphResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_GraphResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_GraphResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *GraphResponse) GetRoot() *Peer {
|
||||
if m != nil {
|
||||
return m.Root
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RoutesRequest struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *RoutesRequest) Reset() { *m = RoutesRequest{} }
|
||||
func (m *RoutesRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*RoutesRequest) ProtoMessage() {}
|
||||
func (*RoutesRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{4}
|
||||
}
|
||||
|
||||
func (m *RoutesRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_RoutesRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *RoutesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_RoutesRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *RoutesRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_RoutesRequest.Merge(m, src)
|
||||
}
|
||||
func (m *RoutesRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_RoutesRequest.Size(m)
|
||||
}
|
||||
func (m *RoutesRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_RoutesRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_RoutesRequest proto.InternalMessageInfo
|
||||
|
||||
type RoutesResponse struct {
|
||||
Routes []*proto1.Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *RoutesResponse) Reset() { *m = RoutesResponse{} }
|
||||
func (m *RoutesResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*RoutesResponse) ProtoMessage() {}
|
||||
func (*RoutesResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{5}
|
||||
}
|
||||
|
||||
func (m *RoutesResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_RoutesResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *RoutesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_RoutesResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *RoutesResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_RoutesResponse.Merge(m, src)
|
||||
}
|
||||
func (m *RoutesResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_RoutesResponse.Size(m)
|
||||
}
|
||||
func (m *RoutesResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_RoutesResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_RoutesResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *RoutesResponse) GetRoutes() []*proto1.Route {
|
||||
if m != nil {
|
||||
return m.Routes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ServicesRequest struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ServicesRequest) Reset() { *m = ServicesRequest{} }
|
||||
func (m *ServicesRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ServicesRequest) ProtoMessage() {}
|
||||
func (*ServicesRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{6}
|
||||
}
|
||||
|
||||
func (m *ServicesRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ServicesRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ServicesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ServicesRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ServicesRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ServicesRequest.Merge(m, src)
|
||||
}
|
||||
func (m *ServicesRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_ServicesRequest.Size(m)
|
||||
}
|
||||
func (m *ServicesRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ServicesRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ServicesRequest proto.InternalMessageInfo
|
||||
|
||||
type ServicesResponse struct {
|
||||
Services []string `protobuf:"bytes,1,rep,name=services,proto3" json:"services,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ServicesResponse) Reset() { *m = ServicesResponse{} }
|
||||
func (m *ServicesResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ServicesResponse) ProtoMessage() {}
|
||||
func (*ServicesResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{7}
|
||||
}
|
||||
|
||||
func (m *ServicesResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ServicesResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ServicesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ServicesResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ServicesResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ServicesResponse.Merge(m, src)
|
||||
}
|
||||
func (m *ServicesResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_ServicesResponse.Size(m)
|
||||
}
|
||||
func (m *ServicesResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ServicesResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ServicesResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *ServicesResponse) GetServices() []string {
|
||||
if m != nil {
|
||||
return m.Services
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Node is network node
|
||||
type Node struct {
|
||||
// node id
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
// node address
|
||||
Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Node) Reset() { *m = Node{} }
|
||||
func (m *Node) String() string { return proto.CompactTextString(m) }
|
||||
func (*Node) ProtoMessage() {}
|
||||
func (*Node) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{8}
|
||||
}
|
||||
|
||||
func (m *Node) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Node.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Node) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Node.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Node) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Node.Merge(m, src)
|
||||
}
|
||||
func (m *Node) XXX_Size() int {
|
||||
return xxx_messageInfo_Node.Size(m)
|
||||
}
|
||||
func (m *Node) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Node.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Node proto.InternalMessageInfo
|
||||
|
||||
func (m *Node) GetId() string {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Node) GetAddress() string {
|
||||
if m != nil {
|
||||
return m.Address
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Connect is sent when the node connects to the network
|
||||
type Connect struct {
|
||||
// network mode
|
||||
Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Connect) Reset() { *m = Connect{} }
|
||||
func (m *Connect) String() string { return proto.CompactTextString(m) }
|
||||
func (*Connect) ProtoMessage() {}
|
||||
func (*Connect) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{9}
|
||||
}
|
||||
|
||||
func (m *Connect) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Connect.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Connect) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Connect.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Connect) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Connect.Merge(m, src)
|
||||
}
|
||||
func (m *Connect) XXX_Size() int {
|
||||
return xxx_messageInfo_Connect.Size(m)
|
||||
}
|
||||
func (m *Connect) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Connect.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Connect proto.InternalMessageInfo
|
||||
|
||||
func (m *Connect) GetNode() *Node {
|
||||
if m != nil {
|
||||
return m.Node
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close is sent when the node disconnects from the network
|
||||
type Close struct {
|
||||
// network node
|
||||
Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Close) Reset() { *m = Close{} }
|
||||
func (m *Close) String() string { return proto.CompactTextString(m) }
|
||||
func (*Close) ProtoMessage() {}
|
||||
func (*Close) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{10}
|
||||
}
|
||||
|
||||
func (m *Close) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Close.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Close) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Close.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Close) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Close.Merge(m, src)
|
||||
}
|
||||
func (m *Close) XXX_Size() int {
|
||||
return xxx_messageInfo_Close.Size(m)
|
||||
}
|
||||
func (m *Close) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Close.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Close proto.InternalMessageInfo
|
||||
|
||||
func (m *Close) GetNode() *Node {
|
||||
if m != nil {
|
||||
return m.Node
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Peer is used to advertise node peers
|
||||
type Peer struct {
|
||||
// network node
|
||||
Node *Node `protobuf:"bytes,1,opt,name=node,proto3" json:"node,omitempty"`
|
||||
// node peers
|
||||
Peers []*Peer `protobuf:"bytes,2,rep,name=peers,proto3" json:"peers,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Peer) Reset() { *m = Peer{} }
|
||||
func (m *Peer) String() string { return proto.CompactTextString(m) }
|
||||
func (*Peer) ProtoMessage() {}
|
||||
func (*Peer) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_0b7953b26a7c4730, []int{11}
|
||||
}
|
||||
|
||||
func (m *Peer) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Peer.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Peer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Peer.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Peer) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Peer.Merge(m, src)
|
||||
}
|
||||
func (m *Peer) XXX_Size() int {
|
||||
return xxx_messageInfo_Peer.Size(m)
|
||||
}
|
||||
func (m *Peer) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Peer.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Peer proto.InternalMessageInfo
|
||||
|
||||
func (m *Peer) GetNode() *Node {
|
||||
if m != nil {
|
||||
return m.Node
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Peer) GetPeers() []*Peer {
|
||||
if m != nil {
|
||||
return m.Peers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*NodesRequest)(nil), "go.micro.network.NodesRequest")
|
||||
proto.RegisterType((*NodesResponse)(nil), "go.micro.network.NodesResponse")
|
||||
proto.RegisterType((*GraphRequest)(nil), "go.micro.network.GraphRequest")
|
||||
proto.RegisterType((*GraphResponse)(nil), "go.micro.network.GraphResponse")
|
||||
proto.RegisterType((*RoutesRequest)(nil), "go.micro.network.RoutesRequest")
|
||||
proto.RegisterType((*RoutesResponse)(nil), "go.micro.network.RoutesResponse")
|
||||
proto.RegisterType((*ServicesRequest)(nil), "go.micro.network.ServicesRequest")
|
||||
proto.RegisterType((*ServicesResponse)(nil), "go.micro.network.ServicesResponse")
|
||||
proto.RegisterType((*Node)(nil), "go.micro.network.Node")
|
||||
proto.RegisterType((*Connect)(nil), "go.micro.network.Connect")
|
||||
proto.RegisterType((*Close)(nil), "go.micro.network.Close")
|
||||
proto.RegisterType((*Peer)(nil), "go.micro.network.Peer")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("github.com/micro/go-micro/network/proto/network.proto", fileDescriptor_0b7953b26a7c4730)
|
||||
}
|
||||
|
||||
var fileDescriptor_0b7953b26a7c4730 = []byte{
|
||||
// 416 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0x5d, 0x6f, 0xda, 0x30,
|
||||
0x14, 0x86, 0x21, 0x10, 0x3e, 0xce, 0x16, 0x60, 0xd6, 0x34, 0x45, 0xb9, 0xd8, 0x98, 0xb5, 0x0b,
|
||||
0x34, 0x6d, 0x66, 0x02, 0x71, 0x35, 0x4d, 0x9a, 0xc4, 0x45, 0xa5, 0x4a, 0x45, 0x95, 0xf9, 0x03,
|
||||
0x85, 0xc4, 0x82, 0xa8, 0x25, 0x4e, 0x1d, 0xd3, 0xfe, 0xc2, 0xfe, 0xaf, 0xca, 0x1f, 0xe1, 0x33,
|
||||
0x41, 0xed, 0x1d, 0xe7, 0xf0, 0xf8, 0x3d, 0x3e, 0xaf, 0xdf, 0xc0, 0x64, 0x15, 0xcb, 0xf5, 0x76,
|
||||
0x49, 0x42, 0xbe, 0x19, 0x6e, 0xe2, 0x50, 0xf0, 0xe1, 0x8a, 0xff, 0x36, 0x3f, 0x12, 0x26, 0x9f,
|
||||
0xb9, 0xb8, 0x1f, 0xa6, 0x82, 0xcb, 0x5d, 0x45, 0x74, 0x85, 0x7a, 0x2b, 0x4e, 0x34, 0x45, 0x6c,
|
||||
0x3f, 0x18, 0x97, 0x0b, 0x09, 0xbe, 0x95, 0x4c, 0x58, 0x1d, 0x53, 0x18, 0x19, 0xfc, 0x03, 0x3e,
|
||||
0xce, 0x78, 0xc4, 0x32, 0xca, 0x1e, 0xb7, 0x2c, 0x93, 0xe8, 0x33, 0xb8, 0x11, 0x4b, 0xe5, 0xda,
|
||||
0xaf, 0xf6, 0xab, 0x03, 0x8f, 0x9a, 0x02, 0xff, 0x03, 0xcf, 0x52, 0x59, 0xca, 0x93, 0x8c, 0xa1,
|
||||
0x5f, 0xe0, 0x26, 0xaa, 0xe1, 0x57, 0xfb, 0xb5, 0xc1, 0x87, 0xd1, 0x17, 0x72, 0x7a, 0x1b, 0xa2,
|
||||
0x78, 0x6a, 0x20, 0x35, 0xe4, 0x4a, 0x2c, 0xd2, 0xf5, 0xe5, 0x21, 0x7f, 0xc1, 0xb3, 0x94, 0x1d,
|
||||
0xf2, 0x13, 0xea, 0x82, 0x73, 0xa9, 0xa9, 0xc2, 0x19, 0xb7, 0x8c, 0x09, 0xaa, 0x19, 0xdc, 0x05,
|
||||
0x8f, 0xaa, 0xbd, 0xf2, 0x45, 0xf0, 0x7f, 0xe8, 0xe4, 0x0d, 0x2b, 0x47, 0xa0, 0xa1, 0x57, 0x2f,
|
||||
0xb8, 0xb4, 0xb5, 0x44, 0x1f, 0xa0, 0x96, 0xc2, 0x9f, 0xa0, 0x3b, 0x67, 0xe2, 0x29, 0x0e, 0xf7,
|
||||
0xa2, 0x04, 0x7a, 0xfb, 0x96, 0x95, 0x0d, 0xa0, 0x95, 0xd9, 0x9e, 0x16, 0x6e, 0xd3, 0x5d, 0x8d,
|
||||
0xff, 0x40, 0x5d, 0xf9, 0x80, 0x3a, 0xe0, 0xc4, 0x91, 0xde, 0xa3, 0x4d, 0x9d, 0x38, 0x42, 0x3e,
|
||||
0x34, 0x17, 0x51, 0x24, 0x58, 0x96, 0xf9, 0x8e, 0x6e, 0xe6, 0x25, 0x9e, 0x40, 0x73, 0xca, 0x93,
|
||||
0x84, 0x85, 0x52, 0xad, 0xaf, 0xec, 0x2b, 0x5f, 0x5f, 0x5b, 0xac, 0x19, 0x3c, 0x06, 0x77, 0xfa,
|
||||
0xc0, 0x8d, 0x67, 0x6f, 0x3e, 0x74, 0x07, 0x75, 0xe5, 0xe0, 0x7b, 0xce, 0xa8, 0x87, 0x4f, 0x19,
|
||||
0x13, 0xea, 0xde, 0xb5, 0x0b, 0x8f, 0x62, 0xa0, 0xd1, 0x8b, 0x03, 0xcd, 0x99, 0xe9, 0xa3, 0x6b,
|
||||
0x70, 0xf5, 0xf3, 0xa2, 0xaf, 0xe7, 0x67, 0x0e, 0xd3, 0x11, 0x7c, 0x2b, 0xfd, 0xdf, 0x38, 0x8e,
|
||||
0x2b, 0x4a, 0x4b, 0xe7, 0xb1, 0x48, 0xeb, 0x30, 0xce, 0x45, 0x5a, 0x47, 0x41, 0xc6, 0x15, 0x74,
|
||||
0x03, 0x0d, 0x13, 0x14, 0x54, 0x00, 0x1f, 0x65, 0x2a, 0xe8, 0x97, 0x03, 0x3b, 0xb9, 0x39, 0xb4,
|
||||
0xf2, 0x88, 0xa0, 0xef, 0xe7, 0xfc, 0x49, 0xa2, 0x02, 0x7c, 0x09, 0xc9, 0x45, 0x97, 0x0d, 0xfd,
|
||||
0xb1, 0x8e, 0x5f, 0x03, 0x00, 0x00, 0xff, 0xff, 0x3a, 0x63, 0x7a, 0x7b, 0x2c, 0x04, 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
|
||||
|
||||
// NetworkClient is the client API for Network service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type NetworkClient interface {
|
||||
// Returns the entire network graph
|
||||
Graph(ctx context.Context, in *GraphRequest, opts ...grpc.CallOption) (*GraphResponse, error)
|
||||
// Returns a list of known nodes in the network
|
||||
Nodes(ctx context.Context, in *NodesRequest, opts ...grpc.CallOption) (*NodesResponse, error)
|
||||
// Returns a list of known routes in the network
|
||||
Routes(ctx context.Context, in *RoutesRequest, opts ...grpc.CallOption) (*RoutesResponse, error)
|
||||
// Returns a list of known services based on routes
|
||||
Services(ctx context.Context, in *ServicesRequest, opts ...grpc.CallOption) (*ServicesResponse, error)
|
||||
}
|
||||
|
||||
type networkClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewNetworkClient(cc *grpc.ClientConn) NetworkClient {
|
||||
return &networkClient{cc}
|
||||
}
|
||||
|
||||
func (c *networkClient) Graph(ctx context.Context, in *GraphRequest, opts ...grpc.CallOption) (*GraphResponse, error) {
|
||||
out := new(GraphResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.network.Network/Graph", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *networkClient) Nodes(ctx context.Context, in *NodesRequest, opts ...grpc.CallOption) (*NodesResponse, error) {
|
||||
out := new(NodesResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.network.Network/Nodes", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *networkClient) Routes(ctx context.Context, in *RoutesRequest, opts ...grpc.CallOption) (*RoutesResponse, error) {
|
||||
out := new(RoutesResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.network.Network/Routes", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *networkClient) Services(ctx context.Context, in *ServicesRequest, opts ...grpc.CallOption) (*ServicesResponse, error) {
|
||||
out := new(ServicesResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.network.Network/Services", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// NetworkServer is the server API for Network service.
|
||||
type NetworkServer interface {
|
||||
// Returns the entire network graph
|
||||
Graph(context.Context, *GraphRequest) (*GraphResponse, error)
|
||||
// Returns a list of known nodes in the network
|
||||
Nodes(context.Context, *NodesRequest) (*NodesResponse, error)
|
||||
// Returns a list of known routes in the network
|
||||
Routes(context.Context, *RoutesRequest) (*RoutesResponse, error)
|
||||
// Returns a list of known services based on routes
|
||||
Services(context.Context, *ServicesRequest) (*ServicesResponse, error)
|
||||
}
|
||||
|
||||
func RegisterNetworkServer(s *grpc.Server, srv NetworkServer) {
|
||||
s.RegisterService(&_Network_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Network_Graph_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GraphRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(NetworkServer).Graph(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.network.Network/Graph",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(NetworkServer).Graph(ctx, req.(*GraphRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Network_Nodes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(NodesRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(NetworkServer).Nodes(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.network.Network/Nodes",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(NetworkServer).Nodes(ctx, req.(*NodesRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Network_Routes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RoutesRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(NetworkServer).Routes(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.network.Network/Routes",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(NetworkServer).Routes(ctx, req.(*RoutesRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Network_Services_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ServicesRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(NetworkServer).Services(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.network.Network/Services",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(NetworkServer).Services(ctx, req.(*ServicesRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Network_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "go.micro.network.Network",
|
||||
HandlerType: (*NetworkServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Graph",
|
||||
Handler: _Network_Graph_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Nodes",
|
||||
Handler: _Network_Nodes_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Routes",
|
||||
Handler: _Network_Routes_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Services",
|
||||
Handler: _Network_Services_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "github.com/micro/go-micro/network/proto/network.proto",
|
||||
}
|
79
network/proto/network.proto
Normal file
79
network/proto/network.proto
Normal file
@ -0,0 +1,79 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package go.micro.network;
|
||||
|
||||
import "github.com/micro/go-micro/router/proto/router.proto";
|
||||
|
||||
// Network service is usesd to gain visibility into networks
|
||||
service Network {
|
||||
// Returns the entire network graph
|
||||
rpc Graph(GraphRequest) returns (GraphResponse) {};
|
||||
// Returns a list of known nodes in the network
|
||||
rpc Nodes(NodesRequest) returns (NodesResponse) {};
|
||||
// Returns a list of known routes in the network
|
||||
rpc Routes(RoutesRequest) returns (RoutesResponse) {};
|
||||
// Returns a list of known services based on routes
|
||||
rpc Services(ServicesRequest) returns (ServicesResponse) {};
|
||||
}
|
||||
|
||||
// PeerRequest requests list of peers
|
||||
message NodesRequest {
|
||||
// node topology depth
|
||||
uint32 depth = 1;
|
||||
}
|
||||
|
||||
// PeerResponse is returned by ListPeers
|
||||
message NodesResponse {
|
||||
// return peer topology
|
||||
repeated Node nodes = 1;
|
||||
}
|
||||
|
||||
message GraphRequest {
|
||||
// node topology depth
|
||||
uint32 depth = 1;
|
||||
}
|
||||
|
||||
message GraphResponse {
|
||||
Peer root = 1;
|
||||
}
|
||||
|
||||
message RoutesRequest {
|
||||
}
|
||||
|
||||
message RoutesResponse {
|
||||
repeated go.micro.router.Route routes = 1;
|
||||
}
|
||||
|
||||
message ServicesRequest {}
|
||||
|
||||
message ServicesResponse {
|
||||
repeated string services = 1;
|
||||
}
|
||||
|
||||
// Node is network node
|
||||
message Node {
|
||||
// node id
|
||||
string id = 1;
|
||||
// node address
|
||||
string address = 2;
|
||||
}
|
||||
|
||||
// Connect is sent when the node connects to the network
|
||||
message Connect {
|
||||
// network mode
|
||||
Node node = 1;
|
||||
}
|
||||
|
||||
// Close is sent when the node disconnects from the network
|
||||
message Close {
|
||||
// network node
|
||||
Node node = 1;
|
||||
}
|
||||
|
||||
// Peer is used to advertise node peers
|
||||
message Peer {
|
||||
// network node
|
||||
Node node = 1;
|
||||
// node peers
|
||||
repeated Peer peers = 2;
|
||||
}
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/micro/go-micro/network/resolver"
|
||||
)
|
||||
|
||||
// Resolver is a DNS network resolve
|
||||
type Resolver struct{}
|
||||
|
||||
// Resolve assumes ID is a domain name e.g micro.mu
|
||||
|
@ -3,6 +3,7 @@ package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@ -10,17 +11,26 @@ import (
|
||||
"github.com/micro/go-micro/network/resolver"
|
||||
)
|
||||
|
||||
// Resolver is a HTTP network resolver
|
||||
type Resolver struct {
|
||||
// If not set, defaults to http
|
||||
Proto string
|
||||
|
||||
// Path sets the path to lookup. Defaults to /network
|
||||
Path string
|
||||
|
||||
// Host url to use for the query
|
||||
Host string
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Nodes []*resolver.Record `json:"nodes,omitempty"`
|
||||
}
|
||||
|
||||
// Resolve assumes ID is a domain which can be converted to a http://name/network request
|
||||
func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) {
|
||||
proto := "http"
|
||||
proto := "https"
|
||||
host := "micro.mu"
|
||||
path := "/network"
|
||||
|
||||
if len(r.Proto) > 0 {
|
||||
@ -31,29 +41,38 @@ func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) {
|
||||
path = r.Path
|
||||
}
|
||||
|
||||
if len(r.Host) > 0 {
|
||||
host = r.Host
|
||||
}
|
||||
|
||||
uri := &url.URL{
|
||||
Scheme: proto,
|
||||
Path: path,
|
||||
Host: name,
|
||||
Host: host,
|
||||
}
|
||||
q := uri.Query()
|
||||
q.Set("name", name)
|
||||
uri.RawQuery = q.Encode()
|
||||
|
||||
rsp, err := http.Get(uri.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rsp.Body.Close()
|
||||
|
||||
if rsp.StatusCode != 200 {
|
||||
return nil, errors.New("non 200 response")
|
||||
}
|
||||
b, err := ioutil.ReadAll(rsp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// encoding format is assumed to be json
|
||||
var records []*resolver.Record
|
||||
var response *Response
|
||||
|
||||
if err := json.Unmarshal(b, &records); err != nil {
|
||||
if err := json.Unmarshal(b, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return records, nil
|
||||
return response.Nodes, nil
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"github.com/micro/go-micro/registry"
|
||||
)
|
||||
|
||||
// Resolver is a registry network resolver
|
||||
type Resolver struct {
|
||||
// Registry is the registry to use otherwise we use the defaul
|
||||
Registry registry.Registry
|
||||
|
@ -5,7 +5,7 @@ package resolver
|
||||
// via the name to connect to. This is done based on Network.Name().
|
||||
// Before we can be part of any network, we have to connect to it.
|
||||
type Resolver interface {
|
||||
// Resolve returns a list of addresses for an name
|
||||
// Resolve returns a list of addresses for a name
|
||||
Resolve(name string) ([]*Record, error)
|
||||
}
|
||||
|
||||
|
33
network/resolver/static/static.go
Normal file
33
network/resolver/static/static.go
Normal file
@ -0,0 +1,33 @@
|
||||
// Package static is a static resolver
|
||||
package registry
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/network/resolver"
|
||||
)
|
||||
|
||||
// Resolver returns a static list of nodes. In the event the node list
|
||||
// is not present it will return the name of the network passed in.
|
||||
type Resolver struct {
|
||||
// A static list of nodes
|
||||
Nodes []string
|
||||
}
|
||||
|
||||
// Resolve returns the list of nodes
|
||||
func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) {
|
||||
// if there are no nodes just return the name
|
||||
if len(r.Nodes) == 0 {
|
||||
return []*resolver.Record{
|
||||
{Address: name},
|
||||
}, nil
|
||||
}
|
||||
|
||||
var records []*resolver.Record
|
||||
|
||||
for _, node := range r.Nodes {
|
||||
records = append(records, &resolver.Record{
|
||||
Address: node,
|
||||
})
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
125
plugin/default.go
Normal file
125
plugin/default.go
Normal file
@ -0,0 +1,125 @@
|
||||
// Package plugin provides the ability to load plugins
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
pg "plugin"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/micro/go-micro/broker"
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/client/selector"
|
||||
"github.com/micro/go-micro/config/cmd"
|
||||
"github.com/micro/go-micro/registry"
|
||||
"github.com/micro/go-micro/server"
|
||||
"github.com/micro/go-micro/transport"
|
||||
)
|
||||
|
||||
type plugin struct{}
|
||||
|
||||
// Init sets up the plugin
|
||||
func (p *plugin) Init(c *Config) error {
|
||||
switch c.Type {
|
||||
case "broker":
|
||||
pg, ok := c.NewFunc.(func(...broker.Option) broker.Broker)
|
||||
if !ok {
|
||||
return fmt.Errorf("Invalid plugin %s", c.Name)
|
||||
}
|
||||
cmd.DefaultBrokers[c.Name] = pg
|
||||
case "client":
|
||||
pg, ok := c.NewFunc.(func(...client.Option) client.Client)
|
||||
if !ok {
|
||||
return fmt.Errorf("Invalid plugin %s", c.Name)
|
||||
}
|
||||
cmd.DefaultClients[c.Name] = pg
|
||||
case "registry":
|
||||
pg, ok := c.NewFunc.(func(...registry.Option) registry.Registry)
|
||||
if !ok {
|
||||
return fmt.Errorf("Invalid plugin %s", c.Name)
|
||||
}
|
||||
cmd.DefaultRegistries[c.Name] = pg
|
||||
|
||||
case "selector":
|
||||
pg, ok := c.NewFunc.(func(...selector.Option) selector.Selector)
|
||||
if !ok {
|
||||
return fmt.Errorf("Invalid plugin %s", c.Name)
|
||||
}
|
||||
cmd.DefaultSelectors[c.Name] = pg
|
||||
case "server":
|
||||
pg, ok := c.NewFunc.(func(...server.Option) server.Server)
|
||||
if !ok {
|
||||
return fmt.Errorf("Invalid plugin %s", c.Name)
|
||||
}
|
||||
cmd.DefaultServers[c.Name] = pg
|
||||
case "transport":
|
||||
pg, ok := c.NewFunc.(func(...transport.Option) transport.Transport)
|
||||
if !ok {
|
||||
return fmt.Errorf("Invalid plugin %s", c.Name)
|
||||
}
|
||||
cmd.DefaultTransports[c.Name] = pg
|
||||
default:
|
||||
return fmt.Errorf("Unknown plugin type: %s for %s", c.Type, c.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load loads a plugin created with `go build -buildmode=plugin`
|
||||
func (p *plugin) Load(path string) (*Config, error) {
|
||||
plugin, err := pg.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s, err := plugin.Lookup("Plugin")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pl, ok := s.(*Config)
|
||||
if !ok {
|
||||
return nil, errors.New("could not cast Plugin object")
|
||||
}
|
||||
return pl, nil
|
||||
}
|
||||
|
||||
// Generate creates a go file at the specified path.
|
||||
// You must use `go build -buildmode=plugin`to build it.
|
||||
func (p *plugin) Generate(path string, c *Config) error {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
t, err := template.New(c.Name).Parse(tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return t.Execute(f, c)
|
||||
}
|
||||
|
||||
// Build generates a dso plugin using the go command `go build -buildmode=plugin`
|
||||
func (p *plugin) Build(path string, c *Config) error {
|
||||
path = strings.TrimSuffix(path, ".so")
|
||||
|
||||
// create go file in tmp path
|
||||
temp := os.TempDir()
|
||||
base := filepath.Base(path)
|
||||
goFile := filepath.Join(temp, base+".go")
|
||||
|
||||
// generate .go file
|
||||
if err := p.Generate(goFile, c); err != nil {
|
||||
return err
|
||||
}
|
||||
// remove .go file
|
||||
defer os.Remove(goFile)
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil && !os.IsExist(err) {
|
||||
return fmt.Errorf("Failed to create dir %s: %v", filepath.Dir(path), err)
|
||||
}
|
||||
cmd := exec.Command("go", "build", "-buildmode=plugin", "-o", path+".so", goFile)
|
||||
return cmd.Run()
|
||||
}
|
46
plugin/plugin.go
Normal file
46
plugin/plugin.go
Normal file
@ -0,0 +1,46 @@
|
||||
// Package plugin provides the ability to load plugins
|
||||
package plugin
|
||||
|
||||
// Plugin is a plugin loaded from a file
|
||||
type Plugin interface {
|
||||
// Initialise a plugin with the config
|
||||
Init(c *Config) error
|
||||
// Load loads a .so plugin at the given path
|
||||
Load(path string) (*Config, error)
|
||||
// Build a .so plugin with config at the path specified
|
||||
Build(path string, c *Config) error
|
||||
}
|
||||
|
||||
// Config is the plugin config
|
||||
type Config struct {
|
||||
// Name of the plugin e.g rabbitmq
|
||||
Name string
|
||||
// Type of the plugin e.g broker
|
||||
Type string
|
||||
// Path specifies the import path
|
||||
Path string
|
||||
// NewFunc creates an instance of the plugin
|
||||
NewFunc interface{}
|
||||
}
|
||||
|
||||
var (
|
||||
// Default plugin loader
|
||||
DefaultPlugin = NewPlugin()
|
||||
)
|
||||
|
||||
// NewPlugin creates a new plugin interface
|
||||
func NewPlugin() Plugin {
|
||||
return &plugin{}
|
||||
}
|
||||
|
||||
func Build(path string, c *Config) error {
|
||||
return DefaultPlugin.Build(path, c)
|
||||
}
|
||||
|
||||
func Load(path string) (*Config, error) {
|
||||
return DefaultPlugin.Load(path)
|
||||
}
|
||||
|
||||
func Init(c *Config) error {
|
||||
return DefaultPlugin.Init(c)
|
||||
}
|
20
plugin/template.go
Normal file
20
plugin/template.go
Normal file
@ -0,0 +1,20 @@
|
||||
package plugin
|
||||
|
||||
var (
|
||||
tmpl = `
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/plugin"
|
||||
|
||||
"{{.Path}}"
|
||||
)
|
||||
|
||||
var Plugin = plugin.Config{
|
||||
Name: "{{.Name}}",
|
||||
Type: "{{.Type}}",
|
||||
Path: "{{.Path}}",
|
||||
NewFunc: {{.Name}}.{{.NewFunc}},
|
||||
}
|
||||
`
|
||||
)
|
@ -10,6 +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/errors"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
@ -61,6 +62,10 @@ func readLoop(r server.Request, s client.Stream) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proxy) SendRequest(ctx context.Context, req client.Request, rsp client.Response) error {
|
||||
return errors.InternalServerError("go.micro.proxy.grpc", "SendRequest is unsupported")
|
||||
}
|
||||
|
||||
// ServeRequest honours the server.Proxy interface
|
||||
func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error {
|
||||
// set default client
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/errors"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
@ -44,6 +45,10 @@ func getEndpoint(hdr map[string]string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Proxy) SendRequest(ctx context.Context, req client.Request, rsp client.Response) error {
|
||||
return errors.InternalServerError("go.micro.proxy.http", "SendRequest is unsupported")
|
||||
}
|
||||
|
||||
// ServeRequest honours the server.Router interface
|
||||
func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error {
|
||||
if p.Endpoint == "" {
|
||||
|
@ -5,13 +5,16 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
"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/errors"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/router"
|
||||
"github.com/micro/go-micro/server"
|
||||
@ -26,9 +29,12 @@ type Proxy struct {
|
||||
// Endpoint specifies the fixed service endpoint to call.
|
||||
Endpoint string
|
||||
|
||||
// The client to use for outbound requests
|
||||
// The client to use for outbound requests in the local network
|
||||
Client client.Client
|
||||
|
||||
// Links are used for outbound requests not in the local network
|
||||
Links map[string]client.Client
|
||||
|
||||
// The router for routes
|
||||
Router router.Router
|
||||
|
||||
@ -76,7 +82,7 @@ func readLoop(r server.Request, s client.Stream) error {
|
||||
}
|
||||
|
||||
// toNodes returns a list of node addresses from given routes
|
||||
func toNodes(routes map[uint64]router.Route) []string {
|
||||
func toNodes(routes []router.Route) []string {
|
||||
var nodes []string
|
||||
for _, node := range routes {
|
||||
address := node.Address
|
||||
@ -88,37 +94,63 @@ func toNodes(routes map[uint64]router.Route) []string {
|
||||
return nodes
|
||||
}
|
||||
|
||||
func (p *Proxy) getRoute(service string) ([]string, error) {
|
||||
func (p *Proxy) getLink(r router.Route) (client.Client, error) {
|
||||
if r.Link == "local" || len(p.Links) == 0 {
|
||||
return p.Client, nil
|
||||
}
|
||||
l, ok := p.Links[r.Link]
|
||||
if !ok {
|
||||
return nil, errors.InternalServerError("go.micro.proxy", "link not found")
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (p *Proxy) getRoute(service string) ([]router.Route, error) {
|
||||
toSlice := func(r map[uint64]router.Route) []router.Route {
|
||||
var routes []router.Route
|
||||
for _, v := range r {
|
||||
routes = append(routes, v)
|
||||
}
|
||||
|
||||
// sort the routes in order of metric
|
||||
sort.Slice(routes, func(i, j int) bool { return routes[i].Metric < routes[j].Metric })
|
||||
|
||||
return routes
|
||||
}
|
||||
|
||||
// lookup the route cache first
|
||||
p.Lock()
|
||||
routes, ok := p.Routes[service]
|
||||
if ok {
|
||||
p.Unlock()
|
||||
return toNodes(routes), nil
|
||||
return toSlice(routes), nil
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// update the proxy cache
|
||||
p.Lock()
|
||||
for _, route := range results {
|
||||
// create if does not exist
|
||||
if _, ok := p.Routes[service]; !ok {
|
||||
p.Routes[service] = make(map[uint64]router.Route)
|
||||
}
|
||||
p.Routes[service][route.Hash()] = route
|
||||
}
|
||||
routes = p.Routes[service]
|
||||
p.Unlock()
|
||||
|
||||
return toNodes(routes), nil
|
||||
return toSlice(routes), nil
|
||||
}
|
||||
|
||||
// manageRouteCache applies action on a given route to Proxy route cache
|
||||
@ -130,9 +162,6 @@ func (p *Proxy) manageRouteCache(route router.Route, action string) error {
|
||||
}
|
||||
p.Routes[route.Service][route.Hash()] = route
|
||||
case "delete":
|
||||
if _, ok := p.Routes[route.Service]; !ok {
|
||||
return fmt.Errorf("route not found")
|
||||
}
|
||||
delete(p.Routes[route.Service], route.Hash())
|
||||
default:
|
||||
return fmt.Errorf("unknown action: %s", action)
|
||||
@ -171,12 +200,31 @@ func (p *Proxy) watchRoutes() {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proxy) SendRequest(ctx context.Context, req client.Request, rsp client.Response) error {
|
||||
return errors.InternalServerError("go.micro.proxy", "SendRequest is unsupported")
|
||||
}
|
||||
|
||||
// ServeRequest honours the server.Router interface
|
||||
func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error {
|
||||
// service name
|
||||
service := req.Service()
|
||||
endpoint := req.Endpoint()
|
||||
// determine if its local routing
|
||||
var local bool
|
||||
// address to call
|
||||
var addresses []string
|
||||
// routes
|
||||
var routes []router.Route
|
||||
// service name to call
|
||||
service := req.Service()
|
||||
// endpoint to call
|
||||
endpoint := req.Endpoint()
|
||||
|
||||
if len(service) == 0 {
|
||||
return errors.BadRequest("go.micro.proxy", "service name is blank")
|
||||
}
|
||||
|
||||
// are we network routing or local routing
|
||||
if len(p.Links) == 0 {
|
||||
local = true
|
||||
}
|
||||
|
||||
// call a specific backend endpoint either by name or address
|
||||
if len(p.Endpoint) > 0 {
|
||||
@ -190,7 +238,7 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server
|
||||
return err
|
||||
}
|
||||
// set the address
|
||||
addresses = addr
|
||||
routes = addr
|
||||
// set the name
|
||||
service = p.Endpoint
|
||||
}
|
||||
@ -201,16 +249,66 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
addresses = addr
|
||||
routes = addr
|
||||
}
|
||||
|
||||
var opts []client.CallOption
|
||||
|
||||
// set address if available
|
||||
// if the address is already set just serve it
|
||||
// TODO: figure it out if we should know to pick a link
|
||||
if len(addresses) > 0 {
|
||||
opts = append(opts, client.WithAddress(addresses...))
|
||||
// serve the normal way
|
||||
return p.serveRequest(ctx, p.Client, service, endpoint, req, rsp, client.WithAddress(addresses...))
|
||||
}
|
||||
|
||||
// there's no links e.g we're local routing then just serve it with addresses
|
||||
if local {
|
||||
var opts []client.CallOption
|
||||
|
||||
// set address if available via routes or specific endpoint
|
||||
if len(routes) > 0 {
|
||||
addresses := toNodes(routes)
|
||||
opts = append(opts, client.WithAddress(addresses...))
|
||||
}
|
||||
|
||||
// serve the normal way
|
||||
return p.serveRequest(ctx, p.Client, service, endpoint, req, rsp, opts...)
|
||||
}
|
||||
|
||||
var gerr error
|
||||
|
||||
// we're routing globally with multiple links
|
||||
// so we need to pick a link per route
|
||||
for _, route := range routes {
|
||||
// pick the link or error out
|
||||
link, err := p.getLink(route)
|
||||
if err != nil {
|
||||
// ok let's try again
|
||||
gerr = err
|
||||
continue
|
||||
}
|
||||
|
||||
// set the address to call
|
||||
addresses := toNodes([]router.Route{route})
|
||||
|
||||
// do the request with the link
|
||||
gerr = p.serveRequest(ctx, link, service, endpoint, req, rsp, client.WithAddress(addresses...))
|
||||
// return on no error since we succeeded
|
||||
if gerr == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// return where the context deadline was exceeded
|
||||
if gerr == context.Canceled || gerr == context.DeadlineExceeded {
|
||||
return err
|
||||
}
|
||||
|
||||
// otherwise attempt to do it all over again
|
||||
}
|
||||
|
||||
// if we got here something went really badly wrong
|
||||
return gerr
|
||||
}
|
||||
|
||||
func (p *Proxy) serveRequest(ctx context.Context, link client.Client, service, endpoint string, req server.Request, rsp server.Response, opts ...client.CallOption) error {
|
||||
// read initial request
|
||||
body, err := req.Read()
|
||||
if err != nil {
|
||||
@ -218,16 +316,33 @@ 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()))
|
||||
creq := link.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 := link.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...)
|
||||
stream, err := link.Stream(ctx, creq, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer stream.Close()
|
||||
|
||||
// create client request read loop
|
||||
// create client request read loop if streaming
|
||||
go readLoop(req, stream)
|
||||
|
||||
// get raw response
|
||||
@ -283,6 +398,7 @@ func NewSingleHostProxy(endpoint string) *Proxy {
|
||||
// NewProxy returns a new proxy which will route based on mucp headers
|
||||
func NewProxy(opts ...options.Option) proxy.Proxy {
|
||||
p := new(Proxy)
|
||||
p.Links = map[string]client.Client{}
|
||||
p.Options = options.NewOptions(opts...)
|
||||
p.Options.Init(options.WithString("mucp"))
|
||||
|
||||
@ -303,6 +419,12 @@ func NewProxy(opts ...options.Option) proxy.Proxy {
|
||||
p.Client = client.DefaultClient
|
||||
}
|
||||
|
||||
// get client
|
||||
links, ok := p.Options.Values().Get("proxy.links")
|
||||
if ok {
|
||||
p.Links = links.(map[string]client.Client)
|
||||
}
|
||||
|
||||
// get router
|
||||
r, ok := p.Options.Values().Get("proxy.router")
|
||||
if ok {
|
||||
@ -319,7 +441,16 @@ func NewProxy(opts ...options.Option) proxy.Proxy {
|
||||
|
||||
// watch router service routes
|
||||
p.errChan = make(chan error, 1)
|
||||
go p.watchRoutes()
|
||||
|
||||
go func() {
|
||||
// continuously attempt to watch routes
|
||||
for {
|
||||
// watch the routes
|
||||
p.watchRoutes()
|
||||
// in case of failure just wait a second
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}()
|
||||
|
||||
return p
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ import (
|
||||
// Proxy can be used as a proxy server for go-micro services
|
||||
type Proxy interface {
|
||||
options.Options
|
||||
// SendRequest honours the client.Router interface
|
||||
SendRequest(context.Context, client.Request, client.Response) error
|
||||
// ServeRequest honours the server.Router interface
|
||||
ServeRequest(context.Context, server.Request, server.Response) error
|
||||
}
|
||||
@ -35,3 +37,20 @@ func WithClient(c client.Client) options.Option {
|
||||
func WithRouter(r router.Router) options.Option {
|
||||
return options.WithValue("proxy.router", r)
|
||||
}
|
||||
|
||||
// WithLink sets a link for outbound requests
|
||||
func WithLink(name string, c client.Client) options.Option {
|
||||
return func(o *options.Values) error {
|
||||
var links map[string]client.Client
|
||||
v, ok := o.Get("proxy.links")
|
||||
if ok {
|
||||
links = v.(map[string]client.Client)
|
||||
} else {
|
||||
links = map[string]client.Client{}
|
||||
}
|
||||
links[name] = c
|
||||
// save the links
|
||||
o.Set("proxy.links", links)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
49
registry/cache/rcache.go
vendored
49
registry/cache/rcache.go
vendored
@ -36,7 +36,13 @@ type cache struct {
|
||||
ttls map[string]time.Time
|
||||
watched map[string]bool
|
||||
|
||||
// used to stop the cache
|
||||
exit chan bool
|
||||
|
||||
// status of the registry
|
||||
// used to hold onto the cache
|
||||
// in failure state
|
||||
status error
|
||||
}
|
||||
|
||||
var (
|
||||
@ -50,6 +56,18 @@ func backoff(attempts int) time.Duration {
|
||||
return time.Duration(math.Pow(10, float64(attempts))) * time.Millisecond
|
||||
}
|
||||
|
||||
func (c *cache) getStatus() error {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
return c.status
|
||||
}
|
||||
|
||||
func (c *cache) setStatus(err error) {
|
||||
c.Lock()
|
||||
c.status = err
|
||||
c.Unlock()
|
||||
}
|
||||
|
||||
// isValid checks if the service is valid
|
||||
func (c *cache) isValid(services []*registry.Service, ttl time.Time) bool {
|
||||
// no services exist
|
||||
@ -81,6 +99,11 @@ func (c *cache) quit() bool {
|
||||
}
|
||||
|
||||
func (c *cache) del(service string) {
|
||||
// don't blow away cache in error state
|
||||
if err := c.getStatus(); err != nil {
|
||||
return
|
||||
}
|
||||
// otherwise delete entries
|
||||
delete(c.cache, service)
|
||||
delete(c.ttls, service)
|
||||
}
|
||||
@ -105,13 +128,26 @@ func (c *cache) get(service string) ([]*registry.Service, error) {
|
||||
}
|
||||
|
||||
// get does the actual request for a service and cache it
|
||||
get := func(service string) ([]*registry.Service, error) {
|
||||
get := func(service string, cached []*registry.Service) ([]*registry.Service, error) {
|
||||
// ask the registry
|
||||
services, err := c.Registry.GetService(service)
|
||||
if err != nil {
|
||||
// check the cache
|
||||
if len(cached) > 0 {
|
||||
// set the error status
|
||||
c.setStatus(err)
|
||||
// return the stale cache
|
||||
return registry.Copy(cached), nil
|
||||
}
|
||||
// otherwise return error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// reset the status
|
||||
if c.getStatus(); err != nil {
|
||||
c.setStatus(nil)
|
||||
}
|
||||
|
||||
// cache results
|
||||
c.Lock()
|
||||
c.set(service, registry.Copy(services))
|
||||
@ -129,7 +165,7 @@ func (c *cache) get(service string) ([]*registry.Service, error) {
|
||||
c.RUnlock()
|
||||
|
||||
// get and return services
|
||||
return get(service)
|
||||
return get(service, services)
|
||||
}
|
||||
|
||||
func (c *cache) set(service string, services []*registry.Service) {
|
||||
@ -283,6 +319,7 @@ func (c *cache) run(service string) {
|
||||
}
|
||||
|
||||
d := backoff(a)
|
||||
c.setStatus(err)
|
||||
|
||||
if a > 3 {
|
||||
log.Log("rcache: ", err, " backing off ", d)
|
||||
@ -305,6 +342,7 @@ func (c *cache) run(service string) {
|
||||
}
|
||||
|
||||
d := backoff(b)
|
||||
c.setStatus(err)
|
||||
|
||||
if b > 3 {
|
||||
log.Log("rcache: ", err, " backing off ", d)
|
||||
@ -348,6 +386,13 @@ func (c *cache) watch(w registry.Watcher) error {
|
||||
close(stop)
|
||||
return err
|
||||
}
|
||||
|
||||
// reset the error status since we succeeded
|
||||
if err := c.getStatus(); err != nil {
|
||||
// reset status
|
||||
c.setStatus(nil)
|
||||
}
|
||||
|
||||
c.update(res)
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ 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"
|
||||
)
|
||||
|
||||
@ -250,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
|
||||
@ -351,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),
|
||||
})
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ func (cw *consulWatcher) serviceHandler(idx uint64, data interface{}) {
|
||||
|
||||
// it's an update rather than creation
|
||||
if len(nodes) > 0 {
|
||||
delService := oldService
|
||||
delService := registry.CopyService(oldService)
|
||||
delService.Nodes = nodes
|
||||
cw.next <- ®istry.Result{Action: "delete", Service: delService}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func TestGossipRegistryBroadcast(t *testing.T) {
|
||||
r1 := newRegistry(Config(mc1), Address("127.0.0.1:54321"))
|
||||
|
||||
mc2 := newMemberlistConfig()
|
||||
r2 := newRegistry(Config(mc2), Address("127.0.0.2:54321"), registry.Addrs("127.0.0.1:54321"))
|
||||
r2 := newRegistry(Config(mc2), Address("127.0.0.1:54322"), registry.Addrs("127.0.0.1:54321"))
|
||||
|
||||
defer r1.(*gossipRegistry).Stop()
|
||||
defer r2.(*gossipRegistry).Stop()
|
||||
@ -100,7 +100,7 @@ func TestGossipRegistryRetry(t *testing.T) {
|
||||
r1 := newRegistry(Config(mc1), Address("127.0.0.1:54321"))
|
||||
|
||||
mc2 := newMemberlistConfig()
|
||||
r2 := newRegistry(Config(mc2), Address("127.0.0.2:54321"), registry.Addrs("127.0.0.1:54321"))
|
||||
r2 := newRegistry(Config(mc2), Address("127.0.0.1:54322"), registry.Addrs("127.0.0.1:54321"))
|
||||
|
||||
defer r1.(*gossipRegistry).Stop()
|
||||
defer r2.(*gossipRegistry).Stop()
|
||||
|
76
registry/handler/handler.go
Normal file
76
registry/handler/handler.go
Normal file
@ -0,0 +1,76 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/errors"
|
||||
"github.com/micro/go-micro/registry"
|
||||
pb "github.com/micro/go-micro/registry/proto"
|
||||
"github.com/micro/go-micro/registry/service"
|
||||
)
|
||||
|
||||
type Registry struct {
|
||||
// internal registry
|
||||
Registry registry.Registry
|
||||
}
|
||||
|
||||
func (r *Registry) GetService(ctx context.Context, req *pb.GetRequest, rsp *pb.GetResponse) error {
|
||||
services, err := r.Registry.GetService(req.Service)
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.registry", err.Error())
|
||||
}
|
||||
for _, srv := range services {
|
||||
rsp.Services = append(rsp.Services, service.ToProto(srv))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Registry) Register(ctx context.Context, req *pb.Service, rsp *pb.EmptyResponse) error {
|
||||
err := r.Registry.Register(service.ToService(req))
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.registry", err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Registry) Deregister(ctx context.Context, req *pb.Service, rsp *pb.EmptyResponse) error {
|
||||
err := r.Registry.Deregister(service.ToService(req))
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.registry", err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Registry) ListServices(ctx context.Context, req *pb.ListRequest, rsp *pb.ListResponse) error {
|
||||
services, err := r.Registry.ListServices()
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.registry", err.Error())
|
||||
}
|
||||
for _, srv := range services {
|
||||
rsp.Services = append(rsp.Services, service.ToProto(srv))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Registry) Watch(ctx context.Context, req *pb.WatchRequest, rsp pb.Registry_WatchStream) error {
|
||||
watcher, err := r.Registry.Watch(registry.WatchService(req.Service))
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.registry", err.Error())
|
||||
}
|
||||
|
||||
for {
|
||||
next, err := watcher.Next()
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.registry", err.Error())
|
||||
}
|
||||
err = rsp.Send(&pb.Result{
|
||||
Action: next.Action,
|
||||
Service: service.ToProto(next.Service),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.registry", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
package mdns
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/registry"
|
||||
)
|
||||
|
||||
@ -9,3 +11,13 @@ import (
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
return registry.NewRegistry(opts...)
|
||||
}
|
||||
|
||||
// Domain sets the mdnsDomain
|
||||
func Domain(d string) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, "mdns.domain", d)
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,11 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/micro/mdns"
|
||||
hash "github.com/mitchellh/hashstructure"
|
||||
)
|
||||
|
||||
var (
|
||||
// use a .micro domain rather than .local
|
||||
mdnsDomain = "micro"
|
||||
)
|
||||
|
||||
type mdnsTxt struct {
|
||||
@ -22,13 +26,14 @@ type mdnsTxt struct {
|
||||
}
|
||||
|
||||
type mdnsEntry struct {
|
||||
hash uint64
|
||||
id string
|
||||
node *mdns.Server
|
||||
}
|
||||
|
||||
type mdnsRegistry struct {
|
||||
opts Options
|
||||
// the mdns domain
|
||||
domain string
|
||||
|
||||
sync.Mutex
|
||||
services map[string][]*mdnsEntry
|
||||
@ -36,11 +41,25 @@ type mdnsRegistry struct {
|
||||
|
||||
func newRegistry(opts ...Option) Registry {
|
||||
options := Options{
|
||||
Context: context.Background(),
|
||||
Timeout: time.Millisecond * 100,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// set the domain
|
||||
domain := mdnsDomain
|
||||
|
||||
d, ok := options.Context.Value("mdns.domain").(string)
|
||||
if ok {
|
||||
domain = d
|
||||
}
|
||||
|
||||
return &mdnsRegistry{
|
||||
opts: options,
|
||||
domain: domain,
|
||||
services: make(map[string][]*mdnsEntry),
|
||||
}
|
||||
}
|
||||
@ -66,7 +85,7 @@ func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error
|
||||
s, err := mdns.NewMDNSService(
|
||||
service.Name,
|
||||
"_services",
|
||||
"",
|
||||
m.domain+".",
|
||||
"",
|
||||
9999,
|
||||
[]net.IP{net.ParseIP("0.0.0.0")},
|
||||
@ -88,13 +107,6 @@ func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error
|
||||
var gerr error
|
||||
|
||||
for _, node := range service.Nodes {
|
||||
// create hash of service; uint64
|
||||
h, err := hash.Hash(node, nil)
|
||||
if err != nil {
|
||||
gerr = err
|
||||
continue
|
||||
}
|
||||
|
||||
var seen bool
|
||||
var e *mdnsEntry
|
||||
|
||||
@ -107,14 +119,11 @@ func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error
|
||||
}
|
||||
|
||||
// already registered, continue
|
||||
if seen && e.hash == h {
|
||||
if seen {
|
||||
continue
|
||||
// hash doesn't match, shutdown
|
||||
} else if seen {
|
||||
e.node.Shutdown()
|
||||
// doesn't exist
|
||||
} else {
|
||||
e = &mdnsEntry{hash: h}
|
||||
e = &mdnsEntry{}
|
||||
}
|
||||
|
||||
txt, err := encode(&mdnsTxt{
|
||||
@ -141,7 +150,7 @@ func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error
|
||||
s, err := mdns.NewMDNSService(
|
||||
node.Id,
|
||||
service.Name,
|
||||
"",
|
||||
m.domain+".",
|
||||
"",
|
||||
port,
|
||||
[]net.IP{net.ParseIP(host)},
|
||||
@ -214,6 +223,8 @@ func (m *mdnsRegistry) GetService(service string) ([]*Service, error) {
|
||||
p.Context, _ = context.WithTimeout(context.Background(), m.opts.Timeout)
|
||||
// set entries channel
|
||||
p.Entries = entries
|
||||
// set the domain
|
||||
p.Domain = m.domain
|
||||
|
||||
go func() {
|
||||
for {
|
||||
@ -223,7 +234,9 @@ func (m *mdnsRegistry) GetService(service string) ([]*Service, error) {
|
||||
if p.Service == "_services" {
|
||||
continue
|
||||
}
|
||||
|
||||
if p.Domain != m.domain {
|
||||
continue
|
||||
}
|
||||
if e.TTL == 0 {
|
||||
continue
|
||||
}
|
||||
@ -288,6 +301,8 @@ func (m *mdnsRegistry) ListServices() ([]*Service, error) {
|
||||
p.Context, _ = context.WithTimeout(context.Background(), m.opts.Timeout)
|
||||
// set entries channel
|
||||
p.Entries = entries
|
||||
// set domain
|
||||
p.Domain = m.domain
|
||||
|
||||
var services []*Service
|
||||
|
||||
@ -298,7 +313,9 @@ func (m *mdnsRegistry) ListServices() ([]*Service, error) {
|
||||
if e.TTL == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(e.Name, p.Domain+".") {
|
||||
continue
|
||||
}
|
||||
name := strings.TrimSuffix(e.Name, "."+p.Service+"."+p.Domain+".")
|
||||
if !serviceMap[name] {
|
||||
serviceMap[name] = true
|
||||
@ -329,9 +346,10 @@ func (m *mdnsRegistry) Watch(opts ...WatchOption) (Watcher, error) {
|
||||
}
|
||||
|
||||
md := &mdnsWatcher{
|
||||
wo: wo,
|
||||
ch: make(chan *mdns.ServiceEntry, 32),
|
||||
exit: make(chan struct{}),
|
||||
wo: wo,
|
||||
ch: make(chan *mdns.ServiceEntry, 32),
|
||||
exit: make(chan struct{}),
|
||||
domain: m.domain,
|
||||
}
|
||||
|
||||
go func() {
|
||||
|
@ -11,6 +11,8 @@ type mdnsWatcher struct {
|
||||
wo WatchOptions
|
||||
ch chan *mdns.ServiceEntry
|
||||
exit chan struct{}
|
||||
// the mdns domain
|
||||
domain string
|
||||
}
|
||||
|
||||
func (m *mdnsWatcher) Next() (*Result, error) {
|
||||
@ -46,13 +48,14 @@ func (m *mdnsWatcher) Next() (*Result, error) {
|
||||
Endpoints: txt.Endpoints,
|
||||
}
|
||||
|
||||
// TODO: don't hardcode .local.
|
||||
if !strings.HasSuffix(e.Name, "."+service.Name+".local.") {
|
||||
// skip anything without the domain we care about
|
||||
suffix := fmt.Sprintf(".%s.%s.", service.Name, m.domain)
|
||||
if !strings.HasSuffix(e.Name, suffix) {
|
||||
continue
|
||||
}
|
||||
|
||||
service.Nodes = append(service.Nodes, &Node{
|
||||
Id: strings.TrimSuffix(e.Name, "."+service.Name+".local."),
|
||||
Id: strings.TrimSuffix(e.Name, suffix),
|
||||
Address: fmt.Sprintf("%s:%d", e.AddrV4.String(), e.Port),
|
||||
Metadata: txt.Metadata,
|
||||
})
|
||||
|
@ -10,6 +10,10 @@ import (
|
||||
"github.com/micro/go-micro/registry"
|
||||
)
|
||||
|
||||
var (
|
||||
timeout = time.Millisecond * 10
|
||||
)
|
||||
|
||||
type Registry struct {
|
||||
options registry.Options
|
||||
|
||||
@ -18,11 +22,28 @@ type Registry struct {
|
||||
Watchers map[string]*Watcher
|
||||
}
|
||||
|
||||
var (
|
||||
timeout = time.Millisecond * 10
|
||||
)
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
options := registry.Options{
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
func (m *Registry) watch(r *registry.Result) {
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
services := getServices(options.Context)
|
||||
if services == nil {
|
||||
services = make(map[string][]*registry.Service)
|
||||
}
|
||||
|
||||
return &Registry{
|
||||
options: options,
|
||||
Services: services,
|
||||
Watchers: make(map[string]*Watcher),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Registry) sendEvent(r *registry.Result) {
|
||||
var watchers []*Watcher
|
||||
|
||||
m.RLock()
|
||||
@ -87,30 +108,55 @@ func (m *Registry) ListServices() ([]*registry.Service, error) {
|
||||
}
|
||||
|
||||
func (m *Registry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
|
||||
go m.watch(®istry.Result{Action: "update", Service: s})
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if service, ok := m.Services[s.Name]; !ok {
|
||||
m.Services[s.Name] = []*registry.Service{s}
|
||||
go m.sendEvent(®istry.Result{Action: "update", Service: s})
|
||||
} else {
|
||||
m.Services[s.Name] = registry.Merge(service, []*registry.Service{s})
|
||||
svcCount := len(service)
|
||||
svcNodeCounts := make(map[string]map[string]int)
|
||||
for _, s := range service {
|
||||
if _, ok := svcNodeCounts[s.Name]; !ok {
|
||||
svcNodeCounts[s.Name] = make(map[string]int)
|
||||
}
|
||||
if _, ok := svcNodeCounts[s.Name][s.Version]; !ok {
|
||||
svcNodeCounts[s.Name][s.Version] = len(s.Nodes)
|
||||
}
|
||||
}
|
||||
// if merged count and original service counts changed we added new version of the service
|
||||
merged := registry.Merge(service, []*registry.Service{s})
|
||||
if len(merged) != svcCount {
|
||||
m.Services[s.Name] = merged
|
||||
go m.sendEvent(®istry.Result{Action: "update", Service: s})
|
||||
return nil
|
||||
}
|
||||
// if the node count for a particular service has changed we added a new node to the service
|
||||
for _, s := range merged {
|
||||
if len(s.Nodes) != svcNodeCounts[s.Name][s.Version] {
|
||||
m.Services[s.Name] = merged
|
||||
go m.sendEvent(®istry.Result{Action: "update", Service: s})
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
m.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Registry) Deregister(s *registry.Service) error {
|
||||
go m.watch(®istry.Result{Action: "delete", Service: s})
|
||||
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
if service, ok := m.Services[s.Name]; ok {
|
||||
go m.sendEvent(®istry.Result{Action: "delete", Service: s})
|
||||
if service := registry.Remove(service, []*registry.Service{s}); len(service) == 0 {
|
||||
delete(m.Services, s.Name)
|
||||
} else {
|
||||
m.Services[s.Name] = service
|
||||
}
|
||||
}
|
||||
m.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -137,24 +183,3 @@ func (m *Registry) Watch(opts ...registry.WatchOption) (registry.Watcher, error)
|
||||
func (m *Registry) String() string {
|
||||
return "memory"
|
||||
}
|
||||
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
options := registry.Options{
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
services := getServices(options.Context)
|
||||
if services == nil {
|
||||
services = make(map[string][]*registry.Service)
|
||||
}
|
||||
|
||||
return &Registry{
|
||||
options: options,
|
||||
Services: services,
|
||||
Watchers: make(map[string]*Watcher),
|
||||
}
|
||||
}
|
||||
|
224
registry/proto/registry.micro.go
Normal file
224
registry/proto/registry.micro.go
Normal file
@ -0,0 +1,224 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: registry.proto
|
||||
|
||||
package go_micro_registry
|
||||
|
||||
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 Registry service
|
||||
|
||||
type RegistryService interface {
|
||||
GetService(ctx context.Context, in *GetRequest, opts ...client.CallOption) (*GetResponse, error)
|
||||
Register(ctx context.Context, in *Service, opts ...client.CallOption) (*EmptyResponse, error)
|
||||
Deregister(ctx context.Context, in *Service, opts ...client.CallOption) (*EmptyResponse, error)
|
||||
ListServices(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error)
|
||||
Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Registry_WatchService, error)
|
||||
}
|
||||
|
||||
type registryService struct {
|
||||
c client.Client
|
||||
name string
|
||||
}
|
||||
|
||||
func NewRegistryService(name string, c client.Client) RegistryService {
|
||||
if c == nil {
|
||||
c = client.NewClient()
|
||||
}
|
||||
if len(name) == 0 {
|
||||
name = "go.micro.registry"
|
||||
}
|
||||
return ®istryService{
|
||||
c: c,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *registryService) GetService(ctx context.Context, in *GetRequest, opts ...client.CallOption) (*GetResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Registry.GetService", in)
|
||||
out := new(GetResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *registryService) Register(ctx context.Context, in *Service, opts ...client.CallOption) (*EmptyResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Registry.Register", in)
|
||||
out := new(EmptyResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *registryService) Deregister(ctx context.Context, in *Service, opts ...client.CallOption) (*EmptyResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Registry.Deregister", in)
|
||||
out := new(EmptyResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *registryService) ListServices(ctx context.Context, in *ListRequest, opts ...client.CallOption) (*ListResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Registry.ListServices", in)
|
||||
out := new(ListResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *registryService) Watch(ctx context.Context, in *WatchRequest, opts ...client.CallOption) (Registry_WatchService, error) {
|
||||
req := c.c.NewRequest(c.name, "Registry.Watch", &WatchRequest{})
|
||||
stream, err := c.c.Stream(ctx, req, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := stream.Send(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ®istryServiceWatch{stream}, nil
|
||||
}
|
||||
|
||||
type Registry_WatchService interface {
|
||||
SendMsg(interface{}) error
|
||||
RecvMsg(interface{}) error
|
||||
Close() error
|
||||
Recv() (*Result, error)
|
||||
}
|
||||
|
||||
type registryServiceWatch struct {
|
||||
stream client.Stream
|
||||
}
|
||||
|
||||
func (x *registryServiceWatch) Close() error {
|
||||
return x.stream.Close()
|
||||
}
|
||||
|
||||
func (x *registryServiceWatch) SendMsg(m interface{}) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (x *registryServiceWatch) RecvMsg(m interface{}) error {
|
||||
return x.stream.Recv(m)
|
||||
}
|
||||
|
||||
func (x *registryServiceWatch) Recv() (*Result, error) {
|
||||
m := new(Result)
|
||||
err := x.stream.Recv(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Server API for Registry service
|
||||
|
||||
type RegistryHandler interface {
|
||||
GetService(context.Context, *GetRequest, *GetResponse) error
|
||||
Register(context.Context, *Service, *EmptyResponse) error
|
||||
Deregister(context.Context, *Service, *EmptyResponse) error
|
||||
ListServices(context.Context, *ListRequest, *ListResponse) error
|
||||
Watch(context.Context, *WatchRequest, Registry_WatchStream) error
|
||||
}
|
||||
|
||||
func RegisterRegistryHandler(s server.Server, hdlr RegistryHandler, opts ...server.HandlerOption) error {
|
||||
type registry interface {
|
||||
GetService(ctx context.Context, in *GetRequest, out *GetResponse) error
|
||||
Register(ctx context.Context, in *Service, out *EmptyResponse) error
|
||||
Deregister(ctx context.Context, in *Service, out *EmptyResponse) error
|
||||
ListServices(ctx context.Context, in *ListRequest, out *ListResponse) error
|
||||
Watch(ctx context.Context, stream server.Stream) error
|
||||
}
|
||||
type Registry struct {
|
||||
registry
|
||||
}
|
||||
h := ®istryHandler{hdlr}
|
||||
return s.Handle(s.NewHandler(&Registry{h}, opts...))
|
||||
}
|
||||
|
||||
type registryHandler struct {
|
||||
RegistryHandler
|
||||
}
|
||||
|
||||
func (h *registryHandler) GetService(ctx context.Context, in *GetRequest, out *GetResponse) error {
|
||||
return h.RegistryHandler.GetService(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *registryHandler) Register(ctx context.Context, in *Service, out *EmptyResponse) error {
|
||||
return h.RegistryHandler.Register(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *registryHandler) Deregister(ctx context.Context, in *Service, out *EmptyResponse) error {
|
||||
return h.RegistryHandler.Deregister(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *registryHandler) ListServices(ctx context.Context, in *ListRequest, out *ListResponse) error {
|
||||
return h.RegistryHandler.ListServices(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *registryHandler) Watch(ctx context.Context, stream server.Stream) error {
|
||||
m := new(WatchRequest)
|
||||
if err := stream.Recv(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return h.RegistryHandler.Watch(ctx, m, ®istryWatchStream{stream})
|
||||
}
|
||||
|
||||
type Registry_WatchStream interface {
|
||||
SendMsg(interface{}) error
|
||||
RecvMsg(interface{}) error
|
||||
Close() error
|
||||
Send(*Result) error
|
||||
}
|
||||
|
||||
type registryWatchStream struct {
|
||||
stream server.Stream
|
||||
}
|
||||
|
||||
func (x *registryWatchStream) Close() error {
|
||||
return x.stream.Close()
|
||||
}
|
||||
|
||||
func (x *registryWatchStream) SendMsg(m interface{}) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (x *registryWatchStream) RecvMsg(m interface{}) error {
|
||||
return x.stream.Recv(m)
|
||||
}
|
||||
|
||||
func (x *registryWatchStream) Send(m *Result) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
714
registry/proto/registry.pb.go
Normal file
714
registry/proto/registry.pb.go
Normal file
@ -0,0 +1,714 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: registry.proto
|
||||
|
||||
package go_micro_registry
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// EventType defines the type of event
|
||||
type EventType int32
|
||||
|
||||
const (
|
||||
EventType_Create EventType = 0
|
||||
EventType_Delete EventType = 1
|
||||
EventType_Update EventType = 2
|
||||
)
|
||||
|
||||
var EventType_name = map[int32]string{
|
||||
0: "Create",
|
||||
1: "Delete",
|
||||
2: "Update",
|
||||
}
|
||||
|
||||
var EventType_value = map[string]int32{
|
||||
"Create": 0,
|
||||
"Delete": 1,
|
||||
"Update": 2,
|
||||
}
|
||||
|
||||
func (x EventType) String() string {
|
||||
return proto.EnumName(EventType_name, int32(x))
|
||||
}
|
||||
|
||||
func (EventType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_41af05d40a615591, []int{0}
|
||||
}
|
||||
|
||||
// Service represents a go-micro service
|
||||
type Service struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
|
||||
Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Endpoints []*Endpoint `protobuf:"bytes,4,rep,name=endpoints,proto3" json:"endpoints,omitempty"`
|
||||
Nodes []*Node `protobuf:"bytes,5,rep,name=nodes,proto3" json:"nodes,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Service) Reset() { *m = Service{} }
|
||||
func (m *Service) String() string { return proto.CompactTextString(m) }
|
||||
func (*Service) ProtoMessage() {}
|
||||
func (*Service) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_41af05d40a615591, []int{0}
|
||||
}
|
||||
|
||||
func (m *Service) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Service.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Service) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Service.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Service) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Service.Merge(m, src)
|
||||
}
|
||||
func (m *Service) XXX_Size() int {
|
||||
return xxx_messageInfo_Service.Size(m)
|
||||
}
|
||||
func (m *Service) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Service.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Service proto.InternalMessageInfo
|
||||
|
||||
func (m *Service) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Service) GetVersion() string {
|
||||
if m != nil {
|
||||
return m.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Service) GetMetadata() map[string]string {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Service) GetEndpoints() []*Endpoint {
|
||||
if m != nil {
|
||||
return m.Endpoints
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Service) GetNodes() []*Node {
|
||||
if m != nil {
|
||||
return m.Nodes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Node represents the node the service is on
|
||||
type Node struct {
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Address string `protobuf:"bytes,2,opt,name=address,proto3" json:"address,omitempty"`
|
||||
Port int64 `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"`
|
||||
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Node) Reset() { *m = Node{} }
|
||||
func (m *Node) String() string { return proto.CompactTextString(m) }
|
||||
func (*Node) ProtoMessage() {}
|
||||
func (*Node) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_41af05d40a615591, []int{1}
|
||||
}
|
||||
|
||||
func (m *Node) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Node.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Node) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Node.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Node) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Node.Merge(m, src)
|
||||
}
|
||||
func (m *Node) XXX_Size() int {
|
||||
return xxx_messageInfo_Node.Size(m)
|
||||
}
|
||||
func (m *Node) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Node.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Node proto.InternalMessageInfo
|
||||
|
||||
func (m *Node) GetId() string {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Node) GetAddress() string {
|
||||
if m != nil {
|
||||
return m.Address
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Node) GetPort() int64 {
|
||||
if m != nil {
|
||||
return m.Port
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Node) GetMetadata() map[string]string {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Endpoint is a endpoint provided by a service
|
||||
type Endpoint struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Request *Value `protobuf:"bytes,2,opt,name=request,proto3" json:"request,omitempty"`
|
||||
Response *Value `protobuf:"bytes,3,opt,name=response,proto3" json:"response,omitempty"`
|
||||
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Endpoint) Reset() { *m = Endpoint{} }
|
||||
func (m *Endpoint) String() string { return proto.CompactTextString(m) }
|
||||
func (*Endpoint) ProtoMessage() {}
|
||||
func (*Endpoint) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_41af05d40a615591, []int{2}
|
||||
}
|
||||
|
||||
func (m *Endpoint) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Endpoint.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Endpoint) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Endpoint.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Endpoint) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Endpoint.Merge(m, src)
|
||||
}
|
||||
func (m *Endpoint) XXX_Size() int {
|
||||
return xxx_messageInfo_Endpoint.Size(m)
|
||||
}
|
||||
func (m *Endpoint) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Endpoint.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Endpoint proto.InternalMessageInfo
|
||||
|
||||
func (m *Endpoint) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Endpoint) GetRequest() *Value {
|
||||
if m != nil {
|
||||
return m.Request
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Endpoint) GetResponse() *Value {
|
||||
if m != nil {
|
||||
return m.Response
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Endpoint) GetMetadata() map[string]string {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value is an opaque value for a request or response
|
||||
type Value struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Values []*Value `protobuf:"bytes,3,rep,name=values,proto3" json:"values,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Value) Reset() { *m = Value{} }
|
||||
func (m *Value) String() string { return proto.CompactTextString(m) }
|
||||
func (*Value) ProtoMessage() {}
|
||||
func (*Value) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_41af05d40a615591, []int{3}
|
||||
}
|
||||
|
||||
func (m *Value) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Value.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Value) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Value.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Value) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Value.Merge(m, src)
|
||||
}
|
||||
func (m *Value) XXX_Size() int {
|
||||
return xxx_messageInfo_Value.Size(m)
|
||||
}
|
||||
func (m *Value) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Value.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Value proto.InternalMessageInfo
|
||||
|
||||
func (m *Value) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Value) GetType() string {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Value) GetValues() []*Value {
|
||||
if m != nil {
|
||||
return m.Values
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Result is returns by the watcher
|
||||
type Result struct {
|
||||
Action string `protobuf:"bytes,1,opt,name=action,proto3" json:"action,omitempty"`
|
||||
Service *Service `protobuf:"bytes,2,opt,name=service,proto3" json:"service,omitempty"`
|
||||
Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Result) Reset() { *m = Result{} }
|
||||
func (m *Result) String() string { return proto.CompactTextString(m) }
|
||||
func (*Result) ProtoMessage() {}
|
||||
func (*Result) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_41af05d40a615591, []int{4}
|
||||
}
|
||||
|
||||
func (m *Result) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Result.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Result) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Result.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Result) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Result.Merge(m, src)
|
||||
}
|
||||
func (m *Result) XXX_Size() int {
|
||||
return xxx_messageInfo_Result.Size(m)
|
||||
}
|
||||
func (m *Result) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Result.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Result proto.InternalMessageInfo
|
||||
|
||||
func (m *Result) GetAction() string {
|
||||
if m != nil {
|
||||
return m.Action
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Result) GetService() *Service {
|
||||
if m != nil {
|
||||
return m.Service
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Result) GetTimestamp() int64 {
|
||||
if m != nil {
|
||||
return m.Timestamp
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type EmptyResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *EmptyResponse) Reset() { *m = EmptyResponse{} }
|
||||
func (m *EmptyResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*EmptyResponse) ProtoMessage() {}
|
||||
func (*EmptyResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_41af05d40a615591, []int{5}
|
||||
}
|
||||
|
||||
func (m *EmptyResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_EmptyResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *EmptyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_EmptyResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *EmptyResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_EmptyResponse.Merge(m, src)
|
||||
}
|
||||
func (m *EmptyResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_EmptyResponse.Size(m)
|
||||
}
|
||||
func (m *EmptyResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_EmptyResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_EmptyResponse proto.InternalMessageInfo
|
||||
|
||||
type GetRequest struct {
|
||||
Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *GetRequest) Reset() { *m = GetRequest{} }
|
||||
func (m *GetRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetRequest) ProtoMessage() {}
|
||||
func (*GetRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_41af05d40a615591, []int{6}
|
||||
}
|
||||
|
||||
func (m *GetRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_GetRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *GetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_GetRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *GetRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_GetRequest.Merge(m, src)
|
||||
}
|
||||
func (m *GetRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_GetRequest.Size(m)
|
||||
}
|
||||
func (m *GetRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_GetRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_GetRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *GetRequest) GetService() string {
|
||||
if m != nil {
|
||||
return m.Service
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type GetResponse struct {
|
||||
Services []*Service `protobuf:"bytes,1,rep,name=services,proto3" json:"services,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *GetResponse) Reset() { *m = GetResponse{} }
|
||||
func (m *GetResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetResponse) ProtoMessage() {}
|
||||
func (*GetResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_41af05d40a615591, []int{7}
|
||||
}
|
||||
|
||||
func (m *GetResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_GetResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *GetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_GetResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *GetResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_GetResponse.Merge(m, src)
|
||||
}
|
||||
func (m *GetResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_GetResponse.Size(m)
|
||||
}
|
||||
func (m *GetResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_GetResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_GetResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *GetResponse) GetServices() []*Service {
|
||||
if m != nil {
|
||||
return m.Services
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListRequest struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ListRequest) Reset() { *m = ListRequest{} }
|
||||
func (m *ListRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListRequest) ProtoMessage() {}
|
||||
func (*ListRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_41af05d40a615591, []int{8}
|
||||
}
|
||||
|
||||
func (m *ListRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ListRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ListRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ListRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ListRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ListRequest.Merge(m, src)
|
||||
}
|
||||
func (m *ListRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_ListRequest.Size(m)
|
||||
}
|
||||
func (m *ListRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ListRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ListRequest proto.InternalMessageInfo
|
||||
|
||||
type ListResponse struct {
|
||||
Services []*Service `protobuf:"bytes,1,rep,name=services,proto3" json:"services,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
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_41af05d40a615591, []int{9}
|
||||
}
|
||||
|
||||
func (m *ListResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ListResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ListResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ListResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ListResponse.Merge(m, src)
|
||||
}
|
||||
func (m *ListResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_ListResponse.Size(m)
|
||||
}
|
||||
func (m *ListResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ListResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ListResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *ListResponse) GetServices() []*Service {
|
||||
if m != nil {
|
||||
return m.Services
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WatchRequest struct {
|
||||
// service is optional
|
||||
Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
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_41af05d40a615591, []int{10}
|
||||
}
|
||||
|
||||
func (m *WatchRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_WatchRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *WatchRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_WatchRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *WatchRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_WatchRequest.Merge(m, src)
|
||||
}
|
||||
func (m *WatchRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_WatchRequest.Size(m)
|
||||
}
|
||||
func (m *WatchRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_WatchRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_WatchRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *WatchRequest) GetService() string {
|
||||
if m != nil {
|
||||
return m.Service
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Event is registry event
|
||||
type Event struct {
|
||||
// Event Id
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
// type of event
|
||||
Type EventType `protobuf:"varint,2,opt,name=type,proto3,enum=go.micro.registry.EventType" json:"type,omitempty"`
|
||||
// unix timestamp of event
|
||||
Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
// service entry
|
||||
Service *Service `protobuf:"bytes,4,opt,name=service,proto3" json:"service,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
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_41af05d40a615591, []int{11}
|
||||
}
|
||||
|
||||
func (m *Event) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Event.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Event) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Event.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Event) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Event.Merge(m, src)
|
||||
}
|
||||
func (m *Event) XXX_Size() int {
|
||||
return xxx_messageInfo_Event.Size(m)
|
||||
}
|
||||
func (m *Event) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Event.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Event proto.InternalMessageInfo
|
||||
|
||||
func (m *Event) GetId() string {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Event) GetType() EventType {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
}
|
||||
return EventType_Create
|
||||
}
|
||||
|
||||
func (m *Event) GetTimestamp() int64 {
|
||||
if m != nil {
|
||||
return m.Timestamp
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Event) GetService() *Service {
|
||||
if m != nil {
|
||||
return m.Service
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("go.micro.registry.EventType", EventType_name, EventType_value)
|
||||
proto.RegisterType((*Service)(nil), "go.micro.registry.Service")
|
||||
proto.RegisterMapType((map[string]string)(nil), "go.micro.registry.Service.MetadataEntry")
|
||||
proto.RegisterType((*Node)(nil), "go.micro.registry.Node")
|
||||
proto.RegisterMapType((map[string]string)(nil), "go.micro.registry.Node.MetadataEntry")
|
||||
proto.RegisterType((*Endpoint)(nil), "go.micro.registry.Endpoint")
|
||||
proto.RegisterMapType((map[string]string)(nil), "go.micro.registry.Endpoint.MetadataEntry")
|
||||
proto.RegisterType((*Value)(nil), "go.micro.registry.Value")
|
||||
proto.RegisterType((*Result)(nil), "go.micro.registry.Result")
|
||||
proto.RegisterType((*EmptyResponse)(nil), "go.micro.registry.EmptyResponse")
|
||||
proto.RegisterType((*GetRequest)(nil), "go.micro.registry.GetRequest")
|
||||
proto.RegisterType((*GetResponse)(nil), "go.micro.registry.GetResponse")
|
||||
proto.RegisterType((*ListRequest)(nil), "go.micro.registry.ListRequest")
|
||||
proto.RegisterType((*ListResponse)(nil), "go.micro.registry.ListResponse")
|
||||
proto.RegisterType((*WatchRequest)(nil), "go.micro.registry.WatchRequest")
|
||||
proto.RegisterType((*Event)(nil), "go.micro.registry.Event")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("registry.proto", fileDescriptor_41af05d40a615591) }
|
||||
|
||||
var fileDescriptor_41af05d40a615591 = []byte{
|
||||
// 632 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xdb, 0x6e, 0xd3, 0x4c,
|
||||
0x10, 0x8e, 0xed, 0x38, 0x87, 0x49, 0xdb, 0xbf, 0xff, 0x08, 0x81, 0x31, 0x05, 0x22, 0x4b, 0xa0,
|
||||
0x80, 0x84, 0xa9, 0x42, 0x85, 0x38, 0x5c, 0x21, 0x62, 0x2a, 0xa1, 0x16, 0x09, 0x73, 0xba, 0x36,
|
||||
0xf1, 0xa8, 0x58, 0xc4, 0x07, 0x76, 0x37, 0x91, 0xfc, 0x0e, 0x48, 0x3c, 0x01, 0x77, 0x3c, 0x0a,
|
||||
0x0f, 0x86, 0xbc, 0x5e, 0x27, 0xa9, 0x62, 0x07, 0xa4, 0xc2, 0xdd, 0x8c, 0xf7, 0x9b, 0x6f, 0x67,
|
||||
0xbe, 0x6f, 0x36, 0x81, 0x3d, 0x46, 0x67, 0x11, 0x17, 0x2c, 0x77, 0x33, 0x96, 0x8a, 0x14, 0xff,
|
||||
0x3f, 0x4b, 0xdd, 0x38, 0x9a, 0xb2, 0xd4, 0xad, 0x0e, 0x9c, 0x1f, 0x3a, 0x74, 0xdf, 0x10, 0x5b,
|
||||
0x44, 0x53, 0x42, 0x84, 0x76, 0x12, 0xc4, 0x64, 0x69, 0x43, 0x6d, 0xd4, 0xf7, 0x65, 0x8c, 0x16,
|
||||
0x74, 0x17, 0xc4, 0x78, 0x94, 0x26, 0x96, 0x2e, 0x3f, 0x57, 0x29, 0x4e, 0xa0, 0x17, 0x93, 0x08,
|
||||
0xc2, 0x40, 0x04, 0x96, 0x31, 0x34, 0x46, 0x83, 0xf1, 0xc8, 0xdd, 0xe0, 0x77, 0x15, 0xb7, 0x7b,
|
||||
0xaa, 0xa0, 0x5e, 0x22, 0x58, 0xee, 0x2f, 0x2b, 0xf1, 0x31, 0xf4, 0x29, 0x09, 0xb3, 0x34, 0x4a,
|
||||
0x04, 0xb7, 0xda, 0x92, 0xe6, 0x5a, 0x0d, 0x8d, 0xa7, 0x30, 0xfe, 0x0a, 0x8d, 0xf7, 0xc0, 0x4c,
|
||||
0xd2, 0x90, 0xb8, 0x65, 0xca, 0xb2, 0x2b, 0x35, 0x65, 0xaf, 0xd2, 0x90, 0xfc, 0x12, 0x65, 0x3f,
|
||||
0x85, 0xdd, 0x73, 0x4d, 0xe0, 0x3e, 0x18, 0x9f, 0x29, 0x57, 0xd3, 0x16, 0x21, 0x5e, 0x02, 0x73,
|
||||
0x11, 0xcc, 0xe6, 0xa4, 0x46, 0x2d, 0x93, 0x27, 0xfa, 0x23, 0xcd, 0xf9, 0xa9, 0x41, 0xbb, 0x20,
|
||||
0xc3, 0x3d, 0xd0, 0xa3, 0x50, 0xd5, 0xe8, 0x51, 0x58, 0xe8, 0x13, 0x84, 0x21, 0x23, 0xce, 0x2b,
|
||||
0x7d, 0x54, 0x5a, 0xa8, 0x99, 0xa5, 0x4c, 0x58, 0xc6, 0x50, 0x1b, 0x19, 0xbe, 0x8c, 0xf1, 0xd9,
|
||||
0x9a, 0x66, 0xe5, 0xb0, 0xb7, 0x1a, 0xba, 0x6e, 0x12, 0xec, 0x62, 0x63, 0x7c, 0xd5, 0xa1, 0x57,
|
||||
0x49, 0x59, 0x6b, 0xf7, 0x18, 0xba, 0x8c, 0xbe, 0xcc, 0x89, 0x0b, 0x59, 0x3c, 0x18, 0x5b, 0x35,
|
||||
0xfd, 0xbd, 0x2f, 0xf8, 0xfc, 0x0a, 0x88, 0x47, 0xd0, 0x63, 0xc4, 0xb3, 0x34, 0xe1, 0x24, 0x87,
|
||||
0xdd, 0x56, 0xb4, 0x44, 0xa2, 0xb7, 0x21, 0xc5, 0x9d, 0x2d, 0xbe, 0xff, 0x1b, 0x39, 0x02, 0x30,
|
||||
0x65, 0x5b, 0xb5, 0x52, 0x20, 0xb4, 0x45, 0x9e, 0x55, 0x55, 0x32, 0xc6, 0x43, 0xe8, 0xc8, 0x6a,
|
||||
0xae, 0x36, 0xbe, 0x79, 0x50, 0x85, 0x73, 0x04, 0x74, 0x7c, 0xe2, 0xf3, 0x99, 0xc0, 0xcb, 0xd0,
|
||||
0x09, 0xa6, 0xa2, 0x78, 0x48, 0xe5, 0x2d, 0x2a, 0xc3, 0x23, 0xe8, 0xf2, 0xf2, 0x91, 0x28, 0xc9,
|
||||
0xed, 0xe6, 0x67, 0xe4, 0x57, 0x50, 0x3c, 0x80, 0xbe, 0x88, 0x62, 0xe2, 0x22, 0x88, 0x33, 0xb5,
|
||||
0x62, 0xab, 0x0f, 0xce, 0x7f, 0xb0, 0xeb, 0xc5, 0x99, 0xc8, 0x7d, 0xa5, 0xb6, 0x73, 0x1b, 0xe0,
|
||||
0x98, 0x84, 0xaf, 0x1c, 0xb3, 0x56, 0x57, 0x96, 0xbd, 0x54, 0xa9, 0xe3, 0xc1, 0x40, 0xe2, 0x94,
|
||||
0x49, 0x0f, 0xa1, 0xa7, 0x4e, 0xb8, 0xa5, 0xc9, 0x89, 0xb7, 0x35, 0xb7, 0xc4, 0x3a, 0xbb, 0x30,
|
||||
0x38, 0x89, 0x78, 0x75, 0x9f, 0xf3, 0x02, 0x76, 0xca, 0xf4, 0x82, 0xb4, 0x23, 0xd8, 0xf9, 0x10,
|
||||
0x88, 0xe9, 0xa7, 0xdf, 0xcf, 0xf1, 0x5d, 0x03, 0xd3, 0x5b, 0x50, 0x22, 0x36, 0x1e, 0xec, 0xe1,
|
||||
0x9a, 0xad, 0x7b, 0xe3, 0x83, 0xba, 0x9d, 0x2b, 0xea, 0xde, 0xe6, 0x19, 0x29, 0xd3, 0xb7, 0x4a,
|
||||
0xbd, 0x6e, 0x5f, 0xfb, 0x8f, 0xed, 0xbb, 0x7b, 0x1f, 0xfa, 0xcb, 0x6b, 0x10, 0xa0, 0xf3, 0x9c,
|
||||
0x51, 0x20, 0x68, 0xbf, 0x55, 0xc4, 0x13, 0x9a, 0x91, 0xa0, 0x7d, 0xad, 0x88, 0xdf, 0x65, 0x61,
|
||||
0xf1, 0x5d, 0x1f, 0x7f, 0x33, 0xa0, 0xe7, 0x2b, 0x3a, 0x3c, 0x95, 0x6e, 0x56, 0x3f, 0xdb, 0xd7,
|
||||
0x6b, 0x2e, 0x5c, 0x99, 0x6d, 0xdf, 0x68, 0x3a, 0x56, 0xab, 0xd1, 0xc2, 0x97, 0x15, 0x35, 0x31,
|
||||
0xdc, 0xd2, 0xbd, 0x3d, 0xac, 0x13, 0xeb, 0xdc, 0x9a, 0xb5, 0xf0, 0x04, 0x60, 0x42, 0xec, 0x6f,
|
||||
0xb1, 0xbd, 0x2e, 0x17, 0x47, 0x95, 0x70, 0xac, 0x9b, 0x65, 0x6d, 0xd1, 0xec, 0x9b, 0x8d, 0xe7,
|
||||
0x4b, 0xca, 0x63, 0x30, 0xe5, 0x0e, 0x61, 0x1d, 0x76, 0x7d, 0xbb, 0xec, 0xab, 0x35, 0x80, 0xf2,
|
||||
0x2d, 0x3b, 0xad, 0x43, 0xed, 0x63, 0x47, 0xfe, 0xa7, 0x3e, 0xf8, 0x15, 0x00, 0x00, 0xff, 0xff,
|
||||
0x08, 0x0e, 0xe4, 0xae, 0x65, 0x07, 0x00, 0x00,
|
||||
}
|
92
registry/proto/registry.proto
Normal file
92
registry/proto/registry.proto
Normal file
@ -0,0 +1,92 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package go.micro.registry;
|
||||
|
||||
service Registry {
|
||||
rpc GetService(GetRequest) returns (GetResponse) {};
|
||||
rpc Register(Service) returns (EmptyResponse) {};
|
||||
rpc Deregister(Service) returns (EmptyResponse) {};
|
||||
rpc ListServices(ListRequest) returns (ListResponse) {};
|
||||
rpc Watch(WatchRequest) returns (stream Result) {};
|
||||
}
|
||||
|
||||
// Service represents a go-micro service
|
||||
message Service {
|
||||
string name = 1;
|
||||
string version = 2;
|
||||
map<string,string> metadata = 3;
|
||||
repeated Endpoint endpoints = 4;
|
||||
repeated Node nodes = 5;
|
||||
}
|
||||
|
||||
// Node represents the node the service is on
|
||||
message Node {
|
||||
string id = 1;
|
||||
string address = 2;
|
||||
int64 port = 3;
|
||||
map<string,string> metadata = 4;
|
||||
}
|
||||
|
||||
// Endpoint is a endpoint provided by a service
|
||||
message Endpoint {
|
||||
string name = 1;
|
||||
Value request = 2;
|
||||
Value response = 3;
|
||||
map<string, string> metadata = 4;
|
||||
}
|
||||
|
||||
// Value is an opaque value for a request or response
|
||||
message Value {
|
||||
string name = 1;
|
||||
string type = 2;
|
||||
repeated Value values = 3;
|
||||
}
|
||||
|
||||
// Result is returns by the watcher
|
||||
message Result {
|
||||
string action = 1; // create, update, delete
|
||||
Service service = 2;
|
||||
int64 timestamp = 3; // unix timestamp
|
||||
}
|
||||
|
||||
message EmptyResponse {}
|
||||
|
||||
message GetRequest {
|
||||
string service = 1;
|
||||
}
|
||||
|
||||
message GetResponse {
|
||||
repeated Service services = 1;
|
||||
}
|
||||
|
||||
message ListRequest {
|
||||
// TODO: filtering
|
||||
}
|
||||
|
||||
message ListResponse {
|
||||
repeated Service services = 1;
|
||||
}
|
||||
|
||||
message WatchRequest {
|
||||
// service is optional
|
||||
string service = 1;
|
||||
}
|
||||
|
||||
// EventType defines the type of event
|
||||
enum EventType {
|
||||
Create = 0;
|
||||
Delete = 1;
|
||||
Update = 2;
|
||||
}
|
||||
|
||||
// Event is registry event
|
||||
message Event {
|
||||
// Event Id
|
||||
string id = 1;
|
||||
// type of event
|
||||
EventType type = 2;
|
||||
// unix timestamp of event
|
||||
int64 timestamp = 3;
|
||||
// service entry
|
||||
Service service = 4;
|
||||
}
|
@ -5,6 +5,15 @@ import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultRegistry = NewRegistry()
|
||||
|
||||
// Not found error when GetService is called
|
||||
ErrNotFound = errors.New("service not found")
|
||||
// Watcher stopped error when watcher is stopped
|
||||
ErrWatcherStopped = errors.New("watcher stopped")
|
||||
)
|
||||
|
||||
// The registry provides an interface for service discovery
|
||||
// and an abstraction over varying implementations
|
||||
// {consul, etcd, zookeeper, ...}
|
||||
@ -25,15 +34,6 @@ type RegisterOption func(*RegisterOptions)
|
||||
|
||||
type WatchOption func(*WatchOptions)
|
||||
|
||||
var (
|
||||
DefaultRegistry = NewRegistry()
|
||||
|
||||
// Not found error when GetService is called
|
||||
ErrNotFound = errors.New("not found")
|
||||
// Watcher stopped error when watcher is stopped
|
||||
ErrWatcherStopped = errors.New("watcher stopped")
|
||||
)
|
||||
|
||||
// Register a service node. Additionally supply options such as TTL.
|
||||
func Register(s *Service, opts ...RegisterOption) error {
|
||||
return DefaultRegistry.Register(s, opts...)
|
||||
|
162
registry/service/service.go
Normal file
162
registry/service/service.go
Normal file
@ -0,0 +1,162 @@
|
||||
// Package service uses the registry service
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/registry"
|
||||
pb "github.com/micro/go-micro/registry/proto"
|
||||
)
|
||||
|
||||
var (
|
||||
// The default service name
|
||||
DefaultService = "go.micro.service"
|
||||
)
|
||||
|
||||
type serviceRegistry struct {
|
||||
opts registry.Options
|
||||
// name of the registry
|
||||
name string
|
||||
// address
|
||||
address []string
|
||||
// client to call registry
|
||||
client pb.RegistryService
|
||||
}
|
||||
|
||||
func (s *serviceRegistry) callOpts() []client.CallOption {
|
||||
var opts []client.CallOption
|
||||
|
||||
// set registry address
|
||||
if len(s.address) > 0 {
|
||||
opts = append(opts, client.WithAddress(s.address...))
|
||||
}
|
||||
|
||||
// set timeout
|
||||
if s.opts.Timeout > time.Duration(0) {
|
||||
opts = append(opts, client.WithRequestTimeout(s.opts.Timeout))
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func (s *serviceRegistry) Init(opts ...registry.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&s.opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *serviceRegistry) Options() registry.Options {
|
||||
return s.opts
|
||||
}
|
||||
|
||||
func (s *serviceRegistry) Register(srv *registry.Service, opts ...registry.RegisterOption) error {
|
||||
var options registry.RegisterOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// register the service
|
||||
_, err := s.client.Register(context.TODO(), ToProto(srv), s.callOpts()...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *serviceRegistry) Deregister(srv *registry.Service) error {
|
||||
// deregister the service
|
||||
_, err := s.client.Deregister(context.TODO(), ToProto(srv), s.callOpts()...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *serviceRegistry) GetService(name string) ([]*registry.Service, error) {
|
||||
rsp, err := s.client.GetService(context.TODO(), &pb.GetRequest{
|
||||
Service: name,
|
||||
}, s.callOpts()...)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var services []*registry.Service
|
||||
for _, service := range rsp.Services {
|
||||
services = append(services, ToService(service))
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (s *serviceRegistry) ListServices() ([]*registry.Service, error) {
|
||||
rsp, err := s.client.ListServices(context.TODO(), &pb.ListRequest{}, s.callOpts()...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var services []*registry.Service
|
||||
for _, service := range rsp.Services {
|
||||
services = append(services, ToService(service))
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (s *serviceRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
|
||||
var options registry.WatchOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
stream, err := s.client.Watch(context.TODO(), &pb.WatchRequest{
|
||||
Service: options.Service,
|
||||
}, s.callOpts()...)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newWatcher(stream), nil
|
||||
}
|
||||
|
||||
func (s *serviceRegistry) String() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
// NewRegistry returns a new registry service client
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
var options registry.Options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// the registry address
|
||||
addrs := options.Addrs
|
||||
|
||||
if len(addrs) == 0 {
|
||||
addrs = []string{"127.0.0.1:8000"}
|
||||
}
|
||||
|
||||
// use mdns as a fall back in case its used
|
||||
mReg := registry.NewRegistry()
|
||||
|
||||
// create new client with mdns
|
||||
cli := client.NewClient(
|
||||
client.Registry(mReg),
|
||||
)
|
||||
|
||||
// service name
|
||||
// TODO: accept option
|
||||
name := DefaultService
|
||||
|
||||
return &serviceRegistry{
|
||||
opts: options,
|
||||
name: name,
|
||||
address: addrs,
|
||||
client: pb.NewRegistryService(name, cli),
|
||||
}
|
||||
}
|
133
registry/service/util.go
Normal file
133
registry/service/util.go
Normal file
@ -0,0 +1,133 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/registry"
|
||||
pb "github.com/micro/go-micro/registry/proto"
|
||||
)
|
||||
|
||||
func values(v []*registry.Value) []*pb.Value {
|
||||
if len(v) == 0 {
|
||||
return []*pb.Value{}
|
||||
}
|
||||
|
||||
var vs []*pb.Value
|
||||
for _, vi := range v {
|
||||
vs = append(vs, &pb.Value{
|
||||
Name: vi.Name,
|
||||
Type: vi.Type,
|
||||
Values: values(vi.Values),
|
||||
})
|
||||
}
|
||||
return vs
|
||||
}
|
||||
|
||||
func toValues(v []*pb.Value) []*registry.Value {
|
||||
if len(v) == 0 {
|
||||
return []*registry.Value{}
|
||||
}
|
||||
|
||||
var vs []*registry.Value
|
||||
for _, vi := range v {
|
||||
vs = append(vs, ®istry.Value{
|
||||
Name: vi.Name,
|
||||
Type: vi.Type,
|
||||
Values: toValues(vi.Values),
|
||||
})
|
||||
}
|
||||
return vs
|
||||
}
|
||||
|
||||
func ToProto(s *registry.Service) *pb.Service {
|
||||
var endpoints []*pb.Endpoint
|
||||
for _, ep := range s.Endpoints {
|
||||
var request, response *pb.Value
|
||||
|
||||
if ep.Request != nil {
|
||||
request = &pb.Value{
|
||||
Name: ep.Request.Name,
|
||||
Type: ep.Request.Type,
|
||||
Values: values(ep.Request.Values),
|
||||
}
|
||||
}
|
||||
|
||||
if ep.Response != nil {
|
||||
response = &pb.Value{
|
||||
Name: ep.Response.Name,
|
||||
Type: ep.Response.Type,
|
||||
Values: values(ep.Response.Values),
|
||||
}
|
||||
}
|
||||
|
||||
endpoints = append(endpoints, &pb.Endpoint{
|
||||
Name: ep.Name,
|
||||
Request: request,
|
||||
Response: response,
|
||||
Metadata: ep.Metadata,
|
||||
})
|
||||
}
|
||||
|
||||
var nodes []*pb.Node
|
||||
|
||||
for _, node := range s.Nodes {
|
||||
nodes = append(nodes, &pb.Node{
|
||||
Id: node.Id,
|
||||
Address: node.Address,
|
||||
Metadata: node.Metadata,
|
||||
})
|
||||
}
|
||||
|
||||
return &pb.Service{
|
||||
Name: s.Name,
|
||||
Version: s.Version,
|
||||
Metadata: s.Metadata,
|
||||
Endpoints: endpoints,
|
||||
Nodes: nodes,
|
||||
}
|
||||
}
|
||||
|
||||
func ToService(s *pb.Service) *registry.Service {
|
||||
var endpoints []*registry.Endpoint
|
||||
for _, ep := range s.Endpoints {
|
||||
var request, response *registry.Value
|
||||
|
||||
if ep.Request != nil {
|
||||
request = ®istry.Value{
|
||||
Name: ep.Request.Name,
|
||||
Type: ep.Request.Type,
|
||||
Values: toValues(ep.Request.Values),
|
||||
}
|
||||
}
|
||||
|
||||
if ep.Response != nil {
|
||||
response = ®istry.Value{
|
||||
Name: ep.Response.Name,
|
||||
Type: ep.Response.Type,
|
||||
Values: toValues(ep.Response.Values),
|
||||
}
|
||||
}
|
||||
|
||||
endpoints = append(endpoints, ®istry.Endpoint{
|
||||
Name: ep.Name,
|
||||
Request: request,
|
||||
Response: response,
|
||||
Metadata: ep.Metadata,
|
||||
})
|
||||
}
|
||||
|
||||
var nodes []*registry.Node
|
||||
for _, node := range s.Nodes {
|
||||
nodes = append(nodes, ®istry.Node{
|
||||
Id: node.Id,
|
||||
Address: node.Address,
|
||||
Metadata: node.Metadata,
|
||||
})
|
||||
}
|
||||
|
||||
return ®istry.Service{
|
||||
Name: s.Name,
|
||||
Version: s.Version,
|
||||
Metadata: s.Metadata,
|
||||
Endpoints: endpoints,
|
||||
Nodes: nodes,
|
||||
}
|
||||
}
|
49
registry/service/watcher.go
Normal file
49
registry/service/watcher.go
Normal file
@ -0,0 +1,49 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/registry"
|
||||
pb "github.com/micro/go-micro/registry/proto"
|
||||
)
|
||||
|
||||
type serviceWatcher struct {
|
||||
stream pb.Registry_WatchService
|
||||
closed chan bool
|
||||
}
|
||||
|
||||
func (s *serviceWatcher) Next() (*registry.Result, error) {
|
||||
for {
|
||||
// check if closed
|
||||
select {
|
||||
case <-s.closed:
|
||||
return nil, registry.ErrWatcherStopped
|
||||
default:
|
||||
}
|
||||
|
||||
r, err := s.stream.Recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ®istry.Result{
|
||||
Action: r.Action,
|
||||
Service: ToService(r.Service),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *serviceWatcher) Stop() {
|
||||
select {
|
||||
case <-s.closed:
|
||||
return
|
||||
default:
|
||||
close(s.closed)
|
||||
s.stream.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func newWatcher(stream pb.Registry_WatchService) registry.Watcher {
|
||||
return &serviceWatcher{
|
||||
stream: stream,
|
||||
closed: make(chan bool),
|
||||
}
|
||||
}
|
@ -48,36 +48,38 @@ func delNodes(old, del []*Node) []*Node {
|
||||
return nodes
|
||||
}
|
||||
|
||||
// CopyService make a copy of service
|
||||
func CopyService(service *Service) *Service {
|
||||
// copy service
|
||||
s := new(Service)
|
||||
*s = *service
|
||||
|
||||
// copy nodes
|
||||
nodes := make([]*Node, len(service.Nodes))
|
||||
for j, node := range service.Nodes {
|
||||
n := new(Node)
|
||||
*n = *node
|
||||
nodes[j] = n
|
||||
}
|
||||
s.Nodes = nodes
|
||||
|
||||
// copy endpoints
|
||||
eps := make([]*Endpoint, len(service.Endpoints))
|
||||
for j, ep := range service.Endpoints {
|
||||
e := new(Endpoint)
|
||||
*e = *ep
|
||||
eps[j] = e
|
||||
}
|
||||
s.Endpoints = eps
|
||||
return s
|
||||
}
|
||||
|
||||
// Copy makes a copy of services
|
||||
func Copy(current []*Service) []*Service {
|
||||
services := make([]*Service, len(current))
|
||||
for i, service := range current {
|
||||
// copy service
|
||||
s := new(Service)
|
||||
*s = *service
|
||||
|
||||
// copy nodes
|
||||
nodes := make([]*Node, len(service.Nodes))
|
||||
for j, node := range service.Nodes {
|
||||
n := new(Node)
|
||||
*n = *node
|
||||
nodes[j] = n
|
||||
}
|
||||
s.Nodes = nodes
|
||||
|
||||
// copy endpoints
|
||||
eps := make([]*Endpoint, len(service.Endpoints))
|
||||
for j, ep := range service.Endpoints {
|
||||
e := new(Endpoint)
|
||||
*e = *ep
|
||||
eps[j] = e
|
||||
}
|
||||
s.Endpoints = eps
|
||||
|
||||
// append service
|
||||
services[i] = s
|
||||
services[i] = CopyService(service)
|
||||
}
|
||||
|
||||
return services
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
package registry
|
||||
|
||||
import "time"
|
||||
|
||||
// Watcher is an interface that returns updates
|
||||
// about services within the registry.
|
||||
type Watcher interface {
|
||||
@ -14,3 +16,41 @@ type Result struct {
|
||||
Action string
|
||||
Service *Service
|
||||
}
|
||||
|
||||
// EventType defines registry event type
|
||||
type EventType int
|
||||
|
||||
const (
|
||||
// Create is emitted when a new service is registered
|
||||
Create EventType = iota
|
||||
// Delete is emitted when an existing service is deregsitered
|
||||
Delete
|
||||
// Update is emitted when an existing servicec is updated
|
||||
Update
|
||||
)
|
||||
|
||||
// String returns human readable event type
|
||||
func (t EventType) String() string {
|
||||
switch t {
|
||||
case Create:
|
||||
return "create"
|
||||
case Delete:
|
||||
return "delete"
|
||||
case Update:
|
||||
return "update"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
// Event is registry event
|
||||
type Event struct {
|
||||
// Id is registry id
|
||||
Id string
|
||||
// Type defines type of event
|
||||
Type EventType
|
||||
// Timestamp is event timestamp
|
||||
Timestamp time.Time
|
||||
// Service is registry service
|
||||
Service *Service
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/registry"
|
||||
"github.com/micro/go-micro/util/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -43,10 +44,9 @@ var (
|
||||
// router implements default router
|
||||
type router struct {
|
||||
sync.RWMutex
|
||||
// embed the table
|
||||
table *table
|
||||
opts Options
|
||||
options Options
|
||||
status Status
|
||||
table *table
|
||||
exit chan struct{}
|
||||
errChan chan error
|
||||
eventChan chan *Event
|
||||
@ -67,33 +67,41 @@ func newRouter(opts ...Option) Router {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
r := &router{
|
||||
// set initial status to Stopped
|
||||
status := Status{Code: Stopped, Error: nil}
|
||||
|
||||
return &router{
|
||||
options: options,
|
||||
status: status,
|
||||
table: newTable(),
|
||||
opts: options,
|
||||
status: Status{Code: Stopped, Error: nil},
|
||||
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)
|
||||
o(&r.options)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Options returns router options
|
||||
func (r *router) Options() Options {
|
||||
return r.opts
|
||||
r.Lock()
|
||||
options := r.options
|
||||
r.Unlock()
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
// Table returns routing table
|
||||
func (r *router) Table() Table {
|
||||
return r.table
|
||||
}
|
||||
@ -105,16 +113,19 @@ func (r *router) manageRoute(route Route, action string) error {
|
||||
if err := r.table.Create(route); err != nil && err != ErrDuplicateRoute {
|
||||
return fmt.Errorf("failed adding route for service %s: %s", route.Service, err)
|
||||
}
|
||||
case "update":
|
||||
if err := r.table.Update(route); err != nil && err != ErrDuplicateRoute {
|
||||
return fmt.Errorf("failed updating route for service %s: %s", route.Service, err)
|
||||
}
|
||||
case "delete":
|
||||
if err := r.table.Delete(route); err != nil && err != ErrRouteNotFound {
|
||||
return fmt.Errorf("failed deleting route for service %s: %s", route.Service, err)
|
||||
}
|
||||
case "update":
|
||||
if err := r.table.Update(route); err != nil {
|
||||
return fmt.Errorf("failed updating route for service %s: %s", route.Service, err)
|
||||
}
|
||||
case "solicit":
|
||||
// nothing to do here
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("failed to manage route for service %s. Unknown action: %s", route.Service, action)
|
||||
return fmt.Errorf("failed to manage route for service %s: unknown action %s", route.Service, action)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -132,7 +143,8 @@ func (r *router) manageServiceRoutes(service *registry.Service, action string) e
|
||||
Service: service.Name,
|
||||
Address: node.Address,
|
||||
Gateway: "",
|
||||
Network: r.opts.Network,
|
||||
Network: r.options.Network,
|
||||
Router: r.options.Id,
|
||||
Link: DefaultLink,
|
||||
Metric: DefaultLocalMetric,
|
||||
}
|
||||
@ -174,10 +186,6 @@ func (r *router) manageRegistryRoutes(reg registry.Registry, action string) erro
|
||||
// watchRegistry watches registry and updates routing table based on the received events.
|
||||
// It returns error if either the registry watcher fails with error or if the routing table update fails.
|
||||
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() {
|
||||
@ -186,6 +194,9 @@ func (r *router) watchRegistry(w registry.Watcher) error {
|
||||
r.wg.Done()
|
||||
}()
|
||||
|
||||
// wait in the background for the router to stop
|
||||
// when the router stops, stop the watcher and exit
|
||||
r.wg.Add(1)
|
||||
go func() {
|
||||
defer w.Stop()
|
||||
|
||||
@ -219,9 +230,6 @@ func (r *router) watchRegistry(w registry.Watcher) error {
|
||||
// watchTable watches routing table entries and either adds or deletes locally registered service to/from network registry
|
||||
// It returns error if the locally registered services either fails to be added/deleted to/from network registry.
|
||||
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() {
|
||||
@ -230,6 +238,9 @@ func (r *router) watchTable(w Watcher) error {
|
||||
r.wg.Done()
|
||||
}()
|
||||
|
||||
// wait in the background for the router to stop
|
||||
// when the router stops, stop the watcher and exit
|
||||
r.wg.Add(1)
|
||||
go func() {
|
||||
defer w.Stop()
|
||||
|
||||
@ -272,13 +283,14 @@ func (r *router) publishAdvert(advType AdvertType, events []*Event) {
|
||||
defer r.advertWg.Done()
|
||||
|
||||
a := &Advert{
|
||||
Id: r.opts.Id,
|
||||
Id: r.options.Id,
|
||||
Type: advType,
|
||||
TTL: DefaultAdvertTTL,
|
||||
Timestamp: time.Now(),
|
||||
Events: events,
|
||||
}
|
||||
|
||||
log.Debugf("Router publishing advert; %+v", a)
|
||||
r.RLock()
|
||||
for _, sub := range r.subscribers {
|
||||
// check the exit chan first
|
||||
@ -325,6 +337,7 @@ func (r *router) advertiseTable() error {
|
||||
|
||||
// advertise all routes as Update events to subscribers
|
||||
if len(events) > 0 {
|
||||
log.Debugf("Router flushing table with %d events: %s", len(events), r.options.Id)
|
||||
r.advertWg.Add(1)
|
||||
go r.publishAdvert(RouteUpdate, events)
|
||||
}
|
||||
@ -334,9 +347,10 @@ func (r *router) advertiseTable() error {
|
||||
}
|
||||
}
|
||||
|
||||
// routeAdvert contains a list of route events to be advertised
|
||||
// routeAdvert contains a route event to be advertised
|
||||
type routeAdvert struct {
|
||||
events []*Event
|
||||
// event received from routing table
|
||||
event *Event
|
||||
// lastUpdate records the time of the last advert update
|
||||
lastUpdate time.Time
|
||||
// penalty is current advert penalty
|
||||
@ -385,9 +399,11 @@ func (r *router) advertiseEvents() error {
|
||||
// suppress/recover the event based on its penalty level
|
||||
switch {
|
||||
case advert.penalty > AdvertSuppress && !advert.isSuppressed:
|
||||
log.Debugf("Router supressing advert %d for route %s", key, advert.event.Route.Address)
|
||||
advert.isSuppressed = true
|
||||
advert.suppressTime = time.Now()
|
||||
case advert.penalty < AdvertRecover && advert.isSuppressed:
|
||||
log.Debugf("Router recovering advert %d for route %s", key, advert.event.Route.Address)
|
||||
advert.isSuppressed = false
|
||||
}
|
||||
|
||||
@ -400,19 +416,18 @@ func (r *router) advertiseEvents() error {
|
||||
}
|
||||
|
||||
if !advert.isSuppressed {
|
||||
for _, event := range advert.events {
|
||||
e := new(Event)
|
||||
*e = *event
|
||||
events = append(events, e)
|
||||
// delete the advert from the advertMap
|
||||
delete(advertMap, key)
|
||||
}
|
||||
e := new(Event)
|
||||
*e = *(advert.event)
|
||||
events = append(events, e)
|
||||
// delete the advert from the advertMap
|
||||
delete(advertMap, key)
|
||||
}
|
||||
}
|
||||
|
||||
// advertise all Update events to subscribers
|
||||
if len(events) > 0 {
|
||||
r.advertWg.Add(1)
|
||||
log.Debugf("Router publishing %d events", len(events))
|
||||
go r.publishAdvert(RouteUpdate, events)
|
||||
}
|
||||
case e := <-r.eventChan:
|
||||
@ -420,7 +435,7 @@ func (r *router) advertiseEvents() error {
|
||||
if e == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("Router processing table event %s for service %s", e.Type, e.Route.Address)
|
||||
// determine the event penalty
|
||||
var penalty float64
|
||||
switch e.Type {
|
||||
@ -431,13 +446,11 @@ func (r *router) advertiseEvents() error {
|
||||
}
|
||||
|
||||
// check if we have already registered the route
|
||||
// we use the route hash as advertMap key
|
||||
hash := e.Route.Hash()
|
||||
advert, ok := advertMap[hash]
|
||||
if !ok {
|
||||
events := []*Event{e}
|
||||
advert = &routeAdvert{
|
||||
events: events,
|
||||
event: e,
|
||||
penalty: penalty,
|
||||
lastUpdate: time.Now(),
|
||||
}
|
||||
@ -445,17 +458,15 @@ func (r *router) advertiseEvents() error {
|
||||
continue
|
||||
}
|
||||
|
||||
// attempt to squash last two events if possible
|
||||
lastEvent := advert.events[len(advert.events)-1]
|
||||
if lastEvent.Type == e.Type {
|
||||
advert.events[len(advert.events)-1] = e
|
||||
} else {
|
||||
advert.events = append(advert.events, e)
|
||||
// override the route event only if the last event was different
|
||||
if advert.event.Type != e.Type {
|
||||
advert.event = e
|
||||
}
|
||||
|
||||
// update event penalty and recorded timestamp
|
||||
// update event penalty and timestamp
|
||||
advert.lastUpdate = time.Now()
|
||||
advert.penalty += penalty
|
||||
log.Debugf("Router advert %d for route %s event penalty: %f", hash, advert.event.Route.Address, advert.penalty)
|
||||
case <-r.exit:
|
||||
// first wait for the advertiser to finish
|
||||
r.advertWg.Wait()
|
||||
@ -464,100 +475,122 @@ func (r *router) advertiseEvents() error {
|
||||
}
|
||||
}
|
||||
|
||||
// close closes exit channels
|
||||
func (r *router) close() {
|
||||
// notify all goroutines to finish
|
||||
close(r.exit)
|
||||
|
||||
// drain the advertise channel only if advertising
|
||||
if r.status.Code == Advertising {
|
||||
// drain the event channel
|
||||
for range r.eventChan {
|
||||
}
|
||||
|
||||
// close advert subscribers
|
||||
for id, sub := range r.subscribers {
|
||||
// close the channel
|
||||
close(sub)
|
||||
|
||||
// delete the subscriber
|
||||
delete(r.subscribers, id)
|
||||
}
|
||||
}
|
||||
|
||||
// mark the router as Stopped and set its Error to nil
|
||||
r.status = Status{Code: Stopped, Error: nil}
|
||||
}
|
||||
|
||||
// watchErrors watches router errors and takes appropriate actions
|
||||
func (r *router) watchErrors() {
|
||||
var err error
|
||||
|
||||
select {
|
||||
case <-r.exit:
|
||||
return
|
||||
case err = <-r.errChan:
|
||||
}
|
||||
|
||||
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
|
||||
if r.status.Code == Advertising {
|
||||
// drain the event channel
|
||||
for range r.eventChan {
|
||||
}
|
||||
// close all the channels
|
||||
r.close()
|
||||
// set the status error
|
||||
if err != nil {
|
||||
r.status.Error = err
|
||||
}
|
||||
|
||||
// mark the router as Stopped and set its Error to nil
|
||||
r.status = Status{Code: Stopped, Error: nil}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
r.status = Status{Code: Error, Error: err}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// only start if we're stopped
|
||||
if r.status.Code != Stopped {
|
||||
return nil
|
||||
}
|
||||
|
||||
return
|
||||
// add all local service routes into the routing table
|
||||
if err := r.manageRegistryRoutes(r.options.Registry, "create"); err != nil {
|
||||
e := fmt.Errorf("failed adding registry routes: %s", err)
|
||||
r.status = Status{Code: Error, Error: e}
|
||||
return e
|
||||
}
|
||||
|
||||
// add default gateway into routing table
|
||||
if r.options.Gateway != "" {
|
||||
// note, the only non-default value is the gateway
|
||||
route := Route{
|
||||
Service: "*",
|
||||
Address: "*",
|
||||
Gateway: r.options.Gateway,
|
||||
Network: "*",
|
||||
Router: r.options.Id,
|
||||
Link: DefaultLink,
|
||||
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.options.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.
|
||||
@ -569,24 +602,14 @@ func (r *router) Advertise() (<-chan *Advert, error) {
|
||||
|
||||
switch r.status.Code {
|
||||
case Advertising:
|
||||
advertChan := make(chan *Advert)
|
||||
advertChan := make(chan *Advert, 128)
|
||||
r.subscribers[uuid.New().String()] = advertChan
|
||||
return advertChan, nil
|
||||
case Running:
|
||||
// list routing table routes to announce
|
||||
routes, err := r.table.List()
|
||||
// list all the routes and pack them into even slice to advertise
|
||||
events, err := r.flushRouteEvents(Create)
|
||||
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 {
|
||||
event := &Event{
|
||||
Type: Create,
|
||||
Timestamp: time.Now(),
|
||||
Route: route,
|
||||
}
|
||||
events[i] = event
|
||||
return nil, fmt.Errorf("failed to flush routes: %s", err)
|
||||
}
|
||||
|
||||
// create event channels
|
||||
@ -619,7 +642,7 @@ func (r *router) Advertise() (<-chan *Advert, error) {
|
||||
r.status = Status{Code: Advertising, Error: nil}
|
||||
|
||||
// create advert channel
|
||||
advertChan := make(chan *Advert)
|
||||
advertChan := make(chan *Advert, 128)
|
||||
r.subscribers[uuid.New().String()] = advertChan
|
||||
|
||||
return advertChan, nil
|
||||
@ -641,10 +664,18 @@ func (r *router) Process(a *Advert) error {
|
||||
return events[i].Timestamp.Before(events[j].Timestamp)
|
||||
})
|
||||
|
||||
log.Debugf("Router %s processing advert from: %s", r.options.Id, a.Id)
|
||||
|
||||
for _, event := range events {
|
||||
// skip if the router is the origin of this route
|
||||
if event.Route.Router == r.options.Id {
|
||||
log.Debugf("Router skipping processing its own route: %s", r.options.Id)
|
||||
continue
|
||||
}
|
||||
// create a copy of the route
|
||||
route := event.Route
|
||||
action := event.Type
|
||||
log.Debugf("Router %s applying %s from router %s for address: %s", r.options.Id, action, route.Router, route.Address)
|
||||
if err := r.manageRoute(route, fmt.Sprintf("%s", action)); err != nil {
|
||||
return fmt.Errorf("failed applying action %s to routing table: %s", action, err)
|
||||
}
|
||||
@ -653,10 +684,49 @@ func (r *router) Process(a *Advert) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// flushRouteEvents returns a slice of events, one per each route in the routing table
|
||||
func (r *router) flushRouteEvents(evType EventType) ([]*Event, error) {
|
||||
// list all routes
|
||||
routes, err := r.table.List()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed listing routes: %s", err)
|
||||
}
|
||||
|
||||
// build a list of events to advertise
|
||||
events := make([]*Event, len(routes))
|
||||
for i, route := range routes {
|
||||
event := &Event{
|
||||
Type: evType,
|
||||
Timestamp: time.Now(),
|
||||
Route: route,
|
||||
}
|
||||
events[i] = event
|
||||
}
|
||||
|
||||
return events, nil
|
||||
}
|
||||
|
||||
// Solicit advertises all of its routes to the network
|
||||
// It returns error if the router fails to list the routes
|
||||
func (r *router) Solicit() error {
|
||||
events, err := r.flushRouteEvents(Update)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed solicit routes: %s", err)
|
||||
}
|
||||
|
||||
// advertise the routes
|
||||
r.advertWg.Add(1)
|
||||
go r.publishAdvert(RouteUpdate, events)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Lookup routes in the routing table
|
||||
func (r *router) Lookup(q Query) ([]Route, error) {
|
||||
return r.table.Query(q)
|
||||
}
|
||||
|
||||
// Watch routes
|
||||
func (r *router) Watch(opts ...WatchOption) (Watcher, error) {
|
||||
return r.table.Watch(opts...)
|
||||
}
|
||||
@ -675,31 +745,15 @@ func (r *router) Status() Status {
|
||||
// Stop stops the router
|
||||
func (r *router) Stop() error {
|
||||
r.Lock()
|
||||
// only close the channel if the router is running and/or advertising
|
||||
if r.status.Code == Running || r.status.Code == Advertising {
|
||||
// notify all goroutines to finish
|
||||
close(r.exit)
|
||||
defer r.Unlock()
|
||||
|
||||
// drain the advertise channel only if advertising
|
||||
if r.status.Code == Advertising {
|
||||
// drain the event channel
|
||||
for range r.eventChan {
|
||||
}
|
||||
}
|
||||
|
||||
// close advert subscribers
|
||||
for id, sub := range r.subscribers {
|
||||
// close the channel
|
||||
close(sub)
|
||||
|
||||
// delete the subscriber
|
||||
delete(r.subscribers, id)
|
||||
}
|
||||
|
||||
// mark the router as Stopped and set its Error to nil
|
||||
r.status = Status{Code: Stopped, Error: nil}
|
||||
switch r.status.Code {
|
||||
case Stopped, Error:
|
||||
return r.status.Error
|
||||
case Running, Advertising:
|
||||
// close all the channels
|
||||
r.close()
|
||||
}
|
||||
r.Unlock()
|
||||
|
||||
// wait for all goroutines to finish
|
||||
r.wg.Wait()
|
||||
@ -709,5 +763,5 @@ func (r *router) Stop() error {
|
||||
|
||||
// String prints debugging information about router
|
||||
func (r *router) String() string {
|
||||
return "default"
|
||||
return "memory"
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ func (r *Router) Lookup(ctx context.Context, req *pb.LookupRequest, resp *pb.Loo
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Router: route.Router,
|
||||
Link: route.Link,
|
||||
Metric: int64(route.Metric),
|
||||
}
|
||||
@ -44,6 +45,16 @@ func (r *Router) Lookup(ctx context.Context, req *pb.LookupRequest, resp *pb.Loo
|
||||
return nil
|
||||
}
|
||||
|
||||
// Solicit triggers full routing table advertisement
|
||||
func (r *Router) Solicit(ctx context.Context, req *pb.Request, resp *pb.Response) error {
|
||||
if err := r.Router.Solicit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Advertise streams router advertisements
|
||||
func (r *Router) Advertise(ctx context.Context, req *pb.Request, stream pb.Router_AdvertiseStream) error {
|
||||
advertChan, err := r.Router.Advertise()
|
||||
if err != nil {
|
||||
@ -58,6 +69,7 @@ func (r *Router) Advertise(ctx context.Context, req *pb.Request, stream pb.Route
|
||||
Address: event.Route.Address,
|
||||
Gateway: event.Route.Gateway,
|
||||
Network: event.Route.Network,
|
||||
Router: event.Route.Router,
|
||||
Link: event.Route.Link,
|
||||
Metric: int64(event.Route.Metric),
|
||||
}
|
||||
@ -89,6 +101,7 @@ func (r *Router) Advertise(ctx context.Context, req *pb.Request, stream pb.Route
|
||||
return nil
|
||||
}
|
||||
|
||||
// Process processes advertisements
|
||||
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 {
|
||||
@ -97,6 +110,7 @@ func (r *Router) Process(ctx context.Context, req *pb.Advert, rsp *pb.ProcessRes
|
||||
Address: event.Route.Address,
|
||||
Gateway: event.Route.Gateway,
|
||||
Network: event.Route.Network,
|
||||
Router: event.Route.Router,
|
||||
Link: event.Route.Link,
|
||||
Metric: int(event.Route.Metric),
|
||||
}
|
||||
@ -123,6 +137,7 @@ func (r *Router) Process(ctx context.Context, req *pb.Advert, rsp *pb.ProcessRes
|
||||
return nil
|
||||
}
|
||||
|
||||
// Status returns router status
|
||||
func (r *Router) Status(ctx context.Context, req *pb.Request, rsp *pb.StatusResponse) error {
|
||||
status := r.Router.Status()
|
||||
|
||||
@ -149,7 +164,7 @@ func (r *Router) Watch(ctx context.Context, req *pb.WatchRequest, stream pb.Rout
|
||||
for {
|
||||
event, err := watcher.Next()
|
||||
if err == router.ErrWatcherStopped {
|
||||
break
|
||||
return errors.InternalServerError("go.micro.router", "watcher stopped")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@ -161,6 +176,7 @@ func (r *Router) Watch(ctx context.Context, req *pb.WatchRequest, stream pb.Rout
|
||||
Address: event.Route.Address,
|
||||
Gateway: event.Route.Gateway,
|
||||
Network: event.Route.Network,
|
||||
Router: event.Route.Router,
|
||||
Link: event.Route.Link,
|
||||
Metric: int64(event.Route.Metric),
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ func (t *Table) Create(ctx context.Context, route *pb.Route, resp *pb.CreateResp
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Router: route.Router,
|
||||
Link: route.Link,
|
||||
Metric: int(route.Metric),
|
||||
})
|
||||
@ -34,6 +35,7 @@ func (t *Table) Update(ctx context.Context, route *pb.Route, resp *pb.UpdateResp
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Router: route.Router,
|
||||
Link: route.Link,
|
||||
Metric: int(route.Metric),
|
||||
})
|
||||
@ -50,6 +52,7 @@ func (t *Table) Delete(ctx context.Context, route *pb.Route, resp *pb.DeleteResp
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Router: route.Router,
|
||||
Link: route.Link,
|
||||
Metric: int(route.Metric),
|
||||
})
|
||||
@ -74,6 +77,7 @@ func (t *Table) List(ctx context.Context, req *pb.Request, resp *pb.ListResponse
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Router: route.Router,
|
||||
Link: route.Link,
|
||||
Metric: int64(route.Metric),
|
||||
}
|
||||
@ -102,6 +106,7 @@ func (t *Table) Query(ctx context.Context, req *pb.QueryRequest, resp *pb.QueryR
|
||||
Address: route.Address,
|
||||
Gateway: route.Gateway,
|
||||
Network: route.Network,
|
||||
Router: route.Router,
|
||||
Link: route.Link,
|
||||
Metric: int64(route.Metric),
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: micro/go-micro/router/proto/router.proto
|
||||
// source: router.proto
|
||||
|
||||
package go_micro_router
|
||||
|
||||
@ -37,6 +37,7 @@ 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 *Request, opts ...client.CallOption) (Router_AdvertiseService, error)
|
||||
Solicit(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error)
|
||||
Process(ctx context.Context, in *Advert, opts ...client.CallOption) (*ProcessResponse, error)
|
||||
Status(ctx context.Context, in *Request, opts ...client.CallOption) (*StatusResponse, error)
|
||||
}
|
||||
@ -157,6 +158,16 @@ func (x *routerServiceAdvertise) Recv() (*Advert, error) {
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *routerService) Solicit(ctx context.Context, in *Request, opts ...client.CallOption) (*Response, error) {
|
||||
req := c.c.NewRequest(c.name, "Router.Solicit", in)
|
||||
out := new(Response)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *routerService) Process(ctx context.Context, in *Advert, opts ...client.CallOption) (*ProcessResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Router.Process", in)
|
||||
out := new(ProcessResponse)
|
||||
@ -183,6 +194,7 @@ type RouterHandler interface {
|
||||
Lookup(context.Context, *LookupRequest, *LookupResponse) error
|
||||
Watch(context.Context, *WatchRequest, Router_WatchStream) error
|
||||
Advertise(context.Context, *Request, Router_AdvertiseStream) error
|
||||
Solicit(context.Context, *Request, *Response) error
|
||||
Process(context.Context, *Advert, *ProcessResponse) error
|
||||
Status(context.Context, *Request, *StatusResponse) error
|
||||
}
|
||||
@ -192,6 +204,7 @@ func RegisterRouterHandler(s server.Server, hdlr RouterHandler, opts ...server.H
|
||||
Lookup(ctx context.Context, in *LookupRequest, out *LookupResponse) error
|
||||
Watch(ctx context.Context, stream server.Stream) error
|
||||
Advertise(ctx context.Context, stream server.Stream) error
|
||||
Solicit(ctx context.Context, in *Request, out *Response) error
|
||||
Process(ctx context.Context, in *Advert, out *ProcessResponse) error
|
||||
Status(ctx context.Context, in *Request, out *StatusResponse) error
|
||||
}
|
||||
@ -280,6 +293,10 @@ func (x *routerAdvertiseStream) Send(m *Advert) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (h *routerHandler) Solicit(ctx context.Context, in *Request, out *Response) error {
|
||||
return h.RouterHandler.Solicit(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *routerHandler) Process(ctx context.Context, in *Advert, out *ProcessResponse) error {
|
||||
return h.RouterHandler.Process(ctx, in, out)
|
||||
}
|
||||
|
@ -1,13 +1,11 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: micro/go-micro/router/proto/router.proto
|
||||
// source: router.proto
|
||||
|
||||
package go_micro_router
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
math "math"
|
||||
)
|
||||
|
||||
@ -45,7 +43,7 @@ func (x AdvertType) String() string {
|
||||
}
|
||||
|
||||
func (AdvertType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{0}
|
||||
return fileDescriptor_367072455c71aedc, []int{0}
|
||||
}
|
||||
|
||||
// EventType defines the type of event
|
||||
@ -74,7 +72,7 @@ func (x EventType) String() string {
|
||||
}
|
||||
|
||||
func (EventType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_6a36eee0b1adf739, []int{1}
|
||||
return fileDescriptor_367072455c71aedc, []int{1}
|
||||
}
|
||||
|
||||
// Empty request
|
||||
@ -88,7 +86,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_6a36eee0b1adf739, []int{0}
|
||||
return fileDescriptor_367072455c71aedc, []int{0}
|
||||
}
|
||||
|
||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
||||
@ -109,6 +107,38 @@ func (m *Request) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_Request proto.InternalMessageInfo
|
||||
|
||||
// Empty response
|
||||
type Response struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Response) Reset() { *m = Response{} }
|
||||
func (m *Response) String() string { return proto.CompactTextString(m) }
|
||||
func (*Response) ProtoMessage() {}
|
||||
func (*Response) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_367072455c71aedc, []int{1}
|
||||
}
|
||||
|
||||
func (m *Response) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Response.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Response.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Response) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Response.Merge(m, src)
|
||||
}
|
||||
func (m *Response) XXX_Size() int {
|
||||
return xxx_messageInfo_Response.Size(m)
|
||||
}
|
||||
func (m *Response) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Response.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Response proto.InternalMessageInfo
|
||||
|
||||
// ListResponse is returned by List
|
||||
type ListResponse struct {
|
||||
Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"`
|
||||
@ -121,7 +151,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_6a36eee0b1adf739, []int{1}
|
||||
return fileDescriptor_367072455c71aedc, []int{2}
|
||||
}
|
||||
|
||||
func (m *ListResponse) XXX_Unmarshal(b []byte) error {
|
||||
@ -161,7 +191,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_6a36eee0b1adf739, []int{2}
|
||||
return fileDescriptor_367072455c71aedc, []int{3}
|
||||
}
|
||||
|
||||
func (m *LookupRequest) XXX_Unmarshal(b []byte) error {
|
||||
@ -201,7 +231,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_6a36eee0b1adf739, []int{3}
|
||||
return fileDescriptor_367072455c71aedc, []int{4}
|
||||
}
|
||||
|
||||
func (m *LookupResponse) XXX_Unmarshal(b []byte) error {
|
||||
@ -229,6 +259,7 @@ func (m *LookupResponse) GetRoutes() []*Route {
|
||||
return nil
|
||||
}
|
||||
|
||||
// QueryRequest queries Table for Routes
|
||||
type QueryRequest struct {
|
||||
Query *Query `protobuf:"bytes,1,opt,name=query,proto3" json:"query,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
@ -240,7 +271,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_6a36eee0b1adf739, []int{4}
|
||||
return fileDescriptor_367072455c71aedc, []int{5}
|
||||
}
|
||||
|
||||
func (m *QueryRequest) XXX_Unmarshal(b []byte) error {
|
||||
@ -268,6 +299,7 @@ func (m *QueryRequest) GetQuery() *Query {
|
||||
return nil
|
||||
}
|
||||
|
||||
// QueryResponse is returned by Query
|
||||
type QueryResponse struct {
|
||||
Routes []*Route `protobuf:"bytes,1,rep,name=routes,proto3" json:"routes,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
@ -279,7 +311,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_6a36eee0b1adf739, []int{5}
|
||||
return fileDescriptor_367072455c71aedc, []int{6}
|
||||
}
|
||||
|
||||
func (m *QueryResponse) XXX_Unmarshal(b []byte) error {
|
||||
@ -318,7 +350,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_6a36eee0b1adf739, []int{6}
|
||||
return fileDescriptor_367072455c71aedc, []int{7}
|
||||
}
|
||||
|
||||
func (m *WatchRequest) XXX_Unmarshal(b []byte) error {
|
||||
@ -360,7 +392,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_6a36eee0b1adf739, []int{7}
|
||||
return fileDescriptor_367072455c71aedc, []int{8}
|
||||
}
|
||||
|
||||
func (m *Advert) XXX_Unmarshal(b []byte) error {
|
||||
@ -416,6 +448,47 @@ func (m *Advert) GetEvents() []*Event {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Solicit solicits routes
|
||||
type Solicit struct {
|
||||
// id of the soliciting router
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Solicit) Reset() { *m = Solicit{} }
|
||||
func (m *Solicit) String() string { return proto.CompactTextString(m) }
|
||||
func (*Solicit) ProtoMessage() {}
|
||||
func (*Solicit) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_367072455c71aedc, []int{9}
|
||||
}
|
||||
|
||||
func (m *Solicit) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Solicit.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Solicit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Solicit.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Solicit) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Solicit.Merge(m, src)
|
||||
}
|
||||
func (m *Solicit) XXX_Size() int {
|
||||
return xxx_messageInfo_Solicit.Size(m)
|
||||
}
|
||||
func (m *Solicit) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Solicit.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Solicit proto.InternalMessageInfo
|
||||
|
||||
func (m *Solicit) GetId() string {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ProcessResponse is returned by Process
|
||||
type ProcessResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
@ -427,7 +500,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_6a36eee0b1adf739, []int{8}
|
||||
return fileDescriptor_367072455c71aedc, []int{10}
|
||||
}
|
||||
|
||||
func (m *ProcessResponse) XXX_Unmarshal(b []byte) error {
|
||||
@ -459,7 +532,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_6a36eee0b1adf739, []int{9}
|
||||
return fileDescriptor_367072455c71aedc, []int{11}
|
||||
}
|
||||
|
||||
func (m *CreateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@ -491,7 +564,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_6a36eee0b1adf739, []int{10}
|
||||
return fileDescriptor_367072455c71aedc, []int{12}
|
||||
}
|
||||
|
||||
func (m *DeleteResponse) XXX_Unmarshal(b []byte) error {
|
||||
@ -523,7 +596,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_6a36eee0b1adf739, []int{11}
|
||||
return fileDescriptor_367072455c71aedc, []int{13}
|
||||
}
|
||||
|
||||
func (m *UpdateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@ -561,7 +634,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_6a36eee0b1adf739, []int{12}
|
||||
return fileDescriptor_367072455c71aedc, []int{14}
|
||||
}
|
||||
|
||||
func (m *Event) XXX_Unmarshal(b []byte) error {
|
||||
@ -620,7 +693,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_6a36eee0b1adf739, []int{13}
|
||||
return fileDescriptor_367072455c71aedc, []int{15}
|
||||
}
|
||||
|
||||
func (m *Query) XXX_Unmarshal(b []byte) error {
|
||||
@ -672,10 +745,12 @@ type Route struct {
|
||||
Gateway string `protobuf:"bytes,3,opt,name=gateway,proto3" json:"gateway,omitempty"`
|
||||
// the network for this destination
|
||||
Network string `protobuf:"bytes,4,opt,name=network,proto3" json:"network,omitempty"`
|
||||
// router if the router id
|
||||
Router string `protobuf:"bytes,5,opt,name=router,proto3" json:"router,omitempty"`
|
||||
// the network link
|
||||
Link string `protobuf:"bytes,5,opt,name=link,proto3" json:"link,omitempty"`
|
||||
Link string `protobuf:"bytes,6,opt,name=link,proto3" json:"link,omitempty"`
|
||||
// the metric / score of this route
|
||||
Metric int64 `protobuf:"varint,6,opt,name=metric,proto3" json:"metric,omitempty"`
|
||||
Metric int64 `protobuf:"varint,7,opt,name=metric,proto3" json:"metric,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@ -685,7 +760,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_6a36eee0b1adf739, []int{14}
|
||||
return fileDescriptor_367072455c71aedc, []int{16}
|
||||
}
|
||||
|
||||
func (m *Route) XXX_Unmarshal(b []byte) error {
|
||||
@ -734,6 +809,13 @@ func (m *Route) GetNetwork() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Route) GetRouter() string {
|
||||
if m != nil {
|
||||
return m.Router
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Route) GetLink() string {
|
||||
if m != nil {
|
||||
return m.Link
|
||||
@ -760,7 +842,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_6a36eee0b1adf739, []int{15}
|
||||
return fileDescriptor_367072455c71aedc, []int{17}
|
||||
}
|
||||
|
||||
func (m *Status) XXX_Unmarshal(b []byte) error {
|
||||
@ -806,7 +888,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_6a36eee0b1adf739, []int{16}
|
||||
return fileDescriptor_367072455c71aedc, []int{18}
|
||||
}
|
||||
|
||||
func (m *StatusResponse) XXX_Unmarshal(b []byte) error {
|
||||
@ -838,6 +920,7 @@ func init() {
|
||||
proto.RegisterEnum("go.micro.router.AdvertType", AdvertType_name, AdvertType_value)
|
||||
proto.RegisterEnum("go.micro.router.EventType", EventType_name, EventType_value)
|
||||
proto.RegisterType((*Request)(nil), "go.micro.router.Request")
|
||||
proto.RegisterType((*Response)(nil), "go.micro.router.Response")
|
||||
proto.RegisterType((*ListResponse)(nil), "go.micro.router.ListResponse")
|
||||
proto.RegisterType((*LookupRequest)(nil), "go.micro.router.LookupRequest")
|
||||
proto.RegisterType((*LookupResponse)(nil), "go.micro.router.LookupResponse")
|
||||
@ -845,6 +928,7 @@ func init() {
|
||||
proto.RegisterType((*QueryResponse)(nil), "go.micro.router.QueryResponse")
|
||||
proto.RegisterType((*WatchRequest)(nil), "go.micro.router.WatchRequest")
|
||||
proto.RegisterType((*Advert)(nil), "go.micro.router.Advert")
|
||||
proto.RegisterType((*Solicit)(nil), "go.micro.router.Solicit")
|
||||
proto.RegisterType((*ProcessResponse)(nil), "go.micro.router.ProcessResponse")
|
||||
proto.RegisterType((*CreateResponse)(nil), "go.micro.router.CreateResponse")
|
||||
proto.RegisterType((*DeleteResponse)(nil), "go.micro.router.DeleteResponse")
|
||||
@ -856,509 +940,53 @@ func init() {
|
||||
proto.RegisterType((*StatusResponse)(nil), "go.micro.router.StatusResponse")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("micro/go-micro/router/proto/router.proto", fileDescriptor_6a36eee0b1adf739)
|
||||
}
|
||||
|
||||
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, 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.
|
||||
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
|
||||
|
||||
// RouterClient is the client API for Router service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
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 *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)
|
||||
}
|
||||
|
||||
type routerClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewRouterClient(cc *grpc.ClientConn) RouterClient {
|
||||
return &routerClient{cc}
|
||||
}
|
||||
|
||||
func (c *routerClient) Lookup(ctx context.Context, in *LookupRequest, opts ...grpc.CallOption) (*LookupResponse, error) {
|
||||
out := new(LookupResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.router.Router/Lookup", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *routerClient) Watch(ctx context.Context, in *WatchRequest, opts ...grpc.CallOption) (Router_WatchClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_Router_serviceDesc.Streams[0], "/go.micro.router.Router/Watch", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &routerWatchClient{stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type Router_WatchClient interface {
|
||||
Recv() (*Event, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type routerWatchClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *routerWatchClient) Recv() (*Event, error) {
|
||||
m := new(Event)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
x := &routerAdvertiseClient{stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type Router_AdvertiseClient interface {
|
||||
Recv() (*Advert, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type routerAdvertiseClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *routerAdvertiseClient) Recv() (*Advert, error) {
|
||||
m := new(Advert)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *routerClient) Process(ctx context.Context, in *Advert, opts ...grpc.CallOption) (*ProcessResponse, error) {
|
||||
out := new(ProcessResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.router.Router/Process", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *routerClient) Status(ctx context.Context, in *Request, opts ...grpc.CallOption) (*StatusResponse, error) {
|
||||
out := new(StatusResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.router.Router/Status", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// RouterServer is the server API for Router service.
|
||||
type RouterServer interface {
|
||||
Lookup(context.Context, *LookupRequest) (*LookupResponse, error)
|
||||
Watch(*WatchRequest, Router_WatchServer) error
|
||||
Advertise(*Request, Router_AdvertiseServer) error
|
||||
Process(context.Context, *Advert) (*ProcessResponse, error)
|
||||
Status(context.Context, *Request) (*StatusResponse, error)
|
||||
}
|
||||
|
||||
func RegisterRouterServer(s *grpc.Server, srv RouterServer) {
|
||||
s.RegisterService(&_Router_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Router_Lookup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(LookupRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RouterServer).Lookup(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.router.Router/Lookup",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RouterServer).Lookup(ctx, req.(*LookupRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Router_Watch_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(WatchRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(RouterServer).Watch(m, &routerWatchServer{stream})
|
||||
}
|
||||
|
||||
type Router_WatchServer interface {
|
||||
Send(*Event) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type routerWatchServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *routerWatchServer) Send(m *Event) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func _Router_Advertise_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(Request)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(RouterServer).Advertise(m, &routerAdvertiseServer{stream})
|
||||
}
|
||||
|
||||
type Router_AdvertiseServer interface {
|
||||
Send(*Advert) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type routerAdvertiseServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *routerAdvertiseServer) Send(m *Advert) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func _Router_Process_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Advert)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RouterServer).Process(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.router.Router/Process",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RouterServer).Process(ctx, req.(*Advert))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Router_Status_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Request)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RouterServer).Status(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.router.Router/Status",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RouterServer).Status(ctx, req.(*Request))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Router_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "go.micro.router.Router",
|
||||
HandlerType: (*RouterServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Lookup",
|
||||
Handler: _Router_Lookup_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Process",
|
||||
Handler: _Router_Process_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Status",
|
||||
Handler: _Router_Status_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "Watch",
|
||||
Handler: _Router_Watch_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "Advertise",
|
||||
Handler: _Router_Advertise_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "micro/go-micro/router/proto/router.proto",
|
||||
}
|
||||
|
||||
// TableClient is the client API for Table service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
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)
|
||||
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 {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewTableClient(cc *grpc.ClientConn) TableClient {
|
||||
return &tableClient{cc}
|
||||
}
|
||||
|
||||
func (c *tableClient) Create(ctx context.Context, in *Route, opts ...grpc.CallOption) (*CreateResponse, error) {
|
||||
out := new(CreateResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.router.Table/Create", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *tableClient) Delete(ctx context.Context, in *Route, opts ...grpc.CallOption) (*DeleteResponse, error) {
|
||||
out := new(DeleteResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.router.Table/Delete", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *tableClient) Update(ctx context.Context, in *Route, opts ...grpc.CallOption) (*UpdateResponse, error) {
|
||||
out := new(UpdateResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.router.Table/Update", 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...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// TableServer is the server API for Table service.
|
||||
type TableServer interface {
|
||||
Create(context.Context, *Route) (*CreateResponse, error)
|
||||
Delete(context.Context, *Route) (*DeleteResponse, error)
|
||||
Update(context.Context, *Route) (*UpdateResponse, error)
|
||||
List(context.Context, *Request) (*ListResponse, error)
|
||||
Query(context.Context, *QueryRequest) (*QueryResponse, error)
|
||||
}
|
||||
|
||||
func RegisterTableServer(s *grpc.Server, srv TableServer) {
|
||||
s.RegisterService(&_Table_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Table_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Route)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TableServer).Create(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.router.Table/Create",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TableServer).Create(ctx, req.(*Route))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Table_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Route)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TableServer).Delete(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.router.Table/Delete",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TableServer).Delete(ctx, req.(*Route))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Table_Update_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Route)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TableServer).Update(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.router.Table/Update",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TableServer).Update(ctx, req.(*Route))
|
||||
}
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(TableServer).List(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.router.Table/List",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(TableServer).List(ctx, req.(*Request))
|
||||
}
|
||||
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),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Create",
|
||||
Handler: _Table_Create_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Delete",
|
||||
Handler: _Table_Delete_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Update",
|
||||
Handler: _Table_Update_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "List",
|
||||
Handler: _Table_List_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Query",
|
||||
Handler: _Table_Query_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "micro/go-micro/router/proto/router.proto",
|
||||
func init() { proto.RegisterFile("router.proto", fileDescriptor_367072455c71aedc) }
|
||||
|
||||
var fileDescriptor_367072455c71aedc = []byte{
|
||||
// 714 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xcd, 0x4e, 0xdb, 0x40,
|
||||
0x10, 0xb6, 0x93, 0xd8, 0x69, 0xa6, 0x21, 0xa4, 0xa3, 0x0a, 0x4c, 0x5a, 0x20, 0xf2, 0x09, 0x21,
|
||||
0x64, 0xaa, 0xf4, 0xda, 0x1f, 0x02, 0xa5, 0xaa, 0x54, 0x0e, 0xad, 0x01, 0xf5, 0x6c, 0xec, 0x15,
|
||||
0xb5, 0x48, 0xbc, 0x66, 0x77, 0x03, 0xca, 0xb9, 0x4f, 0xd3, 0x4b, 0x2f, 0x7d, 0xa4, 0xbe, 0x48,
|
||||
0xe5, 0xdd, 0x75, 0x08, 0x71, 0x16, 0x09, 0x4e, 0xd9, 0xf9, 0xfb, 0x66, 0x66, 0xf7, 0x9b, 0x71,
|
||||
0xa0, 0xcd, 0xe8, 0x44, 0x10, 0x16, 0xe4, 0x8c, 0x0a, 0x8a, 0xab, 0x97, 0x34, 0x18, 0xa7, 0x31,
|
||||
0xa3, 0x81, 0x52, 0xfb, 0x2d, 0x68, 0x86, 0xe4, 0x7a, 0x42, 0xb8, 0xf0, 0x01, 0x9e, 0x85, 0x84,
|
||||
0xe7, 0x34, 0xe3, 0xc4, 0xff, 0x00, 0xed, 0x93, 0x94, 0x8b, 0x52, 0xc6, 0x00, 0x5c, 0x19, 0xc0,
|
||||
0x3d, 0xbb, 0x5f, 0xdf, 0x79, 0x3e, 0x58, 0x0b, 0x16, 0x80, 0x82, 0xb0, 0xf8, 0x09, 0xb5, 0x97,
|
||||
0xff, 0x1e, 0x56, 0x4e, 0x28, 0xbd, 0x9a, 0xe4, 0x1a, 0x1c, 0xf7, 0xc0, 0xb9, 0x9e, 0x10, 0x36,
|
||||
0xf5, 0xec, 0xbe, 0xbd, 0x34, 0xfe, 0x7b, 0x61, 0x0d, 0x95, 0x93, 0x7f, 0x00, 0x9d, 0x32, 0xfc,
|
||||
0x89, 0x05, 0xbc, 0x83, 0xb6, 0x42, 0x7c, 0x52, 0xfe, 0x8f, 0xb0, 0xa2, 0xa3, 0x9f, 0x98, 0xbe,
|
||||
0x03, 0xed, 0x1f, 0x91, 0x88, 0x7f, 0x96, 0x77, 0xfb, 0xdb, 0x06, 0x77, 0x98, 0xdc, 0x10, 0x26,
|
||||
0xb0, 0x03, 0xb5, 0x34, 0x91, 0x65, 0xb4, 0xc2, 0x5a, 0x9a, 0xe0, 0x3e, 0x34, 0xc4, 0x34, 0x27,
|
||||
0x5e, 0xad, 0x6f, 0xef, 0x74, 0x06, 0xaf, 0x2a, 0xc0, 0x2a, 0xec, 0x6c, 0x9a, 0x93, 0x50, 0x3a,
|
||||
0xe2, 0x6b, 0x68, 0x89, 0x74, 0x4c, 0xb8, 0x88, 0xc6, 0xb9, 0x57, 0xef, 0xdb, 0x3b, 0xf5, 0xf0,
|
||||
0x4e, 0x81, 0x5d, 0xa8, 0x0b, 0x31, 0xf2, 0x1a, 0x52, 0x5f, 0x1c, 0x8b, 0xda, 0xc9, 0x0d, 0xc9,
|
||||
0x04, 0xf7, 0x1c, 0x43, 0xed, 0xc7, 0x85, 0x39, 0xd4, 0x5e, 0xfe, 0x06, 0x34, 0x4f, 0xe9, 0x28,
|
||||
0x8d, 0xd3, 0x4a, 0xad, 0xfe, 0x0b, 0x58, 0xfd, 0xc6, 0x68, 0x4c, 0x38, 0x9f, 0x31, 0xa5, 0x0b,
|
||||
0x9d, 0x23, 0x46, 0x22, 0x41, 0xe6, 0x35, 0x9f, 0xc8, 0x88, 0xdc, 0xd7, 0x9c, 0xe7, 0xc9, 0xbc,
|
||||
0xcf, 0x2f, 0x1b, 0x1c, 0x99, 0x15, 0x03, 0xdd, 0xbe, 0x2d, 0xdb, 0xef, 0x2d, 0xaf, 0xcd, 0xd4,
|
||||
0x7d, 0x6d, 0xb1, 0xfb, 0x3d, 0x70, 0x64, 0x9c, 0xbc, 0x17, 0xf3, 0x33, 0x29, 0x27, 0xff, 0x1c,
|
||||
0x1c, 0xf9, 0xcc, 0xe8, 0x41, 0x93, 0x13, 0x76, 0x93, 0xc6, 0x44, 0x37, 0x5b, 0x8a, 0x85, 0xe5,
|
||||
0x32, 0x12, 0xe4, 0x36, 0x9a, 0xca, 0x64, 0xad, 0xb0, 0x14, 0x0b, 0x4b, 0x46, 0xc4, 0x2d, 0x65,
|
||||
0x57, 0x32, 0x59, 0x2b, 0x2c, 0x45, 0xff, 0xaf, 0x0d, 0x8e, 0xcc, 0xf3, 0x30, 0x6e, 0x94, 0x24,
|
||||
0x8c, 0x70, 0x5e, 0xe2, 0x6a, 0x71, 0x3e, 0x63, 0xdd, 0x98, 0xb1, 0x71, 0x2f, 0x23, 0xae, 0x69,
|
||||
0x7a, 0x32, 0xcf, 0x91, 0x06, 0x2d, 0x21, 0x42, 0x63, 0x94, 0x66, 0x57, 0x9e, 0x2b, 0xb5, 0xf2,
|
||||
0x5c, 0xf8, 0x8e, 0x89, 0x60, 0x69, 0xec, 0x35, 0xe5, 0xed, 0x69, 0xc9, 0x1f, 0x80, 0x7b, 0x2a,
|
||||
0x22, 0x31, 0xe1, 0x45, 0x54, 0x4c, 0x93, 0xb2, 0x64, 0x79, 0xc6, 0x97, 0xe0, 0x10, 0xc6, 0x28,
|
||||
0xd3, 0xd5, 0x2a, 0xc1, 0x1f, 0x42, 0x47, 0xc5, 0xcc, 0x06, 0x65, 0x1f, 0x5c, 0x2e, 0x35, 0x7a,
|
||||
0xd0, 0xd6, 0x2b, 0x2f, 0xa0, 0x03, 0xb4, 0xdb, 0xee, 0x00, 0xe0, 0x8e, 0xe1, 0x88, 0xd0, 0x51,
|
||||
0xd2, 0x30, 0xcb, 0xe8, 0x24, 0x8b, 0x49, 0xd7, 0xc2, 0x2e, 0xb4, 0x95, 0x4e, 0x71, 0xa8, 0x6b,
|
||||
0xef, 0xee, 0x43, 0x6b, 0x46, 0x0b, 0x04, 0x70, 0x15, 0x01, 0xbb, 0x56, 0x71, 0x56, 0xd4, 0xeb,
|
||||
0xda, 0xc5, 0x59, 0x07, 0xd4, 0x06, 0x7f, 0xea, 0xe0, 0x86, 0xea, 0x4a, 0xbe, 0x82, 0xab, 0x56,
|
||||
0x0b, 0x6e, 0x55, 0x4a, 0xbb, 0xb7, 0xb2, 0x7a, 0xdb, 0x46, 0xbb, 0x26, 0xb1, 0x85, 0x87, 0xe0,
|
||||
0xc8, 0x31, 0xc7, 0xcd, 0x8a, 0xef, 0xfc, 0xf8, 0xf7, 0x0c, 0x23, 0xe7, 0x5b, 0x6f, 0x6c, 0x3c,
|
||||
0x84, 0x96, 0x6a, 0x2f, 0xe5, 0x04, 0xbd, 0x2a, 0x61, 0x35, 0xc4, 0xba, 0x61, 0x31, 0x48, 0x8c,
|
||||
0x83, 0xbb, 0x91, 0x35, 0x23, 0x6c, 0x2c, 0xb1, 0xcc, 0x3a, 0xf9, 0x0c, 0x4d, 0x3d, 0xd9, 0x68,
|
||||
0xca, 0xd4, 0xeb, 0x57, 0x0c, 0x8b, 0xcb, 0xc0, 0xc2, 0xe3, 0x19, 0x8b, 0xcc, 0x85, 0x6c, 0x9b,
|
||||
0x38, 0x31, 0x83, 0x19, 0xfc, 0xab, 0x81, 0x73, 0x16, 0x5d, 0x8c, 0x08, 0x1e, 0x95, 0xcf, 0x8b,
|
||||
0x86, 0x61, 0x5e, 0x02, 0xb7, 0xb0, 0x90, 0xac, 0x02, 0x44, 0xf1, 0xe2, 0x11, 0x20, 0x0b, 0x3b,
|
||||
0x4c, 0x82, 0x28, 0x42, 0x3d, 0x02, 0x64, 0x61, 0xed, 0x59, 0x38, 0x84, 0x46, 0xf1, 0x61, 0x7d,
|
||||
0xe0, 0x76, 0xaa, 0x54, 0x9a, 0xff, 0x12, 0xfb, 0x16, 0x7e, 0x29, 0xb7, 0xd6, 0xa6, 0xe1, 0x23,
|
||||
0xa6, 0x81, 0xb6, 0x4c, 0xe6, 0x12, 0xe9, 0xc2, 0x95, 0x7f, 0x0a, 0xde, 0xfe, 0x0f, 0x00, 0x00,
|
||||
0xff, 0xff, 0xb7, 0x25, 0xac, 0xac, 0x24, 0x08, 0x00, 0x00,
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ service Router {
|
||||
rpc Lookup(LookupRequest) returns (LookupResponse) {};
|
||||
rpc Watch(WatchRequest) returns (stream Event) {};
|
||||
rpc Advertise(Request) returns (stream Advert) {};
|
||||
rpc Solicit(Request) returns (Response) {};
|
||||
rpc Process(Advert) returns (ProcessResponse) {};
|
||||
rpc Status(Request) returns (StatusResponse) {};
|
||||
}
|
||||
@ -22,6 +23,9 @@ service Table {
|
||||
// Empty request
|
||||
message Request {}
|
||||
|
||||
// Empty response
|
||||
message Response {}
|
||||
|
||||
// ListResponse is returned by List
|
||||
message ListResponse {
|
||||
repeated Route routes = 1;
|
||||
@ -37,10 +41,12 @@ message LookupResponse {
|
||||
repeated Route routes = 1;
|
||||
}
|
||||
|
||||
// QueryRequest queries Table for Routes
|
||||
message QueryRequest{
|
||||
Query query = 1;
|
||||
}
|
||||
|
||||
// QueryResponse is returned by Query
|
||||
message QueryResponse {
|
||||
repeated Route routes = 1;
|
||||
}
|
||||
@ -68,6 +74,12 @@ message Advert {
|
||||
repeated Event events = 5;
|
||||
}
|
||||
|
||||
// Solicit solicits routes
|
||||
message Solicit {
|
||||
// id of the soliciting router
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
// ProcessResponse is returned by Process
|
||||
message ProcessResponse {}
|
||||
|
||||
@ -117,10 +129,12 @@ message Route {
|
||||
string gateway = 3;
|
||||
// the network for this destination
|
||||
string network = 4;
|
||||
// router if the router id
|
||||
string router = 5;
|
||||
// the network link
|
||||
string link = 5;
|
||||
string link = 6;
|
||||
// the metric / score of this route
|
||||
int64 metric = 6;
|
||||
int64 metric = 7;
|
||||
}
|
||||
|
||||
message Status {
|
||||
|
@ -11,29 +11,38 @@ type QueryOptions struct {
|
||||
Gateway string
|
||||
// Network is network address
|
||||
Network string
|
||||
// Router is router id
|
||||
Router string
|
||||
}
|
||||
|
||||
// QueryService sets destination address
|
||||
// QueryService sets service to query
|
||||
func QueryService(s string) QueryOption {
|
||||
return func(o *QueryOptions) {
|
||||
o.Service = s
|
||||
}
|
||||
}
|
||||
|
||||
// QueryGateway sets route gateway
|
||||
// QueryGateway sets gateway address to query
|
||||
func QueryGateway(g string) QueryOption {
|
||||
return func(o *QueryOptions) {
|
||||
o.Gateway = g
|
||||
}
|
||||
}
|
||||
|
||||
// QueryNetwork sets route network address
|
||||
// QueryNetwork sets network name to query
|
||||
func QueryNetwork(n string) QueryOption {
|
||||
return func(o *QueryOptions) {
|
||||
o.Network = n
|
||||
}
|
||||
}
|
||||
|
||||
// QueryRouter sets router id to query
|
||||
func QueryRouter(r string) QueryOption {
|
||||
return func(o *QueryOptions) {
|
||||
o.Router = r
|
||||
}
|
||||
}
|
||||
|
||||
// Query is routing table query
|
||||
type Query interface {
|
||||
// Options returns query options
|
||||
@ -52,6 +61,7 @@ func NewQuery(opts ...QueryOption) Query {
|
||||
Service: "*",
|
||||
Gateway: "*",
|
||||
Network: "*",
|
||||
Router: "*",
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
@ -67,8 +77,3 @@ func NewQuery(opts ...QueryOption) Query {
|
||||
func (q *query) Options() QueryOptions {
|
||||
return q.opts
|
||||
}
|
||||
|
||||
// String prints routing table query in human readable form
|
||||
func (q query) String() string {
|
||||
return "query"
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ import (
|
||||
var (
|
||||
// DefaultLink is default network link
|
||||
DefaultLink = "local"
|
||||
// DefaultLocalMetric is default route cost metric for the local network
|
||||
// DefaultLocalMetric is default route cost for a local route
|
||||
DefaultLocalMetric = 1
|
||||
// DefaultNetworkMetric is default route cost metric for the micro network
|
||||
// DefaultNetworkMetric is default route cost for a network route
|
||||
DefaultNetworkMetric = 10
|
||||
)
|
||||
|
||||
@ -23,6 +23,8 @@ type Route struct {
|
||||
Gateway string
|
||||
// Network is network address
|
||||
Network string
|
||||
// Router is router id
|
||||
Router string
|
||||
// Link is network link
|
||||
Link string
|
||||
// Metric is the route cost metric
|
||||
@ -33,6 +35,6 @@ type Route struct {
|
||||
func (r *Route) Hash() uint64 {
|
||||
h := fnv.New64()
|
||||
h.Reset()
|
||||
h.Write([]byte(r.Service + r.Address + r.Gateway + r.Network + r.Link))
|
||||
h.Write([]byte(r.Service + r.Address + r.Gateway + r.Network + r.Router + r.Link))
|
||||
return h.Sum64()
|
||||
}
|
||||
|
@ -5,6 +5,17 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultAddress is default router address
|
||||
DefaultAddress = ":9093"
|
||||
// DefaultName is default router service name
|
||||
DefaultName = "go.micro.router"
|
||||
// DefaultNetwork is default micro network
|
||||
DefaultNetwork = "go.micro"
|
||||
// DefaultRouter is default network router
|
||||
DefaultRouter = NewRouter()
|
||||
)
|
||||
|
||||
// Router is an interface for a routing control plane
|
||||
type Router interface {
|
||||
// Init initializes the router with options
|
||||
@ -17,10 +28,14 @@ type Router interface {
|
||||
Advertise() (<-chan *Advert, error)
|
||||
// Process processes incoming adverts
|
||||
Process(*Advert) error
|
||||
// Solicit advertises the whole routing table to the network
|
||||
Solicit() error
|
||||
// Lookup queries routes in the routing table
|
||||
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
|
||||
@ -29,16 +44,17 @@ type Router interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
// Table is an interface for routing table
|
||||
type Table interface {
|
||||
// Create new route in the routing table
|
||||
Create(Route) error
|
||||
// Delete deletes existing route from the routing table
|
||||
// Delete existing route from the routing table
|
||||
Delete(Route) error
|
||||
// Update updates route in the routing table
|
||||
// Update route in the routing table
|
||||
Update(Route) error
|
||||
// List returns the list of all routes in the table
|
||||
// List all routes in the table
|
||||
List() ([]Route, error)
|
||||
// Query queries routes in the routing table
|
||||
// Query routes in the routing table
|
||||
Query(Query) ([]Route, error)
|
||||
}
|
||||
|
||||
@ -76,10 +92,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
|
||||
@ -118,17 +139,6 @@ type Advert struct {
|
||||
Events []*Event
|
||||
}
|
||||
|
||||
var (
|
||||
// DefaultAddress is default router address
|
||||
DefaultAddress = ":9093"
|
||||
// DefaultName is default router service name
|
||||
DefaultName = "go.micro.router"
|
||||
// DefaultNetwork is default micro network
|
||||
DefaultNetwork = "go.micro"
|
||||
// DefaultRouter is default network router
|
||||
DefaultRouter = NewRouter()
|
||||
)
|
||||
|
||||
// NewRouter creates new Router and returns it
|
||||
func NewRouter(opts ...Option) Router {
|
||||
return newRouter(opts...)
|
||||
|
@ -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,10 +169,7 @@ 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.Request{}, s.callOpts...)
|
||||
if err != nil {
|
||||
@ -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)
|
||||
@ -202,6 +220,42 @@ func (s *svc) Process(advert *router.Advert) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Solicit advertise all routes
|
||||
func (s *svc) Solicit() error {
|
||||
// list all the routes
|
||||
routes, err := s.table.List()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// build events to advertise
|
||||
events := make([]*router.Event, len(routes))
|
||||
for i, _ := range events {
|
||||
events[i] = &router.Event{
|
||||
Type: router.Update,
|
||||
Timestamp: time.Now(),
|
||||
Route: routes[i],
|
||||
}
|
||||
}
|
||||
|
||||
advert := &router.Advert{
|
||||
Id: s.opts.Id,
|
||||
Type: router.RouteUpdate,
|
||||
Timestamp: time.Now(),
|
||||
TTL: time.Duration(router.DefaultAdvertTTL),
|
||||
Events: events,
|
||||
}
|
||||
|
||||
select {
|
||||
case s.advertChan <- advert:
|
||||
case <-s.exit:
|
||||
close(s.advertChan)
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Status returns router status
|
||||
func (s *svc) Status() router.Status {
|
||||
s.Lock()
|
||||
@ -303,7 +357,9 @@ func (s *svc) Watch(opts ...router.WatchOption) (router.Watcher, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var options router.WatchOptions
|
||||
options := router.WatchOptions{
|
||||
Service: "*",
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
@ -70,11 +70,9 @@ func (w *watcher) watch(stream pb.Router_WatchService) error {
|
||||
Route: route,
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case w.resChan <- event:
|
||||
case <-w.done:
|
||||
}
|
||||
select {
|
||||
case w.resChan <- event:
|
||||
case <-w.done:
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,9 +6,17 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/util/log"
|
||||
)
|
||||
|
||||
// table is an in memory routing table
|
||||
var (
|
||||
// ErrRouteNotFound is returned when no route was found in the routing table
|
||||
ErrRouteNotFound = errors.New("route not found")
|
||||
// ErrDuplicateRoute is returned when the route already exists
|
||||
ErrDuplicateRoute = errors.New("duplicate route")
|
||||
)
|
||||
|
||||
// table is an in-memory routing table
|
||||
type table struct {
|
||||
sync.RWMutex
|
||||
// routes stores service routes
|
||||
@ -25,6 +33,19 @@ func newTable(opts ...Option) *table {
|
||||
}
|
||||
}
|
||||
|
||||
// sendEvent sends events to all subscribed watchers
|
||||
func (t *table) sendEvent(e *Event) {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
|
||||
for _, w := range t.watchers {
|
||||
select {
|
||||
case w.resChan <- e:
|
||||
case <-w.done:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create creates new route in the routing table
|
||||
func (t *table) Create(r Route) error {
|
||||
service := r.Service
|
||||
@ -36,14 +57,12 @@ func (t *table) Create(r Route) error {
|
||||
// check if there are any routes in the table for the route destination
|
||||
if _, ok := t.routes[service]; !ok {
|
||||
t.routes[service] = make(map[uint64]Route)
|
||||
t.routes[service][sum] = r
|
||||
go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r})
|
||||
return nil
|
||||
}
|
||||
|
||||
// add new route to the table for the route destination
|
||||
if _, ok := t.routes[service][sum]; !ok {
|
||||
t.routes[service][sum] = r
|
||||
log.Debugf("Router emitting %s for route: %s", Create, r.Address)
|
||||
go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r})
|
||||
return nil
|
||||
}
|
||||
@ -63,7 +82,12 @@ func (t *table) Delete(r Route) error {
|
||||
return ErrRouteNotFound
|
||||
}
|
||||
|
||||
if _, ok := t.routes[service][sum]; !ok {
|
||||
return ErrRouteNotFound
|
||||
}
|
||||
|
||||
delete(t.routes[service], sum)
|
||||
log.Debugf("Router emitting %s for route: %s", Delete, r.Address)
|
||||
go t.sendEvent(&Event{Type: Delete, Timestamp: time.Now(), Route: r})
|
||||
|
||||
return nil
|
||||
@ -80,13 +104,17 @@ func (t *table) Update(r Route) error {
|
||||
// check if the route destination has any routes in the table
|
||||
if _, ok := t.routes[service]; !ok {
|
||||
t.routes[service] = make(map[uint64]Route)
|
||||
}
|
||||
|
||||
if _, ok := t.routes[service][sum]; !ok {
|
||||
t.routes[service][sum] = r
|
||||
go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r})
|
||||
log.Debugf("Router emitting %s for route: %s", Update, r.Address)
|
||||
go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r})
|
||||
return nil
|
||||
}
|
||||
|
||||
// just update the route, but dont emit Update event
|
||||
t.routes[service][sum] = r
|
||||
go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r})
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -106,21 +134,23 @@ func (t *table) List() ([]Route, error) {
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
// isMatch checks if the route matches given network and router
|
||||
func isMatch(route Route, network, router string) bool {
|
||||
if network == "*" || network == route.Network {
|
||||
if router == "*" || router == route.Gateway {
|
||||
return true
|
||||
// isMatch checks if the route matches given query options
|
||||
func isMatch(route Route, gateway, network, router string) bool {
|
||||
if gateway == "*" || gateway == route.Gateway {
|
||||
if network == "*" || network == route.Network {
|
||||
if router == "*" || router == route.Router {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// findRoutes finds all the routes for given network and router and returns them
|
||||
func findRoutes(routes map[uint64]Route, network, router string) []Route {
|
||||
func findRoutes(routes map[uint64]Route, gateway, network, router string) []Route {
|
||||
var results []Route
|
||||
for _, route := range routes {
|
||||
if isMatch(route, network, router) {
|
||||
if isMatch(route, gateway, network, router) {
|
||||
results = append(results, route)
|
||||
}
|
||||
}
|
||||
@ -136,13 +166,13 @@ func (t *table) Query(q Query) ([]Route, error) {
|
||||
if _, ok := t.routes[q.Options().Service]; !ok {
|
||||
return nil, ErrRouteNotFound
|
||||
}
|
||||
return findRoutes(t.routes[q.Options().Service], q.Options().Network, q.Options().Gateway), nil
|
||||
return findRoutes(t.routes[q.Options().Service], q.Options().Gateway, q.Options().Network, q.Options().Router), nil
|
||||
}
|
||||
|
||||
var results []Route
|
||||
// search through all destinations
|
||||
for _, routes := range t.routes {
|
||||
results = append(results, findRoutes(routes, q.Options().Network, q.Options().Gateway)...)
|
||||
results = append(results, findRoutes(routes, q.Options().Gateway, q.Options().Network, q.Options().Router)...)
|
||||
}
|
||||
|
||||
return results, nil
|
||||
@ -181,23 +211,3 @@ func (t *table) Watch(opts ...WatchOption) (Watcher, error) {
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// sendEvent sends events to all subscribed watchers
|
||||
func (t *table) sendEvent(e *Event) {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
|
||||
for _, w := range t.watchers {
|
||||
select {
|
||||
case w.resChan <- e:
|
||||
case <-w.done:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrRouteNotFound is returned when no route was found in the routing table
|
||||
ErrRouteNotFound = errors.New("route not found")
|
||||
// ErrDuplicateRoute is returned when the route already exists
|
||||
ErrDuplicateRoute = errors.New("duplicate route")
|
||||
)
|
||||
|
@ -9,6 +9,7 @@ func testSetup() (*table, Route) {
|
||||
Service: "dest.svc",
|
||||
Gateway: "dest.gw",
|
||||
Network: "dest.network",
|
||||
Router: "src.router",
|
||||
Link: "det.link",
|
||||
Metric: 10,
|
||||
}
|
||||
@ -109,11 +110,13 @@ func TestQuery(t *testing.T) {
|
||||
svc := []string{"svc1", "svc2", "svc3"}
|
||||
net := []string{"net1", "net2", "net1"}
|
||||
gw := []string{"gw1", "gw2", "gw3"}
|
||||
rtr := []string{"rtr1", "rt2", "rt3"}
|
||||
|
||||
for i := 0; i < len(svc); i++ {
|
||||
route.Service = svc[i]
|
||||
route.Network = net[i]
|
||||
route.Gateway = gw[i]
|
||||
route.Router = rtr[i]
|
||||
if err := table.Create(route); err != nil {
|
||||
t.Errorf("error adding route: %s", err)
|
||||
}
|
||||
@ -127,8 +130,9 @@ func TestQuery(t *testing.T) {
|
||||
t.Errorf("error looking up routes: %s", err)
|
||||
}
|
||||
|
||||
// query particular net
|
||||
query = NewQuery(QueryNetwork("net1"))
|
||||
// query routes particular network
|
||||
network := "net1"
|
||||
query = NewQuery(QueryNetwork(network))
|
||||
|
||||
routes, err = table.Query(query)
|
||||
if err != nil {
|
||||
@ -139,7 +143,13 @@ func TestQuery(t *testing.T) {
|
||||
t.Errorf("incorrect number of routes returned. Expected: %d, found: %d", 2, len(routes))
|
||||
}
|
||||
|
||||
// query particular gateway
|
||||
for _, route := range routes {
|
||||
if route.Network != network {
|
||||
t.Errorf("incorrect route returned. Expected network: %s, found: %s", network, route.Network)
|
||||
}
|
||||
}
|
||||
|
||||
// query routes for particular gateway
|
||||
gateway := "gw1"
|
||||
query = NewQuery(QueryGateway(gateway))
|
||||
|
||||
@ -156,11 +166,28 @@ func TestQuery(t *testing.T) {
|
||||
t.Errorf("incorrect route returned. Expected gateway: %s, found: %s", gateway, routes[0].Gateway)
|
||||
}
|
||||
|
||||
// query particular route
|
||||
network := "net1"
|
||||
// query routes for particular router
|
||||
router := "rtr1"
|
||||
query = NewQuery(QueryRouter(router))
|
||||
|
||||
routes, err = table.Query(query)
|
||||
if err != nil {
|
||||
t.Errorf("error looking up routes: %s", err)
|
||||
}
|
||||
|
||||
if len(routes) != 1 {
|
||||
t.Errorf("incorrect number of routes returned. Expected: %d, found: %d", 1, len(routes))
|
||||
}
|
||||
|
||||
if routes[0].Router != router {
|
||||
t.Errorf("incorrect route returned. Expected router: %s, found: %s", router, routes[0].Router)
|
||||
}
|
||||
|
||||
// query particular gateway and network
|
||||
query = NewQuery(
|
||||
QueryGateway(gateway),
|
||||
QueryNetwork(network),
|
||||
QueryRouter(router),
|
||||
)
|
||||
|
||||
routes, err = table.Query(query)
|
||||
@ -180,7 +207,11 @@ func TestQuery(t *testing.T) {
|
||||
t.Errorf("incorrect network returned. Expected network: %s, found: %s", network, routes[0].Network)
|
||||
}
|
||||
|
||||
// bullshit route query
|
||||
if routes[0].Router != router {
|
||||
t.Errorf("incorrect route returned. Expected router: %s, found: %s", router, routes[0].Router)
|
||||
}
|
||||
|
||||
// non-existen route query
|
||||
query = NewQuery(QueryService("foobar"))
|
||||
|
||||
routes, err = table.Query(query)
|
||||
|
@ -6,6 +6,11 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrWatcherStopped is returned when routing table watcher has been stopped
|
||||
ErrWatcherStopped = errors.New("watcher stopped")
|
||||
)
|
||||
|
||||
// EventType defines routing table event
|
||||
type EventType int
|
||||
|
||||
@ -42,9 +47,6 @@ type Event struct {
|
||||
Route Route
|
||||
}
|
||||
|
||||
// WatchOption is used to define what routes to watch in the table
|
||||
type WatchOption func(*WatchOptions)
|
||||
|
||||
// Watcher defines routing table watcher interface
|
||||
// Watcher returns updates to the routing table
|
||||
type Watcher interface {
|
||||
@ -56,7 +58,11 @@ type Watcher interface {
|
||||
Stop()
|
||||
}
|
||||
|
||||
// WatchOption is used to define what routes to watch in the table
|
||||
type WatchOption func(*WatchOptions)
|
||||
|
||||
// WatchOptions are table watcher options
|
||||
// TODO: expand the options to watch based on other criteria
|
||||
type WatchOptions struct {
|
||||
// Service allows to watch specific service routes
|
||||
Service string
|
||||
@ -70,6 +76,7 @@ func WatchService(s string) WatchOption {
|
||||
}
|
||||
}
|
||||
|
||||
// tableWatcher implements routing table Watcher
|
||||
type tableWatcher struct {
|
||||
sync.RWMutex
|
||||
id string
|
||||
@ -113,8 +120,3 @@ func (w *tableWatcher) Stop() {
|
||||
close(w.done)
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrWatcherStopped is returned when routing table watcher has been stopped
|
||||
ErrWatcherStopped = errors.New("watcher stopped")
|
||||
)
|
||||
|
298
runtime/default.go
Normal file
298
runtime/default.go
Normal file
@ -0,0 +1,298 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/runtime/package"
|
||||
"github.com/micro/go-micro/runtime/process"
|
||||
proc "github.com/micro/go-micro/runtime/process/os"
|
||||
"github.com/micro/go-micro/util/log"
|
||||
)
|
||||
|
||||
type runtime struct {
|
||||
sync.RWMutex
|
||||
// used to stop the runtime
|
||||
closed chan bool
|
||||
// used to start new services
|
||||
start chan *service
|
||||
// indicates if we're running
|
||||
running bool
|
||||
// the service map
|
||||
services map[string]*service
|
||||
}
|
||||
|
||||
type service struct {
|
||||
sync.RWMutex
|
||||
|
||||
running bool
|
||||
closed chan bool
|
||||
err error
|
||||
|
||||
// output for logs
|
||||
output io.Writer
|
||||
|
||||
// service to manage
|
||||
*Service
|
||||
// process creator
|
||||
Process *proc.Process
|
||||
// Exec
|
||||
Exec *process.Executable
|
||||
// process pid
|
||||
PID *process.PID
|
||||
}
|
||||
|
||||
func newRuntime() *runtime {
|
||||
return &runtime{
|
||||
closed: make(chan bool),
|
||||
start: make(chan *service, 128),
|
||||
services: make(map[string]*service),
|
||||
}
|
||||
}
|
||||
|
||||
func newService(s *Service, c CreateOptions) *service {
|
||||
var exec string
|
||||
var args []string
|
||||
|
||||
if len(s.Exec) > 0 {
|
||||
parts := strings.Split(s.Exec, " ")
|
||||
exec = parts[0]
|
||||
args = []string{}
|
||||
|
||||
if len(parts) > 1 {
|
||||
args = parts[1:]
|
||||
}
|
||||
} else {
|
||||
// set command
|
||||
exec = c.Command[0]
|
||||
// set args
|
||||
if len(c.Command) > 1 {
|
||||
args = c.Command[1:]
|
||||
}
|
||||
}
|
||||
|
||||
return &service{
|
||||
Service: s,
|
||||
Process: new(proc.Process),
|
||||
Exec: &process.Executable{
|
||||
Binary: &packager.Binary{
|
||||
Name: s.Name,
|
||||
Path: exec,
|
||||
},
|
||||
Env: c.Env,
|
||||
Args: args,
|
||||
},
|
||||
output: c.Output,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) streamOutput() {
|
||||
go io.Copy(s.output, s.PID.Output)
|
||||
go io.Copy(s.output, s.PID.Error)
|
||||
}
|
||||
|
||||
func (s *service) Running() bool {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
return s.running
|
||||
}
|
||||
|
||||
func (s *service) Start() error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
// reset
|
||||
s.err = nil
|
||||
s.closed = make(chan bool)
|
||||
|
||||
// TODO: pull source & build binary
|
||||
log.Debugf("Runtime service %s forking new process\n")
|
||||
p, err := s.Process.Fork(s.Exec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the pid
|
||||
s.PID = p
|
||||
// set to running
|
||||
s.running = true
|
||||
|
||||
if s.output != nil {
|
||||
s.streamOutput()
|
||||
}
|
||||
|
||||
// wait and watch
|
||||
go s.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) Stop() error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
select {
|
||||
case <-s.closed:
|
||||
return nil
|
||||
default:
|
||||
close(s.closed)
|
||||
s.running = false
|
||||
return s.Process.Kill(s.PID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) Error() error {
|
||||
s.RLock()
|
||||
defer s.RUnlock()
|
||||
return s.err
|
||||
}
|
||||
|
||||
func (s *service) Wait() {
|
||||
// wait for process to exit
|
||||
err := s.Process.Wait(s.PID)
|
||||
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
// save the error
|
||||
if err != nil {
|
||||
s.err = err
|
||||
}
|
||||
|
||||
// no longer running
|
||||
s.running = false
|
||||
}
|
||||
|
||||
func (r *runtime) run() {
|
||||
r.RLock()
|
||||
closed := r.closed
|
||||
r.RUnlock()
|
||||
|
||||
t := time.NewTicker(time.Second * 5)
|
||||
defer t.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
// check running services
|
||||
r.RLock()
|
||||
for _, service := range r.services {
|
||||
if service.Running() {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: check service error
|
||||
log.Debugf("Runtime starting %s", service.Name)
|
||||
if err := service.Start(); err != nil {
|
||||
log.Debugf("Runtime error starting %s: %v", service.Name, err)
|
||||
}
|
||||
}
|
||||
r.RUnlock()
|
||||
case service := <-r.start:
|
||||
if service.Running() {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: check service error
|
||||
log.Debugf("Starting %s", service.Name)
|
||||
if err := service.Start(); err != nil {
|
||||
log.Debugf("Runtime error starting %s: %v", service.Name, err)
|
||||
}
|
||||
case <-closed:
|
||||
// TODO: stop all the things
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *runtime) Create(s *Service, opts ...CreateOption) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if _, ok := r.services[s.Name]; ok {
|
||||
return errors.New("service already registered")
|
||||
}
|
||||
|
||||
var options CreateOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
if len(s.Exec) == 0 && len(options.Command) == 0 {
|
||||
return errors.New("missing exec command")
|
||||
}
|
||||
|
||||
// save service
|
||||
r.services[s.Name] = newService(s, options)
|
||||
|
||||
// push into start queue
|
||||
r.start <- r.services[s.Name]
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *runtime) Delete(s *Service) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if s, ok := r.services[s.Name]; ok {
|
||||
delete(r.services, s.Name)
|
||||
return s.Stop()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *runtime) Start() error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
// already running
|
||||
if r.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
// set running
|
||||
r.running = true
|
||||
r.closed = make(chan bool)
|
||||
|
||||
go r.run()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *runtime) Stop() error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if !r.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
select {
|
||||
case <-r.closed:
|
||||
return nil
|
||||
default:
|
||||
close(r.closed)
|
||||
|
||||
// set not running
|
||||
r.running = false
|
||||
|
||||
// stop all the services
|
||||
for _, service := range r.services {
|
||||
log.Debugf("Runtime stopping %s", service.Name)
|
||||
service.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
40
runtime/options.go
Normal file
40
runtime/options.go
Normal file
@ -0,0 +1,40 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"io"
|
||||
)
|
||||
|
||||
type CreateOption func(o *CreateOptions)
|
||||
|
||||
type CreateOptions struct {
|
||||
// command to execute including args
|
||||
Command []string
|
||||
// Environment to configure
|
||||
Env []string
|
||||
// Log output
|
||||
Output io.Writer
|
||||
}
|
||||
|
||||
// WithCommand specifies the command to execute
|
||||
func WithCommand(c string, args ...string) CreateOption {
|
||||
return func(o *CreateOptions) {
|
||||
// set command
|
||||
o.Command = []string{c}
|
||||
// set args
|
||||
o.Command = append(o.Command, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnv sets the created service env
|
||||
func WithEnv(env []string) CreateOption {
|
||||
return func(o *CreateOptions) {
|
||||
o.Env = env
|
||||
}
|
||||
}
|
||||
|
||||
// WithOutput sets the arg output
|
||||
func WithOutput(out io.Writer) CreateOption {
|
||||
return func(o *CreateOptions) {
|
||||
o.Output = out
|
||||
}
|
||||
}
|
@ -19,10 +19,11 @@ func (p *Process) Exec(exe *process.Executable) error {
|
||||
}
|
||||
|
||||
func (p *Process) Fork(exe *process.Executable) (*process.PID, error) {
|
||||
cmd := exec.Command(exe.Binary.Path)
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// create command
|
||||
cmd := exec.Command(exe.Binary.Path, exe.Args...)
|
||||
// set env vars
|
||||
cmd.Env = append(cmd.Env, exe.Env...)
|
||||
|
||||
in, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -36,6 +37,11 @@ func (p *Process) Fork(exe *process.Executable) (*process.PID, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// start the process
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &process.PID{
|
||||
ID: fmt.Sprintf("%d", cmd.Process.Pid),
|
||||
Input: in,
|
||||
|
@ -22,6 +22,10 @@ type Process interface {
|
||||
type Executable struct {
|
||||
// The executable binary
|
||||
Binary *packager.Binary
|
||||
// The env variables
|
||||
Env []string
|
||||
// Args to pass
|
||||
Args []string
|
||||
}
|
||||
|
||||
// PID is the running process
|
||||
|
108
runtime/proto/runtime.micro.go
Normal file
108
runtime/proto/runtime.micro.go
Normal file
@ -0,0 +1,108 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: micro/go-micro/runtime/proto/runtime.proto
|
||||
|
||||
package go_micro_runtime
|
||||
|
||||
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 Runtime service
|
||||
|
||||
type RuntimeService interface {
|
||||
Create(ctx context.Context, in *CreateRequest, opts ...client.CallOption) (*CreateResponse, error)
|
||||
Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error)
|
||||
}
|
||||
|
||||
type runtimeService struct {
|
||||
c client.Client
|
||||
name string
|
||||
}
|
||||
|
||||
func NewRuntimeService(name string, c client.Client) RuntimeService {
|
||||
if c == nil {
|
||||
c = client.NewClient()
|
||||
}
|
||||
if len(name) == 0 {
|
||||
name = "go.micro.runtime"
|
||||
}
|
||||
return &runtimeService{
|
||||
c: c,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *runtimeService) Create(ctx context.Context, in *CreateRequest, opts ...client.CallOption) (*CreateResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Runtime.Create", in)
|
||||
out := new(CreateResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *runtimeService) Delete(ctx context.Context, in *DeleteRequest, opts ...client.CallOption) (*DeleteResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Runtime.Delete", in)
|
||||
out := new(DeleteResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for Runtime service
|
||||
|
||||
type RuntimeHandler interface {
|
||||
Create(context.Context, *CreateRequest, *CreateResponse) error
|
||||
Delete(context.Context, *DeleteRequest, *DeleteResponse) error
|
||||
}
|
||||
|
||||
func RegisterRuntimeHandler(s server.Server, hdlr RuntimeHandler, opts ...server.HandlerOption) error {
|
||||
type runtime interface {
|
||||
Create(ctx context.Context, in *CreateRequest, out *CreateResponse) error
|
||||
Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error
|
||||
}
|
||||
type Runtime struct {
|
||||
runtime
|
||||
}
|
||||
h := &runtimeHandler{hdlr}
|
||||
return s.Handle(s.NewHandler(&Runtime{h}, opts...))
|
||||
}
|
||||
|
||||
type runtimeHandler struct {
|
||||
RuntimeHandler
|
||||
}
|
||||
|
||||
func (h *runtimeHandler) Create(ctx context.Context, in *CreateRequest, out *CreateResponse) error {
|
||||
return h.RuntimeHandler.Create(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *runtimeHandler) Delete(ctx context.Context, in *DeleteRequest, out *DeleteResponse) error {
|
||||
return h.RuntimeHandler.Delete(ctx, in, out)
|
||||
}
|
366
runtime/proto/runtime.pb.go
Normal file
366
runtime/proto/runtime.pb.go
Normal file
@ -0,0 +1,366 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: micro/go-micro/runtime/proto/runtime.proto
|
||||
|
||||
package go_micro_runtime
|
||||
|
||||
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 Service struct {
|
||||
// name of the service
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
// git url of the source
|
||||
Source string `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"`
|
||||
// local path of the source
|
||||
Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
|
||||
// command to execute
|
||||
Exec string `protobuf:"bytes,4,opt,name=exec,proto3" json:"exec,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Service) Reset() { *m = Service{} }
|
||||
func (m *Service) String() string { return proto.CompactTextString(m) }
|
||||
func (*Service) ProtoMessage() {}
|
||||
func (*Service) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_efcf18966add108e, []int{0}
|
||||
}
|
||||
|
||||
func (m *Service) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Service.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Service) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Service.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Service) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Service.Merge(m, src)
|
||||
}
|
||||
func (m *Service) XXX_Size() int {
|
||||
return xxx_messageInfo_Service.Size(m)
|
||||
}
|
||||
func (m *Service) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Service.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Service proto.InternalMessageInfo
|
||||
|
||||
func (m *Service) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Service) GetSource() string {
|
||||
if m != nil {
|
||||
return m.Source
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Service) GetPath() string {
|
||||
if m != nil {
|
||||
return m.Path
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Service) GetExec() string {
|
||||
if m != nil {
|
||||
return m.Exec
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CreateRequest struct {
|
||||
Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CreateRequest) Reset() { *m = CreateRequest{} }
|
||||
func (m *CreateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateRequest) ProtoMessage() {}
|
||||
func (*CreateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_efcf18966add108e, []int{1}
|
||||
}
|
||||
|
||||
func (m *CreateRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CreateRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CreateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CreateRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CreateRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CreateRequest.Merge(m, src)
|
||||
}
|
||||
func (m *CreateRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_CreateRequest.Size(m)
|
||||
}
|
||||
func (m *CreateRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CreateRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CreateRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *CreateRequest) GetService() *Service {
|
||||
if m != nil {
|
||||
return m.Service
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CreateResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
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_efcf18966add108e, []int{2}
|
||||
}
|
||||
|
||||
func (m *CreateResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CreateResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CreateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CreateResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CreateResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CreateResponse.Merge(m, src)
|
||||
}
|
||||
func (m *CreateResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_CreateResponse.Size(m)
|
||||
}
|
||||
func (m *CreateResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CreateResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CreateResponse proto.InternalMessageInfo
|
||||
|
||||
type DeleteRequest struct {
|
||||
Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) Reset() { *m = DeleteRequest{} }
|
||||
func (m *DeleteRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteRequest) ProtoMessage() {}
|
||||
func (*DeleteRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_efcf18966add108e, []int{3}
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_DeleteRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *DeleteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_DeleteRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *DeleteRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_DeleteRequest.Merge(m, src)
|
||||
}
|
||||
func (m *DeleteRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_DeleteRequest.Size(m)
|
||||
}
|
||||
func (m *DeleteRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_DeleteRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_DeleteRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *DeleteRequest) GetService() *Service {
|
||||
if m != nil {
|
||||
return m.Service
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeleteResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
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_efcf18966add108e, []int{4}
|
||||
}
|
||||
|
||||
func (m *DeleteResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_DeleteResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *DeleteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_DeleteResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *DeleteResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_DeleteResponse.Merge(m, src)
|
||||
}
|
||||
func (m *DeleteResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_DeleteResponse.Size(m)
|
||||
}
|
||||
func (m *DeleteResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_DeleteResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Service)(nil), "go.micro.runtime.Service")
|
||||
proto.RegisterType((*CreateRequest)(nil), "go.micro.runtime.CreateRequest")
|
||||
proto.RegisterType((*CreateResponse)(nil), "go.micro.runtime.CreateResponse")
|
||||
proto.RegisterType((*DeleteRequest)(nil), "go.micro.runtime.DeleteRequest")
|
||||
proto.RegisterType((*DeleteResponse)(nil), "go.micro.runtime.DeleteResponse")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("micro/go-micro/runtime/proto/runtime.proto", fileDescriptor_efcf18966add108e)
|
||||
}
|
||||
|
||||
var fileDescriptor_efcf18966add108e = []byte{
|
||||
// 240 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x91, 0x41, 0x4b, 0xc4, 0x30,
|
||||
0x14, 0x84, 0xb7, 0xba, 0xb4, 0xf8, 0x44, 0x59, 0x72, 0x90, 0xe8, 0xc5, 0x25, 0x27, 0x11, 0xcc,
|
||||
0x42, 0xfb, 0x13, 0xec, 0xd5, 0x4b, 0x3c, 0x7b, 0xa8, 0xe1, 0x51, 0x0b, 0xb6, 0xa9, 0x49, 0x2a,
|
||||
0xfe, 0x23, 0xff, 0xa6, 0x24, 0x2f, 0x15, 0xaa, 0xf5, 0xe4, 0x6d, 0xde, 0x30, 0x7c, 0x33, 0x21,
|
||||
0x70, 0xdb, 0x77, 0xda, 0x9a, 0x43, 0x6b, 0xee, 0x48, 0xd8, 0x69, 0xf0, 0x5d, 0x8f, 0x87, 0xd1,
|
||||
0x1a, 0xff, 0x7d, 0xc9, 0x78, 0xb1, 0x5d, 0x6b, 0x64, 0x4c, 0xc9, 0xe4, 0x8b, 0x27, 0x28, 0x1e,
|
||||
0xd1, 0xbe, 0x77, 0x1a, 0x19, 0x83, 0xed, 0xd0, 0xf4, 0xc8, 0xb3, 0x7d, 0x76, 0x73, 0xa2, 0xa2,
|
||||
0x66, 0x17, 0x90, 0x3b, 0x33, 0x59, 0x8d, 0xfc, 0x28, 0xba, 0xe9, 0x0a, 0xd9, 0xb1, 0xf1, 0x2f,
|
||||
0xfc, 0x98, 0xb2, 0x41, 0x07, 0x0f, 0x3f, 0x50, 0xf3, 0x2d, 0x79, 0x41, 0x8b, 0x1a, 0xce, 0xee,
|
||||
0x2d, 0x36, 0x1e, 0x15, 0xbe, 0x4d, 0xe8, 0x3c, 0xab, 0xa0, 0x70, 0xd4, 0x17, 0x7b, 0x4e, 0xcb,
|
||||
0x4b, 0xf9, 0x73, 0x93, 0x4c, 0x83, 0xd4, 0x9c, 0x14, 0x3b, 0x38, 0x9f, 0x29, 0x6e, 0x34, 0x83,
|
||||
0xc3, 0xc0, 0xad, 0xf1, 0x15, 0xff, 0xcf, 0x9d, 0x29, 0xc4, 0x2d, 0x3f, 0x33, 0x28, 0x14, 0xc5,
|
||||
0xd9, 0x03, 0xe4, 0xd4, 0xca, 0xae, 0x7f, 0xb3, 0x16, 0xaf, 0xba, 0xda, 0xff, 0x1d, 0x48, 0x83,
|
||||
0x37, 0x01, 0x47, 0x65, 0x6b, 0xb8, 0xc5, 0x63, 0xd6, 0x70, 0xcb, 0x9d, 0x62, 0xf3, 0x9c, 0xc7,
|
||||
0x1f, 0xad, 0xbe, 0x02, 0x00, 0x00, 0xff, 0xff, 0x9a, 0xb6, 0x5a, 0xe7, 0xff, 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
|
||||
|
||||
// RuntimeClient is the client API for Runtime service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type RuntimeClient interface {
|
||||
Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error)
|
||||
Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error)
|
||||
}
|
||||
|
||||
type runtimeClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewRuntimeClient(cc *grpc.ClientConn) RuntimeClient {
|
||||
return &runtimeClient{cc}
|
||||
}
|
||||
|
||||
func (c *runtimeClient) Create(ctx context.Context, in *CreateRequest, opts ...grpc.CallOption) (*CreateResponse, error) {
|
||||
out := new(CreateResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.runtime.Runtime/Create", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *runtimeClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*DeleteResponse, error) {
|
||||
out := new(DeleteResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.runtime.Runtime/Delete", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// RuntimeServer is the server API for Runtime service.
|
||||
type RuntimeServer interface {
|
||||
Create(context.Context, *CreateRequest) (*CreateResponse, error)
|
||||
Delete(context.Context, *DeleteRequest) (*DeleteResponse, error)
|
||||
}
|
||||
|
||||
func RegisterRuntimeServer(s *grpc.Server, srv RuntimeServer) {
|
||||
s.RegisterService(&_Runtime_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Runtime_Create_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RuntimeServer).Create(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.runtime.Runtime/Create",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RuntimeServer).Create(ctx, req.(*CreateRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Runtime_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(RuntimeServer).Delete(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.runtime.Runtime/Delete",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(RuntimeServer).Delete(ctx, req.(*DeleteRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Runtime_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "go.micro.runtime.Runtime",
|
||||
HandlerType: (*RuntimeServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Create",
|
||||
Handler: _Runtime_Create_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Delete",
|
||||
Handler: _Runtime_Delete_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "micro/go-micro/runtime/proto/runtime.proto",
|
||||
}
|
31
runtime/proto/runtime.proto
Normal file
31
runtime/proto/runtime.proto
Normal file
@ -0,0 +1,31 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package go.micro.runtime;
|
||||
|
||||
service Runtime {
|
||||
rpc Create(CreateRequest) returns (CreateResponse) {};
|
||||
rpc Delete(DeleteRequest) returns (DeleteResponse) {};
|
||||
}
|
||||
|
||||
message Service {
|
||||
// name of the service
|
||||
string name = 1;
|
||||
// git url of the source
|
||||
string source = 2;
|
||||
// local path of the source
|
||||
string path = 3;
|
||||
// command to execute
|
||||
string exec = 4;
|
||||
}
|
||||
|
||||
message CreateRequest {
|
||||
Service service = 1;
|
||||
}
|
||||
|
||||
message CreateResponse {}
|
||||
|
||||
message DeleteRequest {
|
||||
Service service = 1;
|
||||
}
|
||||
|
||||
message DeleteResponse {}
|
45
runtime/runtime.go
Normal file
45
runtime/runtime.go
Normal file
@ -0,0 +1,45 @@
|
||||
// Package runtime is a service runtime manager
|
||||
package runtime
|
||||
|
||||
// Runtime is a service runtime manager
|
||||
type Runtime interface {
|
||||
// Registers a service
|
||||
Create(*Service, ...CreateOption) error
|
||||
// Remove a service
|
||||
Delete(*Service) error
|
||||
// starts the runtime
|
||||
Start() error
|
||||
// Shutdown the runtime
|
||||
Stop() error
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
// name of the service
|
||||
Name string
|
||||
// url location of source
|
||||
Source string
|
||||
// path to store source
|
||||
Path string
|
||||
// exec command
|
||||
Exec string
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultRuntime = newRuntime()
|
||||
)
|
||||
|
||||
func Create(s *Service, opts ...CreateOption) error {
|
||||
return DefaultRuntime.Create(s, opts...)
|
||||
}
|
||||
|
||||
func Delete(s *Service) error {
|
||||
return DefaultRuntime.Delete(s)
|
||||
}
|
||||
|
||||
func Start() error {
|
||||
return DefaultRuntime.Start()
|
||||
}
|
||||
|
||||
func Stop() error {
|
||||
return DefaultRuntime.Stop()
|
||||
}
|
@ -53,6 +53,8 @@ type grpcServer struct {
|
||||
opts server.Options
|
||||
handlers map[string]server.Handler
|
||||
subscribers map[*subscriber][]broker.Subscriber
|
||||
// marks the serve as started
|
||||
started bool
|
||||
// used for first registration
|
||||
registered bool
|
||||
}
|
||||
@ -271,12 +273,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
|
||||
@ -336,6 +338,11 @@ func (g *grpcServer) processRequest(stream grpc.ServerStream, service *service,
|
||||
|
||||
// define the handler func
|
||||
fn := func(ctx context.Context, req server.Request, rsp interface{}) error {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Logf("handler %s panic recovered, err: %s", mtype.method.Name, r)
|
||||
}
|
||||
}()
|
||||
returnValues = function.Call([]reflect.Value{service.rcvr, mtype.prepareContext(ctx), reflect.ValueOf(argv.Interface()), reflect.ValueOf(rsp)})
|
||||
|
||||
// The return value for the method is an error.
|
||||
@ -454,7 +461,10 @@ func (g *grpcServer) newCodec(contentType string) (codec.NewCodec, error) {
|
||||
}
|
||||
|
||||
func (g *grpcServer) Options() server.Options {
|
||||
g.RLock()
|
||||
opts := g.opts
|
||||
g.RUnlock()
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
@ -700,7 +710,14 @@ func (g *grpcServer) Deregister() error {
|
||||
}
|
||||
|
||||
func (g *grpcServer) Start() error {
|
||||
config := g.opts
|
||||
g.RLock()
|
||||
if g.started {
|
||||
g.RUnlock()
|
||||
return nil
|
||||
}
|
||||
g.RUnlock()
|
||||
|
||||
config := g.Options()
|
||||
|
||||
// micro: config.Transport.Listen(config.Address)
|
||||
ts, err := net.Listen("tcp", config.Address)
|
||||
@ -781,13 +798,34 @@ func (g *grpcServer) Start() error {
|
||||
config.Broker.Disconnect()
|
||||
}()
|
||||
|
||||
// mark the server as started
|
||||
g.Lock()
|
||||
g.started = true
|
||||
g.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcServer) Stop() error {
|
||||
g.RLock()
|
||||
if !g.started {
|
||||
g.RUnlock()
|
||||
return nil
|
||||
}
|
||||
g.RUnlock()
|
||||
|
||||
ch := make(chan error)
|
||||
g.exit <- ch
|
||||
return <-ch
|
||||
|
||||
var err error
|
||||
select {
|
||||
case err = <-ch:
|
||||
g.Lock()
|
||||
g.started = false
|
||||
g.Unlock()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *grpcServer) String() string {
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -42,8 +42,10 @@ type Options struct {
|
||||
|
||||
func newOptions(opt ...Option) Options {
|
||||
opts := Options{
|
||||
Codecs: make(map[string]codec.NewCodec),
|
||||
Metadata: map[string]string{},
|
||||
Codecs: make(map[string]codec.NewCodec),
|
||||
Metadata: map[string]string{},
|
||||
RegisterInterval: DefaultRegisterInterval,
|
||||
RegisterTTL: DefaultRegisterTTL,
|
||||
}
|
||||
|
||||
for _, o := range opt {
|
||||
|
108
server/proto/server.micro.go
Normal file
108
server/proto/server.micro.go
Normal file
@ -0,0 +1,108 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: micro/go-micro/server/proto/server.proto
|
||||
|
||||
package go_micro_server
|
||||
|
||||
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 Server service
|
||||
|
||||
type ServerService interface {
|
||||
Handle(ctx context.Context, in *HandleRequest, opts ...client.CallOption) (*HandleResponse, error)
|
||||
Subscribe(ctx context.Context, in *SubscribeRequest, opts ...client.CallOption) (*SubscribeResponse, error)
|
||||
}
|
||||
|
||||
type serverService struct {
|
||||
c client.Client
|
||||
name string
|
||||
}
|
||||
|
||||
func NewServerService(name string, c client.Client) ServerService {
|
||||
if c == nil {
|
||||
c = client.NewClient()
|
||||
}
|
||||
if len(name) == 0 {
|
||||
name = "go.micro.server"
|
||||
}
|
||||
return &serverService{
|
||||
c: c,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *serverService) Handle(ctx context.Context, in *HandleRequest, opts ...client.CallOption) (*HandleResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Server.Handle", in)
|
||||
out := new(HandleResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *serverService) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...client.CallOption) (*SubscribeResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Server.Subscribe", in)
|
||||
out := new(SubscribeResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for Server service
|
||||
|
||||
type ServerHandler interface {
|
||||
Handle(context.Context, *HandleRequest, *HandleResponse) error
|
||||
Subscribe(context.Context, *SubscribeRequest, *SubscribeResponse) error
|
||||
}
|
||||
|
||||
func RegisterServerHandler(s server.Server, hdlr ServerHandler, opts ...server.HandlerOption) error {
|
||||
type server interface {
|
||||
Handle(ctx context.Context, in *HandleRequest, out *HandleResponse) error
|
||||
Subscribe(ctx context.Context, in *SubscribeRequest, out *SubscribeResponse) error
|
||||
}
|
||||
type Server struct {
|
||||
server
|
||||
}
|
||||
h := &serverHandler{hdlr}
|
||||
return s.Handle(s.NewHandler(&Server{h}, opts...))
|
||||
}
|
||||
|
||||
type serverHandler struct {
|
||||
ServerHandler
|
||||
}
|
||||
|
||||
func (h *serverHandler) Handle(ctx context.Context, in *HandleRequest, out *HandleResponse) error {
|
||||
return h.ServerHandler.Handle(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *serverHandler) Subscribe(ctx context.Context, in *SubscribeRequest, out *SubscribeResponse) error {
|
||||
return h.ServerHandler.Subscribe(ctx, in, out)
|
||||
}
|
314
server/proto/server.pb.go
Normal file
314
server/proto/server.pb.go
Normal file
@ -0,0 +1,314 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: micro/go-micro/server/proto/server.proto
|
||||
|
||||
package go_micro_server
|
||||
|
||||
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 HandleRequest struct {
|
||||
Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
Endpoint string `protobuf:"bytes,2,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
|
||||
Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *HandleRequest) Reset() { *m = HandleRequest{} }
|
||||
func (m *HandleRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*HandleRequest) ProtoMessage() {}
|
||||
func (*HandleRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_aabeb7f1c6b4fe84, []int{0}
|
||||
}
|
||||
|
||||
func (m *HandleRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HandleRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *HandleRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_HandleRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *HandleRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_HandleRequest.Merge(m, src)
|
||||
}
|
||||
func (m *HandleRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_HandleRequest.Size(m)
|
||||
}
|
||||
func (m *HandleRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_HandleRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_HandleRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *HandleRequest) GetService() string {
|
||||
if m != nil {
|
||||
return m.Service
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *HandleRequest) GetEndpoint() string {
|
||||
if m != nil {
|
||||
return m.Endpoint
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *HandleRequest) GetProtocol() string {
|
||||
if m != nil {
|
||||
return m.Protocol
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type HandleResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *HandleResponse) Reset() { *m = HandleResponse{} }
|
||||
func (m *HandleResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*HandleResponse) ProtoMessage() {}
|
||||
func (*HandleResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_aabeb7f1c6b4fe84, []int{1}
|
||||
}
|
||||
|
||||
func (m *HandleResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_HandleResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *HandleResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_HandleResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *HandleResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_HandleResponse.Merge(m, src)
|
||||
}
|
||||
func (m *HandleResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_HandleResponse.Size(m)
|
||||
}
|
||||
func (m *HandleResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_HandleResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_HandleResponse proto.InternalMessageInfo
|
||||
|
||||
type SubscribeRequest struct {
|
||||
Topic string `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *SubscribeRequest) Reset() { *m = SubscribeRequest{} }
|
||||
func (m *SubscribeRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*SubscribeRequest) ProtoMessage() {}
|
||||
func (*SubscribeRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_aabeb7f1c6b4fe84, []int{2}
|
||||
}
|
||||
|
||||
func (m *SubscribeRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SubscribeRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *SubscribeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_SubscribeRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *SubscribeRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_SubscribeRequest.Merge(m, src)
|
||||
}
|
||||
func (m *SubscribeRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_SubscribeRequest.Size(m)
|
||||
}
|
||||
func (m *SubscribeRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_SubscribeRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_SubscribeRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *SubscribeRequest) GetTopic() string {
|
||||
if m != nil {
|
||||
return m.Topic
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SubscribeResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *SubscribeResponse) Reset() { *m = SubscribeResponse{} }
|
||||
func (m *SubscribeResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*SubscribeResponse) ProtoMessage() {}
|
||||
func (*SubscribeResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_aabeb7f1c6b4fe84, []int{3}
|
||||
}
|
||||
|
||||
func (m *SubscribeResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SubscribeResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *SubscribeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_SubscribeResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *SubscribeResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_SubscribeResponse.Merge(m, src)
|
||||
}
|
||||
func (m *SubscribeResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_SubscribeResponse.Size(m)
|
||||
}
|
||||
func (m *SubscribeResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_SubscribeResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_SubscribeResponse proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*HandleRequest)(nil), "go.micro.server.HandleRequest")
|
||||
proto.RegisterType((*HandleResponse)(nil), "go.micro.server.HandleResponse")
|
||||
proto.RegisterType((*SubscribeRequest)(nil), "go.micro.server.SubscribeRequest")
|
||||
proto.RegisterType((*SubscribeResponse)(nil), "go.micro.server.SubscribeResponse")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("micro/go-micro/server/proto/server.proto", fileDescriptor_aabeb7f1c6b4fe84)
|
||||
}
|
||||
|
||||
var fileDescriptor_aabeb7f1c6b4fe84 = []byte{
|
||||
// 228 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x90, 0xcd, 0x4e, 0xc4, 0x20,
|
||||
0x14, 0x85, 0xad, 0xc6, 0xea, 0xdc, 0x44, 0x1d, 0xd1, 0x05, 0xe9, 0xc2, 0x1f, 0x56, 0xdd, 0xc8,
|
||||
0x24, 0xfa, 0x12, 0x26, 0xee, 0x66, 0x7c, 0x81, 0x29, 0xbd, 0x69, 0x48, 0x2a, 0x17, 0x81, 0xfa,
|
||||
0x52, 0xbe, 0xa4, 0x29, 0x94, 0x46, 0x6b, 0x74, 0xc7, 0xc7, 0x39, 0xdc, 0x73, 0x2e, 0x50, 0xbf,
|
||||
0x69, 0xe5, 0x68, 0xd3, 0xd1, 0x43, 0x3a, 0x78, 0x74, 0x1f, 0xe8, 0x36, 0xd6, 0x51, 0xc8, 0x20,
|
||||
0x23, 0xb0, 0x8b, 0x8e, 0x64, 0xf4, 0xc8, 0x74, 0x2d, 0xf6, 0x70, 0xf6, 0xbc, 0x37, 0x6d, 0x8f,
|
||||
0x5b, 0x7c, 0x1f, 0xd0, 0x07, 0xc6, 0xe1, 0x64, 0x94, 0xb4, 0x42, 0x5e, 0xdc, 0x15, 0xf5, 0x6a,
|
||||
0x9b, 0x91, 0x55, 0x70, 0x8a, 0xa6, 0xb5, 0xa4, 0x4d, 0xe0, 0x87, 0x51, 0x9a, 0x79, 0xd4, 0x62,
|
||||
0x80, 0xa2, 0x9e, 0x1f, 0x25, 0x2d, 0xb3, 0x58, 0xc3, 0x79, 0x8e, 0xf0, 0x96, 0x8c, 0x47, 0x51,
|
||||
0xc3, 0x7a, 0x37, 0x34, 0x5e, 0x39, 0xdd, 0xcc, 0xb9, 0xd7, 0x70, 0x1c, 0xc8, 0x6a, 0x35, 0xa5,
|
||||
0x26, 0x10, 0x57, 0x70, 0xf9, 0xcd, 0x99, 0x9e, 0x3f, 0x7e, 0x16, 0x50, 0xee, 0x62, 0x7d, 0xf6,
|
||||
0x02, 0x65, 0x9a, 0xcd, 0x6e, 0xe4, 0x62, 0x35, 0xf9, 0x63, 0xaf, 0xea, 0xf6, 0x4f, 0x7d, 0x2a,
|
||||
0x75, 0xc0, 0x5e, 0x61, 0x35, 0x87, 0xb1, 0xfb, 0x5f, 0xfe, 0x65, 0xe5, 0x4a, 0xfc, 0x67, 0xc9,
|
||||
0x53, 0x9b, 0x32, 0x7e, 0xc4, 0xd3, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf9, 0xb8, 0x5c, 0x69,
|
||||
0xa5, 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
|
||||
|
||||
// ServerClient is the client API for Server service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type ServerClient interface {
|
||||
Handle(ctx context.Context, in *HandleRequest, opts ...grpc.CallOption) (*HandleResponse, error)
|
||||
Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (*SubscribeResponse, error)
|
||||
}
|
||||
|
||||
type serverClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewServerClient(cc *grpc.ClientConn) ServerClient {
|
||||
return &serverClient{cc}
|
||||
}
|
||||
|
||||
func (c *serverClient) Handle(ctx context.Context, in *HandleRequest, opts ...grpc.CallOption) (*HandleResponse, error) {
|
||||
out := new(HandleResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.server.Server/Handle", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *serverClient) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (*SubscribeResponse, error) {
|
||||
out := new(SubscribeResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.server.Server/Subscribe", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ServerServer is the server API for Server service.
|
||||
type ServerServer interface {
|
||||
Handle(context.Context, *HandleRequest) (*HandleResponse, error)
|
||||
Subscribe(context.Context, *SubscribeRequest) (*SubscribeResponse, error)
|
||||
}
|
||||
|
||||
func RegisterServerServer(s *grpc.Server, srv ServerServer) {
|
||||
s.RegisterService(&_Server_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Server_Handle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HandleRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServerServer).Handle(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.server.Server/Handle",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServerServer).Handle(ctx, req.(*HandleRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Server_Subscribe_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SubscribeRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServerServer).Subscribe(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.server.Server/Subscribe",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServerServer).Subscribe(ctx, req.(*SubscribeRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Server_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "go.micro.server.Server",
|
||||
HandlerType: (*ServerServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Handle",
|
||||
Handler: _Server_Handle_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Subscribe",
|
||||
Handler: _Server_Subscribe_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "micro/go-micro/server/proto/server.proto",
|
||||
}
|
22
server/proto/server.proto
Normal file
22
server/proto/server.proto
Normal file
@ -0,0 +1,22 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package go.micro.server;
|
||||
|
||||
service Server {
|
||||
rpc Handle(HandleRequest) returns (HandleResponse) {};
|
||||
rpc Subscribe(SubscribeRequest) returns (SubscribeResponse) {};
|
||||
}
|
||||
|
||||
message HandleRequest {
|
||||
string service = 1;
|
||||
string endpoint = 2;
|
||||
string protocol = 3;
|
||||
}
|
||||
|
||||
message HandleResponse {}
|
||||
|
||||
message SubscribeRequest {
|
||||
string topic = 1;
|
||||
}
|
||||
|
||||
message SubscribeResponse {}
|
@ -15,9 +15,10 @@ import (
|
||||
)
|
||||
|
||||
type rpcCodec struct {
|
||||
socket transport.Socket
|
||||
codec codec.Codec
|
||||
first bool
|
||||
socket transport.Socket
|
||||
codec codec.Codec
|
||||
first bool
|
||||
protocol string
|
||||
|
||||
req *transport.Message
|
||||
buf *readWriteCloser
|
||||
@ -154,16 +155,30 @@ 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,
|
||||
socket: socket,
|
||||
buf: rwc,
|
||||
codec: c(rwc),
|
||||
req: req,
|
||||
socket: socket,
|
||||
protocol: "mucp",
|
||||
}
|
||||
|
||||
// if grpc pre-load the buffer
|
||||
// TODO: remove this terrible hack
|
||||
switch r.codec.String() {
|
||||
case "grpc":
|
||||
// set as first
|
||||
r.first = true
|
||||
// write the body
|
||||
rwc.rbuf.Write(req.Body)
|
||||
// set the protocol
|
||||
r.protocol = "grpc"
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
@ -174,7 +189,7 @@ func (c *rpcCodec) ReadHeader(r *codec.Message, t codec.MessageType) error {
|
||||
Body: c.req.Body,
|
||||
}
|
||||
|
||||
// if its a follow on request read it
|
||||
// first message could be pre-loaded
|
||||
if !c.first {
|
||||
var tm transport.Message
|
||||
|
||||
@ -199,7 +214,7 @@ func (c *rpcCodec) ReadHeader(r *codec.Message, t codec.MessageType) error {
|
||||
c.req = &tm
|
||||
}
|
||||
|
||||
// no longer first read
|
||||
// disable first
|
||||
c.first = false
|
||||
|
||||
// set some internal things
|
||||
@ -300,5 +315,5 @@ func (c *rpcCodec) Close() error {
|
||||
}
|
||||
|
||||
func (c *rpcCodec) String() string {
|
||||
return "rpc"
|
||||
return c.protocol
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user