Compare commits
81 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4aa0192eba | ||
|
1765be049b | ||
|
8d5d812e32 | ||
|
3f910038a3 | ||
|
a8042adac1 | ||
|
10a3636a9f | ||
|
4e5fbbf7eb | ||
|
59035ab801 | ||
|
d3525ebab3 | ||
|
2674294cbe | ||
|
b20dd16f92 | ||
|
5088c9d916 | ||
|
f62fcaad76 | ||
|
322eaae529 | ||
|
6a33b7576b | ||
|
6e669d4611 | ||
|
95fc625e99 | ||
|
338e0fdf18 | ||
|
5899134b66 | ||
|
da18ea4ab5 | ||
|
459f4c8387 | ||
|
9c57f32f58 | ||
|
ad92e6821e | ||
|
d7f0db04ec | ||
|
e4311c3a10 | ||
|
ee8b6b3114 | ||
|
08da7c1283 | ||
|
6587ae07be | ||
|
1c1dae0642 | ||
|
a0cb105cf6 | ||
|
606b1ff7cf | ||
|
73a8b14145 | ||
|
c0a628d65b | ||
|
e9c2df775a | ||
|
d3a6297b17 | ||
|
7266c62d09 | ||
|
6459cdfc21 | ||
|
ed54384bf4 | ||
|
51560009d2 | ||
|
cf2f8a9a55 | ||
|
97cf2cd7c3 | ||
|
d9fe8f802b | ||
|
b754c33549 | ||
|
59eaa89bac | ||
|
f65694670e | ||
|
1a571b8c82 | ||
|
308673b393 | ||
|
3a454d870a | ||
|
baaa386e27 | ||
|
a619321b64 | ||
|
363fb551af | ||
|
7a87ae0efa | ||
ab692ff590 | |||
|
2b18b11ab1 | ||
|
af096951fc | ||
|
97967cbe14 | ||
|
a6e09c9249 | ||
|
000e25a4b2 | ||
|
7a1cef46b0 | ||
|
a5412dd4a0 | ||
|
f81f66c98b | ||
|
43ed8f58f0 | ||
|
7727b359c8 | ||
|
8e4e710e15 | ||
|
4d4686d9be | ||
|
6d06ee8078 | ||
|
aec1ca6635 | ||
|
235a653f78 | ||
|
d030c78d1c | ||
|
90a9df9b8c | ||
|
070bd40b4c | ||
|
46de3ae9a9 | ||
|
b6833e478d | ||
|
73b0a0ed0e | ||
|
7c4515d748 | ||
|
748c20c979 | ||
|
3573ac818f | ||
|
ed4bce3285 | ||
|
95b8147fa1 | ||
|
f5ac238231 | ||
|
bfdec9e2e3 |
51
broker/common_test.go
Normal file
51
broker/common_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package broker
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/registry"
|
||||
)
|
||||
|
||||
var (
|
||||
// mock data
|
||||
testData = map[string][]*registry.Service{
|
||||
"foo": []*registry.Service{
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "1.0.0",
|
||||
Nodes: []*registry.Node{
|
||||
{
|
||||
Id: "foo-1.0.0-123",
|
||||
Address: "localhost",
|
||||
Port: 9999,
|
||||
},
|
||||
{
|
||||
Id: "foo-1.0.0-321",
|
||||
Address: "localhost",
|
||||
Port: 9999,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "1.0.1",
|
||||
Nodes: []*registry.Node{
|
||||
{
|
||||
Id: "foo-1.0.1-321",
|
||||
Address: "localhost",
|
||||
Port: 6666,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "1.0.3",
|
||||
Nodes: []*registry.Node{
|
||||
{
|
||||
Id: "foo-1.0.3-345",
|
||||
Address: "localhost",
|
||||
Port: 8888,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
@@ -14,7 +14,7 @@ import (
|
||||
func newTestRegistry() *memory.Registry {
|
||||
r := memory.NewRegistry()
|
||||
m := r.(*memory.Registry)
|
||||
m.Setup()
|
||||
m.Services = testData
|
||||
return m
|
||||
}
|
||||
|
||||
|
51
client/common_test.go
Normal file
51
client/common_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/registry"
|
||||
)
|
||||
|
||||
var (
|
||||
// mock data
|
||||
testData = map[string][]*registry.Service{
|
||||
"foo": []*registry.Service{
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "1.0.0",
|
||||
Nodes: []*registry.Node{
|
||||
{
|
||||
Id: "foo-1.0.0-123",
|
||||
Address: "localhost",
|
||||
Port: 9999,
|
||||
},
|
||||
{
|
||||
Id: "foo-1.0.0-321",
|
||||
Address: "localhost",
|
||||
Port: 9999,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "1.0.1",
|
||||
Nodes: []*registry.Node{
|
||||
{
|
||||
Id: "foo-1.0.1-321",
|
||||
Address: "localhost",
|
||||
Port: 6666,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "1.0.3",
|
||||
Nodes: []*registry.Node{
|
||||
{
|
||||
Id: "foo-1.0.3-345",
|
||||
Address: "localhost",
|
||||
Port: 8888,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
@@ -2,12 +2,15 @@ package grpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/json-iterator/go"
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/codec/bytes"
|
||||
"github.com/micro/go-micro/codec/jsonrpc"
|
||||
"github.com/micro/go-micro/codec/protorpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
)
|
||||
|
||||
@@ -52,7 +55,28 @@ func (w wrapCodec) String() string {
|
||||
return w.Codec.Name()
|
||||
}
|
||||
|
||||
func (w wrapCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
return b.Data, nil
|
||||
}
|
||||
return w.Codec.Marshal(v)
|
||||
}
|
||||
|
||||
func (w wrapCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
b.Data = data
|
||||
return nil
|
||||
}
|
||||
return w.Codec.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
return b.Data, nil
|
||||
}
|
||||
return proto.Marshal(v.(proto.Message))
|
||||
}
|
||||
|
||||
@@ -96,3 +120,59 @@ func (jsonCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
func (jsonCodec) Name() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
type grpcCodec struct {
|
||||
// headers
|
||||
id string
|
||||
target string
|
||||
method string
|
||||
endpoint string
|
||||
|
||||
s grpc.ClientStream
|
||||
c encoding.Codec
|
||||
}
|
||||
|
||||
func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error {
|
||||
md, err := g.s.Header()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m == nil {
|
||||
m = new(codec.Message)
|
||||
}
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string)
|
||||
}
|
||||
for k, v := range md {
|
||||
m.Header[k] = strings.Join(v, ",")
|
||||
}
|
||||
m.Id = g.id
|
||||
m.Target = g.target
|
||||
m.Method = g.method
|
||||
m.Endpoint = g.endpoint
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcCodec) ReadBody(v interface{}) error {
|
||||
if f, ok := v.(*bytes.Frame); ok {
|
||||
return g.s.RecvMsg(f)
|
||||
}
|
||||
return g.s.RecvMsg(v)
|
||||
}
|
||||
|
||||
func (g *grpcCodec) Write(m *codec.Message, v interface{}) error {
|
||||
// if we don't have a body
|
||||
if v != nil {
|
||||
return g.s.SendMsg(v)
|
||||
}
|
||||
// write the body using the framing codec
|
||||
return g.s.SendMsg(&bytes.Frame{m.Body})
|
||||
}
|
||||
|
||||
func (g *grpcCodec) Close() error {
|
||||
return g.s.CloseSend()
|
||||
}
|
||||
|
||||
func (g *grpcCodec) String() string {
|
||||
return g.c.Name()
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -31,8 +32,9 @@ type grpcClient struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
encoding.RegisterCodec(jsonCodec{})
|
||||
encoding.RegisterCodec(bytesCodec{})
|
||||
encoding.RegisterCodec(wrapCodec{jsonCodec{}})
|
||||
encoding.RegisterCodec(wrapCodec{jsonCodec{}})
|
||||
encoding.RegisterCodec(wrapCodec{bytesCodec{}})
|
||||
}
|
||||
|
||||
// secure returns the dial option for whether its a secure or insecure connection
|
||||
@@ -48,6 +50,18 @@ func (g *grpcClient) secure() grpc.DialOption {
|
||||
}
|
||||
|
||||
func (g *grpcClient) next(request client.Request, opts client.CallOptions) (selector.Next, error) {
|
||||
service := request.Service()
|
||||
|
||||
// get proxy
|
||||
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
|
||||
service = prx
|
||||
}
|
||||
|
||||
// get proxy address
|
||||
if prx := os.Getenv("MICRO_PROXY_ADDRESS"); len(prx) > 0 {
|
||||
opts.Address = prx
|
||||
}
|
||||
|
||||
// return remote address
|
||||
if len(opts.Address) > 0 {
|
||||
return func() (*registry.Node, error) {
|
||||
@@ -58,7 +72,7 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele
|
||||
}
|
||||
|
||||
// get next nodes from the selector
|
||||
next, err := g.opts.Selector.Select(request.Service(), opts.SelectOptions...)
|
||||
next, err := g.opts.Selector.Select(service, opts.SelectOptions...)
|
||||
if err != nil && err == selector.ErrNotFound {
|
||||
return nil, errors.NotFound("go.micro.client", err.Error())
|
||||
} else if err != nil {
|
||||
@@ -99,7 +113,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
|
||||
|
||||
var grr error
|
||||
|
||||
cc, err := g.pool.getConn(address, grpc.WithDefaultCallOptions(grpc.CallCustomCodec(cf)),
|
||||
cc, err := g.pool.getConn(address, grpc.WithDefaultCallOptions(grpc.ForceCodec(cf)),
|
||||
grpc.WithTimeout(opts.DialTimeout), g.secure(),
|
||||
grpc.WithDefaultCallOptions(
|
||||
grpc.MaxCallRecvMsgSize(maxRecvMsgSize),
|
||||
@@ -116,7 +130,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
|
||||
ch := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
err := cc.Invoke(ctx, methodToGRPC(req.Endpoint(), req.Body()), req.Body(), rsp, grpc.CallContentSubtype(cf.String()))
|
||||
err := cc.Invoke(ctx, methodToGRPC(req.Service(), req.Endpoint()), req.Body(), rsp, grpc.ForceCodec(cf))
|
||||
ch <- microError(err)
|
||||
}()
|
||||
|
||||
@@ -164,7 +178,10 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
|
||||
dialCtx, cancel = context.WithCancel(ctx)
|
||||
}
|
||||
defer cancel()
|
||||
cc, err := grpc.DialContext(dialCtx, address, grpc.WithDefaultCallOptions(grpc.CallCustomCodec(cf)), g.secure())
|
||||
|
||||
wc := wrapCodec{cf}
|
||||
|
||||
cc, err := grpc.DialContext(dialCtx, address, grpc.WithDefaultCallOptions(grpc.ForceCodec(wc)), g.secure())
|
||||
if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
|
||||
}
|
||||
@@ -175,16 +192,34 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
|
||||
ServerStreams: true,
|
||||
}
|
||||
|
||||
st, err := cc.NewStream(ctx, desc, methodToGRPC(req.Endpoint(), req.Body()), grpc.CallContentSubtype(cf.String()))
|
||||
st, err := cc.NewStream(ctx, desc, methodToGRPC(req.Service(), req.Endpoint()))
|
||||
if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err))
|
||||
}
|
||||
|
||||
codec := &grpcCodec{
|
||||
s: st,
|
||||
c: wc,
|
||||
}
|
||||
|
||||
// set request codec
|
||||
if r, ok := req.(*grpcRequest); ok {
|
||||
r.codec = codec
|
||||
}
|
||||
|
||||
rsp := &response{
|
||||
conn: cc,
|
||||
stream: st,
|
||||
codec: cf,
|
||||
gcodec: codec,
|
||||
}
|
||||
|
||||
return &grpcStream{
|
||||
context: ctx,
|
||||
request: req,
|
||||
stream: st,
|
||||
conn: cc,
|
||||
context: ctx,
|
||||
request: req,
|
||||
response: rsp,
|
||||
stream: st,
|
||||
conn: cc,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -210,7 +245,7 @@ func (g *grpcClient) maxSendMsgSizeValue() int {
|
||||
return v.(int)
|
||||
}
|
||||
|
||||
func (g *grpcClient) newGRPCCodec(contentType string) (grpc.Codec, error) {
|
||||
func (g *grpcClient) newGRPCCodec(contentType string) (encoding.Codec, error) {
|
||||
codecs := make(map[string]encoding.Codec)
|
||||
if g.opts.Context != nil {
|
||||
if v := g.opts.Context.Value(codecsKey{}); v != nil {
|
||||
@@ -260,7 +295,7 @@ func (g *grpcClient) Options() client.Options {
|
||||
}
|
||||
|
||||
func (g *grpcClient) NewMessage(topic string, msg interface{}, opts ...client.MessageOption) client.Message {
|
||||
return newGRPCPublication(topic, msg, "application/octet-stream")
|
||||
return newGRPCPublication(topic, msg, g.opts.ContentType, opts...)
|
||||
}
|
||||
|
||||
func (g *grpcClient) NewRequest(service, method string, req interface{}, reqOpts ...client.RequestOption) client.Request {
|
||||
|
@@ -45,7 +45,7 @@ func TestGRPCClient(t *testing.T) {
|
||||
|
||||
// register service
|
||||
r.Register(®istry.Service{
|
||||
Name: "test",
|
||||
Name: "helloworld",
|
||||
Version: "test",
|
||||
Nodes: []*registry.Node{
|
||||
®istry.Node{
|
||||
@@ -73,7 +73,7 @@ func TestGRPCClient(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, method := range testMethods {
|
||||
req := c.NewRequest("test", method, &pb.HelloRequest{
|
||||
req := c.NewRequest("helloworld", method, &pb.HelloRequest{
|
||||
Name: "John",
|
||||
})
|
||||
|
||||
|
@@ -2,7 +2,6 @@ package grpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
@@ -15,32 +14,28 @@ type grpcRequest struct {
|
||||
contentType string
|
||||
request interface{}
|
||||
opts client.RequestOptions
|
||||
codec codec.Codec
|
||||
}
|
||||
|
||||
func methodToGRPC(method string, request interface{}) string {
|
||||
// service Struct.Method /service.Struct/Method
|
||||
func methodToGRPC(service, method string) string {
|
||||
// no method or already grpc method
|
||||
if len(method) == 0 || method[0] == '/' {
|
||||
return method
|
||||
}
|
||||
// can't operate on nil request
|
||||
t := reflect.TypeOf(request)
|
||||
if t == nil {
|
||||
return method
|
||||
}
|
||||
// dereference
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
// get package name
|
||||
pParts := strings.Split(t.PkgPath(), "/")
|
||||
pkg := pParts[len(pParts)-1]
|
||||
|
||||
// assume method is Foo.Bar
|
||||
mParts := strings.Split(method, ".")
|
||||
if len(mParts) != 2 {
|
||||
return method
|
||||
}
|
||||
|
||||
if len(service) == 0 {
|
||||
return fmt.Sprintf("/%s/%s", mParts[0], mParts[1])
|
||||
}
|
||||
|
||||
// return /pkg.Foo/Bar
|
||||
return fmt.Sprintf("/%s.%s/%s", pkg, mParts[0], mParts[1])
|
||||
return fmt.Sprintf("/%s.%s/%s", service, mParts[0], mParts[1])
|
||||
}
|
||||
|
||||
func newGRPCRequest(service, method string, request interface{}, contentType string, reqOpts ...client.RequestOption) client.Request {
|
||||
@@ -80,7 +75,7 @@ func (g *grpcRequest) Endpoint() string {
|
||||
}
|
||||
|
||||
func (g *grpcRequest) Codec() codec.Writer {
|
||||
return nil
|
||||
return g.codec
|
||||
}
|
||||
|
||||
func (g *grpcRequest) Body() interface{} {
|
||||
|
@@ -2,45 +2,38 @@ package grpc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
pb "google.golang.org/grpc/examples/helloworld/helloworld"
|
||||
)
|
||||
|
||||
func TestMethodToGRPC(t *testing.T) {
|
||||
testData := []struct {
|
||||
service string
|
||||
method string
|
||||
expect string
|
||||
request interface{}
|
||||
}{
|
||||
{
|
||||
"helloworld",
|
||||
"Greeter.SayHello",
|
||||
"/helloworld.Greeter/SayHello",
|
||||
new(pb.HelloRequest),
|
||||
},
|
||||
{
|
||||
"helloworld",
|
||||
"/helloworld.Greeter/SayHello",
|
||||
"/helloworld.Greeter/SayHello",
|
||||
new(pb.HelloRequest),
|
||||
},
|
||||
{
|
||||
"",
|
||||
"/helloworld.Greeter/SayHello",
|
||||
"/helloworld.Greeter/SayHello",
|
||||
},
|
||||
{
|
||||
"",
|
||||
"Greeter.SayHello",
|
||||
"/helloworld.Greeter/SayHello",
|
||||
pb.HelloRequest{},
|
||||
},
|
||||
{
|
||||
"/helloworld.Greeter/SayHello",
|
||||
"/helloworld.Greeter/SayHello",
|
||||
pb.HelloRequest{},
|
||||
},
|
||||
{
|
||||
"Greeter.SayHello",
|
||||
"Greeter.SayHello",
|
||||
nil,
|
||||
"/Greeter/SayHello",
|
||||
},
|
||||
}
|
||||
|
||||
for _, d := range testData {
|
||||
method := methodToGRPC(d.method, d.request)
|
||||
method := methodToGRPC(d.service, d.method)
|
||||
if method != d.expect {
|
||||
t.Fatalf("expected %s got %s", d.expect, method)
|
||||
}
|
||||
|
44
client/grpc/response.go
Normal file
44
client/grpc/response.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/codec/bytes"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
)
|
||||
|
||||
type response struct {
|
||||
conn *grpc.ClientConn
|
||||
stream grpc.ClientStream
|
||||
codec encoding.Codec
|
||||
gcodec codec.Codec
|
||||
}
|
||||
|
||||
// Read the response
|
||||
func (r *response) Codec() codec.Reader {
|
||||
return r.gcodec
|
||||
}
|
||||
|
||||
// read the header
|
||||
func (r *response) Header() map[string]string {
|
||||
md, err := r.stream.Header()
|
||||
if err != nil {
|
||||
return map[string]string{}
|
||||
}
|
||||
hdr := make(map[string]string)
|
||||
for k, v := range md {
|
||||
hdr[k] = strings.Join(v, ",")
|
||||
}
|
||||
return hdr
|
||||
}
|
||||
|
||||
// Read the undecoded response
|
||||
func (r *response) Read() ([]byte, error) {
|
||||
f := &bytes.Frame{}
|
||||
if err := r.gcodec.ReadBody(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f.Data, nil
|
||||
}
|
@@ -12,11 +12,12 @@ import (
|
||||
// Implements the streamer interface
|
||||
type grpcStream struct {
|
||||
sync.RWMutex
|
||||
err error
|
||||
conn *grpc.ClientConn
|
||||
request client.Request
|
||||
stream grpc.ClientStream
|
||||
context context.Context
|
||||
err error
|
||||
conn *grpc.ClientConn
|
||||
stream grpc.ClientStream
|
||||
request client.Request
|
||||
response client.Response
|
||||
context context.Context
|
||||
}
|
||||
|
||||
func (g *grpcStream) Context() context.Context {
|
||||
@@ -28,7 +29,7 @@ func (g *grpcStream) Request() client.Request {
|
||||
}
|
||||
|
||||
func (g *grpcStream) Response() client.Response {
|
||||
return nil
|
||||
return g.response
|
||||
}
|
||||
|
||||
func (g *grpcStream) Send(msg interface{}) error {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// Package rpc provides an rpc client
|
||||
package rpc
|
||||
// Package mucp provides an mucp client
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/client"
|
203
client/proto/client.micro.go
Normal file
203
client/proto/client.micro.go
Normal file
@@ -0,0 +1,203 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: micro/go-micro/client/proto/client.proto
|
||||
|
||||
package go_micro_client
|
||||
|
||||
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 Micro service
|
||||
|
||||
type MicroService 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)
|
||||
// Publish publishes a message and returns an empty Message
|
||||
Publish(ctx context.Context, in *Message, opts ...client.CallOption) (*Message, error)
|
||||
}
|
||||
|
||||
type microService struct {
|
||||
c client.Client
|
||||
name string
|
||||
}
|
||||
|
||||
func NewMicroService(name string, c client.Client) MicroService {
|
||||
if c == nil {
|
||||
c = client.NewClient()
|
||||
}
|
||||
if len(name) == 0 {
|
||||
name = "go.micro.client"
|
||||
}
|
||||
return µService{
|
||||
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)
|
||||
out := new(Response)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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{})
|
||||
stream, err := c.c.Stream(ctx, req, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return µServiceStream{stream}, nil
|
||||
}
|
||||
|
||||
type Micro_StreamService interface {
|
||||
SendMsg(interface{}) error
|
||||
RecvMsg(interface{}) error
|
||||
Close() error
|
||||
Send(*Request) error
|
||||
Recv() (*Response, error)
|
||||
}
|
||||
|
||||
type microServiceStream struct {
|
||||
stream client.Stream
|
||||
}
|
||||
|
||||
func (x *microServiceStream) Close() error {
|
||||
return x.stream.Close()
|
||||
}
|
||||
|
||||
func (x *microServiceStream) SendMsg(m interface{}) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (x *microServiceStream) RecvMsg(m interface{}) error {
|
||||
return x.stream.Recv(m)
|
||||
}
|
||||
|
||||
func (x *microServiceStream) Send(m *Request) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (x *microServiceStream) Recv() (*Response, error) {
|
||||
m := new(Response)
|
||||
err := x.stream.Recv(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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)
|
||||
out := new(Message)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for Micro service
|
||||
|
||||
type MicroHandler 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
|
||||
// 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 {
|
||||
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
|
||||
}
|
||||
h := µHandler{hdlr}
|
||||
return s.Handle(s.NewHandler(&Micro{h}, opts...))
|
||||
}
|
||||
|
||||
type microHandler struct {
|
||||
MicroHandler
|
||||
}
|
||||
|
||||
func (h *microHandler) Call(ctx context.Context, in *Request, out *Response) error {
|
||||
return h.MicroHandler.Call(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *microHandler) Stream(ctx context.Context, stream server.Stream) error {
|
||||
return h.MicroHandler.Stream(ctx, µStreamStream{stream})
|
||||
}
|
||||
|
||||
type Micro_StreamStream interface {
|
||||
SendMsg(interface{}) error
|
||||
RecvMsg(interface{}) error
|
||||
Close() error
|
||||
Send(*Response) error
|
||||
Recv() (*Request, error)
|
||||
}
|
||||
|
||||
type microStreamStream struct {
|
||||
stream server.Stream
|
||||
}
|
||||
|
||||
func (x *microStreamStream) Close() error {
|
||||
return x.stream.Close()
|
||||
}
|
||||
|
||||
func (x *microStreamStream) SendMsg(m interface{}) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (x *microStreamStream) RecvMsg(m interface{}) error {
|
||||
return x.stream.Recv(m)
|
||||
}
|
||||
|
||||
func (x *microStreamStream) Send(m *Response) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
||||
func (x *microStreamStream) Recv() (*Request, error) {
|
||||
m := new(Request)
|
||||
if err := x.stream.Recv(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (h *microHandler) Publish(ctx context.Context, in *Message, out *Message) error {
|
||||
return h.MicroHandler.Publish(ctx, in, out)
|
||||
}
|
388
client/proto/client.pb.go
Normal file
388
client/proto/client.pb.go
Normal file
@@ -0,0 +1,388 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: micro/go-micro/client/proto/client.proto
|
||||
|
||||
package go_micro_client
|
||||
|
||||
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 Request 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"`
|
||||
ContentType string `protobuf:"bytes,3,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"`
|
||||
Body []byte `protobuf:"bytes,4,opt,name=body,proto3" json:"body,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
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_7d733ae29171347b, []int{0}
|
||||
}
|
||||
|
||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Request.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Request.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Request) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Request.Merge(m, src)
|
||||
}
|
||||
func (m *Request) XXX_Size() int {
|
||||
return xxx_messageInfo_Request.Size(m)
|
||||
}
|
||||
func (m *Request) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Request.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Request proto.InternalMessageInfo
|
||||
|
||||
func (m *Request) GetService() string {
|
||||
if m != nil {
|
||||
return m.Service
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Request) GetEndpoint() string {
|
||||
if m != nil {
|
||||
return m.Endpoint
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Request) GetContentType() string {
|
||||
if m != nil {
|
||||
return m.ContentType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Request) GetBody() []byte {
|
||||
if m != nil {
|
||||
return m.Body
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
Body []byte `protobuf:"bytes,1,opt,name=body,proto3" json:"body,omitempty"`
|
||||
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_7d733ae29171347b, []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
|
||||
|
||||
func (m *Response) GetBody() []byte {
|
||||
if m != nil {
|
||||
return m.Body
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
Topic string `protobuf:"bytes,1,opt,name=topic,proto3" json:"topic,omitempty"`
|
||||
ContentType string `protobuf:"bytes,2,opt,name=content_type,json=contentType,proto3" json:"content_type,omitempty"`
|
||||
Body []byte `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Message) Reset() { *m = Message{} }
|
||||
func (m *Message) String() string { return proto.CompactTextString(m) }
|
||||
func (*Message) ProtoMessage() {}
|
||||
func (*Message) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_7d733ae29171347b, []int{2}
|
||||
}
|
||||
|
||||
func (m *Message) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Message.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Message.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Message) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Message.Merge(m, src)
|
||||
}
|
||||
func (m *Message) XXX_Size() int {
|
||||
return xxx_messageInfo_Message.Size(m)
|
||||
}
|
||||
func (m *Message) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Message.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Message proto.InternalMessageInfo
|
||||
|
||||
func (m *Message) GetTopic() string {
|
||||
if m != nil {
|
||||
return m.Topic
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Message) GetContentType() string {
|
||||
if m != nil {
|
||||
return m.ContentType
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Message) GetBody() []byte {
|
||||
if m != nil {
|
||||
return m.Body
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*Request)(nil), "go.micro.client.Request")
|
||||
proto.RegisterType((*Response)(nil), "go.micro.client.Response")
|
||||
proto.RegisterType((*Message)(nil), "go.micro.client.Message")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("micro/go-micro/client/proto/client.proto", fileDescriptor_7d733ae29171347b)
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
// MicroClient is the client API for Micro 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 {
|
||||
// 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)
|
||||
// Publish publishes a message and returns an empty Message
|
||||
Publish(ctx context.Context, in *Message, opts ...grpc.CallOption) (*Message, error)
|
||||
}
|
||||
|
||||
type microClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewMicroClient(cc *grpc.ClientConn) MicroClient {
|
||||
return µClient{cc}
|
||||
}
|
||||
|
||||
func (c *microClient) 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...)
|
||||
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...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := µStreamClient{stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type Micro_StreamClient interface {
|
||||
Send(*Request) error
|
||||
Recv() (*Response, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type microStreamClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *microStreamClient) Send(m *Request) error {
|
||||
return x.ClientStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *microStreamClient) Recv() (*Response, error) {
|
||||
m := new(Response)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *microClient) 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...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// MicroServer is the server API for Micro service.
|
||||
type MicroServer interface {
|
||||
// Call allows a single request to be made
|
||||
Call(context.Context, *Request) (*Response, error)
|
||||
// Stream is a bidirectional stream
|
||||
Stream(Micro_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 _Micro_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)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.client.Micro/Call",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MicroServer).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})
|
||||
}
|
||||
|
||||
type Micro_StreamServer interface {
|
||||
Send(*Response) error
|
||||
Recv() (*Request, error)
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type microStreamServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *microStreamServer) Send(m *Response) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *microStreamServer) Recv() (*Request, error) {
|
||||
m := new(Request)
|
||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func _Micro_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)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.client.Micro/Publish",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(MicroServer).Publish(ctx, req.(*Message))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Micro_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "go.micro.client.Micro",
|
||||
HandlerType: (*MicroServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Call",
|
||||
Handler: _Micro_Call_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Publish",
|
||||
Handler: _Micro_Publish_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "Stream",
|
||||
Handler: _Micro_Stream_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "micro/go-micro/client/proto/client.proto",
|
||||
}
|
30
client/proto/client.proto
Normal file
30
client/proto/client.proto
Normal file
@@ -0,0 +1,30 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package go.micro.client;
|
||||
|
||||
// Micro is the micro client interface
|
||||
service Micro {
|
||||
// Call allows a single request to be made
|
||||
rpc Call(Request) returns (Response) {};
|
||||
// Stream is a bidirectional stream
|
||||
rpc Stream(stream Request) returns (stream Response) {};
|
||||
// Publish publishes a message and returns an empty Message
|
||||
rpc Publish(Message) returns (Message) {};
|
||||
}
|
||||
|
||||
message Request {
|
||||
string service = 1;
|
||||
string endpoint = 2;
|
||||
string content_type = 3;
|
||||
bytes body = 4;
|
||||
}
|
||||
|
||||
message Response {
|
||||
bytes body = 1;
|
||||
}
|
||||
|
||||
message Message {
|
||||
string topic = 1;
|
||||
string content_type = 2;
|
||||
bytes body = 3;
|
||||
}
|
@@ -567,5 +567,5 @@ func (r *rpcClient) NewRequest(service, method string, request interface{}, reqO
|
||||
}
|
||||
|
||||
func (r *rpcClient) String() string {
|
||||
return "rpc"
|
||||
return "mucp"
|
||||
}
|
||||
|
@@ -13,8 +13,9 @@ import (
|
||||
|
||||
func newTestRegistry() registry.Registry {
|
||||
r := memory.NewRegistry()
|
||||
r.(*memory.Registry).Setup()
|
||||
return r
|
||||
reg := r.(*memory.Registry)
|
||||
reg.Services = testData
|
||||
return reg
|
||||
}
|
||||
|
||||
func TestCallAddress(t *testing.T) {
|
||||
|
12
cmd/cmd.go
12
cmd/cmd.go
@@ -11,7 +11,11 @@ import (
|
||||
|
||||
"github.com/micro/cli"
|
||||
"github.com/micro/go-micro/client"
|
||||
cgrpc "github.com/micro/go-micro/client/grpc"
|
||||
cmucp "github.com/micro/go-micro/client/mucp"
|
||||
"github.com/micro/go-micro/server"
|
||||
sgrpc "github.com/micro/go-micro/server/grpc"
|
||||
smucp "github.com/micro/go-micro/server/mucp"
|
||||
"github.com/micro/go-micro/util/log"
|
||||
|
||||
// brokers
|
||||
@@ -176,7 +180,9 @@ var (
|
||||
}
|
||||
|
||||
DefaultClients = map[string]func(...client.Option) client.Client{
|
||||
"rpc": client.NewClient,
|
||||
"rpc": client.NewClient,
|
||||
"mucp": cmucp.NewClient,
|
||||
"grpc": cgrpc.NewClient,
|
||||
}
|
||||
|
||||
DefaultRegistries = map[string]func(...registry.Option) registry.Registry{
|
||||
@@ -194,7 +200,9 @@ var (
|
||||
}
|
||||
|
||||
DefaultServers = map[string]func(...server.Option) server.Server{
|
||||
"rpc": server.NewServer,
|
||||
"rpc": server.NewServer,
|
||||
"mucp": smucp.NewServer,
|
||||
"grpc": sgrpc.NewServer,
|
||||
}
|
||||
|
||||
DefaultTransports = map[string]func(...transport.Option) transport.Transport{
|
||||
|
@@ -5,6 +5,8 @@ import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"github.com/golang/protobuf/jsonpb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/micro/go-micro/codec"
|
||||
)
|
||||
|
||||
@@ -22,6 +24,9 @@ func (c *Codec) ReadBody(b interface{}) error {
|
||||
if b == nil {
|
||||
return nil
|
||||
}
|
||||
if pb, ok := b.(proto.Message); ok {
|
||||
return jsonpb.UnmarshalNext(c.Decoder, pb)
|
||||
}
|
||||
return c.Decoder.Decode(b)
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,9 @@ package json
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/golang/protobuf/jsonpb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
type Marshaler struct{}
|
||||
@@ -11,6 +14,9 @@ func (j Marshaler) Marshal(v interface{}) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (j Marshaler) Unmarshal(d []byte, v interface{}) error {
|
||||
if pb, ok := v.(proto.Message); ok {
|
||||
return jsonpb.UnmarshalString(string(d), pb)
|
||||
}
|
||||
return json.Unmarshal(d, v)
|
||||
}
|
||||
|
||||
|
@@ -30,6 +30,9 @@ func (c *Codec) ReadBody(b interface{}) error {
|
||||
}
|
||||
|
||||
switch b.(type) {
|
||||
case *string:
|
||||
v := b.(*string)
|
||||
*v = string(buf)
|
||||
case *[]byte:
|
||||
v := b.(*[]byte)
|
||||
*v = buf
|
||||
@@ -51,6 +54,12 @@ func (c *Codec) Write(m *codec.Message, b interface{}) error {
|
||||
case *[]byte:
|
||||
ve := b.(*[]byte)
|
||||
v = *ve
|
||||
case *string:
|
||||
ve := b.(*string)
|
||||
v = []byte(*ve)
|
||||
case string:
|
||||
ve := b.(string)
|
||||
v = []byte(ve)
|
||||
case []byte:
|
||||
v = b.([]byte)
|
||||
default:
|
||||
@@ -65,7 +74,7 @@ func (c *Codec) Close() error {
|
||||
}
|
||||
|
||||
func (c *Codec) String() string {
|
||||
return "bytes"
|
||||
return "text"
|
||||
}
|
||||
|
||||
func NewCodec(c io.ReadWriteCloser) codec.Codec {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package memory
|
||||
package micro
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/registry"
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
var (
|
||||
// mock data
|
||||
Data = map[string][]*registry.Service{
|
||||
testData = map[string][]*registry.Service{
|
||||
"foo": []*registry.Service{
|
||||
{
|
||||
Name: "foo",
|
@@ -4,7 +4,7 @@ The consul source reads config from consul key/values
|
||||
|
||||
## Consul Format
|
||||
|
||||
The consul source expects keys under the default prefix `/micro/config`
|
||||
The consul source expects keys under the default prefix `micro/config`
|
||||
|
||||
Values are expected to be json
|
||||
|
||||
@@ -29,8 +29,8 @@ Specify source with data
|
||||
consulSource := consul.NewSource(
|
||||
// optionally specify consul address; default to localhost:8500
|
||||
consul.WithAddress("10.0.0.10:8500"),
|
||||
// optionally specify prefix; defaults to /micro/config
|
||||
consul.WithPrefix("/my/prefix"),
|
||||
// optionally specify prefix; defaults to micro/config
|
||||
consul.WithPrefix("my/prefix"),
|
||||
// optionally strip the provided prefix from the keys, defaults to false
|
||||
consul.StripPrefix(true),
|
||||
)
|
||||
|
@@ -21,7 +21,7 @@ type consul struct {
|
||||
var (
|
||||
// DefaultPrefix is the prefix that consul keys will be assumed to have if you
|
||||
// haven't specified one
|
||||
DefaultPrefix = "/micro/config/"
|
||||
DefaultPrefix = "micro/config/"
|
||||
)
|
||||
|
||||
func (c *consul) Read() (*source.ChangeSet, error) {
|
||||
|
@@ -1,51 +0,0 @@
|
||||
# Etcd Source
|
||||
|
||||
The etcd source reads config from etcd key/values
|
||||
|
||||
This source supports etcd version 3 and beyond.
|
||||
|
||||
## Etcd Format
|
||||
|
||||
The etcd source expects keys under the default prefix `/micro/config` (prefix can be changed)
|
||||
|
||||
Values are expected to be JSON
|
||||
|
||||
```
|
||||
// set database
|
||||
etcdctl put /micro/config/database '{"address": "10.0.0.1", "port": 3306}'
|
||||
// set cache
|
||||
etcdctl put /micro/config/cache '{"address": "10.0.0.2", "port": 6379}'
|
||||
```
|
||||
|
||||
Keys are split on `/` so access becomes
|
||||
|
||||
```
|
||||
conf.Get("micro", "config", "database")
|
||||
```
|
||||
|
||||
## New Source
|
||||
|
||||
Specify source with data
|
||||
|
||||
```go
|
||||
etcdSource := etcd.NewSource(
|
||||
// optionally specify etcd address; default to localhost:8500
|
||||
etcd.WithAddress("10.0.0.10:8500"),
|
||||
// optionally specify prefix; defaults to /micro/config
|
||||
etcd.WithPrefix("/my/prefix"),
|
||||
// optionally strip the provided prefix from the keys, defaults to false
|
||||
etcd.StripPrefix(true),
|
||||
)
|
||||
```
|
||||
|
||||
## Load Source
|
||||
|
||||
Load the source into config
|
||||
|
||||
```go
|
||||
// Create new config
|
||||
conf := config.NewConfig()
|
||||
|
||||
// Load file source
|
||||
conf.Load(etcdSource)
|
||||
```
|
@@ -1,134 +0,0 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/config/source"
|
||||
cetcd "go.etcd.io/etcd/clientv3"
|
||||
"go.etcd.io/etcd/mvcc/mvccpb"
|
||||
)
|
||||
|
||||
// Currently a single etcd reader
|
||||
type etcd struct {
|
||||
prefix string
|
||||
stripPrefix string
|
||||
opts source.Options
|
||||
client *cetcd.Client
|
||||
cerr error
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultPrefix = "/micro/config/"
|
||||
)
|
||||
|
||||
func (c *etcd) Read() (*source.ChangeSet, error) {
|
||||
if c.cerr != nil {
|
||||
return nil, c.cerr
|
||||
}
|
||||
|
||||
rsp, err := c.client.Get(context.Background(), c.prefix, cetcd.WithPrefix())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rsp == nil || len(rsp.Kvs) == 0 {
|
||||
return nil, fmt.Errorf("source not found: %s", c.prefix)
|
||||
}
|
||||
|
||||
var kvs []*mvccpb.KeyValue
|
||||
for _, v := range rsp.Kvs {
|
||||
kvs = append(kvs, (*mvccpb.KeyValue)(v))
|
||||
}
|
||||
|
||||
data := makeMap(c.opts.Encoder, kvs, c.stripPrefix)
|
||||
|
||||
b, err := c.opts.Encoder.Encode(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading source: %v", err)
|
||||
}
|
||||
|
||||
cs := &source.ChangeSet{
|
||||
Timestamp: time.Now(),
|
||||
Source: c.String(),
|
||||
Data: b,
|
||||
Format: c.opts.Encoder.String(),
|
||||
}
|
||||
cs.Checksum = cs.Sum()
|
||||
|
||||
return cs, nil
|
||||
}
|
||||
|
||||
func (c *etcd) String() string {
|
||||
return "etcd"
|
||||
}
|
||||
|
||||
func (c *etcd) Watch() (source.Watcher, error) {
|
||||
if c.cerr != nil {
|
||||
return nil, c.cerr
|
||||
}
|
||||
cs, err := c.Read()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWatcher(c.prefix, c.stripPrefix, c.client.Watcher, cs, c.opts)
|
||||
}
|
||||
|
||||
func NewSource(opts ...source.Option) source.Source {
|
||||
options := source.NewOptions(opts...)
|
||||
|
||||
var endpoints []string
|
||||
|
||||
// check if there are any addrs
|
||||
addrs, ok := options.Context.Value(addressKey{}).([]string)
|
||||
if ok {
|
||||
for _, a := range addrs {
|
||||
addr, port, err := net.SplitHostPort(a)
|
||||
if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
|
||||
port = "2379"
|
||||
addr = a
|
||||
endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port))
|
||||
} else if err == nil {
|
||||
endpoints = append(endpoints, fmt.Sprintf("%s:%s", addr, port))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(endpoints) == 0 {
|
||||
endpoints = []string{"localhost:2379"}
|
||||
}
|
||||
|
||||
config := cetcd.Config{
|
||||
Endpoints: endpoints,
|
||||
}
|
||||
|
||||
u, ok := options.Context.Value(authKey{}).(*authCreds)
|
||||
if ok {
|
||||
config.Username = u.Username
|
||||
config.Password = u.Password
|
||||
}
|
||||
|
||||
// use default config
|
||||
client, err := cetcd.New(config)
|
||||
|
||||
prefix := DefaultPrefix
|
||||
sp := ""
|
||||
f, ok := options.Context.Value(prefixKey{}).(string)
|
||||
if ok {
|
||||
prefix = f
|
||||
}
|
||||
|
||||
if b, ok := options.Context.Value(stripPrefixKey{}).(bool); ok && b {
|
||||
sp = prefix
|
||||
}
|
||||
|
||||
return &etcd{
|
||||
prefix: prefix,
|
||||
stripPrefix: sp,
|
||||
opts: options,
|
||||
client: client,
|
||||
cerr: err,
|
||||
}
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/config/source"
|
||||
)
|
||||
|
||||
type addressKey struct{}
|
||||
type prefixKey struct{}
|
||||
type stripPrefixKey struct{}
|
||||
type authKey struct{}
|
||||
|
||||
type authCreds struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// WithAddress sets the consul address
|
||||
func WithAddress(a ...string) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, addressKey{}, a)
|
||||
}
|
||||
}
|
||||
|
||||
// WithPrefix sets the key prefix to use
|
||||
func WithPrefix(p string) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, prefixKey{}, p)
|
||||
}
|
||||
}
|
||||
|
||||
// StripPrefix indicates whether to remove the prefix from config entries, or leave it in place.
|
||||
func StripPrefix(strip bool) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
|
||||
o.Context = context.WithValue(o.Context, stripPrefixKey{}, strip)
|
||||
}
|
||||
}
|
||||
|
||||
// Auth allows you to specify username/password
|
||||
func Auth(username, password string) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, authKey{}, &authCreds{Username: username, Password: password})
|
||||
}
|
||||
}
|
@@ -1,89 +0,0 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/micro/go-micro/config/encoder"
|
||||
"go.etcd.io/etcd/clientv3"
|
||||
"go.etcd.io/etcd/mvcc/mvccpb"
|
||||
)
|
||||
|
||||
func makeEvMap(e encoder.Encoder, data map[string]interface{}, kv []*clientv3.Event, stripPrefix string) map[string]interface{} {
|
||||
if data == nil {
|
||||
data = make(map[string]interface{})
|
||||
}
|
||||
|
||||
for _, v := range kv {
|
||||
switch mvccpb.Event_EventType(v.Type) {
|
||||
case mvccpb.DELETE:
|
||||
data = update(e, data, (*mvccpb.KeyValue)(v.Kv), "delete", stripPrefix)
|
||||
default:
|
||||
data = update(e, data, (*mvccpb.KeyValue)(v.Kv), "insert", stripPrefix)
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func makeMap(e encoder.Encoder, kv []*mvccpb.KeyValue, stripPrefix string) map[string]interface{} {
|
||||
data := make(map[string]interface{})
|
||||
|
||||
for _, v := range kv {
|
||||
data = update(e, data, v, "put", stripPrefix)
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func update(e encoder.Encoder, data map[string]interface{}, v *mvccpb.KeyValue, action, stripPrefix string) map[string]interface{} {
|
||||
// remove prefix if non empty, and ensure leading / is removed as well
|
||||
vkey := strings.TrimPrefix(strings.TrimPrefix(string(v.Key), stripPrefix), "/")
|
||||
// split on prefix
|
||||
haveSplit := strings.Contains(vkey, "/")
|
||||
keys := strings.Split(vkey, "/")
|
||||
|
||||
var vals interface{}
|
||||
e.Decode(v.Value, &vals)
|
||||
|
||||
if !haveSplit && len(keys) == 1 {
|
||||
switch action {
|
||||
case "delete":
|
||||
data = make(map[string]interface{})
|
||||
default:
|
||||
v, ok := vals.(map[string]interface{})
|
||||
if ok {
|
||||
data = v
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// set data for first iteration
|
||||
kvals := data
|
||||
// iterate the keys and make maps
|
||||
for i, k := range keys {
|
||||
kval, ok := kvals[k].(map[string]interface{})
|
||||
if !ok {
|
||||
// create next map
|
||||
kval = make(map[string]interface{})
|
||||
// set it
|
||||
kvals[k] = kval
|
||||
}
|
||||
|
||||
// last key: write vals
|
||||
if l := len(keys) - 1; i == l {
|
||||
switch action {
|
||||
case "delete":
|
||||
delete(kvals, k)
|
||||
default:
|
||||
kvals[k] = vals
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
// set kvals for next iterator
|
||||
kvals = kval
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
@@ -1,113 +0,0 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/config/source"
|
||||
cetcd "go.etcd.io/etcd/clientv3"
|
||||
)
|
||||
|
||||
type watcher struct {
|
||||
opts source.Options
|
||||
name string
|
||||
stripPrefix string
|
||||
|
||||
sync.RWMutex
|
||||
cs *source.ChangeSet
|
||||
|
||||
ch chan *source.ChangeSet
|
||||
exit chan bool
|
||||
}
|
||||
|
||||
func newWatcher(key, strip string, wc cetcd.Watcher, cs *source.ChangeSet, opts source.Options) (source.Watcher, error) {
|
||||
w := &watcher{
|
||||
opts: opts,
|
||||
name: "etcd",
|
||||
stripPrefix: strip,
|
||||
cs: cs,
|
||||
ch: make(chan *source.ChangeSet),
|
||||
exit: make(chan bool),
|
||||
}
|
||||
|
||||
ch := wc.Watch(context.Background(), key, cetcd.WithPrefix())
|
||||
|
||||
go w.run(wc, ch)
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (w *watcher) handle(evs []*cetcd.Event) {
|
||||
w.RLock()
|
||||
data := w.cs.Data
|
||||
w.RUnlock()
|
||||
|
||||
var vals map[string]interface{}
|
||||
|
||||
// unpackage existing changeset
|
||||
if err := w.opts.Encoder.Decode(data, &vals); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// update base changeset
|
||||
d := makeEvMap(w.opts.Encoder, vals, evs, w.stripPrefix)
|
||||
|
||||
// pack the changeset
|
||||
b, err := w.opts.Encoder.Encode(d)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// create new changeset
|
||||
cs := &source.ChangeSet{
|
||||
Timestamp: time.Now(),
|
||||
Source: w.name,
|
||||
Data: b,
|
||||
Format: w.opts.Encoder.String(),
|
||||
}
|
||||
cs.Checksum = cs.Sum()
|
||||
|
||||
// set base change set
|
||||
w.Lock()
|
||||
w.cs = cs
|
||||
w.Unlock()
|
||||
|
||||
// send update
|
||||
w.ch <- cs
|
||||
}
|
||||
|
||||
func (w *watcher) run(wc cetcd.Watcher, ch cetcd.WatchChan) {
|
||||
for {
|
||||
select {
|
||||
case rsp, ok := <-ch:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
w.handle(rsp.Events)
|
||||
case <-w.exit:
|
||||
wc.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) Next() (*source.ChangeSet, error) {
|
||||
select {
|
||||
case cs := <-w.ch:
|
||||
return cs, nil
|
||||
case <-w.exit:
|
||||
return nil, errors.New("watcher stopped")
|
||||
}
|
||||
}
|
||||
|
||||
func (w *watcher) Stop() error {
|
||||
select {
|
||||
case <-w.exit:
|
||||
return nil
|
||||
default:
|
||||
close(w.exit)
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -6,24 +6,26 @@ import (
|
||||
"net"
|
||||
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/micro/go-micro/sync/data"
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/data/store"
|
||||
)
|
||||
|
||||
type ckv struct {
|
||||
options.Options
|
||||
client *api.Client
|
||||
}
|
||||
|
||||
func (c *ckv) Read(key string) (*data.Record, error) {
|
||||
func (c *ckv) Read(key string) (*store.Record, error) {
|
||||
keyval, _, err := c.client.KV().Get(key, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if keyval == nil {
|
||||
return nil, data.ErrNotFound
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
|
||||
return &data.Record{
|
||||
return &store.Record{
|
||||
Key: keyval.Key,
|
||||
Value: keyval.Value,
|
||||
}, nil
|
||||
@@ -34,7 +36,7 @@ func (c *ckv) Delete(key string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *ckv) Write(record *data.Record) error {
|
||||
func (c *ckv) Write(record *store.Record) error {
|
||||
_, err := c.client.KV().Put(&api.KVPair{
|
||||
Key: record.Key,
|
||||
Value: record.Value,
|
||||
@@ -42,17 +44,17 @@ func (c *ckv) Write(record *data.Record) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *ckv) Dump() ([]*data.Record, error) {
|
||||
func (c *ckv) Dump() ([]*store.Record, error) {
|
||||
keyval, _, err := c.client.KV().List("/", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if keyval == nil {
|
||||
return nil, data.ErrNotFound
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
var vals []*data.Record
|
||||
var vals []*store.Record
|
||||
for _, keyv := range keyval {
|
||||
vals = append(vals, &data.Record{
|
||||
vals = append(vals, &store.Record{
|
||||
Key: keyv.Key,
|
||||
Value: keyv.Value,
|
||||
})
|
||||
@@ -64,22 +66,22 @@ func (c *ckv) String() string {
|
||||
return "consul"
|
||||
}
|
||||
|
||||
func NewData(opts ...data.Option) data.Data {
|
||||
var options data.Options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
func NewStore(opts ...options.Option) store.Store {
|
||||
options := options.NewOptions(opts...)
|
||||
config := api.DefaultConfig()
|
||||
|
||||
var nodes []string
|
||||
|
||||
if n, ok := options.Values().Get("store.nodes"); ok {
|
||||
nodes = n.([]string)
|
||||
}
|
||||
|
||||
// set host
|
||||
// config.Host something
|
||||
// check if there are any addrs
|
||||
if len(options.Nodes) > 0 {
|
||||
addr, port, err := net.SplitHostPort(options.Nodes[0])
|
||||
if len(nodes) > 0 {
|
||||
addr, port, err := net.SplitHostPort(nodes[0])
|
||||
if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
|
||||
port = "8500"
|
||||
config.Address = fmt.Sprintf("%s:%s", options.Nodes[0], port)
|
||||
config.Address = fmt.Sprintf("%s:%s", nodes[0], port)
|
||||
} else if err == nil {
|
||||
config.Address = fmt.Sprintf("%s:%s", addr, port)
|
||||
}
|
||||
@@ -88,6 +90,7 @@ func NewData(opts ...data.Option) data.Data {
|
||||
client, _ := api.NewClient(config)
|
||||
|
||||
return &ckv{
|
||||
client: client,
|
||||
Options: options,
|
||||
client: client,
|
||||
}
|
||||
}
|
97
data/store/memory/memory.go
Normal file
97
data/store/memory/memory.go
Normal file
@@ -0,0 +1,97 @@
|
||||
// Package memory is a in-memory store store
|
||||
package memory
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/data/store"
|
||||
)
|
||||
|
||||
type memoryStore struct {
|
||||
options.Options
|
||||
|
||||
sync.RWMutex
|
||||
values map[string]*memoryRecord
|
||||
}
|
||||
|
||||
type memoryRecord struct {
|
||||
r *store.Record
|
||||
c time.Time
|
||||
}
|
||||
|
||||
func (m *memoryStore) Dump() ([]*store.Record, error) {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
var values []*store.Record
|
||||
|
||||
for _, v := range m.values {
|
||||
// get expiry
|
||||
d := v.r.Expiry
|
||||
t := time.Since(v.c)
|
||||
|
||||
// expired
|
||||
if d > time.Duration(0) && t > d {
|
||||
continue
|
||||
}
|
||||
values = append(values, v.r)
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func (m *memoryStore) Read(key string) (*store.Record, error) {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
v, ok := m.values[key]
|
||||
if !ok {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
|
||||
// get expiry
|
||||
d := v.r.Expiry
|
||||
t := time.Since(v.c)
|
||||
|
||||
// expired
|
||||
if d > time.Duration(0) && t > d {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
|
||||
return v.r, nil
|
||||
}
|
||||
|
||||
func (m *memoryStore) Write(r *store.Record) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
// set the record
|
||||
m.values[r.Key] = &memoryRecord{
|
||||
r: r,
|
||||
c: time.Now(),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryStore) Delete(key string) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
// delete the value
|
||||
delete(m.values, key)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewStore returns a new store.Store
|
||||
func NewStore(opts ...options.Option) store.Store {
|
||||
options := options.NewOptions(opts...)
|
||||
|
||||
return &memoryStore{
|
||||
Options: options,
|
||||
values: make(map[string]*memoryRecord),
|
||||
}
|
||||
}
|
15
data/store/options.go
Normal file
15
data/store/options.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/config/options"
|
||||
)
|
||||
|
||||
// Set the nodes used to back the store
|
||||
func Nodes(a ...string) options.Option {
|
||||
return options.WithValue("store.nodes", a)
|
||||
}
|
||||
|
||||
// Prefix sets a prefix to any key ids used
|
||||
func Prefix(p string) options.Option {
|
||||
return options.WithValue("store.prefix", p)
|
||||
}
|
@@ -1,17 +1,21 @@
|
||||
// Package data is an interface for key-value storage.
|
||||
package data
|
||||
// Package store is an interface for distribute data storage.
|
||||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/config/options"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotFound = errors.New("not found")
|
||||
)
|
||||
|
||||
// Data is a data storage interface
|
||||
type Data interface {
|
||||
// Store is a data storage interface
|
||||
type Store interface {
|
||||
// embed options
|
||||
options.Options
|
||||
// Dump the known records
|
||||
Dump() ([]*Record, error)
|
||||
// Read a record with key
|
||||
@@ -24,9 +28,7 @@ type Data interface {
|
||||
|
||||
// Record represents a data record
|
||||
type Record struct {
|
||||
Key string
|
||||
Value []byte
|
||||
Expiration time.Duration
|
||||
Key string
|
||||
Value []byte
|
||||
Expiry time.Duration
|
||||
}
|
||||
|
||||
type Option func(o *Options)
|
@@ -14,7 +14,7 @@ func TestFunction(t *testing.T) {
|
||||
wg.Add(1)
|
||||
|
||||
r := memory.NewRegistry()
|
||||
r.(*memory.Registry).Setup()
|
||||
r.(*memory.Registry).Services = testData
|
||||
|
||||
// create service
|
||||
fn := NewFunction(
|
||||
|
54
go.mod
54
go.mod
@@ -3,44 +3,84 @@ module github.com/micro/go-micro
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.40.0 // indirect
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect
|
||||
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect
|
||||
github.com/armon/go-radix v1.0.0 // indirect
|
||||
github.com/beevik/ntp v0.2.0
|
||||
github.com/bitly/go-simplejson v0.5.0
|
||||
github.com/bwmarrin/discordgo v0.19.0
|
||||
github.com/coreos/etcd v3.3.13+incompatible // indirect
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect
|
||||
github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/fsouza/go-dockerclient v1.4.1
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/gliderlabs/ssh v0.2.2 // indirect
|
||||
github.com/go-log/log v0.1.0
|
||||
github.com/go-playground/locales v0.12.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.16.0 // indirect
|
||||
github.com/golang/mock v1.3.1 // indirect
|
||||
github.com/golang/protobuf v1.3.1
|
||||
github.com/google/btree v1.0.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 // indirect
|
||||
github.com/gorilla/handlers v1.4.0
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/hashicorp/consul/api v1.1.0
|
||||
github.com/hashicorp/go-immutable-radix v1.1.0 // indirect
|
||||
github.com/hashicorp/go-msgpack v0.5.5 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.5.4 // indirect
|
||||
github.com/hashicorp/go-rootcerts v1.0.1 // indirect
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 // indirect
|
||||
github.com/hashicorp/go-version v1.2.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0
|
||||
github.com/hashicorp/mdns v1.0.1 // indirect
|
||||
github.com/hashicorp/memberlist v0.1.4
|
||||
github.com/hashicorp/serf v0.8.3 // indirect
|
||||
github.com/imdario/mergo v0.3.7
|
||||
github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1
|
||||
github.com/json-iterator/go v1.1.6
|
||||
github.com/kisielk/errcheck v1.2.0 // indirect
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
github.com/kr/pty v1.1.5 // indirect
|
||||
github.com/leodido/go-urn v1.1.0 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.11.2
|
||||
github.com/marten-seemann/qtls v0.2.4 // indirect
|
||||
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.1.0
|
||||
github.com/miekg/dns v1.1.14 // 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/nats-io/nats.go v1.8.1
|
||||
github.com/nlopes/slack v0.5.0
|
||||
github.com/olekukonko/tablewriter v0.0.1
|
||||
github.com/onsi/ginkgo v1.8.0 // indirect
|
||||
github.com/onsi/gomega v1.5.0 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/posener/complete v1.2.1 // indirect
|
||||
github.com/prometheus/common v0.6.0 // indirect
|
||||
github.com/sirupsen/logrus v1.4.2 // indirect
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
go.etcd.io/etcd v3.3.13+incompatible
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5
|
||||
golang.org/x/net v0.0.0-20190606173856-1492cefac77f
|
||||
go.opencensus.io v0.22.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522 // indirect
|
||||
golang.org/x/image v0.0.0-20190618124811-92942e4437e2 // indirect
|
||||
golang.org/x/mobile v0.0.0-20190607214518-6fa95d984e88 // indirect
|
||||
golang.org/x/mod v0.1.0 // indirect
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
|
||||
golang.org/x/sys v0.0.0-20190621062556-bf70e4678053 // indirect
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
|
||||
golang.org/x/tools v0.0.0-20190620191750-1fa568393b23 // indirect
|
||||
google.golang.org/appengine v1.6.1 // indirect
|
||||
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601 // indirect
|
||||
google.golang.org/grpc v1.21.1
|
||||
gopkg.in/go-playground/validator.v9 v9.29.0
|
||||
gopkg.in/src-d/go-git.v4 v4.11.0
|
||||
gopkg.in/src-d/go-git.v4 v4.12.0
|
||||
gopkg.in/telegram-bot-api.v4 v4.6.4
|
||||
honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b // indirect
|
||||
)
|
||||
|
197
go.sum
197
go.sum
@@ -1,16 +1,30 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM=
|
||||
github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
|
||||
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
|
||||
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
|
||||
@@ -18,11 +32,13 @@ github.com/bwmarrin/discordgo v0.19.0 h1:kMED/DB0NR1QhRcalb85w0Cu3Ep2OrGAqZH1R5a
|
||||
github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M=
|
||||
github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/coreos/etcd v3.3.13+incompatible h1:8F3hqu9fGYLBifCmRCJsicFqDx/D68Rt3q1JMazcgBQ=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc h1:TP+534wVlf61smEIq1nwLLAjQVEK2EADoW3CX9AuT+8=
|
||||
github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16 h1:dmUn0SuGx7unKFwxyeQ/oLUHhEfZosEDrpmYM+6MTuc=
|
||||
@@ -33,6 +49,8 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/emirpasic/gods v1.9.0 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo=
|
||||
github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c h1:pBgVXWDXju1m8W4lnEeIqTHPOzhTUO81a7yknM/xQR4=
|
||||
@@ -44,27 +62,43 @@ github.com/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6V
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/gliderlabs/ssh v0.1.3/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-log/log v0.1.0 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U=
|
||||
github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
|
||||
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/handlers v1.4.0 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA=
|
||||
github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
@@ -75,33 +109,51 @@ github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBt
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-immutable-radix v1.1.0 h1:vN9wG1D6KG6YHRTWr8512cxGOVgTMEfgEdSj/hr8MPc=
|
||||
github.com/hashicorp/go-immutable-radix v1.1.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=
|
||||
github.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-rootcerts v1.0.1 h1:DMo4fmknnz0E0evoNYnV48RjWndOsmd6OW+09R3cEP8=
|
||||
github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc=
|
||||
github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/memberlist v0.1.4 h1:gkyML/r71w3FL8gUi74Vk76avkj/9lYAY9lvg0OcoGs=
|
||||
github.com/hashicorp/memberlist v0.1.4/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hashicorp/serf v0.8.3 h1:MWYcmct5EtKz0efYooPcL0yNkem+7kWxqXDi/UIh+8k=
|
||||
github.com/hashicorp/serf v0.8.3/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd h1:anPrsicrIi2ColgWTVPk+TrN42hJIWlfPHSBP9S0ZkM=
|
||||
github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84=
|
||||
@@ -114,13 +166,19 @@ github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1 h1:lnrOS18wZBYrzdD
|
||||
github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1/go.mod h1:DFXrEwSRX0p/aSvxE21319menCBFeQO0jXpRj7LEZUA=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||
@@ -128,8 +186,15 @@ github.com/lucas-clemente/quic-go v0.11.2 h1:Mop0ac3zALaBR3wGs6j8OYe/tcFvFsxTUFM
|
||||
github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw=
|
||||
github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA=
|
||||
github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||
github.com/marten-seemann/qtls v0.2.4 h1:mCJ6i1jAqcsm9XODrSGvXECodoAb1STta+TkxJCwCnE=
|
||||
github.com/marten-seemann/qtls v0.2.4/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/micro/cli v0.2.0 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA=
|
||||
github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk=
|
||||
github.com/micro/mdns v0.1.0 h1:fuLybUsfynbigJmCot/54i+gwe0hpc/vtCMvWt2WfDI=
|
||||
@@ -137,11 +202,17 @@ github.com/micro/mdns v0.1.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9A
|
||||
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=
|
||||
github.com/miekg/dns v1.1.14 h1:wkQWn9wIp4mZbwW8XV6Km6owkvRPbOiV004ZM2CkGvA=
|
||||
github.com/miekg/dns v1.1.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
|
||||
github.com/mitchellh/hashstructure v1.0.0 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y=
|
||||
github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
@@ -152,6 +223,7 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ=
|
||||
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
|
||||
github.com/nats-io/nkeys v0.0.2 h1:+qM7QpgXnvDDixitZtQUBDY9w/s9mu1ghS+JIbsrx6M=
|
||||
@@ -160,9 +232,13 @@ github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/nlopes/slack v0.5.0 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0=
|
||||
github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM=
|
||||
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
|
||||
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
|
||||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
|
||||
@@ -170,6 +246,7 @@ github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM
|
||||
github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y=
|
||||
github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-buffruneio v0.2.0 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA=
|
||||
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -177,77 +254,181 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.1/go.mod h1:6gapUrK/U1TAN7ciCoNRIdVC5sbdBTUh1DKN0g6uH7E=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME=
|
||||
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
|
||||
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro=
|
||||
github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8=
|
||||
go.etcd.io/etcd v3.3.13+incompatible h1:jCejD5EMnlGxFvcGRyEV4VGlENZc7oPQX6o0t7n3xbw=
|
||||
go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
|
||||
github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70=
|
||||
github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443 h1:IcSOAf4PyMp3U3XbIEj1/xJ2BjNN2jWv7JoyOsMxXUU=
|
||||
golang.org/x/crypto v0.0.0-20190618222545-ea8f1a30c443/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190618124811-92942e4437e2/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190607214518-6fa95d984e88/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190606173856-1492cefac77f h1:IWHgpgFqnL5AhBUBZSgBdjl2vkQUEzcY+JNKWfcgAU0=
|
||||
golang.org/x/net v0.0.0-20190606173856-1492cefac77f/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190502183928-7f726cade0ab/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190607181551-461777fb6f67 h1:rJJxsykSlULwd2P2+pg/rtnwN2FrWp4IuCxOSyS0V00=
|
||||
golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180903190138-2b024373dcd9/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190310054646-10058d7d4faa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190621062556-bf70e4678053 h1:T0MJjz97TtCXa3ZNW2Oenb3KQWB91K965zMEbIJ4ThA=
|
||||
golang.org/x/sys v0.0.0-20190621062556-bf70e4678053/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=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190530171427-2b03ca6e44eb/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190620191750-1fa568393b23/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
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/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=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601 h1:9VBRTdmgQxbs6HE0sUnMrSWNePppAJU07NYvX5dIB04=
|
||||
google.golang.org/genproto v0.0.0-20190620144150-6af8c5fc6601/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.0 h1:5ofssLNYgAA/inWn6rTZ4juWpRJUwEnXc1LG2IeXwgQ=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.1 h1:omN5CrMrMcQ+4I8bJ0wEhOBPanIRWzFC953IiXKdYzo=
|
||||
gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git.v4 v4.11.0 h1:cJwWgJ0DXifrNrXM6RGN1Y2yR60Rr1zQ9Q5DX5S9qgU=
|
||||
gopkg.in/src-d/go-git.v4 v4.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk=
|
||||
gopkg.in/src-d/go-git.v4 v4.12.0 h1:CKgvBCJCcdfNnyXPYI4Cp8PaDDAmAPEN0CtfEdEAbd8=
|
||||
gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4=
|
||||
gopkg.in/telegram-bot-api.v4 v4.6.4 h1:hpHWhzn4jTCsAJZZ2loNKfy2QWyPDRJVl3aTFXeMW8g=
|
||||
gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
@@ -258,3 +439,7 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b/go.mod h1:JlmFZigtG9vBVR3QGIQ9g/Usz4BzH+Xm6Z8iHQWRYUw=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
|
47
network/network.go
Normal file
47
network/network.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// Package network is a package for defining a network overlay
|
||||
package network
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/config/options"
|
||||
)
|
||||
|
||||
// Network is an interface defining networks or graphs
|
||||
type Network interface {
|
||||
options.Options
|
||||
// Id of this node
|
||||
Id() uint64
|
||||
// Connect to a node
|
||||
Connect(id uint64) (Link, error)
|
||||
// Close the network connection
|
||||
Close() error
|
||||
// Accept messages on the network
|
||||
Accept() (*Message, error)
|
||||
// Send a message to the network
|
||||
Send(*Message) error
|
||||
// Retrieve list of connections
|
||||
Links() ([]Link, error)
|
||||
}
|
||||
|
||||
// Node represents a network node
|
||||
type Node interface {
|
||||
// Node is a network. Network is a node.
|
||||
Network
|
||||
}
|
||||
|
||||
// Link is a connection to another node
|
||||
type Link interface {
|
||||
// remote node
|
||||
Node
|
||||
// length of link which dictates speed
|
||||
Length() int
|
||||
// weight of link which dictates curvature
|
||||
Weight() int
|
||||
}
|
||||
|
||||
// Message is the base type for opaque data
|
||||
type Message []byte
|
||||
|
||||
var (
|
||||
// TODO: set default network
|
||||
DefaultNetwork Network
|
||||
)
|
@@ -9,8 +9,7 @@ import (
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/client/grpc"
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/codec/bytes"
|
||||
"github.com/micro/go-micro/options"
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
@@ -86,14 +85,8 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server
|
||||
}
|
||||
}
|
||||
|
||||
// read initial request
|
||||
body, err := req.Read()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create new request with raw bytes body
|
||||
creq := p.Client.NewRequest(service, endpoint, &bytes.Frame{body}, client.WithContentType(req.ContentType()))
|
||||
creq := p.Client.NewRequest(service, endpoint, nil, client.WithContentType(req.ContentType()))
|
||||
|
||||
// create new stream
|
||||
stream, err := p.Client.Stream(ctx, creq, opts...)
|
||||
|
@@ -10,8 +10,8 @@ import (
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/errors"
|
||||
"github.com/micro/go-micro/options"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/codec/bytes"
|
||||
"github.com/micro/go-micro/options"
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/proxy"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
@@ -39,6 +39,7 @@ func readLoop(r server.Request, s client.Stream) error {
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -50,6 +51,7 @@ func readLoop(r server.Request, s client.Stream) error {
|
||||
Header: hdr,
|
||||
Body: body,
|
||||
}
|
||||
|
||||
// write the raw request
|
||||
err = req.Codec().Write(msg, nil)
|
||||
if err == io.EOF {
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/client"
|
||||
"github.com/micro/go-micro/options"
|
||||
"github.com/micro/go-micro/config/options"
|
||||
"github.com/micro/go-micro/server"
|
||||
)
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
package consul
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
@@ -246,14 +245,16 @@ func (cw *consulWatcher) handle(idx uint64, data interface{}) {
|
||||
func (cw *consulWatcher) Next() (*registry.Result, error) {
|
||||
select {
|
||||
case <-cw.exit:
|
||||
return nil, errors.New("result chan closed")
|
||||
return nil, registry.ErrWatcherStopped
|
||||
case r, ok := <-cw.next:
|
||||
if !ok {
|
||||
return nil, errors.New("result chan closed")
|
||||
return nil, registry.ErrWatcherStopped
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
return nil, errors.New("result chan closed")
|
||||
// NOTE: This is a dead code path: e.g. it will never be reached
|
||||
// as we return in all previous code paths never leading to this return
|
||||
return nil, registry.ErrWatcherStopped
|
||||
}
|
||||
|
||||
func (cw *consulWatcher) Stop() {
|
||||
|
@@ -734,6 +734,12 @@ func (g *gossipRegistry) Register(s *registry.Service, opts ...registry.Register
|
||||
notify: nil,
|
||||
})
|
||||
|
||||
// send update to local watchers
|
||||
g.updates <- &update{
|
||||
Update: up,
|
||||
Service: s,
|
||||
}
|
||||
|
||||
// wait
|
||||
<-time.After(g.interval * 2)
|
||||
|
||||
@@ -770,6 +776,12 @@ func (g *gossipRegistry) Deregister(s *registry.Service) error {
|
||||
notify: nil,
|
||||
})
|
||||
|
||||
// send update to local watchers
|
||||
g.updates <- &update{
|
||||
Update: up,
|
||||
Service: s,
|
||||
}
|
||||
|
||||
// wait
|
||||
<-time.After(g.interval * 2)
|
||||
|
||||
|
@@ -115,27 +115,20 @@ func delNodes(old, del []*registry.Node) []*registry.Node {
|
||||
|
||||
func delServices(old, del []*registry.Service) []*registry.Service {
|
||||
var services []*registry.Service
|
||||
|
||||
for _, o := range old {
|
||||
srv := new(registry.Service)
|
||||
*srv = *o
|
||||
|
||||
var rem bool
|
||||
|
||||
for _, s := range del {
|
||||
if srv.Version == s.Version {
|
||||
srv.Nodes = delNodes(srv.Nodes, s.Nodes)
|
||||
|
||||
if len(srv.Nodes) == 0 {
|
||||
if o.Version == s.Version {
|
||||
s.Nodes = delNodes(s.Nodes, o.Nodes)
|
||||
if len(s.Nodes) == 0 {
|
||||
rem = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !rem {
|
||||
services = append(services, srv)
|
||||
services = append(services, o)
|
||||
}
|
||||
}
|
||||
|
||||
return services
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ var (
|
||||
timeout = time.Millisecond * 10
|
||||
)
|
||||
|
||||
/*
|
||||
// Setup sets mock data
|
||||
func (m *Registry) Setup() {
|
||||
m.Lock()
|
||||
@@ -30,6 +31,7 @@ func (m *Registry) Setup() {
|
||||
// add some memory data
|
||||
m.Services = Data
|
||||
}
|
||||
*/
|
||||
|
||||
func (m *Registry) watch(r *registry.Result) {
|
||||
var watchers []*Watcher
|
||||
|
323
router/default_router.go
Normal file
323
router/default_router.go
Normal file
@@ -0,0 +1,323 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/registry"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
var (
|
||||
// AdvertiseTick defines how often in seconds do we scal the local registry
|
||||
// to advertise the local services to the network registry
|
||||
AdvertiseTick = 5 * time.Second
|
||||
// AdvertiseTTL defines network registry TTL in seconds
|
||||
// NOTE: this is a rather arbitrary picked value subject to change
|
||||
AdvertiseTTL = 120 * time.Second
|
||||
)
|
||||
|
||||
type router struct {
|
||||
opts Options
|
||||
exit chan struct{}
|
||||
wg *sync.WaitGroup
|
||||
}
|
||||
|
||||
// newRouter creates new router and returns it
|
||||
func newRouter(opts ...Option) Router {
|
||||
// get default options
|
||||
options := DefaultOptions()
|
||||
|
||||
// apply requested options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &router{
|
||||
opts: options,
|
||||
exit: make(chan struct{}),
|
||||
wg: &sync.WaitGroup{},
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes router with given options
|
||||
func (r *router) Init(opts ...Option) error {
|
||||
for _, o := range opts {
|
||||
o(&r.opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Options returns router options
|
||||
func (r *router) Options() Options {
|
||||
return r.opts
|
||||
}
|
||||
|
||||
// ID returns router ID
|
||||
func (r *router) ID() string {
|
||||
return r.opts.ID
|
||||
}
|
||||
|
||||
// Table returns routing table
|
||||
func (r *router) Table() Table {
|
||||
return r.opts.Table
|
||||
}
|
||||
|
||||
// Address returns router's bind address
|
||||
func (r *router) Address() string {
|
||||
return r.opts.Address
|
||||
}
|
||||
|
||||
// Network returns the address router advertises to the network
|
||||
func (r *router) Network() string {
|
||||
return r.opts.Advertise
|
||||
}
|
||||
|
||||
// Advertise advertises the router routes to the network.
|
||||
// Advertise is a blocking function. It launches multiple goroutines that watch
|
||||
// service registries and advertise the router routes to other routers in the network.
|
||||
// It returns error if any of the launched goroutines fail with error.
|
||||
func (r *router) Advertise() error {
|
||||
// add local service routes into the routing table
|
||||
if err := r.addServiceRoutes(r.opts.Registry, DefaultLocalMetric); err != nil {
|
||||
return fmt.Errorf("failed adding routes for local services: %v", err)
|
||||
}
|
||||
|
||||
// add network service routes into the routing table
|
||||
if err := r.addServiceRoutes(r.opts.Network, DefaultNetworkMetric); err != nil {
|
||||
return fmt.Errorf("failed adding routes for network services: %v", err)
|
||||
}
|
||||
|
||||
node, err := r.parseToNode()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse router into service node: %v", err)
|
||||
}
|
||||
|
||||
localWatcher, err := r.opts.Registry.Watch()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create local registry watcher: %v", err)
|
||||
}
|
||||
|
||||
networkWatcher, err := r.opts.Network.Watch()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create network registry watcher: %v", err)
|
||||
}
|
||||
|
||||
// error channel collecting goroutine errors
|
||||
errChan := make(chan error, 3)
|
||||
|
||||
r.wg.Add(1)
|
||||
go func() {
|
||||
defer r.wg.Done()
|
||||
// watch local registry and register routes in routine table
|
||||
errChan <- r.manageServiceRoutes(localWatcher, DefaultLocalMetric)
|
||||
}()
|
||||
|
||||
r.wg.Add(1)
|
||||
go func() {
|
||||
defer r.wg.Done()
|
||||
// watch network registry and register routes in routine table
|
||||
errChan <- r.manageServiceRoutes(networkWatcher, DefaultNetworkMetric)
|
||||
}()
|
||||
|
||||
r.wg.Add(1)
|
||||
go func() {
|
||||
defer r.wg.Done()
|
||||
// watch local registry and advertise local service to the network
|
||||
errChan <- r.advertiseToNetwork(node)
|
||||
}()
|
||||
|
||||
return <-errChan
|
||||
}
|
||||
|
||||
// addServiceRoutes adds all services in given registry to the routing table.
|
||||
// NOTE: this is a one-off operation done when bootstrapping the routing table of the new router.
|
||||
// It returns error if either the services could not be listed or if the routes could not be added to the routing table.
|
||||
func (r *router) addServiceRoutes(reg registry.Registry, metric int) error {
|
||||
services, err := reg.ListServices()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list services: %v", err)
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
route := Route{
|
||||
Destination: service.Name,
|
||||
Router: r,
|
||||
Network: r.opts.Advertise,
|
||||
Metric: metric,
|
||||
}
|
||||
if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute {
|
||||
return fmt.Errorf("error adding route for service: %s", service.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseToNode parses router into registry.Node and returns the result.
|
||||
// It returns error if the router network address could not be parsed into host and port.
|
||||
func (r *router) parseToNode() (*registry.Node, error) {
|
||||
// split router address to host and port part
|
||||
addr, portStr, err := net.SplitHostPort(r.opts.Advertise)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse router address: %v", err)
|
||||
}
|
||||
|
||||
// try to parse network port into integer
|
||||
port, err := strconv.Atoi(portStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse router network address: %v", err)
|
||||
}
|
||||
|
||||
node := ®istry.Node{
|
||||
Id: r.opts.ID,
|
||||
Address: addr,
|
||||
Port: port,
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
||||
// advertiseToNetwork periodically scans local registry and registers (i.e. advertises) all the local services in the network registry.
|
||||
// It returns error if either the local services failed to be listed or if it fails to register local service in network registry.
|
||||
func (r *router) advertiseToNetwork(node *registry.Node) error {
|
||||
// ticker to periodically scan the local registry
|
||||
ticker := time.NewTicker(AdvertiseTick)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-r.exit:
|
||||
return nil
|
||||
case <-ticker.C:
|
||||
// list all local services
|
||||
services, err := r.opts.Registry.ListServices()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list local services: %v", err)
|
||||
}
|
||||
// loop through all registered local services and register them in the network registry
|
||||
for _, service := range services {
|
||||
svc := ®istry.Service{
|
||||
Name: service.Name,
|
||||
Nodes: []*registry.Node{node},
|
||||
}
|
||||
// register the local service in the network registry
|
||||
if err := r.opts.Network.Register(svc, registry.RegisterTTL(AdvertiseTTL)); err != nil {
|
||||
return fmt.Errorf("failed to register service %s in network registry: %v", svc.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// manageServiceRoutes watches services in given registry and updates the routing table accordingly.
|
||||
// It returns error if the service registry watcher has stopped or if the routing table failed to be updated.
|
||||
func (r *router) manageServiceRoutes(w registry.Watcher, metric int) error {
|
||||
// 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 r.wg.Done()
|
||||
<-r.exit
|
||||
w.Stop()
|
||||
}()
|
||||
|
||||
var watchErr error
|
||||
|
||||
for {
|
||||
res, err := w.Next()
|
||||
if err == registry.ErrWatcherStopped {
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
watchErr = err
|
||||
break
|
||||
}
|
||||
|
||||
route := Route{
|
||||
Destination: res.Service.Name,
|
||||
Router: r,
|
||||
Network: r.opts.Advertise,
|
||||
Metric: metric,
|
||||
}
|
||||
|
||||
switch res.Action {
|
||||
case "create":
|
||||
if len(res.Service.Nodes) > 0 {
|
||||
// only return error if the route is not duplicate, but something else has failed
|
||||
if err := r.opts.Table.Add(route); err != nil && err != ErrDuplicateRoute {
|
||||
return fmt.Errorf("failed to add route for service: %v", res.Service.Name)
|
||||
}
|
||||
}
|
||||
case "delete":
|
||||
if len(res.Service.Nodes) < 1 {
|
||||
// only return error if the route is present in the table, but something else has failed
|
||||
if err := r.opts.Table.Delete(route); err != nil && err != ErrRouteNotFound {
|
||||
return fmt.Errorf("failed to delete route for service: %v", res.Service.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return watchErr
|
||||
}
|
||||
|
||||
// Stop stops the router
|
||||
func (r *router) Stop() error {
|
||||
// notify all goroutines to finish
|
||||
close(r.exit)
|
||||
|
||||
// wait for all goroutines to finish
|
||||
r.wg.Wait()
|
||||
|
||||
// NOTE: we need a more efficient way of doing this e.g. network routes
|
||||
// should ideally be autodeleted when the router stops gossiping
|
||||
query := NewQuery(QueryRouter(r), QueryNetwork(r.opts.Advertise))
|
||||
routes, err := r.opts.Table.Lookup(query)
|
||||
if err != nil && err != ErrRouteNotFound {
|
||||
return fmt.Errorf("failed to lookup routes for router %s: %v", r.opts.ID, err)
|
||||
}
|
||||
|
||||
// parse router to registry.Node
|
||||
node, err := r.parseToNode()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse router into service node: %v", err)
|
||||
}
|
||||
|
||||
for _, route := range routes {
|
||||
service := ®istry.Service{
|
||||
Name: route.Destination,
|
||||
Nodes: []*registry.Node{node},
|
||||
}
|
||||
if err := r.opts.Network.Deregister(service); err != nil {
|
||||
return fmt.Errorf("failed to deregister service %s from network registry: %v", service.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// String prints debugging information about router
|
||||
func (r *router) String() string {
|
||||
sb := &strings.Builder{}
|
||||
|
||||
table := tablewriter.NewWriter(sb)
|
||||
table.SetHeader([]string{"ID", "Address", "Network", "Table"})
|
||||
|
||||
data := []string{
|
||||
r.opts.ID,
|
||||
r.opts.Address,
|
||||
r.opts.Advertise,
|
||||
fmt.Sprintf("%d", r.opts.Table.Size()),
|
||||
}
|
||||
table.Append(data)
|
||||
|
||||
// render table into sb
|
||||
table.Render()
|
||||
|
||||
return sb.String()
|
||||
}
|
289
router/default_table.go
Normal file
289
router/default_table.go
Normal file
@@ -0,0 +1,289 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash"
|
||||
"hash/fnv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
// TableOptions are routing table options
|
||||
// TODO: table options TBD in the future
|
||||
type TableOptions struct{}
|
||||
|
||||
// table is in memory routing table
|
||||
type table struct {
|
||||
// opts are table options
|
||||
opts TableOptions
|
||||
// m stores routing table map
|
||||
m map[string]map[uint64]Route
|
||||
// h hashes route entries
|
||||
h hash.Hash64
|
||||
// w is a list of table watchers
|
||||
w map[string]*tableWatcher
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// newTable creates in memory routing table and returns it
|
||||
func newTable(opts ...TableOption) Table {
|
||||
// default options
|
||||
var options TableOptions
|
||||
|
||||
// apply requested options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
h := fnv.New64()
|
||||
h.Reset()
|
||||
|
||||
return &table{
|
||||
opts: options,
|
||||
m: make(map[string]map[uint64]Route),
|
||||
w: make(map[string]*tableWatcher),
|
||||
h: h,
|
||||
}
|
||||
}
|
||||
|
||||
// Init initializes routing table with options
|
||||
func (t *table) Init(opts ...TableOption) error {
|
||||
for _, o := range opts {
|
||||
o(&t.opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Options returns routing table options
|
||||
func (t *table) Options() TableOptions {
|
||||
return t.opts
|
||||
}
|
||||
|
||||
// Add adds a route to the routing table
|
||||
func (t *table) Add(r Route) error {
|
||||
destAddr := r.Destination
|
||||
sum := t.hash(r)
|
||||
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
// check if the destination has any routes in the table
|
||||
if _, ok := t.m[destAddr]; !ok {
|
||||
t.m[destAddr] = make(map[uint64]Route)
|
||||
t.m[destAddr][sum] = r
|
||||
go t.sendEvent(&Event{Type: CreateEvent, Route: r})
|
||||
return nil
|
||||
}
|
||||
|
||||
// add new route to the table for the given destination
|
||||
if _, ok := t.m[destAddr][sum]; !ok {
|
||||
t.m[destAddr][sum] = r
|
||||
go t.sendEvent(&Event{Type: CreateEvent, Route: r})
|
||||
return nil
|
||||
}
|
||||
|
||||
// only add the route if the route override is explicitly requested
|
||||
if _, ok := t.m[destAddr][sum]; ok && r.Policy == OverrideIfExists {
|
||||
t.m[destAddr][sum] = r
|
||||
go t.sendEvent(&Event{Type: UpdateEvent, Route: r})
|
||||
return nil
|
||||
}
|
||||
|
||||
// if we reached this point without already returning the route already exists
|
||||
// we return nil only if explicitly requested by the client
|
||||
if r.Policy == IgnoreIfExists {
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrDuplicateRoute
|
||||
}
|
||||
|
||||
// Delete deletes the route from the routing table
|
||||
func (t *table) Delete(r Route) error {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
destAddr := r.Destination
|
||||
sum := t.hash(r)
|
||||
|
||||
if _, ok := t.m[destAddr]; !ok {
|
||||
return ErrRouteNotFound
|
||||
}
|
||||
|
||||
delete(t.m[destAddr], sum)
|
||||
go t.sendEvent(&Event{Type: DeleteEvent, Route: r})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update updates routing table with new route
|
||||
func (t *table) Update(r Route) error {
|
||||
destAddr := r.Destination
|
||||
sum := t.hash(r)
|
||||
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
// check if the destAddr has ANY routes in the table
|
||||
if _, ok := t.m[destAddr]; !ok {
|
||||
return ErrRouteNotFound
|
||||
}
|
||||
|
||||
// if the route has been found update it
|
||||
if _, ok := t.m[destAddr][sum]; ok {
|
||||
t.m[destAddr][sum] = r
|
||||
go t.sendEvent(&Event{Type: UpdateEvent, Route: r})
|
||||
return nil
|
||||
}
|
||||
|
||||
return ErrRouteNotFound
|
||||
}
|
||||
|
||||
// List returns a list of all routes in the table
|
||||
func (t *table) List() ([]Route, error) {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
|
||||
var routes []Route
|
||||
for _, rmap := range t.m {
|
||||
for _, route := range rmap {
|
||||
routes = append(routes, route)
|
||||
}
|
||||
}
|
||||
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
// Lookup queries routing table and returns all routes that match it
|
||||
func (t *table) Lookup(q Query) ([]Route, error) {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
|
||||
var results []Route
|
||||
|
||||
for destAddr, routes := range t.m {
|
||||
if q.Options().Destination != "*" {
|
||||
if q.Options().Destination != destAddr {
|
||||
continue
|
||||
}
|
||||
for _, route := range routes {
|
||||
if q.Options().Network == "*" || q.Options().Network == route.Network {
|
||||
if q.Options().Router.ID() == "*" || q.Options().Router.ID() == route.Router.ID() {
|
||||
if route.Metric <= q.Options().Metric {
|
||||
results = append(results, route)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if q.Options().Destination == "*" {
|
||||
for _, route := range routes {
|
||||
if q.Options().Network == "*" || q.Options().Network == route.Router.Network() {
|
||||
if q.Options().Router.ID() == "*" || q.Options().Router.ID() == route.Router.ID() {
|
||||
if route.Metric <= q.Options().Metric {
|
||||
results = append(results, route)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(results) == 0 && q.Options().Policy != DiscardNoRoute {
|
||||
return nil, ErrRouteNotFound
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// Watch returns routing table entry watcher
|
||||
func (t *table) Watch(opts ...WatchOption) (Watcher, error) {
|
||||
// by default watch everything
|
||||
wopts := WatchOptions{
|
||||
Destination: "*",
|
||||
Network: "*",
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&wopts)
|
||||
}
|
||||
|
||||
watcher := &tableWatcher{
|
||||
opts: wopts,
|
||||
resChan: make(chan *Event, 10),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
t.Lock()
|
||||
t.w[uuid.New().String()] = watcher
|
||||
t.Unlock()
|
||||
|
||||
return watcher, nil
|
||||
}
|
||||
|
||||
// sendEvent sends rules to all subscribe watchers
|
||||
func (t *table) sendEvent(r *Event) {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
|
||||
for _, w := range t.w {
|
||||
select {
|
||||
case w.resChan <- r:
|
||||
case <-w.done:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Size returns the size of the routing table
|
||||
func (t *table) Size() int {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
|
||||
return len(t.m)
|
||||
}
|
||||
|
||||
// String returns debug information
|
||||
func (t *table) String() string {
|
||||
t.RLock()
|
||||
defer t.RUnlock()
|
||||
|
||||
// this will help us build routing table string
|
||||
sb := &strings.Builder{}
|
||||
|
||||
// create nice table printing structure
|
||||
table := tablewriter.NewWriter(sb)
|
||||
table.SetHeader([]string{"Destination", "Router", "Network", "Metric"})
|
||||
|
||||
for _, destRoute := range t.m {
|
||||
for _, route := range destRoute {
|
||||
strRoute := []string{
|
||||
route.Destination,
|
||||
route.Router.Address(),
|
||||
route.Network,
|
||||
fmt.Sprintf("%d", route.Metric),
|
||||
}
|
||||
table.Append(strRoute)
|
||||
}
|
||||
}
|
||||
|
||||
// render table into sb
|
||||
table.Render()
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// hash hashes the route using router gateway and network address
|
||||
func (t *table) hash(r Route) uint64 {
|
||||
destAddr := r.Destination
|
||||
routerAddr := r.Router.Address()
|
||||
netAddr := r.Network
|
||||
|
||||
t.h.Reset()
|
||||
t.h.Write([]byte(destAddr + routerAddr + netAddr))
|
||||
|
||||
return t.h.Sum64()
|
||||
}
|
84
router/options.go
Normal file
84
router/options.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/registry"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultAddress is default router address
|
||||
DefaultAddress = ":9093"
|
||||
// DefaultAdvertise is default address advertised to the network
|
||||
DefaultAdvertise = ":9094"
|
||||
)
|
||||
|
||||
// Options are router options
|
||||
type Options struct {
|
||||
// ID is router id
|
||||
ID string
|
||||
// Address is router address
|
||||
Address string
|
||||
// Advertise is the address advertised to the network
|
||||
Advertise string
|
||||
// Registry is the local registry
|
||||
Registry registry.Registry
|
||||
// Networkis the network registry
|
||||
Network registry.Registry
|
||||
// Table is routing table
|
||||
Table Table
|
||||
}
|
||||
|
||||
// ID sets Router ID
|
||||
func ID(id string) Option {
|
||||
return func(o *Options) {
|
||||
o.ID = id
|
||||
}
|
||||
}
|
||||
|
||||
// Address sets router service address
|
||||
func Address(a string) Option {
|
||||
return func(o *Options) {
|
||||
o.Address = a
|
||||
}
|
||||
}
|
||||
|
||||
// Advertise sets the address that is advertise to the network
|
||||
func Advertise(n string) Option {
|
||||
return func(o *Options) {
|
||||
o.Advertise = n
|
||||
}
|
||||
}
|
||||
|
||||
// RoutingTable sets the routing table
|
||||
func RoutingTable(t Table) Option {
|
||||
return func(o *Options) {
|
||||
o.Table = t
|
||||
}
|
||||
}
|
||||
|
||||
// Registry sets the local registry
|
||||
func Registry(r registry.Registry) Option {
|
||||
return func(o *Options) {
|
||||
o.Registry = r
|
||||
}
|
||||
}
|
||||
|
||||
// Network sets the network registry
|
||||
func Network(r registry.Registry) Option {
|
||||
return func(o *Options) {
|
||||
o.Network = r
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultOptions returns router default options
|
||||
func DefaultOptions() Options {
|
||||
// NOTE: by default both local and network registies use default registry i.e. mdns
|
||||
return Options{
|
||||
ID: uuid.New().String(),
|
||||
Address: DefaultAddress,
|
||||
Advertise: DefaultAdvertise,
|
||||
Registry: registry.DefaultRegistry,
|
||||
Network: registry.DefaultRegistry,
|
||||
Table: NewTable(),
|
||||
}
|
||||
}
|
116
router/query.go
Normal file
116
router/query.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package router
|
||||
|
||||
// LookupPolicy defines query policy
|
||||
type LookupPolicy int
|
||||
|
||||
const (
|
||||
// DiscardNoRoute discards query when no route is found
|
||||
DiscardNoRoute LookupPolicy = iota
|
||||
// ClosestMatch returns closest match to supplied query
|
||||
ClosestMatch
|
||||
)
|
||||
|
||||
// String returns human representation of LookupPolicy
|
||||
func (lp LookupPolicy) String() string {
|
||||
switch lp {
|
||||
case DiscardNoRoute:
|
||||
return "DISCARD"
|
||||
case ClosestMatch:
|
||||
return "CLOSEST"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
// QueryOption sets routing table query options
|
||||
type QueryOption func(*QueryOptions)
|
||||
|
||||
// QueryOptions are routing table query options
|
||||
type QueryOptions struct {
|
||||
// Destination is destination address
|
||||
Destination string
|
||||
// Network is network address
|
||||
Network string
|
||||
// Router is gateway address
|
||||
Router Router
|
||||
// Metric is route metric
|
||||
Metric int
|
||||
// Policy is query lookup policy
|
||||
Policy LookupPolicy
|
||||
}
|
||||
|
||||
// QueryDestination sets query destination address
|
||||
func QueryDestination(a string) QueryOption {
|
||||
return func(o *QueryOptions) {
|
||||
o.Destination = a
|
||||
}
|
||||
}
|
||||
|
||||
// QueryNetwork sets query network address
|
||||
func QueryNetwork(a string) QueryOption {
|
||||
return func(o *QueryOptions) {
|
||||
o.Network = a
|
||||
}
|
||||
}
|
||||
|
||||
// QueryRouter sets query gateway address
|
||||
func QueryRouter(r Router) QueryOption {
|
||||
return func(o *QueryOptions) {
|
||||
o.Router = r
|
||||
}
|
||||
}
|
||||
|
||||
// QueryMetric sets query metric
|
||||
func QueryMetric(m int) QueryOption {
|
||||
return func(o *QueryOptions) {
|
||||
o.Metric = m
|
||||
}
|
||||
}
|
||||
|
||||
// QueryPolicy sets query policy
|
||||
// NOTE: this might be renamed to filter or some such
|
||||
func QueryPolicy(p LookupPolicy) QueryOption {
|
||||
return func(o *QueryOptions) {
|
||||
o.Policy = p
|
||||
}
|
||||
}
|
||||
|
||||
// Query is routing table query
|
||||
type Query interface {
|
||||
// Options returns query options
|
||||
Options() QueryOptions
|
||||
}
|
||||
|
||||
// query is a basic implementation of Query
|
||||
type query struct {
|
||||
opts QueryOptions
|
||||
}
|
||||
|
||||
// NewQuery creates new query and returns it
|
||||
func NewQuery(opts ...QueryOption) Query {
|
||||
// default gateway for wildcard router
|
||||
r := newRouter(ID("*"))
|
||||
|
||||
// default options
|
||||
// NOTE: by default we use DefaultNetworkMetric
|
||||
qopts := QueryOptions{
|
||||
Destination: "*",
|
||||
Network: "*",
|
||||
Router: r,
|
||||
Metric: DefaultNetworkMetric,
|
||||
Policy: DiscardNoRoute,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&qopts)
|
||||
}
|
||||
|
||||
return &query{
|
||||
opts: qopts,
|
||||
}
|
||||
}
|
||||
|
||||
// Options returns query options
|
||||
func (q *query) Options() QueryOptions {
|
||||
return q.opts
|
||||
}
|
74
router/route.go
Normal file
74
router/route.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultLocalMetric is default route cost for local network
|
||||
DefaultLocalMetric = 1
|
||||
// DefaultNetworkMetric is default route cost for micro network
|
||||
DefaultNetworkMetric = 10
|
||||
)
|
||||
|
||||
// RoutePolicy defines routing table addition policy
|
||||
type RoutePolicy int
|
||||
|
||||
const (
|
||||
// OverrideIfExists overrides route if it already exists
|
||||
OverrideIfExists RoutePolicy = iota
|
||||
// IgnoreIfExists does not modify existing route
|
||||
IgnoreIfExists
|
||||
)
|
||||
|
||||
// String returns human reprensentation of policy
|
||||
func (p RoutePolicy) String() string {
|
||||
switch p {
|
||||
case OverrideIfExists:
|
||||
return "OVERRIDE"
|
||||
case IgnoreIfExists:
|
||||
return "IGNORE"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
// Route is network route
|
||||
type Route struct {
|
||||
// Destination is destination address
|
||||
Destination string
|
||||
// Router is the network router
|
||||
Router Router
|
||||
// Network is micro network address
|
||||
Network string
|
||||
// Metric is the route cost metric
|
||||
Metric int
|
||||
// Policy defines route policy
|
||||
Policy RoutePolicy
|
||||
}
|
||||
|
||||
// String allows to print the route
|
||||
func (r *Route) String() string {
|
||||
// this will help us build routing table string
|
||||
sb := &strings.Builder{}
|
||||
|
||||
// create nice table printing structure
|
||||
table := tablewriter.NewWriter(sb)
|
||||
table.SetHeader([]string{"Destination", "Router", "Network", "Metric"})
|
||||
|
||||
strRoute := []string{
|
||||
r.Destination,
|
||||
r.Router.Address(),
|
||||
r.Network,
|
||||
fmt.Sprintf("%d", r.Metric),
|
||||
}
|
||||
table.Append(strRoute)
|
||||
|
||||
// render table into sb
|
||||
table.Render()
|
||||
|
||||
return sb.String()
|
||||
}
|
32
router/router.go
Normal file
32
router/router.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Package router provides an interface for micro network router
|
||||
package router
|
||||
|
||||
// Router is micro network router
|
||||
type Router interface {
|
||||
// Init initializes the router with options
|
||||
Init(...Option) error
|
||||
// Options returns the router options
|
||||
Options() Options
|
||||
// ID returns the id of the router
|
||||
ID() string
|
||||
// Table returns the routing table
|
||||
Table() Table
|
||||
// Address returns the router adddress
|
||||
Address() string
|
||||
// Network returns the network address of the router
|
||||
Network() string
|
||||
// Advertise starts advertising the routes to the network
|
||||
Advertise() error
|
||||
// Stop stops the router
|
||||
Stop() error
|
||||
// String returns debug info
|
||||
String() string
|
||||
}
|
||||
|
||||
// Option used by the router
|
||||
type Option func(*Options)
|
||||
|
||||
// NewRouter creates new Router and returns it
|
||||
func NewRouter(opts ...Option) Router {
|
||||
return newRouter(opts...)
|
||||
}
|
44
router/table.go
Normal file
44
router/table.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
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 defines routing table interface
|
||||
type Table interface {
|
||||
// Init initializes the router with options
|
||||
Init(...TableOption) error
|
||||
// Options returns the router options
|
||||
Options() TableOptions
|
||||
// Add adds new route to the routing table
|
||||
Add(Route) error
|
||||
// Delete deletes existing route from the routing table
|
||||
Delete(Route) error
|
||||
// Update updates route in the routing table
|
||||
Update(Route) error
|
||||
// List returns the list of all routes in the table
|
||||
List() ([]Route, error)
|
||||
// Lookup looks up routes in the routing table and returns them
|
||||
Lookup(Query) ([]Route, error)
|
||||
// Watch returns a watcher which allows to track updates to the routing table
|
||||
Watch(opts ...WatchOption) (Watcher, error)
|
||||
// Size returns the size of the routing table
|
||||
Size() int
|
||||
// String prints the routing table
|
||||
String() string
|
||||
}
|
||||
|
||||
// TableOption used by the routing table
|
||||
type TableOption func(*TableOptions)
|
||||
|
||||
// NewTable creates new routing table and returns it
|
||||
func NewTable(opts ...TableOption) Table {
|
||||
return newTable(opts...)
|
||||
}
|
147
router/table_watcher.go
Normal file
147
router/table_watcher.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrWatcherStopped is returned when routing table watcher has been stopped
|
||||
ErrWatcherStopped = errors.New("routing table watcher stopped")
|
||||
)
|
||||
|
||||
// EventType defines routing table event
|
||||
type EventType int
|
||||
|
||||
const (
|
||||
// CreateEvent is emitted when new route has been created
|
||||
CreateEvent EventType = iota
|
||||
// DeleteEvent is emitted when an existing route has been deleted
|
||||
DeleteEvent
|
||||
// UpdateEvent is emitted when a routing table has been updated
|
||||
UpdateEvent
|
||||
)
|
||||
|
||||
// String returns string representation of the event
|
||||
func (et EventType) String() string {
|
||||
switch et {
|
||||
case CreateEvent:
|
||||
return "CREATE"
|
||||
case DeleteEvent:
|
||||
return "DELETE"
|
||||
case UpdateEvent:
|
||||
return "UPDATE"
|
||||
default:
|
||||
return "UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
// Event is returned by a call to Next on the watcher.
|
||||
type Event struct {
|
||||
// Type defines type of event
|
||||
Type EventType
|
||||
// Route is table rout
|
||||
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 {
|
||||
// Next is a blocking call that returns watch result
|
||||
Next() (*Event, error)
|
||||
// Chan returns event channel
|
||||
Chan() (<-chan *Event, error)
|
||||
// Stop stops watcher
|
||||
Stop()
|
||||
}
|
||||
|
||||
// WatchOptions are table watcher options
|
||||
type WatchOptions struct {
|
||||
// Specify destination address to watch
|
||||
Destination string
|
||||
// Specify network to watch
|
||||
Network string
|
||||
}
|
||||
|
||||
// WatchDestination sets what destination to watch
|
||||
// Destination is usually microservice name
|
||||
func WatchDestination(a string) WatchOption {
|
||||
return func(o *WatchOptions) {
|
||||
o.Destination = a
|
||||
}
|
||||
}
|
||||
|
||||
// WatchNetwork sets what network to watch
|
||||
func WatchNetwork(n string) WatchOption {
|
||||
return func(o *WatchOptions) {
|
||||
o.Network = n
|
||||
}
|
||||
}
|
||||
|
||||
type tableWatcher struct {
|
||||
opts WatchOptions
|
||||
resChan chan *Event
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
// Next returns the next noticed action taken on table
|
||||
// TODO: this needs to be thought through properly
|
||||
// we are aiming to provide the same options Query provides
|
||||
func (w *tableWatcher) Next() (*Event, error) {
|
||||
for {
|
||||
select {
|
||||
case res := <-w.resChan:
|
||||
switch w.opts.Destination {
|
||||
case "*", "":
|
||||
if w.opts.Network == "*" || w.opts.Network == res.Route.Network {
|
||||
return res, nil
|
||||
}
|
||||
case res.Route.Destination:
|
||||
if w.opts.Network == "*" || w.opts.Network == res.Route.Network {
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
case <-w.done:
|
||||
return nil, ErrWatcherStopped
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Chan returns watcher events channel
|
||||
func (w *tableWatcher) Chan() (<-chan *Event, error) {
|
||||
return w.resChan, nil
|
||||
}
|
||||
|
||||
// Stop stops routing table watcher
|
||||
func (w *tableWatcher) Stop() {
|
||||
select {
|
||||
case <-w.done:
|
||||
return
|
||||
default:
|
||||
close(w.done)
|
||||
}
|
||||
}
|
||||
|
||||
// String prints debug information
|
||||
func (w *tableWatcher) String() string {
|
||||
sb := &strings.Builder{}
|
||||
|
||||
table := tablewriter.NewWriter(sb)
|
||||
table.SetHeader([]string{"Destination", "Network"})
|
||||
|
||||
data := []string{
|
||||
w.opts.Destination,
|
||||
w.opts.Network,
|
||||
}
|
||||
table.Append(data)
|
||||
|
||||
// render table into sb
|
||||
table.Render()
|
||||
|
||||
return sb.String()
|
||||
}
|
51
selector/common_test.go
Normal file
51
selector/common_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package selector
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/registry"
|
||||
)
|
||||
|
||||
var (
|
||||
// mock data
|
||||
testData = map[string][]*registry.Service{
|
||||
"foo": []*registry.Service{
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "1.0.0",
|
||||
Nodes: []*registry.Node{
|
||||
{
|
||||
Id: "foo-1.0.0-123",
|
||||
Address: "localhost",
|
||||
Port: 9999,
|
||||
},
|
||||
{
|
||||
Id: "foo-1.0.0-321",
|
||||
Address: "localhost",
|
||||
Port: 9999,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "1.0.1",
|
||||
Nodes: []*registry.Node{
|
||||
{
|
||||
Id: "foo-1.0.1-321",
|
||||
Address: "localhost",
|
||||
Port: 6666,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "foo",
|
||||
Version: "1.0.3",
|
||||
Nodes: []*registry.Node{
|
||||
{
|
||||
Id: "foo-1.0.3-345",
|
||||
Address: "localhost",
|
||||
Port: 8888,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
@@ -10,7 +10,8 @@ func TestRegistrySelector(t *testing.T) {
|
||||
counts := map[string]int{}
|
||||
|
||||
r := memory.NewRegistry()
|
||||
r.(*memory.Registry).Setup()
|
||||
rg := r.(*memory.Registry)
|
||||
rg.Services = testData
|
||||
cache := NewSelector(Registry(r))
|
||||
|
||||
next, err := cache.Select("foo")
|
||||
|
@@ -3,17 +3,22 @@ package grpc
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/codec/bytes"
|
||||
"github.com/micro/go-micro/codec/jsonrpc"
|
||||
"github.com/micro/go-micro/codec/protorpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
type jsonCodec struct{}
|
||||
type bytesCodec struct{}
|
||||
type protoCodec struct{}
|
||||
type wrapCodec struct{ encoding.Codec }
|
||||
|
||||
var (
|
||||
defaultGRPCCodecs = map[string]encoding.Codec{
|
||||
@@ -36,6 +41,27 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func (w wrapCodec) String() string {
|
||||
return w.Codec.Name()
|
||||
}
|
||||
|
||||
func (w wrapCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
return b.Data, nil
|
||||
}
|
||||
return w.Codec.Marshal(v)
|
||||
}
|
||||
|
||||
func (w wrapCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
b.Data = data
|
||||
return nil
|
||||
}
|
||||
return w.Codec.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
return proto.Marshal(v.(proto.Message))
|
||||
}
|
||||
@@ -80,3 +106,61 @@ func (bytesCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
func (bytesCodec) Name() string {
|
||||
return "bytes"
|
||||
}
|
||||
|
||||
type grpcCodec struct {
|
||||
// headers
|
||||
id string
|
||||
target string
|
||||
method string
|
||||
endpoint string
|
||||
|
||||
s grpc.ServerStream
|
||||
c encoding.Codec
|
||||
}
|
||||
|
||||
func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error {
|
||||
md, _ := metadata.FromIncomingContext(g.s.Context())
|
||||
if m == nil {
|
||||
m = new(codec.Message)
|
||||
}
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string)
|
||||
}
|
||||
for k, v := range md {
|
||||
m.Header[k] = strings.Join(v, ",")
|
||||
}
|
||||
m.Id = g.id
|
||||
m.Target = g.target
|
||||
m.Method = g.method
|
||||
m.Endpoint = g.endpoint
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcCodec) ReadBody(v interface{}) error {
|
||||
// caller has requested a frame
|
||||
if f, ok := v.(*bytes.Frame); ok {
|
||||
return g.s.RecvMsg(f)
|
||||
}
|
||||
return g.s.RecvMsg(v)
|
||||
}
|
||||
|
||||
func (g *grpcCodec) Write(m *codec.Message, v interface{}) error {
|
||||
// if we don't have a body
|
||||
if v != nil {
|
||||
b, err := g.c.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Body = b
|
||||
}
|
||||
// write the body using the framing codec
|
||||
return g.s.SendMsg(&bytes.Frame{m.Body})
|
||||
}
|
||||
|
||||
func (g *grpcCodec) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcCodec) String() string {
|
||||
return g.c.Name()
|
||||
}
|
||||
|
@@ -56,8 +56,9 @@ type grpcServer struct {
|
||||
}
|
||||
|
||||
func init() {
|
||||
encoding.RegisterCodec(jsonCodec{})
|
||||
encoding.RegisterCodec(bytesCodec{})
|
||||
encoding.RegisterCodec(wrapCodec{protoCodec{}})
|
||||
encoding.RegisterCodec(wrapCodec{jsonCodec{}})
|
||||
encoding.RegisterCodec(wrapCodec{bytesCodec{}})
|
||||
}
|
||||
|
||||
func newGRPCServer(opts ...server.Option) server.Server {
|
||||
@@ -81,6 +82,14 @@ func newGRPCServer(opts ...server.Option) server.Server {
|
||||
return srv
|
||||
}
|
||||
|
||||
type grpcRouter struct {
|
||||
h func(context.Context, server.Request, interface{}) error
|
||||
}
|
||||
|
||||
func (r grpcRouter) ServeRequest(ctx context.Context, req server.Request, rsp server.Response) error {
|
||||
return r.h(ctx, req, rsp)
|
||||
}
|
||||
|
||||
func (g *grpcServer) configure(opts ...server.Option) {
|
||||
// Don't reprocess where there's no config
|
||||
if len(opts) == 0 && g.srv != nil {
|
||||
@@ -167,19 +176,6 @@ func (g *grpcServer) handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return status.New(codes.InvalidArgument, err.Error()).Err()
|
||||
}
|
||||
|
||||
g.rpc.mu.Lock()
|
||||
service := g.rpc.serviceMap[serviceName]
|
||||
g.rpc.mu.Unlock()
|
||||
|
||||
if service == nil {
|
||||
return status.New(codes.Unimplemented, fmt.Sprintf("unknown service %v", service)).Err()
|
||||
}
|
||||
|
||||
mtype := service.method[methodName]
|
||||
if mtype == nil {
|
||||
return status.New(codes.Unimplemented, fmt.Sprintf("unknown service %v", service)).Err()
|
||||
}
|
||||
|
||||
// get grpc metadata
|
||||
gmd, ok := metadata.FromIncomingContext(stream.Context())
|
||||
if !ok {
|
||||
@@ -214,6 +210,67 @@ func (g *grpcServer) handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
}
|
||||
}
|
||||
|
||||
// process via router
|
||||
if g.opts.Router != nil {
|
||||
cc, err := g.newGRPCCodec(ct)
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.server", err.Error())
|
||||
}
|
||||
codec := &grpcCodec{
|
||||
method: fmt.Sprintf("%s.%s", serviceName, methodName),
|
||||
endpoint: fmt.Sprintf("%s.%s", serviceName, methodName),
|
||||
target: g.opts.Name,
|
||||
s: stream,
|
||||
c: cc,
|
||||
}
|
||||
|
||||
// create a client.Request
|
||||
request := &rpcRequest{
|
||||
service: mgrpc.ServiceFromMethod(fullMethod),
|
||||
contentType: ct,
|
||||
method: fmt.Sprintf("%s.%s", serviceName, methodName),
|
||||
codec: codec,
|
||||
}
|
||||
|
||||
response := &rpcResponse{
|
||||
header: make(map[string]string),
|
||||
codec: codec,
|
||||
}
|
||||
|
||||
// create a wrapped function
|
||||
handler := func(ctx context.Context, req server.Request, rsp interface{}) error {
|
||||
return g.opts.Router.ServeRequest(ctx, req, rsp.(server.Response))
|
||||
}
|
||||
|
||||
// execute the wrapper for it
|
||||
for i := len(g.opts.HdlrWrappers); i > 0; i-- {
|
||||
handler = g.opts.HdlrWrappers[i-1](handler)
|
||||
}
|
||||
|
||||
r := grpcRouter{handler}
|
||||
|
||||
// serve the actual request using the request router
|
||||
if err := r.ServeRequest(ctx, request, response); err != nil {
|
||||
return status.Errorf(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// process the standard request flow
|
||||
g.rpc.mu.Lock()
|
||||
service := g.rpc.serviceMap[serviceName]
|
||||
g.rpc.mu.Unlock()
|
||||
|
||||
if service == nil {
|
||||
return status.New(codes.Unimplemented, fmt.Sprintf("unknown service %v", service)).Err()
|
||||
}
|
||||
|
||||
mtype := service.method[methodName]
|
||||
if mtype == nil {
|
||||
return status.New(codes.Unimplemented, fmt.Sprintf("unknown service %v", service)).Err()
|
||||
}
|
||||
|
||||
// process unary
|
||||
if !mtype.stream {
|
||||
return g.processRequest(stream, service, mtype, ct, ctx)
|
||||
|
@@ -2,6 +2,7 @@ package grpc
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/codec"
|
||||
"github.com/micro/go-micro/codec/bytes"
|
||||
)
|
||||
|
||||
type rpcRequest struct {
|
||||
@@ -46,7 +47,11 @@ func (r *rpcRequest) Header() map[string]string {
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Read() ([]byte, error) {
|
||||
return r.body, nil
|
||||
f := &bytes.Frame{}
|
||||
if err := r.codec.ReadBody(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f.Data, nil
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Stream() bool {
|
||||
|
27
server/grpc/response.go
Normal file
27
server/grpc/response.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/codec"
|
||||
)
|
||||
|
||||
type rpcResponse struct {
|
||||
header map[string]string
|
||||
codec codec.Codec
|
||||
}
|
||||
|
||||
func (r *rpcResponse) Codec() codec.Writer {
|
||||
return r.codec
|
||||
}
|
||||
|
||||
func (r *rpcResponse) WriteHeader(hdr map[string]string) {
|
||||
for k, v := range hdr {
|
||||
r.header[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rpcResponse) Write(b []byte) error {
|
||||
return r.codec.Write(&codec.Message{
|
||||
Header: r.header,
|
||||
Body: b,
|
||||
}, nil)
|
||||
}
|
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/micro/go-micro/broker"
|
||||
"github.com/micro/go-micro/codec"
|
||||
@@ -169,6 +170,10 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
|
||||
return func(p broker.Publication) error {
|
||||
msg := p.Message()
|
||||
ct := msg.Header["Content-Type"]
|
||||
if len(ct) == 0 {
|
||||
msg.Header["Content-Type"] = defaultContentType
|
||||
ct = defaultContentType
|
||||
}
|
||||
cf, err := g.newCodec(ct)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -181,6 +186,8 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
|
||||
delete(hdr, "Content-Type")
|
||||
ctx := metadata.NewContext(context.Background(), hdr)
|
||||
|
||||
results := make(chan error, len(sb.handlers))
|
||||
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
handler := sb.handlers[i]
|
||||
|
||||
@@ -231,16 +238,29 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
|
||||
fn = opts.SubWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
g.wg.Add(1)
|
||||
if g.wg != nil {
|
||||
g.wg.Add(1)
|
||||
}
|
||||
go func() {
|
||||
defer g.wg.Done()
|
||||
fn(ctx, &rpcMessage{
|
||||
if g.wg != nil {
|
||||
defer g.wg.Done()
|
||||
}
|
||||
results <- fn(ctx, &rpcMessage{
|
||||
topic: sb.topic,
|
||||
contentType: ct,
|
||||
payload: req.Interface(),
|
||||
})
|
||||
}()
|
||||
}
|
||||
var errors []string
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
if err := <-results; err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
return fmt.Errorf("subscriber error: %s", strings.Join(errors, "\n"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// Package rpc provides an rpc server
|
||||
package rpc
|
||||
// Package mucp provides an mucp server
|
||||
package mucp
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/server"
|
@@ -14,6 +14,7 @@ type rpcRequest struct {
|
||||
codec codec.Codec
|
||||
header map[string]string
|
||||
body []byte
|
||||
rawBody interface{}
|
||||
stream bool
|
||||
}
|
||||
|
||||
@@ -48,8 +49,7 @@ func (r *rpcRequest) Header() map[string]string {
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Body() interface{} {
|
||||
// TODO: convert to interface value
|
||||
return r.body
|
||||
return r.rawBody
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Read() ([]byte, error) {
|
||||
|
@@ -190,6 +190,11 @@ func (s *service) call(ctx context.Context, router *router, sending *sync.Mutex,
|
||||
body: req.msg.Body,
|
||||
}
|
||||
|
||||
// only set if not nil
|
||||
if argv.IsValid() {
|
||||
r.rawBody = argv.Interface()
|
||||
}
|
||||
|
||||
if !mtype.stream {
|
||||
fn := func(ctx context.Context, req Request, rsp interface{}) error {
|
||||
returnValues = function.Call([]reflect.Value{s.rcvr, mtype.prepareContext(ctx), reflect.ValueOf(argv.Interface()), reflect.ValueOf(rsp)})
|
||||
@@ -202,6 +207,11 @@ func (s *service) call(ctx context.Context, router *router, sending *sync.Mutex,
|
||||
return nil
|
||||
}
|
||||
|
||||
// wrap the handler
|
||||
for i := len(router.hdlrWrappers); i > 0; i-- {
|
||||
fn = router.hdlrWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
// execute handler
|
||||
if err := fn(ctx, r, replyv.Interface()); err != nil {
|
||||
return err
|
||||
@@ -235,6 +245,11 @@ func (s *service) call(ctx context.Context, router *router, sending *sync.Mutex,
|
||||
}
|
||||
}
|
||||
|
||||
// wrap the handler
|
||||
for i := len(router.hdlrWrappers); i > 0; i-- {
|
||||
fn = router.hdlrWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
// client.Stream request
|
||||
r.stream = true
|
||||
|
||||
|
@@ -35,9 +35,12 @@ type rpcServer struct {
|
||||
|
||||
func newRpcServer(opts ...Option) Server {
|
||||
options := newOptions(opts...)
|
||||
router := newRpcRouter()
|
||||
router.hdlrWrappers = options.HdlrWrappers
|
||||
|
||||
return &rpcServer{
|
||||
opts: options,
|
||||
router: DefaultRouter,
|
||||
router: router,
|
||||
handlers: make(map[string]Handler),
|
||||
subscribers: make(map[*subscriber][]broker.Subscriber),
|
||||
exit: make(chan chan error),
|
||||
@@ -45,6 +48,14 @@ func newRpcServer(opts ...Option) Server {
|
||||
}
|
||||
}
|
||||
|
||||
type rpcRouter struct {
|
||||
h func(context.Context, Request, interface{}) error
|
||||
}
|
||||
|
||||
func (r rpcRouter) ServeRequest(ctx context.Context, req Request, rsp Response) error {
|
||||
return r.h(ctx, req, rsp)
|
||||
}
|
||||
|
||||
// ServeConn serves a single connection
|
||||
func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
defer func() {
|
||||
@@ -143,24 +154,26 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
}
|
||||
|
||||
// set router
|
||||
r := s.opts.Router
|
||||
r := Router(s.router)
|
||||
|
||||
// if nil use default router
|
||||
if s.opts.Router == nil {
|
||||
r = s.router
|
||||
// if not nil use the router specified
|
||||
if s.opts.Router != nil {
|
||||
// create a wrapped function
|
||||
handler := func(ctx context.Context, req Request, rsp interface{}) error {
|
||||
return s.opts.Router.ServeRequest(ctx, req, rsp.(Response))
|
||||
}
|
||||
|
||||
// execute the wrapper for it
|
||||
for i := len(s.opts.HdlrWrappers); i > 0; i-- {
|
||||
handler = s.opts.HdlrWrappers[i-1](handler)
|
||||
}
|
||||
|
||||
// set the router
|
||||
r = rpcRouter{handler}
|
||||
}
|
||||
|
||||
// create a wrapped function
|
||||
handler := func(ctx context.Context, req Request, rsp interface{}) error {
|
||||
return r.ServeRequest(ctx, req, rsp.(Response))
|
||||
}
|
||||
|
||||
for i := len(s.opts.HdlrWrappers); i > 0; i-- {
|
||||
handler = s.opts.HdlrWrappers[i-1](handler)
|
||||
}
|
||||
|
||||
// TODO: handle error better
|
||||
if err := handler(ctx, request, response); err != nil {
|
||||
// serve the actual request using the request router
|
||||
if err := r.ServeRequest(ctx, request, response); err != nil {
|
||||
// write an error response
|
||||
err = rcodec.Write(&codec.Message{
|
||||
Header: msg.Header,
|
||||
@@ -206,6 +219,15 @@ func (s *rpcServer) Init(opts ...Option) error {
|
||||
for _, opt := range opts {
|
||||
opt(&s.opts)
|
||||
}
|
||||
|
||||
// update router if its the default
|
||||
if s.opts.Router == nil {
|
||||
r := newRpcRouter()
|
||||
r.hdlrWrappers = s.opts.HdlrWrappers
|
||||
r.serviceMap = s.router.serviceMap
|
||||
s.router = r
|
||||
}
|
||||
|
||||
s.Unlock()
|
||||
return nil
|
||||
}
|
||||
@@ -589,5 +611,5 @@ func (s *rpcServer) Stop() error {
|
||||
}
|
||||
|
||||
func (s *rpcServer) String() string {
|
||||
return "rpc"
|
||||
return "mucp"
|
||||
}
|
||||
|
21
service/mucp/mucp.go
Normal file
21
service/mucp/mucp.go
Normal file
@@ -0,0 +1,21 @@
|
||||
// Package mucp initialises a mucp service
|
||||
package mucp
|
||||
|
||||
import (
|
||||
// TODO: change to go-micro/service
|
||||
"github.com/micro/go-micro"
|
||||
cmucp "github.com/micro/go-micro/client/mucp"
|
||||
smucp "github.com/micro/go-micro/server/mucp"
|
||||
)
|
||||
|
||||
// NewService returns a new mucp service
|
||||
func NewService(opts ...micro.Option) micro.Service {
|
||||
options := []micro.Option{
|
||||
micro.Client(cmucp.NewClient()),
|
||||
micro.Server(smucp.NewServer()),
|
||||
}
|
||||
|
||||
options = append(options, opts...)
|
||||
|
||||
return micro.NewService(opts...)
|
||||
}
|
@@ -30,7 +30,7 @@ func testService(ctx context.Context, wg *sync.WaitGroup, name string) Service {
|
||||
wg.Add(1)
|
||||
|
||||
r := memory.NewRegistry()
|
||||
r.(*memory.Registry).Setup()
|
||||
r.(*memory.Registry).Services = testData
|
||||
|
||||
// create service
|
||||
return NewService(
|
||||
|
@@ -10,7 +10,6 @@ an external database or eventing system. Go Sync provides a framework for synchr
|
||||
|
||||
## Getting Started
|
||||
|
||||
- [Data](#data) - simple distributed data storage
|
||||
- [Leader](#leader) - leadership election for group coordination
|
||||
- [Lock](#lock) - distributed locking for exclusive resource access
|
||||
- [Task](#task) - distributed job execution
|
||||
@@ -70,30 +69,6 @@ for {
|
||||
e.Resign()
|
||||
```
|
||||
|
||||
## Data
|
||||
|
||||
Data provides a simple interface for distributed data storage.
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/micro/go-micro/sync/data"
|
||||
"github.com/micro/go-micro/sync/data/consul"
|
||||
)
|
||||
|
||||
keyval := consul.NewData()
|
||||
|
||||
err := keyval.Write(&data.Record{
|
||||
Key: "foo",
|
||||
Value: []byte(`bar`),
|
||||
})
|
||||
// handle err
|
||||
|
||||
v, err := keyval.Read("foo")
|
||||
// handle err
|
||||
|
||||
err = keyval.Delete("foo")
|
||||
```
|
||||
|
||||
## Task
|
||||
|
||||
Task provides distributed job execution. It's a simple way to distribute work across a coordinated pool of workers.
|
||||
|
@@ -1,19 +0,0 @@
|
||||
package data
|
||||
|
||||
type Options struct {
|
||||
Nodes []string
|
||||
Prefix string
|
||||
}
|
||||
|
||||
func Nodes(a ...string) Option {
|
||||
return func(o *Options) {
|
||||
o.Nodes = a
|
||||
}
|
||||
}
|
||||
|
||||
// Prefix sets a prefix to any lock ids used
|
||||
func Prefix(p string) Option {
|
||||
return func(o *Options) {
|
||||
o.Prefix = p
|
||||
}
|
||||
}
|
@@ -6,12 +6,12 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/micro/go-micro/sync/data"
|
||||
ckv "github.com/micro/go-micro/sync/data/consul"
|
||||
"github.com/micro/go-micro/data/store"
|
||||
ckv "github.com/micro/go-micro/data/store/consul"
|
||||
lock "github.com/micro/go-micro/sync/lock/consul"
|
||||
)
|
||||
|
||||
type syncDB struct {
|
||||
type syncMap struct {
|
||||
opts Options
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ func ekey(k interface{}) string {
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
func (m *syncDB) Read(key, val interface{}) error {
|
||||
func (m *syncMap) Read(key, val interface{}) error {
|
||||
if key == nil {
|
||||
return fmt.Errorf("key is nil")
|
||||
}
|
||||
@@ -34,7 +34,7 @@ func (m *syncDB) Read(key, val interface{}) error {
|
||||
defer m.opts.Lock.Release(kstr)
|
||||
|
||||
// get key
|
||||
kval, err := m.opts.Data.Read(kstr)
|
||||
kval, err := m.opts.Store.Read(kstr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -43,7 +43,7 @@ func (m *syncDB) Read(key, val interface{}) error {
|
||||
return json.Unmarshal(kval.Value, val)
|
||||
}
|
||||
|
||||
func (m *syncDB) Write(key, val interface{}) error {
|
||||
func (m *syncMap) Write(key, val interface{}) error {
|
||||
if key == nil {
|
||||
return fmt.Errorf("key is nil")
|
||||
}
|
||||
@@ -63,13 +63,13 @@ func (m *syncDB) Write(key, val interface{}) error {
|
||||
}
|
||||
|
||||
// set key
|
||||
return m.opts.Data.Write(&data.Record{
|
||||
return m.opts.Store.Write(&store.Record{
|
||||
Key: kstr,
|
||||
Value: b,
|
||||
})
|
||||
}
|
||||
|
||||
func (m *syncDB) Delete(key interface{}) error {
|
||||
func (m *syncMap) Delete(key interface{}) error {
|
||||
if key == nil {
|
||||
return fmt.Errorf("key is nil")
|
||||
}
|
||||
@@ -81,11 +81,11 @@ func (m *syncDB) Delete(key interface{}) error {
|
||||
return err
|
||||
}
|
||||
defer m.opts.Lock.Release(kstr)
|
||||
return m.opts.Data.Delete(kstr)
|
||||
return m.opts.Store.Delete(kstr)
|
||||
}
|
||||
|
||||
func (m *syncDB) Iterate(fn func(key, val interface{}) error) error {
|
||||
keyvals, err := m.opts.Data.Dump()
|
||||
func (m *syncMap) Iterate(fn func(key, val interface{}) error) error {
|
||||
keyvals, err := m.opts.Store.Dump()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -126,7 +126,7 @@ func (m *syncDB) Iterate(fn func(key, val interface{}) error) error {
|
||||
}
|
||||
|
||||
// set key
|
||||
if err := m.opts.Data.Write(&data.Record{
|
||||
if err := m.opts.Store.Write(&store.Record{
|
||||
Key: keyval.Key,
|
||||
Value: b,
|
||||
}); err != nil {
|
||||
@@ -137,7 +137,7 @@ func (m *syncDB) Iterate(fn func(key, val interface{}) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewDB(opts ...Option) DB {
|
||||
func NewMap(opts ...Option) Map {
|
||||
var options Options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
@@ -147,11 +147,11 @@ func NewDB(opts ...Option) DB {
|
||||
options.Lock = lock.NewLock()
|
||||
}
|
||||
|
||||
if options.Data == nil {
|
||||
options.Data = ckv.NewData()
|
||||
if options.Store == nil {
|
||||
options.Store = ckv.NewStore()
|
||||
}
|
||||
|
||||
return &syncDB{
|
||||
return &syncMap{
|
||||
opts: options,
|
||||
}
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/sync/data"
|
||||
"github.com/micro/go-micro/data/store"
|
||||
"github.com/micro/go-micro/sync/leader"
|
||||
"github.com/micro/go-micro/sync/lock"
|
||||
"github.com/micro/go-micro/sync/time"
|
||||
@@ -21,10 +21,10 @@ func WithLock(l lock.Lock) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithData sets the data implementation option
|
||||
func WithData(s data.Data) Option {
|
||||
// WithStore sets the store implementation option
|
||||
func WithStore(s store.Store) Option {
|
||||
return func(o *Options) {
|
||||
o.Data = s
|
||||
o.Store = s
|
||||
}
|
||||
}
|
||||
|
||||
|
10
sync/sync.go
10
sync/sync.go
@@ -2,17 +2,17 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/sync/data"
|
||||
"github.com/micro/go-micro/data/store"
|
||||
"github.com/micro/go-micro/sync/leader"
|
||||
"github.com/micro/go-micro/sync/lock"
|
||||
"github.com/micro/go-micro/sync/task"
|
||||
"github.com/micro/go-micro/sync/time"
|
||||
)
|
||||
|
||||
// DB provides synchronized access to key-value storage.
|
||||
// It uses the data interface and lock interface to
|
||||
// Map provides synchronized access to key-value storage.
|
||||
// It uses the store interface and lock interface to
|
||||
// provide a consistent storage mechanism.
|
||||
type DB interface {
|
||||
type Map interface {
|
||||
// Read value with given key
|
||||
Read(key, val interface{}) error
|
||||
// Write value with given key
|
||||
@@ -33,7 +33,7 @@ type Cron interface {
|
||||
type Options struct {
|
||||
Leader leader.Leader
|
||||
Lock lock.Lock
|
||||
Data data.Data
|
||||
Store store.Store
|
||||
Task task.Task
|
||||
Time time.Time
|
||||
}
|
||||
|
@@ -38,3 +38,20 @@ func ServiceMethod(m string) (string, string, error) {
|
||||
|
||||
return parts[0], parts[1], nil
|
||||
}
|
||||
|
||||
// ServiceFromMethod returns the service
|
||||
// /service.Foo/Bar => service
|
||||
func ServiceFromMethod(m string) string {
|
||||
if len(m) == 0 {
|
||||
return m
|
||||
}
|
||||
if m[0] != '/' {
|
||||
return m
|
||||
}
|
||||
parts := strings.Split(m, "/")
|
||||
if len(parts) < 3 {
|
||||
return m
|
||||
}
|
||||
parts = strings.Split(parts[1], ".")
|
||||
return strings.Join(parts[:len(parts)-1], ".")
|
||||
}
|
||||
|
Reference in New Issue
Block a user