| @@ -1,9 +1,11 @@ | |||||||
| language: go | language: go | ||||||
| go: | go: | ||||||
| - 1.11.x |  | ||||||
| - 1.12.x | - 1.12.x | ||||||
| env: | env: | ||||||
|   - GO111MODULE=on |   - GO111MODULE=on | ||||||
| notifications: | notifications: | ||||||
|   slack: |   slack: | ||||||
|     secure: aEvhLbhujaGaKSrOokiG3//PaVHTIrc3fBpoRbCRqfZpyq6WREoapJJhF+tIpWWOwaC9GmChbD6aHo/jMUgwKXVyPSaNjiEL87YzUUpL8B2zslNp1rgfTg/LrzthOx3Q1TYwpaAl3to0fuHUVFX4yMeC2vuThq7WSXgMMxFCtbc= |     secure: aEvhLbhujaGaKSrOokiG3//PaVHTIrc3fBpoRbCRqfZpyq6WREoapJJhF+tIpWWOwaC9GmChbD6aHo/jMUgwKXVyPSaNjiEL87YzUUpL8B2zslNp1rgfTg/LrzthOx3Q1TYwpaAl3to0fuHUVFX4yMeC2vuThq7WSXgMMxFCtbc= | ||||||
|  | cache: | ||||||
|  |   directories: | ||||||
|  |     - $GOPATH/pkg/mod | ||||||
|   | |||||||
							
								
								
									
										197
									
								
								agent/README.md
									
									
									
									
									
								
							
							
						
						
									
										197
									
								
								agent/README.md
									
									
									
									
									
								
							| @@ -1,197 +0,0 @@ | |||||||
| # Agent  |  | ||||||
|  |  | ||||||
| Agent is a library used to create commands, inputs and robot services |  | ||||||
|  |  | ||||||
| ## Getting Started |  | ||||||
|  |  | ||||||
| - [Commands](#commands) - Commands are functions executed by the bot based on text based pattern matching. |  | ||||||
| - [Inputs](#inputs) - Inputs are plugins for communication e.g Slack, Telegram, IRC, etc. |  | ||||||
| - [Services](#services) - Write bots as micro services |  | ||||||
|  |  | ||||||
| ## Commands |  | ||||||
|  |  | ||||||
| Commands are functions executed by the bot based on text based pattern matching. |  | ||||||
|  |  | ||||||
| ### Write a Command |  | ||||||
|  |  | ||||||
| ```go |  | ||||||
| import "github.com/micro/go-micro/agent/command" |  | ||||||
|  |  | ||||||
| func Ping() command.Command { |  | ||||||
| 	usage := "ping" |  | ||||||
| 	description := "Returns pong" |  | ||||||
|  |  | ||||||
| 	return command.NewCommand("ping", usage, desc, func(args ...string) ([]byte, error) { |  | ||||||
| 		return []byte("pong"), nil |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### Register the command |  | ||||||
|  |  | ||||||
| Add the command to the Commands map with a pattern key that can be matched by golang/regexp.Match |  | ||||||
|  |  | ||||||
| ```go |  | ||||||
| import "github.com/micro/go-micro/agent/command" |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	command.Commands["^ping$"] = Ping() |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### Rebuild Micro |  | ||||||
|  |  | ||||||
| Build binary |  | ||||||
| ```shell |  | ||||||
| cd github.com/micro/micro |  | ||||||
|  |  | ||||||
| // For local use |  | ||||||
| go build -i -o micro ./main.go |  | ||||||
|  |  | ||||||
| // For docker image |  | ||||||
| CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w' -i -o micro ./main.go |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ## Inputs |  | ||||||
|  |  | ||||||
| Inputs are plugins for communication e.g Slack, HipChat, XMPP, IRC, SMTP, etc, etc.  |  | ||||||
|  |  | ||||||
| New inputs can be added in the following way. |  | ||||||
|  |  | ||||||
| ### Write an Input |  | ||||||
|  |  | ||||||
| Write an input that satisfies the Input interface. |  | ||||||
|  |  | ||||||
| ```go |  | ||||||
| type Input interface { |  | ||||||
| 	// Provide cli flags |  | ||||||
| 	Flags() []cli.Flag |  | ||||||
| 	// Initialise input using cli context |  | ||||||
| 	Init(*cli.Context) error |  | ||||||
| 	// Stream events from the input |  | ||||||
| 	Stream() (Conn, error) |  | ||||||
| 	// Start the input |  | ||||||
| 	Start() error |  | ||||||
| 	// Stop the input |  | ||||||
| 	Stop() error |  | ||||||
| 	// name of the input |  | ||||||
| 	String() string |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### Register the input |  | ||||||
|  |  | ||||||
| Add the input to the Inputs map. |  | ||||||
|  |  | ||||||
| ```go |  | ||||||
| import "github.com/micro/micro/bot/input" |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	input.Inputs["name"] = MyInput |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### Rebuild Micro |  | ||||||
|  |  | ||||||
| Build binary |  | ||||||
| ```shell |  | ||||||
| cd github.com/micro/micro |  | ||||||
|  |  | ||||||
| // For local use |  | ||||||
| go build -i -o micro ./main.go |  | ||||||
|  |  | ||||||
| // For docker image |  | ||||||
| CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -ldflags '-w' -i -o micro ./main.go |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ## Services |  | ||||||
|  |  | ||||||
| The micro bot supports the ability to create commands as micro services.  |  | ||||||
|  |  | ||||||
| ### How does it work? |  | ||||||
|  |  | ||||||
| The bot watches the service registry for services with it's namespace. The default namespace is `go.micro.bot`.  |  | ||||||
| Any service within this namespace will automatically be added to the list of available commands. When a command  |  | ||||||
| is executed, the bot will call the service with method `Command.Exec`. It also expects the method `Command.Help`  |  | ||||||
| to exist for usage info. |  | ||||||
|  |  | ||||||
|  |  | ||||||
| The service interface is as follows and can be found at [go-micro/agent/proto](https://github.com/micro/go-micro/agent/blob/master/proto/bot.proto) |  | ||||||
|  |  | ||||||
| ``` |  | ||||||
| syntax = "proto3"; |  | ||||||
|  |  | ||||||
| package go.micro.bot; |  | ||||||
|  |  | ||||||
| service Command { |  | ||||||
| 	rpc Help(HelpRequest) returns (HelpResponse) {}; |  | ||||||
| 	rpc Exec(ExecRequest) returns (ExecResponse) {}; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message HelpRequest { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message HelpResponse { |  | ||||||
| 	string usage = 1; |  | ||||||
| 	string description = 2; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message ExecRequest { |  | ||||||
| 	repeated string args = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| message ExecResponse { |  | ||||||
| 	bytes result = 1; |  | ||||||
| 	string error = 2; |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ### Example |  | ||||||
|  |  | ||||||
| Here's an example echo command as a microservice |  | ||||||
|  |  | ||||||
| ```go |  | ||||||
| package main |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"strings" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro" |  | ||||||
| 	"golang.org/x/net/context" |  | ||||||
|  |  | ||||||
| 	proto "github.com/micro/go-micro/agent/proto" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type Command struct{} |  | ||||||
|  |  | ||||||
| // Help returns the command usage |  | ||||||
| func (c *Command) Help(ctx context.Context, req *proto.HelpRequest, rsp *proto.HelpResponse) error { |  | ||||||
| 	// Usage should include the name of the command |  | ||||||
| 	rsp.Usage = "echo" |  | ||||||
| 	rsp.Description = "This is an example bot command as a micro service which echos the message" |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Exec executes the command |  | ||||||
| func (c *Command) Exec(ctx context.Context, req *proto.ExecRequest, rsp *proto.ExecResponse) error { |  | ||||||
| 	rsp.Result = []byte(strings.Join(req.Args, " ")) |  | ||||||
| 	// rsp.Error could be set to return an error instead |  | ||||||
| 	// the function error would only be used for service level issues |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func main() { |  | ||||||
| 	service := micro.NewService( |  | ||||||
| 		micro.Name("go.micro.bot.echo"), |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	service.Init() |  | ||||||
|  |  | ||||||
| 	proto.RegisterCommandHandler(service.Server(), new(Command)) |  | ||||||
|  |  | ||||||
| 	if err := service.Run(); err != nil { |  | ||||||
| 		fmt.Println(err) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| # Go API [](https://opensource.org/licenses/Apache-2.0) [](https://godoc.org/github.com/micro/go-micro/api) [](https://travis-ci.org/micro/go-micro/api) [](https://goreportcard.com/report/github.com/micro/go-micro/api) |  | ||||||
|  |  | ||||||
| Go API is a pluggable API framework driven by service discovery to help build powerful public API gateways. |  | ||||||
|  |  | ||||||
| ## Overview |  | ||||||
|  |  | ||||||
| The Go API library provides api gateway routing capabilities. A microservice architecture decouples application logic into  |  | ||||||
| separate service. An api gateway provides a single entry point to consolidate these services into a unified api. The  |  | ||||||
| Go API uses routes defined in service discovery metadata to generate routing rules and serve http requests. |  | ||||||
|  |  | ||||||
| <img src="https://micro.mu/docs/images/go-api.png?v=1" alt="Go API" /> |  | ||||||
|  |  | ||||||
| Go API is the basis for the [micro api](https://micro.mu/docs/api.html). |  | ||||||
|  |  | ||||||
| ## Getting Started |  | ||||||
|  |  | ||||||
| See the [docs](https://micro.mu/docs/go-api.html) to learn more |  | ||||||
|  |  | ||||||
| @@ -8,8 +8,8 @@ import ( | |||||||
| 	"github.com/micro/go-micro/api/handler" | 	"github.com/micro/go-micro/api/handler" | ||||||
| 	api "github.com/micro/go-micro/api/proto" | 	api "github.com/micro/go-micro/api/proto" | ||||||
| 	"github.com/micro/go-micro/client" | 	"github.com/micro/go-micro/client" | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/errors" | 	"github.com/micro/go-micro/errors" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| 	"github.com/micro/go-micro/util/ctx" | 	"github.com/micro/go-micro/util/ctx" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -9,8 +9,8 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	api "github.com/micro/go-micro/api/proto" | 	api "github.com/micro/go-micro/api/proto" | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func requestToProto(r *http.Request) (*api.Request, error) { | func requestToProto(r *http.Request) (*api.Request, error) { | ||||||
|   | |||||||
| @@ -120,7 +120,7 @@ func (c *conn) writeLoop() { | |||||||
| 		opts = append(opts, broker.Queue(c.queue)) | 		opts = append(opts, broker.Queue(c.queue)) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subscriber, err := c.b.Subscribe(c.topic, func(p broker.Publication) error { | 	subscriber, err := c.b.Subscribe(c.topic, func(p broker.Event) error { | ||||||
| 		b, err := json.Marshal(p.Message()) | 		b, err := json.Marshal(p.Message()) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil | 			return nil | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/api" | 	"github.com/micro/go-micro/api" | ||||||
| 	"github.com/micro/go-micro/api/handler" | 	"github.com/micro/go-micro/api/handler" | ||||||
| 	"github.com/micro/go-micro/selector" | 	"github.com/micro/go-micro/client/selector" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -73,7 +73,7 @@ func (h *httpHandler) getService(r *http.Request) (string, error) { | |||||||
| 		return "", nil | 		return "", nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return fmt.Sprintf("http://%s:%d", s.Address, s.Port), nil | 	return fmt.Sprintf("http://%s", s.Address), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (h *httpHandler) String() string { | func (h *httpHandler) String() string { | ||||||
|   | |||||||
| @@ -4,14 +4,12 @@ import ( | |||||||
| 	"net" | 	"net" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/http/httptest" | 	"net/http/httptest" | ||||||
| 	"strconv" |  | ||||||
| 	"strings" |  | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/api/handler" | 	"github.com/micro/go-micro/api/handler" | ||||||
| 	"github.com/micro/go-micro/api/router" | 	"github.com/micro/go-micro/api/router" | ||||||
| 	regRouter "github.com/micro/go-micro/api/router/registry" | 	regRouter "github.com/micro/go-micro/api/router/registry" | ||||||
| 	"github.com/micro/go-micro/cmd" | 	"github.com/micro/go-micro/config/cmd" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/registry/memory" | 	"github.com/micro/go-micro/registry/memory" | ||||||
| ) | ) | ||||||
| @@ -26,21 +24,12 @@ func testHttp(t *testing.T, path, service, ns string) { | |||||||
| 	} | 	} | ||||||
| 	defer l.Close() | 	defer l.Close() | ||||||
|  |  | ||||||
| 	parts := strings.Split(l.Addr().String(), ":") |  | ||||||
|  |  | ||||||
| 	var host string |  | ||||||
| 	var port int |  | ||||||
|  |  | ||||||
| 	host = parts[0] |  | ||||||
| 	port, _ = strconv.Atoi(parts[1]) |  | ||||||
|  |  | ||||||
| 	s := ®istry.Service{ | 	s := ®istry.Service{ | ||||||
| 		Name: service, | 		Name: service, | ||||||
| 		Nodes: []*registry.Node{ | 		Nodes: []*registry.Node{ | ||||||
| 			®istry.Node{ | 			®istry.Node{ | ||||||
| 				Id:      service + "-1", | 				Id:      service + "-1", | ||||||
| 				Address: host, | 				Address: l.Addr().String(), | ||||||
| 				Port:    port, |  | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -14,12 +14,12 @@ import ( | |||||||
| 	"github.com/micro/go-micro/api/handler" | 	"github.com/micro/go-micro/api/handler" | ||||||
| 	proto "github.com/micro/go-micro/api/internal/proto" | 	proto "github.com/micro/go-micro/api/internal/proto" | ||||||
| 	"github.com/micro/go-micro/client" | 	"github.com/micro/go-micro/client" | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/codec" | 	"github.com/micro/go-micro/codec" | ||||||
| 	"github.com/micro/go-micro/codec/jsonrpc" | 	"github.com/micro/go-micro/codec/jsonrpc" | ||||||
| 	"github.com/micro/go-micro/codec/protorpc" | 	"github.com/micro/go-micro/codec/protorpc" | ||||||
| 	"github.com/micro/go-micro/errors" | 	"github.com/micro/go-micro/errors" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| 	"github.com/micro/go-micro/util/ctx" | 	"github.com/micro/go-micro/util/ctx" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -120,32 +120,6 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||||||
| 	var rsp []byte | 	var rsp []byte | ||||||
|  |  | ||||||
| 	switch { | 	switch { | ||||||
| 	// json codecs |  | ||||||
| 	case hasCodec(ct, jsonCodecs): |  | ||||||
| 		var request json.RawMessage |  | ||||||
| 		// if the extracted payload isn't empty lets use it |  | ||||||
| 		if len(br) > 0 { |  | ||||||
| 			request = json.RawMessage(br) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// create request/response |  | ||||||
| 		var response json.RawMessage |  | ||||||
|  |  | ||||||
| 		req := c.NewRequest( |  | ||||||
| 			service.Name, |  | ||||||
| 			service.Endpoint.Name, |  | ||||||
| 			&request, |  | ||||||
| 			client.WithContentType(ct), |  | ||||||
| 		) |  | ||||||
|  |  | ||||||
| 		// make the call |  | ||||||
| 		if err := c.Call(cx, req, &response, client.WithSelectOption(so)); err != nil { |  | ||||||
| 			writeError(w, r, err) |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// marshall response |  | ||||||
| 		rsp, _ = response.MarshalJSON() |  | ||||||
| 	// proto codecs | 	// proto codecs | ||||||
| 	case hasCodec(ct, protoCodecs): | 	case hasCodec(ct, protoCodecs): | ||||||
| 		request := &proto.Message{} | 		request := &proto.Message{} | ||||||
| @@ -173,10 +147,38 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |||||||
| 		// marshall response | 		// marshall response | ||||||
| 		rsp, _ = response.Marshal() | 		rsp, _ = response.Marshal() | ||||||
| 	default: | 	default: | ||||||
| 		http.Error(w, "Unsupported Content-Type", 400) | 		// if json codec is not present set to json | ||||||
|  | 		if !hasCodec(ct, jsonCodecs) { | ||||||
|  | 			ct = "application/json" | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// default to trying json | ||||||
|  | 		var request json.RawMessage | ||||||
|  | 		// if the extracted payload isn't empty lets use it | ||||||
|  | 		if len(br) > 0 { | ||||||
|  | 			request = json.RawMessage(br) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// create request/response | ||||||
|  | 		var response json.RawMessage | ||||||
|  |  | ||||||
|  | 		req := c.NewRequest( | ||||||
|  | 			service.Name, | ||||||
|  | 			service.Endpoint.Name, | ||||||
|  | 			&request, | ||||||
|  | 			client.WithContentType(ct), | ||||||
|  | 		) | ||||||
|  |  | ||||||
|  | 		// make the call | ||||||
|  | 		if err := c.Call(cx, req, &response, client.WithSelectOption(so)); err != nil { | ||||||
|  | 			writeError(w, r, err) | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		// marshall response | ||||||
|  | 		rsp, _ = response.MarshalJSON() | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// write the response | 	// write the response | ||||||
| 	writeResponse(w, r, rsp) | 	writeResponse(w, r, rsp) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/api" | 	"github.com/micro/go-micro/api" | ||||||
| 	"github.com/micro/go-micro/api/handler" | 	"github.com/micro/go-micro/api/handler" | ||||||
| 	"github.com/micro/go-micro/selector" | 	"github.com/micro/go-micro/client/selector" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const ( | const ( | ||||||
| @@ -79,7 +79,7 @@ func (wh *webHandler) getService(r *http.Request) (string, error) { | |||||||
| 		return "", nil | 		return "", nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return fmt.Sprintf("http://%s:%d", s.Address, s.Port), nil | 	return fmt.Sprintf("http://%s", s.Address), nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // serveWebSocket used to serve a web socket proxied connection | // serveWebSocket used to serve a web socket proxied connection | ||||||
|   | |||||||
| @@ -3,7 +3,7 @@ package router | |||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/api/resolver" | 	"github.com/micro/go-micro/api/resolver" | ||||||
| 	"github.com/micro/go-micro/api/resolver/micro" | 	"github.com/micro/go-micro/api/resolver/micro" | ||||||
| 	"github.com/micro/go-micro/cmd" | 	"github.com/micro/go-micro/config/cmd" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,28 +3,28 @@ package broker | |||||||
|  |  | ||||||
| // Broker is an interface used for asynchronous messaging. | // Broker is an interface used for asynchronous messaging. | ||||||
| type Broker interface { | type Broker interface { | ||||||
|  | 	Init(...Option) error | ||||||
| 	Options() Options | 	Options() Options | ||||||
| 	Address() string | 	Address() string | ||||||
| 	Connect() error | 	Connect() error | ||||||
| 	Disconnect() error | 	Disconnect() error | ||||||
| 	Init(...Option) error | 	Publish(topic string, m *Message, opts ...PublishOption) error | ||||||
| 	Publish(string, *Message, ...PublishOption) error | 	Subscribe(topic string, h Handler, opts ...SubscribeOption) (Subscriber, error) | ||||||
| 	Subscribe(string, Handler, ...SubscribeOption) (Subscriber, error) |  | ||||||
| 	String() string | 	String() string | ||||||
| } | } | ||||||
|  |  | ||||||
| // Handler is used to process messages via a subscription of a topic. | // Handler is used to process messages via a subscription of a topic. | ||||||
| // The handler is passed a publication interface which contains the | // The handler is passed a publication interface which contains the | ||||||
| // message and optional Ack method to acknowledge receipt of the message. | // message and optional Ack method to acknowledge receipt of the message. | ||||||
| type Handler func(Publication) error | type Handler func(Event) error | ||||||
|  |  | ||||||
| type Message struct { | type Message struct { | ||||||
| 	Header map[string]string | 	Header map[string]string | ||||||
| 	Body   []byte | 	Body   []byte | ||||||
| } | } | ||||||
|  |  | ||||||
| // Publication is given to a subscription handler for processing | // Event is given to a subscription handler for processing | ||||||
| type Publication interface { | type Event interface { | ||||||
| 	Topic() string | 	Topic() string | ||||||
| 	Message() *Message | 	Message() *Message | ||||||
| 	Ack() error | 	Ack() error | ||||||
|   | |||||||
| @@ -14,13 +14,11 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.0-123", | 						Id:      "foo-1.0.0-123", | ||||||
| 						Address: "localhost", | 						Address: "localhost:9999", | ||||||
| 						Port:    9999, |  | ||||||
| 					}, | 					}, | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.0-321", | 						Id:      "foo-1.0.0-321", | ||||||
| 						Address: "localhost", | 						Address: "localhost:9999", | ||||||
| 						Port:    9999, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| @@ -30,8 +28,7 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.1-321", | 						Id:      "foo-1.0.1-321", | ||||||
| 						Address: "localhost", | 						Address: "localhost:6666", | ||||||
| 						Port:    6666, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| @@ -41,8 +38,7 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.3-345", | 						Id:      "foo-1.0.3-345", | ||||||
| 						Address: "localhost", | 						Address: "localhost:8888", | ||||||
| 						Port:    8888, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
|   | |||||||
| @@ -13,8 +13,6 @@ import ( | |||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"runtime" | 	"runtime" | ||||||
| 	"strconv" |  | ||||||
| 	"strings" |  | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| @@ -59,7 +57,7 @@ type httpSubscriber struct { | |||||||
| 	hb    *httpBroker | 	hb    *httpBroker | ||||||
| } | } | ||||||
|  |  | ||||||
| type httpPublication struct { | type httpEvent struct { | ||||||
| 	m *Message | 	m *Message | ||||||
| 	t string | 	t string | ||||||
| } | } | ||||||
| @@ -155,15 +153,15 @@ func newHttpBroker(opts ...Option) Broker { | |||||||
| 	return h | 	return h | ||||||
| } | } | ||||||
|  |  | ||||||
| func (h *httpPublication) Ack() error { | func (h *httpEvent) Ack() error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (h *httpPublication) Message() *Message { | func (h *httpEvent) Message() *Message { | ||||||
| 	return h.m | 	return h.m | ||||||
| } | } | ||||||
|  |  | ||||||
| func (h *httpPublication) Topic() string { | func (h *httpEvent) Topic() string { | ||||||
| 	return h.t | 	return h.t | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -323,7 +321,7 @@ func (h *httpBroker) ServeHTTP(w http.ResponseWriter, req *http.Request) { | |||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	p := &httpPublication{m: m, t: topic} | 	p := &httpEvent{m: m, t: topic} | ||||||
| 	id := req.Form.Get("id") | 	id := req.Form.Get("id") | ||||||
|  |  | ||||||
| 	h.RLock() | 	h.RLock() | ||||||
| @@ -403,6 +401,7 @@ func (h *httpBroker) Connect() error { | |||||||
| 	go func() { | 	go func() { | ||||||
| 		h.run(l) | 		h.run(l) | ||||||
| 		h.Lock() | 		h.Lock() | ||||||
|  | 		h.opts.Addrs = []string{addr} | ||||||
| 		h.address = addr | 		h.address = addr | ||||||
| 		h.Unlock() | 		h.Unlock() | ||||||
| 	}() | 	}() | ||||||
| @@ -542,7 +541,7 @@ func (h *httpBroker) Publish(topic string, msg *Message, opts ...PublishOption) | |||||||
| 		vals := url.Values{} | 		vals := url.Values{} | ||||||
| 		vals.Add("id", node.Id) | 		vals.Add("id", node.Id) | ||||||
|  |  | ||||||
| 		uri := fmt.Sprintf("%s://%s:%d%s?%s", scheme, node.Address, node.Port, DefaultSubPath, vals.Encode()) | 		uri := fmt.Sprintf("%s://%s%s?%s", scheme, node.Address, DefaultSubPath, vals.Encode()) | ||||||
| 		r, err := h.c.Post(uri, "application/json", bytes.NewReader(b)) | 		r, err := h.c.Post(uri, "application/json", bytes.NewReader(b)) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| @@ -613,12 +612,15 @@ func (h *httpBroker) Publish(topic string, msg *Message, opts ...PublishOption) | |||||||
| } | } | ||||||
|  |  | ||||||
| func (h *httpBroker) Subscribe(topic string, handler Handler, opts ...SubscribeOption) (Subscriber, error) { | func (h *httpBroker) Subscribe(topic string, handler Handler, opts ...SubscribeOption) (Subscriber, error) { | ||||||
|  | 	var err error | ||||||
|  | 	var host, port string | ||||||
| 	options := NewSubscribeOptions(opts...) | 	options := NewSubscribeOptions(opts...) | ||||||
|  |  | ||||||
| 	// parse address for host, port | 	// parse address for host, port | ||||||
| 	parts := strings.Split(h.Address(), ":") | 	host, port, err = net.SplitHostPort(h.Address()) | ||||||
| 	host := strings.Join(parts[:len(parts)-1], ":") | 	if err != nil { | ||||||
| 	port, _ := strconv.Atoi(parts[len(parts)-1]) | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	addr, err := maddr.Extract(host) | 	addr, err := maddr.Extract(host) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -637,8 +639,7 @@ func (h *httpBroker) Subscribe(topic string, handler Handler, opts ...SubscribeO | |||||||
| 	// register service | 	// register service | ||||||
| 	node := ®istry.Node{ | 	node := ®istry.Node{ | ||||||
| 		Id:      id, | 		Id:      id, | ||||||
| 		Address: addr, | 		Address: mnet.HostPort(addr, port), | ||||||
| 		Port:    port, |  | ||||||
| 		Metadata: map[string]string{ | 		Metadata: map[string]string{ | ||||||
| 			"secure": fmt.Sprintf("%t", secure), | 			"secure": fmt.Sprintf("%t", secure), | ||||||
| 		}, | 		}, | ||||||
|   | |||||||
| @@ -47,7 +47,7 @@ func sub(be *testing.B, c int) { | |||||||
| 	done := make(chan bool, c) | 	done := make(chan bool, c) | ||||||
|  |  | ||||||
| 	for i := 0; i < c; i++ { | 	for i := 0; i < c; i++ { | ||||||
| 		sub, err := b.Subscribe(topic, func(p Publication) error { | 		sub, err := b.Subscribe(topic, func(p Event) error { | ||||||
| 			done <- true | 			done <- true | ||||||
| 			m := p.Message() | 			m := p.Message() | ||||||
|  |  | ||||||
| @@ -107,7 +107,7 @@ func pub(be *testing.B, c int) { | |||||||
|  |  | ||||||
| 	done := make(chan bool, c*4) | 	done := make(chan bool, c*4) | ||||||
|  |  | ||||||
| 	sub, err := b.Subscribe(topic, func(p Publication) error { | 	sub, err := b.Subscribe(topic, func(p Event) error { | ||||||
| 		done <- true | 		done <- true | ||||||
| 		m := p.Message() | 		m := p.Message() | ||||||
| 		if string(m.Body) != string(msg.Body) { | 		if string(m.Body) != string(msg.Body) { | ||||||
| @@ -175,7 +175,7 @@ func TestBroker(t *testing.T) { | |||||||
|  |  | ||||||
| 	done := make(chan bool) | 	done := make(chan bool) | ||||||
|  |  | ||||||
| 	sub, err := b.Subscribe("test", func(p Publication) error { | 	sub, err := b.Subscribe("test", func(p Event) error { | ||||||
| 		m := p.Message() | 		m := p.Message() | ||||||
|  |  | ||||||
| 		if string(m.Body) != string(msg.Body) { | 		if string(m.Body) != string(msg.Body) { | ||||||
| @@ -224,7 +224,7 @@ func TestConcurrentSubBroker(t *testing.T) { | |||||||
| 	var wg sync.WaitGroup | 	var wg sync.WaitGroup | ||||||
|  |  | ||||||
| 	for i := 0; i < 10; i++ { | 	for i := 0; i < 10; i++ { | ||||||
| 		sub, err := b.Subscribe("test", func(p Publication) error { | 		sub, err := b.Subscribe("test", func(p Event) error { | ||||||
| 			defer wg.Done() | 			defer wg.Done() | ||||||
|  |  | ||||||
| 			m := p.Message() | 			m := p.Message() | ||||||
| @@ -279,7 +279,7 @@ func TestConcurrentPubBroker(t *testing.T) { | |||||||
|  |  | ||||||
| 	var wg sync.WaitGroup | 	var wg sync.WaitGroup | ||||||
|  |  | ||||||
| 	sub, err := b.Subscribe("test", func(p Publication) error { | 	sub, err := b.Subscribe("test", func(p Event) error { | ||||||
| 		defer wg.Done() | 		defer wg.Done() | ||||||
|  |  | ||||||
| 		m := p.Message() | 		m := p.Message() | ||||||
|   | |||||||
| @@ -3,21 +3,26 @@ package memory | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"math/rand" | ||||||
| 	"sync" | 	"sync" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/micro/go-micro/broker" | 	"github.com/micro/go-micro/broker" | ||||||
|  | 	maddr "github.com/micro/go-micro/util/addr" | ||||||
|  | 	mnet "github.com/micro/go-micro/util/net" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type memoryBroker struct { | type memoryBroker struct { | ||||||
| 	opts broker.Options | 	opts broker.Options | ||||||
|  |  | ||||||
|  | 	addr string | ||||||
| 	sync.RWMutex | 	sync.RWMutex | ||||||
| 	connected   bool | 	connected   bool | ||||||
| 	Subscribers map[string][]*memorySubscriber | 	Subscribers map[string][]*memorySubscriber | ||||||
| } | } | ||||||
|  |  | ||||||
| type memoryPublication struct { | type memoryEvent struct { | ||||||
| 	topic   string | 	topic   string | ||||||
| 	message *broker.Message | 	message *broker.Message | ||||||
| } | } | ||||||
| @@ -35,7 +40,7 @@ func (m *memoryBroker) Options() broker.Options { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (m *memoryBroker) Address() string { | func (m *memoryBroker) Address() string { | ||||||
| 	return "" | 	return m.addr | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *memoryBroker) Connect() error { | func (m *memoryBroker) Connect() error { | ||||||
| @@ -46,6 +51,15 @@ func (m *memoryBroker) Connect() error { | |||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	addr, err := maddr.Extract("::") | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	i := rand.Intn(20000) | ||||||
|  | 	// set addr with port | ||||||
|  | 	addr = mnet.HostPort(addr, 10000+i) | ||||||
|  |  | ||||||
|  | 	m.addr = addr | ||||||
| 	m.connected = true | 	m.connected = true | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| @@ -72,19 +86,19 @@ func (m *memoryBroker) Init(opts ...broker.Option) error { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (m *memoryBroker) Publish(topic string, message *broker.Message, opts ...broker.PublishOption) error { | func (m *memoryBroker) Publish(topic string, message *broker.Message, opts ...broker.PublishOption) error { | ||||||
| 	m.Lock() | 	m.RLock() | ||||||
| 	defer m.Unlock() |  | ||||||
|  |  | ||||||
| 	if !m.connected { | 	if !m.connected { | ||||||
|  | 		m.RUnlock() | ||||||
| 		return errors.New("not connected") | 		return errors.New("not connected") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	subs, ok := m.Subscribers[topic] | 	subs, ok := m.Subscribers[topic] | ||||||
|  | 	m.RUnlock() | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	p := &memoryPublication{ | 	p := &memoryEvent{ | ||||||
| 		topic:   topic, | 		topic:   topic, | ||||||
| 		message: message, | 		message: message, | ||||||
| 	} | 	} | ||||||
| @@ -99,12 +113,12 @@ func (m *memoryBroker) Publish(topic string, message *broker.Message, opts ...br | |||||||
| } | } | ||||||
|  |  | ||||||
| func (m *memoryBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) { | func (m *memoryBroker) Subscribe(topic string, handler broker.Handler, opts ...broker.SubscribeOption) (broker.Subscriber, error) { | ||||||
| 	m.Lock() | 	m.RLock() | ||||||
| 	defer m.Unlock() |  | ||||||
|  |  | ||||||
| 	if !m.connected { | 	if !m.connected { | ||||||
|  | 		m.RUnlock() | ||||||
| 		return nil, errors.New("not connected") | 		return nil, errors.New("not connected") | ||||||
| 	} | 	} | ||||||
|  | 	m.RUnlock() | ||||||
|  |  | ||||||
| 	var options broker.SubscribeOptions | 	var options broker.SubscribeOptions | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| @@ -119,7 +133,9 @@ func (m *memoryBroker) Subscribe(topic string, handler broker.Handler, opts ...b | |||||||
| 		opts:    options, | 		opts:    options, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	m.Lock() | ||||||
| 	m.Subscribers[topic] = append(m.Subscribers[topic], sub) | 	m.Subscribers[topic] = append(m.Subscribers[topic], sub) | ||||||
|  | 	m.Unlock() | ||||||
|  |  | ||||||
| 	go func() { | 	go func() { | ||||||
| 		<-sub.exit | 		<-sub.exit | ||||||
| @@ -142,15 +158,15 @@ func (m *memoryBroker) String() string { | |||||||
| 	return "memory" | 	return "memory" | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *memoryPublication) Topic() string { | func (m *memoryEvent) Topic() string { | ||||||
| 	return m.topic | 	return m.topic | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *memoryPublication) Message() *broker.Message { | func (m *memoryEvent) Message() *broker.Message { | ||||||
| 	return m.message | 	return m.message | ||||||
| } | } | ||||||
|  |  | ||||||
| func (m *memoryPublication) Ack() error { | func (m *memoryEvent) Ack() error { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -169,6 +185,7 @@ func (m *memorySubscriber) Unsubscribe() error { | |||||||
|  |  | ||||||
| func NewBroker(opts ...broker.Option) broker.Broker { | func NewBroker(opts ...broker.Option) broker.Broker { | ||||||
| 	var options broker.Options | 	var options broker.Options | ||||||
|  | 	rand.Seed(time.Now().UnixNano()) | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		o(&options) | 		o(&options) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ func TestMemoryBroker(t *testing.T) { | |||||||
| 	topic := "test" | 	topic := "test" | ||||||
| 	count := 10 | 	count := 10 | ||||||
|  |  | ||||||
| 	fn := func(p broker.Publication) error { | 	fn := func(p broker.Event) error { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,18 +13,19 @@ import ( | |||||||
| ) | ) | ||||||
|  |  | ||||||
| type natsBroker struct { | type natsBroker struct { | ||||||
|  | 	sync.Once | ||||||
| 	sync.RWMutex | 	sync.RWMutex | ||||||
| 	addrs   []string | 	addrs   []string | ||||||
| 	conn    *nats.Conn | 	conn    *nats.Conn | ||||||
| 	opts    broker.Options | 	opts    broker.Options | ||||||
| 	nopts   nats.Options | 	nopts   nats.Options | ||||||
| 	drain   bool | 	drain   bool | ||||||
|  | 	closeCh chan (error) | ||||||
| } | } | ||||||
|  |  | ||||||
| type subscriber struct { | type subscriber struct { | ||||||
| 	s    *nats.Subscription | 	s    *nats.Subscription | ||||||
| 	opts broker.SubscribeOptions | 	opts broker.SubscribeOptions | ||||||
| 	drain bool |  | ||||||
| } | } | ||||||
|  |  | ||||||
| type publication struct { | type publication struct { | ||||||
| @@ -54,9 +55,6 @@ func (s *subscriber) Topic() string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (s *subscriber) Unsubscribe() error { | func (s *subscriber) Unsubscribe() error { | ||||||
| 	if s.drain { |  | ||||||
| 		return s.s.Drain() |  | ||||||
| 	} |  | ||||||
| 	return s.s.Unsubscribe() | 	return s.s.Unsubscribe() | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -122,20 +120,17 @@ func (n *natsBroker) Connect() error { | |||||||
|  |  | ||||||
| func (n *natsBroker) Disconnect() error { | func (n *natsBroker) Disconnect() error { | ||||||
| 	n.RLock() | 	n.RLock() | ||||||
|  | 	defer n.RUnlock() | ||||||
| 	if n.drain { | 	if n.drain { | ||||||
| 		n.conn.Drain() | 		n.conn.Drain() | ||||||
| 	} else { | 		return <-n.closeCh | ||||||
| 		n.conn.Close() |  | ||||||
| 	} | 	} | ||||||
| 	n.RUnlock() | 	n.conn.Close() | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (n *natsBroker) Init(opts ...broker.Option) error { | func (n *natsBroker) Init(opts ...broker.Option) error { | ||||||
| 	for _, o := range opts { | 	n.setOption(opts...) | ||||||
| 		o(&n.opts) |  | ||||||
| 	} |  | ||||||
| 	n.addrs = setAddrs(n.opts.Addrs) |  | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -167,11 +162,6 @@ func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...bro | |||||||
| 		o(&opt) | 		o(&opt) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var drain bool |  | ||||||
| 	if _, ok := opt.Context.Value(drainSubscriptionKey{}).(bool); ok { |  | ||||||
| 		drain = true |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	fn := func(msg *nats.Msg) { | 	fn := func(msg *nats.Msg) { | ||||||
| 		var m broker.Message | 		var m broker.Message | ||||||
| 		if err := n.opts.Codec.Unmarshal(msg.Data, &m); err != nil { | 		if err := n.opts.Codec.Unmarshal(msg.Data, &m); err != nil { | ||||||
| @@ -193,7 +183,7 @@ func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...bro | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	return &subscriber{s: sub, opts: opt, drain: drain}, nil | 	return &subscriber{s: sub, opts: opt}, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (n *natsBroker) String() string { | func (n *natsBroker) String() string { | ||||||
| @@ -207,39 +197,59 @@ func NewBroker(opts ...broker.Option) broker.Broker { | |||||||
| 		Context: context.Background(), | 		Context: context.Background(), | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	n := &natsBroker{ | ||||||
|  | 		opts: options, | ||||||
|  | 	} | ||||||
|  | 	n.setOption(opts...) | ||||||
|  |  | ||||||
|  | 	return n | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (n *natsBroker) setOption(opts ...broker.Option) { | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		o(&options) | 		o(&n.opts) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	natsOpts := nats.GetDefaultOptions() | 	n.Once.Do(func() { | ||||||
| 	if n, ok := options.Context.Value(optionsKey{}).(nats.Options); ok { | 		n.nopts = nats.GetDefaultOptions() | ||||||
| 		natsOpts = n | 	}) | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	var drain bool | 	if nopts, ok := n.opts.Context.Value(optionsKey{}).(nats.Options); ok { | ||||||
| 	if _, ok := options.Context.Value(drainSubscriptionKey{}).(bool); ok { | 		n.nopts = nopts | ||||||
| 		drain = true |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// broker.Options have higher priority than nats.Options | 	// broker.Options have higher priority than nats.Options | ||||||
| 	// only if Addrs, Secure or TLSConfig were not set through a broker.Option | 	// only if Addrs, Secure or TLSConfig were not set through a broker.Option | ||||||
| 	// we read them from nats.Option | 	// we read them from nats.Option | ||||||
| 	if len(options.Addrs) == 0 { | 	if len(n.opts.Addrs) == 0 { | ||||||
| 		options.Addrs = natsOpts.Servers | 		n.opts.Addrs = n.nopts.Servers | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if !options.Secure { | 	if !n.opts.Secure { | ||||||
| 		options.Secure = natsOpts.Secure | 		n.opts.Secure = n.nopts.Secure | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if options.TLSConfig == nil { | 	if n.opts.TLSConfig == nil { | ||||||
| 		options.TLSConfig = natsOpts.TLSConfig | 		n.opts.TLSConfig = n.nopts.TLSConfig | ||||||
|  | 	} | ||||||
|  | 	n.addrs = setAddrs(n.opts.Addrs) | ||||||
|  |  | ||||||
|  | 	if n.opts.Context.Value(drainConnectionKey{}) != nil { | ||||||
|  | 		n.drain = true | ||||||
|  | 		n.closeCh = make(chan error) | ||||||
|  | 		n.nopts.ClosedCB = n.onClose | ||||||
|  | 		n.nopts.AsyncErrorCB = n.onAsyncError | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| 	return &natsBroker{ | func (n *natsBroker) onClose(conn *nats.Conn) { | ||||||
| 		opts:  options, | 	n.closeCh <- nil | ||||||
| 		nopts: natsOpts, | } | ||||||
| 		addrs: setAddrs(options.Addrs), |  | ||||||
| 		drain: drain, | func (n *natsBroker) onAsyncError(conn *nats.Conn, sub *nats.Subscription, err error) { | ||||||
|  | 	// There are kinds of different async error nats might callback, but we are interested | ||||||
|  | 	// in ErrDrainTimeout only here. | ||||||
|  | 	if err == nats.ErrDrainTimeout { | ||||||
|  | 		n.closeCh <- err | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ import ( | |||||||
|  |  | ||||||
| type optionsKey struct{} | type optionsKey struct{} | ||||||
| type drainConnectionKey struct{} | type drainConnectionKey struct{} | ||||||
| type drainSubscriptionKey struct{} |  | ||||||
|  |  | ||||||
| // Options accepts nats.Options | // Options accepts nats.Options | ||||||
| func Options(opts nats.Options) broker.Option { | func Options(opts nats.Options) broker.Option { | ||||||
| @@ -16,10 +15,5 @@ func Options(opts nats.Options) broker.Option { | |||||||
|  |  | ||||||
| // DrainConnection will drain subscription on close | // DrainConnection will drain subscription on close | ||||||
| func DrainConnection() broker.Option { | func DrainConnection() broker.Option { | ||||||
| 	return setBrokerOption(drainConnectionKey{}, true) | 	return setBrokerOption(drainConnectionKey{}, struct{}{}) | ||||||
| } |  | ||||||
|  |  | ||||||
| // DrainSubscription will drain pending messages when unsubscribe |  | ||||||
| func DrainSubscription() broker.SubscribeOption { |  | ||||||
| 	return setSubscribeOption(drainSubscriptionKey{}, true) |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,14 +0,0 @@ | |||||||
| package client |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type buffer struct { |  | ||||||
| 	*bytes.Buffer |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (b *buffer) Close() error { |  | ||||||
| 	b.Buffer.Reset() |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -10,7 +10,7 @@ import ( | |||||||
|  |  | ||||||
| // Client is the interface used to make requests to services. | // Client is the interface used to make requests to services. | ||||||
| // It supports Request/Response via Transport and Publishing via the Broker. | // It supports Request/Response via Transport and Publishing via the Broker. | ||||||
| // It also supports bidiectional streaming of requests. | // It also supports bidirectional streaming of requests. | ||||||
| type Client interface { | type Client interface { | ||||||
| 	Init(...Option) error | 	Init(...Option) error | ||||||
| 	Options() Options | 	Options() Options | ||||||
|   | |||||||
| @@ -14,13 +14,11 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.0-123", | 						Id:      "foo-1.0.0-123", | ||||||
| 						Address: "localhost", | 						Address: "localhost:9999", | ||||||
| 						Port:    9999, |  | ||||||
| 					}, | 					}, | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.0-321", | 						Id:      "foo-1.0.0-321", | ||||||
| 						Address: "localhost", | 						Address: "localhost:9999", | ||||||
| 						Port:    9999, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| @@ -30,8 +28,7 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.1-321", | 						Id:      "foo-1.0.1-321", | ||||||
| 						Address: "localhost", | 						Address: "localhost:6666", | ||||||
| 						Port:    6666, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| @@ -41,8 +38,7 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.3-345", | 						Id:      "foo-1.0.3-345", | ||||||
| 						Address: "localhost", | 						Address: "localhost:8888", | ||||||
| 						Port:    8888, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
|   | |||||||
| @@ -1,14 +0,0 @@ | |||||||
| package grpc |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"bytes" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type buffer struct { |  | ||||||
| 	*bytes.Buffer |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (b *buffer) Close() error { |  | ||||||
| 	b.Buffer.Reset() |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| @@ -2,12 +2,18 @@ package grpc | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  |  | ||||||
|  | 	b "bytes" | ||||||
|  |  | ||||||
|  | 	"github.com/golang/protobuf/jsonpb" | ||||||
| 	"github.com/golang/protobuf/proto" | 	"github.com/golang/protobuf/proto" | ||||||
| 	"github.com/json-iterator/go" | 	jsoniter "github.com/json-iterator/go" | ||||||
| 	"github.com/micro/go-micro/codec" | 	"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/jsonrpc" | ||||||
| 	"github.com/micro/go-micro/codec/protorpc" | 	"github.com/micro/go-micro/codec/protorpc" | ||||||
|  | 	"google.golang.org/grpc" | ||||||
| 	"google.golang.org/grpc/encoding" | 	"google.golang.org/grpc/encoding" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -16,6 +22,8 @@ type protoCodec struct{} | |||||||
| type bytesCodec struct{} | type bytesCodec struct{} | ||||||
| type wrapCodec struct{ encoding.Codec } | type wrapCodec struct{ encoding.Codec } | ||||||
|  |  | ||||||
|  | var jsonpbMarshaler = &jsonpb.Marshaler{} | ||||||
|  |  | ||||||
| var ( | var ( | ||||||
| 	defaultGRPCCodecs = map[string]encoding.Codec{ | 	defaultGRPCCodecs = map[string]encoding.Codec{ | ||||||
| 		"application/json":         jsonCodec{}, | 		"application/json":         jsonCodec{}, | ||||||
| @@ -52,7 +60,28 @@ func (w wrapCodec) String() string { | |||||||
| 	return w.Codec.Name() | 	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) { | func (protoCodec) Marshal(v interface{}) ([]byte, error) { | ||||||
|  | 	b, ok := v.(*bytes.Frame) | ||||||
|  | 	if ok { | ||||||
|  | 		return b.Data, nil | ||||||
|  | 	} | ||||||
| 	return proto.Marshal(v.(proto.Message)) | 	return proto.Marshal(v.(proto.Message)) | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -86,13 +115,79 @@ func (bytesCodec) Name() string { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (jsonCodec) Marshal(v interface{}) ([]byte, error) { | func (jsonCodec) Marshal(v interface{}) ([]byte, error) { | ||||||
|  | 	if pb, ok := v.(proto.Message); ok { | ||||||
|  | 		s, err := jsonpbMarshaler.MarshalToString(pb) | ||||||
|  |  | ||||||
|  | 		return []byte(s), err | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return json.Marshal(v) | 	return json.Marshal(v) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (jsonCodec) Unmarshal(data []byte, v interface{}) error { | func (jsonCodec) Unmarshal(data []byte, v interface{}) error { | ||||||
|  | 	if pb, ok := v.(proto.Message); ok { | ||||||
|  | 		return jsonpb.Unmarshal(b.NewReader(data), pb) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return json.Unmarshal(data, v) | 	return json.Unmarshal(data, v) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (jsonCodec) Name() string { | func (jsonCodec) Name() string { | ||||||
| 	return "json" | 	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() | ||||||
|  | } | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ | |||||||
| package grpc | package grpc | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" |  | ||||||
| 	"context" | 	"context" | ||||||
| 	"crypto/tls" | 	"crypto/tls" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| @@ -12,13 +11,14 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/broker" | 	"github.com/micro/go-micro/broker" | ||||||
| 	"github.com/micro/go-micro/client" | 	"github.com/micro/go-micro/client" | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/codec" | 	"github.com/micro/go-micro/codec" | ||||||
| 	"github.com/micro/go-micro/errors" | 	"github.com/micro/go-micro/errors" | ||||||
| 	"github.com/micro/go-micro/metadata" | 	"github.com/micro/go-micro/metadata" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| 	"github.com/micro/go-micro/transport" | 	"github.com/micro/go-micro/transport" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/util/buf" | ||||||
| 	"google.golang.org/grpc" | 	"google.golang.org/grpc" | ||||||
| 	"google.golang.org/grpc/credentials" | 	"google.golang.org/grpc/credentials" | ||||||
| 	"google.golang.org/grpc/encoding" | 	"google.golang.org/grpc/encoding" | ||||||
| @@ -32,8 +32,9 @@ type grpcClient struct { | |||||||
| } | } | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
| 	encoding.RegisterCodec(jsonCodec{}) | 	encoding.RegisterCodec(wrapCodec{jsonCodec{}}) | ||||||
| 	encoding.RegisterCodec(bytesCodec{}) | 	encoding.RegisterCodec(wrapCodec{protoCodec{}}) | ||||||
|  | 	encoding.RegisterCodec(wrapCodec{bytesCodec{}}) | ||||||
| } | } | ||||||
|  |  | ||||||
| // secure returns the dial option for whether its a secure or insecure connection | // secure returns the dial option for whether its a secure or insecure connection | ||||||
| @@ -58,14 +59,14 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele | |||||||
|  |  | ||||||
| 	// get proxy address | 	// get proxy address | ||||||
| 	if prx := os.Getenv("MICRO_PROXY_ADDRESS"); len(prx) > 0 { | 	if prx := os.Getenv("MICRO_PROXY_ADDRESS"); len(prx) > 0 { | ||||||
| 		opts.Address = prx | 		opts.Address = []string{prx} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// return remote address | 	// return remote address | ||||||
| 	if len(opts.Address) > 0 { | 	if len(opts.Address) > 0 { | ||||||
| 		return func() (*registry.Node, error) { | 		return func() (*registry.Node, error) { | ||||||
| 			return ®istry.Node{ | 			return ®istry.Node{ | ||||||
| 				Address: opts.Address, | 				Address: opts.Address[0], | ||||||
| 			}, nil | 			}, nil | ||||||
| 		}, nil | 		}, nil | ||||||
| 	} | 	} | ||||||
| @@ -83,9 +84,6 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele | |||||||
|  |  | ||||||
| func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error { | func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error { | ||||||
| 	address := node.Address | 	address := node.Address | ||||||
| 	if node.Port > 0 { |  | ||||||
| 		address = fmt.Sprintf("%s:%d", address, node.Port) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	header := make(map[string]string) | 	header := make(map[string]string) | ||||||
| 	if md, ok := metadata.FromContext(ctx); ok { | 	if md, ok := metadata.FromContext(ctx); ok { | ||||||
| @@ -129,7 +127,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R | |||||||
| 	ch := make(chan error, 1) | 	ch := make(chan error, 1) | ||||||
|  |  | ||||||
| 	go func() { | 	go func() { | ||||||
| 		err := cc.Invoke(ctx, methodToGRPC(req.Endpoint(), req.Body()), req.Body(), rsp, grpc.ForceCodec(cf)) | 		err := cc.Invoke(ctx, methodToGRPC(req.Service(), req.Endpoint()), req.Body(), rsp, grpc.CallContentSubtype(cf.Name())) | ||||||
| 		ch <- microError(err) | 		ch <- microError(err) | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| @@ -145,9 +143,6 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R | |||||||
|  |  | ||||||
| func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, opts client.CallOptions) (client.Stream, error) { | func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, opts client.CallOptions) (client.Stream, error) { | ||||||
| 	address := node.Address | 	address := node.Address | ||||||
| 	if node.Port > 0 { |  | ||||||
| 		address = fmt.Sprintf("%s:%d", address, node.Port) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	header := make(map[string]string) | 	header := make(map[string]string) | ||||||
| 	if md, ok := metadata.FromContext(ctx); ok { | 	if md, ok := metadata.FromContext(ctx); ok { | ||||||
| @@ -177,7 +172,10 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client | |||||||
| 		dialCtx, cancel = context.WithCancel(ctx) | 		dialCtx, cancel = context.WithCancel(ctx) | ||||||
| 	} | 	} | ||||||
| 	defer cancel() | 	defer cancel() | ||||||
| 	cc, err := grpc.DialContext(dialCtx, address, grpc.WithDefaultCallOptions(grpc.ForceCodec(cf)), g.secure()) |  | ||||||
|  | 	wc := wrapCodec{cf} | ||||||
|  |  | ||||||
|  | 	cc, err := grpc.DialContext(dialCtx, address, grpc.WithDefaultCallOptions(grpc.ForceCodec(wc)), g.secure()) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) | 		return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err)) | ||||||
| 	} | 	} | ||||||
| @@ -188,15 +186,26 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client | |||||||
| 		ServerStreams: true, | 		ServerStreams: true, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	st, err := cc.NewStream(ctx, desc, methodToGRPC(req.Endpoint(), req.Body())) | 	st, err := cc.NewStream(ctx, desc, methodToGRPC(req.Service(), req.Endpoint())) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err)) | 		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{ | 	rsp := &response{ | ||||||
| 		conn:   cc, | 		conn:   cc, | ||||||
| 		stream: st, | 		stream: st, | ||||||
| 		codec:  cf, | 		codec:  cf, | ||||||
|  | 		gcodec: codec, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return &grpcStream{ | 	return &grpcStream{ | ||||||
| @@ -280,7 +289,7 @@ func (g *grpcClient) Options() client.Options { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (g *grpcClient) NewMessage(topic string, msg interface{}, opts ...client.MessageOption) client.Message { | func (g *grpcClient) NewMessage(topic string, msg interface{}, opts ...client.MessageOption) client.Message { | ||||||
| 	return newGRPCPublication(topic, msg, "application/octet-stream") | 	return newGRPCEvent(topic, msg, g.opts.ContentType, opts...) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (g *grpcClient) NewRequest(service, method string, req interface{}, reqOpts ...client.RequestOption) client.Request { | func (g *grpcClient) NewRequest(service, method string, req interface{}, reqOpts ...client.RequestOption) client.Request { | ||||||
| @@ -357,9 +366,9 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface | |||||||
| 	var gerr error | 	var gerr error | ||||||
|  |  | ||||||
| 	for i := 0; i <= callOpts.Retries; i++ { | 	for i := 0; i <= callOpts.Retries; i++ { | ||||||
| 		go func() { | 		go func(i int) { | ||||||
| 			ch <- call(i) | 			ch <- call(i) | ||||||
| 		}() | 		}(i) | ||||||
|  |  | ||||||
| 		select { | 		select { | ||||||
| 		case <-ctx.Done(): | 		case <-ctx.Done(): | ||||||
| @@ -440,10 +449,10 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli | |||||||
| 	var grr error | 	var grr error | ||||||
|  |  | ||||||
| 	for i := 0; i <= callOpts.Retries; i++ { | 	for i := 0; i <= callOpts.Retries; i++ { | ||||||
| 		go func() { | 		go func(i int) { | ||||||
| 			s, err := call(i) | 			s, err := call(i) | ||||||
| 			ch <- response{s, err} | 			ch <- response{s, err} | ||||||
| 		}() | 		}(i) | ||||||
|  |  | ||||||
| 		select { | 		select { | ||||||
| 		case <-ctx.Done(): | 		case <-ctx.Done(): | ||||||
| @@ -482,8 +491,9 @@ func (g *grpcClient) Publish(ctx context.Context, p client.Message, opts ...clie | |||||||
| 		return errors.InternalServerError("go.micro.client", err.Error()) | 		return errors.InternalServerError("go.micro.client", err.Error()) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	b := &buffer{bytes.NewBuffer(nil)} | 	b := buf.New(nil) | ||||||
| 	if err := cf(b).Write(&codec.Message{Type: codec.Publication}, p.Payload()); err != nil { |  | ||||||
|  | 	if err := cf(b).Write(&codec.Message{Type: codec.Event}, p.Payload()); err != nil { | ||||||
| 		return errors.InternalServerError("go.micro.client", err.Error()) | 		return errors.InternalServerError("go.micro.client", err.Error()) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,14 +3,12 @@ package grpc | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"net" | 	"net" | ||||||
| 	"strconv" |  | ||||||
| 	"strings" |  | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/client" | 	"github.com/micro/go-micro/client" | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/registry/memory" | 	"github.com/micro/go-micro/registry/memory" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| 	pgrpc "google.golang.org/grpc" | 	pgrpc "google.golang.org/grpc" | ||||||
| 	pb "google.golang.org/grpc/examples/helloworld/helloworld" | 	pb "google.golang.org/grpc/examples/helloworld/helloworld" | ||||||
| ) | ) | ||||||
| @@ -36,22 +34,17 @@ func TestGRPCClient(t *testing.T) { | |||||||
| 	go s.Serve(l) | 	go s.Serve(l) | ||||||
| 	defer s.Stop() | 	defer s.Stop() | ||||||
|  |  | ||||||
| 	parts := strings.Split(l.Addr().String(), ":") |  | ||||||
| 	port, _ := strconv.Atoi(parts[len(parts)-1]) |  | ||||||
| 	addr := strings.Join(parts[:len(parts)-1], ":") |  | ||||||
|  |  | ||||||
| 	// create mock registry | 	// create mock registry | ||||||
| 	r := memory.NewRegistry() | 	r := memory.NewRegistry() | ||||||
|  |  | ||||||
| 	// register service | 	// register service | ||||||
| 	r.Register(®istry.Service{ | 	r.Register(®istry.Service{ | ||||||
| 		Name:    "test", | 		Name:    "helloworld", | ||||||
| 		Version: "test", | 		Version: "test", | ||||||
| 		Nodes: []*registry.Node{ | 		Nodes: []*registry.Node{ | ||||||
| 			®istry.Node{ | 			®istry.Node{ | ||||||
| 				Id:      "test-1", | 				Id:      "test-1", | ||||||
| 				Address: addr, | 				Address: l.Addr().String(), | ||||||
| 				Port:    port, |  | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	}) | 	}) | ||||||
| @@ -73,7 +66,7 @@ func TestGRPCClient(t *testing.T) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, method := range testMethods { | 	for _, method := range testMethods { | ||||||
| 		req := c.NewRequest("test", method, &pb.HelloRequest{ | 		req := c.NewRequest("helloworld", method, &pb.HelloRequest{ | ||||||
| 			Name: "John", | 			Name: "John", | ||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,13 +4,13 @@ import ( | |||||||
| 	"github.com/micro/go-micro/client" | 	"github.com/micro/go-micro/client" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type grpcPublication struct { | type grpcEvent struct { | ||||||
| 	topic       string | 	topic       string | ||||||
| 	contentType string | 	contentType string | ||||||
| 	payload     interface{} | 	payload     interface{} | ||||||
| } | } | ||||||
|  |  | ||||||
| func newGRPCPublication(topic string, payload interface{}, contentType string, opts ...client.MessageOption) client.Message { | func newGRPCEvent(topic string, payload interface{}, contentType string, opts ...client.MessageOption) client.Message { | ||||||
| 	var options client.MessageOptions | 	var options client.MessageOptions | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		o(&options) | 		o(&options) | ||||||
| @@ -20,21 +20,21 @@ func newGRPCPublication(topic string, payload interface{}, contentType string, o | |||||||
| 		contentType = options.ContentType | 		contentType = options.ContentType | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return &grpcPublication{ | 	return &grpcEvent{ | ||||||
| 		payload:     payload, | 		payload:     payload, | ||||||
| 		topic:       topic, | 		topic:       topic, | ||||||
| 		contentType: contentType, | 		contentType: contentType, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func (g *grpcPublication) ContentType() string { | func (g *grpcEvent) ContentType() string { | ||||||
| 	return g.contentType | 	return g.contentType | ||||||
| } | } | ||||||
|  |  | ||||||
| func (g *grpcPublication) Topic() string { | func (g *grpcEvent) Topic() string { | ||||||
| 	return g.topic | 	return g.topic | ||||||
| } | } | ||||||
|  |  | ||||||
| func (g *grpcPublication) Payload() interface{} { | func (g *grpcEvent) Payload() interface{} { | ||||||
| 	return g.payload | 	return g.payload | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,7 +2,6 @@ package grpc | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"reflect" |  | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/client" | 	"github.com/micro/go-micro/client" | ||||||
| @@ -18,30 +17,25 @@ type grpcRequest struct { | |||||||
| 	codec       codec.Codec | 	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 | 	// no method or already grpc method | ||||||
| 	if len(method) == 0 || method[0] == '/' { | 	if len(method) == 0 || method[0] == '/' { | ||||||
| 		return method | 		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 | 	// assume method is Foo.Bar | ||||||
| 	mParts := strings.Split(method, ".") | 	mParts := strings.Split(method, ".") | ||||||
| 	if len(mParts) != 2 { | 	if len(mParts) != 2 { | ||||||
| 		return method | 		return method | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if len(service) == 0 { | ||||||
|  | 		return fmt.Sprintf("/%s/%s", mParts[0], mParts[1]) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// return /pkg.Foo/Bar | 	// 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 { | func newGRPCRequest(service, method string, request interface{}, contentType string, reqOpts ...client.RequestOption) client.Request { | ||||||
|   | |||||||
| @@ -2,45 +2,38 @@ package grpc | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	pb "google.golang.org/grpc/examples/helloworld/helloworld" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestMethodToGRPC(t *testing.T) { | func TestMethodToGRPC(t *testing.T) { | ||||||
| 	testData := []struct { | 	testData := []struct { | ||||||
|  | 		service string | ||||||
| 		method  string | 		method  string | ||||||
| 		expect  string | 		expect  string | ||||||
| 		request interface{} |  | ||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
|  | 			"helloworld", | ||||||
| 			"Greeter.SayHello", | 			"Greeter.SayHello", | ||||||
| 			"/helloworld.Greeter/SayHello", | 			"/helloworld.Greeter/SayHello", | ||||||
| 			new(pb.HelloRequest), |  | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
|  | 			"helloworld", | ||||||
| 			"/helloworld.Greeter/SayHello", | 			"/helloworld.Greeter/SayHello", | ||||||
| 			"/helloworld.Greeter/SayHello", | 			"/helloworld.Greeter/SayHello", | ||||||
| 			new(pb.HelloRequest), |  | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
|  | 			"", | ||||||
|  | 			"/helloworld.Greeter/SayHello", | ||||||
|  | 			"/helloworld.Greeter/SayHello", | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			"", | ||||||
| 			"Greeter.SayHello", | 			"Greeter.SayHello", | ||||||
| 			"/helloworld.Greeter/SayHello", | 			"/Greeter/SayHello", | ||||||
| 			pb.HelloRequest{}, |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"/helloworld.Greeter/SayHello", |  | ||||||
| 			"/helloworld.Greeter/SayHello", |  | ||||||
| 			pb.HelloRequest{}, |  | ||||||
| 		}, |  | ||||||
| 		{ |  | ||||||
| 			"Greeter.SayHello", |  | ||||||
| 			"Greeter.SayHello", |  | ||||||
| 			nil, |  | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, d := range testData { | 	for _, d := range testData { | ||||||
| 		method := methodToGRPC(d.method, d.request) | 		method := methodToGRPC(d.service, d.method) | ||||||
| 		if method != d.expect { | 		if method != d.expect { | ||||||
| 			t.Fatalf("expected %s got %s", d.expect, method) | 			t.Fatalf("expected %s got %s", d.expect, method) | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/codec" | 	"github.com/micro/go-micro/codec" | ||||||
|  | 	"github.com/micro/go-micro/codec/bytes" | ||||||
| 	"google.golang.org/grpc" | 	"google.golang.org/grpc" | ||||||
| 	"google.golang.org/grpc/encoding" | 	"google.golang.org/grpc/encoding" | ||||||
| ) | ) | ||||||
| @@ -12,11 +13,12 @@ type response struct { | |||||||
| 	conn   *grpc.ClientConn | 	conn   *grpc.ClientConn | ||||||
| 	stream grpc.ClientStream | 	stream grpc.ClientStream | ||||||
| 	codec  encoding.Codec | 	codec  encoding.Codec | ||||||
|  | 	gcodec codec.Codec | ||||||
| } | } | ||||||
|  |  | ||||||
| // Read the response | // Read the response | ||||||
| func (r *response) Codec() codec.Reader { | func (r *response) Codec() codec.Reader { | ||||||
| 	return nil | 	return r.gcodec | ||||||
| } | } | ||||||
|  |  | ||||||
| // read the header | // read the header | ||||||
| @@ -34,5 +36,9 @@ func (r *response) Header() map[string]string { | |||||||
|  |  | ||||||
| // Read the undecoded response | // Read the undecoded response | ||||||
| func (r *response) Read() ([]byte, error) { | func (r *response) Read() ([]byte, error) { | ||||||
| 	return nil, nil | 	f := &bytes.Frame{} | ||||||
|  | 	if err := r.gcodec.ReadBody(f); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return f.Data, nil | ||||||
| } | } | ||||||
|   | |||||||
| @@ -5,9 +5,9 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/broker" | 	"github.com/micro/go-micro/broker" | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/codec" | 	"github.com/micro/go-micro/codec" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| 	"github.com/micro/go-micro/transport" | 	"github.com/micro/go-micro/transport" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -43,8 +43,8 @@ type Options struct { | |||||||
| type CallOptions struct { | type CallOptions struct { | ||||||
| 	SelectOptions []selector.SelectOption | 	SelectOptions []selector.SelectOption | ||||||
|  |  | ||||||
| 	// Address of remote host | 	// Address of remote hosts | ||||||
| 	Address string | 	Address []string | ||||||
| 	// Backoff func | 	// Backoff func | ||||||
| 	Backoff BackoffFunc | 	Backoff BackoffFunc | ||||||
| 	// Check if retriable func | 	// Check if retriable func | ||||||
| @@ -245,8 +245,8 @@ func WithExchange(e string) PublishOption { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // WithAddress sets the remote address to use rather than using service discovery | // WithAddress sets the remote addresses to use rather than using service discovery | ||||||
| func WithAddress(a string) CallOption { | func WithAddress(a ...string) CallOption { | ||||||
| 	return func(o *CallOptions) { | 	return func(o *CallOptions) { | ||||||
| 		o.Address = a | 		o.Address = a | ||||||
| 	} | 	} | ||||||
|   | |||||||
							
								
								
									
										114
									
								
								client/pool/default.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								client/pool/default.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,114 @@ | |||||||
|  | package pool | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/google/uuid" | ||||||
|  | 	"github.com/micro/go-micro/transport" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type pool struct { | ||||||
|  | 	size int | ||||||
|  | 	ttl  time.Duration | ||||||
|  | 	tr   transport.Transport | ||||||
|  |  | ||||||
|  | 	sync.Mutex | ||||||
|  | 	conns map[string][]*poolConn | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type poolConn struct { | ||||||
|  | 	transport.Client | ||||||
|  | 	id      string | ||||||
|  | 	created time.Time | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newPool(options Options) *pool { | ||||||
|  | 	return &pool{ | ||||||
|  | 		size:  options.Size, | ||||||
|  | 		tr:    options.Transport, | ||||||
|  | 		ttl:   options.TTL, | ||||||
|  | 		conns: make(map[string][]*poolConn), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *pool) Close() error { | ||||||
|  | 	p.Lock() | ||||||
|  | 	for k, c := range p.conns { | ||||||
|  | 		for _, conn := range c { | ||||||
|  | 			conn.Client.Close() | ||||||
|  | 		} | ||||||
|  | 		delete(p.conns, k) | ||||||
|  | 	} | ||||||
|  | 	p.Unlock() | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NoOp the Close since we manage it | ||||||
|  | func (p *poolConn) Close() error { | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *poolConn) Id() string { | ||||||
|  | 	return p.id | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *poolConn) Created() time.Time { | ||||||
|  | 	return p.created | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *pool) Get(addr string, opts ...transport.DialOption) (Conn, error) { | ||||||
|  | 	p.Lock() | ||||||
|  | 	conns := p.conns[addr] | ||||||
|  |  | ||||||
|  | 	// while we have conns check age and then return one | ||||||
|  | 	// otherwise we'll create a new conn | ||||||
|  | 	for len(conns) > 0 { | ||||||
|  | 		conn := conns[len(conns)-1] | ||||||
|  | 		conns = conns[:len(conns)-1] | ||||||
|  | 		p.conns[addr] = conns | ||||||
|  |  | ||||||
|  | 		// if conn is old kill it and move on | ||||||
|  | 		if d := time.Since(conn.Created()); d > p.ttl { | ||||||
|  | 			conn.Client.Close() | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// we got a good conn, lets unlock and return it | ||||||
|  | 		p.Unlock() | ||||||
|  |  | ||||||
|  | 		return conn, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	p.Unlock() | ||||||
|  |  | ||||||
|  | 	// create new conn | ||||||
|  | 	c, err := p.tr.Dial(addr, opts...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return &poolConn{ | ||||||
|  | 		Client:  c, | ||||||
|  | 		id:      uuid.New().String(), | ||||||
|  | 		created: time.Now(), | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (p *pool) Release(conn Conn, err error) error { | ||||||
|  | 	// don't store the conn if it has errored | ||||||
|  | 	if err != nil { | ||||||
|  | 		return conn.(*poolConn).Client.Close() | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// otherwise put it back for reuse | ||||||
|  | 	p.Lock() | ||||||
|  | 	conns := p.conns[conn.Remote()] | ||||||
|  | 	if len(conns) >= p.size { | ||||||
|  | 		p.Unlock() | ||||||
|  | 		return conn.(*poolConn).Client.Close() | ||||||
|  | 	} | ||||||
|  | 	p.conns[conn.Remote()] = append(conns, conn.(*poolConn)) | ||||||
|  | 	p.Unlock() | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package client | package pool | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"testing" | 	"testing" | ||||||
| @@ -9,12 +9,17 @@ import ( | |||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func testPool(t *testing.T, size int, ttl time.Duration) { | func testPool(t *testing.T, size int, ttl time.Duration) { | ||||||
| 	// zero pool |  | ||||||
| 	p := newPool(size, ttl) |  | ||||||
| 
 |  | ||||||
| 	// mock transport | 	// mock transport | ||||||
| 	tr := memory.NewTransport() | 	tr := memory.NewTransport() | ||||||
| 
 | 
 | ||||||
|  | 	options := Options{ | ||||||
|  | 		TTL:       ttl, | ||||||
|  | 		Size:      size, | ||||||
|  | 		Transport: tr, | ||||||
|  | 	} | ||||||
|  | 	// zero pool | ||||||
|  | 	p := newPool(options) | ||||||
|  | 
 | ||||||
| 	// listen | 	// listen | ||||||
| 	l, err := tr.Listen(":0") | 	l, err := tr.Listen(":0") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @@ -43,7 +48,7 @@ func testPool(t *testing.T, size int, ttl time.Duration) { | |||||||
| 
 | 
 | ||||||
| 	for i := 0; i < 10; i++ { | 	for i := 0; i < 10; i++ { | ||||||
| 		// get a conn | 		// get a conn | ||||||
| 		c, err := p.getConn(l.Addr(), tr) | 		c, err := p.Get(l.Addr()) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			t.Fatal(err) | 			t.Fatal(err) | ||||||
| 		} | 		} | ||||||
| @@ -67,7 +72,7 @@ func testPool(t *testing.T, size int, ttl time.Duration) { | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// release the conn | 		// release the conn | ||||||
| 		p.release(l.Addr(), c, nil) | 		p.Release(c, nil) | ||||||
| 
 | 
 | ||||||
| 		p.Lock() | 		p.Lock() | ||||||
| 		if i := len(p.conns[l.Addr()]); i > size { | 		if i := len(p.conns[l.Addr()]); i > size { | ||||||
| @@ -78,7 +83,7 @@ func testPool(t *testing.T, size int, ttl time.Duration) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestRPCPool(t *testing.T) { | func TestClientPool(t *testing.T) { | ||||||
| 	testPool(t, 0, time.Minute) | 	testPool(t, 0, time.Minute) | ||||||
| 	testPool(t, 2, time.Minute) | 	testPool(t, 2, time.Minute) | ||||||
| } | } | ||||||
							
								
								
									
										33
									
								
								client/pool/options.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								client/pool/options.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | package pool | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/transport" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Options struct { | ||||||
|  | 	Transport transport.Transport | ||||||
|  | 	TTL       time.Duration | ||||||
|  | 	Size      int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type Option func(*Options) | ||||||
|  |  | ||||||
|  | func Size(i int) Option { | ||||||
|  | 	return func(o *Options) { | ||||||
|  | 		o.Size = i | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Transport(t transport.Transport) Option { | ||||||
|  | 	return func(o *Options) { | ||||||
|  | 		o.Transport = t | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TTL(t time.Duration) Option { | ||||||
|  | 	return func(o *Options) { | ||||||
|  | 		o.TTL = t | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								client/pool/pool.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								client/pool/pool.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | // Package pool is a connection pool | ||||||
|  | package pool | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/transport" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Pool is an interface for connection pooling | ||||||
|  | type Pool interface { | ||||||
|  | 	// Close the pool | ||||||
|  | 	Close() error | ||||||
|  | 	// Get a connection | ||||||
|  | 	Get(addr string, opts ...transport.DialOption) (Conn, error) | ||||||
|  | 	// Releaes the connection | ||||||
|  | 	Release(c Conn, status error) error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type Conn interface { | ||||||
|  | 	// unique id of connection | ||||||
|  | 	Id() string | ||||||
|  | 	// time it was created | ||||||
|  | 	Created() time.Time | ||||||
|  | 	// embedded connection | ||||||
|  | 	transport.Client | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func NewPool(opts ...Option) Pool { | ||||||
|  | 	var options Options | ||||||
|  | 	for _, o := range opts { | ||||||
|  | 		o(&options) | ||||||
|  | 	} | ||||||
|  | 	return newPool(options) | ||||||
|  | } | ||||||
							
								
								
									
										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; | ||||||
|  | } | ||||||
| @@ -1,40 +1,45 @@ | |||||||
| package client | package client | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" |  | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"net" |  | ||||||
| 	"os" | 	"os" | ||||||
| 	"strconv" |  | ||||||
| 	"sync" | 	"sync" | ||||||
| 	"sync/atomic" | 	"sync/atomic" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
| 	"github.com/google/uuid" | 	"github.com/google/uuid" | ||||||
| 	"github.com/micro/go-micro/broker" | 	"github.com/micro/go-micro/broker" | ||||||
|  | 	"github.com/micro/go-micro/client/pool" | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/codec" | 	"github.com/micro/go-micro/codec" | ||||||
| 	"github.com/micro/go-micro/errors" | 	"github.com/micro/go-micro/errors" | ||||||
| 	"github.com/micro/go-micro/metadata" | 	"github.com/micro/go-micro/metadata" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| 	"github.com/micro/go-micro/transport" | 	"github.com/micro/go-micro/transport" | ||||||
|  | 	"github.com/micro/go-micro/util/buf" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type rpcClient struct { | type rpcClient struct { | ||||||
| 	once sync.Once | 	once sync.Once | ||||||
| 	opts Options | 	opts Options | ||||||
| 	pool *pool | 	pool pool.Pool | ||||||
| 	seq  uint64 | 	seq  uint64 | ||||||
| } | } | ||||||
|  |  | ||||||
| func newRpcClient(opt ...Option) Client { | func newRpcClient(opt ...Option) Client { | ||||||
| 	opts := newOptions(opt...) | 	opts := newOptions(opt...) | ||||||
|  |  | ||||||
|  | 	p := pool.NewPool( | ||||||
|  | 		pool.Size(opts.PoolSize), | ||||||
|  | 		pool.TTL(opts.PoolTTL), | ||||||
|  | 		pool.Transport(opts.Transport), | ||||||
|  | 	) | ||||||
|  |  | ||||||
| 	rc := &rpcClient{ | 	rc := &rpcClient{ | ||||||
| 		once: sync.Once{}, | 		once: sync.Once{}, | ||||||
| 		opts: opts, | 		opts: opts, | ||||||
| 		pool: newPool(opts.PoolSize, opts.PoolTTL), | 		pool: p, | ||||||
| 		seq:  0, | 		seq:  0, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -60,9 +65,6 @@ func (r *rpcClient) newCodec(contentType string) (codec.NewCodec, error) { | |||||||
|  |  | ||||||
| func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request, resp interface{}, opts CallOptions) error { | func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request, resp interface{}, opts CallOptions) error { | ||||||
| 	address := node.Address | 	address := node.Address | ||||||
| 	if node.Port > 0 { |  | ||||||
| 		address = fmt.Sprintf("%s:%d", address, node.Port) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	msg := &transport.Message{ | 	msg := &transport.Message{ | ||||||
| 		Header: make(map[string]string), | 		Header: make(map[string]string), | ||||||
| @@ -95,13 +97,13 @@ func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request, | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	var grr error | 	var grr error | ||||||
| 	c, err := r.pool.getConn(address, r.opts.Transport, transport.WithTimeout(opts.DialTimeout)) | 	c, err := r.pool.Get(address, transport.WithTimeout(opts.DialTimeout)) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return errors.InternalServerError("go.micro.client", "connection error: %v", err) | 		return errors.InternalServerError("go.micro.client", "connection error: %v", err) | ||||||
| 	} | 	} | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		// defer execution of release | 		// defer execution of release | ||||||
| 		r.pool.release(address, c, grr) | 		r.pool.Release(c, grr) | ||||||
| 	}() | 	}() | ||||||
|  |  | ||||||
| 	seq := atomic.LoadUint64(&r.seq) | 	seq := atomic.LoadUint64(&r.seq) | ||||||
| @@ -160,9 +162,6 @@ func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request, | |||||||
|  |  | ||||||
| func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request, opts CallOptions) (Stream, error) { | func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request, opts CallOptions) (Stream, error) { | ||||||
| 	address := node.Address | 	address := node.Address | ||||||
| 	if node.Port > 0 { |  | ||||||
| 		address = fmt.Sprintf("%s:%d", address, node.Port) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	msg := &transport.Message{ | 	msg := &transport.Message{ | ||||||
| 		Header: make(map[string]string), | 		Header: make(map[string]string), | ||||||
| @@ -253,17 +252,22 @@ func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request | |||||||
| func (r *rpcClient) Init(opts ...Option) error { | func (r *rpcClient) Init(opts ...Option) error { | ||||||
| 	size := r.opts.PoolSize | 	size := r.opts.PoolSize | ||||||
| 	ttl := r.opts.PoolTTL | 	ttl := r.opts.PoolTTL | ||||||
|  | 	tr := r.opts.Transport | ||||||
|  |  | ||||||
| 	for _, o := range opts { | 	for _, o := range opts { | ||||||
| 		o(&r.opts) | 		o(&r.opts) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// update pool configuration if the options changed | 	// update pool configuration if the options changed | ||||||
| 	if size != r.opts.PoolSize || ttl != r.opts.PoolTTL { | 	if size != r.opts.PoolSize || ttl != r.opts.PoolTTL || tr != r.opts.Transport { | ||||||
| 		r.pool.Lock() | 		// close existing pool | ||||||
| 		r.pool.size = r.opts.PoolSize | 		r.pool.Close() | ||||||
| 		r.pool.ttl = int64(r.opts.PoolTTL.Seconds()) | 		// create new pool | ||||||
| 		r.pool.Unlock() | 		r.pool = pool.NewPool( | ||||||
|  | 			pool.Size(r.opts.PoolSize), | ||||||
|  | 			pool.TTL(r.opts.PoolTTL), | ||||||
|  | 			pool.Transport(r.opts.Transport), | ||||||
|  | 		) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return nil | 	return nil | ||||||
| @@ -283,29 +287,26 @@ func (r *rpcClient) next(request Request, opts CallOptions) (selector.Next, erro | |||||||
|  |  | ||||||
| 	// get proxy address | 	// get proxy address | ||||||
| 	if prx := os.Getenv("MICRO_PROXY_ADDRESS"); len(prx) > 0 { | 	if prx := os.Getenv("MICRO_PROXY_ADDRESS"); len(prx) > 0 { | ||||||
| 		opts.Address = prx | 		opts.Address = []string{prx} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// return remote address | 	// return remote address | ||||||
| 	if len(opts.Address) > 0 { | 	if len(opts.Address) > 0 { | ||||||
| 		address := opts.Address | 		nodes := make([]*registry.Node, len(opts.Address)) | ||||||
| 		port := 0 |  | ||||||
|  |  | ||||||
| 		host, sport, err := net.SplitHostPort(opts.Address) | 		for i, address := range opts.Address { | ||||||
| 		if err == nil { | 			nodes[i] = ®istry.Node{ | ||||||
| 			address = host |  | ||||||
| 			port, _ = strconv.Atoi(sport) |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		return func() (*registry.Node, error) { |  | ||||||
| 			return ®istry.Node{ |  | ||||||
| 				Address: address, | 				Address: address, | ||||||
| 				Port:    port, |  | ||||||
| 				// Set the protocol | 				// Set the protocol | ||||||
| 				Metadata: map[string]string{ | 				Metadata: map[string]string{ | ||||||
| 					"protocol": "mucp", | 					"protocol": "mucp", | ||||||
| 				}, | 				}, | ||||||
| 			}, nil | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// crude return method | ||||||
|  | 		return func() (*registry.Node, error) { | ||||||
|  | 			return nodes[time.Now().Unix()%int64(len(nodes))], nil | ||||||
| 		}, nil | 		}, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -537,10 +538,13 @@ func (r *rpcClient) Publish(ctx context.Context, msg Message, opts ...PublishOpt | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return errors.InternalServerError("go.micro.client", err.Error()) | 		return errors.InternalServerError("go.micro.client", err.Error()) | ||||||
| 	} | 	} | ||||||
| 	b := &buffer{bytes.NewBuffer(nil)} |  | ||||||
|  | 	// new buffer | ||||||
|  | 	b := buf.New(nil) | ||||||
|  |  | ||||||
| 	if err := cf(b).Write(&codec.Message{ | 	if err := cf(b).Write(&codec.Message{ | ||||||
| 		Target: topic, | 		Target: topic, | ||||||
| 		Type:   codec.Publication, | 		Type:   codec.Event, | ||||||
| 		Header: map[string]string{ | 		Header: map[string]string{ | ||||||
| 			"Micro-Id":    id, | 			"Micro-Id":    id, | ||||||
| 			"Micro-Topic": msg.Topic(), | 			"Micro-Topic": msg.Topic(), | ||||||
|   | |||||||
| @@ -5,10 +5,10 @@ import ( | |||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/errors" | 	"github.com/micro/go-micro/errors" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/registry/memory" | 	"github.com/micro/go-micro/registry/memory" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func newTestRegistry() registry.Registry { | func newTestRegistry() registry.Registry { | ||||||
| @@ -22,8 +22,7 @@ func TestCallAddress(t *testing.T) { | |||||||
| 	var called bool | 	var called bool | ||||||
| 	service := "test.service" | 	service := "test.service" | ||||||
| 	endpoint := "Test.Endpoint" | 	endpoint := "Test.Endpoint" | ||||||
| 	address := "10.1.10.1" | 	address := "10.1.10.1:8080" | ||||||
| 	port := 8080 |  | ||||||
|  |  | ||||||
| 	wrap := func(cf CallFunc) CallFunc { | 	wrap := func(cf CallFunc) CallFunc { | ||||||
| 		return func(ctx context.Context, node *registry.Node, req Request, rsp interface{}, opts CallOptions) error { | 		return func(ctx context.Context, node *registry.Node, req Request, rsp interface{}, opts CallOptions) error { | ||||||
| @@ -41,10 +40,6 @@ func TestCallAddress(t *testing.T) { | |||||||
| 				return fmt.Errorf("expected address: %s got %s", address, node.Address) | 				return fmt.Errorf("expected address: %s got %s", address, node.Address) | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if node.Port != port { |  | ||||||
| 				return fmt.Errorf("expected address: %d got %d", port, node.Port) |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			// don't do the call | 			// don't do the call | ||||||
| 			return nil | 			return nil | ||||||
| 		} | 		} | ||||||
| @@ -60,7 +55,7 @@ func TestCallAddress(t *testing.T) { | |||||||
| 	req := c.NewRequest(service, endpoint, nil) | 	req := c.NewRequest(service, endpoint, nil) | ||||||
|  |  | ||||||
| 	// test calling remote address | 	// test calling remote address | ||||||
| 	if err := c.Call(context.Background(), req, nil, WithAddress(fmt.Sprintf("%s:%d", address, port))); err != nil { | 	if err := c.Call(context.Background(), req, nil, WithAddress(address)); err != nil { | ||||||
| 		t.Fatal("call with address error", err) | 		t.Fatal("call with address error", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -114,8 +109,7 @@ func TestCallWrapper(t *testing.T) { | |||||||
| 	id := "test.1" | 	id := "test.1" | ||||||
| 	service := "test.service" | 	service := "test.service" | ||||||
| 	endpoint := "Test.Endpoint" | 	endpoint := "Test.Endpoint" | ||||||
| 	address := "10.1.10.1" | 	address := "10.1.10.1:8080" | ||||||
| 	port := 8080 |  | ||||||
|  |  | ||||||
| 	wrap := func(cf CallFunc) CallFunc { | 	wrap := func(cf CallFunc) CallFunc { | ||||||
| 		return func(ctx context.Context, node *registry.Node, req Request, rsp interface{}, opts CallOptions) error { | 		return func(ctx context.Context, node *registry.Node, req Request, rsp interface{}, opts CallOptions) error { | ||||||
| @@ -152,7 +146,6 @@ func TestCallWrapper(t *testing.T) { | |||||||
| 			®istry.Node{ | 			®istry.Node{ | ||||||
| 				Id:      id, | 				Id:      id, | ||||||
| 				Address: address, | 				Address: address, | ||||||
| 				Port:    port, |  | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| 	}) | 	}) | ||||||
|   | |||||||
| @@ -1,87 +0,0 @@ | |||||||
| package client |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"sync" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/transport" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type pool struct { |  | ||||||
| 	size int |  | ||||||
| 	ttl  int64 |  | ||||||
|  |  | ||||||
| 	sync.Mutex |  | ||||||
| 	conns map[string][]*poolConn |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type poolConn struct { |  | ||||||
| 	transport.Client |  | ||||||
| 	created int64 |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func newPool(size int, ttl time.Duration) *pool { |  | ||||||
| 	return &pool{ |  | ||||||
| 		size:  size, |  | ||||||
| 		ttl:   int64(ttl.Seconds()), |  | ||||||
| 		conns: make(map[string][]*poolConn), |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NoOp the Close since we manage it |  | ||||||
| func (p *poolConn) Close() error { |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *pool) getConn(addr string, tr transport.Transport, opts ...transport.DialOption) (*poolConn, error) { |  | ||||||
| 	p.Lock() |  | ||||||
| 	conns := p.conns[addr] |  | ||||||
| 	now := time.Now().Unix() |  | ||||||
|  |  | ||||||
| 	// while we have conns check age and then return one |  | ||||||
| 	// otherwise we'll create a new conn |  | ||||||
| 	for len(conns) > 0 { |  | ||||||
| 		conn := conns[len(conns)-1] |  | ||||||
| 		conns = conns[:len(conns)-1] |  | ||||||
| 		p.conns[addr] = conns |  | ||||||
|  |  | ||||||
| 		// if conn is old kill it and move on |  | ||||||
| 		if d := now - conn.created; d > p.ttl { |  | ||||||
| 			conn.Client.Close() |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// we got a good conn, lets unlock and return it |  | ||||||
| 		p.Unlock() |  | ||||||
|  |  | ||||||
| 		return conn, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	p.Unlock() |  | ||||||
|  |  | ||||||
| 	// create new conn |  | ||||||
| 	c, err := tr.Dial(addr, opts...) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
| 	return &poolConn{c, time.Now().Unix()}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (p *pool) release(addr string, conn *poolConn, err error) { |  | ||||||
| 	// don't store the conn if it has errored |  | ||||||
| 	if err != nil { |  | ||||||
| 		conn.Client.Close() |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// otherwise put it back for reuse |  | ||||||
| 	p.Lock() |  | ||||||
| 	conns := p.conns[addr] |  | ||||||
| 	if len(conns) >= p.size { |  | ||||||
| 		p.Unlock() |  | ||||||
| 		conn.Client.Close() |  | ||||||
| 		return |  | ||||||
| 	} |  | ||||||
| 	p.conns[addr] = append(conns, conn) |  | ||||||
| 	p.Unlock() |  | ||||||
| } |  | ||||||
| @@ -14,13 +14,11 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.0-123", | 						Id:      "foo-1.0.0-123", | ||||||
| 						Address: "localhost", | 						Address: "localhost:9999", | ||||||
| 						Port:    9999, |  | ||||||
| 					}, | 					}, | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.0-321", | 						Id:      "foo-1.0.0-321", | ||||||
| 						Address: "localhost", | 						Address: "localhost:9999", | ||||||
| 						Port:    9999, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| @@ -30,8 +28,7 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.1-321", | 						Id:      "foo-1.0.1-321", | ||||||
| 						Address: "localhost", | 						Address: "localhost:6666", | ||||||
| 						Port:    6666, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| @@ -41,8 +38,7 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.3-345", | 						Id:      "foo-1.0.3-345", | ||||||
| 						Address: "localhost", | 						Address: "localhost:8888", | ||||||
| 						Port:    8888, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| @@ -2,11 +2,12 @@ | |||||||
| package dns | package dns | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"net" | 	"net" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type dnsSelector struct { | type dnsSelector struct { | ||||||
| @@ -66,8 +67,7 @@ func (d *dnsSelector) Select(service string, opts ...selector.SelectOption) (sel | |||||||
| 	for _, node := range srv { | 	for _, node := range srv { | ||||||
| 		nodes = append(nodes, ®istry.Node{ | 		nodes = append(nodes, ®istry.Node{ | ||||||
| 			Id:      node.Target, | 			Id:      node.Target, | ||||||
| 			Address: node.Target, | 			Address: fmt.Sprintf("%s:%d", node.Target, node.Port), | ||||||
| 			Port:    int(node.Port), |  | ||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @@ -4,7 +4,7 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/micro/go-micro/selector" | 	"github.com/micro/go-micro/client/selector" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Set the registry cache ttl | // Set the registry cache ttl | ||||||
| @@ -2,7 +2,7 @@ | |||||||
| package registry | package registry | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"github.com/micro/go-micro/selector" | 	"github.com/micro/go-micro/client/selector" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // NewSelector returns a new registry selector | // NewSelector returns a new registry selector | ||||||
							
								
								
									
										272
									
								
								client/selector/router/router.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								client/selector/router/router.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,272 @@ | |||||||
|  | // Package router is a network/router selector | ||||||
|  | package router | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"os" | ||||||
|  | 	"sort" | ||||||
|  | 	"sync" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/client" | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
|  | 	"github.com/micro/go-micro/registry" | ||||||
|  | 	"github.com/micro/go-micro/router" | ||||||
|  | 	pb "github.com/micro/go-micro/router/proto" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type routerSelector struct { | ||||||
|  | 	opts selector.Options | ||||||
|  |  | ||||||
|  | 	// the router | ||||||
|  | 	r router.Router | ||||||
|  |  | ||||||
|  | 	// the client we have | ||||||
|  | 	c client.Client | ||||||
|  |  | ||||||
|  | 	// the client for the remote router | ||||||
|  | 	rs pb.RouterService | ||||||
|  |  | ||||||
|  | 	// name of the router | ||||||
|  | 	name string | ||||||
|  |  | ||||||
|  | 	// address of the remote router | ||||||
|  | 	addr string | ||||||
|  |  | ||||||
|  | 	// whether to use the remote router | ||||||
|  | 	remote bool | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type clientKey struct{} | ||||||
|  | type routerKey struct{} | ||||||
|  |  | ||||||
|  | // getRoutes returns the routes whether they are remote or local | ||||||
|  | func (r *routerSelector) getRoutes(service string) ([]router.Route, error) { | ||||||
|  | 	if !r.remote { | ||||||
|  | 		// lookup router for routes for the service | ||||||
|  | 		return r.r.Lookup(router.NewQuery( | ||||||
|  | 			router.QueryService(service), | ||||||
|  | 		)) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// lookup the remote router | ||||||
|  |  | ||||||
|  | 	var addrs []string | ||||||
|  |  | ||||||
|  | 	// set the remote address if specified | ||||||
|  | 	if len(r.addr) > 0 { | ||||||
|  | 		addrs = append(addrs, r.addr) | ||||||
|  | 	} else { | ||||||
|  | 		// we have a name so we need to check the registry | ||||||
|  | 		services, err := r.c.Options().Registry.GetService(r.name) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, err | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for _, service := range services { | ||||||
|  | 			for _, node := range service.Nodes { | ||||||
|  | 				addrs = append(addrs, node.Address) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// no router addresses available | ||||||
|  | 	if len(addrs) == 0 { | ||||||
|  | 		return nil, selector.ErrNoneAvailable | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var pbRoutes *pb.LookupResponse | ||||||
|  | 	var err error | ||||||
|  |  | ||||||
|  | 	// TODO: implement backoff and retries | ||||||
|  | 	for _, addr := range addrs { | ||||||
|  | 		// call the router | ||||||
|  | 		pbRoutes, err = r.rs.Lookup(context.Background(), &pb.LookupRequest{ | ||||||
|  | 			Query: &pb.Query{ | ||||||
|  | 				Service: service, | ||||||
|  | 			}, | ||||||
|  | 		}, client.WithAddress(addr)) | ||||||
|  | 		if err != nil { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		break | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// errored out | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// no routes | ||||||
|  | 	if pbRoutes == nil { | ||||||
|  | 		return nil, selector.ErrNoneAvailable | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var routes []router.Route | ||||||
|  |  | ||||||
|  | 	// convert from pb to []*router.Route | ||||||
|  | 	for _, r := range pbRoutes.Routes { | ||||||
|  | 		routes = append(routes, router.Route{ | ||||||
|  | 			Service: r.Service, | ||||||
|  | 			Address: r.Address, | ||||||
|  | 			Gateway: r.Gateway, | ||||||
|  | 			Network: r.Network, | ||||||
|  | 			Link:    r.Link, | ||||||
|  | 			Metric:  int(r.Metric), | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return routes, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *routerSelector) Init(opts ...selector.Option) error { | ||||||
|  | 	// no op | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *routerSelector) Options() selector.Options { | ||||||
|  | 	return r.opts | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *routerSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) { | ||||||
|  | 	// TODO: pull routes asynchronously and cache | ||||||
|  | 	routes, err := r.getRoutes(service) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// no routes return not found error | ||||||
|  | 	if len(routes) == 0 { | ||||||
|  | 		return nil, selector.ErrNotFound | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// TODO: apply filters by pseudo constructing service | ||||||
|  |  | ||||||
|  | 	// sort the routes based on metric | ||||||
|  | 	sort.Slice(routes, func(i, j int) bool { | ||||||
|  | 		return routes[i].Metric < routes[j].Metric | ||||||
|  | 	}) | ||||||
|  |  | ||||||
|  | 	// roundrobin assuming routes are in metric preference order | ||||||
|  | 	var i int | ||||||
|  | 	var mtx sync.Mutex | ||||||
|  |  | ||||||
|  | 	return func() (*registry.Node, error) { | ||||||
|  | 		// get index and increment counter with every call to next | ||||||
|  | 		mtx.Lock() | ||||||
|  | 		idx := i | ||||||
|  | 		i++ | ||||||
|  | 		mtx.Unlock() | ||||||
|  |  | ||||||
|  | 		// get route based on idx | ||||||
|  | 		route := routes[idx%len(routes)] | ||||||
|  |  | ||||||
|  | 		// defaults to gateway and no port | ||||||
|  | 		address := route.Address | ||||||
|  | 		if len(route.Gateway) > 0 { | ||||||
|  | 			address = route.Gateway | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// return as a node | ||||||
|  | 		return ®istry.Node{ | ||||||
|  | 			// TODO: add id and metadata if we can | ||||||
|  | 			Address: address, | ||||||
|  | 		}, nil | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *routerSelector) Mark(service string, node *registry.Node, err error) { | ||||||
|  | 	// TODO: pass back metrics or information to the router | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *routerSelector) Reset(service string) { | ||||||
|  | 	// TODO: reset the metrics or information at the router | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *routerSelector) Close() error { | ||||||
|  | 	// stop the router advertisements | ||||||
|  | 	return r.r.Stop() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (r *routerSelector) String() string { | ||||||
|  | 	return "router" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // NewSelector returns a new router based selector | ||||||
|  | func NewSelector(opts ...selector.Option) selector.Selector { | ||||||
|  | 	options := selector.Options{ | ||||||
|  | 		Context: context.Background(), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, o := range opts { | ||||||
|  | 		o(&options) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// set default registry if not set | ||||||
|  | 	if options.Registry == nil { | ||||||
|  | 		options.Registry = registry.DefaultRegistry | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// try get router from the context | ||||||
|  | 	r, ok := options.Context.Value(routerKey{}).(router.Router) | ||||||
|  | 	if !ok { | ||||||
|  | 		// TODO: Use router.DefaultRouter? | ||||||
|  | 		r = router.NewRouter( | ||||||
|  | 			router.Registry(options.Registry), | ||||||
|  | 		) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// try get client from the context | ||||||
|  | 	c, ok := options.Context.Value(clientKey{}).(client.Client) | ||||||
|  | 	if !ok { | ||||||
|  | 		c = client.DefaultClient | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// get the router from env vars if its a remote service | ||||||
|  | 	remote := true | ||||||
|  | 	routerName := os.Getenv("MICRO_ROUTER") | ||||||
|  | 	routerAddress := os.Getenv("MICRO_ROUTER_ADDRESS") | ||||||
|  |  | ||||||
|  | 	// start the router advertisements if we're running it locally | ||||||
|  | 	if len(routerName) == 0 && len(routerAddress) == 0 { | ||||||
|  | 		go r.Advertise() | ||||||
|  | 		remote = false | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &routerSelector{ | ||||||
|  | 		opts: options, | ||||||
|  | 		// set the internal router | ||||||
|  | 		r: r, | ||||||
|  | 		// set the client | ||||||
|  | 		c: c, | ||||||
|  | 		// set the router client | ||||||
|  | 		rs: pb.NewRouterService(routerName, c), | ||||||
|  | 		// name of the router | ||||||
|  | 		name: routerName, | ||||||
|  | 		// address of router | ||||||
|  | 		addr: routerAddress, | ||||||
|  | 		// let ourselves know to use the remote router | ||||||
|  | 		remote: remote, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithClient sets the client for the request | ||||||
|  | func WithClient(c client.Client) selector.Option { | ||||||
|  | 	return func(o *selector.Options) { | ||||||
|  | 		if o.Context == nil { | ||||||
|  | 			o.Context = context.Background() | ||||||
|  | 		} | ||||||
|  | 		o.Context = context.WithValue(o.Context, clientKey{}, c) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // WithRouter sets the router as an option | ||||||
|  | func WithRouter(r router.Router) selector.Option { | ||||||
|  | 	return func(o *selector.Options) { | ||||||
|  | 		if o.Context == nil { | ||||||
|  | 			o.Context = context.Background() | ||||||
|  | 		} | ||||||
|  | 		o.Context = context.WithValue(o.Context, routerKey{}, r) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @@ -2,11 +2,8 @@ | |||||||
| package static | package static | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"net" | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"strconv" |  | ||||||
| 
 |  | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // staticSelector is a static selector | // staticSelector is a static selector | ||||||
| @@ -26,20 +23,10 @@ func (s *staticSelector) Options() selector.Options { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *staticSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) { | func (s *staticSelector) Select(service string, opts ...selector.SelectOption) (selector.Next, error) { | ||||||
| 	var port int |  | ||||||
| 	addr, pt, err := net.SplitHostPort(service) |  | ||||||
| 	if err != nil { |  | ||||||
| 		addr = service |  | ||||||
| 		port = 0 |  | ||||||
| 	} else { |  | ||||||
| 		port, _ = strconv.Atoi(pt) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return func() (*registry.Node, error) { | 	return func() (*registry.Node, error) { | ||||||
| 		return ®istry.Node{ | 		return ®istry.Node{ | ||||||
| 			Id:      service, | 			Id:      service, | ||||||
| 			Address: addr, | 			Address: service, | ||||||
| 			Port:    port, |  | ||||||
| 		}, nil | 		}, nil | ||||||
| 	}, nil | 	}, nil | ||||||
| } | } | ||||||
| @@ -14,13 +14,11 @@ func TestStrategies(t *testing.T) { | |||||||
| 			Nodes: []*registry.Node{ | 			Nodes: []*registry.Node{ | ||||||
| 				®istry.Node{ | 				®istry.Node{ | ||||||
| 					Id:      "test1-1", | 					Id:      "test1-1", | ||||||
| 					Address: "10.0.0.1", | 					Address: "10.0.0.1:1001", | ||||||
| 					Port:    1001, |  | ||||||
| 				}, | 				}, | ||||||
| 				®istry.Node{ | 				®istry.Node{ | ||||||
| 					Id:      "test1-2", | 					Id:      "test1-2", | ||||||
| 					Address: "10.0.0.2", | 					Address: "10.0.0.2:1002", | ||||||
| 					Port:    1002, |  | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| @@ -30,13 +28,11 @@ func TestStrategies(t *testing.T) { | |||||||
| 			Nodes: []*registry.Node{ | 			Nodes: []*registry.Node{ | ||||||
| 				®istry.Node{ | 				®istry.Node{ | ||||||
| 					Id:      "test1-3", | 					Id:      "test1-3", | ||||||
| 					Address: "10.0.0.3", | 					Address: "10.0.0.3:1003", | ||||||
| 					Port:    1003, |  | ||||||
| 				}, | 				}, | ||||||
| 				®istry.Node{ | 				®istry.Node{ | ||||||
| 					Id:      "test1-4", | 					Id:      "test1-4", | ||||||
| 					Address: "10.0.0.4", | 					Address: "10.0.0.4:1004", | ||||||
| 					Port:    1004, |  | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
| @@ -9,7 +9,7 @@ const ( | |||||||
| 	Error MessageType = iota | 	Error MessageType = iota | ||||||
| 	Request | 	Request | ||||||
| 	Response | 	Response | ||||||
| 	Publication | 	Event | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type MessageType int | type MessageType int | ||||||
|   | |||||||
| @@ -33,7 +33,7 @@ func (j *jsonCodec) Write(m *codec.Message, b interface{}) error { | |||||||
| 		return j.c.Write(m, b) | 		return j.c.Write(m, b) | ||||||
| 	case codec.Response, codec.Error: | 	case codec.Response, codec.Error: | ||||||
| 		return j.s.Write(m, b) | 		return j.s.Write(m, b) | ||||||
| 	case codec.Publication: | 	case codec.Event: | ||||||
| 		data, err := json.Marshal(b) | 		data, err := json.Marshal(b) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| @@ -54,7 +54,7 @@ func (j *jsonCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error { | |||||||
| 		return j.s.ReadHeader(m) | 		return j.s.ReadHeader(m) | ||||||
| 	case codec.Response: | 	case codec.Response: | ||||||
| 		return j.c.ReadHeader(m) | 		return j.c.ReadHeader(m) | ||||||
| 	case codec.Publication: | 	case codec.Event: | ||||||
| 		_, err := io.Copy(j.buf, j.rwc) | 		_, err := io.Copy(j.buf, j.rwc) | ||||||
| 		return err | 		return err | ||||||
| 	default: | 	default: | ||||||
| @@ -69,7 +69,7 @@ func (j *jsonCodec) ReadBody(b interface{}) error { | |||||||
| 		return j.s.ReadBody(b) | 		return j.s.ReadBody(b) | ||||||
| 	case codec.Response: | 	case codec.Response: | ||||||
| 		return j.c.ReadBody(b) | 		return j.c.ReadBody(b) | ||||||
| 	case codec.Publication: | 	case codec.Event: | ||||||
| 		if b != nil { | 		if b != nil { | ||||||
| 			return json.Unmarshal(j.buf.Bytes(), b) | 			return json.Unmarshal(j.buf.Bytes(), b) | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -99,7 +99,7 @@ func (c *protoCodec) Write(m *codec.Message, b interface{}) error { | |||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	case codec.Publication: | 	case codec.Event: | ||||||
| 		data, err := proto.Marshal(b.(proto.Message)) | 		data, err := proto.Marshal(b.(proto.Message)) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| @@ -141,7 +141,7 @@ func (c *protoCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error { | |||||||
| 		m.Method = rtmp.GetServiceMethod() | 		m.Method = rtmp.GetServiceMethod() | ||||||
| 		m.Id = fmt.Sprintf("%d", rtmp.GetSeq()) | 		m.Id = fmt.Sprintf("%d", rtmp.GetSeq()) | ||||||
| 		m.Error = rtmp.GetError() | 		m.Error = rtmp.GetError() | ||||||
| 	case codec.Publication: | 	case codec.Event: | ||||||
| 		_, err := io.Copy(c.buf, c.rwc) | 		_, err := io.Copy(c.buf, c.rwc) | ||||||
| 		return err | 		return err | ||||||
| 	default: | 	default: | ||||||
| @@ -159,7 +159,7 @@ func (c *protoCodec) ReadBody(b interface{}) error { | |||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return err | 			return err | ||||||
| 		} | 		} | ||||||
| 	case codec.Publication: | 	case codec.Event: | ||||||
| 		data = c.buf.Bytes() | 		data = c.buf.Bytes() | ||||||
| 	default: | 	default: | ||||||
| 		return fmt.Errorf("Unrecognised message type: %v", c.mt) | 		return fmt.Errorf("Unrecognised message type: %v", c.mt) | ||||||
|   | |||||||
| @@ -14,13 +14,11 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.0-123", | 						Id:      "foo-1.0.0-123", | ||||||
| 						Address: "localhost", | 						Address: "localhost:9999", | ||||||
| 						Port:    9999, |  | ||||||
| 					}, | 					}, | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.0-321", | 						Id:      "foo-1.0.0-321", | ||||||
| 						Address: "localhost", | 						Address: "localhost:9999", | ||||||
| 						Port:    9999, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| @@ -30,8 +28,7 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.1-321", | 						Id:      "foo-1.0.1-321", | ||||||
| 						Address: "localhost", | 						Address: "localhost:6666", | ||||||
| 						Port:    6666, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| @@ -41,8 +38,7 @@ var ( | |||||||
| 				Nodes: []*registry.Node{ | 				Nodes: []*registry.Node{ | ||||||
| 					{ | 					{ | ||||||
| 						Id:      "foo-1.0.3-345", | 						Id:      "foo-1.0.3-345", | ||||||
| 						Address: "localhost", | 						Address: "localhost:8888", | ||||||
| 						Port:    8888, |  | ||||||
| 					}, | 					}, | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| # Config [](https://godoc.org/github.com/micro/go-micro/config) | # Config [](https://godoc.org/github.com/micro/go-micro/config) | ||||||
|  |  | ||||||
| Go Config is a pluggable dynamic config library. | Config is a pluggable dynamic config package | ||||||
|  |  | ||||||
| Most config in applications are statically configured or include complex logic to load from multiple sources.  | Most config in applications are statically configured or include complex logic to load from multiple sources.  | ||||||
| Go Config makes this easy, pluggable and mergeable. You'll never have to deal with config in the same way again. | Go Config makes this easy, pluggable and mergeable. You'll never have to deal with config in the same way again. | ||||||
|   | |||||||
| @@ -14,8 +14,8 @@ import ( | |||||||
| 	cgrpc "github.com/micro/go-micro/client/grpc" | 	cgrpc "github.com/micro/go-micro/client/grpc" | ||||||
| 	cmucp "github.com/micro/go-micro/client/mucp" | 	cmucp "github.com/micro/go-micro/client/mucp" | ||||||
| 	"github.com/micro/go-micro/server" | 	"github.com/micro/go-micro/server" | ||||||
| 	smucp "github.com/micro/go-micro/server/mucp" |  | ||||||
| 	sgrpc "github.com/micro/go-micro/server/grpc" | 	sgrpc "github.com/micro/go-micro/server/grpc" | ||||||
|  | 	smucp "github.com/micro/go-micro/server/mucp" | ||||||
| 	"github.com/micro/go-micro/util/log" | 	"github.com/micro/go-micro/util/log" | ||||||
| 
 | 
 | ||||||
| 	// brokers | 	// brokers | ||||||
| @@ -32,15 +32,17 @@ import ( | |||||||
| 	rmem "github.com/micro/go-micro/registry/memory" | 	rmem "github.com/micro/go-micro/registry/memory" | ||||||
| 
 | 
 | ||||||
| 	// selectors | 	// selectors | ||||||
| 	"github.com/micro/go-micro/selector" | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/selector/dns" | 	"github.com/micro/go-micro/client/selector/dns" | ||||||
| 	"github.com/micro/go-micro/selector/static" | 	"github.com/micro/go-micro/client/selector/router" | ||||||
|  | 	"github.com/micro/go-micro/client/selector/static" | ||||||
| 
 | 
 | ||||||
| 	// transports | 	// transports | ||||||
| 	"github.com/micro/go-micro/transport" | 	"github.com/micro/go-micro/transport" | ||||||
| 	tgrpc "github.com/micro/go-micro/transport/grpc" | 	tgrpc "github.com/micro/go-micro/transport/grpc" | ||||||
| 	thttp "github.com/micro/go-micro/transport/http" | 	thttp "github.com/micro/go-micro/transport/http" | ||||||
| 	tmem "github.com/micro/go-micro/transport/memory" | 	tmem "github.com/micro/go-micro/transport/memory" | ||||||
|  | 	"github.com/micro/go-micro/transport/quic" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Cmd interface { | type Cmd interface { | ||||||
| @@ -196,6 +198,7 @@ var ( | |||||||
| 		"default": selector.NewSelector, | 		"default": selector.NewSelector, | ||||||
| 		"dns":     dns.NewSelector, | 		"dns":     dns.NewSelector, | ||||||
| 		"cache":   selector.NewSelector, | 		"cache":   selector.NewSelector, | ||||||
|  | 		"router":  router.NewSelector, | ||||||
| 		"static":  static.NewSelector, | 		"static":  static.NewSelector, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @@ -209,6 +212,7 @@ var ( | |||||||
| 		"memory": tmem.NewTransport, | 		"memory": tmem.NewTransport, | ||||||
| 		"http":   thttp.NewTransport, | 		"http":   thttp.NewTransport, | ||||||
| 		"grpc":   tgrpc.NewTransport, | 		"grpc":   tgrpc.NewTransport, | ||||||
|  | 		"quic":   quic.NewTransport, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// used for default selection as the fall back | 	// used for default selection as the fall back | ||||||
| @@ -5,8 +5,8 @@ import ( | |||||||
| 
 | 
 | ||||||
| 	"github.com/micro/go-micro/broker" | 	"github.com/micro/go-micro/broker" | ||||||
| 	"github.com/micro/go-micro/client" | 	"github.com/micro/go-micro/client" | ||||||
|  | 	"github.com/micro/go-micro/client/selector" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| 	"github.com/micro/go-micro/server" | 	"github.com/micro/go-micro/server" | ||||||
| 	"github.com/micro/go-micro/transport" | 	"github.com/micro/go-micro/transport" | ||||||
| ) | ) | ||||||
| @@ -8,9 +8,25 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/config/source/env" | ||||||
| 	"github.com/micro/go-micro/config/source/file" | 	"github.com/micro/go-micro/config/source/file" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | func createFileForIssue18(t *testing.T, content string) *os.File { | ||||||
|  | 	data := []byte(content) | ||||||
|  | 	path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano())) | ||||||
|  | 	fh, err := os.Create(path) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  | 	_, err = fh.Write(data) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Error(err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return fh | ||||||
|  | } | ||||||
|  |  | ||||||
| func createFileForTest(t *testing.T) *os.File { | func createFileForTest(t *testing.T) *os.File { | ||||||
| 	data := []byte(`{"foo": "bar"}`) | 	data := []byte(`{"foo": "bar"}`) | ||||||
| 	path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano())) | 	path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano())) | ||||||
| @@ -26,7 +42,7 @@ func createFileForTest(t *testing.T) *os.File { | |||||||
| 	return fh | 	return fh | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestLoadWithGoodFile(t *testing.T) { | func TestConfigLoadWithGoodFile(t *testing.T) { | ||||||
| 	fh := createFileForTest(t) | 	fh := createFileForTest(t) | ||||||
| 	path := fh.Name() | 	path := fh.Name() | ||||||
| 	defer func() { | 	defer func() { | ||||||
| @@ -44,7 +60,7 @@ func TestLoadWithGoodFile(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestLoadWithInvalidFile(t *testing.T) { | func TestConfigLoadWithInvalidFile(t *testing.T) { | ||||||
| 	fh := createFileForTest(t) | 	fh := createFileForTest(t) | ||||||
| 	path := fh.Name() | 	path := fh.Name() | ||||||
| 	defer func() { | 	defer func() { | ||||||
| @@ -68,34 +84,35 @@ func TestLoadWithInvalidFile(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestConsul(t *testing.T) { | func TestConfigMerge(t *testing.T) { | ||||||
| 	/*consulSource := consul.NewSource( | 	fh := createFileForIssue18(t, `{ | ||||||
| 		// optionally specify consul address; default to localhost:8500 |   "amqp": { | ||||||
| 		consul.WithAddress("131.150.38.111:8500"), |     "host": "rabbit.platform", | ||||||
| 		// optionally specify prefix; defaults to /micro/config |     "port": 80 | ||||||
| 		consul.WithPrefix("/project"), |   }, | ||||||
| 		// optionally strip the provided prefix from the keys, defaults to false |   "handler": { | ||||||
| 		consul.StripPrefix(true), |     "exchange": "springCloudBus" | ||||||
| 		consul.WithDatacenter("dc1"), |   } | ||||||
| 		consul.WithToken("xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"), | }`) | ||||||
|  | 	path := fh.Name() | ||||||
|  | 	defer func() { | ||||||
|  | 		fh.Close() | ||||||
|  | 		os.Remove(path) | ||||||
|  | 	}() | ||||||
|  | 	os.Setenv("AMQP_HOST", "rabbit.testing.com") | ||||||
|  |  | ||||||
|  | 	conf := NewConfig() | ||||||
|  | 	conf.Load( | ||||||
|  | 		file.NewSource( | ||||||
|  | 			file.WithPath(path), | ||||||
|  | 		), | ||||||
|  | 		env.NewSource(), | ||||||
| 	) | 	) | ||||||
|  |  | ||||||
| 	// Create new config | 	actualHost := conf.Get("amqp", "host").String("backup") | ||||||
| 	conf := NewConfig() | 	if actualHost != "rabbit.testing.com" { | ||||||
|  | 		t.Fatalf("Expected %v but got %v", | ||||||
| 	// Load file source | 			"rabbit.testing.com", | ||||||
| 	err := conf.Load(consulSource) | 			actualHost) | ||||||
| 	if err != nil { |  | ||||||
| 		t.Error(err) |  | ||||||
| 		return |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	m := conf.Map() |  | ||||||
| 	t.Log("m: ", m) |  | ||||||
|  |  | ||||||
| 	v := conf.Get("project", "dc111", "port") |  | ||||||
|  |  | ||||||
| 	t.Log("v: ", v.Int(13))*/ |  | ||||||
|  |  | ||||||
| 	t.Log("OK") |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,60 +0,0 @@ | |||||||
| package config |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"os" |  | ||||||
| 	"path/filepath" |  | ||||||
| 	"testing" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/config/source/env" |  | ||||||
| 	"github.com/micro/go-micro/config/source/file" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| func createFileForIssue18(t *testing.T, content string) *os.File { |  | ||||||
| 	data := []byte(content) |  | ||||||
| 	path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano())) |  | ||||||
| 	fh, err := os.Create(path) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Error(err) |  | ||||||
| 	} |  | ||||||
| 	_, err = fh.Write(data) |  | ||||||
| 	if err != nil { |  | ||||||
| 		t.Error(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return fh |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func TestIssue18(t *testing.T) { |  | ||||||
| 	fh := createFileForIssue18(t, `{ |  | ||||||
|   "amqp": { |  | ||||||
|     "host": "rabbit.platform", |  | ||||||
|     "port": 80 |  | ||||||
|   }, |  | ||||||
|   "handler": { |  | ||||||
|     "exchange": "springCloudBus" |  | ||||||
|   } |  | ||||||
| }`) |  | ||||||
| 	path := fh.Name() |  | ||||||
| 	defer func() { |  | ||||||
| 		fh.Close() |  | ||||||
| 		os.Remove(path) |  | ||||||
| 	}() |  | ||||||
| 	os.Setenv("AMQP_HOST", "rabbit.testing.com") |  | ||||||
|  |  | ||||||
| 	conf := NewConfig() |  | ||||||
| 	conf.Load( |  | ||||||
| 		file.NewSource( |  | ||||||
| 			file.WithPath(path), |  | ||||||
| 		), |  | ||||||
| 		env.NewSource(), |  | ||||||
| 	) |  | ||||||
|  |  | ||||||
| 	actualHost := conf.Get("amqp", "host").String("backup") |  | ||||||
| 	if actualHost != "rabbit.testing.com" { |  | ||||||
| 		t.Fatalf("Expected %v but got %v", |  | ||||||
| 			"rabbit.testing.com", |  | ||||||
| 			actualHost) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -1,39 +1,85 @@ | |||||||
| package json | package json | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
|  | 	"reflect" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/config/source" | 	"github.com/micro/go-micro/config/source" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestValues(t *testing.T) { | func TestValues(t *testing.T) { | ||||||
| 	data := []byte(`{"foo": "bar", "baz": {"bar": "cat"}}`) | 	emptyStr := "" | ||||||
|  |  | ||||||
| 	testData := []struct { | 	testData := []struct { | ||||||
|  | 		csdata   []byte | ||||||
| 		path     []string | 		path     []string | ||||||
| 		value string | 		accepter interface{} | ||||||
|  | 		value    interface{} | ||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
|  | 			[]byte(`{"foo": "bar", "baz": {"bar": "cat"}}`), | ||||||
| 			[]string{"foo"}, | 			[]string{"foo"}, | ||||||
|  | 			emptyStr, | ||||||
| 			"bar", | 			"bar", | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
|  | 			[]byte(`{"foo": "bar", "baz": {"bar": "cat"}}`), | ||||||
| 			[]string{"baz", "bar"}, | 			[]string{"baz", "bar"}, | ||||||
|  | 			emptyStr, | ||||||
| 			"cat", | 			"cat", | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	for idx, test := range testData { | ||||||
| 		values, err := newValues(&source.ChangeSet{ | 		values, err := newValues(&source.ChangeSet{ | ||||||
| 		Data: data, | 			Data: test.csdata, | ||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			t.Fatal(err) | 			t.Fatal(err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 	for _, test := range testData { | 		err = values.Get(test.path...).Scan(&test.accepter) | ||||||
| 		if v := values.Get(test.path...).String(""); v != test.value { | 		if err != nil { | ||||||
| 			t.Fatalf("Expected %s got %s for path %v", test.value, v, test.path) | 			t.Fatal(err) | ||||||
|  | 		} | ||||||
|  | 		if test.accepter != test.value { | ||||||
|  | 			t.Fatalf("No.%d Expected %v got %v for path %v", idx, test.value, test.accepter, test.path) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestStructArray(t *testing.T) { | ||||||
|  | 	type T struct { | ||||||
|  | 		Foo string | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	emptyTSlice := []T{} | ||||||
|  |  | ||||||
|  | 	testData := []struct { | ||||||
|  | 		csdata   []byte | ||||||
|  | 		accepter []T | ||||||
|  | 		value    []T | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			[]byte(`[{"foo": "bar"}]`), | ||||||
|  | 			emptyTSlice, | ||||||
|  | 			[]T{T{Foo: "bar"}}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for idx, test := range testData { | ||||||
|  | 		values, err := newValues(&source.ChangeSet{ | ||||||
|  | 			Data: test.csdata, | ||||||
|  | 		}) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatal(err) | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		err = values.Get().Scan(&test.accepter) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatal(err) | ||||||
|  | 		} | ||||||
|  | 		if !reflect.DeepEqual(test.accepter, test.value) { | ||||||
|  | 			t.Fatalf("No.%d Expected %v got %v", idx, test.value, test.accepter) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -9,7 +9,7 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/imdario/mergo" | 	"github.com/imdario/mergo" | ||||||
| 	"github.com/micro/cli" | 	"github.com/micro/cli" | ||||||
| 	"github.com/micro/go-micro/cmd" | 	"github.com/micro/go-micro/config/cmd" | ||||||
| 	"github.com/micro/go-micro/config/source" | 	"github.com/micro/go-micro/config/source" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/micro/cli" | 	"github.com/micro/cli" | ||||||
| 	"github.com/micro/go-micro/cmd" | 	"github.com/micro/go-micro/config/cmd" | ||||||
| 	"github.com/micro/go-micro/config/source" | 	"github.com/micro/go-micro/config/source" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -74,6 +74,11 @@ func NewSource(opts ...source.Option) source.Source { | |||||||
| 	// use default config | 	// use default config | ||||||
| 	config := api.DefaultConfig() | 	config := api.DefaultConfig() | ||||||
|  |  | ||||||
|  | 	// use the consul config passed in the options if any | ||||||
|  | 	if co, ok := options.Context.Value(configKey{}).(*api.Config); ok { | ||||||
|  | 		config = co | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// check if there are any addrs | 	// check if there are any addrs | ||||||
| 	a, ok := options.Context.Value(addressKey{}).(string) | 	a, ok := options.Context.Value(addressKey{}).(string) | ||||||
| 	if ok { | 	if ok { | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ package consul | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  |  | ||||||
|  | 	"github.com/hashicorp/consul/api" | ||||||
| 	"github.com/micro/go-micro/config/source" | 	"github.com/micro/go-micro/config/source" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -11,6 +12,7 @@ type prefixKey struct{} | |||||||
| type stripPrefixKey struct{} | type stripPrefixKey struct{} | ||||||
| type dcKey struct{} | type dcKey struct{} | ||||||
| type tokenKey struct{} | type tokenKey struct{} | ||||||
|  | type configKey struct{} | ||||||
|  |  | ||||||
| // WithAddress sets the consul address | // WithAddress sets the consul address | ||||||
| func WithAddress(a string) source.Option { | func WithAddress(a string) source.Option { | ||||||
| @@ -61,3 +63,13 @@ func WithToken(p string) source.Option { | |||||||
| 		o.Context = context.WithValue(o.Context, tokenKey{}, p) | 		o.Context = context.WithValue(o.Context, tokenKey{}, p) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // WithConfig set consul-specific options | ||||||
|  | func WithConfig(c *api.Config) source.Option { | ||||||
|  | 	return func(o *source.Options) { | ||||||
|  | 		if o.Context == nil { | ||||||
|  | 			o.Context = context.Background() | ||||||
|  | 		} | ||||||
|  | 		o.Context = context.WithValue(o.Context, configKey{}, c) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -8,40 +8,80 @@ import ( | |||||||
| 	"github.com/micro/go-micro/config/encoder" | 	"github.com/micro/go-micro/config/encoder" | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | type configValue interface { | ||||||
|  | 	Value() interface{} | ||||||
|  | 	Decode(encoder.Encoder, []byte) error | ||||||
|  | } | ||||||
|  | type configArrayValue struct { | ||||||
|  | 	v []interface{} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (a *configArrayValue) Value() interface{} { return a.v } | ||||||
|  | func (a *configArrayValue) Decode(e encoder.Encoder, b []byte) error { | ||||||
|  | 	return e.Decode(b, &a.v) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type configMapValue struct { | ||||||
|  | 	v map[string]interface{} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *configMapValue) Value() interface{} { return m.v } | ||||||
|  | func (m *configMapValue) Decode(e encoder.Encoder, b []byte) error { | ||||||
|  | 	return e.Decode(b, &m.v) | ||||||
|  | } | ||||||
|  |  | ||||||
| func makeMap(e encoder.Encoder, kv api.KVPairs, stripPrefix string) (map[string]interface{}, error) { | func makeMap(e encoder.Encoder, kv api.KVPairs, stripPrefix string) (map[string]interface{}, error) { | ||||||
|  |  | ||||||
| 	data := make(map[string]interface{}) | 	data := make(map[string]interface{}) | ||||||
|  |  | ||||||
| 	// consul guarantees lexicographic order, so no need to sort | 	// consul guarantees lexicographic order, so no need to sort | ||||||
| 	for _, v := range kv { | 	for _, v := range kv { | ||||||
| 		pathString := strings.TrimPrefix(strings.TrimPrefix(v.Key, stripPrefix), "/") | 		pathString := strings.TrimPrefix(strings.TrimPrefix(v.Key, strings.TrimPrefix(stripPrefix, "/")), "/") | ||||||
| 		var val map[string]interface{} | 		if pathString == "" { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		var val configValue | ||||||
|  | 		var err error | ||||||
|  |  | ||||||
| 		// ensure a valid value is stored at this location | 		// ensure a valid value is stored at this location | ||||||
| 		if len(v.Value) > 0 { | 		if len(v.Value) > 0 { | ||||||
| 			if err := e.Decode(v.Value, &val); err != nil { | 			// try to decode into map value or array value | ||||||
|  | 			arrayV := &configArrayValue{v: []interface{}{}} | ||||||
|  | 			mapV := &configMapValue{v: map[string]interface{}{}} | ||||||
|  | 			switch { | ||||||
|  | 			case arrayV.Decode(e, v.Value) == nil: | ||||||
|  | 				val = arrayV | ||||||
|  | 			case mapV.Decode(e, v.Value) == nil: | ||||||
|  | 				val = mapV | ||||||
|  | 			default: | ||||||
| 				return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err) | 				return nil, fmt.Errorf("faild decode value. path: %s, error: %s", pathString, err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		// set target at the root | 		// set target at the root | ||||||
| 		target := data | 		target := data | ||||||
|  |  | ||||||
| 		// then descend to the target location, creating as we go, if need be |  | ||||||
| 		if pathString != "" { |  | ||||||
| 		path := strings.Split(pathString, "/") | 		path := strings.Split(pathString, "/") | ||||||
| 			// find (or create) the location we want to put this value at | 		// find (or create) the leaf node we want to put this value at | ||||||
| 			for _, dir := range path { | 		for _, dir := range path[:len(path)-1] { | ||||||
| 			if _, ok := target[dir]; !ok { | 			if _, ok := target[dir]; !ok { | ||||||
| 				target[dir] = make(map[string]interface{}) | 				target[dir] = make(map[string]interface{}) | ||||||
| 			} | 			} | ||||||
| 			target = target[dir].(map[string]interface{}) | 			target = target[dir].(map[string]interface{}) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		} | 		leafDir := path[len(path)-1] | ||||||
|  |  | ||||||
| 		// copy over the keys from the value | 		// copy over the keys from the value | ||||||
| 		for k := range val { | 		switch val.(type) { | ||||||
| 			target[k] = val[k] | 		case *configArrayValue: | ||||||
|  | 			target[leafDir] = val.Value() | ||||||
|  | 		case *configMapValue: | ||||||
|  | 			target[leafDir] = make(map[string]interface{}) | ||||||
|  | 			target = target[leafDir].(map[string]interface{}) | ||||||
|  | 			mapv := val.Value().(map[string]interface{}) | ||||||
|  | 			for k := range mapv { | ||||||
|  | 				target[k] = mapv[k] | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
| @@ -27,7 +27,7 @@ Specify source with data | |||||||
|  |  | ||||||
| ```go | ```go | ||||||
| memorySource := memory.NewSource( | memorySource := memory.NewSource( | ||||||
| 	memory.WithData(data), | 	memory.WithJSON(data), | ||||||
| ) | ) | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								data/data.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								data/data.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  | // Package data is an interface for data access | ||||||
|  | package data | ||||||
| @@ -7,7 +7,7 @@ import ( | |||||||
| 
 | 
 | ||||||
| 	"github.com/hashicorp/consul/api" | 	"github.com/hashicorp/consul/api" | ||||||
| 	"github.com/micro/go-micro/config/options" | 	"github.com/micro/go-micro/config/options" | ||||||
| 	"github.com/micro/go-micro/store" | 	"github.com/micro/go-micro/data/store" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type ckv struct { | type ckv struct { | ||||||
| @@ -6,7 +6,7 @@ import ( | |||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/micro/go-micro/config/options" | 	"github.com/micro/go-micro/config/options" | ||||||
| 	"github.com/micro/go-micro/store" | 	"github.com/micro/go-micro/data/store" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type memoryStore struct { | type memoryStore struct { | ||||||
| @@ -32,10 +32,16 @@ func (m *memoryStore) Dump() ([]*store.Record, error) { | |||||||
| 		d := v.r.Expiry | 		d := v.r.Expiry | ||||||
| 		t := time.Since(v.c) | 		t := time.Since(v.c) | ||||||
| 
 | 
 | ||||||
|  | 		if d > time.Duration(0) { | ||||||
| 			// expired | 			// expired | ||||||
| 		if d > time.Duration(0) && t > d { | 			if t > d { | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  | 			// update expiry | ||||||
|  | 			v.r.Expiry -= t | ||||||
|  | 			v.c = time.Now() | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		values = append(values, v.r) | 		values = append(values, v.r) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @@ -56,9 +62,14 @@ func (m *memoryStore) Read(key string) (*store.Record, error) { | |||||||
| 	t := time.Since(v.c) | 	t := time.Since(v.c) | ||||||
| 
 | 
 | ||||||
| 	// expired | 	// expired | ||||||
| 	if d > time.Duration(0) && t > d { | 	if d > time.Duration(0) { | ||||||
|  | 		if t > d { | ||||||
| 			return nil, store.ErrNotFound | 			return nil, store.ErrNotFound | ||||||
| 		} | 		} | ||||||
|  | 		// update expiry | ||||||
|  | 		v.r.Expiry -= t | ||||||
|  | 		v.c = time.Now() | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	return v.r, nil | 	return v.r, nil | ||||||
| } | } | ||||||
							
								
								
									
										37
									
								
								data/store/memory/memory_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								data/store/memory/memory_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | package memory | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/data/store" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestReadRecordExpire(t *testing.T) { | ||||||
|  | 	s := NewStore() | ||||||
|  |  | ||||||
|  | 	var ( | ||||||
|  | 		key    = "foo" | ||||||
|  | 		expire = 100 * time.Millisecond | ||||||
|  | 	) | ||||||
|  | 	rec := &store.Record{ | ||||||
|  | 		Key:    key, | ||||||
|  | 		Value:  nil, | ||||||
|  | 		Expiry: expire, | ||||||
|  | 	} | ||||||
|  | 	s.Write(rec) | ||||||
|  |  | ||||||
|  | 	rrec, err := s.Read(key) | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	if rrec.Expiry >= expire { | ||||||
|  | 		t.Fatal("expiry of read record is not changed") | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	time.Sleep(expire) | ||||||
|  |  | ||||||
|  | 	if _, err := s.Read(key); err != store.ErrNotFound { | ||||||
|  | 		t.Fatal("expire elapsed, but key still accessable") | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										41
									
								
								debug/handler/debug.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								debug/handler/debug.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | package handler | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"runtime" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	proto "github.com/micro/go-micro/debug/proto" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Debug struct { | ||||||
|  | 	proto.DebugHandler | ||||||
|  | 	started int64 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	DefaultHandler = newDebug() | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func newDebug() *Debug { | ||||||
|  | 	return &Debug{ | ||||||
|  | 		started: time.Now().Unix(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *Debug) Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error { | ||||||
|  | 	rsp.Status = "ok" | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (d *Debug) Stats(ctx context.Context, req *proto.StatsRequest, rsp *proto.StatsResponse) error { | ||||||
|  | 	var mstat runtime.MemStats | ||||||
|  | 	runtime.ReadMemStats(&mstat) | ||||||
|  |  | ||||||
|  | 	rsp.Started = uint64(d.started) | ||||||
|  | 	rsp.Uptime = uint64(time.Now().Unix() - d.started) | ||||||
|  | 	rsp.Memory = mstat.Alloc | ||||||
|  | 	rsp.Gc = mstat.PauseTotalNs | ||||||
|  | 	rsp.Threads = uint64(runtime.NumGoroutine()) | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
							
								
								
									
										108
									
								
								debug/proto/debug.micro.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								debug/proto/debug.micro.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | |||||||
|  | // Code generated by protoc-gen-micro. DO NOT EDIT. | ||||||
|  | // source: micro/go-micro/debug/proto/debug.proto | ||||||
|  |  | ||||||
|  | package debug | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	fmt "fmt" | ||||||
|  | 	proto "github.com/golang/protobuf/proto" | ||||||
|  | 	math "math" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	context "context" | ||||||
|  | 	client "github.com/micro/go-micro/client" | ||||||
|  | 	server "github.com/micro/go-micro/server" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Reference imports to suppress errors if they are not otherwise used. | ||||||
|  | var _ = proto.Marshal | ||||||
|  | var _ = fmt.Errorf | ||||||
|  | var _ = math.Inf | ||||||
|  |  | ||||||
|  | // This is a compile-time assertion to ensure that this generated file | ||||||
|  | // is compatible with the proto package it is being compiled against. | ||||||
|  | // A compilation error at this line likely means your copy of the | ||||||
|  | // proto package needs to be updated. | ||||||
|  | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package | ||||||
|  |  | ||||||
|  | // Reference imports to suppress errors if they are not otherwise used. | ||||||
|  | var _ context.Context | ||||||
|  | var _ client.Option | ||||||
|  | var _ server.Option | ||||||
|  |  | ||||||
|  | // Client API for Debug service | ||||||
|  |  | ||||||
|  | type DebugService interface { | ||||||
|  | 	Health(ctx context.Context, in *HealthRequest, opts ...client.CallOption) (*HealthResponse, error) | ||||||
|  | 	Stats(ctx context.Context, in *StatsRequest, opts ...client.CallOption) (*StatsResponse, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type debugService struct { | ||||||
|  | 	c    client.Client | ||||||
|  | 	name string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func NewDebugService(name string, c client.Client) DebugService { | ||||||
|  | 	if c == nil { | ||||||
|  | 		c = client.NewClient() | ||||||
|  | 	} | ||||||
|  | 	if len(name) == 0 { | ||||||
|  | 		name = "debug" | ||||||
|  | 	} | ||||||
|  | 	return &debugService{ | ||||||
|  | 		c:    c, | ||||||
|  | 		name: name, | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *debugService) Health(ctx context.Context, in *HealthRequest, opts ...client.CallOption) (*HealthResponse, error) { | ||||||
|  | 	req := c.c.NewRequest(c.name, "Debug.Health", in) | ||||||
|  | 	out := new(HealthResponse) | ||||||
|  | 	err := c.c.Call(ctx, req, out, opts...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return out, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *debugService) Stats(ctx context.Context, in *StatsRequest, opts ...client.CallOption) (*StatsResponse, error) { | ||||||
|  | 	req := c.c.NewRequest(c.name, "Debug.Stats", in) | ||||||
|  | 	out := new(StatsResponse) | ||||||
|  | 	err := c.c.Call(ctx, req, out, opts...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return out, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Server API for Debug service | ||||||
|  |  | ||||||
|  | type DebugHandler interface { | ||||||
|  | 	Health(context.Context, *HealthRequest, *HealthResponse) error | ||||||
|  | 	Stats(context.Context, *StatsRequest, *StatsResponse) error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RegisterDebugHandler(s server.Server, hdlr DebugHandler, opts ...server.HandlerOption) error { | ||||||
|  | 	type debug interface { | ||||||
|  | 		Health(ctx context.Context, in *HealthRequest, out *HealthResponse) error | ||||||
|  | 		Stats(ctx context.Context, in *StatsRequest, out *StatsResponse) error | ||||||
|  | 	} | ||||||
|  | 	type Debug struct { | ||||||
|  | 		debug | ||||||
|  | 	} | ||||||
|  | 	h := &debugHandler{hdlr} | ||||||
|  | 	return s.Handle(s.NewHandler(&Debug{h}, opts...)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type debugHandler struct { | ||||||
|  | 	DebugHandler | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (h *debugHandler) Health(ctx context.Context, in *HealthRequest, out *HealthResponse) error { | ||||||
|  | 	return h.DebugHandler.Health(ctx, in, out) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (h *debugHandler) Stats(ctx context.Context, in *StatsRequest, out *StatsResponse) error { | ||||||
|  | 	return h.DebugHandler.Stats(ctx, in, out) | ||||||
|  | } | ||||||
							
								
								
									
										336
									
								
								debug/proto/debug.pb.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								debug/proto/debug.pb.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,336 @@ | |||||||
|  | // Code generated by protoc-gen-go. DO NOT EDIT. | ||||||
|  | // source: micro/go-micro/debug/proto/debug.proto | ||||||
|  |  | ||||||
|  | package debug | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	context "context" | ||||||
|  | 	fmt "fmt" | ||||||
|  | 	proto "github.com/golang/protobuf/proto" | ||||||
|  | 	grpc "google.golang.org/grpc" | ||||||
|  | 	math "math" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Reference imports to suppress errors if they are not otherwise used. | ||||||
|  | var _ = proto.Marshal | ||||||
|  | var _ = fmt.Errorf | ||||||
|  | var _ = math.Inf | ||||||
|  |  | ||||||
|  | // This is a compile-time assertion to ensure that this generated file | ||||||
|  | // is compatible with the proto package it is being compiled against. | ||||||
|  | // A compilation error at this line likely means your copy of the | ||||||
|  | // proto package needs to be updated. | ||||||
|  | const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package | ||||||
|  |  | ||||||
|  | type HealthRequest struct { | ||||||
|  | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
|  | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
|  | 	XXX_sizecache        int32    `json:"-"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *HealthRequest) Reset()         { *m = HealthRequest{} } | ||||||
|  | func (m *HealthRequest) String() string { return proto.CompactTextString(m) } | ||||||
|  | func (*HealthRequest) ProtoMessage()    {} | ||||||
|  | func (*HealthRequest) Descriptor() ([]byte, []int) { | ||||||
|  | 	return fileDescriptor_f25415e61bccfa1f, []int{0} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *HealthRequest) XXX_Unmarshal(b []byte) error { | ||||||
|  | 	return xxx_messageInfo_HealthRequest.Unmarshal(m, b) | ||||||
|  | } | ||||||
|  | func (m *HealthRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||||
|  | 	return xxx_messageInfo_HealthRequest.Marshal(b, m, deterministic) | ||||||
|  | } | ||||||
|  | func (m *HealthRequest) XXX_Merge(src proto.Message) { | ||||||
|  | 	xxx_messageInfo_HealthRequest.Merge(m, src) | ||||||
|  | } | ||||||
|  | func (m *HealthRequest) XXX_Size() int { | ||||||
|  | 	return xxx_messageInfo_HealthRequest.Size(m) | ||||||
|  | } | ||||||
|  | func (m *HealthRequest) XXX_DiscardUnknown() { | ||||||
|  | 	xxx_messageInfo_HealthRequest.DiscardUnknown(m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var xxx_messageInfo_HealthRequest proto.InternalMessageInfo | ||||||
|  |  | ||||||
|  | type HealthResponse struct { | ||||||
|  | 	// default: ok | ||||||
|  | 	Status               string   `protobuf:"bytes,1,opt,name=status,proto3" json:"status,omitempty"` | ||||||
|  | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
|  | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
|  | 	XXX_sizecache        int32    `json:"-"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *HealthResponse) Reset()         { *m = HealthResponse{} } | ||||||
|  | func (m *HealthResponse) String() string { return proto.CompactTextString(m) } | ||||||
|  | func (*HealthResponse) ProtoMessage()    {} | ||||||
|  | func (*HealthResponse) Descriptor() ([]byte, []int) { | ||||||
|  | 	return fileDescriptor_f25415e61bccfa1f, []int{1} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *HealthResponse) XXX_Unmarshal(b []byte) error { | ||||||
|  | 	return xxx_messageInfo_HealthResponse.Unmarshal(m, b) | ||||||
|  | } | ||||||
|  | func (m *HealthResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||||
|  | 	return xxx_messageInfo_HealthResponse.Marshal(b, m, deterministic) | ||||||
|  | } | ||||||
|  | func (m *HealthResponse) XXX_Merge(src proto.Message) { | ||||||
|  | 	xxx_messageInfo_HealthResponse.Merge(m, src) | ||||||
|  | } | ||||||
|  | func (m *HealthResponse) XXX_Size() int { | ||||||
|  | 	return xxx_messageInfo_HealthResponse.Size(m) | ||||||
|  | } | ||||||
|  | func (m *HealthResponse) XXX_DiscardUnknown() { | ||||||
|  | 	xxx_messageInfo_HealthResponse.DiscardUnknown(m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var xxx_messageInfo_HealthResponse proto.InternalMessageInfo | ||||||
|  |  | ||||||
|  | func (m *HealthResponse) GetStatus() string { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Status | ||||||
|  | 	} | ||||||
|  | 	return "" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type StatsRequest struct { | ||||||
|  | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
|  | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
|  | 	XXX_sizecache        int32    `json:"-"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *StatsRequest) Reset()         { *m = StatsRequest{} } | ||||||
|  | func (m *StatsRequest) String() string { return proto.CompactTextString(m) } | ||||||
|  | func (*StatsRequest) ProtoMessage()    {} | ||||||
|  | func (*StatsRequest) Descriptor() ([]byte, []int) { | ||||||
|  | 	return fileDescriptor_f25415e61bccfa1f, []int{2} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *StatsRequest) XXX_Unmarshal(b []byte) error { | ||||||
|  | 	return xxx_messageInfo_StatsRequest.Unmarshal(m, b) | ||||||
|  | } | ||||||
|  | func (m *StatsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||||
|  | 	return xxx_messageInfo_StatsRequest.Marshal(b, m, deterministic) | ||||||
|  | } | ||||||
|  | func (m *StatsRequest) XXX_Merge(src proto.Message) { | ||||||
|  | 	xxx_messageInfo_StatsRequest.Merge(m, src) | ||||||
|  | } | ||||||
|  | func (m *StatsRequest) XXX_Size() int { | ||||||
|  | 	return xxx_messageInfo_StatsRequest.Size(m) | ||||||
|  | } | ||||||
|  | func (m *StatsRequest) XXX_DiscardUnknown() { | ||||||
|  | 	xxx_messageInfo_StatsRequest.DiscardUnknown(m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var xxx_messageInfo_StatsRequest proto.InternalMessageInfo | ||||||
|  |  | ||||||
|  | type StatsResponse struct { | ||||||
|  | 	// unix timestamp | ||||||
|  | 	Started uint64 `protobuf:"varint,1,opt,name=started,proto3" json:"started,omitempty"` | ||||||
|  | 	// in seconds | ||||||
|  | 	Uptime uint64 `protobuf:"varint,2,opt,name=uptime,proto3" json:"uptime,omitempty"` | ||||||
|  | 	// in bytes | ||||||
|  | 	Memory uint64 `protobuf:"varint,3,opt,name=memory,proto3" json:"memory,omitempty"` | ||||||
|  | 	// num threads | ||||||
|  | 	Threads uint64 `protobuf:"varint,4,opt,name=threads,proto3" json:"threads,omitempty"` | ||||||
|  | 	// total gc in nanoseconds | ||||||
|  | 	Gc                   uint64   `protobuf:"varint,5,opt,name=gc,proto3" json:"gc,omitempty"` | ||||||
|  | 	XXX_NoUnkeyedLiteral struct{} `json:"-"` | ||||||
|  | 	XXX_unrecognized     []byte   `json:"-"` | ||||||
|  | 	XXX_sizecache        int32    `json:"-"` | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *StatsResponse) Reset()         { *m = StatsResponse{} } | ||||||
|  | func (m *StatsResponse) String() string { return proto.CompactTextString(m) } | ||||||
|  | func (*StatsResponse) ProtoMessage()    {} | ||||||
|  | func (*StatsResponse) Descriptor() ([]byte, []int) { | ||||||
|  | 	return fileDescriptor_f25415e61bccfa1f, []int{3} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *StatsResponse) XXX_Unmarshal(b []byte) error { | ||||||
|  | 	return xxx_messageInfo_StatsResponse.Unmarshal(m, b) | ||||||
|  | } | ||||||
|  | func (m *StatsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { | ||||||
|  | 	return xxx_messageInfo_StatsResponse.Marshal(b, m, deterministic) | ||||||
|  | } | ||||||
|  | func (m *StatsResponse) XXX_Merge(src proto.Message) { | ||||||
|  | 	xxx_messageInfo_StatsResponse.Merge(m, src) | ||||||
|  | } | ||||||
|  | func (m *StatsResponse) XXX_Size() int { | ||||||
|  | 	return xxx_messageInfo_StatsResponse.Size(m) | ||||||
|  | } | ||||||
|  | func (m *StatsResponse) XXX_DiscardUnknown() { | ||||||
|  | 	xxx_messageInfo_StatsResponse.DiscardUnknown(m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var xxx_messageInfo_StatsResponse proto.InternalMessageInfo | ||||||
|  |  | ||||||
|  | func (m *StatsResponse) GetStarted() uint64 { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Started | ||||||
|  | 	} | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *StatsResponse) GetUptime() uint64 { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Uptime | ||||||
|  | 	} | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *StatsResponse) GetMemory() uint64 { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Memory | ||||||
|  | 	} | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *StatsResponse) GetThreads() uint64 { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Threads | ||||||
|  | 	} | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *StatsResponse) GetGc() uint64 { | ||||||
|  | 	if m != nil { | ||||||
|  | 		return m.Gc | ||||||
|  | 	} | ||||||
|  | 	return 0 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	proto.RegisterType((*HealthRequest)(nil), "HealthRequest") | ||||||
|  | 	proto.RegisterType((*HealthResponse)(nil), "HealthResponse") | ||||||
|  | 	proto.RegisterType((*StatsRequest)(nil), "StatsRequest") | ||||||
|  | 	proto.RegisterType((*StatsResponse)(nil), "StatsResponse") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func init() { | ||||||
|  | 	proto.RegisterFile("micro/go-micro/debug/proto/debug.proto", fileDescriptor_f25415e61bccfa1f) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var fileDescriptor_f25415e61bccfa1f = []byte{ | ||||||
|  | 	// 230 bytes of a gzipped FileDescriptorProto | ||||||
|  | 	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x90, 0x41, 0x4b, 0xc4, 0x30, | ||||||
|  | 	0x10, 0x85, 0xb7, 0x75, 0x5b, 0x71, 0xb0, 0x59, 0xc8, 0x41, 0xc2, 0x9e, 0x24, 0x07, 0x29, 0x88, | ||||||
|  | 	0x59, 0xd0, 0xbf, 0xe0, 0xc1, 0x73, 0xbd, 0x0b, 0xd9, 0x76, 0xe8, 0x16, 0xac, 0xa9, 0x99, 0xe9, | ||||||
|  | 	0xc1, 0xb3, 0x7f, 0x5c, 0x9a, 0xa4, 0x60, 0x6f, 0xef, 0xbd, 0xf0, 0x1e, 0xf9, 0x06, 0x1e, 0xc6, | ||||||
|  | 	0xa1, 0xf5, 0xee, 0xd4, 0xbb, 0xa7, 0x28, 0x3a, 0x3c, 0xcf, 0xfd, 0x69, 0xf2, 0x8e, 0x93, 0x36, | ||||||
|  | 	0x41, 0xeb, 0x03, 0x54, 0x6f, 0x68, 0x3f, 0xf9, 0xd2, 0xe0, 0xf7, 0x8c, 0xc4, 0xba, 0x06, 0xb1, | ||||||
|  | 	0x06, 0x34, 0xb9, 0x2f, 0x42, 0x79, 0x07, 0x25, 0xb1, 0xe5, 0x99, 0x54, 0x76, 0x9f, 0xd5, 0x37, | ||||||
|  | 	0x4d, 0x72, 0x5a, 0xc0, 0xed, 0x3b, 0x5b, 0xa6, 0xb5, 0xf9, 0x9b, 0x41, 0x95, 0x82, 0xd4, 0x54, | ||||||
|  | 	0x70, 0x4d, 0x6c, 0x3d, 0x63, 0x17, 0xaa, 0xfb, 0x66, 0xb5, 0xcb, 0xe6, 0x3c, 0xf1, 0x30, 0xa2, | ||||||
|  | 	0xca, 0xc3, 0x43, 0x72, 0x4b, 0x3e, 0xe2, 0xe8, 0xfc, 0x8f, 0xba, 0x8a, 0x79, 0x74, 0xcb, 0x12, | ||||||
|  | 	0x5f, 0x3c, 0xda, 0x8e, 0xd4, 0x3e, 0x2e, 0x25, 0x2b, 0x05, 0xe4, 0x7d, 0xab, 0x8a, 0x10, 0xe6, | ||||||
|  | 	0x7d, 0xfb, 0xfc, 0x01, 0xc5, 0xeb, 0xc2, 0x27, 0x1f, 0xa1, 0x8c, 0x20, 0x52, 0x98, 0x0d, 0xe2, | ||||||
|  | 	0xf1, 0x60, 0xb6, 0x84, 0x7a, 0x27, 0x6b, 0x28, 0xc2, 0xd7, 0x65, 0x65, 0xfe, 0x33, 0x1d, 0x85, | ||||||
|  | 	0xd9, 0x10, 0xe9, 0xdd, 0xb9, 0x0c, 0x77, 0x7b, 0xf9, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xb9, | ||||||
|  | 	0x5f, 0xf7, 0x61, 0x01, 0x00, 0x00, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Reference imports to suppress errors if they are not otherwise used. | ||||||
|  | var _ context.Context | ||||||
|  | var _ grpc.ClientConn | ||||||
|  |  | ||||||
|  | // This is a compile-time assertion to ensure that this generated file | ||||||
|  | // is compatible with the grpc package it is being compiled against. | ||||||
|  | const _ = grpc.SupportPackageIsVersion4 | ||||||
|  |  | ||||||
|  | // DebugClient is the client API for Debug service. | ||||||
|  | // | ||||||
|  | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. | ||||||
|  | type DebugClient interface { | ||||||
|  | 	Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error) | ||||||
|  | 	Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type debugClient struct { | ||||||
|  | 	cc *grpc.ClientConn | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func NewDebugClient(cc *grpc.ClientConn) DebugClient { | ||||||
|  | 	return &debugClient{cc} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *debugClient) Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error) { | ||||||
|  | 	out := new(HealthResponse) | ||||||
|  | 	err := c.cc.Invoke(ctx, "/Debug/Health", in, out, opts...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return out, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (c *debugClient) Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error) { | ||||||
|  | 	out := new(StatsResponse) | ||||||
|  | 	err := c.cc.Invoke(ctx, "/Debug/Stats", in, out, opts...) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	return out, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // DebugServer is the server API for Debug service. | ||||||
|  | type DebugServer interface { | ||||||
|  | 	Health(context.Context, *HealthRequest) (*HealthResponse, error) | ||||||
|  | 	Stats(context.Context, *StatsRequest) (*StatsResponse, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func RegisterDebugServer(s *grpc.Server, srv DebugServer) { | ||||||
|  | 	s.RegisterService(&_Debug_serviceDesc, srv) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _Debug_Health_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | ||||||
|  | 	in := new(HealthRequest) | ||||||
|  | 	if err := dec(in); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if interceptor == nil { | ||||||
|  | 		return srv.(DebugServer).Health(ctx, in) | ||||||
|  | 	} | ||||||
|  | 	info := &grpc.UnaryServerInfo{ | ||||||
|  | 		Server:     srv, | ||||||
|  | 		FullMethod: "/Debug/Health", | ||||||
|  | 	} | ||||||
|  | 	handler := func(ctx context.Context, req interface{}) (interface{}, error) { | ||||||
|  | 		return srv.(DebugServer).Health(ctx, req.(*HealthRequest)) | ||||||
|  | 	} | ||||||
|  | 	return interceptor(ctx, in, info, handler) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func _Debug_Stats_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { | ||||||
|  | 	in := new(StatsRequest) | ||||||
|  | 	if err := dec(in); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	if interceptor == nil { | ||||||
|  | 		return srv.(DebugServer).Stats(ctx, in) | ||||||
|  | 	} | ||||||
|  | 	info := &grpc.UnaryServerInfo{ | ||||||
|  | 		Server:     srv, | ||||||
|  | 		FullMethod: "/Debug/Stats", | ||||||
|  | 	} | ||||||
|  | 	handler := func(ctx context.Context, req interface{}) (interface{}, error) { | ||||||
|  | 		return srv.(DebugServer).Stats(ctx, req.(*StatsRequest)) | ||||||
|  | 	} | ||||||
|  | 	return interceptor(ctx, in, info, handler) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var _Debug_serviceDesc = grpc.ServiceDesc{ | ||||||
|  | 	ServiceName: "Debug", | ||||||
|  | 	HandlerType: (*DebugServer)(nil), | ||||||
|  | 	Methods: []grpc.MethodDesc{ | ||||||
|  | 		{ | ||||||
|  | 			MethodName: "Health", | ||||||
|  | 			Handler:    _Debug_Health_Handler, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			MethodName: "Stats", | ||||||
|  | 			Handler:    _Debug_Stats_Handler, | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 	Streams:  []grpc.StreamDesc{}, | ||||||
|  | 	Metadata: "micro/go-micro/debug/proto/debug.proto", | ||||||
|  | } | ||||||
| @@ -1,13 +1,9 @@ | |||||||
| syntax = "proto3"; | syntax = "proto3"; | ||||||
| 
 | 
 | ||||||
| // This is commented out due to import cycles. | service Debug { | ||||||
| // But its what we expect the RPC service to  |  	rpc Health(HealthRequest) returns (HealthResponse) {} | ||||||
| // return. |  	rpc Stats(StatsRequest) returns (StatsResponse) {} | ||||||
| // | } | ||||||
| // service Debug { |  | ||||||
| // 	rpc Health(HealthRequest) returns (HealthResponse) {} |  | ||||||
| // 	rpc Stats(StatsRequest) returns (StatsResponse) {} |  | ||||||
| // } |  | ||||||
| 
 | 
 | ||||||
| message HealthRequest { | message HealthRequest { | ||||||
| } | } | ||||||
| @@ -5,8 +5,8 @@ import ( | |||||||
| 	"sync" | 	"sync" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
|  | 	proto "github.com/micro/go-micro/debug/proto" | ||||||
| 	"github.com/micro/go-micro/registry/memory" | 	"github.com/micro/go-micro/registry/memory" | ||||||
| 	proto "github.com/micro/go-micro/server/debug/proto" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestFunction(t *testing.T) { | func TestFunction(t *testing.T) { | ||||||
|   | |||||||
							
								
								
									
										58
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								go.mod
									
									
									
									
									
								
							| @@ -3,42 +3,78 @@ module github.com/micro/go-micro | |||||||
| go 1.12 | go 1.12 | ||||||
|  |  | ||||||
| require ( | require ( | ||||||
|  | 	cloud.google.com/go v0.43.0 // indirect | ||||||
| 	github.com/BurntSushi/toml v0.3.1 | 	github.com/BurntSushi/toml v0.3.1 | ||||||
|  | 	github.com/Microsoft/go-winio v0.4.14 // indirect | ||||||
|  | 	github.com/armon/circbuf v0.0.0-20190214190532-5111143e8da2 // indirect | ||||||
|  | 	github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 // indirect | ||||||
|  | 	github.com/armon/go-radix v1.0.0 // indirect | ||||||
| 	github.com/beevik/ntp v0.2.0 | 	github.com/beevik/ntp v0.2.0 | ||||||
| 	github.com/bitly/go-simplejson v0.5.0 | 	github.com/bitly/go-simplejson v0.5.0 | ||||||
| 	github.com/bwmarrin/discordgo v0.19.0 | 	github.com/bwmarrin/discordgo v0.19.0 | ||||||
|  | 	github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc // indirect | ||||||
| 	github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c | 	github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c | ||||||
| 	github.com/fsnotify/fsnotify v1.4.7 | 	github.com/fsnotify/fsnotify v1.4.7 | ||||||
| 	github.com/fsouza/go-dockerclient v1.4.1 | 	github.com/fsouza/go-dockerclient v1.4.2 | ||||||
| 	github.com/ghodss/yaml v1.0.0 | 	github.com/ghodss/yaml v1.0.0 | ||||||
|  | 	github.com/go-kit/kit v0.9.0 // indirect | ||||||
| 	github.com/go-log/log v0.1.0 | 	github.com/go-log/log v0.1.0 | ||||||
| 	github.com/go-playground/locales v0.12.1 // indirect | 	github.com/go-playground/locales v0.12.1 // indirect | ||||||
| 	github.com/go-playground/universal-translator v0.16.0 // indirect | 	github.com/go-playground/universal-translator v0.16.0 // indirect | ||||||
| 	github.com/golang/protobuf v1.3.1 | 	github.com/golang/protobuf v1.3.2 | ||||||
|  | 	github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70 // indirect | ||||||
| 	github.com/google/uuid v1.1.1 | 	github.com/google/uuid v1.1.1 | ||||||
| 	github.com/gorilla/handlers v1.4.0 | 	github.com/gorilla/handlers v1.4.2 | ||||||
| 	github.com/gorilla/websocket v1.4.0 | 	github.com/gorilla/websocket v1.4.0 | ||||||
| 	github.com/hashicorp/consul/api v1.1.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/golang-lru v0.5.3 // indirect | ||||||
| 	github.com/hashicorp/hcl v1.0.0 | 	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/memberlist v0.1.4 | ||||||
|  | 	github.com/hashicorp/serf v0.8.3 // indirect | ||||||
| 	github.com/imdario/mergo v0.3.7 | 	github.com/imdario/mergo v0.3.7 | ||||||
| 	github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1 | 	github.com/joncalhoun/qson v0.0.0-20170526102502-8a9cab3a62b1 | ||||||
| 	github.com/json-iterator/go v1.1.6 | 	github.com/json-iterator/go v1.1.7 | ||||||
|  | 	github.com/kisielk/errcheck v1.2.0 // indirect | ||||||
|  | 	github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect | ||||||
| 	github.com/leodido/go-urn v1.1.0 // indirect | 	github.com/leodido/go-urn v1.1.0 // indirect | ||||||
| 	github.com/lucas-clemente/quic-go v0.11.2 | 	github.com/lucas-clemente/quic-go v0.12.0 | ||||||
|  | 	github.com/mattn/go-colorable v0.1.2 // indirect | ||||||
|  | 	github.com/mattn/go-runewidth v0.0.4 // indirect | ||||||
| 	github.com/micro/cli v0.2.0 | 	github.com/micro/cli v0.2.0 | ||||||
| 	github.com/micro/mdns v0.1.0 | 	github.com/micro/mdns v0.2.0 | ||||||
|  | 	github.com/miekg/dns v1.1.15 // indirect | ||||||
|  | 	github.com/mitchellh/gox v1.0.1 // indirect | ||||||
| 	github.com/mitchellh/hashstructure v1.0.0 | 	github.com/mitchellh/hashstructure v1.0.0 | ||||||
| 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | ||||||
| 	github.com/modern-go/reflect2 v1.0.1 // indirect | 	github.com/modern-go/reflect2 v1.0.1 // indirect | ||||||
|  | 	github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect | ||||||
| 	github.com/nats-io/nats.go v1.8.1 | 	github.com/nats-io/nats.go v1.8.1 | ||||||
|  | 	github.com/nats-io/nkeys v0.1.0 // indirect | ||||||
| 	github.com/nlopes/slack v0.5.0 | 	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/pkg/errors v0.8.1 | ||||||
|  | 	github.com/posener/complete v1.2.1 // indirect | ||||||
|  | 	github.com/prometheus/client_golang v1.1.0 // indirect | ||||||
|  | 	github.com/sirupsen/logrus v1.4.2 // indirect | ||||||
| 	github.com/technoweenie/multipartstreamer v1.0.1 // indirect | 	github.com/technoweenie/multipartstreamer v1.0.1 // indirect | ||||||
| 	golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 | 	golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 | ||||||
| 	golang.org/x/net v0.0.0-20190607181551-461777fb6f67 | 	golang.org/x/mobile v0.0.0-20190806162312-597adff16ade // indirect | ||||||
| 	google.golang.org/grpc v1.21.1 | 	golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 | ||||||
| 	gopkg.in/go-playground/validator.v9 v9.29.0 | 	golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect | ||||||
| 	gopkg.in/src-d/go-git.v4 v4.11.0 | 	golang.org/x/tools v0.0.0-20190807201305-8be58fba6352 // indirect | ||||||
|  | 	google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64 // indirect | ||||||
|  | 	google.golang.org/grpc v1.22.1 | ||||||
|  | 	gopkg.in/go-playground/validator.v9 v9.29.1 | ||||||
|  | 	gopkg.in/src-d/go-git.v4 v4.13.1 | ||||||
| 	gopkg.in/telegram-bot-api.v4 v4.6.4 | 	gopkg.in/telegram-bot-api.v4 v4.6.4 | ||||||
|  | 	honnef.co/go/tools v0.0.1-2019.2.2 // indirect | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										296
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										296
									
								
								go.sum
									
									
									
									
									
								
							| @@ -1,16 +1,38 @@ | |||||||
| cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | 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= | ||||||
|  | cloud.google.com/go v0.41.0/go.mod h1:OauMR7DV8fzvZIl2qg6rkaIhD/vmgk4iwEw/h6ercmg= | ||||||
|  | cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= | ||||||
| github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= | 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 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= | ||||||
| github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||||||
|  | github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= | ||||||
|  | github.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= | ||||||
| github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= | github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= | ||||||
|  | github.com/Microsoft/go-winio v0.4.13/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= | ||||||
|  | github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= | ||||||
|  | github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= | ||||||
| github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= | github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= | ||||||
|  | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | ||||||
|  | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= | ||||||
|  | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= | ||||||
|  | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= | ||||||
| github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= | github.com/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-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 h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= | ||||||
| github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= | 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 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 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw= | ||||||
| github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= | github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= | ||||||
|  | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= | ||||||
|  | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= | ||||||
|  | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= | ||||||
| github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= | github.com/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 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= | ||||||
| github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= | github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= | ||||||
| @@ -18,19 +40,30 @@ 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/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 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= | ||||||
| github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= | 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/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 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M= | ||||||
| github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= | github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= | ||||||
|  | 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/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= | ||||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | github.com/davecgh/go-spew v1.1.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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
|  | github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= | ||||||
|  | github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= | ||||||
| github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16 h1:dmUn0SuGx7unKFwxyeQ/oLUHhEfZosEDrpmYM+6MTuc= | github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16 h1:dmUn0SuGx7unKFwxyeQ/oLUHhEfZosEDrpmYM+6MTuc= | ||||||
| github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= | github.com/docker/docker v0.7.3-0.20190309235953-33c3200e0d16/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= | ||||||
|  | github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b h1:+Ga+YpCDpcY1fln6GI0fiiirpqHGcob5/Vk3oKNuGdU= | ||||||
|  | github.com/docker/docker v1.4.2-0.20190710153559-aa8249ae1b8b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= | ||||||
| github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= | ||||||
| github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= | ||||||
| github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= | 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/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 h1:rUF4PuzEjMChMiNsVjdI+SyLu7rEqpQ5reNFnhC7oFo= | ||||||
| github.com/emirpasic/gods v1.9.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= | 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/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/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= | ||||||
| github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c h1:pBgVXWDXju1m8W4lnEeIqTHPOzhTUO81a7yknM/xQR4= | github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c h1:pBgVXWDXju1m8W4lnEeIqTHPOzhTUO81a7yknM/xQR4= | ||||||
| @@ -39,33 +72,61 @@ github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV | |||||||
| github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= | ||||||
| github.com/fsouza/go-dockerclient v1.4.1 h1:W7wuJ3IB48WYZv/UBk9dCTIb9oX805+L9KIm65HcUYs= | github.com/fsouza/go-dockerclient v1.4.1 h1:W7wuJ3IB48WYZv/UBk9dCTIb9oX805+L9KIm65HcUYs= | ||||||
| github.com/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6VKyZvJ99hDjB0qs= | github.com/fsouza/go-dockerclient v1.4.1/go.mod h1:PUNHxbowDqRXfRgZqMz1OeGtbWC6VKyZvJ99hDjB0qs= | ||||||
|  | github.com/fsouza/go-dockerclient v1.4.2 h1:dl6GfIWS5Qn4C6OfSnnoe6YuOV8lvKAE8W/YD1Q7udo= | ||||||
|  | github.com/fsouza/go-dockerclient v1.4.2/go.mod h1:COunfLZrsdwX/j3YVDAG8gIw3KutrI0x1+vGEJ5zxdI= | ||||||
| github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= | github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= | ||||||
| github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= | 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.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-kit/kit v0.9.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 h1:wudGTNsiGzrD5ZjgIkVZ517ugi2XRe9Q/xRCzwEO4/U= | ||||||
| github.com/go-log/log v0.1.0/go.mod h1:4mBwpdRMFLiuXZDCwU2lKQFsoSCo72j3HqBK9d81N2M= | 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 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= | ||||||
| github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= | 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 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= | ||||||
| github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= | 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 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= | ||||||
| github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= | 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/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.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.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.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.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 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= | ||||||
| github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||||
|  | github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= | ||||||
|  | github.com/golang/protobuf v1.3.2/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 h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= | ||||||
| github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= | 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.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | ||||||
| github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||||||
|  | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | ||||||
|  | github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= | ||||||
|  | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||||||
|  | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||||||
|  | github.com/google/pprof v0.0.0-20190723021845-34ac40c74b70/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||||||
|  | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= | ||||||
| github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= | github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= | ||||||
| github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | 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 h1:XulKRWSQK5uChr4pEgSE4Tc/OcmnU9GJuSwdog/tZsA= | ||||||
| github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= | github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= | ||||||
|  | github.com/gorilla/handlers v1.4.1 h1:BHvcRGJe/TrL+OqFxoKQGddTgeibiOjaBssV5a/N9sw= | ||||||
|  | github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= | ||||||
|  | github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= | ||||||
|  | github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= | ||||||
| github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | ||||||
|  | github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | ||||||
| github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= | github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= | ||||||
| github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | ||||||
| github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= | github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= | ||||||
| @@ -73,33 +134,53 @@ 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/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 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= | ||||||
| github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= | 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 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= | ||||||
| github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= | 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 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.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 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.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 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= | ||||||
| github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= | 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 h1:Rqb66Oo1X/eSV1x66xbDccZjhJigjg0+e82kpwzSwCI= | ||||||
| github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= | 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 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= | ||||||
| github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= | 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-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.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-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/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 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.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||||||
|  | github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= | ||||||
|  | github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||||||
|  | github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= | ||||||
|  | github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= | ||||||
| github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= | github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= | ||||||
| github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= | 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/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.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.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= | ||||||
| github.com/hashicorp/memberlist v0.1.4 h1:gkyML/r71w3FL8gUi74Vk76avkj/9lYAY9lvg0OcoGs= | 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/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 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= | ||||||
| github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= | 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/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 h1:anPrsicrIi2ColgWTVPk+TrN42hJIWlfPHSBP9S0ZkM= | ||||||
| github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84= | github.com/ijc/Gotty v0.0.0-20170406111628-a8b993ba6abd/go.mod h1:3LVOLeyx9XVvwPgrt2be44XgSqndprz1G18rSk8KD84= | ||||||
| @@ -112,55 +193,106 @@ 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/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 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= | ||||||
| github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | ||||||
|  | github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= | ||||||
|  | github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||||
|  | github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= | ||||||
|  | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= | ||||||
| github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8= | github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8= | ||||||
| github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | ||||||
|  | github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c h1:VAx3LRNjVNvjtgO7KFRuT/3aye/0zJvwn01rHSfoolo= | ||||||
|  | github.com/kevinburke/ssh_config v0.0.0-20190630040420-2e50c441276c/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | ||||||
|  | github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= | ||||||
|  | github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | ||||||
| github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= | github.com/kisielk/errcheck v1.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/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.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/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.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||||||
|  | github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= | ||||||
|  | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= | ||||||
| github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | 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 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= | ||||||
| github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= | github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= | ||||||
|  | github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031 h1:wjcGvgllMOQw8wNYFH6acq/KlTAdjKMSo1EUYybHXto= | ||||||
|  | github.com/lucas-clemente/quic-go v0.7.1-0.20190710050138-1441923ab031/go.mod h1:lb5aAxL68VvhZ00e7yYuQVK/9FLggtYy4qo7oI5qzqA= | ||||||
| github.com/lucas-clemente/quic-go v0.11.2 h1:Mop0ac3zALaBR3wGs6j8OYe/tcFvFsxTUFMkE/7yUOI= | github.com/lucas-clemente/quic-go v0.11.2 h1:Mop0ac3zALaBR3wGs6j8OYe/tcFvFsxTUFMkE/7yUOI= | ||||||
| github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= | github.com/lucas-clemente/quic-go v0.11.2/go.mod h1:PpMmPfPKO9nKJ/psF49ESTAGQSdfXxlg1otPbEB2nOw= | ||||||
|  | github.com/lucas-clemente/quic-go v0.12.0 h1:dYHUyB50gEQlK3KqytmNySzuyzAcaQ3iuI2ZReAfVrE= | ||||||
|  | github.com/lucas-clemente/quic-go v0.12.0/go.mod h1:UXJJPE4RfFef/xPO5wQm0tITK8gNfqwTxjbE7s3Vb8s= | ||||||
|  | github.com/marten-seemann/qpack v0.1.0/go.mod h1:LFt1NU/Ptjip0C2CPkhimBz5CGE3WGDAUWqna+CNTrI= | ||||||
| github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA= | github.com/marten-seemann/qtls v0.2.3 h1:0yWJ43C62LsZt08vuQJDK1uC1czUc3FJeCLPoNAI4vA= | ||||||
| github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= | 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/marten-seemann/qtls v0.3.1 h1:ySYIvhFjFY2JsNHY6VACvomMEDy3EvdPA6yciUFAiHw= | ||||||
|  | github.com/marten-seemann/qtls v0.3.1/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= | ||||||
|  | github.com/marten-seemann/qtls v0.3.2 h1:O7awy4bHEzSX/K3h+fZig3/Vo03s/RxlxgsAk9sYamI= | ||||||
|  | github.com/marten-seemann/qtls v0.3.2/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk= | ||||||
| github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= | github.com/mattn/go-colorable v0.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.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 h1:ut3rV5JWqZjsXIa2MvGF+qMUP8DAUTvHX9Br5gO4afA= | ||||||
| github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= | github.com/micro/cli v0.2.0/go.mod h1:jRT9gmfVKWSS6pkKcXQ8YhUyj6bzwxK8Fp5b0Y7qNnk= | ||||||
| github.com/micro/mdns v0.1.0 h1:fuLybUsfynbigJmCot/54i+gwe0hpc/vtCMvWt2WfDI= | github.com/micro/mdns v0.1.0 h1:fuLybUsfynbigJmCot/54i+gwe0hpc/vtCMvWt2WfDI= | ||||||
| github.com/micro/mdns v0.1.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= | github.com/micro/mdns v0.1.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= | ||||||
|  | github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478 h1:L6jnZZ763dMLlvst8P0dWHa1WbUu7ppUY1q3AY2hhIU= | ||||||
|  | github.com/micro/mdns v0.1.1-0.20190729112526-ef68c9635478/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= | ||||||
|  | github.com/micro/mdns v0.2.0 h1:/+/n2PSiJURrXsBIGtfCz0hex/XYKqVsn51GAGdFrOE= | ||||||
|  | github.com/micro/mdns v0.2.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc= | ||||||
| github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= | 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 h1:1g0r1IvskvgL8rR+AcHzUA+oFmGcQlaIm4IqakufeMM= | ||||||
| github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= | 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/miekg/dns v1.1.15 h1:CSSIDtllwGLMoA6zjdKnaE6Tx6eVUxQ29LUgGetiDCI= | ||||||
|  | github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= | ||||||
| github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= | 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 h1:vKb8ShqSby24Yrqr/yDYkuFz8d0WUjys40rvnGC8aR0= | ||||||
| github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= | 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-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 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 h1:ZkRJX1CyOoTkar7p/mLS5TZU4nJ1Rn/F8u9dGS02Q3Y= | ||||||
| github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= | github.com/mitchellh/hashstructure v1.0.0/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= | ||||||
| github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= | github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= | ||||||
| github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||||||
| github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= | github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= | ||||||
| github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= | ||||||
|  | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= | ||||||
| github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | ||||||
|  | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | ||||||
| github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= | ||||||
| github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= | ||||||
|  | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= | ||||||
|  | github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= | ||||||
| github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ= | github.com/nats-io/nats.go v1.8.1 h1:6lF/f1/NN6kzUDBz6pyvQDEXO39jqXcWRLu/tKjtOUQ= | ||||||
| github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM= | 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= | github.com/nats-io/nkeys v0.0.2 h1:+qM7QpgXnvDDixitZtQUBDY9w/s9mu1ghS+JIbsrx6M= | ||||||
| github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= | github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= | ||||||
|  | github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4= | ||||||
|  | github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= | ||||||
| github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= | 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/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 h1:NbIae8Kd0NpqaEI3iUrsuS0KbcEDhzhc939jLW5fNm0= | ||||||
| github.com/nlopes/slack v0.5.0/go.mod h1:jVI4BBK3lSktibKahxBF74txcK2vyvkza1z/+rRnVAM= | 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.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.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.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 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= | ||||||
| github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= | 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= | github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= | ||||||
| @@ -168,6 +300,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 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= | ||||||
| github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= | 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.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 h1:U4t4R6YkofJ5xHm3dJzuRpPZ0mr5MMCoAWooScCR7aA= | ||||||
| github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= | github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= | ||||||
| github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||||||
| @@ -175,75 +308,232 @@ 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/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/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.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_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= | ||||||
|  | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= | ||||||
|  | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||||||
|  | github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= | ||||||
|  | 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/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= | ||||||
|  | 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 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 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= | ||||||
| github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= | 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 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= | ||||||
| github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= | 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 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= | ||||||
| github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= | github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= | ||||||
|  | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= | ||||||
|  | github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= | ||||||
|  | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= | ||||||
| github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= | 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/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.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.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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | 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 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM= | ||||||
| github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog= | 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 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro= | ||||||
| github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8= | github.com/xanzy/ssh-agent v0.2.0/go.mod h1:0NyE30eGUDliuLEHJgYte/zncp2zdTStcOnWhgSqHD8= | ||||||
|  | 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-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-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-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-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-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-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-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 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= | ||||||
| golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | 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/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= | ||||||
|  | golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/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/exp v0.0.0-20190627132806-fd42eb6b336f/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | ||||||
|  | golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= | ||||||
|  | golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | ||||||
|  | golang.org/x/image v0.0.0-20190618124811-92942e4437e2/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | ||||||
|  | golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | ||||||
|  | golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= | ||||||
|  | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||||||
|  | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= | ||||||
|  | golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||||||
| golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | 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/mobile v0.0.0-20190711165009-e47acb2ca7f9/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= | ||||||
|  | golang.org/x/mobile v0.0.0-20190806162312-597adff16ade/go.mod h1:AlhUtkH4DA4asiFC5RgK7ZKmauvtkAVcy9L0epCzlWo= | ||||||
|  | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= | ||||||
|  | golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= | ||||||
|  | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||||
|  | 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-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-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-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-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-20190228165749-92fc7df08ae7/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-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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||||
|  | 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 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-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/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= | ||||||
|  | golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
|  | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= | ||||||
|  | golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | golang.org/x/oauth2 v0.0.0-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-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-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-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-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-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-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-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-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-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-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-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 h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= | ||||||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | 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/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542 h1:6ZQFf1D2YYDDI7eSwW8adlkkavTB9sw5I24FVtEvNUQ= | ||||||
|  | golang.org/x/sys v0.0.0-20190710143415-6ec70d6a5542/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
|  | golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M= | ||||||
|  | golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||||
| golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | 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.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-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-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-20190524140312-2c0ae7006135/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= | ||||||
|  | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||||||
|  | golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||||||
|  | golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||||||
|  | golang.org/x/tools v0.0.0-20190710184609-286818132824/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= | ||||||
|  | golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= | ||||||
|  | golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= | ||||||
|  | golang.org/x/tools v0.0.0-20190807201305-8be58fba6352/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||||
|  | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
|  | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= | ||||||
|  | google.golang.org/api v0.6.0/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4= | ||||||
|  | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= | ||||||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | 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-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 h1:lohp5blsw53GBXtLyLNaTXPXS9pJ1tiTw61ZHUoE9Qw= | ||||||
| google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | 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/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= | ||||||
|  | google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532 h1:5pOB7se0B2+IssELuQUs6uoBgYJenkU2AQlvopc2sRw= | ||||||
|  | google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= | ||||||
|  | google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= | ||||||
|  | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64 h1:iKtrH9Y8mcbADOP0YFaEMth7OfuHY9xHOwNj4znpM1A= | ||||||
|  | google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= | ||||||
|  | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | ||||||
|  | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= | ||||||
| google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= | google.golang.org/grpc v1.21.1 h1:j6XxA85m/6txkUCHvzlV5f+HBNl/1r5cZ2A/3IEFOO8= | ||||||
| google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | ||||||
|  | google.golang.org/grpc v1.22.0 h1:J0UbZOIrCAl+fpTOf8YLs4dJo8L/owV4LYVtAXQoPkw= | ||||||
|  | google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= | ||||||
|  | google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM= | ||||||
|  | google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= | ||||||
|  | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 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/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/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 h1:5ofssLNYgAA/inWn6rTZ4juWpRJUwEnXc1LG2IeXwgQ= | ||||||
| gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= | gopkg.in/go-playground/validator.v9 v9.29.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= | ||||||
|  | gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= | ||||||
|  | gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= | ||||||
| gopkg.in/src-d/go-billy.v4 v4.2.1 h1:omN5CrMrMcQ+4I8bJ0wEhOBPanIRWzFC953IiXKdYzo= | gopkg.in/src-d/go-billy.v4 v4.2.1 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.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= | ||||||
|  | gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek= | ||||||
|  | gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= | ||||||
|  | gopkg.in/src-d/go-billy.v4 v4.3.1 h1:OkK1DmefDy1Z6Veu82wdNj/cLpYORhdX4qdaYCPwc7s= | ||||||
|  | gopkg.in/src-d/go-billy.v4 v4.3.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= | ||||||
|  | gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= | ||||||
|  | gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= | ||||||
| gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= | gopkg.in/src-d/go-git-fixtures.v3 v3.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 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.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= | ||||||
|  | gopkg.in/src-d/go-git.v4 v4.12.0 h1:CKgvBCJCcdfNnyXPYI4Cp8PaDDAmAPEN0CtfEdEAbd8= | ||||||
|  | gopkg.in/src-d/go-git.v4 v4.12.0/go.mod h1:zjlNnzc1Wjn43v3Mtii7RVxiReNP0fIu9npcXKzuNp4= | ||||||
|  | gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= | ||||||
|  | gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= | ||||||
| gopkg.in/telegram-bot-api.v4 v4.6.4 h1:hpHWhzn4jTCsAJZZ2loNKfy2QWyPDRJVl3aTFXeMW8g= | gopkg.in/telegram-bot-api.v4 v4.6.4 h1:hpHWhzn4jTCsAJZZ2loNKfy2QWyPDRJVl3aTFXeMW8g= | ||||||
| gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM= | 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= | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= | ||||||
| @@ -254,3 +544,9 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= | |||||||
| gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||||||
| gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= | 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-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-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||||||
|  | honnef.co/go/tools v0.0.0-20190614002413-cb51c254f01b/go.mod h1:JlmFZigtG9vBVR3QGIQ9g/Usz4BzH+Xm6Z8iHQWRYUw= | ||||||
|  | honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= | ||||||
|  | rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= | ||||||
|   | |||||||
							
								
								
									
										311
									
								
								monitor/default.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										311
									
								
								monitor/default.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,311 @@ | |||||||
|  | package monitor | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"context" | ||||||
|  | 	"errors" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/client" | ||||||
|  | 	pb "github.com/micro/go-micro/debug/proto" | ||||||
|  | 	"github.com/micro/go-micro/registry" | ||||||
|  | 	"github.com/micro/go-micro/registry/cache" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type monitor struct { | ||||||
|  | 	options Options | ||||||
|  |  | ||||||
|  | 	exit     chan bool | ||||||
|  | 	registry cache.Cache | ||||||
|  | 	client   client.Client | ||||||
|  |  | ||||||
|  | 	sync.RWMutex | ||||||
|  | 	running  bool | ||||||
|  | 	services map[string]*Status | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // check provides binary running/failed status. | ||||||
|  | // In the event Debug.Health cannot be called on a service we reap the node. | ||||||
|  | func (m *monitor) check(service string) (*Status, error) { | ||||||
|  | 	services, err := m.registry.GetService(service) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// create debug client | ||||||
|  | 	debug := pb.NewDebugService(service, m.client) | ||||||
|  |  | ||||||
|  | 	var status *Status | ||||||
|  | 	var gerr error | ||||||
|  |  | ||||||
|  | 	// iterate through multiple versions of a service | ||||||
|  | 	for _, service := range services { | ||||||
|  | 		for _, node := range service.Nodes { | ||||||
|  | 			rsp, err := debug.Health( | ||||||
|  | 				context.Background(), | ||||||
|  | 				// empty health request | ||||||
|  | 				&pb.HealthRequest{}, | ||||||
|  | 				// call this specific node | ||||||
|  | 				client.WithAddress(node.Address), | ||||||
|  | 				// retry in the event of failure | ||||||
|  | 				client.WithRetries(3), | ||||||
|  | 			) | ||||||
|  | 			if err != nil { | ||||||
|  | 				// reap the dead node | ||||||
|  | 				m.registry.Deregister(®istry.Service{ | ||||||
|  | 					Name:    service.Name, | ||||||
|  | 					Version: service.Version, | ||||||
|  | 					Nodes:   []*registry.Node{node}, | ||||||
|  | 				}) | ||||||
|  |  | ||||||
|  | 				// save the error | ||||||
|  | 				gerr = err | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// expecting ok response status | ||||||
|  | 			if rsp.Status != "ok" { | ||||||
|  | 				gerr = errors.New(rsp.Status) | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// no error set status | ||||||
|  | 			status = &Status{ | ||||||
|  | 				Code: StatusRunning, | ||||||
|  | 				Info: "running", | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// if we got the success case return it | ||||||
|  | 	if status != nil { | ||||||
|  | 		return status, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// if gerr is not nil return it | ||||||
|  | 	if gerr != nil { | ||||||
|  | 		return &Status{ | ||||||
|  | 			Code:  StatusFailed, | ||||||
|  | 			Info:  "not running", | ||||||
|  | 			Error: gerr.Error(), | ||||||
|  | 		}, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// otherwise unknown status | ||||||
|  | 	return &Status{ | ||||||
|  | 		Code: StatusUnknown, | ||||||
|  | 		Info: "unknown status", | ||||||
|  | 	}, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *monitor) reap() { | ||||||
|  | 	services, err := m.registry.ListServices() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	serviceMap := make(map[string]bool) | ||||||
|  | 	for _, service := range services { | ||||||
|  | 		serviceMap[service.Name] = true | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	m.Lock() | ||||||
|  | 	defer m.Unlock() | ||||||
|  |  | ||||||
|  | 	// range over our watched services | ||||||
|  | 	for service, _ := range m.services { | ||||||
|  | 		// check if the service exists in the registry | ||||||
|  | 		if !serviceMap[service] { | ||||||
|  | 			// if not, delete it in our status map | ||||||
|  | 			delete(m.services, service) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *monitor) run() { | ||||||
|  | 	// check the status every tick | ||||||
|  | 	t := time.NewTicker(time.Minute) | ||||||
|  | 	defer t.Stop() | ||||||
|  |  | ||||||
|  | 	// reap dead services | ||||||
|  | 	t2 := time.NewTicker(time.Hour) | ||||||
|  | 	defer t2.Stop() | ||||||
|  |  | ||||||
|  | 	// list the known services | ||||||
|  | 	services, _ := m.registry.ListServices() | ||||||
|  |  | ||||||
|  | 	// create a check chan of same length | ||||||
|  | 	check := make(chan string, len(services)) | ||||||
|  |  | ||||||
|  | 	// front-load the services to watch | ||||||
|  | 	for _, service := range services { | ||||||
|  | 		check <- service.Name | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		select { | ||||||
|  | 		// exit if we're told to | ||||||
|  | 		case <-m.exit: | ||||||
|  | 			return | ||||||
|  | 		// check a service when told to | ||||||
|  | 		case service := <-check: | ||||||
|  | 			// check the status | ||||||
|  | 			status, err := m.check(service) | ||||||
|  | 			if err != nil { | ||||||
|  | 				status = &Status{ | ||||||
|  | 					Code: StatusUnknown, | ||||||
|  | 					Info: "unknown status", | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// save the status | ||||||
|  | 			m.Lock() | ||||||
|  | 			m.services[service] = status | ||||||
|  | 			m.Unlock() | ||||||
|  | 		// on the tick interval get all services and issue a check | ||||||
|  | 		case <-t.C: | ||||||
|  | 			// create a list of services | ||||||
|  | 			serviceMap := make(map[string]bool) | ||||||
|  |  | ||||||
|  | 			m.RLock() | ||||||
|  | 			for service, _ := range m.services { | ||||||
|  | 				serviceMap[service] = true | ||||||
|  | 			} | ||||||
|  | 			m.RUnlock() | ||||||
|  |  | ||||||
|  | 			go func() { | ||||||
|  | 				// check the status of all watched services | ||||||
|  | 				for service, _ := range serviceMap { | ||||||
|  | 					select { | ||||||
|  | 					case <-m.exit: | ||||||
|  | 						return | ||||||
|  | 					case check <- service: | ||||||
|  | 					default: | ||||||
|  | 						// barf if we block | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				// list services | ||||||
|  | 				services, _ := m.registry.ListServices() | ||||||
|  |  | ||||||
|  | 				for _, service := range services { | ||||||
|  | 					// start watching the service | ||||||
|  | 					if ok := serviceMap[service.Name]; !ok { | ||||||
|  | 						m.Watch(service.Name) | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}() | ||||||
|  | 		case <-t2.C: | ||||||
|  | 			// reap any dead/non-existent services | ||||||
|  | 			m.reap() | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *monitor) Reap(service string) error { | ||||||
|  | 	services, err := m.registry.GetService(service) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	m.Lock() | ||||||
|  | 	defer m.Unlock() | ||||||
|  | 	delete(m.services, service) | ||||||
|  | 	for _, service := range services { | ||||||
|  | 		m.registry.Deregister(service) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *monitor) Status(service string) (Status, error) { | ||||||
|  | 	m.RLock() | ||||||
|  | 	defer m.RUnlock() | ||||||
|  | 	if status, ok := m.services[service]; ok { | ||||||
|  | 		return *status, nil | ||||||
|  | 	} | ||||||
|  | 	return Status{}, ErrNotWatching | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *monitor) Watch(service string) error { | ||||||
|  | 	m.Lock() | ||||||
|  | 	defer m.Unlock() | ||||||
|  |  | ||||||
|  | 	// check if we're watching | ||||||
|  | 	if _, ok := m.services[service]; ok { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// get the status | ||||||
|  | 	status, err := m.check(service) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// set the status | ||||||
|  | 	m.services[service] = status | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *monitor) Run() error { | ||||||
|  | 	m.Lock() | ||||||
|  | 	defer m.Unlock() | ||||||
|  |  | ||||||
|  | 	if m.running { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// reset the exit channel | ||||||
|  | 	m.exit = make(chan bool) | ||||||
|  | 	// setup a new cache | ||||||
|  | 	m.registry = cache.New(m.options.Registry) | ||||||
|  |  | ||||||
|  | 	// start running | ||||||
|  | 	go m.run() | ||||||
|  |  | ||||||
|  | 	// set to running | ||||||
|  | 	m.running = true | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (m *monitor) Stop() error { | ||||||
|  | 	m.Lock() | ||||||
|  | 	defer m.Unlock() | ||||||
|  |  | ||||||
|  | 	if !m.running { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	select { | ||||||
|  | 	case <-m.exit: | ||||||
|  | 		return nil | ||||||
|  | 	default: | ||||||
|  | 		close(m.exit) | ||||||
|  | 		for s, _ := range m.services { | ||||||
|  | 			delete(m.services, s) | ||||||
|  | 		} | ||||||
|  | 		m.registry.Stop() | ||||||
|  | 		m.running = false | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newMonitor(opts ...Option) Monitor { | ||||||
|  | 	options := Options{ | ||||||
|  | 		Client:   client.DefaultClient, | ||||||
|  | 		Registry: registry.DefaultRegistry, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	for _, o := range opts { | ||||||
|  | 		o(&options) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return &monitor{ | ||||||
|  | 		options:  options, | ||||||
|  | 		exit:     make(chan bool), | ||||||
|  | 		client:   options.Client, | ||||||
|  | 		registry: cache.New(options.Registry), | ||||||
|  | 		services: make(map[string]*Status), | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								monitor/default_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								monitor/default_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | package monitor | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func TestMonitor(t *testing.T) { | ||||||
|  | 	// create new monitor | ||||||
|  | 	m := NewMonitor() | ||||||
|  |  | ||||||
|  | 	if err := m.Run(); err != nil { | ||||||
|  | 		t.Fatalf("failed to stop monitor: %v", err) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	services := []string{"foo", "bar", "baz"} | ||||||
|  |  | ||||||
|  | 	for _, service := range services { | ||||||
|  | 		_, err := m.Status(service) | ||||||
|  | 		if err == nil { | ||||||
|  | 			t.Fatal("expected status error for unknown service") | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if err := m.Watch(service); err == nil { | ||||||
|  | 			t.Fatal("expected watch error for unknown service") | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// TODO: | ||||||
|  | 		// 1. start a service | ||||||
|  | 		// 2. watch service | ||||||
|  | 		// 3. get service status | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// stop monitor | ||||||
|  | 	if err := m.Stop(); err != nil { | ||||||
|  | 		t.Fatalf("failed to stop monitor: %v", err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								monitor/monitor.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								monitor/monitor.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | // Package monitor monitors service health | ||||||
|  | package monitor | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	StatusUnknown StatusCode = iota | ||||||
|  | 	StatusRunning | ||||||
|  | 	StatusFailed | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type StatusCode int | ||||||
|  |  | ||||||
|  | // Monitor monitors a service and reaps dead instances | ||||||
|  | type Monitor interface { | ||||||
|  | 	// Reap a service and stop monitoring | ||||||
|  | 	Reap(service string) error | ||||||
|  | 	// Status of the service | ||||||
|  | 	Status(service string) (Status, error) | ||||||
|  | 	// Watch starts watching the service | ||||||
|  | 	Watch(service string) error | ||||||
|  | 	// Run the monitor to watch all services | ||||||
|  | 	Run() error | ||||||
|  | 	// Stop monitoring | ||||||
|  | 	Stop() error | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type Status struct { | ||||||
|  | 	Code  StatusCode | ||||||
|  | 	Info  string | ||||||
|  | 	Error string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	ErrNotWatching = errors.New("not watching") | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // NewMonitor returns a new monitor | ||||||
|  | func NewMonitor(opts ...Option) Monitor { | ||||||
|  | 	return newMonitor(opts...) | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								monitor/options.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								monitor/options.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | package monitor | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"github.com/micro/go-micro/client" | ||||||
|  | 	"github.com/micro/go-micro/registry" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Options struct { | ||||||
|  | 	Client   client.Client | ||||||
|  | 	Registry registry.Registry | ||||||
|  | } | ||||||
|  |  | ||||||
|  | type Option func(*Options) | ||||||
|  |  | ||||||
|  | func Client(c client.Client) Option { | ||||||
|  | 	return func(o *Options) { | ||||||
|  | 		o.Client = c | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func Registry(r registry.Registry) Option { | ||||||
|  | 	return func(o *Options) { | ||||||
|  | 		o.Registry = r | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										288
									
								
								network/link/default.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								network/link/default.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,288 @@ | |||||||
|  | // Package link provides a measured transport.Socket link | ||||||
|  | package link | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"io" | ||||||
|  | 	"sync" | ||||||
|  | 	"time" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/config/options" | ||||||
|  | 	"github.com/micro/go-micro/transport" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type link struct { | ||||||
|  | 	sync.RWMutex | ||||||
|  |  | ||||||
|  | 	// the link id | ||||||
|  | 	id string | ||||||
|  |  | ||||||
|  | 	// the remote end to dial | ||||||
|  | 	addr string | ||||||
|  |  | ||||||
|  | 	// channel used to close the link | ||||||
|  | 	closed chan bool | ||||||
|  |  | ||||||
|  | 	// if its connected | ||||||
|  | 	connected bool | ||||||
|  |  | ||||||
|  | 	// the transport to use | ||||||
|  | 	transport transport.Transport | ||||||
|  |  | ||||||
|  | 	// the send queue to the socket | ||||||
|  | 	sendQueue chan *transport.Message | ||||||
|  | 	// the recv queue to the socket | ||||||
|  | 	recvQueue chan *transport.Message | ||||||
|  |  | ||||||
|  | 	// the socket for this link | ||||||
|  | 	socket transport.Socket | ||||||
|  |  | ||||||
|  | 	// determines the cost of the link | ||||||
|  | 	// based on queue length and roundtrip | ||||||
|  | 	length int | ||||||
|  | 	weight int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func newLink(options options.Options) *link { | ||||||
|  | 	// default values | ||||||
|  | 	var sock transport.Socket | ||||||
|  | 	var addr string | ||||||
|  | 	id := "local" | ||||||
|  | 	tr := transport.DefaultTransport | ||||||
|  |  | ||||||
|  | 	lid, ok := options.Values().Get("link.id") | ||||||
|  | 	if ok { | ||||||
|  | 		id = lid.(string) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	laddr, ok := options.Values().Get("link.address") | ||||||
|  | 	if ok { | ||||||
|  | 		addr = laddr.(string) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ltr, ok := options.Values().Get("link.transport") | ||||||
|  | 	if ok { | ||||||
|  | 		tr = ltr.(transport.Transport) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	lsock, ok := options.Values().Get("link.socket") | ||||||
|  | 	if ok { | ||||||
|  | 		sock = lsock.(transport.Socket) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	l := &link{ | ||||||
|  | 		// the remote end to dial | ||||||
|  | 		addr: addr, | ||||||
|  | 		// transport to dial link | ||||||
|  | 		transport: tr, | ||||||
|  | 		// the socket to use | ||||||
|  | 		// this is nil if not specified | ||||||
|  | 		socket: sock, | ||||||
|  | 		// unique id assigned to the link | ||||||
|  | 		id: id, | ||||||
|  | 		// the closed channel used to close the conn | ||||||
|  | 		closed: make(chan bool), | ||||||
|  | 		// then send queue | ||||||
|  | 		sendQueue: make(chan *transport.Message, 128), | ||||||
|  | 		// the receive queue | ||||||
|  | 		recvQueue: make(chan *transport.Message, 128), | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// return the link | ||||||
|  | 	return l | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // link methods | ||||||
|  |  | ||||||
|  | // process processes messages on the send and receive queues. | ||||||
|  | func (l *link) process() { | ||||||
|  | 	go func() { | ||||||
|  | 		for { | ||||||
|  | 			m := new(transport.Message) | ||||||
|  | 			if err := l.recv(m); err != nil { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			select { | ||||||
|  | 			case l.recvQueue <- m: | ||||||
|  | 			case <-l.closed: | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  |  | ||||||
|  | 	// messages sent | ||||||
|  | 	i := 0 | ||||||
|  | 	length := 0 | ||||||
|  |  | ||||||
|  | 	for { | ||||||
|  | 		select { | ||||||
|  | 		case m := <-l.sendQueue: | ||||||
|  | 			t := time.Now() | ||||||
|  |  | ||||||
|  | 			// send the message | ||||||
|  | 			if err := l.send(m); err != nil { | ||||||
|  | 				return | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// get header size, body size and time taken | ||||||
|  | 			hl := len(m.Header) | ||||||
|  | 			bl := len(m.Body) | ||||||
|  | 			d := time.Since(t) | ||||||
|  |  | ||||||
|  | 			// don't calculate on empty messages | ||||||
|  | 			if hl == 0 && bl == 0 { | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// increment sent | ||||||
|  | 			i++ | ||||||
|  |  | ||||||
|  | 			// time take to send some bits and bytes | ||||||
|  | 			td := float64(hl+bl) / float64(d.Nanoseconds()) | ||||||
|  | 			// increase the scale | ||||||
|  | 			td += 1 | ||||||
|  |  | ||||||
|  | 			// judge the length | ||||||
|  | 			length = int(td) / (length + int(td)) | ||||||
|  |  | ||||||
|  | 			// every 10 messages update length | ||||||
|  | 			if (i % 10) == 1 { | ||||||
|  | 				// cost average the length | ||||||
|  | 				// save it | ||||||
|  | 				l.Lock() | ||||||
|  | 				l.length = length | ||||||
|  | 				l.Unlock() | ||||||
|  | 			} | ||||||
|  | 		case <-l.closed: | ||||||
|  | 			return | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // send a message over the link | ||||||
|  | func (l *link) send(m *transport.Message) error { | ||||||
|  | 	// TODO: measure time taken and calculate length/rate | ||||||
|  | 	// send via the transport socket | ||||||
|  | 	return l.socket.Send(m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // recv a message on the link | ||||||
|  | func (l *link) recv(m *transport.Message) error { | ||||||
|  | 	if m.Header == nil { | ||||||
|  | 		m.Header = make(map[string]string) | ||||||
|  | 	} | ||||||
|  | 	// receive the transport message | ||||||
|  | 	return l.socket.Recv(m) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Connect attempts to connect to an address and sets the socket | ||||||
|  | func (l *link) Connect() error { | ||||||
|  | 	l.Lock() | ||||||
|  | 	if l.connected { | ||||||
|  | 		l.Unlock() | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	defer l.Unlock() | ||||||
|  |  | ||||||
|  | 	// replace closed | ||||||
|  | 	l.closed = make(chan bool) | ||||||
|  |  | ||||||
|  | 	// assume existing socket | ||||||
|  | 	if len(l.addr) == 0 { | ||||||
|  | 		go l.process() | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// dial the endpoint | ||||||
|  | 	c, err := l.transport.Dial(l.addr) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// set the socket | ||||||
|  | 	l.socket = c | ||||||
|  |  | ||||||
|  | 	// kick start the processing | ||||||
|  | 	go l.process() | ||||||
|  |  | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Close the link | ||||||
|  | func (l *link) Close() error { | ||||||
|  | 	select { | ||||||
|  | 	case <-l.closed: | ||||||
|  | 		return nil | ||||||
|  | 	default: | ||||||
|  | 		close(l.closed) | ||||||
|  | 		l.Lock() | ||||||
|  | 		l.connected = false | ||||||
|  | 		l.Unlock() | ||||||
|  | 		return l.socket.Close() | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // returns the node id | ||||||
|  | func (l *link) Id() string { | ||||||
|  | 	l.RLock() | ||||||
|  | 	defer l.RUnlock() | ||||||
|  | 	return l.id | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // the remote ip of the link | ||||||
|  | func (l *link) Remote() string { | ||||||
|  | 	l.RLock() | ||||||
|  | 	defer l.RUnlock() | ||||||
|  | 	return l.socket.Remote() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // the local ip of the link | ||||||
|  | func (l *link) Local() string { | ||||||
|  | 	l.RLock() | ||||||
|  | 	defer l.RUnlock() | ||||||
|  | 	return l.socket.Local() | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // length/rate of the link | ||||||
|  | func (l *link) Length() int { | ||||||
|  | 	l.RLock() | ||||||
|  | 	defer l.RUnlock() | ||||||
|  | 	return l.length | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // weight checks the size of the queues | ||||||
|  | func (l *link) Weight() int { | ||||||
|  | 	return len(l.sendQueue) + len(l.recvQueue) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Accept accepts a message on the socket | ||||||
|  | func (l *link) Recv(m *transport.Message) error { | ||||||
|  | 	select { | ||||||
|  | 	case <-l.closed: | ||||||
|  | 		return io.EOF | ||||||
|  | 	case rm := <-l.recvQueue: | ||||||
|  | 		*m = *rm | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 	// never reach | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Send sends a message on the socket immediately | ||||||
|  | func (l *link) Send(m *transport.Message) error { | ||||||
|  | 	select { | ||||||
|  | 	case <-l.closed: | ||||||
|  | 		return io.EOF | ||||||
|  | 	case l.sendQueue <- m: | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func (l *link) Status() string { | ||||||
|  | 	select { | ||||||
|  | 	case <-l.closed: | ||||||
|  | 		return "closed" | ||||||
|  | 	default: | ||||||
|  | 		return "connected" | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										60
									
								
								network/link/link.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								network/link/link.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | // Package link provides a measured link on top of a transport.Socket | ||||||
|  | package link | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/config/options" | ||||||
|  | 	"github.com/micro/go-micro/transport" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // Link is a layer on top of a transport socket with the | ||||||
|  | // buffering send and recv queue's with the ability to | ||||||
|  | // measure the actual transport link and reconnect if | ||||||
|  | // an address is specified. | ||||||
|  | type Link interface { | ||||||
|  | 	// provides the transport.Socket interface | ||||||
|  | 	transport.Socket | ||||||
|  | 	// Connect connects the link. It must be called first | ||||||
|  | 	// if there's an expectation to create a new socket. | ||||||
|  | 	Connect() error | ||||||
|  | 	// Id of the link is "local" if not specified | ||||||
|  | 	Id() string | ||||||
|  | 	// Status of the link | ||||||
|  | 	Status() string | ||||||
|  | 	// Depth of the buffers | ||||||
|  | 	Weight() int | ||||||
|  | 	// Rate of the link | ||||||
|  | 	Length() int | ||||||
|  | } | ||||||
|  |  | ||||||
|  | var ( | ||||||
|  | 	ErrLinkClosed = errors.New("link closed") | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // NewLink creates a new link on top of a socket | ||||||
|  | func NewLink(opts ...options.Option) Link { | ||||||
|  | 	return newLink(options.NewOptions(opts...)) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Sets the link id which otherwise defaults to "local" | ||||||
|  | func Id(id string) options.Option { | ||||||
|  | 	return options.WithValue("link.id", id) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // The address to use for the link. Connect must be | ||||||
|  | // called for this to be used, its otherwise unused. | ||||||
|  | func Address(a string) options.Option { | ||||||
|  | 	return options.WithValue("link.address", a) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // The transport to use for the link where we | ||||||
|  | // want to dial the connection first. | ||||||
|  | func Transport(t transport.Transport) options.Option { | ||||||
|  | 	return options.WithValue("link.transport", t) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Socket sets the socket to use instead of dialing. | ||||||
|  | func Socket(s transport.Socket) options.Option { | ||||||
|  | 	return options.WithValue("link.socket", s) | ||||||
|  | } | ||||||
| @@ -1,45 +1,2 @@ | |||||||
| // Package network is an interface for defining a network overlay | // Package network is for creating internetworks | ||||||
| package network | package network | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"github.com/micro/go-micro/config/options" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type Network interface { |  | ||||||
| 	options.Options |  | ||||||
| 	// Id of this network |  | ||||||
| 	Id() string |  | ||||||
| 	// Connect to the network with id |  | ||||||
| 	Connect(id string) error |  | ||||||
| 	// Close the network connection |  | ||||||
| 	Close() error |  | ||||||
| 	// Accept messages |  | ||||||
| 	Accept() (*Message, error) |  | ||||||
| 	// Send a message |  | ||||||
| 	Send(*Message) error |  | ||||||
| 	// Advertise a service on this network |  | ||||||
| 	Advertise(service string) error |  | ||||||
| 	// Retrieve list of nodes for a service |  | ||||||
| 	Nodes(service string) ([]Node, error) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Node represents a network node |  | ||||||
| type Node interface { |  | ||||||
| 	// Node is a network. Network is a node. |  | ||||||
| 	Network |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Message is a message sent over the network |  | ||||||
| type Message struct { |  | ||||||
| 	// Headers are the routing headers |  | ||||||
| 	// e.g Micro-Service, Micro-Endpoint, Micro-Network |  | ||||||
| 	// see https://github.com/micro/development/blob/master/protocol.md |  | ||||||
| 	Header map[string]string |  | ||||||
| 	// Body is the encaspulated payload |  | ||||||
| 	Body []byte |  | ||||||
| } |  | ||||||
|  |  | ||||||
| var ( |  | ||||||
| 	// TODO: set default network |  | ||||||
| 	DefaultNetwork Network |  | ||||||
| ) |  | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								network/resolver/dns/dns.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								network/resolver/dns/dns.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | // Package dns resolves names to dns srv records | ||||||
|  | package dns | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"net" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/network/resolver" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Resolver struct{} | ||||||
|  |  | ||||||
|  | // Resolve assumes ID is a domain name e.g micro.mu | ||||||
|  | func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) { | ||||||
|  | 	_, addrs, err := net.LookupSRV("network", "udp", name) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	var records []*resolver.Record | ||||||
|  | 	for _, addr := range addrs { | ||||||
|  | 		address := addr.Target | ||||||
|  | 		if addr.Port > 0 { | ||||||
|  | 			address = fmt.Sprintf("%s:%d", addr.Target, addr.Port) | ||||||
|  | 		} | ||||||
|  | 		records = append(records, &resolver.Record{ | ||||||
|  | 			Address: address, | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 	return records, nil | ||||||
|  | } | ||||||
							
								
								
									
										59
									
								
								network/resolver/http/http.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								network/resolver/http/http.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | // Package http resolves names to network addresses using a http request | ||||||
|  | package http | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"encoding/json" | ||||||
|  | 	"io/ioutil" | ||||||
|  | 	"net/http" | ||||||
|  | 	"net/url" | ||||||
|  |  | ||||||
|  | 	"github.com/micro/go-micro/network/resolver" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Resolver struct { | ||||||
|  | 	// If not set, defaults to http | ||||||
|  | 	Proto string | ||||||
|  |  | ||||||
|  | 	// Path sets the path to lookup. Defaults to /network | ||||||
|  | 	Path string | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Resolve assumes ID is a domain which can be converted to a http://name/network request | ||||||
|  | func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) { | ||||||
|  | 	proto := "http" | ||||||
|  | 	path := "/network" | ||||||
|  |  | ||||||
|  | 	if len(r.Proto) > 0 { | ||||||
|  | 		proto = r.Proto | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if len(r.Path) > 0 { | ||||||
|  | 		path = r.Path | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	uri := &url.URL{ | ||||||
|  | 		Scheme: proto, | ||||||
|  | 		Path:   path, | ||||||
|  | 		Host:   name, | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	rsp, err := http.Get(uri.String()) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	defer rsp.Body.Close() | ||||||
|  |  | ||||||
|  | 	b, err := ioutil.ReadAll(rsp.Body) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// encoding format is assumed to be json | ||||||
|  | 	var records []*resolver.Record | ||||||
|  |  | ||||||
|  | 	if err := json.Unmarshal(b, &records); err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return records, nil | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								network/resolver/registry/registry.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								network/resolver/registry/registry.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | // Package registry resolves names using the go-micro registry | ||||||
|  | package registry | ||||||
|  |  | ||||||
|  | import ( | ||||||
|  | 	"github.com/micro/go-micro/network/resolver" | ||||||
|  | 	"github.com/micro/go-micro/registry" | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | type Resolver struct { | ||||||
|  | 	// Registry is the registry to use otherwise we use the defaul | ||||||
|  | 	Registry registry.Registry | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Resolve assumes ID is a domain name e.g micro.mu | ||||||
|  | func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) { | ||||||
|  | 	reg := r.Registry | ||||||
|  | 	if reg == nil { | ||||||
|  | 		reg = registry.DefaultRegistry | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	services, err := reg.GetService(name) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	var records []*resolver.Record | ||||||
|  |  | ||||||
|  | 	for _, service := range services { | ||||||
|  | 		for _, node := range service.Nodes { | ||||||
|  | 			records = append(records, &resolver.Record{ | ||||||
|  | 				Address: node.Address, | ||||||
|  | 			}) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return records, nil | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								network/resolver/resolver.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								network/resolver/resolver.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | // Package resolver resolves network names to addresses | ||||||
|  | package resolver | ||||||
|  |  | ||||||
|  | // Resolver is network resolver. It's used to find network nodes | ||||||
|  | // via the name to connect to. This is done based on Network.Name(). | ||||||
|  | // Before we can be part of any network, we have to connect to it. | ||||||
|  | type Resolver interface { | ||||||
|  | 	// Resolve returns a list of addresses for an name | ||||||
|  | 	Resolve(name string) ([]*Record, error) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // A resolved record | ||||||
|  | type Record struct { | ||||||
|  | 	Address string `json:"address"` | ||||||
|  | } | ||||||
| @@ -1,203 +0,0 @@ | |||||||
| // Package transport implements the network as a transport interface |  | ||||||
| package transport |  | ||||||
|  |  | ||||||
| import ( |  | ||||||
| 	"context" |  | ||||||
| 	"time" |  | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/network" |  | ||||||
| 	"github.com/micro/go-micro/transport" |  | ||||||
| 	"github.com/micro/go-micro/util/backoff" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| type networkKey struct{} |  | ||||||
|  |  | ||||||
| // Transport is a network transport |  | ||||||
| type Transport struct { |  | ||||||
| 	Network network.Network |  | ||||||
| 	options transport.Options |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Socket is a transport socket |  | ||||||
| type Socket struct { |  | ||||||
| 	// The service |  | ||||||
| 	Service string |  | ||||||
|  |  | ||||||
| 	// Send via Network.Send(Message) |  | ||||||
| 	Network network.Network |  | ||||||
|  |  | ||||||
| 	// Remote/Local |  | ||||||
| 	remote, local string |  | ||||||
|  |  | ||||||
| 	// the first message if its a listener |  | ||||||
| 	message *network.Message |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Listener is a transport listener |  | ||||||
| type Listener struct { |  | ||||||
| 	// The local service |  | ||||||
| 	Service string |  | ||||||
|  |  | ||||||
| 	// The network |  | ||||||
| 	Network network.Network |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Socket) Local() string { |  | ||||||
| 	return s.local |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Socket) Remote() string { |  | ||||||
| 	return s.remote |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Socket) Close() error { |  | ||||||
| 	// TODO: should it close the network? |  | ||||||
| 	return s.Network.Close() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (t *Transport) Init(opts ...transport.Option) error { |  | ||||||
| 	for _, o := range opts { |  | ||||||
| 		o(&t.options) |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (t *Transport) Options() transport.Options { |  | ||||||
| 	return t.options |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (t *Transport) Dial(service string, opts ...transport.DialOption) (transport.Client, error) { |  | ||||||
| 	// TODO: establish pseudo socket? |  | ||||||
| 	return &Socket{ |  | ||||||
| 		Service: service, |  | ||||||
| 		Network: t.Network, |  | ||||||
| 		remote:  service, |  | ||||||
| 		// TODO: local |  | ||||||
| 		local: "local", |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (t *Transport) Listen(service string, opts ...transport.ListenOption) (transport.Listener, error) { |  | ||||||
| 	// TODO specify connect id |  | ||||||
| 	if err := t.Network.Connect("micro.mu"); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// advertise the service |  | ||||||
| 	if err := t.Network.Advertise(service); err != nil { |  | ||||||
| 		return nil, err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return &Listener{ |  | ||||||
| 		Service: service, |  | ||||||
| 		Network: t.Network, |  | ||||||
| 	}, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (t *Transport) String() string { |  | ||||||
| 	return "network" |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Socket) Send(msg *transport.Message) error { |  | ||||||
| 	// TODO: set routing headers? |  | ||||||
| 	return s.Network.Send(&network.Message{ |  | ||||||
| 		Header: msg.Header, |  | ||||||
| 		Body:   msg.Body, |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (s *Socket) Recv(msg *transport.Message) error { |  | ||||||
| 	if msg == nil { |  | ||||||
| 		msg = new(transport.Message) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	// return first message |  | ||||||
| 	if s.message != nil { |  | ||||||
| 		msg.Header = s.message.Header |  | ||||||
| 		msg.Body = s.message.Body |  | ||||||
| 		s.message = nil |  | ||||||
| 		return nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	m, err := s.Network.Accept() |  | ||||||
| 	if err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	msg.Header = m.Header |  | ||||||
| 	msg.Body = m.Body |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (l *Listener) Addr() string { |  | ||||||
| 	return l.Service |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (l *Listener) Close() error { |  | ||||||
| 	return l.Network.Close() |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (l *Listener) Accept(fn func(transport.Socket)) error { |  | ||||||
| 	var i int |  | ||||||
|  |  | ||||||
| 	for { |  | ||||||
| 		msg, err := l.Network.Accept() |  | ||||||
| 		if err != nil { |  | ||||||
| 			// increment error counter |  | ||||||
| 			i++ |  | ||||||
|  |  | ||||||
| 			// break if lots of error |  | ||||||
| 			if i > 3 { |  | ||||||
| 				return err |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			// otherwise continue |  | ||||||
| 			time.Sleep(backoff.Do(i)) |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		// reset |  | ||||||
| 		i = 0 |  | ||||||
|  |  | ||||||
| 		// execute in go routine |  | ||||||
| 		go fn(&Socket{ |  | ||||||
| 			Service: l.Service, |  | ||||||
| 			Network: l.Network, |  | ||||||
| 			local:   l.Service, |  | ||||||
| 			// TODO: remote |  | ||||||
| 			remote:  "remote", |  | ||||||
| 			message: msg, |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // NewTransport returns a new network transport. It assumes the network is already connected |  | ||||||
| func NewTransport(opts ...transport.Option) transport.Transport { |  | ||||||
| 	options := transport.Options{ |  | ||||||
| 		Context: context.Background(), |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	for _, o := range opts { |  | ||||||
| 		o(&options) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	net, ok := options.Context.Value(networkKey{}).(network.Network) |  | ||||||
| 	if !ok { |  | ||||||
| 		net = network.DefaultNetwork |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return &Transport{ |  | ||||||
| 		options: options, |  | ||||||
| 		Network: net, |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // WithNetwork passes in the network |  | ||||||
| func WithNetwork(n network.Network) transport.Option { |  | ||||||
| 	return func(o *transport.Options) { |  | ||||||
| 		if o.Context == nil { |  | ||||||
| 			o.Context = context.Background() |  | ||||||
| 		} |  | ||||||
| 		o.Context = context.WithValue(o.Context, networkKey{}, n) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @@ -7,9 +7,9 @@ import ( | |||||||
| 	"github.com/micro/cli" | 	"github.com/micro/cli" | ||||||
| 	"github.com/micro/go-micro/broker" | 	"github.com/micro/go-micro/broker" | ||||||
| 	"github.com/micro/go-micro/client" | 	"github.com/micro/go-micro/client" | ||||||
| 	"github.com/micro/go-micro/cmd" | 	"github.com/micro/go-micro/client/selector" | ||||||
|  | 	"github.com/micro/go-micro/config/cmd" | ||||||
| 	"github.com/micro/go-micro/registry" | 	"github.com/micro/go-micro/registry" | ||||||
| 	"github.com/micro/go-micro/selector" |  | ||||||
| 	"github.com/micro/go-micro/server" | 	"github.com/micro/go-micro/server" | ||||||
| 	"github.com/micro/go-micro/transport" | 	"github.com/micro/go-micro/transport" | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -1,25 +0,0 @@ | |||||||
| # Go Proxy [](https://opensource.org/licenses/Apache-2.0) [](https://godoc.org/github.com/micro/go-proxy) |  | ||||||
|  |  | ||||||
| Go Proxy is a proxy library for Go Micro. |  | ||||||
|  |  | ||||||
| ## Overview |  | ||||||
|  |  | ||||||
| Go Micro is a distributed systems framework for client/server communication. It handles the details  |  | ||||||
| around discovery, fault tolerance, rpc communication, etc. We may want to leverage this in broader ecosystems  |  | ||||||
| which make use of standard http or we may also want to offload a number of requirements to a single proxy. |  | ||||||
|  |  | ||||||
| ## Features |  | ||||||
|  |  | ||||||
| - **Transparent Proxy** - Proxy requests to any micro services through a single location. Go Proxy enables  |  | ||||||
| you to write Go Micro proxies which handle and forward requests. This is good for incorporating wrappers. |  | ||||||
|  |  | ||||||
| - **Single Backend Router** - Enable the single backend router to proxy directly to your local app. The proxy  |  | ||||||
| allows you to set a router which serves your backend service whether its http, grpc, etc. |  | ||||||
|  |  | ||||||
| - **Protocol Aware Handler** - Set a request handler which speaks your app protocol to make outbound requests.  |  | ||||||
| Your app may not speak the MUCP protocol so it may be easier to translate internally. |  | ||||||
|  |  | ||||||
| - **Control Planes** - Additionally we support use of control planes to offload many distributed systems concerns. |  | ||||||
|   * [x] [Consul](https://www.consul.io/docs/connect/native.html) - Using Connect-Native to provide secure mTLS. |  | ||||||
|   * [x] [NATS](https://nats.io/) - Fully leveraging NATS as the control plane and data plane. |  | ||||||
|  |  | ||||||
| @@ -9,7 +9,6 @@ import ( | |||||||
| 	"github.com/micro/go-micro/client" | 	"github.com/micro/go-micro/client" | ||||||
| 	"github.com/micro/go-micro/client/grpc" | 	"github.com/micro/go-micro/client/grpc" | ||||||
| 	"github.com/micro/go-micro/codec" | 	"github.com/micro/go-micro/codec" | ||||||
| 	"github.com/micro/go-micro/codec/bytes" |  | ||||||
| 	"github.com/micro/go-micro/config/options" | 	"github.com/micro/go-micro/config/options" | ||||||
| 	"github.com/micro/go-micro/proxy" | 	"github.com/micro/go-micro/proxy" | ||||||
| 	"github.com/micro/go-micro/server" | 	"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 | 	// 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 | 	// create new stream | ||||||
| 	stream, err := p.Client.Stream(ctx, creq, opts...) | 	stream, err := p.Client.Stream(ctx, creq, opts...) | ||||||
|   | |||||||
| @@ -10,8 +10,8 @@ import ( | |||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"path" | 	"path" | ||||||
|  |  | ||||||
| 	"github.com/micro/go-micro/errors" |  | ||||||
| 	"github.com/micro/go-micro/config/options" | 	"github.com/micro/go-micro/config/options" | ||||||
|  | 	"github.com/micro/go-micro/errors" | ||||||
| 	"github.com/micro/go-micro/proxy" | 	"github.com/micro/go-micro/proxy" | ||||||
| 	"github.com/micro/go-micro/server" | 	"github.com/micro/go-micro/server" | ||||||
| ) | ) | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user