You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by sp...@apache.org on 2021/05/31 02:07:07 UTC

[apisix-go-plugin-runner] branch master created (now cfb8bbf)

This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git.


      at cfb8bbf  fix: clean up sock file

This branch includes the following new commits:

     new d0e3a4e  Init commit
     new b4b6bc0  Add supported structure
     new e9937ce  feat: prepare conf
     new b2496e1  test: for main's version cmd
     new 7e9d6ab  feat: report error
     new d35ce28  refacor: rename method
     new 8dd97b2  feat: init cache according to the env
     new f00ec5e  chore: tweak error handling
     new e3d2617  fix: concurrent issues
     new 669598c  chore: tweak for test
     new 03e1181  feat: handle CodeBAD_REQUEST in error protocol
     new c0d1860  feat: add basic structure for HTTPReqCall
     new 38309c7  feat: record response
     new d8647f9  feat: extend pkg Request
     new d825c84  chore: pass lint
     new 65cbe80  feat: add Request.Header
     new f9169fb  chore: increase log level and add -race flag
     new 8e69bfa  perf: reuse objects
     new 56ca824  fix: miss pkg
     new 05f4082  feat: add Args
     new 4ad02de  feat: expose ConfToken method
     new cfb8bbf  fix: clean up sock file

The 22 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[apisix-go-plugin-runner] 21/22: feat: expose ConfToken method

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit 4ad02dec9e6d409344ca01a58944cf6b73881466
Author: spacewander <sp...@gmail.com>
AuthorDate: Fri May 28 10:21:45 2021 +0800

    feat: expose ConfToken method
---
 internal/plugin/plugin.go | 11 +++++++++--
 pkg/http/http.go          |  5 +++++
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go
index b88ade7..b7400b0 100644
--- a/internal/plugin/plugin.go
+++ b/internal/plugin/plugin.go
@@ -15,6 +15,7 @@
 package plugin
 
 import (
+	"context"
 	"net/http"
 
 	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
@@ -25,7 +26,7 @@ import (
 	pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http"
 )
 
-func handle(conf RuleConf, w http.ResponseWriter, r pkgHTTP.Request) error {
+func handle(conf RuleConf, ctx context.Context, w http.ResponseWriter, r pkgHTTP.Request) error {
 	return nil
 }
 
@@ -36,6 +37,10 @@ func reportAction(id uint32, req *inHTTP.Request, resp *inHTTP.Response) *flatbu
 		return builder
 	}
 
+	if req != nil && req.FetchChanges(id, builder) {
+		return builder
+	}
+
 	hrc.RespStart(builder)
 	hrc.RespAddId(builder, id)
 	res := hrc.RespEnd(builder)
@@ -55,7 +60,9 @@ func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
 	if err != nil {
 		return nil, err
 	}
-	err = handle(conf, resp, req)
+
+	ctx := context.Background()
+	err = handle(conf, ctx, resp, req)
 	if err != nil {
 		return nil, err
 	}
diff --git a/pkg/http/http.go b/pkg/http/http.go
index cfc4284..d7ca549 100644
--- a/pkg/http/http.go
+++ b/pkg/http/http.go
@@ -32,6 +32,11 @@ import (
 type Request interface {
 	// ID returns the request id
 	ID() uint32
+	// ConfToken returns the token represents the configuration of current route.
+	// Each route have its unique token, so we can use it to distinguish different
+	// route in the same plugin.
+	ConfToken() uint32
+
 	// SrcIP returns the client's IP
 	SrcIP() net.IP
 	// Method returns the HTTP method (GET, POST, PUT, etc.)

[apisix-go-plugin-runner] 20/22: feat: add Args

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit 05f40828227555cb4b1e181dcaddd2a70cfb543a
Author: spacewander <sp...@gmail.com>
AuthorDate: Fri May 28 10:18:14 2021 +0800

    feat: add Args
---
 internal/http/request.go      | 80 ++++++++++++++++++++++++++++++++++++++++++-
 internal/http/request_test.go | 66 ++++++++++++++++++++++++++++++++++-
 pkg/http/http.go              |  3 ++
 3 files changed, 147 insertions(+), 2 deletions(-)

diff --git a/internal/http/request.go b/internal/http/request.go
index c7f2e8d..33b9f74 100644
--- a/internal/http/request.go
+++ b/internal/http/request.go
@@ -17,6 +17,8 @@ package http
 import (
 	"net"
 	"net/http"
+	"net/url"
+	"reflect"
 	"sync"
 
 	pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http"
@@ -33,6 +35,9 @@ type Request struct {
 
 	hdr    *Header
 	rawHdr http.Header
+
+	args    url.Values
+	rawArgs url.Values
 }
 
 func (r *Request) ConfToken() uint32 {
@@ -79,13 +84,45 @@ func (r *Request) Header() pkgHTTP.Header {
 	return r.hdr
 }
 
+func cloneUrlValues(oldV url.Values) url.Values {
+	nv := 0
+	for _, vv := range oldV {
+		nv += len(vv)
+	}
+	sv := make([]string, nv)
+	newV := make(url.Values, len(oldV))
+	for k, vv := range oldV {
+		n := copy(sv, vv)
+		newV[k] = sv[:n:n]
+		sv = sv[n:]
+	}
+	return newV
+}
+
+func (r *Request) Args() url.Values {
+	if r.args == nil {
+		args := url.Values{}
+		size := r.r.ArgsLength()
+		obj := A6.TextEntry{}
+		for i := 0; i < size; i++ {
+			if r.r.Args(&obj, i) {
+				args.Add(string(obj.Name()), string(obj.Value()))
+			}
+		}
+		r.args = args
+		r.rawArgs = cloneUrlValues(args)
+	}
+	return r.args
+}
+
 func (r *Request) Reset() {
 	r.path = nil
 	r.hdr = nil
+	r.args = nil
 }
 
 func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
-	if r.path == nil && r.hdr == nil {
+	if r.path == nil && r.hdr == nil && r.args == nil {
 		return false
 	}
 
@@ -130,6 +167,44 @@ func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
 		hdrVec = builder.EndVector(size)
 	}
 
+	var argsVec flatbuffers.UOffsetT
+	if r.args != nil {
+		args := []flatbuffers.UOffsetT{}
+		oldArgs := r.rawArgs
+		newArgs := r.args
+		for n := range oldArgs {
+			if _, ok := newArgs[n]; !ok {
+				// deleted
+				name := builder.CreateString(n)
+				A6.TextEntryStart(builder)
+				A6.TextEntryAddName(builder, name)
+				te := A6.TextEntryEnd(builder)
+				args = append(args, te)
+			}
+		}
+		for n, v := range newArgs {
+			if raw, ok := oldArgs[n]; !ok || !reflect.DeepEqual(raw, v) {
+				// set / add
+				for _, vv := range v {
+					name := builder.CreateString(n)
+					value := builder.CreateString(vv)
+					A6.TextEntryStart(builder)
+					A6.TextEntryAddName(builder, name)
+					A6.TextEntryAddValue(builder, value)
+					te := A6.TextEntryEnd(builder)
+					args = append(args, te)
+				}
+			}
+		}
+		size := len(args)
+		hrc.RewriteStartArgsVector(builder, size)
+		for i := size - 1; i >= 0; i-- {
+			te := args[i]
+			builder.PrependUOffsetT(te)
+		}
+		argsVec = builder.EndVector(size)
+	}
+
 	hrc.RewriteStart(builder)
 	if path > 0 {
 		hrc.RewriteAddPath(builder, path)
@@ -137,6 +212,9 @@ func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
 	if hdrVec > 0 {
 		hrc.RewriteAddHeaders(builder, hdrVec)
 	}
+	if argsVec > 0 {
+		hrc.RewriteAddArgs(builder, argsVec)
+	}
 	rewrite := hrc.RewriteEnd(builder)
 
 	hrc.RespStart(builder)
diff --git a/internal/http/request_test.go b/internal/http/request_test.go
index accaa38..64f3ebf 100644
--- a/internal/http/request_test.go
+++ b/internal/http/request_test.go
@@ -17,6 +17,7 @@ package http
 import (
 	"net"
 	"net/http"
+	"net/url"
 	"testing"
 
 	"github.com/apache/apisix-go-plugin-runner/internal/util"
@@ -49,6 +50,7 @@ type reqOpt struct {
 	method  A6.Method
 	path    string
 	headers []pair
+	args    []pair
 }
 
 func buildReq(opt reqOpt) []byte {
@@ -78,7 +80,7 @@ func buildReq(opt reqOpt) []byte {
 			hdrs = append(hdrs, te)
 		}
 		size := len(hdrs)
-		hrc.StopStartHeadersVector(builder, size)
+		hrc.RewriteStartHeadersVector(builder, size)
 		for i := size - 1; i >= 0; i-- {
 			te := hdrs[i]
 			builder.PrependUOffsetT(te)
@@ -86,6 +88,28 @@ func buildReq(opt reqOpt) []byte {
 		hdrVec = builder.EndVector(size)
 	}
 
+	argsLen := len(opt.args)
+	var argsVec flatbuffers.UOffsetT
+	if argsLen > 0 {
+		args := []flatbuffers.UOffsetT{}
+		for _, v := range opt.args {
+			name := builder.CreateString(v.name)
+			value := builder.CreateString(v.value)
+			A6.TextEntryStart(builder)
+			A6.TextEntryAddName(builder, name)
+			A6.TextEntryAddValue(builder, value)
+			te := A6.TextEntryEnd(builder)
+			args = append(args, te)
+		}
+		size := len(args)
+		hrc.RewriteStartArgsVector(builder, size)
+		for i := size - 1; i >= 0; i-- {
+			te := args[i]
+			builder.PrependUOffsetT(te)
+		}
+		argsVec = builder.EndVector(size)
+	}
+
 	hrc.ReqStart(builder)
 	hrc.ReqAddId(builder, 233)
 	hrc.ReqAddConfToken(builder, 1)
@@ -101,6 +125,9 @@ func buildReq(opt reqOpt) []byte {
 	if hdrVec > 0 {
 		hrc.ReqAddHeaders(builder, hdrVec)
 	}
+	if argsVec > 0 {
+		hrc.ReqAddArgs(builder, argsVec)
+	}
 	r := hrc.ReqEnd(builder)
 	builder.Finish(r)
 	return builder.FinishedBytes()
@@ -187,3 +214,40 @@ func TestHeader(t *testing.T) {
 	}
 	assert.Equal(t, exp, res)
 }
+
+func TestArgs(t *testing.T) {
+	out := buildReq(reqOpt{args: []pair{
+		{"del", "a"},
+		{"override", "a"},
+		{"add", "a"},
+	}})
+	r := CreateRequest(out)
+	args := r.Args()
+	args.Add("add", "b")
+	args.Set("set", "a")
+	args.Set("override", "b")
+	args.Del("del")
+
+	builder := util.GetBuilder()
+	assert.True(t, r.FetchChanges(1, builder))
+	rewrite := getRewriteAction(t, builder)
+
+	exp := url.Values{}
+	exp.Set("set", "a")
+	exp.Set("override", "b")
+	exp.Add("add", "a")
+	exp.Add("add", "b")
+	deleted := ""
+	res := url.Values{}
+	for i := 0; i < rewrite.ArgsLength(); i++ {
+		e := &A6.TextEntry{}
+		rewrite.Args(e, i)
+		if e.Value() == nil {
+			deleted = string(e.Name())
+		} else {
+			res.Add(string(e.Name()), string(e.Value()))
+		}
+	}
+	assert.Equal(t, exp, res)
+	assert.Equal(t, "del", deleted)
+}
diff --git a/pkg/http/http.go b/pkg/http/http.go
index cbbceeb..cfc4284 100644
--- a/pkg/http/http.go
+++ b/pkg/http/http.go
@@ -17,6 +17,7 @@ package http
 import (
 	"net"
 	"net/http"
+	"net/url"
 )
 
 // Request represents the HTTP request received by APISIX.
@@ -43,6 +44,8 @@ type Request interface {
 	SetPath([]byte)
 	// Header returns the HTTP headers
 	Header() Header
+	// Args returns the query string
+	Args() url.Values
 }
 
 // Header is like http.Header, but only implements the subset of its methods

[apisix-go-plugin-runner] 09/22: fix: concurrent issues

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit e3d2617b44efc9268ac19a0498aea82c03ed567b
Author: spacewander <sp...@gmail.com>
AuthorDate: Thu May 20 17:01:05 2021 +0800

    fix: concurrent issues
---
 internal/plugin/conf.go                    | 19 ++++-------
 internal/plugin/conf_test.go               | 54 ++++++++++++++++++++++++++----
 internal/server/error.go                   | 11 +++---
 internal/server/error_test.go              |  6 ++--
 internal/server/server.go                  | 14 ++++++--
 internal/{server/error.go => util/pool.go} | 36 ++++++++------------
 6 files changed, 87 insertions(+), 53 deletions(-)

diff --git a/internal/plugin/conf.go b/internal/plugin/conf.go
index 6c79cb6..8e18ecc 100644
--- a/internal/plugin/conf.go
+++ b/internal/plugin/conf.go
@@ -16,9 +16,11 @@ package plugin
 
 import (
 	"strconv"
+	"sync/atomic"
 	"time"
 
 	"github.com/ReneKroon/ttlcache/v2"
+	"github.com/apache/apisix-go-plugin-runner/internal/util"
 	A6 "github.com/api7/ext-plugin-proto/go/A6"
 	pc "github.com/api7/ext-plugin-proto/go/A6/PrepareConf"
 	flatbuffers "github.com/google/flatbuffers/go"
@@ -31,8 +33,6 @@ type ConfEntry struct {
 type RuleConf []ConfEntry
 
 var (
-	builder = flatbuffers.NewBuilder(1024)
-
 	cache        *ttlcache.Cache
 	cacheCounter uint32 = 0
 )
@@ -41,20 +41,14 @@ func InitConfCache(ttl time.Duration) {
 	cache = ttlcache.NewCache()
 	cache.SetTTL(ttl)
 	cache.SkipTTLExtensionOnHit(false)
+	cacheCounter = 0
 }
 
 func genCacheToken() uint32 {
-	cacheCounter++
-	if cacheCounter == 0 {
-		// overflow, skip 0 which means none
-		cacheCounter++
-	}
-	return cacheCounter
+	return atomic.AddUint32(&cacheCounter, 1)
 }
 
-func PrepareConf(buf []byte) ([]byte, error) {
-	builder.Reset()
-
+func PrepareConf(buf []byte) (*flatbuffers.Builder, error) {
 	req := pc.GetRootAsReq(buf, 0)
 	entries := make(RuleConf, req.ConfLength())
 
@@ -72,11 +66,12 @@ func PrepareConf(buf []byte) ([]byte, error) {
 		return nil, err
 	}
 
+	builder := util.GetBuilder()
 	pc.RespStart(builder)
 	pc.RespAddConfToken(builder, token)
 	root := pc.RespEnd(builder)
 	builder.Finish(root)
-	return builder.FinishedBytes(), nil
+	return builder, nil
 }
 
 func GetRuleConf(token uint32) (RuleConf, error) {
diff --git a/internal/plugin/conf_test.go b/internal/plugin/conf_test.go
index b4135a5..aa2ded4 100644
--- a/internal/plugin/conf_test.go
+++ b/internal/plugin/conf_test.go
@@ -15,6 +15,8 @@
 package plugin
 
 import (
+	"sort"
+	"sync"
 	"testing"
 	"time"
 
@@ -34,15 +36,52 @@ func TestPrepareConf(t *testing.T) {
 	builder.Finish(root)
 	b := builder.FinishedBytes()
 
-	out, _ := PrepareConf(b)
+	bd, _ := PrepareConf(b)
+	out := bd.FinishedBytes()
 	resp := pc.GetRootAsResp(out, 0)
 	assert.Equal(t, uint32(1), resp.ConfToken())
 
-	out, _ = PrepareConf(b)
+	bd, _ = PrepareConf(b)
+	out = bd.FinishedBytes()
 	resp = pc.GetRootAsResp(out, 0)
 	assert.Equal(t, uint32(2), resp.ConfToken())
 }
 
+func TestPrepareConfConcurrently(t *testing.T) {
+	InitConfCache(10 * time.Millisecond)
+
+	builder := flatbuffers.NewBuilder(1024)
+	pc.ReqStart(builder)
+	root := pc.ReqEnd(builder)
+	builder.Finish(root)
+	b := builder.FinishedBytes()
+
+	n := 10
+	var wg sync.WaitGroup
+	res := make([][]byte, n)
+	for i := 0; i < n; i++ {
+		wg.Add(1)
+		go func(i int) {
+			bd, err := PrepareConf(b)
+			assert.Nil(t, err)
+			res[i] = bd.FinishedBytes()[:]
+			wg.Done()
+		}(i)
+	}
+	wg.Wait()
+
+	tokens := make([]int, n)
+	for i := 0; i < n; i++ {
+		resp := pc.GetRootAsResp(res[i], 0)
+		tokens[i] = int(resp.ConfToken())
+	}
+
+	sort.Ints(tokens)
+	for i := 0; i < n; i++ {
+		assert.Equal(t, i+1, tokens[i])
+	}
+}
+
 func TestGetRuleConf(t *testing.T) {
 	InitConfCache(1 * time.Millisecond)
 	builder := flatbuffers.NewBuilder(1024)
@@ -51,15 +90,16 @@ func TestGetRuleConf(t *testing.T) {
 	builder.Finish(root)
 	b := builder.FinishedBytes()
 
-	out, _ := PrepareConf(b)
+	bd, _ := PrepareConf(b)
+	out := bd.FinishedBytes()
 	resp := pc.GetRootAsResp(out, 0)
-	assert.Equal(t, uint32(3), resp.ConfToken())
+	assert.Equal(t, uint32(1), resp.ConfToken())
 
-	res, _ := GetRuleConf(3)
+	res, _ := GetRuleConf(1)
 	assert.Equal(t, 0, len(res))
 
 	time.Sleep(2 * time.Millisecond)
-	_, err := GetRuleConf(3)
+	_, err := GetRuleConf(1)
 	assert.Equal(t, ttlcache.ErrNotFound, err)
 }
 
@@ -85,7 +125,7 @@ func TestGetRuleConfCheckConf(t *testing.T) {
 	b := builder.FinishedBytes()
 
 	PrepareConf(b)
-	res, _ := GetRuleConf(4)
+	res, _ := GetRuleConf(1)
 	assert.Equal(t, 1, len(res))
 	assert.Equal(t, "echo", res[0].Name)
 }
diff --git a/internal/server/error.go b/internal/server/error.go
index 8ba517c..81d77c3 100644
--- a/internal/server/error.go
+++ b/internal/server/error.go
@@ -18,15 +18,12 @@ import (
 	"github.com/ReneKroon/ttlcache/v2"
 	A6Err "github.com/api7/ext-plugin-proto/go/A6/Err"
 	flatbuffers "github.com/google/flatbuffers/go"
-)
 
-var (
-	builder = flatbuffers.NewBuilder(256)
+	"github.com/apache/apisix-go-plugin-runner/internal/util"
 )
 
-func ReportError(err error) []byte {
-	builder.Reset()
-
+func ReportError(err error) *flatbuffers.Builder {
+	builder := util.GetBuilder()
 	A6Err.RespStart(builder)
 
 	var code A6Err.Code
@@ -40,5 +37,5 @@ func ReportError(err error) []byte {
 	A6Err.RespAddCode(builder, code)
 	resp := A6Err.RespEnd(builder)
 	builder.Finish(resp)
-	return builder.FinishedBytes()
+	return builder
 }
diff --git a/internal/server/error_test.go b/internal/server/error_test.go
index 4d8bb21..fb5b426 100644
--- a/internal/server/error_test.go
+++ b/internal/server/error_test.go
@@ -29,12 +29,14 @@ func TestReportErrorCacheToken(t *testing.T) {
 
 	_, err := plugin.GetRuleConf(uint32(999999))
 	b := ReportError(err)
-	resp := A6Err.GetRootAsResp(b, 0)
+	out := b.FinishedBytes()
+	resp := A6Err.GetRootAsResp(out, 0)
 	assert.Equal(t, A6Err.CodeCONF_TOKEN_NOT_FOUND, resp.Code())
 }
 
 func TestReportErrorUnknownErr(t *testing.T) {
 	b := ReportError(io.EOF)
-	resp := A6Err.GetRootAsResp(b, 0)
+	out := b.FinishedBytes()
+	resp := A6Err.GetRootAsResp(out, 0)
 	assert.Equal(t, A6Err.CodeSERVICE_UNAVAILABLE, resp.Code())
 }
diff --git a/internal/server/server.go b/internal/server/server.go
index c2deef9..52c5624 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -28,6 +28,8 @@ import (
 
 	"github.com/apache/apisix-go-plugin-runner/internal/log"
 	"github.com/apache/apisix-go-plugin-runner/internal/plugin"
+	"github.com/apache/apisix-go-plugin-runner/internal/util"
+	flatbuffers "github.com/google/flatbuffers/go"
 )
 
 const (
@@ -92,14 +94,15 @@ func handleConn(c net.Conn) {
 			break
 		}
 
-		var out []byte
+		var bd *flatbuffers.Builder
 		switch ty {
 		case RPCPrepareConf:
-			out, err = plugin.PrepareConf(buf)
+			bd, err = plugin.PrepareConf(buf)
 		default:
 			err = fmt.Errorf("unknown type %d", ty)
 		}
 
+		out := bd.FinishedBytes()
 		size := len(out)
 		if size > MaxDataSize {
 			err = fmt.Errorf("the max length of data is %d but got %d", MaxDataSize, size)
@@ -108,7 +111,9 @@ func handleConn(c net.Conn) {
 
 		if err != nil {
 			ty = RPCError
-			out = ReportError(err)
+			util.PutBuilder(bd)
+			bd = ReportError(err)
+			out = bd.FinishedBytes()
 		}
 
 		binary.BigEndian.PutUint32(header, uint32(size))
@@ -117,14 +122,17 @@ func handleConn(c net.Conn) {
 		n, err = c.Write(header)
 		if err != nil {
 			writeErr(n, err)
+			util.PutBuilder(bd)
 			break
 		}
 
 		n, err = c.Write(out)
 		if err != nil {
 			writeErr(n, err)
+			util.PutBuilder(bd)
 			break
 		}
+		util.PutBuilder(bd)
 	}
 }
 
diff --git a/internal/server/error.go b/internal/util/pool.go
similarity index 62%
copy from internal/server/error.go
copy to internal/util/pool.go
index 8ba517c..bf6a746 100644
--- a/internal/server/error.go
+++ b/internal/util/pool.go
@@ -12,33 +12,25 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package server
+package util
 
 import (
-	"github.com/ReneKroon/ttlcache/v2"
-	A6Err "github.com/api7/ext-plugin-proto/go/A6/Err"
-	flatbuffers "github.com/google/flatbuffers/go"
-)
+	"sync"
 
-var (
-	builder = flatbuffers.NewBuilder(256)
+	flatbuffers "github.com/google/flatbuffers/go"
 )
 
-func ReportError(err error) []byte {
-	builder.Reset()
-
-	A6Err.RespStart(builder)
+var builderPool = sync.Pool{
+	New: func() interface{} {
+		return flatbuffers.NewBuilder(256)
+	},
+}
 
-	var code A6Err.Code
-	switch err {
-	case ttlcache.ErrNotFound:
-		code = A6Err.CodeCONF_TOKEN_NOT_FOUND
-	default:
-		code = A6Err.CodeSERVICE_UNAVAILABLE
-	}
+func GetBuilder() *flatbuffers.Builder {
+	return builderPool.Get().(*flatbuffers.Builder)
+}
 
-	A6Err.RespAddCode(builder, code)
-	resp := A6Err.RespEnd(builder)
-	builder.Finish(resp)
-	return builder.FinishedBytes()
+func PutBuilder(b *flatbuffers.Builder) {
+	b.Reset()
+	builderPool.Put(b)
 }

[apisix-go-plugin-runner] 02/22: Add supported structure

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit b4b6bc004b38863ec72c94ebc22edc12aad25b3e
Author: spacewander <sp...@gmail.com>
AuthorDate: Tue May 18 14:14:06 2021 +0800

    Add supported structure
---
 .gitignore               |   7 ++
 .golangci.yml            |  19 ++++
 Makefile                 |  74 ++++++++++++++
 cmd/go-runner/main.go    |  56 ++++++++++-
 cmd/go-runner/version.go |  53 ++++++++++
 go.mod                   |   1 +
 go.sum                   | 254 +++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 462 insertions(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..af0f1bb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+go-runner
+!go-runner/
+release/
+*.tgz
+.idea
+.DS_Store
+coverage.txt
diff --git a/.golangci.yml b/.golangci.yml
new file mode 100644
index 0000000..6d6cb0f
--- /dev/null
+++ b/.golangci.yml
@@ -0,0 +1,19 @@
+run:
+  skip-files:
+    - ".*_test.go$"
+
+linters:
+  disable-all: true
+  enable:
+    - deadcode
+    - errcheck
+    - goimports
+    - gosimple
+    - ineffassign
+    - misspell
+    - staticcheck
+    - structcheck
+    - unconvert
+    - unused
+    - varcheck
+    - vet
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..3fba8fc
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,74 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+default: help
+
+VERSION ?= latest
+RELEASE_SRC = apache-apisix-go-plugin-runner-${VERSION}-src
+
+GITSHA ?= $(shell git rev-parse --short=7 HEAD)
+OSNAME ?= $(shell uname -s | tr A-Z a-z)
+OSARCH ?= $(shell uname -m | tr A-Z a-z)
+PWD ?= $(shell pwd)
+ifeq ($(OSARCH), x86_64)
+	OSARCH = amd64
+endif
+
+VERSYM=main._buildVersion
+GITSHASYM=main._buildGitRevision
+BUILDOSSYM=main._buildOS
+GO_LDFLAGS ?= "-X '$(VERSYM)=$(VERSION)' -X '$(GITSHASYM)=$(GITSHA)' -X '$(BUILDOSSYM)=$(OSNAME)/$(OSARCH)'"
+
+.PHONY: build
+build:
+	cd cmd/go-runner && \
+	go build -ldflags $(GO_LDFLAGS) && \
+	mv go-runner ../..
+
+.PHONY: lint
+lint:
+	golangci-lint run --verbose
+
+.PHONY: test
+test:
+	go test -race -cover -coverprofile=coverage.txt ./...
+
+.PHONY: release-src
+release-src: compress-tar
+	gpg --batch --yes --armor --detach-sig $(RELEASE_SRC).tgz
+	shasum -a 512 $(RELEASE_SRC).tgz > $(RELEASE_SRC).tgz.sha512
+
+	mkdir -p release
+	mv $(RELEASE_SRC).tgz release/$(RELEASE_SRC).tgz
+	mv $(RELEASE_SRC).tgz.asc release/$(RELEASE_SRC).tgz.asc
+	mv $(RELEASE_SRC).tgz.sha512 release/$(RELEASE_SRC).tgz.sha512
+
+.PHONY: compress-tar
+compress-tar:
+	tar -zcvf $(RELEASE_SRC).tgz \
+	./cmd \
+	./internal \
+	LICENSE \
+	Makefile \
+	go.mod \
+	go.sum \
+	*.md
+
+.PHONY: help
+help:
+	@echo Makefile rules:
+	@echo
+	@grep -E '^### [-A-Za-z0-9_]+:' Makefile | sed 's/###/   /'
diff --git a/cmd/go-runner/main.go b/cmd/go-runner/main.go
index e01254e..38b83be 100644
--- a/cmd/go-runner/main.go
+++ b/cmd/go-runner/main.go
@@ -14,8 +14,60 @@
 // limitations under the License.
 package main
 
-import "github.com/apache/apisix-go-plugin-runner/internal/server"
+import (
+	"fmt"
+	"os"
+
+	"github.com/spf13/cobra"
+
+	"github.com/apache/apisix-go-plugin-runner/internal/server"
+)
+
+func newVersionCommand() *cobra.Command {
+	var long bool
+	cmd := &cobra.Command{
+		Use:   "version",
+		Short: "version",
+		Run: func(cmd *cobra.Command, _ []string) {
+			if long {
+				fmt.Print(longVersion())
+			} else {
+				fmt.Printf("version %s\n", shortVersion())
+			}
+		},
+	}
+
+	cmd.PersistentFlags().BoolVar(&long, "long", false, "show long mode version information")
+	return cmd
+}
+
+func newRunCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "run",
+		Short: "run",
+		Run: func(cmd *cobra.Command, _ []string) {
+			server.Run()
+		},
+	}
+	return cmd
+}
+
+func NewCommand() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:     "apisix-go-plugin-runner [command]",
+		Long:    "The Plugin runner to run Go plugins",
+		Version: shortVersion(),
+	}
+
+	cmd.AddCommand(newRunCommand())
+	cmd.AddCommand(newVersionCommand())
+	return cmd
+}
 
 func main() {
-	server.Run()
+	root := NewCommand()
+	if err := root.Execute(); err != nil {
+		fmt.Fprintln(os.Stderr, err.Error())
+		os.Exit(1)
+	}
 }
diff --git a/cmd/go-runner/version.go b/cmd/go-runner/version.go
new file mode 100644
index 0000000..333ea25
--- /dev/null
+++ b/cmd/go-runner/version.go
@@ -0,0 +1,53 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"runtime"
+)
+
+var (
+	// The following fields are populated at build time using -ldflags -X.
+	_buildVersion     = "unknown"
+	_buildGitRevision = "unknown"
+	_buildOS          = "unknown"
+
+	_buildGoVersion = runtime.Version()
+	_runningOS      = runtime.GOOS + "/" + runtime.GOARCH
+)
+
+// shortVersion produces a single-line version info with format:
+// <version>-<git revision>-<go version>
+func shortVersion() string {
+	return fmt.Sprintf("%s-%s-%s", _buildVersion, _buildGitRevision, _buildGoVersion)
+}
+
+// longVersion produces a verbose version info with format:
+// Version: xxx
+// Git SHA: xxx
+// GO Version: xxx
+// Running OS/Arch: xxx/xxx
+// Building OS/Arch: xxx/xxx
+func longVersion() string {
+	buf := bytes.NewBuffer(nil)
+	fmt.Fprintln(buf, "Version:", _buildVersion)
+	fmt.Fprintln(buf, "Git SHA:", _buildGitRevision)
+	fmt.Fprintln(buf, "Go Version:", _buildGoVersion)
+	fmt.Fprintln(buf, "Building OS/Arch:", _buildOS)
+	fmt.Fprintln(buf, "Running OS/Arch:", _runningOS)
+	return buf.String()
+}
diff --git a/go.mod b/go.mod
index 210b8f7..c14f634 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module github.com/apache/apisix-go-plugin-runner
 go 1.15
 
 require (
+	github.com/spf13/cobra v1.1.3
 	github.com/stretchr/testify v1.7.0
 	go.uber.org/multierr v1.7.0 // indirect
 	go.uber.org/zap v1.16.0
diff --git a/go.sum b/go.sum
index 25be7fe..283e23c 100644
--- a/go.sum
+++ b/go.sum
@@ -1,54 +1,308 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
+github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
+github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
 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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
+github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
+github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
+github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
+github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
+github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
+github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
+github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
+github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
+github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
+github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
+github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
+github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
+github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+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/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
+github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
+github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
+github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
 github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
 go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
 go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
 go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
 go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
 go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
 go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
 go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-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-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=

[apisix-go-plugin-runner] 12/22: feat: add basic structure for HTTPReqCall

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit c0d186030e6757c328589d17f523572194e45a09
Author: spacewander <sp...@gmail.com>
AuthorDate: Mon May 24 08:50:52 2021 +0800

    feat: add basic structure for HTTPReqCall
---
 internal/http/{http.go => request.go}            | 23 +++++++++------
 internal/http/{http.go => response.go}           | 29 +++++++++++--------
 internal/plugin/conf.go                          |  4 +++
 internal/{http/http.go => plugin/plugin.go}      | 36 ++++++++++++++++++++----
 internal/{http/http.go => plugin/plugin_test.go} | 31 ++++++++++++++------
 internal/server/server.go                        |  3 +-
 {internal => pkg}/http/http.go                   | 23 +++++++--------
 7 files changed, 100 insertions(+), 49 deletions(-)

diff --git a/internal/http/http.go b/internal/http/request.go
similarity index 74%
copy from internal/http/http.go
copy to internal/http/request.go
index d946102..4c96aa2 100644
--- a/internal/http/http.go
+++ b/internal/http/request.go
@@ -15,16 +15,21 @@
 package http
 
 import (
-	flatbuffers "github.com/google/flatbuffers/go"
-
-	"github.com/apache/apisix-go-plugin-runner/internal/util"
 	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
 )
 
-func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
-	builder := util.GetBuilder()
-	hrc.RespStart(builder)
-	resp := hrc.RespEnd(builder)
-	builder.Finish(resp)
-	return builder, nil
+type Request struct {
+	// the root of the flatbuffers HTTPReqCall Request msg
+	r *hrc.Req
+}
+
+func (r Request) ConfToken() uint32 {
+	return r.r.ConfToken()
+}
+
+func CreateRequest(buf []byte) *Request {
+	req := &Request{
+		r: hrc.GetRootAsReq(buf, 0),
+	}
+	return req
 }
diff --git a/internal/http/http.go b/internal/http/response.go
similarity index 69%
copy from internal/http/http.go
copy to internal/http/response.go
index d946102..46fbeeb 100644
--- a/internal/http/http.go
+++ b/internal/http/response.go
@@ -14,17 +14,24 @@
 // limitations under the License.
 package http
 
-import (
-	flatbuffers "github.com/google/flatbuffers/go"
+import "net/http"
 
-	"github.com/apache/apisix-go-plugin-runner/internal/util"
-	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
-)
+type Response struct {
+	code int
+}
+
+func (r Response) Header() http.Header {
+	return nil
+}
+
+func (r Response) Write([]byte) (int, error) {
+	return 0, nil
+}
+
+func (r Response) WriteHeader(statusCode int) {
+	r.code = statusCode
+}
 
-func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
-	builder := util.GetBuilder()
-	hrc.RespStart(builder)
-	resp := hrc.RespEnd(builder)
-	builder.Finish(resp)
-	return builder, nil
+func CreateResponse() *Response {
+	return &Response{}
 }
diff --git a/internal/plugin/conf.go b/internal/plugin/conf.go
index 8e18ecc..3b3a8bb 100644
--- a/internal/plugin/conf.go
+++ b/internal/plugin/conf.go
@@ -81,3 +81,7 @@ func GetRuleConf(token uint32) (RuleConf, error) {
 	}
 	return res.(RuleConf), err
 }
+
+func SetRuleConf(token uint32, conf RuleConf) error {
+	return cache.Set(strconv.FormatInt(int64(token), 10), conf)
+}
diff --git a/internal/http/http.go b/internal/plugin/plugin.go
similarity index 62%
copy from internal/http/http.go
copy to internal/plugin/plugin.go
index d946102..ba07c8a 100644
--- a/internal/http/http.go
+++ b/internal/plugin/plugin.go
@@ -12,19 +12,45 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package http
+package plugin
 
 import (
+	"net/http"
+
+	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
 	flatbuffers "github.com/google/flatbuffers/go"
 
+	inHTTP "github.com/apache/apisix-go-plugin-runner/internal/http"
 	"github.com/apache/apisix-go-plugin-runner/internal/util"
-	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
+	pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http"
 )
 
-func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
+func handle(conf RuleConf, w http.ResponseWriter, r pkgHTTP.Request) error {
+	return nil
+}
+
+func reportAction(req *inHTTP.Request, resp *inHTTP.Response) *flatbuffers.Builder {
 	builder := util.GetBuilder()
 	hrc.RespStart(builder)
-	resp := hrc.RespEnd(builder)
-	builder.Finish(resp)
+	res := hrc.RespEnd(builder)
+	builder.Finish(res)
+	return builder
+}
+
+func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
+	req := inHTTP.CreateRequest(buf)
+	resp := inHTTP.CreateResponse()
+
+	token := req.ConfToken()
+	conf, err := GetRuleConf(token)
+	if err != nil {
+		return nil, err
+	}
+	err = handle(conf, resp, req)
+	if err != nil {
+		return nil, err
+	}
+
+	builder := reportAction(req, resp)
 	return builder, nil
 }
diff --git a/internal/http/http.go b/internal/plugin/plugin_test.go
similarity index 64%
copy from internal/http/http.go
copy to internal/plugin/plugin_test.go
index d946102..5433cca 100644
--- a/internal/http/http.go
+++ b/internal/plugin/plugin_test.go
@@ -12,19 +12,32 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-package http
+package plugin
 
 import (
-	flatbuffers "github.com/google/flatbuffers/go"
+	"testing"
+	"time"
 
-	"github.com/apache/apisix-go-plugin-runner/internal/util"
 	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
+	flatbuffers "github.com/google/flatbuffers/go"
+	"github.com/stretchr/testify/assert"
 )
 
-func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
-	builder := util.GetBuilder()
-	hrc.RespStart(builder)
-	resp := hrc.RespEnd(builder)
-	builder.Finish(resp)
-	return builder, nil
+func TestHTTPReqCall(t *testing.T) {
+	InitConfCache(10 * time.Millisecond)
+	SetRuleConf(1, RuleConf{})
+
+	builder := flatbuffers.NewBuilder(1024)
+	hrc.ReqStart(builder)
+	hrc.ReqAddConfToken(builder, 1)
+	r := hrc.ReqEnd(builder)
+	builder.Finish(r)
+	out := builder.FinishedBytes()
+
+	b, err := HTTPReqCall(out)
+	assert.Nil(t, err)
+
+	out = b.FinishedBytes()
+	resp := hrc.GetRootAsResp(out, 0)
+	assert.Equal(t, hrc.ActionNONE, resp.ActionType())
 }
diff --git a/internal/server/server.go b/internal/server/server.go
index a856066..7299252 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -27,7 +27,6 @@ import (
 	"syscall"
 	"time"
 
-	"github.com/apache/apisix-go-plugin-runner/internal/http"
 	"github.com/apache/apisix-go-plugin-runner/internal/log"
 	"github.com/apache/apisix-go-plugin-runner/internal/plugin"
 	"github.com/apache/apisix-go-plugin-runner/internal/util"
@@ -101,7 +100,7 @@ func handleConn(c net.Conn) {
 		case RPCPrepareConf:
 			bd, err = plugin.PrepareConf(buf)
 		case RPCHTTPReqCall:
-			bd, err = http.HTTPReqCall(buf)
+			bd, err = plugin.HTTPReqCall(buf)
 		default:
 			err = UnknownType{ty}
 		}
diff --git a/internal/http/http.go b/pkg/http/http.go
similarity index 57%
rename from internal/http/http.go
rename to pkg/http/http.go
index d946102..54edde1 100644
--- a/internal/http/http.go
+++ b/pkg/http/http.go
@@ -14,17 +14,14 @@
 // limitations under the License.
 package http
 
-import (
-	flatbuffers "github.com/google/flatbuffers/go"
-
-	"github.com/apache/apisix-go-plugin-runner/internal/util"
-	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
-)
-
-func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
-	builder := util.GetBuilder()
-	hrc.RespStart(builder)
-	resp := hrc.RespEnd(builder)
-	builder.Finish(resp)
-	return builder, nil
+// Request represents the HTTP request received by APISIX.
+// We don't use net/http's Request because it doesn't suit our purpose.
+// Take `Request.Header` as an example:
+//
+// 1. We need to record any change to the request headers. As the Request.Header
+// is not an interface, there is not way to inject our special tracker.
+// 2. As the author of fasthttp pointed out, "headers are stored in a map[string][]string.
+// So the server must parse all the headers, ...". The official API is suboptimal, which
+// is even worse in our case as it is not a real HTTP server.
+type Request interface {
 }

[apisix-go-plugin-runner] 13/22: feat: record response

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit 38309c734030f838e90b4660df3376d4622047ec
Author: spacewander <sp...@gmail.com>
AuthorDate: Mon May 24 13:04:12 2021 +0800

    feat: record response
---
 internal/http/request.go       |  4 ++
 internal/http/response.go      | 92 ++++++++++++++++++++++++++++++++++++++---
 internal/http/response_test.go | 93 ++++++++++++++++++++++++++++++++++++++++++
 internal/plugin/plugin.go      | 11 ++++-
 internal/plugin/plugin_test.go |  2 +
 pkg/http/http.go               |  2 +
 6 files changed, 196 insertions(+), 8 deletions(-)

diff --git a/internal/http/request.go b/internal/http/request.go
index 4c96aa2..596b0c4 100644
--- a/internal/http/request.go
+++ b/internal/http/request.go
@@ -27,6 +27,10 @@ func (r Request) ConfToken() uint32 {
 	return r.r.ConfToken()
 }
 
+func (r Request) Id() uint32 {
+	return r.r.Id()
+}
+
 func CreateRequest(buf []byte) *Request {
 	req := &Request{
 		r: hrc.GetRootAsReq(buf, 0),
diff --git a/internal/http/response.go b/internal/http/response.go
index 46fbeeb..ef28b9a 100644
--- a/internal/http/response.go
+++ b/internal/http/response.go
@@ -14,24 +14,104 @@
 // limitations under the License.
 package http
 
-import "net/http"
+import (
+	"bytes"
+	"net/http"
+
+	"github.com/api7/ext-plugin-proto/go/A6"
+	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
+	flatbuffers "github.com/google/flatbuffers/go"
+)
 
 type Response struct {
+	hdr  http.Header
+	body *bytes.Buffer
 	code int
 }
 
-func (r Response) Header() http.Header {
-	return nil
+func (r *Response) Header() http.Header {
+	r.hdr = http.Header{}
+	return r.hdr
 }
 
-func (r Response) Write([]byte) (int, error) {
-	return 0, nil
+func (r *Response) Write(b []byte) (int, error) {
+	if r.body == nil {
+		r.body = &bytes.Buffer{}
+	}
+
+	return r.body.Write(b)
 }
 
-func (r Response) WriteHeader(statusCode int) {
+func (r *Response) WriteHeader(statusCode int) {
+	if r.code != 0 {
+		// official WriteHeader can't override written status
+		// keep the same behavior
+		return
+	}
 	r.code = statusCode
 }
 
+func (r *Response) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
+	if r.body == nil && r.code == 0 && len(r.hdr) == 0 {
+		return false
+	}
+
+	hdrLen := len(r.hdr)
+	var hdrVec flatbuffers.UOffsetT
+	if hdrLen > 0 {
+		hdrs := []flatbuffers.UOffsetT{}
+		for n, arr := range r.hdr {
+			for _, v := range arr {
+				name := builder.CreateString(n)
+				value := builder.CreateString(v)
+				A6.TextEntryStart(builder)
+				A6.TextEntryAddName(builder, name)
+				A6.TextEntryAddValue(builder, value)
+				te := A6.TextEntryEnd(builder)
+				hdrs = append(hdrs, te)
+			}
+		}
+		size := len(hdrs)
+		hrc.StopStartHeadersVector(builder, size)
+		for i := size - 1; i >= 0; i-- {
+			te := hdrs[i]
+			builder.PrependUOffsetT(te)
+		}
+		hdrVec = builder.EndVector(size)
+	}
+
+	var bodyVec flatbuffers.UOffsetT
+	if r.body != nil {
+		b := r.body.Bytes()
+		if len(b) > 0 {
+			bodyVec = builder.CreateByteVector(b)
+		}
+	}
+
+	hrc.StopStart(builder)
+	if r.code == 0 {
+		hrc.StopAddStatus(builder, 200)
+	} else {
+		hrc.StopAddStatus(builder, uint16(r.code))
+	}
+	if hdrLen > 0 {
+		hrc.StopAddHeaders(builder, hdrVec)
+	}
+	if r.body != nil {
+		hrc.StopAddBody(builder, bodyVec)
+	}
+	stop := hrc.StopEnd(builder)
+
+	hrc.RespStart(builder)
+	hrc.RespAddId(builder, id)
+	hrc.RespAddActionType(builder, hrc.ActionStop)
+	hrc.RespAddAction(builder, stop)
+	res := hrc.RespEnd(builder)
+	builder.Finish(res)
+
+	return true
+}
+
 func CreateResponse() *Response {
 	return &Response{}
 }
diff --git a/internal/http/response_test.go b/internal/http/response_test.go
new file mode 100644
index 0000000..5eddd4c
--- /dev/null
+++ b/internal/http/response_test.go
@@ -0,0 +1,93 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package http
+
+import (
+	"net/http"
+	"testing"
+
+	"github.com/api7/ext-plugin-proto/go/A6"
+	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
+	flatbuffers "github.com/google/flatbuffers/go"
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/apisix-go-plugin-runner/internal/util"
+)
+
+func getStopAction(t *testing.T, b *flatbuffers.Builder) *hrc.Stop {
+	buf := b.FinishedBytes()
+	res := hrc.GetRootAsResp(buf, 0)
+	tab := &flatbuffers.Table{}
+	if res.Action(tab) {
+		assert.Equal(t, hrc.ActionStop, res.ActionType())
+		stop := &hrc.Stop{}
+		stop.Init(tab.Bytes, tab.Pos)
+		return stop
+	}
+	return nil
+}
+
+func TestFetchChanges(t *testing.T) {
+	r := CreateResponse()
+	r.Write([]byte("hello"))
+	h := r.Header()
+	h.Set("foo", "bar")
+	h.Add("foo", "baz")
+	h.Add("cat", "dog")
+	r.Write([]byte(" world"))
+	assert.Equal(t, "dog", h.Get("cat"))
+	builder := util.GetBuilder()
+	assert.True(t, r.FetchChanges(1, builder))
+
+	stop := getStopAction(t, builder)
+	assert.Equal(t, uint16(200), stop.Status())
+	assert.Equal(t, []byte("hello world"), stop.BodyBytes())
+
+	res := http.Header{}
+	assert.Equal(t, 3, stop.HeadersLength())
+	for i := 0; i < stop.HeadersLength(); i++ {
+		e := &A6.TextEntry{}
+		stop.Headers(e, i)
+		res.Add(string(e.Name()), string(e.Value()))
+	}
+	assert.Equal(t, h, res)
+}
+
+func TestFetchChangesEmptyResponse(t *testing.T) {
+	r := CreateResponse()
+	builder := util.GetBuilder()
+	assert.False(t, r.FetchChanges(1, builder))
+}
+
+func TestFetchChangesStatusOnly(t *testing.T) {
+	r := CreateResponse()
+	r.WriteHeader(400)
+	builder := util.GetBuilder()
+	assert.True(t, r.FetchChanges(1, builder))
+
+	stop := getStopAction(t, builder)
+	assert.Equal(t, uint16(400), stop.Status())
+}
+
+func TestWriteHeaderTwice(t *testing.T) {
+	r := CreateResponse()
+	r.WriteHeader(400)
+	r.WriteHeader(503)
+	builder := util.GetBuilder()
+	assert.True(t, r.FetchChanges(1, builder))
+
+	stop := getStopAction(t, builder)
+	assert.Equal(t, uint16(400), stop.Status())
+}
diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go
index ba07c8a..e4d9ef6 100644
--- a/internal/plugin/plugin.go
+++ b/internal/plugin/plugin.go
@@ -29,9 +29,15 @@ func handle(conf RuleConf, w http.ResponseWriter, r pkgHTTP.Request) error {
 	return nil
 }
 
-func reportAction(req *inHTTP.Request, resp *inHTTP.Response) *flatbuffers.Builder {
+func reportAction(id uint32, req *inHTTP.Request, resp *inHTTP.Response) *flatbuffers.Builder {
 	builder := util.GetBuilder()
+
+	if resp != nil && resp.FetchChanges(id, builder) {
+		return builder
+	}
+
 	hrc.RespStart(builder)
+	hrc.RespAddId(builder, id)
 	res := hrc.RespEnd(builder)
 	builder.Finish(res)
 	return builder
@@ -51,6 +57,7 @@ func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
 		return nil, err
 	}
 
-	builder := reportAction(req, resp)
+	id := req.Id()
+	builder := reportAction(id, req, resp)
 	return builder, nil
 }
diff --git a/internal/plugin/plugin_test.go b/internal/plugin/plugin_test.go
index 5433cca..c433f3f 100644
--- a/internal/plugin/plugin_test.go
+++ b/internal/plugin/plugin_test.go
@@ -29,6 +29,7 @@ func TestHTTPReqCall(t *testing.T) {
 
 	builder := flatbuffers.NewBuilder(1024)
 	hrc.ReqStart(builder)
+	hrc.ReqAddId(builder, 233)
 	hrc.ReqAddConfToken(builder, 1)
 	r := hrc.ReqEnd(builder)
 	builder.Finish(r)
@@ -39,5 +40,6 @@ func TestHTTPReqCall(t *testing.T) {
 
 	out = b.FinishedBytes()
 	resp := hrc.GetRootAsResp(out, 0)
+	assert.Equal(t, uint32(233), resp.Id())
 	assert.Equal(t, hrc.ActionNONE, resp.ActionType())
 }
diff --git a/pkg/http/http.go b/pkg/http/http.go
index 54edde1..de83956 100644
--- a/pkg/http/http.go
+++ b/pkg/http/http.go
@@ -24,4 +24,6 @@ package http
 // So the server must parse all the headers, ...". The official API is suboptimal, which
 // is even worse in our case as it is not a real HTTP server.
 type Request interface {
+	// Id returns the request id
+	Id() uint32
 }

[apisix-go-plugin-runner] 08/22: chore: tweak error handling

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit f00ec5ec4bb4ea2e418ebb70c61826a356484ed1
Author: spacewander <sp...@gmail.com>
AuthorDate: Wed May 19 17:46:31 2021 +0800

    chore: tweak error handling
---
 internal/server/server.go | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/internal/server/server.go b/internal/server/server.go
index 26ab5cf..c2deef9 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -17,6 +17,7 @@ package server
 import (
 	"encoding/binary"
 	"errors"
+	"fmt"
 	"io"
 	"net"
 	"os"
@@ -95,6 +96,14 @@ func handleConn(c net.Conn) {
 		switch ty {
 		case RPCPrepareConf:
 			out, err = plugin.PrepareConf(buf)
+		default:
+			err = fmt.Errorf("unknown type %d", ty)
+		}
+
+		size := len(out)
+		if size > MaxDataSize {
+			err = fmt.Errorf("the max length of data is %d but got %d", MaxDataSize, size)
+			log.Errorf("%s", err)
 		}
 
 		if err != nil {
@@ -102,12 +111,6 @@ func handleConn(c net.Conn) {
 			out = ReportError(err)
 		}
 
-		size := len(out)
-		if size > MaxDataSize {
-			log.Errorf("the max length of data is %d but got %d", MaxDataSize, size)
-			continue
-		}
-
 		binary.BigEndian.PutUint32(header, uint32(size))
 		header[0] = ty
 

[apisix-go-plugin-runner] 03/22: feat: prepare conf

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit e9937ce9a05eab0ecd669e3d03d80d7956f74453
Author: spacewander <sp...@gmail.com>
AuthorDate: Tue May 18 17:09:52 2021 +0800

    feat: prepare conf
---
 go.mod                         |  3 ++
 go.sum                         | 41 +++++++++++++++++++
 internal/plugin/conf.go        | 70 +++++++++++++++++++++++++++++++-
 internal/plugin/conf_test.go   | 91 ++++++++++++++++++++++++++++++++++++++++++
 internal/server/server.go      | 20 ++++++----
 internal/server/server_test.go |  4 ++
 6 files changed, 221 insertions(+), 8 deletions(-)

diff --git a/go.mod b/go.mod
index c14f634..34ee1d0 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,9 @@ module github.com/apache/apisix-go-plugin-runner
 go 1.15
 
 require (
+	github.com/ReneKroon/ttlcache/v2 v2.4.0
+	github.com/api7/ext-plugin-proto v0.1.4
+	github.com/google/flatbuffers v2.0.0+incompatible
 	github.com/spf13/cobra v1.1.3
 	github.com/stretchr/testify v1.7.0
 	go.uber.org/multierr v1.7.0 // indirect
diff --git a/go.sum b/go.sum
index 283e23c..4e96f53 100644
--- a/go.sum
+++ b/go.sum
@@ -11,11 +11,17 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl
 cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
 cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/ReneKroon/ttlcache/v2 v2.4.0 h1:KywGhjik+ZFTDXMNLiPECSzmdx2yNvAlDNKESCRaVEs=
+github.com/ReneKroon/ttlcache/v2 v2.4.0/go.mod h1:zbo6Pv/28e21Z8CzzqgYRArQYGYtjONRxaAKGxzQvG4=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alvaroloes/enumer v1.1.2/go.mod h1:FxrjvuXoDAx9isTJrv4c+T410zFi0DtXIT0m65DJ+Wo=
+github.com/api7/ext-plugin-proto v0.1.4 h1:gxw+fmtM2UPsSku+mEOFNTQpAGEOKrkWZvQgIcglaG0=
+github.com/api7/ext-plugin-proto v0.1.4/go.mod h1:8dbdAgCESeqwZ0IXirbjLbshEntmdrAX3uet+LW3jVU=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
@@ -56,6 +62,8 @@ github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI=
+github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -89,6 +97,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
 github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
 github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
 github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -99,8 +108,10 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -120,8 +131,10 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pascaldekloe/name v0.0.0-20180628100202-0fd16699aae1/go.mod h1:eD5JxqMiuNYyFNmyY9rkJ/slN8y59oEu4Ei7F8OoKWQ=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
@@ -166,6 +179,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
 github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@@ -174,6 +188,8 @@ go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
 go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
 go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
 go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
+go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
 go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
@@ -188,6 +204,8 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -201,11 +219,17 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5 h1:2M3HP5CCK1Si9FQhwnzYhXdG6DXeebvUHFpre8QvbyI=
+golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 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-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -220,6 +244,7 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -228,6 +253,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -241,9 +267,11 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -256,6 +284,7 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
 golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524210228-3d17549cdc6b/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
@@ -264,8 +293,17 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc h1:NCy3Ohtk6Iny5V/reW2Ktypo4zIpWBdRJ1uFMjBxdg8=
 golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064 h1:BmCFkEH4nJrYcAc2L08yX5RhYGD4j58PTMkEUDkpz2I=
+golang.org/x/tools v0.0.0-20210112230658-8b4aab62c064/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -289,6 +327,7 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@@ -297,6 +336,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl
 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.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
@@ -304,5 +344,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
diff --git a/internal/plugin/conf.go b/internal/plugin/conf.go
index 843ac0b..a6eccab 100644
--- a/internal/plugin/conf.go
+++ b/internal/plugin/conf.go
@@ -14,6 +14,74 @@
 // limitations under the License.
 package plugin
 
+import (
+	"strconv"
+	"time"
+
+	"github.com/ReneKroon/ttlcache/v2"
+	A6 "github.com/api7/ext-plugin-proto/go/A6"
+	pc "github.com/api7/ext-plugin-proto/go/A6/PrepareConf"
+	flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type ConfEntry struct {
+	Name  string
+	Value interface{}
+}
+type RuleConf []ConfEntry
+
+var (
+	builder *flatbuffers.Builder
+
+	cache        *ttlcache.Cache
+	cacheCounter uint32 = 0
+)
+
+func init() {
+	builder = flatbuffers.NewBuilder(1024)
+}
+
+func InitCache(ttl time.Duration) {
+	cache = ttlcache.NewCache()
+	cache.SetTTL(ttl)
+	cache.SkipTTLExtensionOnHit(false)
+}
+
+func genCacheToken() uint32 {
+	cacheCounter++
+	if cacheCounter == 0 {
+		// overflow, skip 0 which means none
+		cacheCounter++
+	}
+	return cacheCounter
+}
+
 func PrepareConf(buf []byte) []byte {
-	return buf
+	req := pc.GetRootAsReq(buf, 0)
+	entries := make(RuleConf, req.ConfLength())
+
+	te := A6.TextEntry{}
+	for i := 0; i < req.ConfLength(); i++ {
+		if req.Conf(&te, i) {
+			entries[i].Name = string(te.Name())
+			entries[i].Value = te.Value
+		}
+	}
+
+	token := genCacheToken()
+	cache.Set(strconv.FormatInt(int64(token), 10), entries)
+
+	pc.RespStart(builder)
+	pc.RespAddConfToken(builder, token)
+	root := pc.RespEnd(builder)
+	builder.Finish(root)
+	return builder.FinishedBytes()
+}
+
+func GetRuleConf(token uint32) (RuleConf, error) {
+	res, err := cache.Get(strconv.FormatInt(int64(token), 10))
+	if err != nil {
+		return nil, err
+	}
+	return res.(RuleConf), err
 }
diff --git a/internal/plugin/conf_test.go b/internal/plugin/conf_test.go
new file mode 100644
index 0000000..cdb3749
--- /dev/null
+++ b/internal/plugin/conf_test.go
@@ -0,0 +1,91 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package plugin
+
+import (
+	"testing"
+	"time"
+
+	"github.com/ReneKroon/ttlcache/v2"
+	A6 "github.com/api7/ext-plugin-proto/go/A6"
+	pc "github.com/api7/ext-plugin-proto/go/A6/PrepareConf"
+	flatbuffers "github.com/google/flatbuffers/go"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestPrepareConf(t *testing.T) {
+	InitCache(10 * time.Millisecond)
+
+	builder := flatbuffers.NewBuilder(1024)
+	pc.ReqStart(builder)
+	root := pc.ReqEnd(builder)
+	builder.Finish(root)
+	b := builder.FinishedBytes()
+
+	out := PrepareConf(b)
+	resp := pc.GetRootAsResp(out, 0)
+	assert.Equal(t, uint32(1), resp.ConfToken())
+
+	out = PrepareConf(b)
+	resp = pc.GetRootAsResp(out, 0)
+	assert.Equal(t, uint32(2), resp.ConfToken())
+}
+
+func TestGetRuleConf(t *testing.T) {
+	InitCache(1 * time.Millisecond)
+	builder := flatbuffers.NewBuilder(1024)
+	pc.ReqStart(builder)
+	root := pc.ReqEnd(builder)
+	builder.Finish(root)
+	b := builder.FinishedBytes()
+
+	out := PrepareConf(b)
+	resp := pc.GetRootAsResp(out, 0)
+	assert.Equal(t, uint32(3), resp.ConfToken())
+
+	res, _ := GetRuleConf(3)
+	assert.Equal(t, 0, len(res))
+
+	time.Sleep(2 * time.Millisecond)
+	_, err := GetRuleConf(3)
+	assert.Equal(t, ttlcache.ErrNotFound, err)
+}
+
+func TestGetRuleConfCheckConf(t *testing.T) {
+	InitCache(1 * time.Millisecond)
+	builder := flatbuffers.NewBuilder(1024)
+
+	name := builder.CreateString("echo")
+	value := builder.CreateString(`{"body":"yes"}`)
+	A6.TextEntryStart(builder)
+	A6.TextEntryAddName(builder, name)
+	A6.TextEntryAddValue(builder, value)
+	te := A6.TextEntryEnd(builder)
+
+	pc.ReqStartConfVector(builder, 1)
+	builder.PrependUOffsetT(te)
+	v := builder.EndVector(1)
+
+	pc.ReqStart(builder)
+	pc.ReqAddConf(builder, v)
+	root := pc.ReqEnd(builder)
+	builder.Finish(root)
+	b := builder.FinishedBytes()
+
+	PrepareConf(b)
+	res, _ := GetRuleConf(4)
+	assert.Equal(t, 1, len(res))
+	assert.Equal(t, "echo", res[0].Name)
+}
diff --git a/internal/server/server.go b/internal/server/server.go
index 162a704..0180ed6 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -39,13 +39,15 @@ const (
 	RPCHTTPReqCall
 )
 
-func readErr(n int, err error) {
-	if err == io.EOF && n != 0 {
+func readErr(n int, err error, required int) bool {
+	if n < required {
 		err = errors.New("truncated")
 	}
-	if err != io.EOF {
+	if err != nil && err != io.EOF {
 		log.Errorf("read: %s", err)
+		return true
 	}
+	return false
 }
 
 func writeErr(n int, err error) {
@@ -55,14 +57,19 @@ func writeErr(n int, err error) {
 }
 
 func handleConn(c net.Conn) {
+	defer func() {
+		if err := recover(); err != nil {
+			log.Errorf("panic recovered: %s", err)
+		}
+	}()
+
 	log.Infof("Client connected (%s)", c.RemoteAddr().Network())
 	defer c.Close()
 
 	header := make([]byte, HeaderLen)
 	for {
 		n, err := c.Read(header)
-		if err != nil {
-			readErr(n, err)
+		if readErr(n, err, HeaderLen) {
 			break
 		}
 
@@ -76,8 +83,7 @@ func handleConn(c net.Conn) {
 
 		buf := make([]byte, length)
 		n, err = c.Read(buf)
-		if err != nil {
-			readErr(n, err)
+		if readErr(n, err, int(length)) {
 			break
 		}
 
diff --git a/internal/server/server_test.go b/internal/server/server_test.go
index 81529bf..c62634b 100644
--- a/internal/server/server_test.go
+++ b/internal/server/server_test.go
@@ -15,6 +15,7 @@
 package server
 
 import (
+	"bytes"
 	"encoding/binary"
 	"net"
 	"os"
@@ -53,10 +54,13 @@ func TestRun(t *testing.T) {
 		{header},
 		// header without body truncated
 		{append(header, 32)},
+		// header with bad body
+		{append(header, bytes.Repeat([]byte{1, 2}, 16)...)},
 	}
 
 	for _, c := range cases {
 		conn, err := net.DialTimeout("unix", addr, 1*time.Second)
+		defer conn.Close()
 		assert.NotNil(t, conn, err)
 		conn.Write(c.header)
 	}

[apisix-go-plugin-runner] 14/22: feat: extend pkg Request

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit d8647f9bf36785c976fd0400abab488ead73212d
Author: spacewander <sp...@gmail.com>
AuthorDate: Tue May 25 14:58:51 2021 +0800

    feat: extend pkg Request
---
 internal/http/request.go      |  54 +++++++++++++++++++-
 internal/http/request_test.go | 113 ++++++++++++++++++++++++++++++++++++++++++
 internal/plugin/plugin.go     |   2 +-
 pkg/http/http.go              |  16 +++++-
 4 files changed, 180 insertions(+), 5 deletions(-)

diff --git a/internal/http/request.go b/internal/http/request.go
index 596b0c4..570c245 100644
--- a/internal/http/request.go
+++ b/internal/http/request.go
@@ -15,22 +15,72 @@
 package http
 
 import (
+	"net"
+
 	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
+	flatbuffers "github.com/google/flatbuffers/go"
 )
 
 type Request struct {
 	// the root of the flatbuffers HTTPReqCall Request msg
 	r *hrc.Req
+
+	path []byte
 }
 
-func (r Request) ConfToken() uint32 {
+func (r *Request) ConfToken() uint32 {
 	return r.r.ConfToken()
 }
 
-func (r Request) Id() uint32 {
+func (r *Request) ID() uint32 {
 	return r.r.Id()
 }
 
+func (r *Request) SrcIP() net.IP {
+	return r.r.SrcIpBytes()
+}
+
+func (r *Request) Method() string {
+	return r.r.Method().String()
+}
+
+func (r *Request) Path() []byte {
+	if r.path == nil {
+		return r.r.Path()
+	}
+	return r.path
+}
+
+func (r *Request) SetPath(path []byte) {
+	r.path = path
+}
+
+func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
+	if r.path == nil {
+		return false
+	}
+
+	var path flatbuffers.UOffsetT
+	if r.path != nil {
+		path = builder.CreateByteString(r.path)
+	}
+
+	hrc.RewriteStart(builder)
+	if path > 0 {
+		hrc.RewriteAddPath(builder, path)
+	}
+	rewrite := hrc.RewriteEnd(builder)
+
+	hrc.RespStart(builder)
+	hrc.RespAddId(builder, id)
+	hrc.RespAddActionType(builder, hrc.ActionRewrite)
+	hrc.RespAddAction(builder, rewrite)
+	res := hrc.RespEnd(builder)
+	builder.Finish(res)
+
+	return true
+}
+
 func CreateRequest(buf []byte) *Request {
 	req := &Request{
 		r: hrc.GetRootAsReq(buf, 0),
diff --git a/internal/http/request_test.go b/internal/http/request_test.go
new file mode 100644
index 0000000..667138e
--- /dev/null
+++ b/internal/http/request_test.go
@@ -0,0 +1,113 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package http
+
+import (
+	"net"
+	"testing"
+
+	"github.com/apache/apisix-go-plugin-runner/internal/util"
+	"github.com/api7/ext-plugin-proto/go/A6"
+	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
+	flatbuffers "github.com/google/flatbuffers/go"
+	"github.com/stretchr/testify/assert"
+)
+
+func getRewriteAction(t *testing.T, b *flatbuffers.Builder) *hrc.Rewrite {
+	buf := b.FinishedBytes()
+	res := hrc.GetRootAsResp(buf, 0)
+	tab := &flatbuffers.Table{}
+	if res.Action(tab) {
+		assert.Equal(t, hrc.ActionRewrite, res.ActionType())
+		rewrite := &hrc.Rewrite{}
+		rewrite.Init(tab.Bytes, tab.Pos)
+		return rewrite
+	}
+	return nil
+}
+
+type reqOpt struct {
+	srcIP  []byte
+	method A6.Method
+	path   string
+}
+
+func buildReq(opt reqOpt) []byte {
+	builder := flatbuffers.NewBuilder(1024)
+
+	var ip flatbuffers.UOffsetT
+	if len(opt.srcIP) > 0 {
+		ip = builder.CreateByteVector(opt.srcIP)
+	}
+
+	var path flatbuffers.UOffsetT
+	if opt.path != "" {
+		path = builder.CreateString(opt.path)
+	}
+
+	hrc.ReqStart(builder)
+	hrc.ReqAddId(builder, 233)
+	hrc.ReqAddConfToken(builder, 1)
+	if ip > 0 {
+		hrc.ReqAddSrcIp(builder, ip)
+	}
+	if opt.method != 0 {
+		hrc.ReqAddMethod(builder, opt.method)
+	}
+	if path > 0 {
+		hrc.ReqAddPath(builder, path)
+	}
+	r := hrc.ReqEnd(builder)
+	builder.Finish(r)
+	return builder.FinishedBytes()
+}
+
+func TestSrcIp(t *testing.T) {
+	for _, ip := range []net.IP{
+		net.IPv4(127, 0, 0, 1),
+		net.IPv4(127, 2, 3, 1),
+		net.ParseIP("2001:db8::68"),
+		net.ParseIP("::12"),
+	} {
+		out := buildReq(reqOpt{srcIP: ip})
+		r := CreateRequest(out)
+		assert.Equal(t, ip, r.SrcIP())
+	}
+}
+
+func TestMethod(t *testing.T) {
+	for _, m := range []A6.Method{
+		A6.MethodGET,
+		A6.MethodPATCH,
+	} {
+		out := buildReq(reqOpt{method: m})
+		r := CreateRequest(out)
+		assert.Equal(t, m.String(), r.Method())
+	}
+}
+
+func TestPath(t *testing.T) {
+	out := buildReq(reqOpt{path: "/apisix"})
+	r := CreateRequest(out)
+	assert.Equal(t, "/apisix", string(r.Path()))
+
+	r.SetPath([]byte("/go"))
+	assert.Equal(t, "/go", string(r.Path()))
+
+	builder := util.GetBuilder()
+	assert.True(t, r.FetchChanges(1, builder))
+	rewrite := getRewriteAction(t, builder)
+	assert.Equal(t, "/go", string(rewrite.Path()))
+}
diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go
index e4d9ef6..3ca4159 100644
--- a/internal/plugin/plugin.go
+++ b/internal/plugin/plugin.go
@@ -57,7 +57,7 @@ func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
 		return nil, err
 	}
 
-	id := req.Id()
+	id := req.ID()
 	builder := reportAction(id, req, resp)
 	return builder, nil
 }
diff --git a/pkg/http/http.go b/pkg/http/http.go
index de83956..ebae8ac 100644
--- a/pkg/http/http.go
+++ b/pkg/http/http.go
@@ -14,6 +14,8 @@
 // limitations under the License.
 package http
 
+import "net"
+
 // Request represents the HTTP request received by APISIX.
 // We don't use net/http's Request because it doesn't suit our purpose.
 // Take `Request.Header` as an example:
@@ -24,6 +26,16 @@ package http
 // So the server must parse all the headers, ...". The official API is suboptimal, which
 // is even worse in our case as it is not a real HTTP server.
 type Request interface {
-	// Id returns the request id
-	Id() uint32
+	// ID returns the request id
+	ID() uint32
+	// SrcIP returns the client's IP
+	SrcIP() net.IP
+	// Method returns the HTTP method (GET, POST, PUT, etc.)
+	Method() string
+	// Path returns the path part of the client's URI (without query string and the other parts)
+	// It won't be equal to the one in the Request-Line sent by the client if it has
+	// been rewritten by APISIX
+	Path() []byte
+	// SetPath is the setter for Path
+	SetPath([]byte)
 }

[apisix-go-plugin-runner] 15/22: chore: pass lint

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit d825c844afaa8b4e3a19287930a12936b7b6879f
Author: spacewander <sp...@gmail.com>
AuthorDate: Tue May 25 15:40:41 2021 +0800

    chore: pass lint
---
 internal/plugin/conf.go | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/internal/plugin/conf.go b/internal/plugin/conf.go
index 3b3a8bb..5c4dccf 100644
--- a/internal/plugin/conf.go
+++ b/internal/plugin/conf.go
@@ -20,6 +20,7 @@ import (
 	"time"
 
 	"github.com/ReneKroon/ttlcache/v2"
+	"github.com/apache/apisix-go-plugin-runner/internal/log"
 	"github.com/apache/apisix-go-plugin-runner/internal/util"
 	A6 "github.com/api7/ext-plugin-proto/go/A6"
 	pc "github.com/api7/ext-plugin-proto/go/A6/PrepareConf"
@@ -39,7 +40,10 @@ var (
 
 func InitConfCache(ttl time.Duration) {
 	cache = ttlcache.NewCache()
-	cache.SetTTL(ttl)
+	err := cache.SetTTL(ttl)
+	if err != nil {
+		log.Fatalf("failed to set global ttl for cache: %s", err)
+	}
 	cache.SkipTTLExtensionOnHit(false)
 	cacheCounter = 0
 }

[apisix-go-plugin-runner] 05/22: feat: report error

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit 7e9d6ab70e2ad74269672b2987d9aa5d662e6a30
Author: spacewander <sp...@gmail.com>
AuthorDate: Wed May 19 14:56:12 2021 +0800

    feat: report error
---
 internal/plugin/conf.go       | 17 +++++++++--------
 internal/plugin/conf_test.go  |  6 +++---
 internal/server/error.go      | 44 +++++++++++++++++++++++++++++++++++++++++++
 internal/server/error_test.go | 40 +++++++++++++++++++++++++++++++++++++++
 internal/server/server.go     |  7 ++++++-
 5 files changed, 102 insertions(+), 12 deletions(-)

diff --git a/internal/plugin/conf.go b/internal/plugin/conf.go
index a6eccab..ae7d0c6 100644
--- a/internal/plugin/conf.go
+++ b/internal/plugin/conf.go
@@ -31,16 +31,12 @@ type ConfEntry struct {
 type RuleConf []ConfEntry
 
 var (
-	builder *flatbuffers.Builder
+	builder = flatbuffers.NewBuilder(1024)
 
 	cache        *ttlcache.Cache
 	cacheCounter uint32 = 0
 )
 
-func init() {
-	builder = flatbuffers.NewBuilder(1024)
-}
-
 func InitCache(ttl time.Duration) {
 	cache = ttlcache.NewCache()
 	cache.SetTTL(ttl)
@@ -56,7 +52,9 @@ func genCacheToken() uint32 {
 	return cacheCounter
 }
 
-func PrepareConf(buf []byte) []byte {
+func PrepareConf(buf []byte) ([]byte, error) {
+	builder.Reset()
+
 	req := pc.GetRootAsReq(buf, 0)
 	entries := make(RuleConf, req.ConfLength())
 
@@ -69,13 +67,16 @@ func PrepareConf(buf []byte) []byte {
 	}
 
 	token := genCacheToken()
-	cache.Set(strconv.FormatInt(int64(token), 10), entries)
+	err := cache.Set(strconv.FormatInt(int64(token), 10), entries)
+	if err != nil {
+		return nil, err
+	}
 
 	pc.RespStart(builder)
 	pc.RespAddConfToken(builder, token)
 	root := pc.RespEnd(builder)
 	builder.Finish(root)
-	return builder.FinishedBytes()
+	return builder.FinishedBytes(), nil
 }
 
 func GetRuleConf(token uint32) (RuleConf, error) {
diff --git a/internal/plugin/conf_test.go b/internal/plugin/conf_test.go
index cdb3749..1b2e668 100644
--- a/internal/plugin/conf_test.go
+++ b/internal/plugin/conf_test.go
@@ -34,11 +34,11 @@ func TestPrepareConf(t *testing.T) {
 	builder.Finish(root)
 	b := builder.FinishedBytes()
 
-	out := PrepareConf(b)
+	out, _ := PrepareConf(b)
 	resp := pc.GetRootAsResp(out, 0)
 	assert.Equal(t, uint32(1), resp.ConfToken())
 
-	out = PrepareConf(b)
+	out, _ = PrepareConf(b)
 	resp = pc.GetRootAsResp(out, 0)
 	assert.Equal(t, uint32(2), resp.ConfToken())
 }
@@ -51,7 +51,7 @@ func TestGetRuleConf(t *testing.T) {
 	builder.Finish(root)
 	b := builder.FinishedBytes()
 
-	out := PrepareConf(b)
+	out, _ := PrepareConf(b)
 	resp := pc.GetRootAsResp(out, 0)
 	assert.Equal(t, uint32(3), resp.ConfToken())
 
diff --git a/internal/server/error.go b/internal/server/error.go
new file mode 100644
index 0000000..8ba517c
--- /dev/null
+++ b/internal/server/error.go
@@ -0,0 +1,44 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package server
+
+import (
+	"github.com/ReneKroon/ttlcache/v2"
+	A6Err "github.com/api7/ext-plugin-proto/go/A6/Err"
+	flatbuffers "github.com/google/flatbuffers/go"
+)
+
+var (
+	builder = flatbuffers.NewBuilder(256)
+)
+
+func ReportError(err error) []byte {
+	builder.Reset()
+
+	A6Err.RespStart(builder)
+
+	var code A6Err.Code
+	switch err {
+	case ttlcache.ErrNotFound:
+		code = A6Err.CodeCONF_TOKEN_NOT_FOUND
+	default:
+		code = A6Err.CodeSERVICE_UNAVAILABLE
+	}
+
+	A6Err.RespAddCode(builder, code)
+	resp := A6Err.RespEnd(builder)
+	builder.Finish(resp)
+	return builder.FinishedBytes()
+}
diff --git a/internal/server/error_test.go b/internal/server/error_test.go
new file mode 100644
index 0000000..9586ba5
--- /dev/null
+++ b/internal/server/error_test.go
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package server
+
+import (
+	"io"
+	"testing"
+	"time"
+
+	"github.com/apache/apisix-go-plugin-runner/internal/plugin"
+	A6Err "github.com/api7/ext-plugin-proto/go/A6/Err"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestReportErrorCacheToken(t *testing.T) {
+	plugin.InitCache(10 * time.Millisecond)
+
+	_, err := plugin.GetRuleConf(uint32(999999))
+	b := ReportError(err)
+	resp := A6Err.GetRootAsResp(b, 0)
+	assert.Equal(t, A6Err.CodeCONF_TOKEN_NOT_FOUND, resp.Code())
+}
+
+func TestReportErrorUnknownErr(t *testing.T) {
+	b := ReportError(io.EOF)
+	resp := A6Err.GetRootAsResp(b, 0)
+	assert.Equal(t, A6Err.CodeSERVICE_UNAVAILABLE, resp.Code())
+}
diff --git a/internal/server/server.go b/internal/server/server.go
index 0180ed6..8f333fb 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -90,7 +90,12 @@ func handleConn(c net.Conn) {
 		var out []byte
 		switch ty {
 		case RPCPrepareConf:
-			out = plugin.PrepareConf(buf)
+			out, err = plugin.PrepareConf(buf)
+		}
+
+		if err != nil {
+			ty = RPCError
+			out = ReportError(err)
 		}
 
 		size := len(out)

[apisix-go-plugin-runner] 18/22: perf: reuse objects

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit 8e69bfa957c36474d503209d6125e5402566e8f2
Author: spacewander <sp...@gmail.com>
AuthorDate: Wed May 26 14:40:39 2021 +0800

    perf: reuse objects
---
 internal/http/request.go       | 22 +++++++++++++++++++---
 internal/http/request_test.go  |  1 +
 internal/http/response.go      | 20 +++++++++++++++++++-
 internal/http/response_test.go |  1 +
 internal/plugin/plugin.go      |  3 +++
 5 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/internal/http/request.go b/internal/http/request.go
index 11c9ef4..c7f2e8d 100644
--- a/internal/http/request.go
+++ b/internal/http/request.go
@@ -17,6 +17,7 @@ package http
 import (
 	"net"
 	"net/http"
+	"sync"
 
 	pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http"
 	"github.com/api7/ext-plugin-proto/go/A6"
@@ -78,6 +79,11 @@ func (r *Request) Header() pkgHTTP.Header {
 	return r.hdr
 }
 
+func (r *Request) Reset() {
+	r.path = nil
+	r.hdr = nil
+}
+
 func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
 	if r.path == nil && r.hdr == nil {
 		return false
@@ -143,13 +149,23 @@ func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
 	return true
 }
 
+var reqPool = sync.Pool{
+	New: func() interface{} {
+		return &Request{}
+	},
+}
+
 func CreateRequest(buf []byte) *Request {
-	req := &Request{
-		r: hrc.GetRootAsReq(buf, 0),
-	}
+	req := reqPool.Get().(*Request)
+	req.r = hrc.GetRootAsReq(buf, 0)
 	return req
 }
 
+func ReuseRequest(r *Request) {
+	r.Reset()
+	reqPool.Put(r)
+}
+
 type Header struct {
 	http.Header
 }
diff --git a/internal/http/request_test.go b/internal/http/request_test.go
index 54fed1e..accaa38 100644
--- a/internal/http/request_test.go
+++ b/internal/http/request_test.go
@@ -116,6 +116,7 @@ func TestSrcIp(t *testing.T) {
 		out := buildReq(reqOpt{srcIP: ip})
 		r := CreateRequest(out)
 		assert.Equal(t, ip, r.SrcIP())
+		ReuseRequest(r)
 	}
 }
 
diff --git a/internal/http/response.go b/internal/http/response.go
index ef28b9a..d0aa8a4 100644
--- a/internal/http/response.go
+++ b/internal/http/response.go
@@ -17,6 +17,7 @@ package http
 import (
 	"bytes"
 	"net/http"
+	"sync"
 
 	"github.com/api7/ext-plugin-proto/go/A6"
 	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
@@ -51,6 +52,12 @@ func (r *Response) WriteHeader(statusCode int) {
 	r.code = statusCode
 }
 
+func (r *Response) Reset() {
+	r.body = nil
+	r.code = 0
+	r.hdr = nil
+}
+
 func (r *Response) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
 	if r.body == nil && r.code == 0 && len(r.hdr) == 0 {
 		return false
@@ -112,6 +119,17 @@ func (r *Response) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
 	return true
 }
 
+var respPool = sync.Pool{
+	New: func() interface{} {
+		return &Response{}
+	},
+}
+
 func CreateResponse() *Response {
-	return &Response{}
+	return respPool.Get().(*Response)
+}
+
+func ReuseResponse(r *Response) {
+	r.Reset()
+	respPool.Put(r)
 }
diff --git a/internal/http/response_test.go b/internal/http/response_test.go
index 5eddd4c..eadad62 100644
--- a/internal/http/response_test.go
+++ b/internal/http/response_test.go
@@ -41,6 +41,7 @@ func getStopAction(t *testing.T, b *flatbuffers.Builder) *hrc.Stop {
 
 func TestFetchChanges(t *testing.T) {
 	r := CreateResponse()
+	defer ReuseResponse(r)
 	r.Write([]byte("hello"))
 	h := r.Header()
 	h.Set("foo", "bar")
diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go
index 3ca4159..b88ade7 100644
--- a/internal/plugin/plugin.go
+++ b/internal/plugin/plugin.go
@@ -45,7 +45,10 @@ func reportAction(id uint32, req *inHTTP.Request, resp *inHTTP.Response) *flatbu
 
 func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
 	req := inHTTP.CreateRequest(buf)
+	defer inHTTP.ReuseRequest(req)
+
 	resp := inHTTP.CreateResponse()
+	defer inHTTP.ReuseResponse(resp)
 
 	token := req.ConfToken()
 	conf, err := GetRuleConf(token)

[apisix-go-plugin-runner] 16/22: feat: add Request.Header

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit 65cbe80b2aba18644d8e485dc2f3a4f7814af36b
Author: spacewander <sp...@gmail.com>
AuthorDate: Wed May 26 10:41:05 2021 +0800

    feat: add Request.Header
---
 internal/http/request.go      | 78 ++++++++++++++++++++++++++++++++++++++++-
 internal/http/request_test.go | 81 +++++++++++++++++++++++++++++++++++++++++--
 pkg/http/http.go              | 26 +++++++++++++-
 3 files changed, 180 insertions(+), 5 deletions(-)

diff --git a/internal/http/request.go b/internal/http/request.go
index 570c245..11c9ef4 100644
--- a/internal/http/request.go
+++ b/internal/http/request.go
@@ -16,7 +16,10 @@ package http
 
 import (
 	"net"
+	"net/http"
 
+	pkgHTTP "github.com/apache/apisix-go-plugin-runner/pkg/http"
+	"github.com/api7/ext-plugin-proto/go/A6"
 	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
 	flatbuffers "github.com/google/flatbuffers/go"
 )
@@ -26,6 +29,9 @@ type Request struct {
 	r *hrc.Req
 
 	path []byte
+
+	hdr    *Header
+	rawHdr http.Header
 }
 
 func (r *Request) ConfToken() uint32 {
@@ -55,8 +61,25 @@ func (r *Request) SetPath(path []byte) {
 	r.path = path
 }
 
+func (r *Request) Header() pkgHTTP.Header {
+	if r.hdr == nil {
+		hdr := newHeader()
+		hh := hdr.View()
+		size := r.r.HeadersLength()
+		obj := A6.TextEntry{}
+		for i := 0; i < size; i++ {
+			if r.r.Headers(&obj, i) {
+				hh.Add(string(obj.Name()), string(obj.Value()))
+			}
+		}
+		r.hdr = hdr
+		r.rawHdr = hdr.Clone()
+	}
+	return r.hdr
+}
+
 func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
-	if r.path == nil {
+	if r.path == nil && r.hdr == nil {
 		return false
 	}
 
@@ -65,10 +88,49 @@ func (r *Request) FetchChanges(id uint32, builder *flatbuffers.Builder) bool {
 		path = builder.CreateByteString(r.path)
 	}
 
+	var hdrVec flatbuffers.UOffsetT
+	if r.hdr != nil {
+		hdrs := []flatbuffers.UOffsetT{}
+		oldHdr := r.rawHdr
+		newHdr := r.hdr.View()
+		for n := range oldHdr {
+			if _, ok := newHdr[n]; !ok {
+				// deleted
+				name := builder.CreateString(n)
+				A6.TextEntryStart(builder)
+				A6.TextEntryAddName(builder, name)
+				te := A6.TextEntryEnd(builder)
+				hdrs = append(hdrs, te)
+			}
+		}
+		for n, v := range newHdr {
+			if raw, ok := oldHdr[n]; !ok || raw[0] != v[0] {
+				// set
+				name := builder.CreateString(n)
+				value := builder.CreateString(v[0])
+				A6.TextEntryStart(builder)
+				A6.TextEntryAddName(builder, name)
+				A6.TextEntryAddValue(builder, value)
+				te := A6.TextEntryEnd(builder)
+				hdrs = append(hdrs, te)
+			}
+		}
+		size := len(hdrs)
+		hrc.RewriteStartHeadersVector(builder, size)
+		for i := size - 1; i >= 0; i-- {
+			te := hdrs[i]
+			builder.PrependUOffsetT(te)
+		}
+		hdrVec = builder.EndVector(size)
+	}
+
 	hrc.RewriteStart(builder)
 	if path > 0 {
 		hrc.RewriteAddPath(builder, path)
 	}
+	if hdrVec > 0 {
+		hrc.RewriteAddHeaders(builder, hdrVec)
+	}
 	rewrite := hrc.RewriteEnd(builder)
 
 	hrc.RespStart(builder)
@@ -87,3 +149,17 @@ func CreateRequest(buf []byte) *Request {
 	}
 	return req
 }
+
+type Header struct {
+	http.Header
+}
+
+func newHeader() *Header {
+	return &Header{
+		Header: http.Header{},
+	}
+}
+
+func (h *Header) View() http.Header {
+	return h.Header
+}
diff --git a/internal/http/request_test.go b/internal/http/request_test.go
index 667138e..54fed1e 100644
--- a/internal/http/request_test.go
+++ b/internal/http/request_test.go
@@ -16,6 +16,7 @@ package http
 
 import (
 	"net"
+	"net/http"
 	"testing"
 
 	"github.com/apache/apisix-go-plugin-runner/internal/util"
@@ -38,10 +39,16 @@ func getRewriteAction(t *testing.T, b *flatbuffers.Builder) *hrc.Rewrite {
 	return nil
 }
 
+type pair struct {
+	name  string
+	value string
+}
+
 type reqOpt struct {
-	srcIP  []byte
-	method A6.Method
-	path   string
+	srcIP   []byte
+	method  A6.Method
+	path    string
+	headers []pair
 }
 
 func buildReq(opt reqOpt) []byte {
@@ -57,6 +64,28 @@ func buildReq(opt reqOpt) []byte {
 		path = builder.CreateString(opt.path)
 	}
 
+	hdrLen := len(opt.headers)
+	var hdrVec flatbuffers.UOffsetT
+	if hdrLen > 0 {
+		hdrs := []flatbuffers.UOffsetT{}
+		for _, v := range opt.headers {
+			name := builder.CreateString(v.name)
+			value := builder.CreateString(v.value)
+			A6.TextEntryStart(builder)
+			A6.TextEntryAddName(builder, name)
+			A6.TextEntryAddValue(builder, value)
+			te := A6.TextEntryEnd(builder)
+			hdrs = append(hdrs, te)
+		}
+		size := len(hdrs)
+		hrc.StopStartHeadersVector(builder, size)
+		for i := size - 1; i >= 0; i-- {
+			te := hdrs[i]
+			builder.PrependUOffsetT(te)
+		}
+		hdrVec = builder.EndVector(size)
+	}
+
 	hrc.ReqStart(builder)
 	hrc.ReqAddId(builder, 233)
 	hrc.ReqAddConfToken(builder, 1)
@@ -69,6 +98,9 @@ func buildReq(opt reqOpt) []byte {
 	if path > 0 {
 		hrc.ReqAddPath(builder, path)
 	}
+	if hdrVec > 0 {
+		hrc.ReqAddHeaders(builder, hdrVec)
+	}
 	r := hrc.ReqEnd(builder)
 	builder.Finish(r)
 	return builder.FinishedBytes()
@@ -111,3 +143,46 @@ func TestPath(t *testing.T) {
 	rewrite := getRewriteAction(t, builder)
 	assert.Equal(t, "/go", string(rewrite.Path()))
 }
+
+func TestHeader(t *testing.T) {
+	out := buildReq(reqOpt{headers: []pair{
+		{"k", "v"},
+		{"cache-control", "no-cache"},
+		{"cache-control", "no-store"},
+		{"cat", "dog"},
+	}})
+	r := CreateRequest(out)
+	hdr := r.Header()
+	assert.Equal(t, "v", hdr.Get("k"))
+	assert.Equal(t, "no-cache", hdr.Get("Cache-Control"))
+	assert.Equal(t, "no-cache", hdr.Get("cache-control"))
+
+	hdr.Del("empty")
+	hdr.Del("k")
+	assert.Equal(t, "", hdr.Get("k"))
+
+	hdr.Set("cache-control", "max-age=10s")
+	assert.Equal(t, "max-age=10s", hdr.Get("Cache-Control"))
+	hdr.Del("cache-Control")
+	assert.Equal(t, "", hdr.Get("cache-control"))
+
+	hdr.Set("k", "v2")
+	hdr.Del("cat")
+
+	builder := util.GetBuilder()
+	assert.True(t, r.FetchChanges(1, builder))
+	rewrite := getRewriteAction(t, builder)
+	assert.Equal(t, 3, rewrite.HeadersLength())
+
+	exp := http.Header{}
+	exp.Set("Cache-Control", "")
+	exp.Set("cat", "")
+	exp.Set("k", "v2")
+	res := http.Header{}
+	for i := 0; i < rewrite.HeadersLength(); i++ {
+		e := &A6.TextEntry{}
+		rewrite.Headers(e, i)
+		res.Add(string(e.Name()), string(e.Value()))
+	}
+	assert.Equal(t, exp, res)
+}
diff --git a/pkg/http/http.go b/pkg/http/http.go
index ebae8ac..cbbceeb 100644
--- a/pkg/http/http.go
+++ b/pkg/http/http.go
@@ -14,7 +14,10 @@
 // limitations under the License.
 package http
 
-import "net"
+import (
+	"net"
+	"net/http"
+)
 
 // Request represents the HTTP request received by APISIX.
 // We don't use net/http's Request because it doesn't suit our purpose.
@@ -38,4 +41,25 @@ type Request interface {
 	Path() []byte
 	// SetPath is the setter for Path
 	SetPath([]byte)
+	// Header returns the HTTP headers
+	Header() Header
+}
+
+// Header is like http.Header, but only implements the subset of its methods
+type Header interface {
+	// Set sets the header entries associated with key to the single element value.
+	// It replaces any existing values associated with key.
+	// The key is case insensitive
+	Set(key, value string)
+	// Del deletes the values associated with key. The key is case insensitive
+	Del(key string)
+	// Get gets the first value associated with the given key.
+	// If there are no values associated with the key, Get returns "".
+	// It is case insensitive
+	Get(key string) string
+	// View returns the internal structure. It is expected for read operations. Any write operation
+	// won't be recorded
+	View() http.Header
+
+	// TODO: support Add
 }

[apisix-go-plugin-runner] 19/22: fix: miss pkg

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit 56ca82477fe8a31684a5cded01af9cd7d475daf9
Author: spacewander <sp...@gmail.com>
AuthorDate: Wed May 26 15:25:29 2021 +0800

    fix: miss pkg
---
 Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Makefile b/Makefile
index 1c37ad7..1f124cb 100644
--- a/Makefile
+++ b/Makefile
@@ -61,6 +61,7 @@ compress-tar:
 	tar -zcvf $(RELEASE_SRC).tgz \
 	./cmd \
 	./internal \
+	./pkg \
 	LICENSE \
 	Makefile \
 	go.mod \

[apisix-go-plugin-runner] 04/22: test: for main's version cmd

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit b2496e11c5f181a809583f50758f47c6584585b7
Author: spacewander <sp...@gmail.com>
AuthorDate: Wed May 19 11:45:47 2021 +0800

    test: for main's version cmd
---
 cmd/go-runner/main.go      |  9 +++++++--
 cmd/go-runner/main_test.go | 21 +++++++++++++++++++++
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/cmd/go-runner/main.go b/cmd/go-runner/main.go
index 38b83be..74851db 100644
--- a/cmd/go-runner/main.go
+++ b/cmd/go-runner/main.go
@@ -16,6 +16,7 @@ package main
 
 import (
 	"fmt"
+	"io"
 	"os"
 
 	"github.com/spf13/cobra"
@@ -23,6 +24,10 @@ import (
 	"github.com/apache/apisix-go-plugin-runner/internal/server"
 )
 
+var (
+	InfoOut io.Writer = os.Stdout
+)
+
 func newVersionCommand() *cobra.Command {
 	var long bool
 	cmd := &cobra.Command{
@@ -30,9 +35,9 @@ func newVersionCommand() *cobra.Command {
 		Short: "version",
 		Run: func(cmd *cobra.Command, _ []string) {
 			if long {
-				fmt.Print(longVersion())
+				fmt.Fprint(InfoOut, longVersion())
 			} else {
-				fmt.Printf("version %s\n", shortVersion())
+				fmt.Fprintf(InfoOut, "version %s\n", shortVersion())
 			}
 		},
 	}
diff --git a/cmd/go-runner/main_test.go b/cmd/go-runner/main_test.go
new file mode 100644
index 0000000..49d7446
--- /dev/null
+++ b/cmd/go-runner/main_test.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+	"bytes"
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestVersion(t *testing.T) {
+	args := []string{"version", "--long"}
+	os.Args = append([]string{"cmd"}, args...)
+
+	var b bytes.Buffer
+	InfoOut = &b
+	main()
+
+	assert.True(t, strings.Contains(b.String(), "Building OS/Arch"))
+}

[apisix-go-plugin-runner] 01/22: Init commit

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit d0e3a4e1c0db373cc0488b6e926aead23484d445
Author: spacewander <sp...@gmail.com>
AuthorDate: Mon May 17 15:09:58 2021 +0800

    Init commit
---
 cmd/go-runner/main.go          |  21 ++++++
 go.mod                         |   9 +++
 go.sum                         |  54 ++++++++++++++
 internal/log/log.go            |  58 +++++++++++++++
 internal/plugin/conf.go        |  19 +++++
 internal/server/server.go      | 164 +++++++++++++++++++++++++++++++++++++++++
 internal/server/server_test.go |  63 ++++++++++++++++
 7 files changed, 388 insertions(+)

diff --git a/cmd/go-runner/main.go b/cmd/go-runner/main.go
new file mode 100644
index 0000000..e01254e
--- /dev/null
+++ b/cmd/go-runner/main.go
@@ -0,0 +1,21 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package main
+
+import "github.com/apache/apisix-go-plugin-runner/internal/server"
+
+func main() {
+	server.Run()
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..210b8f7
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,9 @@
+module github.com/apache/apisix-go-plugin-runner
+
+go 1.15
+
+require (
+	github.com/stretchr/testify v1.7.0
+	go.uber.org/multierr v1.7.0 // indirect
+	go.uber.org/zap v1.16.0
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..25be7fe
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,54 @@
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
+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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
+go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
+go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
+go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
+go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
+go.uber.org/multierr v1.7.0 h1:zaiO/rmgFjbmCXdSYJWQcdvOCsthmdaHfr3Gm2Kx4Ec=
+go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
+go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
+go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
+go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+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/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
diff --git a/internal/log/log.go b/internal/log/log.go
new file mode 100644
index 0000000..4b4c28d
--- /dev/null
+++ b/internal/log/log.go
@@ -0,0 +1,58 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package log
+
+import (
+	"os"
+
+	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
+)
+
+var (
+	logger *zap.SugaredLogger
+)
+
+func newLogger() *zap.SugaredLogger {
+	var level = zap.NewAtomicLevel()
+	level.SetLevel(zapcore.InfoLevel)
+
+	core := zapcore.NewCore(
+		zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()),
+		os.Stdout,
+		level)
+	lg := zap.New(core, zap.AddStacktrace(zap.ErrorLevel), zap.AddCaller())
+	return lg.Sugar()
+}
+
+func init() {
+	logger = newLogger()
+}
+
+func Infof(template string, args ...interface{}) {
+	logger.Infof(template, args...)
+}
+
+func Warnf(template string, args ...interface{}) {
+	logger.Warnf(template, args...)
+}
+
+func Errorf(template string, args ...interface{}) {
+	logger.Errorf(template, args...)
+}
+
+func Fatalf(template string, args ...interface{}) {
+	logger.Fatalf(template, args...)
+}
diff --git a/internal/plugin/conf.go b/internal/plugin/conf.go
new file mode 100644
index 0000000..843ac0b
--- /dev/null
+++ b/internal/plugin/conf.go
@@ -0,0 +1,19 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package plugin
+
+func PrepareConf(buf []byte) []byte {
+	return buf
+}
diff --git a/internal/server/server.go b/internal/server/server.go
new file mode 100644
index 0000000..162a704
--- /dev/null
+++ b/internal/server/server.go
@@ -0,0 +1,164 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package server
+
+import (
+	"encoding/binary"
+	"errors"
+	"io"
+	"net"
+	"os"
+	"os/signal"
+	"syscall"
+
+	"github.com/apache/apisix-go-plugin-runner/internal/log"
+	"github.com/apache/apisix-go-plugin-runner/internal/plugin"
+)
+
+const (
+	HeaderLen   = 4
+	MaxDataSize = 2<<24 - 1
+	SockAddrEnv = "APISIX_LISTEN_ADDRESS"
+)
+
+const (
+	RPCError = iota
+	RPCPrepareConf
+	RPCHTTPReqCall
+)
+
+func readErr(n int, err error) {
+	if err == io.EOF && n != 0 {
+		err = errors.New("truncated")
+	}
+	if err != io.EOF {
+		log.Errorf("read: %s", err)
+	}
+}
+
+func writeErr(n int, err error) {
+	if err != nil {
+		log.Errorf("write: %s", err)
+	}
+}
+
+func handleConn(c net.Conn) {
+	log.Infof("Client connected (%s)", c.RemoteAddr().Network())
+	defer c.Close()
+
+	header := make([]byte, HeaderLen)
+	for {
+		n, err := c.Read(header)
+		if err != nil {
+			readErr(n, err)
+			break
+		}
+
+		ty := header[0]
+		// we only use last 3 bytes to store the length, so the first byte is
+		// consider zero
+		header[0] = 0
+		length := binary.BigEndian.Uint32(header)
+
+		log.Infof("receive rpc type: %d data length: %d", ty, length)
+
+		buf := make([]byte, length)
+		n, err = c.Read(buf)
+		if err != nil {
+			readErr(n, err)
+			break
+		}
+
+		var out []byte
+		switch ty {
+		case RPCPrepareConf:
+			out = plugin.PrepareConf(buf)
+		}
+
+		size := len(out)
+		if size > MaxDataSize {
+			log.Errorf("the max length of data is %d but got %d", MaxDataSize, size)
+			continue
+		}
+
+		binary.BigEndian.PutUint32(header, uint32(size))
+		header[0] = ty
+
+		n, err = c.Write(header)
+		if err != nil {
+			writeErr(n, err)
+			break
+		}
+
+		n, err = c.Write(out)
+		if err != nil {
+			writeErr(n, err)
+			break
+		}
+	}
+}
+
+func getSockAddr() string {
+	path := os.Getenv(SockAddrEnv)
+	if path == "" {
+		log.Errorf("invalid socket address: %s", path)
+		return ""
+	}
+	return path
+}
+
+func Run() {
+	sockAddr := getSockAddr()
+	if sockAddr == "" {
+		log.Fatalf("A valid socket address should be set via environment variable %s", SockAddrEnv)
+	}
+	log.Infof("listening to %s", sockAddr)
+
+	if err := os.RemoveAll(sockAddr); err != nil {
+		log.Fatalf("remove file %s: %s", sockAddr, err)
+	}
+
+	l, err := net.Listen("unix", sockAddr)
+	if err != nil {
+		log.Fatalf("listen %s: %s", sockAddr, err)
+	}
+	defer l.Close()
+
+	done := make(chan struct{})
+	quit := make(chan os.Signal, 1)
+	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+
+	go func() {
+		for {
+			select {
+			case <-done:
+				return
+			default:
+			}
+
+			conn, err := l.Accept()
+			if err != nil {
+				log.Errorf("accept: %s", err)
+				continue
+			}
+
+			go handleConn(conn)
+		}
+	}()
+
+	sig := <-quit
+	log.Infof("server receive %s and exit", sig.String())
+	close(done)
+}
diff --git a/internal/server/server_test.go b/internal/server/server_test.go
new file mode 100644
index 0000000..81529bf
--- /dev/null
+++ b/internal/server/server_test.go
@@ -0,0 +1,63 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package server
+
+import (
+	"encoding/binary"
+	"net"
+	"os"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestGetSockAddr(t *testing.T) {
+	os.Unsetenv(SockAddrEnv)
+	assert.Equal(t, "", getSockAddr())
+
+	os.Setenv(SockAddrEnv, "/tmp/x.sock")
+	assert.Equal(t, "/tmp/x.sock", getSockAddr())
+}
+
+func TestRun(t *testing.T) {
+	addr := "/tmp/x.sock"
+	os.Setenv(SockAddrEnv, addr)
+
+	go func() {
+		Run()
+	}()
+
+	time.Sleep(100 * time.Millisecond)
+	header := make([]byte, 4)
+	binary.BigEndian.PutUint32(header, uint32(32))
+	header[0] = 1
+	cases := []struct {
+		header []byte
+	}{
+		// dad header
+		{[]byte("a")},
+		// header without body
+		{header},
+		// header without body truncated
+		{append(header, 32)},
+	}
+
+	for _, c := range cases {
+		conn, err := net.DialTimeout("unix", addr, 1*time.Second)
+		assert.NotNil(t, conn, err)
+		conn.Write(c.header)
+	}
+}

[apisix-go-plugin-runner] 11/22: feat: handle CodeBAD_REQUEST in error protocol

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit 03e11816458774f8e77517cfccbe5ddded08e5b0
Author: spacewander <sp...@gmail.com>
AuthorDate: Fri May 21 10:50:02 2021 +0800

    feat: handle CodeBAD_REQUEST in error protocol
---
 internal/server/error.go      | 17 ++++++++++++++++-
 internal/server/error_test.go |  7 +++++++
 internal/server/server.go     |  5 +++--
 3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/internal/server/error.go b/internal/server/error.go
index 81d77c3..75ff24c 100644
--- a/internal/server/error.go
+++ b/internal/server/error.go
@@ -15,6 +15,8 @@
 package server
 
 import (
+	"fmt"
+
 	"github.com/ReneKroon/ttlcache/v2"
 	A6Err "github.com/api7/ext-plugin-proto/go/A6/Err"
 	flatbuffers "github.com/google/flatbuffers/go"
@@ -22,6 +24,14 @@ import (
 	"github.com/apache/apisix-go-plugin-runner/internal/util"
 )
 
+type UnknownType struct {
+	ty byte
+}
+
+func (err UnknownType) Error() string {
+	return fmt.Sprintf("unknown type %d", err.ty)
+}
+
 func ReportError(err error) *flatbuffers.Builder {
 	builder := util.GetBuilder()
 	A6Err.RespStart(builder)
@@ -31,7 +41,12 @@ func ReportError(err error) *flatbuffers.Builder {
 	case ttlcache.ErrNotFound:
 		code = A6Err.CodeCONF_TOKEN_NOT_FOUND
 	default:
-		code = A6Err.CodeSERVICE_UNAVAILABLE
+		switch err.(type) {
+		case UnknownType:
+			code = A6Err.CodeBAD_REQUEST
+		default:
+			code = A6Err.CodeSERVICE_UNAVAILABLE
+		}
 	}
 
 	A6Err.RespAddCode(builder, code)
diff --git a/internal/server/error_test.go b/internal/server/error_test.go
index fb5b426..db9133e 100644
--- a/internal/server/error_test.go
+++ b/internal/server/error_test.go
@@ -34,6 +34,13 @@ func TestReportErrorCacheToken(t *testing.T) {
 	assert.Equal(t, A6Err.CodeCONF_TOKEN_NOT_FOUND, resp.Code())
 }
 
+func TestReportErrorUnknownType(t *testing.T) {
+	b := ReportError(UnknownType{23})
+	out := b.FinishedBytes()
+	resp := A6Err.GetRootAsResp(out, 0)
+	assert.Equal(t, A6Err.CodeBAD_REQUEST, resp.Code())
+}
+
 func TestReportErrorUnknownErr(t *testing.T) {
 	b := ReportError(io.EOF)
 	out := b.FinishedBytes()
diff --git a/internal/server/server.go b/internal/server/server.go
index 88f2a17..a856066 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -103,17 +103,18 @@ func handleConn(c net.Conn) {
 		case RPCHTTPReqCall:
 			bd, err = http.HTTPReqCall(buf)
 		default:
-			err = fmt.Errorf("unknown type %d", ty)
+			err = UnknownType{ty}
 		}
 
 		out := bd.FinishedBytes()
 		size := len(out)
 		if size > MaxDataSize {
 			err = fmt.Errorf("the max length of data is %d but got %d", MaxDataSize, size)
-			log.Errorf("%s", err)
 		}
 
 		if err != nil {
+			log.Errorf("%s", err)
+
 			ty = RPCError
 			util.PutBuilder(bd)
 			bd = ReportError(err)

[apisix-go-plugin-runner] 22/22: fix: clean up sock file

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit cfb8bbfa32a62d80ec28ea8576d19c863932cc61
Author: spacewander <sp...@gmail.com>
AuthorDate: Mon May 31 10:06:20 2021 +0800

    fix: clean up sock file
---
 internal/server/server.go      |  7 +++++++
 internal/server/server_test.go | 10 +++++++++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/internal/server/server.go b/internal/server/server.go
index 7299252..fe2dcea 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -175,9 +175,16 @@ func Run() {
 	}
 	log.Infof("listening to %s", sockAddr)
 
+	// clean up sock file created by others
 	if err := os.RemoveAll(sockAddr); err != nil {
 		log.Fatalf("remove file %s: %s", sockAddr, err)
 	}
+	// clean up sock file created by me
+	defer func() {
+		if err := os.RemoveAll(sockAddr); err != nil {
+			log.Errorf("remove file %s: %s", sockAddr, err)
+		}
+	}()
 
 	l, err := net.Listen("unix", sockAddr)
 	if err != nil {
diff --git a/internal/server/server_test.go b/internal/server/server_test.go
index 4a5b3dd..497e073 100644
--- a/internal/server/server_test.go
+++ b/internal/server/server_test.go
@@ -19,6 +19,7 @@ import (
 	"encoding/binary"
 	"net"
 	"os"
+	"syscall"
 	"testing"
 	"time"
 
@@ -34,7 +35,8 @@ func TestGetSockAddr(t *testing.T) {
 }
 
 func TestRun(t *testing.T) {
-	addr := "unix:/tmp/x.sock"
+	path := "/tmp/x.sock"
+	addr := "unix:" + path
 	os.Setenv(SockAddrEnv, addr)
 	os.Setenv(ConfCacheTTLEnv, "60")
 
@@ -65,4 +67,10 @@ func TestRun(t *testing.T) {
 		defer conn.Close()
 		conn.Write(c.header)
 	}
+
+	syscall.Kill(syscall.Getpid(), syscall.SIGINT)
+	time.Sleep(10 * time.Millisecond)
+
+	_, err := os.Stat(path)
+	assert.True(t, os.IsNotExist(err))
 }

[apisix-go-plugin-runner] 10/22: chore: tweak for test

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit 669598cd58bd7e6769a40b7c97dfe4d3d68f676b
Author: spacewander <sp...@gmail.com>
AuthorDate: Thu May 20 18:07:13 2021 +0800

    chore: tweak for test
---
 internal/http/http.go          | 30 ++++++++++++++++++++++++++++++
 internal/server/server.go      |  8 ++++++--
 internal/server/server_test.go |  8 ++++----
 3 files changed, 40 insertions(+), 6 deletions(-)

diff --git a/internal/http/http.go b/internal/http/http.go
new file mode 100644
index 0000000..d946102
--- /dev/null
+++ b/internal/http/http.go
@@ -0,0 +1,30 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package http
+
+import (
+	flatbuffers "github.com/google/flatbuffers/go"
+
+	"github.com/apache/apisix-go-plugin-runner/internal/util"
+	hrc "github.com/api7/ext-plugin-proto/go/A6/HTTPReqCall"
+)
+
+func HTTPReqCall(buf []byte) (*flatbuffers.Builder, error) {
+	builder := util.GetBuilder()
+	hrc.RespStart(builder)
+	resp := hrc.RespEnd(builder)
+	builder.Finish(resp)
+	return builder, nil
+}
diff --git a/internal/server/server.go b/internal/server/server.go
index 52c5624..88f2a17 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -23,9 +23,11 @@ import (
 	"os"
 	"os/signal"
 	"strconv"
+	"strings"
 	"syscall"
 	"time"
 
+	"github.com/apache/apisix-go-plugin-runner/internal/http"
 	"github.com/apache/apisix-go-plugin-runner/internal/log"
 	"github.com/apache/apisix-go-plugin-runner/internal/plugin"
 	"github.com/apache/apisix-go-plugin-runner/internal/util"
@@ -98,6 +100,8 @@ func handleConn(c net.Conn) {
 		switch ty {
 		case RPCPrepareConf:
 			bd, err = plugin.PrepareConf(buf)
+		case RPCHTTPReqCall:
+			bd, err = http.HTTPReqCall(buf)
 		default:
 			err = fmt.Errorf("unknown type %d", ty)
 		}
@@ -148,11 +152,11 @@ func getConfCacheTTL() time.Duration {
 
 func getSockAddr() string {
 	path := os.Getenv(SockAddrEnv)
-	if path == "" {
+	if !strings.HasPrefix(path, "unix:") {
 		log.Errorf("invalid socket address: %s", path)
 		return ""
 	}
-	return path
+	return path[len("unix:"):]
 }
 
 func Run() {
diff --git a/internal/server/server_test.go b/internal/server/server_test.go
index bd483eb..4a5b3dd 100644
--- a/internal/server/server_test.go
+++ b/internal/server/server_test.go
@@ -29,12 +29,12 @@ func TestGetSockAddr(t *testing.T) {
 	os.Unsetenv(SockAddrEnv)
 	assert.Equal(t, "", getSockAddr())
 
-	os.Setenv(SockAddrEnv, "/tmp/x.sock")
+	os.Setenv(SockAddrEnv, "unix:/tmp/x.sock")
 	assert.Equal(t, "/tmp/x.sock", getSockAddr())
 }
 
 func TestRun(t *testing.T) {
-	addr := "/tmp/x.sock"
+	addr := "unix:/tmp/x.sock"
 	os.Setenv(SockAddrEnv, addr)
 	os.Setenv(ConfCacheTTLEnv, "60")
 
@@ -60,9 +60,9 @@ func TestRun(t *testing.T) {
 	}
 
 	for _, c := range cases {
-		conn, err := net.DialTimeout("unix", addr, 1*time.Second)
-		defer conn.Close()
+		conn, err := net.DialTimeout("unix", addr[len("unix:"):], 1*time.Second)
 		assert.NotNil(t, conn, err)
+		defer conn.Close()
 		conn.Write(c.header)
 	}
 }

[apisix-go-plugin-runner] 06/22: refacor: rename method

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit d35ce282abf44818c49cdec6d336eb1dbd1b4183
Author: spacewander <sp...@gmail.com>
AuthorDate: Wed May 19 15:30:56 2021 +0800

    refacor: rename method
---
 internal/plugin/conf.go       | 2 +-
 internal/plugin/conf_test.go  | 6 +++---
 internal/server/error_test.go | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/internal/plugin/conf.go b/internal/plugin/conf.go
index ae7d0c6..6c79cb6 100644
--- a/internal/plugin/conf.go
+++ b/internal/plugin/conf.go
@@ -37,7 +37,7 @@ var (
 	cacheCounter uint32 = 0
 )
 
-func InitCache(ttl time.Duration) {
+func InitConfCache(ttl time.Duration) {
 	cache = ttlcache.NewCache()
 	cache.SetTTL(ttl)
 	cache.SkipTTLExtensionOnHit(false)
diff --git a/internal/plugin/conf_test.go b/internal/plugin/conf_test.go
index 1b2e668..b4135a5 100644
--- a/internal/plugin/conf_test.go
+++ b/internal/plugin/conf_test.go
@@ -26,7 +26,7 @@ import (
 )
 
 func TestPrepareConf(t *testing.T) {
-	InitCache(10 * time.Millisecond)
+	InitConfCache(10 * time.Millisecond)
 
 	builder := flatbuffers.NewBuilder(1024)
 	pc.ReqStart(builder)
@@ -44,7 +44,7 @@ func TestPrepareConf(t *testing.T) {
 }
 
 func TestGetRuleConf(t *testing.T) {
-	InitCache(1 * time.Millisecond)
+	InitConfCache(1 * time.Millisecond)
 	builder := flatbuffers.NewBuilder(1024)
 	pc.ReqStart(builder)
 	root := pc.ReqEnd(builder)
@@ -64,7 +64,7 @@ func TestGetRuleConf(t *testing.T) {
 }
 
 func TestGetRuleConfCheckConf(t *testing.T) {
-	InitCache(1 * time.Millisecond)
+	InitConfCache(1 * time.Millisecond)
 	builder := flatbuffers.NewBuilder(1024)
 
 	name := builder.CreateString("echo")
diff --git a/internal/server/error_test.go b/internal/server/error_test.go
index 9586ba5..4d8bb21 100644
--- a/internal/server/error_test.go
+++ b/internal/server/error_test.go
@@ -25,7 +25,7 @@ import (
 )
 
 func TestReportErrorCacheToken(t *testing.T) {
-	plugin.InitCache(10 * time.Millisecond)
+	plugin.InitConfCache(10 * time.Millisecond)
 
 	_, err := plugin.GetRuleConf(uint32(999999))
 	b := ReportError(err)

[apisix-go-plugin-runner] 17/22: chore: increase log level and add -race flag

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit f9169fbacbb4634c1139e3f95106f6d5ac574243
Author: spacewander <sp...@gmail.com>
AuthorDate: Wed May 26 11:17:08 2021 +0800

    chore: increase log level and add -race flag
---
 Makefile            | 2 +-
 internal/log/log.go | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 3fba8fc..1c37ad7 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,7 @@ GO_LDFLAGS ?= "-X '$(VERSYM)=$(VERSION)' -X '$(GITSHASYM)=$(GITSHA)' -X '$(BUILD
 .PHONY: build
 build:
 	cd cmd/go-runner && \
-	go build -ldflags $(GO_LDFLAGS) && \
+	go build $(GO_BUILD_FLAGS) -ldflags $(GO_LDFLAGS) && \
 	mv go-runner ../..
 
 .PHONY: lint
diff --git a/internal/log/log.go b/internal/log/log.go
index 4b4c28d..b68ec2a 100644
--- a/internal/log/log.go
+++ b/internal/log/log.go
@@ -27,7 +27,7 @@ var (
 
 func newLogger() *zap.SugaredLogger {
 	var level = zap.NewAtomicLevel()
-	level.SetLevel(zapcore.InfoLevel)
+	level.SetLevel(zapcore.WarnLevel)
 
 	core := zapcore.NewCore(
 		zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()),

[apisix-go-plugin-runner] 07/22: feat: init cache according to the env

Posted by sp...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

spacewander pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-go-plugin-runner.git

commit 8dd97b28c8c906f5f294a6d326441daa80813365
Author: spacewander <sp...@gmail.com>
AuthorDate: Wed May 19 17:06:45 2021 +0800

    feat: init cache according to the env
---
 internal/server/server.go      | 25 ++++++++++++++++++++++++-
 internal/server/server_test.go |  1 +
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/internal/server/server.go b/internal/server/server.go
index 8f333fb..26ab5cf 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -21,7 +21,9 @@ import (
 	"net"
 	"os"
 	"os/signal"
+	"strconv"
 	"syscall"
+	"time"
 
 	"github.com/apache/apisix-go-plugin-runner/internal/log"
 	"github.com/apache/apisix-go-plugin-runner/internal/plugin"
@@ -30,7 +32,9 @@ import (
 const (
 	HeaderLen   = 4
 	MaxDataSize = 2<<24 - 1
-	SockAddrEnv = "APISIX_LISTEN_ADDRESS"
+
+	SockAddrEnv     = "APISIX_LISTEN_ADDRESS"
+	ConfCacheTTLEnv = "APISIX_CONF_EXPIRE_TIME"
 )
 
 const (
@@ -121,6 +125,16 @@ func handleConn(c net.Conn) {
 	}
 }
 
+func getConfCacheTTL() time.Duration {
+	ttl := os.Getenv(ConfCacheTTLEnv)
+	n, err := strconv.Atoi(ttl)
+	if err != nil || n <= 0 {
+		log.Errorf("invalid cache ttl: %s", ttl)
+		return 0
+	}
+	return time.Duration(n) * time.Second
+}
+
 func getSockAddr() string {
 	path := os.Getenv(SockAddrEnv)
 	if path == "" {
@@ -131,6 +145,15 @@ func getSockAddr() string {
 }
 
 func Run() {
+	ttl := getConfCacheTTL()
+	if ttl == 0 {
+		log.Fatalf("A valid conf cache ttl should be set via environment variable %s",
+			ConfCacheTTLEnv)
+	}
+	log.Infof("conf cache ttl is %v", ttl)
+
+	plugin.InitConfCache(ttl)
+
 	sockAddr := getSockAddr()
 	if sockAddr == "" {
 		log.Fatalf("A valid socket address should be set via environment variable %s", SockAddrEnv)
diff --git a/internal/server/server_test.go b/internal/server/server_test.go
index c62634b..bd483eb 100644
--- a/internal/server/server_test.go
+++ b/internal/server/server_test.go
@@ -36,6 +36,7 @@ func TestGetSockAddr(t *testing.T) {
 func TestRun(t *testing.T) {
 	addr := "/tmp/x.sock"
 	os.Setenv(SockAddrEnv, addr)
+	os.Setenv(ConfCacheTTLEnv, "60")
 
 	go func() {
 		Run()