remove api handlers and proto
This commit is contained in:
@@ -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/micro/go-micro/v3/api"
|
|
||||||
"github.com/micro/go-micro/v3/api/handler"
|
|
||||||
api "github.com/micro/go-micro/v3/api/proto"
|
|
||||||
"github.com/micro/go-micro/v3/client"
|
|
||||||
"github.com/micro/go-micro/v3/errors"
|
|
||||||
"github.com/micro/go-micro/v3/util/ctx"
|
|
||||||
"github.com/micro/go-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"
|
|
||||||
|
|
||||||
api "github.com/micro/go-micro/v3/api/proto"
|
|
||||||
"github.com/oxtoacart/bpool"
|
|
||||||
)
|
|
||||||
|
|
||||||
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,46 +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/micro/go-micro/v3/api/handler"
|
|
||||||
proto "github.com/micro/go-micro/v3/api/proto"
|
|
||||||
"github.com/micro/go-micro/v3/util/ctx"
|
|
||||||
"github.com/oxtoacart/bpool"
|
|
||||||
)
|
|
||||||
|
|
||||||
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,112 +0,0 @@
|
|||||||
package rpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto"
|
|
||||||
go_api "github.com/micro/go-micro/v3/api/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRequestPayloadFromRequest(t *testing.T) {
|
|
||||||
|
|
||||||
// our test event so that we can validate serialising / deserializing of true protos works
|
|
||||||
protoEvent := go_api.Event{
|
|
||||||
Name: "Test",
|
|
||||||
}
|
|
||||||
|
|
||||||
protoBytes, err := proto.Marshal(&protoEvent)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("Failed to marshal proto", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonBytes, err := json.Marshal(protoEvent)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal("Failed to marshal proto to JSON ", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonUrlBytes := []byte(`{"key1":"val1","key2":"val2","name":"Test"}`)
|
|
||||||
|
|
||||||
t.Run("extracting a json from a POST request with url params", func(t *testing.T) {
|
|
||||||
r, err := http.NewRequest("POST", "http://localhost/my/path?key1=val1&key2=val2", bytes.NewReader(jsonBytes))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to created http.Request: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
extByte, err := requestPayload(r)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to extract payload from request: %v", err)
|
|
||||||
}
|
|
||||||
if string(extByte) != string(jsonUrlBytes) {
|
|
||||||
t.Fatalf("Expected %v and %v to match", string(extByte), jsonUrlBytes)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("extracting a proto from a POST request", func(t *testing.T) {
|
|
||||||
r, err := http.NewRequest("POST", "http://localhost/my/path", bytes.NewReader(protoBytes))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to created http.Request: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
extByte, err := requestPayload(r)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to extract payload from request: %v", err)
|
|
||||||
}
|
|
||||||
if string(extByte) != string(protoBytes) {
|
|
||||||
t.Fatalf("Expected %v and %v to match", string(extByte), string(protoBytes))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("extracting JSON from a POST request", func(t *testing.T) {
|
|
||||||
r, err := http.NewRequest("POST", "http://localhost/my/path", bytes.NewReader(jsonBytes))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to created http.Request: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
extByte, err := requestPayload(r)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to extract payload from request: %v", err)
|
|
||||||
}
|
|
||||||
if string(extByte) != string(jsonBytes) {
|
|
||||||
t.Fatalf("Expected %v and %v to match", string(extByte), string(jsonBytes))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("extracting params from a GET request", func(t *testing.T) {
|
|
||||||
|
|
||||||
r, err := http.NewRequest("GET", "http://localhost/my/path", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to created http.Request: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
q := r.URL.Query()
|
|
||||||
q.Add("name", "Test")
|
|
||||||
r.URL.RawQuery = q.Encode()
|
|
||||||
|
|
||||||
extByte, err := requestPayload(r)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to extract payload from request: %v", err)
|
|
||||||
}
|
|
||||||
if string(extByte) != string(jsonBytes) {
|
|
||||||
t.Fatalf("Expected %v and %v to match", string(extByte), string(jsonBytes))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("GET request with no params", func(t *testing.T) {
|
|
||||||
|
|
||||||
r, err := http.NewRequest("GET", "http://localhost/my/path", nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to created http.Request: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
extByte, err := requestPayload(r)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Failed to extract payload from request: %v", err)
|
|
||||||
}
|
|
||||||
if string(extByte) != "" {
|
|
||||||
t.Fatalf("Expected %v and %v to match", string(extByte), "")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
@@ -1,181 +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/micro/go-micro/v3/api"
|
|
||||||
"github.com/micro/go-micro/v3/api/handler"
|
|
||||||
"github.com/micro/go-micro/v3/registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
|
||||||
var nodes []*registry.Node
|
|
||||||
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,335 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. 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
|
|
||||||
|
|
||||||
type Pair struct {
|
|
||||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
|
||||||
Values []string `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"`
|
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
|
||||||
XXX_unrecognized []byte `json:"-"`
|
|
||||||
XXX_sizecache int32 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Pair) Reset() { *m = Pair{} }
|
|
||||||
func (m *Pair) String() string { return proto.CompactTextString(m) }
|
|
||||||
func (*Pair) ProtoMessage() {}
|
|
||||||
func (*Pair) Descriptor() ([]byte, []int) {
|
|
||||||
return fileDescriptor_2df576b66d12087a, []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Pair) XXX_Unmarshal(b []byte) error {
|
|
||||||
return xxx_messageInfo_Pair.Unmarshal(m, b)
|
|
||||||
}
|
|
||||||
func (m *Pair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
|
||||||
return xxx_messageInfo_Pair.Marshal(b, m, deterministic)
|
|
||||||
}
|
|
||||||
func (m *Pair) XXX_Merge(src proto.Message) {
|
|
||||||
xxx_messageInfo_Pair.Merge(m, src)
|
|
||||||
}
|
|
||||||
func (m *Pair) XXX_Size() int {
|
|
||||||
return xxx_messageInfo_Pair.Size(m)
|
|
||||||
}
|
|
||||||
func (m *Pair) XXX_DiscardUnknown() {
|
|
||||||
xxx_messageInfo_Pair.DiscardUnknown(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
var xxx_messageInfo_Pair proto.InternalMessageInfo
|
|
||||||
|
|
||||||
func (m *Pair) GetKey() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Key
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Pair) GetValues() []string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Values
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// A HTTP request as RPC
|
|
||||||
// Forward by the api handler
|
|
||||||
type Request struct {
|
|
||||||
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"`
|
|
||||||
Url string `protobuf:"bytes,7,opt,name=url,proto3" json:"url,omitempty"`
|
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
|
||||||
XXX_unrecognized []byte `json:"-"`
|
|
||||||
XXX_sizecache int32 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) Reset() { *m = Request{} }
|
|
||||||
func (m *Request) String() string { return proto.CompactTextString(m) }
|
|
||||||
func (*Request) ProtoMessage() {}
|
|
||||||
func (*Request) Descriptor() ([]byte, []int) {
|
|
||||||
return fileDescriptor_2df576b66d12087a, []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) XXX_Unmarshal(b []byte) error {
|
|
||||||
return xxx_messageInfo_Request.Unmarshal(m, b)
|
|
||||||
}
|
|
||||||
func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
|
||||||
return xxx_messageInfo_Request.Marshal(b, m, deterministic)
|
|
||||||
}
|
|
||||||
func (m *Request) XXX_Merge(src proto.Message) {
|
|
||||||
xxx_messageInfo_Request.Merge(m, src)
|
|
||||||
}
|
|
||||||
func (m *Request) XXX_Size() int {
|
|
||||||
return xxx_messageInfo_Request.Size(m)
|
|
||||||
}
|
|
||||||
func (m *Request) XXX_DiscardUnknown() {
|
|
||||||
xxx_messageInfo_Request.DiscardUnknown(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
var xxx_messageInfo_Request proto.InternalMessageInfo
|
|
||||||
|
|
||||||
func (m *Request) GetMethod() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Method
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) GetPath() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Path
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) GetHeader() map[string]*Pair {
|
|
||||||
if m != nil {
|
|
||||||
return m.Header
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) GetGet() map[string]*Pair {
|
|
||||||
if m != nil {
|
|
||||||
return m.Get
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) GetPost() map[string]*Pair {
|
|
||||||
if m != nil {
|
|
||||||
return m.Post
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) GetBody() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Body
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Request) GetUrl() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Url
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// A HTTP response as RPC
|
|
||||||
// Expected response for the api handler
|
|
||||||
type Response struct {
|
|
||||||
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"`
|
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
|
||||||
XXX_unrecognized []byte `json:"-"`
|
|
||||||
XXX_sizecache int32 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Response) Reset() { *m = Response{} }
|
|
||||||
func (m *Response) String() string { return proto.CompactTextString(m) }
|
|
||||||
func (*Response) ProtoMessage() {}
|
|
||||||
func (*Response) Descriptor() ([]byte, []int) {
|
|
||||||
return fileDescriptor_2df576b66d12087a, []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Response) XXX_Unmarshal(b []byte) error {
|
|
||||||
return xxx_messageInfo_Response.Unmarshal(m, b)
|
|
||||||
}
|
|
||||||
func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
|
||||||
return xxx_messageInfo_Response.Marshal(b, m, deterministic)
|
|
||||||
}
|
|
||||||
func (m *Response) XXX_Merge(src proto.Message) {
|
|
||||||
xxx_messageInfo_Response.Merge(m, src)
|
|
||||||
}
|
|
||||||
func (m *Response) XXX_Size() int {
|
|
||||||
return xxx_messageInfo_Response.Size(m)
|
|
||||||
}
|
|
||||||
func (m *Response) XXX_DiscardUnknown() {
|
|
||||||
xxx_messageInfo_Response.DiscardUnknown(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
var xxx_messageInfo_Response proto.InternalMessageInfo
|
|
||||||
|
|
||||||
func (m *Response) GetStatusCode() int32 {
|
|
||||||
if m != nil {
|
|
||||||
return m.StatusCode
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Response) GetHeader() map[string]*Pair {
|
|
||||||
if m != nil {
|
|
||||||
return m.Header
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Response) GetBody() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Body
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// A HTTP event as RPC
|
|
||||||
// Forwarded by the event handler
|
|
||||||
type Event struct {
|
|
||||||
// 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"`
|
|
||||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
|
||||||
XXX_unrecognized []byte `json:"-"`
|
|
||||||
XXX_sizecache int32 `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Event) Reset() { *m = Event{} }
|
|
||||||
func (m *Event) String() string { return proto.CompactTextString(m) }
|
|
||||||
func (*Event) ProtoMessage() {}
|
|
||||||
func (*Event) Descriptor() ([]byte, []int) {
|
|
||||||
return fileDescriptor_2df576b66d12087a, []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Event) XXX_Unmarshal(b []byte) error {
|
|
||||||
return xxx_messageInfo_Event.Unmarshal(m, b)
|
|
||||||
}
|
|
||||||
func (m *Event) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
|
||||||
return xxx_messageInfo_Event.Marshal(b, m, deterministic)
|
|
||||||
}
|
|
||||||
func (m *Event) XXX_Merge(src proto.Message) {
|
|
||||||
xxx_messageInfo_Event.Merge(m, src)
|
|
||||||
}
|
|
||||||
func (m *Event) XXX_Size() int {
|
|
||||||
return xxx_messageInfo_Event.Size(m)
|
|
||||||
}
|
|
||||||
func (m *Event) XXX_DiscardUnknown() {
|
|
||||||
xxx_messageInfo_Event.DiscardUnknown(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
var xxx_messageInfo_Event proto.InternalMessageInfo
|
|
||||||
|
|
||||||
func (m *Event) GetName() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Name
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Event) GetId() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Id
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Event) GetTimestamp() int64 {
|
|
||||||
if m != nil {
|
|
||||||
return m.Timestamp
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Event) GetHeader() map[string]*Pair {
|
|
||||||
if m != nil {
|
|
||||||
return m.Header
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Event) GetData() string {
|
|
||||||
if m != nil {
|
|
||||||
return m.Data
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
proto.RegisterType((*Pair)(nil), "go.api.Pair")
|
|
||||||
proto.RegisterType((*Request)(nil), "go.api.Request")
|
|
||||||
proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Request.GetEntry")
|
|
||||||
proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Request.HeaderEntry")
|
|
||||||
proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Request.PostEntry")
|
|
||||||
proto.RegisterType((*Response)(nil), "go.api.Response")
|
|
||||||
proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Response.HeaderEntry")
|
|
||||||
proto.RegisterType((*Event)(nil), "go.api.Event")
|
|
||||||
proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Event.HeaderEntry")
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { proto.RegisterFile("api/proto/api.proto", fileDescriptor_2df576b66d12087a) }
|
|
||||||
|
|
||||||
var fileDescriptor_2df576b66d12087a = []byte{
|
|
||||||
// 393 bytes of a gzipped FileDescriptorProto
|
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xcd, 0xce, 0xd3, 0x30,
|
|
||||||
0x10, 0x54, 0xe2, 0x24, 0x6d, 0xb6, 0x08, 0x21, 0x23, 0x21, 0x53, 0x2a, 0x54, 0xe5, 0x54, 0x21,
|
|
||||||
0x91, 0x42, 0xcb, 0x01, 0x71, 0x85, 0xaa, 0x1c, 0x2b, 0xbf, 0x81, 0xab, 0x58, 0x6d, 0x44, 0x13,
|
|
||||||
0x9b, 0xd8, 0xa9, 0xd4, 0x87, 0xe3, 0xc0, 0x63, 0xf0, 0x36, 0xc8, 0x1b, 0xf7, 0xe7, 0xab, 0xfa,
|
|
||||||
0x5d, 0xbe, 0xaf, 0xb7, 0x89, 0x3d, 0x3b, 0x3b, 0x3b, 0xeb, 0xc0, 0x6b, 0xa1, 0xcb, 0xa9, 0x6e,
|
|
||||||
0x94, 0x55, 0x53, 0xa1, 0xcb, 0x1c, 0x11, 0x4d, 0x36, 0x2a, 0x17, 0xba, 0xcc, 0x3e, 0x41, 0xb4,
|
|
||||||
0x12, 0x65, 0x43, 0x5f, 0x01, 0xf9, 0x25, 0x0f, 0x2c, 0x18, 0x07, 0x93, 0x94, 0x3b, 0x48, 0xdf,
|
|
||||||
0x40, 0xb2, 0x17, 0xbb, 0x56, 0x1a, 0x16, 0x8e, 0xc9, 0x24, 0xe5, 0xfe, 0x2b, 0xfb, 0x4b, 0xa0,
|
|
||||||
0xc7, 0xe5, 0xef, 0x56, 0x1a, 0xeb, 0x38, 0x95, 0xb4, 0x5b, 0x55, 0xf8, 0x42, 0xff, 0x45, 0x29,
|
|
||||||
0x44, 0x5a, 0xd8, 0x2d, 0x0b, 0xf1, 0x14, 0x31, 0x9d, 0x43, 0xb2, 0x95, 0xa2, 0x90, 0x0d, 0x23,
|
|
||||||
0x63, 0x32, 0x19, 0xcc, 0xde, 0xe5, 0x9d, 0x85, 0xdc, 0x8b, 0xe5, 0x3f, 0xf1, 0x76, 0x51, 0xdb,
|
|
||||||
0xe6, 0xc0, 0x3d, 0x95, 0x7e, 0x00, 0xb2, 0x91, 0x96, 0x45, 0x58, 0xc1, 0xae, 0x2b, 0x96, 0xd2,
|
|
||||||
0x76, 0x74, 0x47, 0xa2, 0x1f, 0x21, 0xd2, 0xca, 0x58, 0x16, 0x23, 0xf9, 0xed, 0x35, 0x79, 0xa5,
|
|
||||||
0x8c, 0x67, 0x23, 0xcd, 0x79, 0x5c, 0xab, 0xe2, 0xc0, 0x92, 0xce, 0xa3, 0xc3, 0x2e, 0x85, 0xb6,
|
|
||||||
0xd9, 0xb1, 0x5e, 0x97, 0x42, 0xdb, 0xec, 0x86, 0x4b, 0x18, 0x5c, 0xf8, 0xba, 0x11, 0x53, 0x06,
|
|
||||||
0x31, 0x06, 0x83, 0xb3, 0x0e, 0x66, 0x2f, 0x8e, 0x6d, 0x5d, 0xaa, 0xbc, 0xbb, 0xfa, 0x16, 0x7e,
|
|
||||||
0x0d, 0x86, 0x3f, 0xa0, 0x7f, 0xb4, 0xfb, 0x0c, 0x95, 0x05, 0xa4, 0xa7, 0x39, 0x9e, 0x2e, 0x93,
|
|
||||||
0xfd, 0x09, 0xa0, 0xcf, 0xa5, 0xd1, 0xaa, 0x36, 0x92, 0xbe, 0x07, 0x30, 0x56, 0xd8, 0xd6, 0x7c,
|
|
||||||
0x57, 0x85, 0x44, 0xb5, 0x98, 0x5f, 0x9c, 0xd0, 0x2f, 0xa7, 0xc5, 0x85, 0x98, 0xec, 0xe8, 0x9c,
|
|
||||||
0x6c, 0xa7, 0x70, 0x73, 0x73, 0xc7, 0x78, 0xc9, 0x39, 0xde, 0xbb, 0x85, 0x99, 0xfd, 0x0b, 0x20,
|
|
||||||
0x5e, 0xec, 0x65, 0x8d, 0x5b, 0xac, 0x45, 0x25, 0xbd, 0x08, 0x62, 0xfa, 0x12, 0xc2, 0xb2, 0xf0,
|
|
||||||
0x6f, 0x2f, 0x2c, 0x0b, 0x3a, 0x82, 0xd4, 0x96, 0x95, 0x34, 0x56, 0x54, 0x1a, 0xfd, 0x10, 0x7e,
|
|
||||||
0x3e, 0xa0, 0x9f, 0x4f, 0xe3, 0x45, 0x0f, 0x1f, 0x0e, 0x36, 0x78, 0x6c, 0xb6, 0x42, 0x58, 0xc1,
|
|
||||||
0xe2, 0xae, 0xa9, 0xc3, 0x77, 0x9b, 0x6d, 0x9d, 0xe0, 0x0f, 0x3a, 0xff, 0x1f, 0x00, 0x00, 0xff,
|
|
||||||
0xff, 0xd4, 0x6d, 0x70, 0x51, 0xb7, 0x03, 0x00, 0x00,
|
|
||||||
}
|
|
@@ -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;
|
|
||||||
}
|
|
4
go.mod
4
go.mod
@@ -23,10 +23,10 @@ require (
|
|||||||
github.com/google/uuid v1.1.2
|
github.com/google/uuid v1.1.2
|
||||||
github.com/gorilla/handlers v1.4.2
|
github.com/gorilla/handlers v1.4.2
|
||||||
github.com/hpcloud/tail v1.0.0
|
github.com/hpcloud/tail v1.0.0
|
||||||
|
github.com/klauspost/cpuid v1.3.1 // indirect
|
||||||
github.com/kr/pretty v0.2.0
|
github.com/kr/pretty v0.2.0
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/miekg/dns v1.1.27
|
github.com/miekg/dns v1.1.27
|
||||||
github.com/minio/minio-go/v7 v7.0.5
|
|
||||||
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/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
|
||||||
@@ -37,6 +37,8 @@ require (
|
|||||||
go.etcd.io/bbolt v1.3.5
|
go.etcd.io/bbolt v1.3.5
|
||||||
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
|
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
|
||||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
golang.org/x/net v0.0.0-20200707034311-ab3426394381
|
||||||
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae // indirect
|
||||||
|
golang.org/x/text v0.3.3 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013
|
||||||
google.golang.org/grpc v1.27.0
|
google.golang.org/grpc v1.27.0
|
||||||
google.golang.org/protobuf v1.25.0
|
google.golang.org/protobuf v1.25.0
|
||||||
|
13
go.sum
13
go.sum
@@ -211,8 +211,6 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht
|
|||||||
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
@@ -249,12 +247,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
|
|||||||
github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
github.com/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||||
github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
|
github.com/miekg/dns v1.1.27 h1:aEH/kqUzUxGJ/UHcEKdJY+ugH6WEzsEBBSPa8zuy1aM=
|
||||||
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
github.com/miekg/dns v1.1.27/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
|
||||||
github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4=
|
|
||||||
github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw=
|
|
||||||
github.com/minio/minio-go/v7 v7.0.5 h1:I2NIJ2ojwJqD/YByemC1M59e1b4FW9kS7NlOar7HPV4=
|
|
||||||
github.com/minio/minio-go/v7 v7.0.5/go.mod h1:TA0CQCjJZHM5SJj9IjqR0NmpmQJ6bCbXifAJ3mUU6Hw=
|
|
||||||
github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU=
|
|
||||||
github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
||||||
@@ -324,8 +316,6 @@ github.com/rainycape/memcache v0.0.0-20150622160815-1031fa0ce2f2/go.mod h1:7tZKc
|
|||||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
|
|
||||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
|
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
|
||||||
@@ -557,8 +547,6 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
|
|||||||
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE=
|
||||||
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.44.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/ini.v1 v1.57.0 h1:9unxIsFcTt4I55uWluz+UmL95q4kdJ0buvQ1ZIqVQww=
|
|
||||||
gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
|
||||||
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw=
|
gopkg.in/ns1/ns1-go.v2 v2.0.0-20190730140822-b51389932cbc/go.mod h1:VV+3haRsgDiVLxyifmMBrBIuCWFBPYKbRssXB9z67Hw=
|
||||||
gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
|
gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
@@ -570,7 +558,6 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD
|
|||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/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=
|
||||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||||
|
Reference in New Issue
Block a user