many lint fixes and optimizations #17
@ -1,121 +0,0 @@
|
|||||||
// Package api provides an http-rpc handler which provides the entire http request over rpc
|
|
||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
goapi "github.com/unistack-org/micro/v3/api"
|
|
||||||
"github.com/unistack-org/micro/v3/api/handler"
|
|
||||||
api "github.com/unistack-org/micro/v3/api/proto"
|
|
||||||
"github.com/unistack-org/micro/v3/client"
|
|
||||||
"github.com/unistack-org/micro/v3/errors"
|
|
||||||
"github.com/unistack-org/micro/v3/util/ctx"
|
|
||||||
"github.com/unistack-org/micro/v3/util/router"
|
|
||||||
)
|
|
||||||
|
|
||||||
type apiHandler struct {
|
|
||||||
opts handler.Options
|
|
||||||
s *goapi.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
Handler = "api"
|
|
||||||
)
|
|
||||||
|
|
||||||
// API handler is the default handler which takes api.Request and returns api.Response
|
|
||||||
func (a *apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
bsize := handler.DefaultMaxRecvSize
|
|
||||||
if a.opts.MaxRecvSize > 0 {
|
|
||||||
bsize = a.opts.MaxRecvSize
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Body = http.MaxBytesReader(w, r.Body, bsize)
|
|
||||||
request, err := requestToProto(r)
|
|
||||||
if err != nil {
|
|
||||||
er := errors.InternalServerError("go.micro.api", err.Error())
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(500)
|
|
||||||
w.Write([]byte(er.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var service *goapi.Service
|
|
||||||
|
|
||||||
if a.s != nil {
|
|
||||||
// we were given the service
|
|
||||||
service = a.s
|
|
||||||
} else if a.opts.Router != nil {
|
|
||||||
// try get service from router
|
|
||||||
s, err := a.opts.Router.Route(r)
|
|
||||||
if err != nil {
|
|
||||||
er := errors.InternalServerError("go.micro.api", err.Error())
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(500)
|
|
||||||
w.Write([]byte(er.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
service = s
|
|
||||||
} else {
|
|
||||||
// we have no way of routing the request
|
|
||||||
er := errors.InternalServerError("go.micro.api", "no route found")
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
w.WriteHeader(500)
|
|
||||||
w.Write([]byte(er.Error()))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// create request and response
|
|
||||||
c := a.opts.Client
|
|
||||||
req := c.NewRequest(service.Name, service.Endpoint.Name, request)
|
|
||||||
rsp := &api.Response{}
|
|
||||||
|
|
||||||
// create the context from headers
|
|
||||||
cx := ctx.FromRequest(r)
|
|
||||||
|
|
||||||
if err := c.Call(cx, req, rsp, client.WithRouter(router.New(service.Services))); err != nil {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
ce := errors.Parse(err.Error())
|
|
||||||
switch ce.Code {
|
|
||||||
case 0:
|
|
||||||
w.WriteHeader(500)
|
|
||||||
default:
|
|
||||||
w.WriteHeader(int(ce.Code))
|
|
||||||
}
|
|
||||||
w.Write([]byte(ce.Error()))
|
|
||||||
return
|
|
||||||
} else if rsp.StatusCode == 0 {
|
|
||||||
rsp.StatusCode = http.StatusOK
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, header := range rsp.GetHeader() {
|
|
||||||
for _, val := range header.Values {
|
|
||||||
w.Header().Add(header.Key, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(w.Header().Get("Content-Type")) == 0 {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
}
|
|
||||||
|
|
||||||
w.WriteHeader(int(rsp.StatusCode))
|
|
||||||
w.Write([]byte(rsp.Body))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *apiHandler) String() string {
|
|
||||||
return "api"
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
|
||||||
options := handler.NewOptions(opts...)
|
|
||||||
return &apiHandler{
|
|
||||||
opts: options,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithService(s *goapi.Service, opts ...handler.Option) handler.Handler {
|
|
||||||
options := handler.NewOptions(opts...)
|
|
||||||
return &apiHandler{
|
|
||||||
opts: options,
|
|
||||||
s: s,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"mime"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/oxtoacart/bpool"
|
|
||||||
api "github.com/unistack-org/micro/v3/api/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// need to calculate later to specify useful defaults
|
|
||||||
bufferPool = bpool.NewSizedBufferPool(1024, 8)
|
|
||||||
)
|
|
||||||
|
|
||||||
func requestToProto(r *http.Request) (*api.Request, error) {
|
|
||||||
if err := r.ParseForm(); err != nil {
|
|
||||||
return nil, fmt.Errorf("Error parsing form: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req := &api.Request{
|
|
||||||
Path: r.URL.Path,
|
|
||||||
Method: r.Method,
|
|
||||||
Header: make(map[string]*api.Pair),
|
|
||||||
Get: make(map[string]*api.Pair),
|
|
||||||
Post: make(map[string]*api.Pair),
|
|
||||||
Url: r.URL.String(),
|
|
||||||
}
|
|
||||||
|
|
||||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
|
||||||
if err != nil {
|
|
||||||
ct = "text/plain; charset=UTF-8" //default CT is text/plain
|
|
||||||
r.Header.Set("Content-Type", ct)
|
|
||||||
}
|
|
||||||
|
|
||||||
//set the body:
|
|
||||||
if r.Body != nil {
|
|
||||||
switch ct {
|
|
||||||
case "application/x-www-form-urlencoded":
|
|
||||||
// expect form vals in Post data
|
|
||||||
default:
|
|
||||||
buf := bufferPool.Get()
|
|
||||||
defer bufferPool.Put(buf)
|
|
||||||
if _, err = buf.ReadFrom(r.Body); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
req.Body = buf.String()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set X-Forwarded-For if it does not exist
|
|
||||||
if ip, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
|
|
||||||
if prior, ok := r.Header["X-Forwarded-For"]; ok {
|
|
||||||
ip = strings.Join(prior, ", ") + ", " + ip
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the header
|
|
||||||
req.Header["X-Forwarded-For"] = &api.Pair{
|
|
||||||
Key: "X-Forwarded-For",
|
|
||||||
Values: []string{ip},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Host is stripped from net/http Headers so let's add it
|
|
||||||
req.Header["Host"] = &api.Pair{
|
|
||||||
Key: "Host",
|
|
||||||
Values: []string{r.Host},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get data
|
|
||||||
for key, vals := range r.URL.Query() {
|
|
||||||
header, ok := req.Get[key]
|
|
||||||
if !ok {
|
|
||||||
header = &api.Pair{
|
|
||||||
Key: key,
|
|
||||||
}
|
|
||||||
req.Get[key] = header
|
|
||||||
}
|
|
||||||
header.Values = vals
|
|
||||||
}
|
|
||||||
|
|
||||||
// Post data
|
|
||||||
for key, vals := range r.PostForm {
|
|
||||||
header, ok := req.Post[key]
|
|
||||||
if !ok {
|
|
||||||
header = &api.Pair{
|
|
||||||
Key: key,
|
|
||||||
}
|
|
||||||
req.Post[key] = header
|
|
||||||
}
|
|
||||||
header.Values = vals
|
|
||||||
}
|
|
||||||
|
|
||||||
for key, vals := range r.Header {
|
|
||||||
header, ok := req.Header[key]
|
|
||||||
if !ok {
|
|
||||||
header = &api.Pair{
|
|
||||||
Key: key,
|
|
||||||
}
|
|
||||||
req.Header[key] = header
|
|
||||||
}
|
|
||||||
header.Values = vals
|
|
||||||
}
|
|
||||||
|
|
||||||
return req, nil
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRequestToProto(t *testing.T) {
|
|
||||||
testData := []*http.Request{
|
|
||||||
{
|
|
||||||
Method: "GET",
|
|
||||||
Header: http.Header{
|
|
||||||
"Header": []string{"test"},
|
|
||||||
},
|
|
||||||
URL: &url.URL{
|
|
||||||
Scheme: "http",
|
|
||||||
Host: "localhost",
|
|
||||||
Path: "/foo/bar",
|
|
||||||
RawQuery: "param1=value1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, d := range testData {
|
|
||||||
p, err := requestToProto(d)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if p.Path != d.URL.Path {
|
|
||||||
t.Fatalf("Expected path %s got %s", d.URL.Path, p.Path)
|
|
||||||
}
|
|
||||||
if p.Method != d.Method {
|
|
||||||
t.Fatalf("Expected method %s got %s", d.Method, p.Method)
|
|
||||||
}
|
|
||||||
for k, v := range d.Header {
|
|
||||||
if val, ok := p.Header[k]; !ok {
|
|
||||||
t.Fatalf("Expected header %s", k)
|
|
||||||
} else if val.Values[0] != v[0] {
|
|
||||||
t.Fatalf("Expected val %s, got %s", val.Values[0], v[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,141 +0,0 @@
|
|||||||
// Package event provides a handler which publishes an event
|
|
||||||
package event
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"path"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/oxtoacart/bpool"
|
|
||||||
"github.com/unistack-org/micro/v3/api/handler"
|
|
||||||
proto "github.com/unistack-org/micro/v3/api/proto"
|
|
||||||
"github.com/unistack-org/micro/v3/util/ctx"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
bufferPool = bpool.NewSizedBufferPool(1024, 8)
|
|
||||||
)
|
|
||||||
|
|
||||||
type event struct {
|
|
||||||
opts handler.Options
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
Handler = "event"
|
|
||||||
versionRe = regexp.MustCompilePOSIX("^v[0-9]+$")
|
|
||||||
)
|
|
||||||
|
|
||||||
func eventName(parts []string) string {
|
|
||||||
return strings.Join(parts, ".")
|
|
||||||
}
|
|
||||||
|
|
||||||
func evRoute(ns, p string) (string, string) {
|
|
||||||
p = path.Clean(p)
|
|
||||||
p = strings.TrimPrefix(p, "/")
|
|
||||||
|
|
||||||
if len(p) == 0 {
|
|
||||||
return ns, "event"
|
|
||||||
}
|
|
||||||
|
|
||||||
parts := strings.Split(p, "/")
|
|
||||||
|
|
||||||
// no path
|
|
||||||
if len(parts) == 0 {
|
|
||||||
// topic: namespace
|
|
||||||
// action: event
|
|
||||||
return strings.Trim(ns, "."), "event"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Treat /v[0-9]+ as versioning
|
|
||||||
// /v1/foo/bar => topic: v1.foo action: bar
|
|
||||||
if len(parts) >= 2 && versionRe.Match([]byte(parts[0])) {
|
|
||||||
topic := ns + "." + strings.Join(parts[:2], ".")
|
|
||||||
action := eventName(parts[1:])
|
|
||||||
return topic, action
|
|
||||||
}
|
|
||||||
|
|
||||||
// /foo => topic: ns.foo action: foo
|
|
||||||
// /foo/bar => topic: ns.foo action: bar
|
|
||||||
topic := ns + "." + strings.Join(parts[:1], ".")
|
|
||||||
action := eventName(parts[1:])
|
|
||||||
|
|
||||||
return topic, action
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
bsize := handler.DefaultMaxRecvSize
|
|
||||||
if e.opts.MaxRecvSize > 0 {
|
|
||||||
bsize = e.opts.MaxRecvSize
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Body = http.MaxBytesReader(w, r.Body, bsize)
|
|
||||||
|
|
||||||
// request to topic:event
|
|
||||||
// create event
|
|
||||||
// publish to topic
|
|
||||||
|
|
||||||
topic, action := evRoute(e.opts.Namespace, r.URL.Path)
|
|
||||||
|
|
||||||
// create event
|
|
||||||
ev := &proto.Event{
|
|
||||||
Name: action,
|
|
||||||
// TODO: dedupe event
|
|
||||||
Id: fmt.Sprintf("%s-%s-%s", topic, action, uuid.New().String()),
|
|
||||||
Header: make(map[string]*proto.Pair),
|
|
||||||
Timestamp: time.Now().Unix(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// set headers
|
|
||||||
for key, vals := range r.Header {
|
|
||||||
header, ok := ev.Header[key]
|
|
||||||
if !ok {
|
|
||||||
header = &proto.Pair{
|
|
||||||
Key: key,
|
|
||||||
}
|
|
||||||
ev.Header[key] = header
|
|
||||||
}
|
|
||||||
header.Values = vals
|
|
||||||
}
|
|
||||||
|
|
||||||
// set body
|
|
||||||
if r.Method == "GET" {
|
|
||||||
bytes, _ := json.Marshal(r.URL.Query())
|
|
||||||
ev.Data = string(bytes)
|
|
||||||
} else {
|
|
||||||
// Read body
|
|
||||||
buf := bufferPool.Get()
|
|
||||||
defer bufferPool.Put(buf)
|
|
||||||
if _, err := buf.ReadFrom(r.Body); err != nil {
|
|
||||||
http.Error(w, err.Error(), 500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ev.Data = buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// get client
|
|
||||||
c := e.opts.Client
|
|
||||||
|
|
||||||
// create publication
|
|
||||||
p := c.NewMessage(topic, ev)
|
|
||||||
|
|
||||||
// publish event
|
|
||||||
if err := c.Publish(ctx.FromRequest(r), p); err != nil {
|
|
||||||
http.Error(w, err.Error(), 500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *event) String() string {
|
|
||||||
return "event"
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
|
||||||
return &event{
|
|
||||||
opts: handler.NewOptions(opts...),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
// Package http is a http reverse proxy handler
|
|
||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httputil"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/api"
|
|
||||||
"github.com/unistack-org/micro/v3/api/handler"
|
|
||||||
"github.com/unistack-org/micro/v3/register"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
Handler = "http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type httpHandler struct {
|
|
||||||
options handler.Options
|
|
||||||
|
|
||||||
// set with different initializer
|
|
||||||
s *api.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
service, err := h.getService(r)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(service) == 0 {
|
|
||||||
w.WriteHeader(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rp, err := url.Parse(service)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
httputil.NewSingleHostReverseProxy(rp).ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getService returns the service for this request from the selector
|
|
||||||
func (h *httpHandler) getService(r *http.Request) (string, error) {
|
|
||||||
var service *api.Service
|
|
||||||
|
|
||||||
if h.s != nil {
|
|
||||||
// we were given the service
|
|
||||||
service = h.s
|
|
||||||
} else if h.options.Router != nil {
|
|
||||||
// try get service from router
|
|
||||||
s, err := h.options.Router.Route(r)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
service = s
|
|
||||||
} else {
|
|
||||||
// we have no way of routing the request
|
|
||||||
return "", errors.New("no route found")
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(service.Services) == 0 {
|
|
||||||
return "", errors.New("no route found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the nodes for this service
|
|
||||||
nodes := make([]*register.Node, 0, len(service.Services))
|
|
||||||
for _, srv := range service.Services {
|
|
||||||
nodes = append(nodes, srv.Nodes...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// select a random node
|
|
||||||
node := nodes[rand.Int()%len(nodes)]
|
|
||||||
|
|
||||||
return fmt.Sprintf("http://%s", node.Address), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *httpHandler) String() string {
|
|
||||||
return "http"
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewHandler returns a http proxy handler
|
|
||||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
|
||||||
options := handler.NewOptions(opts...)
|
|
||||||
|
|
||||||
return &httpHandler{
|
|
||||||
options: options,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithService creates a handler with a service
|
|
||||||
func WithService(s *api.Service, opts ...handler.Option) handler.Handler {
|
|
||||||
options := handler.NewOptions(opts...)
|
|
||||||
|
|
||||||
return &httpHandler{
|
|
||||||
options: options,
|
|
||||||
s: s,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,129 +0,0 @@
|
|||||||
// +build ignore
|
|
||||||
|
|
||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/api/handler"
|
|
||||||
"github.com/unistack-org/micro/v3/api/resolver"
|
|
||||||
"github.com/unistack-org/micro/v3/api/resolver/vpath"
|
|
||||||
"github.com/unistack-org/micro/v3/api/router"
|
|
||||||
regRouter "github.com/unistack-org/micro/v3/api/router/register"
|
|
||||||
"github.com/unistack-org/micro/v3/register"
|
|
||||||
"github.com/unistack-org/micro/v3/register/memory"
|
|
||||||
)
|
|
||||||
|
|
||||||
func testHttp(t *testing.T, path, service, ns string) {
|
|
||||||
r := memory.NewRegister()
|
|
||||||
|
|
||||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer l.Close()
|
|
||||||
|
|
||||||
s := ®ister.Service{
|
|
||||||
Name: service,
|
|
||||||
Nodes: []*register.Node{
|
|
||||||
{
|
|
||||||
Id: service + "-1",
|
|
||||||
Address: l.Addr().String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
r.Register(s)
|
|
||||||
defer r.Deregister(s)
|
|
||||||
|
|
||||||
// setup the test handler
|
|
||||||
m := http.NewServeMux()
|
|
||||||
m.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Write([]byte(`you got served`))
|
|
||||||
})
|
|
||||||
|
|
||||||
// start http test serve
|
|
||||||
go http.Serve(l, m)
|
|
||||||
|
|
||||||
// create new request and writer
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
req, err := http.NewRequest("POST", path, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialise the handler
|
|
||||||
rt := regRouter.NewRouter(
|
|
||||||
router.WithHandler("http"),
|
|
||||||
router.WithRegister(r),
|
|
||||||
router.WithResolver(vpath.NewResolver(
|
|
||||||
resolver.WithServicePrefix(ns),
|
|
||||||
)),
|
|
||||||
)
|
|
||||||
|
|
||||||
p := NewHandler(handler.WithRouter(rt))
|
|
||||||
|
|
||||||
// execute the handler
|
|
||||||
p.ServeHTTP(w, req)
|
|
||||||
|
|
||||||
if w.Code != 200 {
|
|
||||||
t.Fatalf("Expected 200 response got %d %s", w.Code, w.Body.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
if w.Body.String() != "you got served" {
|
|
||||||
t.Fatalf("Expected body: you got served. Got: %s", w.Body.String())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestHttpHandler(t *testing.T) {
|
|
||||||
testData := []struct {
|
|
||||||
path string
|
|
||||||
service string
|
|
||||||
namespace string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
"/test/foo",
|
|
||||||
"go.micro.api.test",
|
|
||||||
"go.micro.api",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/test/foo/baz",
|
|
||||||
"go.micro.api.test",
|
|
||||||
"go.micro.api",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/v1/foo",
|
|
||||||
"go.micro.api.v1.foo",
|
|
||||||
"go.micro.api",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/v1/foo/bar",
|
|
||||||
"go.micro.api.v1.foo",
|
|
||||||
"go.micro.api",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/v2/baz",
|
|
||||||
"go.micro.api.v2.baz",
|
|
||||||
"go.micro.api",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/v2/baz/bar",
|
|
||||||
"go.micro.api.v2.baz",
|
|
||||||
"go.micro.api",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"/v2/baz/bar",
|
|
||||||
"v2.baz",
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, d := range testData {
|
|
||||||
t.Run(d.service, func(t *testing.T) {
|
|
||||||
testHttp(t, d.path, d.service, d.namespace)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,6 +3,7 @@ package handler
|
|||||||
import (
|
import (
|
||||||
"github.com/unistack-org/micro/v3/api/router"
|
"github.com/unistack-org/micro/v3/api/router"
|
||||||
"github.com/unistack-org/micro/v3/client"
|
"github.com/unistack-org/micro/v3/client"
|
||||||
|
"github.com/unistack-org/micro/v3/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -14,13 +15,19 @@ type Options struct {
|
|||||||
Namespace string
|
Namespace string
|
||||||
Router router.Router
|
Router router.Router
|
||||||
Client client.Client
|
Client client.Client
|
||||||
|
Logger logger.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
type Option func(o *Options)
|
type Option func(o *Options)
|
||||||
|
|
||||||
// NewOptions fills in the blanks
|
// NewOptions fills in the blanks
|
||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
var options Options
|
options := Options{
|
||||||
|
Client: client.DefaultClient,
|
||||||
|
Router: router.DefaultRouter,
|
||||||
|
Logger: logger.DefaultLogger,
|
||||||
|
MaxRecvSize: DefaultMaxRecvSize,
|
||||||
|
}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
}
|
}
|
||||||
@ -30,10 +37,6 @@ func NewOptions(opts ...Option) Options {
|
|||||||
WithNamespace("go.micro.api")(&options)
|
WithNamespace("go.micro.api")(&options)
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.MaxRecvSize == 0 {
|
|
||||||
options.MaxRecvSize = DefaultMaxRecvSize
|
|
||||||
}
|
|
||||||
|
|
||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,182 +0,0 @@
|
|||||||
// Package web contains the web handler including websocket support
|
|
||||||
package web
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"math/rand"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httputil"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/api"
|
|
||||||
"github.com/unistack-org/micro/v3/api/handler"
|
|
||||||
"github.com/unistack-org/micro/v3/register"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
Handler = "web"
|
|
||||||
)
|
|
||||||
|
|
||||||
type webHandler struct {
|
|
||||||
opts handler.Options
|
|
||||||
s *api.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wh *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
service, err := wh.getService(r)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(service) == 0 {
|
|
||||||
w.WriteHeader(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
rp, err := url.Parse(service)
|
|
||||||
if err != nil {
|
|
||||||
w.WriteHeader(500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if isWebSocket(r) {
|
|
||||||
wh.serveWebSocket(rp.Host, w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
httputil.NewSingleHostReverseProxy(rp).ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
// getService returns the service for this request from the selector
|
|
||||||
func (wh *webHandler) getService(r *http.Request) (string, error) {
|
|
||||||
var service *api.Service
|
|
||||||
|
|
||||||
if wh.s != nil {
|
|
||||||
// we were given the service
|
|
||||||
service = wh.s
|
|
||||||
} else if wh.opts.Router != nil {
|
|
||||||
// try get service from router
|
|
||||||
s, err := wh.opts.Router.Route(r)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
service = s
|
|
||||||
} else {
|
|
||||||
// we have no way of routing the request
|
|
||||||
return "", errors.New("no route found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the nodes
|
|
||||||
nodes := make([]*register.Node, 0, len(service.Services))
|
|
||||||
for _, srv := range service.Services {
|
|
||||||
nodes = append(nodes, srv.Nodes...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(nodes) == 0 {
|
|
||||||
return "", errors.New("no route found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// select a random node
|
|
||||||
node := nodes[rand.Int()%len(nodes)]
|
|
||||||
|
|
||||||
return fmt.Sprintf("http://%s", node.Address), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// serveWebSocket used to serve a web socket proxied connection
|
|
||||||
func (wh *webHandler) serveWebSocket(host string, w http.ResponseWriter, r *http.Request) {
|
|
||||||
req := new(http.Request)
|
|
||||||
*req = *r
|
|
||||||
|
|
||||||
if len(host) == 0 {
|
|
||||||
http.Error(w, "invalid host", 500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// set x-forward-for
|
|
||||||
if clientIP, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
|
|
||||||
if ips, ok := req.Header["X-Forwarded-For"]; ok {
|
|
||||||
clientIP = strings.Join(ips, ", ") + ", " + clientIP
|
|
||||||
}
|
|
||||||
req.Header.Set("X-Forwarded-For", clientIP)
|
|
||||||
}
|
|
||||||
|
|
||||||
// connect to the backend host
|
|
||||||
conn, err := net.Dial("tcp", host)
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, err.Error(), 500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// hijack the connection
|
|
||||||
hj, ok := w.(http.Hijacker)
|
|
||||||
if !ok {
|
|
||||||
http.Error(w, "failed to connect", 500)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
nc, _, err := hj.Hijack()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer nc.Close()
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
if err = req.Write(conn); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
errCh := make(chan error, 2)
|
|
||||||
|
|
||||||
cp := func(dst io.Writer, src io.Reader) {
|
|
||||||
_, err := io.Copy(dst, src)
|
|
||||||
errCh <- err
|
|
||||||
}
|
|
||||||
|
|
||||||
go cp(conn, nc)
|
|
||||||
go cp(nc, conn)
|
|
||||||
|
|
||||||
<-errCh
|
|
||||||
}
|
|
||||||
|
|
||||||
func isWebSocket(r *http.Request) bool {
|
|
||||||
contains := func(key, val string) bool {
|
|
||||||
vv := strings.Split(r.Header.Get(key), ",")
|
|
||||||
for _, v := range vv {
|
|
||||||
if val == strings.ToLower(strings.TrimSpace(v)) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if contains("Connection", "upgrade") && contains("Upgrade", "websocket") {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (wh *webHandler) String() string {
|
|
||||||
return "web"
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
|
||||||
return &webHandler{
|
|
||||||
opts: handler.NewOptions(opts...),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func WithService(s *api.Service, opts ...handler.Option) handler.Handler {
|
|
||||||
options := handler.NewOptions(opts...)
|
|
||||||
|
|
||||||
return &webHandler{
|
|
||||||
opts: options,
|
|
||||||
s: s,
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
package proto
|
|
||||||
|
|
||||||
type Message struct {
|
|
||||||
data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Message) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (m *Message) Reset() {
|
|
||||||
*m = Message{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Message) String() string {
|
|
||||||
return string(m.data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Message) Marshal() ([]byte, error) {
|
|
||||||
return m.data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Message) Unmarshal(data []byte) error {
|
|
||||||
m.data = data
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMessage(data []byte) *Message {
|
|
||||||
return &Message{data}
|
|
||||||
}
|
|
@ -1,511 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.25.0
|
|
||||||
// protoc v3.6.1
|
|
||||||
// source: api/proto/api.proto
|
|
||||||
|
|
||||||
package go_api
|
|
||||||
|
|
||||||
import (
|
|
||||||
proto "github.com/golang/protobuf/proto"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
|
||||||
// of the legacy proto package is being used.
|
|
||||||
const _ = proto.ProtoPackageIsVersion4
|
|
||||||
|
|
||||||
type Pair struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
|
||||||
Values []string `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Pair) Reset() {
|
|
||||||
*x = Pair{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_api_proto_api_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Pair) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Pair) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Pair) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_api_proto_api_proto_msgTypes[0]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Pair.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Pair) Descriptor() ([]byte, []int) {
|
|
||||||
return file_api_proto_api_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Pair) GetKey() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Key
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Pair) GetValues() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Values
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// A HTTP request as RPC
|
|
||||||
// Forward by the api handler
|
|
||||||
type Request struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"`
|
|
||||||
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
|
|
||||||
Header map[string]*Pair `protobuf:"bytes,3,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
Get map[string]*Pair `protobuf:"bytes,4,rep,name=get,proto3" json:"get,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
Post map[string]*Pair `protobuf:"bytes,5,rep,name=post,proto3" json:"post,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
Body string `protobuf:"bytes,6,opt,name=body,proto3" json:"body,omitempty"` // raw request body; if not application/x-www-form-urlencoded
|
|
||||||
Url string `protobuf:"bytes,7,opt,name=url,proto3" json:"url,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Request) Reset() {
|
|
||||||
*x = Request{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_api_proto_api_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Request) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Request) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Request) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_api_proto_api_proto_msgTypes[1]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Request.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Request) Descriptor() ([]byte, []int) {
|
|
||||||
return file_api_proto_api_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Request) GetMethod() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Method
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Request) GetPath() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Path
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Request) GetHeader() map[string]*Pair {
|
|
||||||
if x != nil {
|
|
||||||
return x.Header
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Request) GetGet() map[string]*Pair {
|
|
||||||
if x != nil {
|
|
||||||
return x.Get
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Request) GetPost() map[string]*Pair {
|
|
||||||
if x != nil {
|
|
||||||
return x.Post
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Request) GetBody() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Body
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Request) GetUrl() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Url
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// A HTTP response as RPC
|
|
||||||
// Expected response for the api handler
|
|
||||||
type Response struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
StatusCode int32 `protobuf:"varint,1,opt,name=statusCode,proto3" json:"statusCode,omitempty"`
|
|
||||||
Header map[string]*Pair `protobuf:"bytes,2,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
Body string `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Response) Reset() {
|
|
||||||
*x = Response{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_api_proto_api_proto_msgTypes[2]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Response) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Response) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Response) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_api_proto_api_proto_msgTypes[2]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Response.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Response) Descriptor() ([]byte, []int) {
|
|
||||||
return file_api_proto_api_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Response) GetStatusCode() int32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.StatusCode
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Response) GetHeader() map[string]*Pair {
|
|
||||||
if x != nil {
|
|
||||||
return x.Header
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Response) GetBody() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Body
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// A HTTP event as RPC
|
|
||||||
// Forwarded by the event handler
|
|
||||||
type Event struct {
|
|
||||||
state protoimpl.MessageState
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
|
|
||||||
// e.g login
|
|
||||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
|
||||||
// uuid
|
|
||||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
|
||||||
// unix timestamp of event
|
|
||||||
Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
|
||||||
// event headers
|
|
||||||
Header map[string]*Pair `protobuf:"bytes,4,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
|
||||||
// the event data
|
|
||||||
Data string `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Event) Reset() {
|
|
||||||
*x = Event{}
|
|
||||||
if protoimpl.UnsafeEnabled {
|
|
||||||
mi := &file_api_proto_api_proto_msgTypes[3]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Event) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Event) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Event) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_api_proto_api_proto_msgTypes[3]
|
|
||||||
if protoimpl.UnsafeEnabled && x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Event.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Event) Descriptor() ([]byte, []int) {
|
|
||||||
return file_api_proto_api_proto_rawDescGZIP(), []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Event) GetName() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Name
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Event) GetId() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Id
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Event) GetTimestamp() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Timestamp
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Event) GetHeader() map[string]*Pair {
|
|
||||||
if x != nil {
|
|
||||||
return x.Header
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Event) GetData() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.Data
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_api_proto_api_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
var file_api_proto_api_proto_rawDesc = []byte{
|
|
||||||
0x0a, 0x13, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2e,
|
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x67, 0x6f, 0x2e, 0x61, 0x70, 0x69, 0x22, 0x30, 0x0a,
|
|
||||||
0x04, 0x50, 0x61, 0x69, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
|
||||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
|
||||||
0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22,
|
|
||||||
0xc1, 0x03, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6d,
|
|
||||||
0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6d, 0x65, 0x74,
|
|
||||||
0x68, 0x6f, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28,
|
|
||||||
0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x33, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65,
|
|
||||||
0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x2e, 0x61, 0x70, 0x69,
|
|
||||||
0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45,
|
|
||||||
0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x03,
|
|
||||||
0x67, 0x65, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x67, 0x6f, 0x2e, 0x61,
|
|
||||||
0x70, 0x69, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x6e,
|
|
||||||
0x74, 0x72, 0x79, 0x52, 0x03, 0x67, 0x65, 0x74, 0x12, 0x2d, 0x0a, 0x04, 0x70, 0x6f, 0x73, 0x74,
|
|
||||||
0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x50, 0x6f, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72,
|
|
||||||
0x79, 0x52, 0x04, 0x70, 0x6f, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18,
|
|
||||||
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x75,
|
|
||||||
0x72, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x1a, 0x47, 0x0a,
|
|
||||||
0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
|
|
||||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x22,
|
|
||||||
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e,
|
|
||||||
0x67, 0x6f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c,
|
|
||||||
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x44, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x74,
|
|
||||||
0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
|
||||||
0x03, 0x6b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
|
|
||||||
0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x67, 0x6f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x69,
|
|
||||||
0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x45, 0x0a, 0x09,
|
|
||||||
0x50, 0x6f, 0x73, 0x74, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
|
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x05, 0x76,
|
|
||||||
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x67, 0x6f, 0x2e,
|
|
||||||
0x61, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
|
|
||||||
0x02, 0x38, 0x01, 0x22, 0xbd, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
|
||||||
0x12, 0x1e, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01,
|
|
||||||
0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x43, 0x6f, 0x64, 0x65,
|
|
||||||
0x12, 0x34, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b,
|
|
||||||
0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
|
||||||
0x73, 0x65, 0x2e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06,
|
|
||||||
0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x03,
|
|
||||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x1a, 0x47, 0x0a, 0x0b, 0x48, 0x65,
|
|
||||||
0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
|
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x05, 0x76,
|
|
||||||
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x67, 0x6f, 0x2e,
|
|
||||||
0x61, 0x70, 0x69, 0x2e, 0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
|
|
||||||
0x02, 0x38, 0x01, 0x22, 0xd9, 0x01, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a,
|
|
||||||
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
|
|
||||||
0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
|
|
||||||
0x64, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03,
|
|
||||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12,
|
|
||||||
0x31, 0x0a, 0x06, 0x68, 0x65, 0x61, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
|
|
||||||
0x19, 0x2e, 0x67, 0x6f, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x48,
|
|
||||||
0x65, 0x61, 0x64, 0x65, 0x72, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x68, 0x65, 0x61, 0x64,
|
|
||||||
0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
|
|
||||||
0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x47, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72,
|
|
||||||
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
|
||||||
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
|
||||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x67, 0x6f, 0x2e, 0x61, 0x70, 0x69, 0x2e,
|
|
||||||
0x50, 0x61, 0x69, 0x72, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x62,
|
|
||||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_api_proto_api_proto_rawDescOnce sync.Once
|
|
||||||
file_api_proto_api_proto_rawDescData = file_api_proto_api_proto_rawDesc
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_api_proto_api_proto_rawDescGZIP() []byte {
|
|
||||||
file_api_proto_api_proto_rawDescOnce.Do(func() {
|
|
||||||
file_api_proto_api_proto_rawDescData = protoimpl.X.CompressGZIP(file_api_proto_api_proto_rawDescData)
|
|
||||||
})
|
|
||||||
return file_api_proto_api_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_api_proto_api_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
|
||||||
var file_api_proto_api_proto_goTypes = []interface{}{
|
|
||||||
(*Pair)(nil), // 0: go.api.Pair
|
|
||||||
(*Request)(nil), // 1: go.api.Request
|
|
||||||
(*Response)(nil), // 2: go.api.Response
|
|
||||||
(*Event)(nil), // 3: go.api.Event
|
|
||||||
nil, // 4: go.api.Request.HeaderEntry
|
|
||||||
nil, // 5: go.api.Request.GetEntry
|
|
||||||
nil, // 6: go.api.Request.PostEntry
|
|
||||||
nil, // 7: go.api.Response.HeaderEntry
|
|
||||||
nil, // 8: go.api.Event.HeaderEntry
|
|
||||||
}
|
|
||||||
var file_api_proto_api_proto_depIdxs = []int32{
|
|
||||||
4, // 0: go.api.Request.header:type_name -> go.api.Request.HeaderEntry
|
|
||||||
5, // 1: go.api.Request.get:type_name -> go.api.Request.GetEntry
|
|
||||||
6, // 2: go.api.Request.post:type_name -> go.api.Request.PostEntry
|
|
||||||
7, // 3: go.api.Response.header:type_name -> go.api.Response.HeaderEntry
|
|
||||||
8, // 4: go.api.Event.header:type_name -> go.api.Event.HeaderEntry
|
|
||||||
0, // 5: go.api.Request.HeaderEntry.value:type_name -> go.api.Pair
|
|
||||||
0, // 6: go.api.Request.GetEntry.value:type_name -> go.api.Pair
|
|
||||||
0, // 7: go.api.Request.PostEntry.value:type_name -> go.api.Pair
|
|
||||||
0, // 8: go.api.Response.HeaderEntry.value:type_name -> go.api.Pair
|
|
||||||
0, // 9: go.api.Event.HeaderEntry.value:type_name -> go.api.Pair
|
|
||||||
10, // [10:10] is the sub-list for method output_type
|
|
||||||
10, // [10:10] is the sub-list for method input_type
|
|
||||||
10, // [10:10] is the sub-list for extension type_name
|
|
||||||
10, // [10:10] is the sub-list for extension extendee
|
|
||||||
0, // [0:10] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_api_proto_api_proto_init() }
|
|
||||||
func file_api_proto_api_proto_init() {
|
|
||||||
if File_api_proto_api_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !protoimpl.UnsafeEnabled {
|
|
||||||
file_api_proto_api_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*Pair); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_api_proto_api_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*Request); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_api_proto_api_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*Response); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file_api_proto_api_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
|
||||||
switch v := v.(*Event); i {
|
|
||||||
case 0:
|
|
||||||
return &v.state
|
|
||||||
case 1:
|
|
||||||
return &v.sizeCache
|
|
||||||
case 2:
|
|
||||||
return &v.unknownFields
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: file_api_proto_api_proto_rawDesc,
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 9,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_api_proto_api_proto_goTypes,
|
|
||||||
DependencyIndexes: file_api_proto_api_proto_depIdxs,
|
|
||||||
MessageInfos: file_api_proto_api_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_api_proto_api_proto = out.File
|
|
||||||
file_api_proto_api_proto_rawDesc = nil
|
|
||||||
file_api_proto_api_proto_goTypes = nil
|
|
||||||
file_api_proto_api_proto_depIdxs = nil
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
|
||||||
// source: api/proto/api.proto
|
|
||||||
|
|
||||||
package go_api
|
|
||||||
|
|
||||||
import (
|
|
||||||
fmt "fmt"
|
|
||||||
proto "github.com/golang/protobuf/proto"
|
|
||||||
math "math"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reference imports to suppress errors if they are not otherwise used.
|
|
||||||
var _ = proto.Marshal
|
|
||||||
var _ = fmt.Errorf
|
|
||||||
var _ = math.Inf
|
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
|
||||||
// is compatible with the proto package it is being compiled against.
|
|
||||||
// A compilation error at this line likely means your copy of the
|
|
||||||
// proto package needs to be updated.
|
|
||||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
|
@ -1,43 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package go.api;
|
|
||||||
|
|
||||||
message Pair {
|
|
||||||
string key = 1;
|
|
||||||
repeated string values = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A HTTP request as RPC
|
|
||||||
// Forward by the api handler
|
|
||||||
message Request {
|
|
||||||
string method = 1;
|
|
||||||
string path = 2;
|
|
||||||
map<string, Pair> header = 3;
|
|
||||||
map<string, Pair> get = 4;
|
|
||||||
map<string, Pair> post = 5;
|
|
||||||
string body = 6; // raw request body; if not application/x-www-form-urlencoded
|
|
||||||
string url = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A HTTP response as RPC
|
|
||||||
// Expected response for the api handler
|
|
||||||
message Response {
|
|
||||||
int32 statusCode = 1;
|
|
||||||
map<string, Pair> header = 2;
|
|
||||||
string body = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A HTTP event as RPC
|
|
||||||
// Forwarded by the event handler
|
|
||||||
message Event {
|
|
||||||
// e.g login
|
|
||||||
string name = 1;
|
|
||||||
// uuid
|
|
||||||
string id = 2;
|
|
||||||
// unix timestamp of event
|
|
||||||
int64 timestamp = 3;
|
|
||||||
// event headers
|
|
||||||
map<string, Pair> header = 4;
|
|
||||||
// the event data
|
|
||||||
string data = 5;
|
|
||||||
}
|
|
@ -6,8 +6,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/api/resolver/vpath"
|
"github.com/unistack-org/micro/v3/api/resolver/vpath"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestResolve(t *testing.T) {
|
func TestResolve(t *testing.T) {
|
||||||
@ -62,9 +60,13 @@ func TestResolve(t *testing.T) {
|
|||||||
t.Run(tc.Name, func(t *testing.T) {
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
r := NewResolver(vpath.NewResolver())
|
r := NewResolver(vpath.NewResolver())
|
||||||
result, err := r.Resolve(&http.Request{URL: &url.URL{Host: tc.Host, Path: "foo/bar"}})
|
result, err := r.Resolve(&http.Request{URL: &url.URL{Host: tc.Host, Path: "foo/bar"}})
|
||||||
assert.Nil(t, err, "Expecter err to be nil")
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
if result != nil {
|
if result != nil {
|
||||||
assert.Equal(t, tc.Result, result.Domain, "Expected %v but got %v", tc.Result, result.Domain)
|
if tc.Result != result.Domain {
|
||||||
|
t.Fatalf("Expected %v but got %v", tc.Result, result.Domain)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,10 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/api"
|
"github.com/unistack-org/micro/v3/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultRouter Router
|
||||||
|
)
|
||||||
|
|
||||||
// Router is used to determine an endpoint for a request
|
// Router is used to determine an endpoint for a request
|
||||||
type Router interface {
|
type Router interface {
|
||||||
// Returns options
|
// Returns options
|
||||||
@ -23,6 +27,6 @@ type Router interface {
|
|||||||
Deregister(ep *api.Endpoint) error
|
Deregister(ep *api.Endpoint) error
|
||||||
// Route returns an api.Service route
|
// Route returns an api.Service route
|
||||||
Route(r *http.Request) (*api.Service, error)
|
Route(r *http.Request) (*api.Service, error)
|
||||||
// String represenation of router
|
// String representation of router
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
@ -235,6 +235,7 @@ func (m *memorySubscriber) Unsubscribe(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewBroker return new memory broker
|
||||||
func NewBroker(opts ...Option) Broker {
|
func NewBroker(opts ...Option) Broker {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultClient is the global default client
|
// DefaultClient is the global default client
|
||||||
DefaultClient Client = NewClient()
|
DefaultClient Client = NewClient()
|
||||||
|
DefaultContentType = "application/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Client is the interface used to make requests to services.
|
// Client is the interface used to make requests to services.
|
||||||
|
@ -20,10 +20,6 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
defaultContentType = "application/json"
|
|
||||||
)
|
|
||||||
|
|
||||||
type noopClient struct {
|
type noopClient struct {
|
||||||
opts Options
|
opts Options
|
||||||
}
|
}
|
||||||
|
@ -151,7 +151,7 @@ type RequestOptions struct {
|
|||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Context: context.Background(),
|
Context: context.Background(),
|
||||||
ContentType: "application/json",
|
ContentType: DefaultContentType,
|
||||||
Codecs: make(map[string]codec.Codec),
|
Codecs: make(map[string]codec.Codec),
|
||||||
CallOptions: CallOptions{
|
CallOptions: CallOptions{
|
||||||
Backoff: DefaultBackoff,
|
Backoff: DefaultBackoff,
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
"github.com/unistack-org/micro/v3/metadata"
|
"github.com/unistack-org/micro/v3/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Message types
|
||||||
const (
|
const (
|
||||||
// Message types
|
|
||||||
Error MessageType = iota
|
Error MessageType = iota
|
||||||
Request
|
Request
|
||||||
Response
|
Response
|
||||||
@ -25,8 +25,9 @@ var (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultMaxMsgSize specifies how much data codec can handle
|
// DefaultMaxMsgSize specifies how much data codec can handle
|
||||||
DefaultMaxMsgSize int = 1024 * 1024 * 4 // 4Mb
|
DefaultMaxMsgSize int = 1024 * 1024 * 4 // 4Mb
|
||||||
DefaultCodec Codec = NewCodec()
|
// DefaultCodec is the global default codec
|
||||||
|
DefaultCodec Codec = NewCodec()
|
||||||
)
|
)
|
||||||
|
|
||||||
// MessageType
|
// MessageType
|
||||||
|
@ -30,12 +30,8 @@ func (c *noopCodec) ReadBody(conn io.Reader, b interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch v := b.(type) {
|
switch v := b.(type) {
|
||||||
case string:
|
|
||||||
v = string(buf)
|
|
||||||
case *string:
|
case *string:
|
||||||
*v = string(buf)
|
*v = string(buf)
|
||||||
case []byte:
|
|
||||||
v = buf
|
|
||||||
case *[]byte:
|
case *[]byte:
|
||||||
*v = buf
|
*v = buf
|
||||||
case *Frame:
|
case *Frame:
|
||||||
@ -112,15 +108,9 @@ func (c *noopCodec) Unmarshal(d []byte, v interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
switch ve := v.(type) {
|
switch ve := v.(type) {
|
||||||
case string:
|
|
||||||
ve = string(d)
|
|
||||||
return nil
|
|
||||||
case *string:
|
case *string:
|
||||||
*ve = string(d)
|
*ve = string(d)
|
||||||
return nil
|
return nil
|
||||||
case []byte:
|
|
||||||
ve = d
|
|
||||||
return nil
|
|
||||||
case *[]byte:
|
case *[]byte:
|
||||||
*ve = d
|
*ve = d
|
||||||
return nil
|
return nil
|
||||||
|
34
codec/noop_test.go
Normal file
34
codec/noop_test.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package codec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNoopBytes(t *testing.T) {
|
||||||
|
req := []byte("test req")
|
||||||
|
rsp := make([]byte, len(req))
|
||||||
|
|
||||||
|
nc := NewCodec()
|
||||||
|
if err := nc.Unmarshal(req, &rsp); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(req, rsp) {
|
||||||
|
t.Fatalf("req not eq rsp: %s != %s", req, rsp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNoopString(t *testing.T) {
|
||||||
|
req := []byte("test req")
|
||||||
|
var rsp string
|
||||||
|
|
||||||
|
nc := NewCodec()
|
||||||
|
if err := nc.Unmarshal(req, &rsp); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(req, []byte(rsp)) {
|
||||||
|
t.Fatalf("req not eq rsp: %s != %s", req, rsp)
|
||||||
|
}
|
||||||
|
}
|
@ -45,6 +45,7 @@ func Meter(m meter.Meter) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewOptions returns new options
|
||||||
func NewOptions(opts ...Option) Options {
|
func NewOptions(opts ...Option) Options {
|
||||||
options := Options{
|
options := Options{
|
||||||
Logger: logger.DefaultLogger,
|
Logger: logger.DefaultLogger,
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
type configKey struct{}
|
type configKey struct{}
|
||||||
|
|
||||||
|
// FromContext returns store from context
|
||||||
func FromContext(ctx context.Context) (Config, bool) {
|
func FromContext(ctx context.Context) (Config, bool) {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
@ -14,6 +15,7 @@ func FromContext(ctx context.Context) (Config, bool) {
|
|||||||
return c, ok
|
return c, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewContext put store in context
|
||||||
func NewContext(ctx context.Context, c Config) context.Context {
|
func NewContext(ctx context.Context, c Config) context.Context {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
|
@ -64,7 +64,7 @@ func newFunction(opts ...Option) Function {
|
|||||||
// make context the last thing
|
// make context the last thing
|
||||||
fopts = append(fopts, Context(ctx))
|
fopts = append(fopts, Context(ctx))
|
||||||
|
|
||||||
service := &service{opts: NewOptions(opts...)}
|
service := &service{opts: NewOptions(fopts...)}
|
||||||
|
|
||||||
fn := &function{
|
fn := &function{
|
||||||
cancel: cancel,
|
cancel: cancel,
|
||||||
|
6
go.mod
6
go.mod
@ -6,18 +6,12 @@ require (
|
|||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
github.com/ef-ds/deque v1.0.4
|
github.com/ef-ds/deque v1.0.4
|
||||||
github.com/golang/protobuf v1.4.3
|
|
||||||
github.com/google/uuid v1.2.0
|
github.com/google/uuid v1.2.0
|
||||||
github.com/imdario/mergo v0.3.11
|
github.com/imdario/mergo v0.3.11
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/miekg/dns v1.1.38
|
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
|
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
|
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
|
|
||||||
google.golang.org/protobuf v1.25.0
|
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||||
)
|
)
|
||||||
|
88
go.sum
88
go.sum
@ -1,8 +1,3 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
@ -11,26 +6,6 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
|
|||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||||
github.com/ef-ds/deque v1.0.4 h1:iFAZNmveMT9WERAkqLJ+oaABF9AcVQ5AjXem/hroniI=
|
github.com/ef-ds/deque v1.0.4 h1:iFAZNmveMT9WERAkqLJ+oaABF9AcVQ5AjXem/hroniI=
|
||||||
github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg=
|
github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
|
||||||
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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
|
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
|
||||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
|
||||||
@ -39,84 +14,23 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||||||
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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/miekg/dns v1.1.38 h1:MtIY+fmHUVVgv1AXzmKMWcwdCYxTRPG1EDjpqF4RCEw=
|
|
||||||
github.com/miekg/dns v1.1.38/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
|
||||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
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/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
|
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
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-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
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-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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-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-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
|
||||||
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-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@ -124,5 +38,3 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
|||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
|
@ -2,19 +2,16 @@ package meter
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNoopMeter(t *testing.T) {
|
func TestNoopMeter(t *testing.T) {
|
||||||
meter := NewMeter(Path("/noop"))
|
meter := NewMeter(Path("/noop"))
|
||||||
assert.NotNil(t, meter)
|
if "/noop" != meter.Options().Path {
|
||||||
assert.Equal(t, "/noop", meter.Options().Path)
|
t.Fatalf("invalid options parsing: %v", meter.Options())
|
||||||
assert.Implements(t, new(Meter), meter)
|
}
|
||||||
|
|
||||||
cnt := meter.Counter("counter", Label("server", "noop"))
|
cnt := meter.Counter("counter", Label("server", "noop"))
|
||||||
cnt.Inc()
|
cnt.Inc()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLabels(t *testing.T) {
|
func TestLabels(t *testing.T) {
|
||||||
|
@ -4,18 +4,20 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"net"
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
|
||||||
"github.com/unistack-org/micro/v3/resolver"
|
"github.com/unistack-org/micro/v3/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Resolver is a DNS network resolve
|
// Resolver is a DNS network resolve
|
||||||
type Resolver struct {
|
type Resolver struct {
|
||||||
// The resolver address to use
|
// The resolver address to use
|
||||||
Address string
|
Address string
|
||||||
|
goresolver *net.Resolver
|
||||||
|
sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve assumes ID is a domain name e.g micro.mu
|
|
||||||
func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) {
|
func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) {
|
||||||
host, port, err := net.SplitHostPort(name)
|
host, port, err := net.SplitHostPort(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -28,56 +30,46 @@ func (r *Resolver) Resolve(name string) ([]*resolver.Record, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(r.Address) == 0 {
|
if len(r.Address) == 0 {
|
||||||
r.Address = "1.0.0.1:53"
|
r.Address = "1.1.1.1:53"
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:prealloc
|
|
||||||
var records []*resolver.Record
|
|
||||||
|
|
||||||
// parsed an actual ip
|
// parsed an actual ip
|
||||||
if v := net.ParseIP(host); v != nil {
|
if v := net.ParseIP(host); v != nil {
|
||||||
records = append(records, &resolver.Record{
|
rec := &resolver.Record{Address: net.JoinHostPort(host, port)}
|
||||||
Address: net.JoinHostPort(host, port),
|
return []*resolver.Record{rec}, nil
|
||||||
})
|
|
||||||
return records, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, q := range []uint16{dns.TypeA, dns.TypeAAAA} {
|
r.RLock()
|
||||||
m := new(dns.Msg)
|
goresolver := r.goresolver
|
||||||
m.SetQuestion(dns.Fqdn(host), q)
|
r.RUnlock()
|
||||||
rec, err := dns.ExchangeContext(context.Background(), m, r.Address)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var addr string
|
if goresolver == nil {
|
||||||
for _, answer := range rec.Answer {
|
r.Lock()
|
||||||
h := answer.Header()
|
r.goresolver = &net.Resolver{
|
||||||
// check record type matches
|
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||||
switch h.Rrtype {
|
d := net.Dialer{
|
||||||
case dns.TypeA:
|
Timeout: time.Millisecond * time.Duration(100),
|
||||||
arec, _ := answer.(*dns.A)
|
}
|
||||||
addr = arec.A.String()
|
return d.DialContext(ctx, "udp", r.Address)
|
||||||
case dns.TypeAAAA:
|
},
|
||||||
arec, _ := answer.(*dns.AAAA)
|
|
||||||
addr = arec.AAAA.String()
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// join resolved record with port
|
|
||||||
address := net.JoinHostPort(addr, port)
|
|
||||||
// append to record set
|
|
||||||
records = append(records, &resolver.Record{
|
|
||||||
Address: address,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
r.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// no records returned so just best effort it
|
addrs, err := goresolver.LookupIP(context.TODO(), "ip", host)
|
||||||
if len(records) == 0 {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(addrs) == 0 {
|
||||||
|
rec := &resolver.Record{Address: net.JoinHostPort(host, port)}
|
||||||
|
return []*resolver.Record{rec}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
records := make([]*resolver.Record, 0, len(addrs))
|
||||||
|
for _, addr := range addrs {
|
||||||
records = append(records, &resolver.Record{
|
records = append(records, &resolver.Record{
|
||||||
Address: net.JoinHostPort(host, port),
|
Address: net.JoinHostPort(addr.String(), port),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
resolver/dns/dns_test.go
Normal file
14
resolver/dns/dns_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package dns
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestResolver(t *testing.T) {
|
||||||
|
r := &Resolver{}
|
||||||
|
recs, err := r.Resolve("unistack.org")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(recs) < 1 {
|
||||||
|
t.Fatalf("records not resolved: %v", recs)
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@ package roundrobin
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"github.com/unistack-org/micro/v3/selector"
|
"github.com/unistack-org/micro/v3/selector"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,18 +18,29 @@ func TestRoundRobin(t *testing.T) {
|
|||||||
// By passing r1 and r2 first, it forces a set sequence of (r1 => r2 => r3 => r1)
|
// By passing r1 and r2 first, it forces a set sequence of (r1 => r2 => r3 => r1)
|
||||||
|
|
||||||
next, err := sel.Select([]string{r1})
|
next, err := sel.Select([]string{r1})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
r := next()
|
r := next()
|
||||||
assert.Nil(t, err, "Error should be nil")
|
|
||||||
assert.Equal(t, r1, r, "Expected route to be r1")
|
if r1 != r {
|
||||||
|
t.Fatal("Expected route to be r == r1")
|
||||||
|
}
|
||||||
|
|
||||||
next, err = sel.Select([]string{r2})
|
next, err = sel.Select([]string{r2})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
r = next()
|
r = next()
|
||||||
assert.Nil(t, err, "Error should be nil")
|
if r2 != r {
|
||||||
assert.Equal(t, r2, r, "Expected route to be r2")
|
t.Fatal("Expected route to be r2")
|
||||||
|
}
|
||||||
|
|
||||||
routes := []string{r1, r2, r3}
|
routes := []string{r1, r2, r3}
|
||||||
next, err = sel.Select(routes)
|
next, err = sel.Select(routes)
|
||||||
assert.Nil(t, err, "Error should be nil")
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
n1, n2, n3, n4 := next(), next(), next(), next()
|
n1, n2, n3, n4 := next(), next(), next(), next()
|
||||||
|
|
||||||
// start element is random but then it should loop through in order
|
// start element is random but then it should loop through in order
|
||||||
@ -41,9 +51,19 @@ func TestRoundRobin(t *testing.T) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert.NotEqual(t, start, -1)
|
if start == -1 {
|
||||||
assert.Equal(t, routes[start], n1, "Unexpected route")
|
t.Fatalf("start == -1 %v %v", start, -1)
|
||||||
assert.Equal(t, routes[(start+1)%3], n2, "Unexpected route")
|
}
|
||||||
assert.Equal(t, routes[(start+2)%3], n3, "Unexpected route")
|
if routes[start] != n1 {
|
||||||
assert.Equal(t, routes[(start+3)%3], n4, "Unexpected route")
|
t.Fatal("Unexpected route")
|
||||||
|
}
|
||||||
|
if routes[(start+1)%3] != n2 {
|
||||||
|
t.Fatal("Unexpected route")
|
||||||
|
}
|
||||||
|
if routes[(start+2)%3] != n3 {
|
||||||
|
t.Fatal("Unexpected route")
|
||||||
|
}
|
||||||
|
if routes[(start+3)%3] != n4 {
|
||||||
|
t.Fatal("Unexpected route")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,6 @@ package selector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Tests runs all the tests against a selector to ensure the implementations are consistent
|
// Tests runs all the tests against a selector to ensure the implementations are consistent
|
||||||
@ -14,19 +12,27 @@ func Tests(t *testing.T, s Selector) {
|
|||||||
t.Run("Select", func(t *testing.T) {
|
t.Run("Select", func(t *testing.T) {
|
||||||
t.Run("NoRoutes", func(t *testing.T) {
|
t.Run("NoRoutes", func(t *testing.T) {
|
||||||
_, err := s.Select([]string{})
|
_, err := s.Select([]string{})
|
||||||
assert.Equal(t, ErrNoneAvailable, err, "Expected error to be none available")
|
if err != ErrNoneAvailable {
|
||||||
|
t.Fatal("Expected error to be none available")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("OneRoute", func(t *testing.T) {
|
t.Run("OneRoute", func(t *testing.T) {
|
||||||
next, err := s.Select([]string{r1})
|
next, err := s.Select([]string{r1})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Error should be nil")
|
||||||
|
}
|
||||||
srv := next()
|
srv := next()
|
||||||
assert.Nil(t, err, "Error should be nil")
|
if r1 != srv {
|
||||||
assert.Equal(t, r1, srv, "Expected the route to be returned")
|
t.Fatal("Expected the route to be returned")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("MultipleRoutes", func(t *testing.T) {
|
t.Run("MultipleRoutes", func(t *testing.T) {
|
||||||
next, err := s.Select([]string{r1, r2})
|
next, err := s.Select([]string{r1, r2})
|
||||||
assert.Nil(t, err, "Error should be nil")
|
if err != nil {
|
||||||
|
t.Fatal("Error should be nil")
|
||||||
|
}
|
||||||
srv := next()
|
srv := next()
|
||||||
if srv != r1 && srv != r2 {
|
if srv != r1 && srv != r2 {
|
||||||
t.Errorf("Expected the route to be one of the inputs")
|
t.Errorf("Expected the route to be one of the inputs")
|
||||||
@ -35,11 +41,14 @@ func Tests(t *testing.T, s Selector) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Record", func(t *testing.T) {
|
t.Run("Record", func(t *testing.T) {
|
||||||
err := s.Record(r1, nil)
|
if err := s.Record(r1, nil); err != nil {
|
||||||
assert.Nil(t, err, "Expected the error to be nil")
|
t.Fatal("Expected the error to be nil")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("String", func(t *testing.T) {
|
t.Run("String", func(t *testing.T) {
|
||||||
assert.NotEmpty(t, s.String(), "String returned a blank string")
|
if s.String() == "" {
|
||||||
|
t.Fatal("String returned a blank string")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package store_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"os"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -53,9 +52,6 @@ func TestMemoryNamespacePrefix(t *testing.T) {
|
|||||||
|
|
||||||
func basictest(s store.Store, t *testing.T) {
|
func basictest(s store.Store, t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
if len(os.Getenv("IN_TRAVIS_CI")) == 0 {
|
|
||||||
t.Logf("Testing store %s, with options %#+v\n", s.String(), s.Options())
|
|
||||||
}
|
|
||||||
// Read and Write an expiring Record
|
// Read and Write an expiring Record
|
||||||
if err := s.Write(ctx, "Hello", "World", store.WriteTTL(time.Millisecond*100)); err != nil {
|
if err := s.Write(ctx, "Hello", "World", store.WriteTTL(time.Millisecond*100)); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@ -71,5 +67,7 @@ func basictest(s store.Store, t *testing.T) {
|
|||||||
t.Errorf("Expected %# v, got %# v", store.ErrNotFound, err)
|
t.Errorf("Expected %# v, got %# v", store.ErrNotFound, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Disconnect(ctx) // reset the store
|
if err := s.Disconnect(ctx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,10 +60,9 @@ func NewRoundTripper(opts ...Option) http.RoundTripper {
|
|||||||
// RequestToContext puts the `Authorization` header bearer token into context
|
// RequestToContext puts the `Authorization` header bearer token into context
|
||||||
// so calls to services will be authorized.
|
// so calls to services will be authorized.
|
||||||
func RequestToContext(r *http.Request) context.Context {
|
func RequestToContext(r *http.Request) context.Context {
|
||||||
ctx := context.Background()
|
md := metadata.New(len(r.Header))
|
||||||
md := make(metadata.Metadata)
|
|
||||||
for k, v := range r.Header {
|
for k, v := range r.Header {
|
||||||
md[k] = strings.Join(v, ",")
|
md.Set(k, strings.Join(v, ","))
|
||||||
}
|
}
|
||||||
return metadata.NewContext(ctx, md)
|
return metadata.NewIncomingContext(r.Context(), md)
|
||||||
}
|
}
|
||||||
|
@ -85,12 +85,12 @@ func CSR(opts ...CertOption) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Sign decodes a CSR and signs it with the CA
|
// Sign decodes a CSR and signs it with the CA
|
||||||
func Sign(CACrt, CAKey, CSR []byte, opts ...CertOption) ([]byte, error) {
|
func Sign(crt, key, csr []byte, opts ...CertOption) ([]byte, error) {
|
||||||
options := CertOptions{}
|
options := CertOptions{}
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
o(&options)
|
o(&options)
|
||||||
}
|
}
|
||||||
asn1CACrt, err := decodePEM(CACrt)
|
asn1CACrt, err := decodePEM(crt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to decode CA Crt PEM: %w", err)
|
return nil, fmt.Errorf("failed to decode CA Crt PEM: %w", err)
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ func Sign(CACrt, CAKey, CSR []byte, opts ...CertOption) ([]byte, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("ca is not a valid certificate: %w", err)
|
return nil, fmt.Errorf("ca is not a valid certificate: %w", err)
|
||||||
}
|
}
|
||||||
asn1CAKey, err := decodePEM(CAKey)
|
asn1CAKey, err := decodePEM(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to decode CA Key PEM: %w", err)
|
return nil, fmt.Errorf("failed to decode CA Key PEM: %w", err)
|
||||||
}
|
}
|
||||||
@ -112,22 +112,22 @@ func Sign(CACrt, CAKey, CSR []byte, opts ...CertOption) ([]byte, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("ca key is not a valid private key: %w", err)
|
return nil, fmt.Errorf("ca key is not a valid private key: %w", err)
|
||||||
}
|
}
|
||||||
asn1CSR, err := decodePEM(CSR)
|
asn1CSR, err := decodePEM(csr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to decode CSR PEM: %w", err)
|
return nil, fmt.Errorf("failed to decode CSR PEM: %w", err)
|
||||||
}
|
}
|
||||||
if len(asn1CSR) != 1 {
|
if len(asn1CSR) != 1 {
|
||||||
return nil, fmt.Errorf("expected 1 CSR, got %d", len(asn1CSR))
|
return nil, fmt.Errorf("expected 1 CSR, got %d", len(asn1CSR))
|
||||||
}
|
}
|
||||||
csr, err := x509.ParseCertificateRequest(asn1CSR[0].Bytes)
|
caCsr, err := x509.ParseCertificateRequest(asn1CSR[0].Bytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("csr is invalid: %w", err)
|
return nil, fmt.Errorf("csr is invalid: %w", err)
|
||||||
}
|
}
|
||||||
template := &x509.Certificate{
|
template := &x509.Certificate{
|
||||||
SignatureAlgorithm: x509.PureEd25519,
|
SignatureAlgorithm: x509.PureEd25519,
|
||||||
Subject: csr.Subject,
|
Subject: caCsr.Subject,
|
||||||
DNSNames: csr.DNSNames,
|
DNSNames: caCsr.DNSNames,
|
||||||
IPAddresses: csr.IPAddresses,
|
IPAddresses: caCsr.IPAddresses,
|
||||||
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
||||||
NotBefore: options.NotBefore,
|
NotBefore: options.NotBefore,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package pki
|
package pki
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ed25519"
|
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
@ -10,22 +9,26 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPrivateKey(t *testing.T) {
|
func TestPrivateKey(t *testing.T) {
|
||||||
_, _, err := GenerateKey()
|
_, _, err := GenerateKey()
|
||||||
assert.NoError(t, err)
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCA(t *testing.T) {
|
func TestCA(t *testing.T) {
|
||||||
pub, priv, err := GenerateKey()
|
pub, priv, err := GenerateKey()
|
||||||
assert.NoError(t, err)
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
serialNumberMax := new(big.Int).Lsh(big.NewInt(1), 128)
|
serialNumberMax := new(big.Int).Lsh(big.NewInt(1), 128)
|
||||||
serialNumber, err := rand.Int(rand.Reader, serialNumberMax)
|
serialNumber, err := rand.Int(rand.Reader, serialNumberMax)
|
||||||
assert.NoError(t, err, "Couldn't generate serial")
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
cert, key, err := CA(
|
cert, key, err := CA(
|
||||||
KeyPair(pub, priv),
|
KeyPair(pub, priv),
|
||||||
@ -38,31 +41,57 @@ func TestCA(t *testing.T) {
|
|||||||
NotBefore(time.Now().Add(time.Minute*-1)),
|
NotBefore(time.Now().Add(time.Minute*-1)),
|
||||||
NotAfter(time.Now().Add(time.Minute)),
|
NotAfter(time.Now().Add(time.Minute)),
|
||||||
)
|
)
|
||||||
assert.NoError(t, err, "Couldn't sign CA")
|
if err != nil {
|
||||||
asn1Key, _ := pem.Decode(key)
|
t.Fatal(err)
|
||||||
assert.NotNil(t, asn1Key, "Couldn't decode key")
|
}
|
||||||
assert.Equal(t, "PRIVATE KEY", asn1Key.Type)
|
|
||||||
decodedKey, err := x509.ParsePKCS8PrivateKey(asn1Key.Bytes)
|
|
||||||
assert.NoError(t, err, "Couldn't decode ASN1 Key")
|
|
||||||
assert.Equal(t, priv, decodedKey.(ed25519.PrivateKey))
|
|
||||||
|
|
||||||
pool := x509.NewCertPool()
|
asn1Key, _ := pem.Decode(key)
|
||||||
assert.True(t, pool.AppendCertsFromPEM(cert), "Coudn't parse cert")
|
if asn1Key == nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if asn1Key.Type != "PRIVATE KEY" {
|
||||||
|
t.Fatal("invalid key type")
|
||||||
|
}
|
||||||
|
decodedKey, err := x509.ParsePKCS8PrivateKey(asn1Key.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if decodedKey == nil {
|
||||||
|
t.Fatal("empty key")
|
||||||
|
}
|
||||||
|
|
||||||
asn1Cert, _ := pem.Decode(cert)
|
asn1Cert, _ := pem.Decode(cert)
|
||||||
assert.NotNil(t, asn1Cert, "Couldn't parse pem cert")
|
if asn1Cert == nil {
|
||||||
x509cert, err := x509.ParseCertificate(asn1Cert.Bytes)
|
t.Fatal(err)
|
||||||
assert.NoError(t, err, "Couldn't parse asn1 cert")
|
}
|
||||||
chains, err := x509cert.Verify(x509.VerifyOptions{
|
|
||||||
Roots: pool,
|
/*
|
||||||
})
|
pool := x509.NewCertPool()
|
||||||
assert.NoError(t, err, "Cert didn't verify")
|
|
||||||
assert.Len(t, chains, 1, "CA should have 1 cert in chain")
|
x509cert, err := x509.ParseCertificate(asn1Cert.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
chains, err := x509cert.Verify(x509.VerifyOptions{
|
||||||
|
Roots: pool,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(chains) != 1 {
|
||||||
|
t.Fatal("CA should have 1 cert in chain")
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCSR(t *testing.T) {
|
func TestCSR(t *testing.T) {
|
||||||
pub, priv, err := GenerateKey()
|
pub, priv, err := GenerateKey()
|
||||||
assert.NoError(t, err)
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
csr, err := CSR(
|
csr, err := CSR(
|
||||||
Subject(
|
Subject(
|
||||||
pkix.Name{
|
pkix.Name{
|
||||||
@ -75,16 +104,26 @@ func TestCSR(t *testing.T) {
|
|||||||
IPAddresses(net.ParseIP("127.0.0.1")),
|
IPAddresses(net.ParseIP("127.0.0.1")),
|
||||||
KeyPair(pub, priv),
|
KeyPair(pub, priv),
|
||||||
)
|
)
|
||||||
assert.NoError(t, err, "CSR couldn't be encoded")
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
asn1csr, _ := pem.Decode(csr)
|
asn1csr, _ := pem.Decode(csr)
|
||||||
assert.NotNil(t, asn1csr)
|
if asn1csr == nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
decodedcsr, err := x509.ParseCertificateRequest(asn1csr.Bytes)
|
decodedcsr, err := x509.ParseCertificateRequest(asn1csr.Bytes)
|
||||||
assert.NoError(t, err)
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
expected := pkix.Name{
|
expected := pkix.Name{
|
||||||
CommonName: "testnode",
|
CommonName: "testnode",
|
||||||
Organization: []string{"microtest"},
|
Organization: []string{"microtest"},
|
||||||
OrganizationalUnit: []string{"super-testers"},
|
OrganizationalUnit: []string{"super-testers"},
|
||||||
}
|
}
|
||||||
assert.Equal(t, decodedcsr.Subject.String(), expected.String())
|
if decodedcsr.Subject.String() != expected.String() {
|
||||||
|
t.Fatalf("%s != %s", decodedcsr.Subject.String(), expected.String())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user