diff --git a/cmd/gateway/main.go b/cmd/gateway/main.go index 27170c3..12374f7 100644 --- a/cmd/gateway/main.go +++ b/cmd/gateway/main.go @@ -4,10 +4,9 @@ import ( "log" "github.com/begonia-org/begonia/config" + "github.com/begonia-org/begonia/gateway" "github.com/begonia-org/begonia/internal" "github.com/spf13/cobra" - "github.com/begonia-org/begonia/gateway" - ) // var ProviderSet = wire.NewSet(NewMasterCmd) diff --git a/config/settings.yml b/config/settings.yml index 18cfc57..1abcc40 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -109,14 +109,14 @@ test: private_key: "/tmp/auth_private_key.pem" public_key: "/tmp/auth_public_key.pem" common: - rdb_key_prefix: "begonia" - filter_key_prefix: "begonia:filter" - app_key_prefix: "begonia:kv:app" - blacklist_key_prefix: "begonia:blacklist" - pubsub_key_prefix: "begonia:pubsub" + cache_prefix_key: "begonia" + filter_key_prefix: "filter" + app_key_prefix: "kv:app" + # blacklist_key_prefix: "blacklist" + pubsub_key_prefix: "pubsub" multi_cache_strategy: 1 - kv_prefix: "begonia:cache" - pubsub_key_channel: "begonia:pubsub:channel" + kv_prefix: "cache" + pubsub_key_channel: "pubsub:channel" etcd: endpoint: prefix: "/begonia/endpoints" diff --git a/gateway/exception_test.go b/gateway/exception_test.go index 3481963..be8175a 100644 --- a/gateway/exception_test.go +++ b/gateway/exception_test.go @@ -44,14 +44,14 @@ func TestUnaryInterceptor(t *testing.T) { mid := NewException(Log) ctx := context.Background() - handler:= func(ctx context.Context, req interface{}) (interface{}, error) { + handler := func(ctx context.Context, req interface{}) (interface{}, error) { panic("test panic error") } _, err := mid.UnaryInterceptor(ctx, nil, &grpc.UnaryServerInfo{}, handler) c.So(err, c.ShouldNotBeNil) c.So(err.Error(), c.ShouldContainSubstring, "test panic error") - handler2:= func(ctx context.Context, req interface{}) (interface{}, error) { + handler2 := func(ctx context.Context, req interface{}) (interface{}, error) { return nil, fmt.Errorf("test error") } _, err2 := mid.UnaryInterceptor(ctx, nil, &grpc.UnaryServerInfo{}, handler2) diff --git a/gateway/formdata_test.go b/gateway/formdata_test.go index 453eee9..f6244d8 100644 --- a/gateway/formdata_test.go +++ b/gateway/formdata_test.go @@ -82,8 +82,8 @@ func TestFormDataContentType(t *testing.T) { c.So(pb.SfixedData, c.ShouldEqual, 11949) c.So(pb.Sfixed32Data, c.ShouldEqual, 21949) c.So(pb.Fixed32Data, c.ShouldEqual, 31949) - marshal:=&FormDataMarshaler{} - c.So(marshal.ContentType(nil),c.ShouldEqual,"multipart/form-data") + marshal := &FormDataMarshaler{} + c.So(marshal.ContentType(nil), c.ShouldEqual, "multipart/form-data") }) } @@ -108,8 +108,8 @@ func TestFormUrlEncodedContentType(t *testing.T) { c.So(err, c.ShouldBeNil) c.So(pb.Message, c.ShouldEqual, "John Doe") c.So(pb.Allow, c.ShouldEqual, api.EnumAllow_DENY) - marshal:=&FormUrlEncodedMarshaler{} - c.So(marshal.ContentType(nil),c.ShouldEqual,"application/x-www-form-urlencoded") + marshal := &FormUrlEncodedMarshaler{} + c.So(marshal.ContentType(nil), c.ShouldEqual, "application/x-www-form-urlencoded") }) } @@ -136,21 +136,20 @@ func TestFormUrlEncodedErr(t *testing.T) { formData.Add("message", "John Doe") formData.Add("allow", api.EnumAllow_DENY.String()) _, filePath, _, _ := runtime.Caller(0) - + // 添加文件 data, _ := os.ReadFile(filePath) formData.Add("byte_data", string(data)) pb := &api.ExampleMessage{} dpb := dynamicpb.NewMessage(pb.ProtoReflect().Descriptor()) decoder := &FormUrlEncodedDecoder{r: strings.NewReader(formData.Encode())} - patch:=gomonkey.ApplyFuncReturn(caseV.patch, caseV.output...) + patch := gomonkey.ApplyFuncReturn(caseV.patch, caseV.output...) defer patch.Reset() err := decoder.Decode(dpb) c.So(err, c.ShouldNotBeNil) patch.Reset() } - }) } diff --git a/gateway/mask.go b/gateway/mask.go index 111e83e..f62dfef 100644 --- a/gateway/mask.go +++ b/gateway/mask.go @@ -83,6 +83,6 @@ func (d *maskDecoder) Decode(v interface{}) error { } // 设置更新掩码字段 SetUpdateMaskFields(message, fields) - + return nil } diff --git a/gateway/mask_test.go b/gateway/mask_test.go index 027dd43..4db86a3 100644 --- a/gateway/mask_test.go +++ b/gateway/mask_test.go @@ -73,7 +73,7 @@ func TestDecodeErr(t *testing.T) { } r := bytes.NewReader([]byte(`{"message":"John Doe","msg":{"msg":"hello world"},"allow":"DENY","repeated_msg":[{"msg":"John Doe"}]}`)) decoder := NewMaskDecoder(NewJsonDecoder(r)) - mapData:=make(map[string]interface{}) + mapData := make(map[string]interface{}) err := decoder.Decode(mapData) c.So(err, c.ShouldBeNil) c.So(len(mapData), c.ShouldEqual, 0) diff --git a/gateway/middlewares.go b/gateway/middlewares.go index fde450c..60b07bd 100644 --- a/gateway/middlewares.go +++ b/gateway/middlewares.go @@ -233,9 +233,9 @@ func HandleErrorWithLogger(logger logger.Logger) runtime.ErrorHandlerFunc { "status": statusCode, }, ) - if _,ok:=metadata.FromIncomingContext(ctx);!ok{ - md:=IncomingHeadersToMetadata(ctx,req) - ctx=metadata.NewIncomingContext(ctx,md) + if _, ok := metadata.FromIncomingContext(ctx); !ok { + md := IncomingHeadersToMetadata(ctx, req) + ctx = metadata.NewIncomingContext(ctx, md) } code := statusCode data := &common.HttpResponse{} diff --git a/gateway/protobuf_test.go b/gateway/protobuf_test.go index c99b631..b04db55 100644 --- a/gateway/protobuf_test.go +++ b/gateway/protobuf_test.go @@ -77,15 +77,15 @@ func testSetHttpResponseErr(t *testing.T) { c.So(err, c.ShouldNotBeNil) patch.Reset() } - patch:=gomonkey.ApplyFunc((*json.Decoder).Decode, func(_ *json.Decoder, v any) error { - val:=v.(*map[string]interface{}) - (*val)["/SayHello"]=[]interface{}{map[string]interface{}{"OutName":"HttpBody"}} + patch := gomonkey.ApplyFunc((*json.Decoder).Decode, func(_ *json.Decoder, v any) error { + val := v.(*map[string]interface{}) + (*val)["/SayHello"] = []interface{}{map[string]interface{}{"OutName": "HttpBody"}} return nil }) defer patch.Reset() err = pd.SetHttpResponse(common.E_HttpResponse) c.So(err, c.ShouldNotBeNil) - c.So(err.Error(),c.ShouldContainSubstring,"invalid gateway.json") + c.So(err.Error(), c.ShouldContainSubstring, "invalid gateway.json") patch.Reset() }) } diff --git a/gateway/serialization.go b/gateway/serialization.go index 26ba323..d474925 100644 --- a/gateway/serialization.go +++ b/gateway/serialization.go @@ -198,8 +198,3 @@ func (m *JSONMarshaler) Marshal(v interface{}) ([]byte, error) { func (m *JSONMarshaler) ContentType(v interface{}) string { return "application/json" } - -// func (m *JSONMarshaler) NewDecoder(r io.Reader) runtime.Decoder { -// // return NewMaskDecoder(m.JSONPb.NewDecoder(r)) -// return json.NewDecoder(r) -// } diff --git a/gateway/serialization_test.go b/gateway/serialization_test.go index 2c20ef9..4eab9e5 100644 --- a/gateway/serialization_test.go +++ b/gateway/serialization_test.go @@ -58,7 +58,7 @@ func TestRawBinaryUnmarshaler(t *testing.T) { c.So(marshal.ContentType(msg2), c.ShouldEqual, "application/octet-stream") patch1.Reset() - patch2:=gomonkey.ApplyFuncReturn(proto.Unmarshal, fmt.Errorf("io.ReadAll: unexpected EOF")) + patch2 := gomonkey.ApplyFuncReturn(proto.Unmarshal, fmt.Errorf("io.ReadAll: unexpected EOF")) defer patch2.Reset() c.So(marshal.ContentType(msg2), c.ShouldEqual, "application/octet-stream") }) diff --git a/gateway/types.go b/gateway/types.go index d415054..ed309ac 100644 --- a/gateway/types.go +++ b/gateway/types.go @@ -67,10 +67,10 @@ func (x *serverSideStreamClient) Recv() (protoreflect.ProtoMessage, error) { } return x.buildEventStreamResponse(out) } -func (x *serverSideStreamClient)SendMsg(v any)error{ +func (x *serverSideStreamClient) SendMsg(v any) error { return x.ClientStream.SendMsg(v) } -func (x *serverSideStreamClient)CloseSend()error{ +func (x *serverSideStreamClient) CloseSend() error { return x.ClientStream.CloseSend() } @@ -81,7 +81,7 @@ func (x *clientSideStreamClient) Send(m protoreflect.ProtoMessage) error { func (x *clientSideStreamClient) CloseSend() error { return x.ClientStream.CloseSend() } -func (x *clientSideStreamClient)RecvMsg(v any)error{ +func (x *clientSideStreamClient) RecvMsg(v any) error { return x.ClientStream.RecvMsg(v) } func (x *clientSideStreamClient) CloseAndRecv() (protoreflect.ProtoMessage, error) { diff --git a/gateway/websocket.go b/gateway/websocket.go index cbaf9a5..2120524 100644 --- a/gateway/websocket.go +++ b/gateway/websocket.go @@ -38,9 +38,9 @@ func (w *websocketForwarder) Flush() { } func (w *websocketForwarder) Close() error { // w.websocket.NextWriter() - return w.websocket.WriteMessage(websocket.CloseMessage,websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) + return w.websocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "")) } -func (w *websocketForwarder)CloseConn() error{ +func (w *websocketForwarder) CloseConn() error { return w.websocket.Close() } func (w *websocketForwarder) NextReader() (io.Reader, error) { diff --git a/go.mod b/go.mod index 57cb1d3..e06c0a3 100644 --- a/go.mod +++ b/go.mod @@ -94,15 +94,23 @@ require ( require ( dario.cat/mergo v1.0.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/DATA-DOG/go-sqlmock v1.5.2 // indirect - github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/ProtonMail/go-crypto v1.0.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/redact v1.1.5 // indirect + github.com/containerd/continuity v0.4.3 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/docker/cli v26.1.3+incompatible // indirect + github.com/docker/docker v26.1.3+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/getsentry/sentry-go v0.18.0 // indirect @@ -114,7 +122,9 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/gopherjs/gopherjs v1.17.2 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jtolds/gls v4.20.0+incompatible // indirect @@ -122,6 +132,12 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/opencontainers/runc v1.1.12 // indirect + github.com/ory/dockertest/v3 v3.10.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect @@ -129,6 +145,9 @@ require ( github.com/skeema/knownhosts v1.2.2 // indirect github.com/smarty/assertions v1.15.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.13 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/mod v0.17.0 // indirect @@ -137,6 +156,7 @@ require ( golang.org/x/tools v0.21.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240521202816-d264139d666e // indirect gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) // replace github.com/spark-lence/tiga => /data/work/spark-lence/tiga diff --git a/go.sum b/go.sum index f793274..e86c285 100644 --- a/go.sum +++ b/go.sum @@ -2,11 +2,17 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= +github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= @@ -15,6 +21,7 @@ github.com/agiledragon/gomonkey/v2 v2.11.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoa github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk= github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -30,8 +37,12 @@ github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= github.com/bsm/redislock v0.9.4 h1:X/Wse1DPpiQgHbVYRE9zv6m070UcKoOGekgvpNhiSvw= github.com/bsm/redislock v0.9.4/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDPoDeAk= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= @@ -43,6 +54,9 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/colinmarc/hdfs/v2 v2.4.0 h1:v6R8oBx/Wu9fHpdPoJJjpGSUxo8NhHIwrwsfhFvU9W0= github.com/colinmarc/hdfs/v2 v2.4.0/go.mod h1:0NAO+/3knbMx6+5pCv+Hcbaz4xn/Zzbn9+WIib2rKVI= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= +github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= +github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= @@ -56,6 +70,14 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= +github.com/docker/cli v26.1.3+incompatible h1:bUpXT/N0kDE3VUHI2r5VMsYQgi38kYuoC0oL9yt3lqc= +github.com/docker/cli v26.1.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v26.1.3+incompatible h1:lLCzRbrVZrljpVNobJu1J2FHk8V0s4BawoZippkc+xo= +github.com/docker/docker v26.1.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= @@ -90,6 +112,7 @@ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -100,6 +123,8 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -114,11 +139,13 @@ github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7Fsg github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb-client-go/v2 v2.13.0 h1:ioBbLmR5NMbAjP4UVA5r9b5xGjpABD7j65pI8kFphDM= @@ -154,6 +181,7 @@ github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCy github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -167,6 +195,11 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= @@ -174,6 +207,16 @@ github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmt github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/runc v1.1.12 h1:BOIssBaW1La0/qbNZHXOOa71dZfZEQOzW7dqQf3phss= +github.com/opencontainers/runc v1.1.12/go.mod h1:S+lQwSfncpBha7XTy/5lBwWgm5+y5Ma/O44Ekby9FK8= +github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4= +github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= @@ -191,6 +234,7 @@ github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0= github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I= github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= @@ -199,10 +243,12 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/segmentio/kafka-go v0.4.47 h1:IqziR4pA3vrZq7YdRxaT3w1/5fvIH5qpCwstUanQQB0= github.com/segmentio/kafka-go v0.4.47/go.mod h1:HjF6XbOKh0Pjlkr5GVZxt6CsjjwnmhVOfURM5KMd8qg= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -245,8 +291,12 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/thinkeridea/go-extend v1.3.2 h1:0ZImRXpJc+wBNIrNEMbTuKwIvJ6eFoeuNAewvzONrI0= github.com/thinkeridea/go-extend v1.3.2/go.mod h1:xqN1e3y1PdVSij1VZp6iPKlO8I4jLbS8CUuTySj981g= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= @@ -255,6 +305,13 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 h1:tBiBTKHnIjovYoLX/TPkcf+OjqqKGQrPtGT3Foz+Pgo= github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76/go.mod h1:SQliXeA7Dhkt//vS29v3zpbEwoa+zb2Cn5xj5uO4K5U= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -333,6 +390,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -397,12 +455,14 @@ gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UD gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/internal/auth/auth.go b/internal/auth/auth.go deleted file mode 100644 index ebcedf3..0000000 --- a/internal/auth/auth.go +++ /dev/null @@ -1,218 +0,0 @@ -package auth - -import ( - "crypto/aes" - "crypto/cipher" - "crypto/rand" - "crypto/rsa" - "crypto/sha256" - "crypto/x509" - "encoding/base64" - "encoding/hex" - "encoding/pem" - "fmt" - "io" - "math/big" - mrand "math/rand" - "os" - "path" - "path/filepath" - "runtime" - "time" - - "github.com/spark-lence/tiga" -) - -type AuthValidator struct { - rsaKey *rsa.PrivateKey -} -type AuthSeed struct { - Seed int64 `json:"seed"` - Key string `json:"key"` -} -type AuthKeys struct { - Pri string - Pub string - Seed string -} - -func NewAuthVildator() *AuthValidator { - _, filename, _, ok := runtime.Caller(0) - if !ok { - panic("No caller information") - } - dir := path.Dir(path.Dir(path.Dir(filename))) - rsaKeyPath := filepath.Join(dir, "cert", "auth_private_key.pem") - validator := &AuthValidator{} - rsa, err := validator.LoadPrivateKey(rsaKeyPath) - if err != nil { - panic(err) - } - validator.rsaKey = rsa - return validator -} - -func (a AuthValidator) GenerateRandPasswd() (string, error) { - var charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - var length = 16 // 可以根据需要设置密码长度 - passwd := make([]byte, length) - - for i := 0; i < length; i++ { - num, err := rand.Int(rand.Reader, big.NewInt(int64(len(charset)))) - if err != nil { - return "", fmt.Errorf("生成随机密码失败,%w", err) - } - passwd[i] = charset[num.Int64()] - } - - return string(passwd), nil -} - -func (a AuthValidator) GenerateRandSeed() int64 { - // 使用当前时间的 Unix 时间戳(秒级) - timestamp := time.Now().Unix() - seed := time.Now().UnixNano() - - src := mrand.NewSource(seed) - r := mrand.New(src) - // 生成一个 0 到 999 之间的随机数 - randomThreeDigits := r.Intn(10000) - - // 将随机数拼接到时间戳后面 - seed = timestamp*10000 + int64(randomThreeDigits) - - return seed -} - -// 生成密钥对 -func (a AuthValidator) GenerateKeys(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) { - privateKey, err := rsa.GenerateKey(rand.Reader, bits) - if err != nil { - return nil, nil, err - } - - publicKey := &privateKey.PublicKey - return privateKey, publicKey, nil -} - -// 基于公钥加密 -func (a AuthValidator) EncryptWithPublicKey(msg string, pubKey *rsa.PublicKey) ([]byte, error) { - label := []byte("") // 使用空标签 - hash := sha256.New() - - ciphertext, err := rsa.EncryptOAEP(hash, rand.Reader, pubKey, []byte(msg), label) - if err != nil { - return nil, err - } - - return ciphertext, nil -} - -// 基于私钥解密 -func (a AuthValidator) DecryptWithPrivateKey(ciphertext []byte, privKey *rsa.PrivateKey) (string, error) { - label := []byte("") // 使用空标签 - hash := sha256.New() - - plaintext, err := rsa.DecryptOAEP(hash, rand.Reader, privKey, ciphertext, label) - if err != nil { - return "", err - } - - return string(plaintext), nil -} -func (a AuthValidator) publicKeyToString(pubKey *rsa.PublicKey) (string, error) { - // 将公钥转换为 ASN.1 DER 编码 - derBytes, err := x509.MarshalPKIXPublicKey(pubKey) - if err != nil { - return "", err - } - - // 构造 PEM 编码的结构 - pemBlock := &pem.Block{ - Type: "PUBLIC KEY", // 这是一个公钥 - Bytes: derBytes, - } - - // 将 PEM 编码的数据转换为字符串 - pemBytes := pem.EncodeToMemory(pemBlock) - - return string(pemBytes), nil -} - -// 另一种方式是将 DER 编码的数据直接转换为 Base64 编码的字符串 -func (a AuthValidator) publicKeyToBase64String(pubKey *rsa.PublicKey) (string, error) { - derBytes, err := x509.MarshalPKIXPublicKey(pubKey) - if err != nil { - return "", err - } - - return base64.StdEncoding.EncodeToString(derBytes), nil -} -func (a AuthValidator) EncryptAES(key []byte, plaintext string) (string, error) { - block, err := aes.NewCipher(key) - if err != nil { - return "", err - } - - // 随机初始化向量 - iv := make([]byte, aes.BlockSize) - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return "", err - } - - // 加密器 - stream := cipher.NewCFBEncrypter(block, iv) - cipherText := make([]byte, len(plaintext)) - stream.XORKeyStream(cipherText, []byte(plaintext)) - // 返回带有IV的加密文本 - return hex.EncodeToString(iv) + hex.EncodeToString(cipherText), nil -} -func (a AuthValidator) GenerateAuthSeed(aesKey string) (string, error) { - key, err := a.GenerateRandPasswd() - if err != nil { - return "", err - } - seed := AuthSeed{ - Seed: a.GenerateRandSeed(), - Key: key, - } - str, err := tiga.StructToJsonStr(&seed) - if err != nil { - return "", fmt.Errorf("struct转换为json string出错:%w", err) - } - encodedData := base64.StdEncoding.EncodeToString([]byte(str)) - return a.EncryptAES([]byte(aesKey), encodedData) - -} - -// loadPrivateKey 从文件中加载 RSA 私钥 -func (a AuthValidator) LoadPrivateKey(path string) (*rsa.PrivateKey, error) { - keyData, err := os.ReadFile(path) - if err != nil { - return nil, err - } - - block, _ := pem.Decode(keyData) - if block == nil { - return nil, fmt.Errorf("invalid private key data") - } - - priv, err := x509.ParsePKCS8PrivateKey(block.Bytes) - if err != nil { - return nil, fmt.Errorf("invalid private key data: %w", err) - } - privKey, ok := priv.(*rsa.PrivateKey) - if !ok { - return nil, fmt.Errorf("not an RSA private key") - } - return privKey, nil -} - -// rsaDecrypt 使用 RSA 私钥解密数据 -func (a AuthValidator) RSADecrypt(ciphertext string) ([]byte, error) { - decodedData, err := base64.StdEncoding.DecodeString(ciphertext) - if err != nil { - return nil, err - } - return rsa.DecryptPKCS1v15(rand.Reader, a.rsaKey, decodedData) -} diff --git a/internal/biz/app_test.go b/internal/biz/app_test.go index dec37f1..016c153 100644 --- a/internal/biz/app_test.go +++ b/internal/biz/app_test.go @@ -260,7 +260,7 @@ func testListApp(t *testing.T) { config := config.ReadConfig(env) repo := data.NewAppRepo(config, gateway.Log) - patch := gomonkey.ApplyMethodReturn(repo, "List",nil, fmt.Errorf("list error")) + patch := gomonkey.ApplyMethodReturn(repo, "List", nil, fmt.Errorf("list error")) defer patch.Reset() _, err = appBiz.List(context.TODO(), &api.AppsListRequest{ PageSize: 10, diff --git a/internal/biz/biz.go b/internal/biz/biz.go index 79c4957..eb8c2f3 100644 --- a/internal/biz/biz.go +++ b/internal/biz/biz.go @@ -1,8 +1,8 @@ package biz import ( - "github.com/begonia-org/begonia/internal/biz/file" "github.com/begonia-org/begonia/internal/biz/endpoint" + "github.com/begonia-org/begonia/internal/biz/file" "github.com/google/wire" ) diff --git a/internal/biz/data.go b/internal/biz/data.go index 9740b36..04fe9b6 100644 --- a/internal/biz/data.go +++ b/internal/biz/data.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "log" "sync" "time" @@ -77,6 +78,7 @@ func (d *DataOperatorUsecase) Handle(ctx context.Context) { a := action go func(action operationAction, wg *sync.WaitGroup) { defer wg.Done() + d.log.Infof(ctx, "start action") errChan <- action(ctx) }(a, wg) @@ -96,20 +98,20 @@ func (d *DataOperatorUsecase) Handle(ctx context.Context) { // loadUsersBlacklist 加载用户黑名单 func (d *DataOperatorUsecase) loadUsersBlacklist(ctx context.Context) error { exp := d.config.GetUserBlackListExpiration() - 1 + if exp <= 0 { + return fmt.Errorf("expiration time is too short") } lockKey := d.config.GetUserBlackListLockKey() - // d.log.Infof(ctx, "lock key:%d", exp) - lock, err := d.repo.Locker(ctx, lockKey, time.Second*time.Duration(exp)) + log.Printf("lockKey:%s", lockKey) + lock, err := d.repo.Locker(ctx, lockKey, time.Second*time.Duration(10)) if err != nil { - d.log.Errorf(ctx, "get lock error:%s", err.Error()) return fmt.Errorf("get lock error:%w", err) } if err = lock.Lock(ctx); err != nil && err != redislock.ErrNotObtained { - // d.log.Error("lock error:", err) return fmt.Errorf("lock error: %w", err) } defer func() { @@ -126,6 +128,7 @@ func (d *DataOperatorUsecase) loadUsersBlacklist(ctx context.Context) error { // 如果缓存时间小于3秒,说明刚刚更新过,不需要再次更新 // 直接加载远程缓存到本地 // lastUpdate ttl 0 then + redis.call("DEL", unpack(keys)) + end + until cursor == "0" + return "OK" + ` + + _, err := rdb.GetClient().Eval(context.Background(), luaScript, []string{"test:*"}).Result() + if err != nil { + log.Fatalf("Could not execute Lua script: %v", err) + } + etcd := tiga.NewEtcdDao(conf) + // 设置前缀 + prefix := "/test" + + // 使用前缀删除所有键 + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + err = etcd.Delete(ctx, prefix, clientv3.WithPrefix()) + if err != nil { + log.Fatalf("Failed to delete keys with prefix %s: %v", prefix, err) + } +} + func newDataOperatorUsecase() *biz.DataOperatorUsecase { env := "dev" if begonia.Env != "" { @@ -102,6 +156,8 @@ func TestDo(t *testing.T) { } err = appBiz.Put(context.TODO(), app, u2.Uid) c.So(err, c.ShouldBeNil) + patch := gomonkey.ApplyFuncReturn((*cfg.Config).GetUserBlackListExpiration, 3) + defer patch.Reset() go dataOperator.Do(context.Background()) go dataOperator.Do(context.Background()) @@ -115,15 +171,15 @@ func TestDo(t *testing.T) { c.So(err, c.ShouldBeNil) c.So(val, c.ShouldNotBeEmpty) - patch := gomonkey.ApplyFuncReturn((*biz.DataOperatorUsecase).OnStart, fmt.Errorf("test data operator on start error")) - defer patch.Reset() + patch1 := gomonkey.ApplyFuncReturn((*biz.DataOperatorUsecase).OnStart, fmt.Errorf("test data operator on start error")) + defer patch1.Reset() repo := data.NewOperator(config, gateway.Log) patch2 := gomonkey.ApplyMethodReturn(repo, "Watcher", fmt.Errorf("test data watcher list error")) defer patch2.Reset() ctx, cancel := context.WithCancel(context.Background()) go dataOperator.Do(ctx) time.Sleep(1 * time.Second) - patch.Reset() + patch1.Reset() patch2.Reset() cancel() ctx, cancel = context.WithCancel(context.Background()) @@ -172,7 +228,7 @@ func TestHandleError(t *testing.T) { cancel() patch4 := gomonkey.ApplyMethodReturn(repo, "GetAllForbiddenUsers", nil, fmt.Errorf("test latest GetAllForbiddenUsers error")) - patch4 = patch4.ApplyMethodReturn(repo, "LastUpdated", time.Time{},nil) + patch4 = patch4.ApplyMethodReturn(repo, "LastUpdated", time.Time{}, nil) defer patch4.Reset() ctx, cancel = context.WithCancel(context.Background()) go dataOperator.Handle(ctx) @@ -181,7 +237,7 @@ func TestHandleError(t *testing.T) { cancel() patch5 := gomonkey.ApplyMethodReturn(repo, "FlashUsersCache", fmt.Errorf("test latest FlashUsersCache error")) - patch5 = patch5.ApplyMethodReturn(repo, "LastUpdated", time.Time{},nil) + patch5 = patch5.ApplyMethodReturn(repo, "LastUpdated", time.Time{}, nil) defer patch5.Reset() ctx, cancel = context.WithCancel(context.Background()) go dataOperator.Handle(ctx) @@ -211,7 +267,7 @@ func TestOnStart(t *testing.T) { patch.Reset() cancel() // []*api.Endpoints, error - patch2:= gomonkey.ApplyMethodReturn(repo, "List", []*ep.Endpoints{{ + patch2 := gomonkey.ApplyMethodReturn(repo, "List", []*ep.Endpoints{{ Name: "test", Owner: "test", Description: "test", diff --git a/internal/biz/endpoint/endpoint_test.go b/internal/biz/endpoint/endpoint_test.go index c33163b..505b715 100644 --- a/internal/biz/endpoint/endpoint_test.go +++ b/internal/biz/endpoint/endpoint_test.go @@ -334,16 +334,16 @@ func testDelEndpoint(t *testing.T) { c.So(err, c.ShouldBeNil) }) c.Convey("Test Del Endpoint Fail", t, func() { - repo:=data.NewEndpointRepo(nil,gateway.Log) - patch:=gomonkey.ApplyMethodReturn(repo,"Del",fmt.Errorf("test Del error")) + repo := data.NewEndpointRepo(nil, gateway.Log) + patch := gomonkey.ApplyMethodReturn(repo, "Del", fmt.Errorf("test Del error")) defer patch.Reset() err := endpointBiz.Delete(context.TODO(), epId) patch.Reset() c.So(err, c.ShouldNotBeNil) c.So(err.Error(), c.ShouldContainSubstring, "test Del error") - patch2:=gomonkey.ApplyMethodReturn(repo,"Del",nil) - patch2.ApplyFuncReturn((*endpoint.EndpointWatcher).Del,fmt.Errorf("test watcher Del error")) + patch2 := gomonkey.ApplyMethodReturn(repo, "Del", nil) + patch2.ApplyFuncReturn((*endpoint.EndpointWatcher).Del, fmt.Errorf("test watcher Del error")) defer patch2.Reset() err = endpointBiz.Delete(context.TODO(), epId) patch2.Reset() @@ -427,8 +427,6 @@ func testWatcherUpdate(t *testing.T) { c.So(err, c.ShouldNotBeNil) c.So(err.Error(), c.ShouldContainSubstring, pkg.ErrUnknownLoadBalancer.Error()) - - }) } func testWatcherDel(t *testing.T) { diff --git a/internal/biz/endpoint/watcher.go b/internal/biz/endpoint/watcher.go index d487629..8149c29 100644 --- a/internal/biz/endpoint/watcher.go +++ b/internal/biz/endpoint/watcher.go @@ -23,7 +23,7 @@ import ( type EndpointWatcher struct { config *config.Config repo EndpointRepo - mux sync.Mutex + mux sync.Mutex } // update @@ -110,6 +110,6 @@ func NewWatcher(config *config.Config, repo EndpointRepo) *EndpointWatcher { return &EndpointWatcher{ config: config, repo: repo, - mux:sync.Mutex{}, + mux: sync.Mutex{}, } } diff --git a/internal/biz/file/reader.go b/internal/biz/file/reader.go index 4da03fb..9b5e82a 100644 --- a/internal/biz/file/reader.go +++ b/internal/biz/file/reader.go @@ -149,7 +149,7 @@ func NewFileVersionReader(path string, version string) (FileVersionReader, error fileName := filepath.Base(path) repo, err := git.PlainOpen(dir) if err != nil { - log.Printf("failed to open git repository,%s: %v",dir, err) + log.Printf("failed to open git repository,%s: %v", dir, err) return nil, err } diff --git a/internal/biz/user.go b/internal/biz/user.go index 5eecd51..ccf06b0 100644 --- a/internal/biz/user.go +++ b/internal/biz/user.go @@ -20,7 +20,7 @@ type UserRepo interface { Del(ctx context.Context, key string) error List(ctx context.Context, dept []string, status []api.USER_STATUS, page, pageSize int32) ([]*api.Users, error) Patch(ctx context.Context, model *api.Users) error - Cache(ctx context.Context, prefix string, models []*api.Users, exp time.Duration, getValue func(user *api.Users) ([]byte, interface{})) (redis.Pipeliner,error) + Cache(ctx context.Context, prefix string, models []*api.Users, exp time.Duration, getValue func(user *api.Users) ([]byte, interface{})) (redis.Pipeliner, error) } type UserUsecase struct { diff --git a/internal/biz/user_test.go b/internal/biz/user_test.go index 771fd1e..32879ff 100644 --- a/internal/biz/user_test.go +++ b/internal/biz/user_test.go @@ -218,7 +218,7 @@ func testListUser(t *testing.T) { env = begonia.Env } repo := data.NewUserRepo(config.ReadConfig(env), gateway.Log) - patch := gomonkey.ApplyMethodReturn(repo, "List",nil, fmt.Errorf("error in your SQL syntax")) + patch := gomonkey.ApplyMethodReturn(repo, "List", nil, fmt.Errorf("error in your SQL syntax")) defer patch.Reset() _, err = userBiz.List(context.TODO(), []string{"unknown"}, []api.USER_STATUS{api.USER_STATUS_DELETED}, 1, 20) c.So(err, c.ShouldNotBeNil) diff --git a/internal/data/app.go b/internal/data/app.go index 27aca2a..d1c2ad3 100644 --- a/internal/data/app.go +++ b/internal/data/app.go @@ -28,13 +28,13 @@ func (r *appRepoImpl) Add(ctx context.Context, apps *api.Apps) error { } key := r.cfg.GetAPPAccessKey(apps.AccessKey) exp := r.cfg.GetAPPAccessKeyExpiration() - appidKey:=r.cfg.GetAppidKey(apps.AccessKey) + appidKey := r.cfg.GetAppidKey(apps.AccessKey) err := r.local.Set(ctx, key, []byte(apps.Secret), time.Duration(exp)*time.Second) - if err!=nil{ + if err != nil { return err } - return r.local.Set(ctx,appidKey,[]byte(apps.Appid), time.Duration(exp)*time.Second) + return r.local.Set(ctx, appidKey, []byte(apps.Appid), time.Duration(exp)*time.Second) } func (r *appRepoImpl) Get(ctx context.Context, key string) (*api.Apps, error) { @@ -69,9 +69,9 @@ func (r *appRepoImpl) List(ctx context.Context, tags []string, status []api.APPS conds := make([]interface{}, 0) if len(tags) > 0 { for _, tag := range tags[:len(tags)-1] { - query += fmt.Sprintf(`JSON_CONTAINS(tags,'"%s"') OR `,tag) + query += fmt.Sprintf(`JSON_CONTAINS(tags,'"%s"') OR `, tag) } - query += fmt.Sprintf(`JSON_CONTAINS(tags,'"%s"')`,tags[len(tags)-1]) + query += fmt.Sprintf(`JSON_CONTAINS(tags,'"%s"')`, tags[len(tags)-1]) } if len(status) > 0 { @@ -102,7 +102,7 @@ func (a *appRepoImpl) GetSecret(ctx context.Context, accessKey string) (string, secret := string(secretBytes) if err != nil { apps, err := a.Get(ctx, accessKey) - if err != nil||apps.Secret=="" { + if err != nil || apps.Secret == "" { return "", fmt.Errorf("get app secret failed: %w", err) } secret = apps.Secret @@ -118,8 +118,8 @@ func (a *appRepoImpl) GetAppid(ctx context.Context, accessKey string) (string, e appid := string(secretBytes) if err != nil { apps, err := a.Get(ctx, accessKey) - if err != nil|| apps.Appid=="" { - return "", fmt.Errorf("get app appid err:%w",err) + if err != nil || apps.Appid == "" { + return "", fmt.Errorf("get app appid err:%w", err) } appid = apps.Appid diff --git a/internal/data/app_test.go b/internal/data/app_test.go index 5572413..cebc8ed 100644 --- a/internal/data/app_test.go +++ b/internal/data/app_test.go @@ -190,7 +190,7 @@ func patchTest(t *testing.T) { c.So(err, c.ShouldNotBeNil) c.So(err.Error(), c.ShouldContainSubstring, "appid can not be updated") - patch := gomonkey.ApplyFuncReturn(getPrimaryColumnValue,"",nil, fmt.Errorf("getPrimaryColumnValue error")) + patch := gomonkey.ApplyFuncReturn(getPrimaryColumnValue, "", nil, fmt.Errorf("getPrimaryColumnValue error")) defer patch.Reset() err = repo.Patch(context.Background(), updated) c.So(err, c.ShouldNotBeNil) diff --git a/internal/data/authz_test.go b/internal/data/authz_test.go index a684119..685a5fd 100644 --- a/internal/data/authz_test.go +++ b/internal/data/authz_test.go @@ -7,9 +7,9 @@ import ( "github.com/begonia-org/begonia" cfg "github.com/begonia-org/begonia/config" + "github.com/begonia-org/begonia/gateway" c "github.com/smartystreets/goconvey/convey" "github.com/spark-lence/tiga" - "github.com/begonia-org/begonia/gateway" ) var token = "" diff --git a/internal/data/cache.go b/internal/data/cache.go index ffe13a4..599ae93 100644 --- a/internal/data/cache.go +++ b/internal/data/cache.go @@ -24,7 +24,8 @@ type LayeredCache struct { } var layered *LayeredCache -func newCache(rdb *tiga.RedisDao, config *config.Config, log logger.Logger)*LayeredCache{ + +func newCache(rdb *tiga.RedisDao, config *config.Config, log logger.Logger) *LayeredCache { kvWatcher := source.NewWatchOptions([]interface{}{config.GetKeyValuePubsubKey()}) strategy := glc.CacheReadStrategy(config.GetMultiCacheReadStrategy()) KvOptions := glc.LayeredBuildOptions{ @@ -57,6 +58,7 @@ func newCache(rdb *tiga.RedisDao, config *config.Config, log logger.Logger)*Laye }) return &LayeredCache{kv: kv, config: config, log: log, mux: sync.Mutex{}, onceOnStart: sync.Once{}, filters: filter} } + // NewLayeredCache creates a new layered cache only once func NewLayeredCache(rdb *tiga.RedisDao, config *config.Config, log logger.Logger) *LayeredCache { onceLayered.Do(func() { @@ -105,7 +107,7 @@ func (l *LayeredCache) DelInFilter(ctx context.Context, key string, value []byte func (l *LayeredCache) Watch(ctx context.Context) { errChan := l.kv.Watch(ctx) for err := range errChan { - l.log.Errorf(ctx,"Watch layered-cache error:%v", err) + l.log.Errorf(ctx, "Watch layered-cache error:%v", err) } } diff --git a/internal/data/cache_test.go b/internal/data/cache_test.go index 4c22cda..bc1c48b 100644 --- a/internal/data/cache_test.go +++ b/internal/data/cache_test.go @@ -30,7 +30,7 @@ func TestGetFromLocalErr(t *testing.T) { defer patch.Reset() _, err = cache.GetFromLocal(context.Background(), fmt.Sprintf("test-local:%s", time.Now().Format("20060102150405"))) c.So(err, c.ShouldNotBeNil) - c.So(err.Error(),c.ShouldContainSubstring,"local cache value is not found") + c.So(err.Error(), c.ShouldContainSubstring, "local cache value is not found") patch.Reset() fk := fmt.Sprintf("test-local:%s", time.Now().Format("20060102150405")) @@ -61,14 +61,14 @@ func TestCacheWatch(t *testing.T) { cnf := config.NewConfig(conf) key := fmt.Sprintf("%s:%s", cnf.GetKeyValuePrefix(), time.Now().Format("20060102150405")) // _ = rdb.GetClient().Set(context.Background(), key, key, 10*time.Second) - cache2 := newCache(tiga.NewRedisDao(conf),cnf, gateway.Log) + cache2 := newCache(tiga.NewRedisDao(conf), cnf, gateway.Log) - err:=cache2.Set(context.Background(), key, []byte(key), 10*time.Second) - c.So(err,c.ShouldBeNil) - time.Sleep(2*time.Second) - val,err:=cache.GetFromLocal(context.Background(), key) - c.So(err,c.ShouldBeNil) - c.So(string(val),c.ShouldEqual,key) + err := cache2.Set(context.Background(), key, []byte(key), 10*time.Second) + c.So(err, c.ShouldBeNil) + time.Sleep(2 * time.Second) + val, err := cache.GetFromLocal(context.Background(), key) + c.So(err, c.ShouldBeNil) + c.So(string(val), c.ShouldEqual, key) }) } diff --git a/internal/data/data_test.go b/internal/data/data_test.go index 9c7a7e1..3de085d 100644 --- a/internal/data/data_test.go +++ b/internal/data/data_test.go @@ -1,12 +1,64 @@ package data import ( + "context" "log" "testing" + "time" + + "github.com/begonia-org/begonia" + cfg "github.com/begonia-org/begonia/config" + "github.com/spark-lence/tiga" + clientv3 "go.etcd.io/etcd/client/v3" ) // func TestCreateInBatches(t *testing.T) { func TestMain(m *testing.M) { + log.Printf("Start testing") + setup() code := m.Run() log.Printf("All tests passed with code %d", code) } + +func setup() { + env := "dev" + if begonia.Env != "" { + env = begonia.Env + } + conf := cfg.ReadConfig(env) + + // cnf:=config.NewConfig(conf) + rdb := tiga.NewRedisDao(conf) + luaScript := ` + local prefix = KEYS[1] + local cursor = "0" + local count = 100 + repeat + local result = redis.call("SCAN", cursor, "MATCH", prefix, "COUNT", count) + cursor = result[1] + local keys = result[2] + if #keys > 0 then + redis.call("DEL", unpack(keys)) + end + until cursor == "0" + return "OK" + ` + + _, err := rdb.GetClient().Eval(context.Background(), luaScript, []string{"test:*"}).Result() + if err != nil { + log.Fatalf("Could not execute Lua script: %v", err) + } + + etcd := tiga.NewEtcdDao(conf) + // 设置前缀 + prefix := "/test" + + // 使用前缀删除所有键 + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + err = etcd.Delete(ctx, prefix, clientv3.WithPrefix()) + if err != nil { + log.Fatalf("Failed to delete keys with prefix %s: %v", prefix, err) + } +} diff --git a/internal/data/endpoint_test.go b/internal/data/endpoint_test.go index 364638b..cfff2c1 100644 --- a/internal/data/endpoint_test.go +++ b/internal/data/endpoint_test.go @@ -353,7 +353,7 @@ func delEndpointTest(t *testing.T) { c.So(err.Error(), c.ShouldContainSubstring, "del GetWithPrefix fail") patch.Reset() - patch2:=gomonkey.ApplyFuncReturn((*Data).PutEtcdWithTxn, false, fmt.Errorf("del PutEtcdWithTxn fail")) + patch2 := gomonkey.ApplyFuncReturn((*Data).PutEtcdWithTxn, false, fmt.Errorf("del PutEtcdWithTxn fail")) defer patch2.Reset() err = repo.Del(context.Background(), endpointId) c.So(err, c.ShouldNotBeNil) @@ -372,7 +372,6 @@ func delEndpointTest(t *testing.T) { c.So(err, c.ShouldBeNil) c.So(keys, c.ShouldBeEmpty) - }) } func putTagsTest(t *testing.T) { @@ -427,7 +426,7 @@ func putTagsTest(t *testing.T) { c.So(err.Error(), c.ShouldContainSubstring, "marshal tags fail") patch2.Reset() - patch3 := gomonkey.ApplyFuncReturn((*endpointRepoImpl).Get,"", fmt.Errorf("get endpoint fail")) + patch3 := gomonkey.ApplyFuncReturn((*endpointRepoImpl).Get, "", fmt.Errorf("get endpoint fail")) defer patch3.Reset() err = repo.PutTags(context.Background(), endpointId, []string{tag1, tag2, tag3}) c.So(err, c.ShouldNotBeNil) diff --git a/internal/data/operator.go b/internal/data/operator.go index 763db21..f0412c0 100644 --- a/internal/data/operator.go +++ b/internal/data/operator.go @@ -52,8 +52,8 @@ func (r *dataOperatorRepo) GetAllForbiddenUsers(ctx context.Context) ([]*api.Use page := int32(1) for { user, err := r.user.List(ctx, nil, []api.USER_STATUS{api.USER_STATUS_LOCKED, api.USER_STATUS_DELETED, api.USER_STATUS_INACTIVE}, page, 100) - if err != nil||len(user) == 0 { - if err!=nil&&strings.Contains(err.Error(), gorm.ErrRecordNotFound.Error()) { + if err != nil || len(user) == 0 { + if err != nil && strings.Contains(err.Error(), gorm.ErrRecordNotFound.Error()) { break } return users, err @@ -70,8 +70,8 @@ func (r *dataOperatorRepo) GetAllApps(ctx context.Context) ([]*app.Apps, error) page := int32(1) for { app, err := r.app.List(ctx, nil, nil, page, 100) - if err != nil||len(app) == 0 { - if err!=nil&&strings.Contains(err.Error(), gorm.ErrRecordNotFound.Error()) { + if err != nil || len(app) == 0 { + if err != nil && strings.Contains(err.Error(), gorm.ErrRecordNotFound.Error()) { break } return apps, err @@ -132,7 +132,7 @@ func (d *dataOperatorRepo) FlashUsersCache(ctx context.Context, prefix string, m return err } -func (d *dataOperatorRepo) LoadRemoteCache(ctx context.Context)error { +func (d *dataOperatorRepo) LoadRemoteCache(ctx context.Context) error { err := d.local.kv.LoadDump(ctx) if err != nil { @@ -192,7 +192,7 @@ func (d *dataOperatorRepo) Sync(interval time.Duration) { go func() { for range ticker.C { - _=d.LoadRemoteCache(context.Background()) + _ = d.LoadRemoteCache(context.Background()) } }() @@ -210,7 +210,8 @@ func (d *dataOperatorRepo) onStartOperator() { for err := range errKvChan { d.local.log.Errorf(context.TODO(), "kv error %v", err) } - }()} + }() +} func (d *dataOperatorRepo) OnStart() { d.onceOnStart.Do(func() { d.onStartOperator() diff --git a/internal/data/operator_test.go b/internal/data/operator_test.go index 4bd20f8..98202a9 100644 --- a/internal/data/operator_test.go +++ b/internal/data/operator_test.go @@ -234,18 +234,18 @@ func testWatcher(t *testing.T) { env = begonia.Env } operator := NewOperator(cfg.ReadConfig(env), gateway.Log) - updated := make(chan string,1) - deleted := make(chan string,1) - ctx,cancel:=context.WithCancel(context.Background()) + updated := make(chan string, 1) + deleted := make(chan string, 1) + ctx, cancel := context.WithCancel(context.Background()) defer cancel() defer close(updated) defer close(deleted) go func(ctx context.Context) { err := operator.Watcher(ctx, "/test/watcher/user/info", func(ctx context.Context, op mvccpb.Event_EventType, key, value string) error { if op == mvccpb.PUT { - updated<-key + updated <- key } else if op == mvccpb.DELETE { - deleted<-key + deleted <- key } return nil }) @@ -257,16 +257,16 @@ func testWatcher(t *testing.T) { uid := snk.GenerateIDString() err := operator.(*dataOperatorRepo).data.etcd.Put(context.Background(), fmt.Sprintf("/test/watcher/user/info/%s", uid), fmt.Sprintf("user-%s", time.Now().Format("20060102150405"))) c.So(err, c.ShouldBeNil) - up:=<-updated + up := <-updated c.So(up, c.ShouldEqual, fmt.Sprintf("/test/watcher/user/info/%s", uid)) err = operator.(*dataOperatorRepo).data.etcd.Delete(context.Background(), fmt.Sprintf("/test/watcher/user/info/%s", uid)) c.So(err, c.ShouldBeNil) - d:=<-deleted + d := <-deleted c.So(d, c.ShouldEqual, fmt.Sprintf("/test/watcher/user/info/%s", uid)) cancel() - + }) } diff --git a/internal/data/user.go b/internal/data/user.go index 8ae2363..ee68480 100644 --- a/internal/data/user.go +++ b/internal/data/user.go @@ -65,7 +65,7 @@ func (r *userRepoImpl) List(ctx context.Context, dept []string, status []api.USE query += "status in (?)" conds = append(conds, status) } - + pagination := &tiga.Pagination{ Page: page, PageSize: pageSize, @@ -88,17 +88,17 @@ func (r *userRepoImpl) List(ctx context.Context, dept []string, status []api.USE return apps, nil } -func (u *userRepoImpl) Cache(ctx context.Context, prefix string, models []*api.Users, exp time.Duration, getValue func(user *api.Users) ([]byte, interface{})) (redis.Pipeliner,error) { +func (u *userRepoImpl) Cache(ctx context.Context, prefix string, models []*api.Users, exp time.Duration, getValue func(user *api.Users) ([]byte, interface{})) (redis.Pipeliner, error) { kv := make([]interface{}, 0) for _, model := range models { valByte, val := getValue(model) key := fmt.Sprintf("%s:%s", prefix, model.Uid) if err := u.cacheUsers(ctx, prefix, model.Uid, valByte, exp); err != nil { - return nil,err + return nil, err } kv = append(kv, key, val) } - return u.data.BatchCacheByTx(ctx, exp, kv...),nil + return u.data.BatchCacheByTx(ctx, exp, kv...), nil } func (u *userRepoImpl) cacheUsers(ctx context.Context, prefix string, uid string, value []byte, exp time.Duration) error { key := fmt.Sprintf("%s:%s", prefix, uid) diff --git a/internal/data/user_test.go b/internal/data/user_test.go index e02c027..ba6d68b 100644 --- a/internal/data/user_test.go +++ b/internal/data/user_test.go @@ -53,7 +53,7 @@ func testAddUser(t *testing.T) { c.So(err, c.ShouldBeNil) time.Sleep(2 * time.Second) - pipe,err := repo.Cache(context.TODO(), "test:user:cache", []*api.Users{{Uid: uid, Name: user1, Dept: "dev"}}, 3*time.Second, func(user *api.Users) ([]byte, interface{}) { + pipe, err := repo.Cache(context.TODO(), "test:user:cache", []*api.Users{{Uid: uid, Name: user1, Dept: "dev"}}, 3*time.Second, func(user *api.Users) ([]byte, interface{}) { return []byte(user.Uid), user.Uid }) c.So(err, c.ShouldBeNil) @@ -212,7 +212,7 @@ func testUpdateUser(t *testing.T) { createdAt := user.CreatedAt user.Name = fmt.Sprintf("user-update-%s", time.Now().Format("20060102150405")) time.Sleep(1 * time.Second) - snk,_:=tiga.NewSnowflake(1) + snk, _ := tiga.NewSnowflake(1) user.Phone = snk.GenerateIDString() user.UpdateMask = &fieldmaskpb.FieldMask{Paths: []string{"name", "phone"}} err = repo.Patch(context.TODO(), user) @@ -340,7 +340,7 @@ func testCacheError(t *testing.T) { } patch := gomonkey.ApplyFuncReturn((*LayeredCache).Set, fmt.Errorf("set cache error")) defer patch.Reset() - _,err := repo.Cache(context.TODO(), "test:user:cache", users, 3*time.Second, func(user *api.Users) ([]byte, interface{}) { + _, err := repo.Cache(context.TODO(), "test:user:cache", users, 3*time.Second, func(user *api.Users) ([]byte, interface{}) { return []byte(user.Uid), user.Uid }) c.So(err, c.ShouldNotBeNil) diff --git a/internal/data/wire.go b/internal/data/wire.go index a26075a..321839f 100644 --- a/internal/data/wire.go +++ b/internal/data/wire.go @@ -39,6 +39,6 @@ func NewOperator(cfg *tiga.Configuration, log logger.Logger) biz.DataOperatorRep func NewDataRepo(cfg *tiga.Configuration, log logger.Logger) *Data { panic(wire.Build(ProviderSet)) } -func NewLocker(cfg *tiga.Configuration, log logger.Logger,key string, ttl time.Duration,retry int) biz.DataLock { +func NewLocker(cfg *tiga.Configuration, log logger.Logger, key string, ttl time.Duration, retry int) biz.DataLock { panic(wire.Build(ProviderSet)) } diff --git a/internal/middleware/auth/ak_test.go b/internal/middleware/auth/ak_test.go index 0148b5a..789f7cb 100644 --- a/internal/middleware/auth/ak_test.go +++ b/internal/middleware/auth/ak_test.go @@ -54,28 +54,28 @@ func TestAccessKeyAuthMiddleware(t *testing.T) { err = ak.StreamInterceptor(context.Background(), &testStream{ctx: context.Background()}, &grpc.StreamServerInfo{ FullMethod: "/example.v1.HelloService/TEST", - },func(srv any, stream grpc.ServerStream) error { + }, func(srv any, stream grpc.ServerStream) error { return fmt.Errorf("metadata not exists in context") }) c.So(err.Error(), c.ShouldContainSubstring, fmt.Errorf("metadata not exists in context").Error()) - patch:=gomonkey.ApplyFuncReturn((*auth.AccessKeyAuthMiddleware).StreamRequestBefore, nil, nil) - patch =patch.ApplyFuncReturn((*auth.AccessKeyAuthMiddleware).StreamResponseAfter, fmt.Errorf("StreamResponseAfter err")) + patch := gomonkey.ApplyFuncReturn((*auth.AccessKeyAuthMiddleware).StreamRequestBefore, nil, nil) + patch = patch.ApplyFuncReturn((*auth.AccessKeyAuthMiddleware).StreamResponseAfter, fmt.Errorf("StreamResponseAfter err")) defer patch.Reset() - err = ak.StreamInterceptor(context.Background(), &testStream{ctx: context.Background()}, &grpc.StreamServerInfo{FullMethod: "/integration.TestService/Get"},func(srv any, stream grpc.ServerStream) error { + err = ak.StreamInterceptor(context.Background(), &testStream{ctx: context.Background()}, &grpc.StreamServerInfo{FullMethod: "/integration.TestService/Get"}, func(srv any, stream grpc.ServerStream) error { return nil - + }) - c.So(err,c.ShouldBeNil) + c.So(err, c.ShouldBeNil) patch.Reset() - patch2:=gomonkey.ApplyFuncReturn((*auth.AccessKeyAuthMiddleware).StreamRequestBefore, nil, fmt.Errorf("StreamRequestBefore err")) + patch2 := gomonkey.ApplyFuncReturn((*auth.AccessKeyAuthMiddleware).StreamRequestBefore, nil, fmt.Errorf("StreamRequestBefore err")) defer patch2.Reset() - err = ak.StreamInterceptor(context.Background(), &testStream{ctx: context.Background()}, &grpc.StreamServerInfo{FullMethod: "/integration.TestService/Get"},func(srv any, stream grpc.ServerStream) error { + err = ak.StreamInterceptor(context.Background(), &testStream{ctx: context.Background()}, &grpc.StreamServerInfo{FullMethod: "/integration.TestService/Get"}, func(srv any, stream grpc.ServerStream) error { return nil - + }) patch2.Reset() - c.So(err.Error(),c.ShouldContainSubstring,fmt.Errorf("StreamRequestBefore err").Error()) + c.So(err.Error(), c.ShouldContainSubstring, fmt.Errorf("StreamRequestBefore err").Error()) }) } func TestRequestBeforeErr(t *testing.T) { @@ -138,8 +138,8 @@ func TestValidateStream(t *testing.T) { c.So(err, c.ShouldNotBeNil) c.So(err.Error(), c.ShouldContainSubstring, "NewGatewayRequestFromGrpc err") - stream:=auth.NewGrpcStream(&testStream{},"",context.TODO(),nil) - err=ak.StreamResponseAfter(context.TODO(),stream,nil) - c.So(err,c.ShouldBeNil) + stream := auth.NewGrpcStream(&testStream{}, "", context.TODO(), nil) + err = ak.StreamResponseAfter(context.TODO(), stream, nil) + c.So(err, c.ShouldBeNil) }) } diff --git a/internal/middleware/auth/auth.go b/internal/middleware/auth/auth.go index 8c7f5e8..d34ad0d 100644 --- a/internal/middleware/auth/auth.go +++ b/internal/middleware/auth/auth.go @@ -75,7 +75,7 @@ func (a *Auth) StreamInterceptor(srv any, ss grpc.ServerStream, info *grpc.Strea if strings.Contains(authorization, "Bearer") { return a.jwt.StreamInterceptor(srv, ss, info, handler) - } + } return a.ak.StreamInterceptor(srv, ss, info, handler) } diff --git a/internal/middleware/auth/auth_test.go b/internal/middleware/auth/auth_test.go index 0e94b75..e122ef4 100644 --- a/internal/middleware/auth/auth_test.go +++ b/internal/middleware/auth/auth_test.go @@ -455,13 +455,12 @@ func TestStreamInterceptorErr(t *testing.T) { c.So(err, c.ShouldNotBeNil) c.So(err.Error(), c.ShouldContainSubstring, fmt.Errorf("metadata not exists in context").Error()) - err = mid.StreamInterceptor(&hello.HelloRequest{}, &greeterSayHelloWebsocketServer{ServerStream: &testStream{ctx: metadata.NewIncomingContext(context.Background(),metadata.Pairs("Authorization", ""))}}, &grpc.StreamServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(srv any, ss grpc.ServerStream) error { + err = mid.StreamInterceptor(&hello.HelloRequest{}, &greeterSayHelloWebsocketServer{ServerStream: &testStream{ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("Authorization", ""))}}, &grpc.StreamServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(srv any, ss grpc.ServerStream) error { return ss.RecvMsg(srv) }) c.So(err, c.ShouldNotBeNil) c.So(err.Error(), c.ShouldContainSubstring, pkg.ErrTokenMissing.Error()) - }) } diff --git a/internal/middleware/auth/jwt.go b/internal/middleware/auth/jwt.go index 807a879..83a8f5c 100644 --- a/internal/middleware/auth/jwt.go +++ b/internal/middleware/auth/jwt.go @@ -56,11 +56,11 @@ func (a *JWTAuth) jwt2BasicAuth(authorization string) (*api.BasicAuth, error) { token = strArr[1] } if token == "" { - return nil, gosdk.NewError(pkg.ErrHeaderTokenFormat,int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR),codes.Unauthenticated , "check_token") + return nil, gosdk.NewError(pkg.ErrHeaderTokenFormat, int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR), codes.Unauthenticated, "check_token") } jwtInfo := strings.Split(token, ".") if len(jwtInfo) != 3 { - return nil, gosdk.NewError(pkg.ErrHeaderTokenFormat, int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR),codes.Unauthenticated, "check_token_format") + return nil, gosdk.NewError(pkg.ErrHeaderTokenFormat, int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR), codes.Unauthenticated, "check_token_format") } // 生成signature sig := fmt.Sprintf("%s.%s", jwtInfo[0], jwtInfo[1]) @@ -68,16 +68,16 @@ func (a *JWTAuth) jwt2BasicAuth(authorization string) (*api.BasicAuth, error) { sig = tiga.ComputeHmacSha256(sig, secret) if sig != jwtInfo[2] { - return nil, gosdk.NewError(pkg.ErrTokenInvalid, int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR),codes.Internal,"check_sign") + return nil, gosdk.NewError(pkg.ErrTokenInvalid, int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR), codes.Internal, "check_sign") } payload := &api.BasicAuth{} payloadBytes, err := tiga.Base64URL2Bytes(jwtInfo[1]) if err != nil { - return nil, gosdk.NewError(fmt.Errorf("%w:%w", pkg.ErrAuthDecrypt, err), int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR),codes.Unauthenticated, "check_token") + return nil, gosdk.NewError(fmt.Errorf("%w:%w", pkg.ErrAuthDecrypt, err), int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR), codes.Unauthenticated, "check_token") } err = json.Unmarshal(payloadBytes, payload) if err != nil { - return nil, gosdk.NewError(fmt.Errorf("%w:%w", pkg.ErrDecode, err), int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR),codes.Unauthenticated, "check_token") + return nil, gosdk.NewError(fmt.Errorf("%w:%w", pkg.ErrDecode, err), int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR), codes.Unauthenticated, "check_token") } return payload, nil } @@ -88,18 +88,18 @@ func (a *JWTAuth) JWTLock(uid string) (*redislock.Lock, error) { func (a *JWTAuth) checkJWTItem(ctx context.Context, payload *api.BasicAuth, token string) (bool, error) { if payload.Expiration < time.Now().Unix() { - return false, gosdk.NewError(pkg.ErrTokenExpired, int32(api.UserSvrCode_USER_TOKEN_EXPIRE_ERR),codes.Internal,"check_expired") + return false, gosdk.NewError(pkg.ErrTokenExpired, int32(api.UserSvrCode_USER_TOKEN_EXPIRE_ERR), codes.Internal, "check_expired") } if payload.NotBefore > time.Now().Unix() { remain := payload.NotBefore - time.Now().Unix() msg := fmt.Sprintf("Please retry after %d seconds ", remain) - return false, gosdk.NewError(pkg.ErrTokenNotActive, int32(api.UserSvrCode_USER_TOKEN_NOT_ACTIVTE_ERR),codes.Canceled,"check_not_active", gosdk.WithClientMessage(msg)) + return false, gosdk.NewError(pkg.ErrTokenNotActive, int32(api.UserSvrCode_USER_TOKEN_NOT_ACTIVTE_ERR), codes.Canceled, "check_not_active", gosdk.WithClientMessage(msg)) } if payload.Issuer != "gateway" { - return false, gosdk.NewError(pkg.ErrTokenIssuer, int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR),codes.Unauthenticated,"check_issuer") + return false, gosdk.NewError(pkg.ErrTokenIssuer, int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR), codes.Unauthenticated, "check_issuer") } if ok, err := a.biz.CheckInBlackList(ctx, tiga.GetMd5(token)); ok { - return false, gosdk.NewError(fmt.Errorf("%w or %w", pkg.ErrTokenBlackList, err), int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR),codes.Unauthenticated,"check_blacklist") + return false, gosdk.NewError(fmt.Errorf("%w or %w", pkg.ErrTokenBlackList, err), int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR), codes.Unauthenticated, "check_blacklist") } return true, nil @@ -152,7 +152,7 @@ func (a *JWTAuth) checkJWT(ctx context.Context, authorization string, rspHeader secret := a.config.GetJWTSecret() newToken, err := tiga.GenerateJWT(payload, secret) if err != nil { - return false, gosdk.NewError(fmt.Errorf("%s:%w", "generate new token error", err), int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR),codes.Unauthenticated, "generate_token") + return false, gosdk.NewError(fmt.Errorf("%s:%w", "generate new token error", err), int32(api.UserSvrCode_USER_TOKEN_INVALIDATE_ERR), codes.Unauthenticated, "generate_token") } // 旧token加入黑名单 go a.biz.PutBlackList(ctx, a.config.GetUserBlackListKey(tiga.GetMd5(token))) diff --git a/internal/middleware/auth/jwt_test.go b/internal/middleware/auth/jwt_test.go index f2ecb6e..75f5cf4 100644 --- a/internal/middleware/auth/jwt_test.go +++ b/internal/middleware/auth/jwt_test.go @@ -314,7 +314,7 @@ func TestJWTStreamInterceptor(t *testing.T) { c.So(err.Error(), c.ShouldContainSubstring, "test") patch.Reset() - err=jwt.StreamResponseAfter(context.TODO(), auth.NewGrpcStream(&testStream{},"",context.TODO(),nil), nil) + err = jwt.StreamResponseAfter(context.TODO(), auth.NewGrpcStream(&testStream{}, "", context.TODO(), nil), nil) c.So(err, c.ShouldBeNil) }) } diff --git a/internal/middleware/auth/stream.go b/internal/middleware/auth/stream.go index 2534cf1..2fde49c 100644 --- a/internal/middleware/auth/stream.go +++ b/internal/middleware/auth/stream.go @@ -11,8 +11,7 @@ import ( ) type StreamValidator interface { - ValidateStream(ctx context.Context, req interface{}, fullName string, headers Header) (context.Context, error) - + ValidateStream(ctx context.Context, req interface{}, fullName string, headers Header) (context.Context, error) } type grpcServerStream struct { grpc.ServerStream @@ -28,7 +27,8 @@ var streamPool = &sync.Pool{ } }, } -func NewGrpcStream(s grpc.ServerStream, fullName string, ctx context.Context,validator StreamValidator) *grpcServerStream { + +func NewGrpcStream(s grpc.ServerStream, fullName string, ctx context.Context, validator StreamValidator) *grpcServerStream { stream := streamPool.Get().(*grpcServerStream) stream.ServerStream = s stream.fullName = fullName @@ -61,7 +61,7 @@ func (s *grpcServerStream) RecvMsg(m interface{}) error { } - header :=NewGrpcStreamHeader(in, s.Context(), out, s.ServerStream) + header := NewGrpcStreamHeader(in, s.Context(), out, s.ServerStream) _, err := s.validate.ValidateStream(s.Context(), m, s.fullName, header) s.ctx = header.ctx header.Release() diff --git a/internal/middleware/http.go b/internal/middleware/http.go index 6f6a083..4fe8e85 100644 --- a/internal/middleware/http.go +++ b/internal/middleware/http.go @@ -3,8 +3,6 @@ package middleware import ( "context" "fmt" - "net/http" - "strconv" "strings" "github.com/begonia-org/begonia/internal/pkg/routers" @@ -18,7 +16,6 @@ import ( _ "github.com/begonia-org/go-sdk/api/user/v1" common "github.com/begonia-org/go-sdk/common/api/v1" - "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" "google.golang.org/genproto/googleapis/api/httpbody" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -52,13 +49,14 @@ func (s *HttpStream) SendMsg(m interface{}) error { if !ok { return s.ServerStream.SendMsg(m) } - if protocol, ok := md["grpcgateway-content-type"]; ok { + if protocol, ok := md["grpcgateway-accept"]; ok { if !strings.EqualFold(protocol[0], "application/json") { return s.ServerStream.SendMsg(m) } routersList := routers.Get() + router := routersList.GetRouteByGrpcMethod(s.FullMethod) // 对内置服务的http响应进行格式化 - if routersList.IsLocalSrv(s.FullMethod) { + if routersList.IsLocalSrv(s.FullMethod) || router.UseJsonResponse { rsp, _ := grpcToHttpResponse(m, nil) return s.ServerStream.SendMsg(rsp) @@ -83,86 +81,8 @@ func getClientMessageMap() map[int32]string { } -// func isValidContentType(ct string) bool { -// mimeType, _, err := mime.ParseMediaType(ct) -// return err == nil && mimeType != "" -// } - -func writeHttpHeaders(w http.ResponseWriter, key string, value []string) { - if httpKey := gosdk.GetHttpHeaderKey(key); httpKey != "" { - for _, v := range value { - w.Header().Del(key) - if v != "" { - if strings.EqualFold(httpKey, "Content-Type") { - w.Header().Set(httpKey, v) - } else { - w.Header().Add(httpKey, v) - - } - - headers := w.Header().Values("Access-Control-Expose-Headers") - for _, h := range headers { - if strings.EqualFold(h, httpKey) { - return - } - } - headers = append(headers, http.CanonicalHeaderKey(httpKey)) - w.Header().Set("Access-Control-Expose-Headers", strings.Join(headers, ",")) - - } - } - - } - -} -func HttpResponseBodyModify(ctx context.Context, w http.ResponseWriter, msg proto.Message) error { - httpCode := http.StatusOK - for key, value := range w.Header() { - if strings.HasPrefix(key, "Grpc-Metadata-") { - w.Header().Del(key) - } - writeHttpHeaders(w, key, value) - if strings.HasSuffix(http.CanonicalHeaderKey(key), "X-Http-Code") { - codeStr := value[0] - code, err := strconv.ParseInt(codeStr, 10, 32) - if err != nil { - return gosdk.NewError(err, int32(common.Code_INTERNAL_ERROR), codes.Internal, "internal_error") - } - httpCode = int(code) - - } - - } - - out, ok := metadata.FromOutgoingContext(ctx) - if ok { - for k, v := range out { - writeHttpHeaders(w, k, v) - } - } - if httpCode != http.StatusOK { - w.WriteHeader(httpCode) - } - return nil -} - -func OutgoingMetaInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { - md, ok := metadata.FromIncomingContext(ctx) - if ok { - if reqIds, ok := md["x-request-id"]; ok { - ctx = metadata.AppendToOutgoingContext(ctx, gosdk.GetMetadataKey("x-request-id"), reqIds[0]) - } - } - resp, err = handler(ctx, req) - if err == nil { - return resp, err - } - return nil, err -} - func toStructMessage(msg protoreflect.ProtoMessage) (*structpb.Struct, error) { jsonBytes, err := protojson.Marshal(msg) - if err != nil { return nil, fmt.Errorf("Failed to serialize message to JSON: %w", err) } @@ -175,7 +95,6 @@ func toStructMessage(msg protoreflect.ProtoMessage) (*structpb.Struct, error) { return structMsg, nil } func grpcToHttpResponse(rsp interface{}, err error) (*common.HttpResponse, error) { - // log.Printf("error code:%d", 2222222) if err != nil { if st, ok := status.FromError(err); ok { @@ -219,7 +138,7 @@ func grpcToHttpResponse(rsp interface{}, err error) (*common.HttpResponse, error Code: int32(common.Code_INTERNAL_ERROR), Data: nil, Message: "internal error", - }, nil + }, err } anyData := &structpb.Struct{} @@ -247,8 +166,9 @@ func (h *Http) UnaryInterceptor(ctx context.Context, req interface{}, info *grpc return handler(ctx, req) } routersList := routers.Get() + router := routersList.GetRouteByGrpcMethod(info.FullMethod) // 对内置服务的http响应进行格式化 - if routersList.IsLocalSrv(info.FullMethod) { + if routersList.IsLocalSrv(info.FullMethod) || router.UseJsonResponse { rsp, err := handler(ctx, req) if _, ok := rsp.(*httpbody.HttpBody); ok { return rsp, err @@ -279,18 +199,3 @@ func (h *Http) SetPriority(priority int) { func (h *Http) Name() string { return h.name } - -func HandleRoutingError(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, r *http.Request, httpStatus int) { - if httpStatus != http.StatusMethodNotAllowed { - runtime.DefaultRoutingErrorHandler(ctx, mux, marshaler, w, r, httpStatus) - return - } - - // Use HTTPStatusError to customize the DefaultHTTPErrorHandler status code - err := &runtime.HTTPStatusError{ - HTTPStatus: httpStatus, - Err: status.Error(codes.Unimplemented, http.StatusText(httpStatus)), - } - - runtime.DefaultHTTPErrorHandler(ctx, mux, marshaler, w, r, err) -} diff --git a/internal/middleware/http_test.go b/internal/middleware/http_test.go new file mode 100644 index 0000000..805d4c0 --- /dev/null +++ b/internal/middleware/http_test.go @@ -0,0 +1,187 @@ +package middleware_test + +import ( + "context" + "fmt" + "path/filepath" + "runtime" + "testing" + + "github.com/agiledragon/gomonkey/v2" + "github.com/begonia-org/begonia/gateway" + "github.com/begonia-org/begonia/internal/middleware" + "github.com/begonia-org/begonia/internal/pkg" + "github.com/begonia-org/begonia/internal/pkg/routers" + gosdk "github.com/begonia-org/go-sdk" + hello "github.com/begonia-org/go-sdk/api/example/v1" + user "github.com/begonia-org/go-sdk/api/user/v1" + c "github.com/smartystreets/goconvey/convey" + "google.golang.org/genproto/googleapis/api/httpbody" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/encoding/protojson" +) + +type testStream struct { + ctx context.Context +} + +func (t *testStream) SetHeader(metadata.MD) error { + return nil +} +func (t *testStream) SendHeader(metadata.MD) error { + return nil +} +func (t *testStream) SetTrailer(metadata.MD) { + +} +func (t *testStream) Context() context.Context { + return t.ctx + +} +func (t *testStream) SendMsg(m interface{}) error { + return nil +} +func (t *testStream) RecvMsg(m interface{}) error { + return nil +} + +type greeterSayHelloWebsocketServer struct { + grpc.ServerStream +} + +func (x *greeterSayHelloWebsocketServer) Send(m *hello.HelloReply) error { + return x.ServerStream.SendMsg(m) +} + +func (x *greeterSayHelloWebsocketServer) Recv() (*hello.HelloRequest, error) { + m := new(hello.HelloRequest) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} +func (x *greeterSayHelloWebsocketServer) Context() context.Context { + return x.ServerStream.Context() + +} +func TestStreamInterceptor(t *testing.T) { + c.Convey("test stream interceptor", t, func() { + mid := middleware.NewHttp() + R := routers.Get() + _, filename, _, _ := runtime.Caller(0) + pbFile := filepath.Join(filepath.Dir(filepath.Dir(filepath.Dir(filename))), "testdata") + + pd, err := gateway.NewDescription(pbFile) + c.So(err, c.ShouldBeNil) + R.LoadAllRouters(pd) + ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("grpcgateway-accept", "application/json")) + err = mid.StreamInterceptor(&hello.HelloRequest{}, &greeterSayHelloWebsocketServer{ServerStream: &testStream{ctx: ctx}}, &grpc.StreamServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(srv any, ss grpc.ServerStream) error { + return ss.SendMsg(srv) + }) + c.So(err, c.ShouldBeNil) + }) +} +func TestUnaryInterceptor(t *testing.T) { + c.Convey("test unary interceptor", t, func() { + mid := middleware.NewHttp() + R := routers.Get() + _, filename, _, _ := runtime.Caller(0) + pbFile := filepath.Join(filepath.Dir(filepath.Dir(filepath.Dir(filename))), "testdata") + + pd, err := gateway.NewDescription(pbFile) + c.So(err, c.ShouldBeNil) + R.LoadAllRouters(pd) + ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("grpcgateway-accept", "application/json")) + req, err := mid.UnaryInterceptor(ctx, &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return req, nil + }) + c.So(err, c.ShouldBeNil) + c.So(req, c.ShouldNotBeNil) + mid.SetPriority(1) + c.So(mid.Priority(), c.ShouldEqual, 1) + c.So(mid.Name(), c.ShouldEqual, "http") + req, err = mid.UnaryInterceptor(ctx, &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, gosdk.NewError(pkg.ErrAPIKeyNotMatch, int32(user.UserSvrCode_USER_ACCOUNT_ERR), codes.Internal, "test", gosdk.WithClientMessage("test message")) + }) + c.So(err, c.ShouldNotBeNil) + c.So(req, c.ShouldNotBeNil) + + req, err = mid.UnaryInterceptor(ctx, &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, status.Error(codes.NotFound, "test") + }) + c.So(err, c.ShouldNotBeNil) + c.So(req, c.ShouldNotBeNil) + + req, err = mid.UnaryInterceptor(ctx, &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, status.Error(codes.Unimplemented, "test") + }) + c.So(err, c.ShouldNotBeNil) + c.So(req, c.ShouldNotBeNil) + + req, err = mid.UnaryInterceptor(ctx, &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, fmt.Errorf("test") + }) + c.So(err, c.ShouldNotBeNil) + c.So(req, c.ShouldNotBeNil) + + patch := gomonkey.ApplyFuncReturn(protojson.Marshal, nil, fmt.Errorf("test")) + defer patch.Reset() + req, err = mid.UnaryInterceptor(ctx, &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return &hello.HelloReply{}, nil + }) + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "test") + c.So(req, c.ShouldBeNil) + patch.Reset() + + patch1 := gomonkey.ApplyFuncReturn(protojson.Unmarshal, fmt.Errorf("unmarshal test")) + defer patch1.Reset() + req, err = mid.UnaryInterceptor(ctx, &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return &hello.HelloReply{}, nil + }) + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "unmarshal test") + c.So(req, c.ShouldBeNil) + patch1.Reset() + + req, err = mid.UnaryInterceptor(context.Background(), &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return &hello.HelloReply{}, nil + }) + c.So(err, c.ShouldBeNil) + c.So(req, c.ShouldNotBeNil) + + req, err = mid.UnaryInterceptor(metadata.NewIncomingContext(context.Background(), metadata.Pairs("grpcgateway-accept", "test")), &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return &hello.HelloReply{}, nil + }) + c.So(err, c.ShouldBeNil) + c.So(req, c.ShouldNotBeNil) + + req, err = mid.UnaryInterceptor(ctx, &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return &httpbody.HttpBody{}, nil + }) + c.So(err, c.ShouldBeNil) + c.So(req, c.ShouldNotBeNil) + + req, err = mid.UnaryInterceptor(metadata.NewIncomingContext(context.Background(), metadata.Pairs("grpcgateway-test", "test")), &hello.HelloRequest{}, &grpc.UnaryServerInfo{FullMethod: "/INTEGRATION.TESTSERVICE/GET"}, func(ctx context.Context, req interface{}) (interface{}, error) { + return &hello.HelloReply{}, nil + }) + c.So(err, c.ShouldBeNil) + c.So(req, c.ShouldNotBeNil) + + stream := &middleware.HttpStream{ServerStream: &greeterSayHelloWebsocketServer{ServerStream: &testStream{ctx: context.Background()}}, FullMethod: "/INTEGRATION.TESTSERVICE/GET"} + err = stream.SendMsg(&hello.HelloReply{}) + c.So(err, c.ShouldBeNil) + + stream = &middleware.HttpStream{ServerStream: &greeterSayHelloWebsocketServer{ServerStream: &testStream{ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("grpcgateway-test", "test"))}}, FullMethod: "/INTEGRATION.TESTSERVICE/GET"} + err = stream.SendMsg(&hello.HelloReply{}) + c.So(err, c.ShouldBeNil) + + stream = &middleware.HttpStream{ServerStream: &greeterSayHelloWebsocketServer{ServerStream: &testStream{ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("grpcgateway-accept", "test"))}}, FullMethod: "/INTEGRATION.TESTSERVICE/GET"} + err = stream.SendMsg(&hello.HelloReply{}) + c.So(err, c.ShouldBeNil) + + }) +} diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index 14b665a..e19c43e 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -2,12 +2,12 @@ package middleware import ( "context" + "fmt" "sort" "time" "github.com/begonia-org/begonia/gateway" "github.com/begonia-org/begonia/internal/biz" - "github.com/begonia-org/begonia/internal/data" "github.com/begonia-org/begonia/internal/middleware/auth" "github.com/begonia-org/begonia/internal/pkg/config" goloadbalancer "github.com/begonia-org/go-loadbalancer" @@ -21,14 +21,14 @@ import ( // var Plugins = map[string]gosdk.GrpcPlugin{ // "jwt": &auth.JWTAuth{}, // } -var ProviderSet = wire.NewSet(New,auth.NewAccessKeyAuth) +var ProviderSet = wire.NewSet(New, auth.NewAccessKeyAuth) func New(config *config.Config, rdb *tiga.RedisDao, user *biz.AuthzUsecase, log logger.Logger, authz *biz.AccessKeyAuth, - local *data.LayeredCache) *PluginsApply { +) *PluginsApply { jwt := auth.NewJWTAuth(config, rdb, user, log) ak := auth.NewAccessKeyAuth(authz, config, log) apiKey := auth.NewApiKeyAuth(config) @@ -50,15 +50,15 @@ func New(config *config.Config, if plugin, ok := plugins[pluginName]; ok { pluginsApply.Register(plugin, priority.(int)) } else { - log.Warnf(context.TODO(), "plugin %s not found", pluginName) + panic(fmt.Sprintf("plugin %s not found", pluginName)) } } rpcPlugins, err := config.GetRPCPlugins() if err != nil { - log.Errorf(context.TODO(), "get rpc plugins error:%v", err) - return pluginsApply + panic(fmt.Sprintf("get rpc plugins error:%v", err)) + } for _, rpc := range rpcPlugins { lb := goloadbalancer.NewGrpcLoadBalance(rpc) diff --git a/internal/middleware/middleware_test.go b/internal/middleware/middleware_test.go new file mode 100644 index 0000000..be8a8e6 --- /dev/null +++ b/internal/middleware/middleware_test.go @@ -0,0 +1,57 @@ +package middleware_test + +import ( + "fmt" + "testing" + + "github.com/agiledragon/gomonkey/v2" + "github.com/begonia-org/begonia" + "github.com/begonia-org/begonia/config" + "github.com/begonia-org/begonia/gateway" + "github.com/begonia-org/begonia/internal/biz" + "github.com/begonia-org/begonia/internal/data" + "github.com/begonia-org/begonia/internal/middleware" + cfg "github.com/begonia-org/begonia/internal/pkg/config" + "github.com/begonia-org/begonia/internal/pkg/crypto" + c "github.com/smartystreets/goconvey/convey" + "github.com/spark-lence/tiga" +) + +func TestMiddlewareUnaryInterceptorChains(t *testing.T) { + c.Convey("test middleware unary interceptor chains", t, func() { + env := "dev" + if begonia.Env != "" { + env = begonia.Env + } + config := config.ReadConfig(env) + cnf := cfg.NewConfig(config) + user := data.NewUserRepo(config, gateway.Log) + userAuth := crypto.NewUsersAuth(cnf) + authzRepo := data.NewAuthzRepo(config, gateway.Log) + authz := biz.NewAuthzUsecase(authzRepo, user, gateway.Log, userAuth, cnf) + repo := data.NewAppRepo(config, gateway.Log) + + akBiz := biz.NewAccessKeyAuth(repo, cnf, gateway.Log) + mid := middleware.New(cnf, tiga.NewRedisDao(config), authz, gateway.Log, akBiz) + // mid.SetPriority(1) + c.So(len(mid.StreamInterceptorChains()), c.ShouldBeGreaterThanOrEqualTo, 0) + c.So(len(mid.UnaryInterceptorChains()), c.ShouldBeGreaterThanOrEqualTo, 0) + + plugins := cnf.GetPlugins() + plugins["test"] = 1 + patch := gomonkey.ApplyFuncReturn((*cfg.Config).GetPlugins, plugins) + defer patch.Reset() + f := func() { + middleware.New(cnf, tiga.NewRedisDao(config), authz, gateway.Log, akBiz) + + } + c.So(f, c.ShouldPanicWith, "plugin test not found") + patch.Reset() + delete(plugins, "test") + + patch2 := gomonkey.ApplyFuncReturn((*cfg.Config).GetRPCPlugins, nil, fmt.Errorf("get rpc plugins error")) + defer patch2.Reset() + c.So(f, c.ShouldPanicWith, "get rpc plugins error:get rpc plugins error") + patch2.Reset() + }) +} diff --git a/internal/middleware/rpc.go b/internal/middleware/rpc.go index ea7b900..010c377 100644 --- a/internal/middleware/rpc.go +++ b/internal/middleware/rpc.go @@ -22,15 +22,15 @@ import ( type RPCPluginCaller interface{} -type rpcPluginCallerImpl struct { - plugins gosdk.Plugins -} +// type rpcPluginCallerImpl struct { +// plugins gosdk.Plugins +// } -func NewRPCPluginCaller() RPCPluginCaller { - return &rpcPluginCallerImpl{ - plugins: make(gosdk.Plugins, 0), - } -} +// func NewRPCPluginCaller() RPCPluginCaller { +// return &rpcPluginCallerImpl{ +// plugins: make(gosdk.Plugins, 0), +// } +// } type pluginImpl struct { priority int @@ -52,33 +52,15 @@ func (p *pluginImpl) Name() string { } func (p *pluginImpl) UnaryInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp any, err error) { - endpoint, err := p.getEndpoint(ctx) - if err != nil { - return nil, err - } - cn, err := endpoint.Get(ctx) - if err != nil { - return nil, gosdk.NewError(err, int32(common.Code_INTERNAL_ERROR), codes.Internal, "get_connection") - } - defer endpoint.AfterTransform(ctx, cn.((goloadbalancer.Connection))) - conn := cn.(goloadbalancer.Connection).ConnInstance().(*grpc.ClientConn) - plugin := api.NewPluginServiceClient(conn) - anyReq, err := anypb.New(req.(proto.Message)) - if err != nil { - return nil, gosdk.NewError(fmt.Errorf("new any to plugin error: %w", err), int32(common.Code_PARAMS_ERROR), codes.InvalidArgument, "new_any") - - } - rsp, err := plugin.Call(ctx, &api.PluginRequest{ - Request: anyReq, - FullMethodName: info.FullMethod, - }) - if err != nil { - return nil, gosdk.NewError(fmt.Errorf("call plugin error: %w", err), int32(common.Code_INTERNAL_ERROR), codes.Internal, "call_plugin") - } md, ok := metadata.FromIncomingContext(ctx) if !ok { md = metadata.New(nil) } + rsp, err := p.Apply(ctx, req, info.FullMethod) + if err != nil { + return nil, gosdk.NewError(fmt.Errorf("call plugin error: %w", err), int32(common.Code_INTERNAL_ERROR), codes.Internal, "call_plugin") + } + for k, v := range rsp.Metadata { md.Append(k, v) } @@ -115,7 +97,7 @@ func (p *pluginImpl) getEndpoint(ctx context.Context) (lb.Endpoint, error) { return endpoint, nil } -func (p *pluginImpl) Call(ctx context.Context, in *api.PluginRequest, opts ...grpc.CallOption) (*api.PluginResponse, error) { +func (p *pluginImpl) Apply(ctx context.Context, in interface{}, fullMethodName string) (*api.PluginResponse, error) { endpoint, err := p.getEndpoint(ctx) if err != nil { @@ -129,9 +111,18 @@ func (p *pluginImpl) Call(ctx context.Context, in *api.PluginRequest, opts ...gr conn := cn.(goloadbalancer.Connection).ConnInstance().(*grpc.ClientConn) plugin := api.NewPluginServiceClient(conn) - return plugin.Call(ctx, in, opts...) + anyReq, err := anypb.New(in.(proto.Message)) + if err != nil { + return nil, gosdk.NewError(fmt.Errorf("new any to plugin error: %w", err), int32(common.Code_PARAMS_ERROR), codes.InvalidArgument, "new_any") + + } + return plugin.Apply(ctx, &api.PluginRequest{ + Request: anyReq, + FullMethodName: fullMethodName, + }) + // return plugin.Call(ctx, anyReq, opts...) } -func (p *pluginImpl) GetPluginInfo(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*api.PluginInfo, error) { +func (p *pluginImpl) Info(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*api.PluginInfo, error) { endpoint, err := p.getEndpoint(ctx) if err != nil { return nil, err @@ -143,11 +134,22 @@ func (p *pluginImpl) GetPluginInfo(ctx context.Context, in *emptypb.Empty, opts defer endpoint.AfterTransform(ctx, cn.((goloadbalancer.Connection))) conn := cn.(goloadbalancer.Connection).ConnInstance().(*grpc.ClientConn) plugin := api.NewPluginServiceClient(conn) - return plugin.GetPluginInfo(ctx, in, opts...) + return plugin.Info(ctx, in, opts...) } func (p *pluginImpl) StreamInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { grpcStream := NewGrpcPluginStream(ss, info.FullMethod, ss.Context(), p) + if grpcStream != nil { + defer grpcStream.Release() + + } return handler(srv, grpcStream) } +func NewPluginImpl(lb lb.LoadBalance, name string, timeout time.Duration) *pluginImpl { + return &pluginImpl{ + lb: lb, + name: name, + timeout: timeout, + } +} diff --git a/internal/middleware/rpc_test.go b/internal/middleware/rpc_test.go new file mode 100644 index 0000000..dd09e60 --- /dev/null +++ b/internal/middleware/rpc_test.go @@ -0,0 +1,199 @@ +package middleware_test + +import ( + "context" + "fmt" + "net" + "testing" + "time" + + "github.com/agiledragon/gomonkey/v2" + "github.com/begonia-org/begonia/internal/middleware" + goloadbalancer "github.com/begonia-org/go-loadbalancer" + hello "github.com/begonia-org/go-sdk/api/example/v1" + "github.com/begonia-org/go-sdk/example" + c "github.com/smartystreets/goconvey/convey" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/peer" + "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/emptypb" +) + +func TestPluginUnaryInterceptor(t *testing.T) { + c.Convey("test plugin unary interceptor", t, func() { + go example.RunPlugins(":9850") + time.Sleep(2 * time.Second) + lb := goloadbalancer.NewGrpcLoadBalance(&goloadbalancer.Server{ + Name: "test", + Endpoints: []goloadbalancer.EndpointServer{ + { + Addr: "127.0.0.1:9850", + }, + }, + Pool: &goloadbalancer.PoolConfig{ + MaxOpenConns: 10, + MaxIdleConns: 5, + MaxActiveConns: 5, + }, + }) + mid := middleware.NewPluginImpl(lb, "test", 3*time.Second) + c.So(mid.Name(), c.ShouldEqual, "test") + mid.SetPriority(3) + c.So(mid.Priority(), c.ShouldEqual, 3) + addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:9090") + c.So(err, c.ShouldBeNil) + patch := gomonkey.ApplyFuncReturn(peer.FromContext, &peer.Peer{Addr: addr}, true) + defer patch.Reset() + _, err = mid.UnaryInterceptor(metadata.NewIncomingContext(context.Background(), metadata.Pairs("X-Forwarded-For", "127.0.0.1:9090")), &hello.HelloRequest{}, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + c.So(err, c.ShouldBeNil) + + _, err = mid.Info(metadata.NewIncomingContext(context.Background(), metadata.Pairs("test", "test")), &emptypb.Empty{}) + c.So(err, c.ShouldBeNil) + + err = mid.StreamInterceptor(&hello.HelloRequest{}, &testStream{ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("test", "test"))}, &grpc.StreamServerInfo{}, func(srv interface{}, ss grpc.ServerStream) error { + return ss.RecvMsg(srv) + }) + c.So(err, c.ShouldBeNil) + patch2 := gomonkey.ApplyFuncSeq(metadata.FromIncomingContext, []gomonkey.OutputCell{{ + Values: gomonkey.Params{metadata.New(map[string]string{"test": "test"}), true}, + Times: 2, + }, + { + Values: gomonkey.Params{nil, false}, + }, + }) + defer patch2.Reset() + err = mid.StreamInterceptor(&hello.HelloRequest{}, &testStream{ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("test", "test"))}, &grpc.StreamServerInfo{}, func(srv interface{}, ss grpc.ServerStream) error { + return ss.RecvMsg(srv) + }) + patch2.Reset() + c.So(err, c.ShouldBeNil) + + }) +} + +func TestPluginUnaryInterceptorErr(t *testing.T) { + c.Convey("test plugin unary interceptor", t, func() { + go example.RunPlugins(":9850") + time.Sleep(2 * time.Second) + lb := goloadbalancer.NewGrpcLoadBalance(&goloadbalancer.Server{ + Name: "test", + Endpoints: []goloadbalancer.EndpointServer{ + { + Addr: "127.0.0.1:9850", + }, + }, + Pool: &goloadbalancer.PoolConfig{ + MaxOpenConns: 10, + MaxIdleConns: 5, + MaxActiveConns: 5, + }, + }) + mid := middleware.NewPluginImpl(lb, "test", 3*time.Second) + c.So(mid.Name(), c.ShouldEqual, "test") + mid.SetPriority(3) + c.So(mid.Priority(), c.ShouldEqual, 3) + _, err := mid.UnaryInterceptor(context.Background(), &hello.HelloRequest{}, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "get metadata from context error") + + patch := gomonkey.ApplyMethodReturn(lb, "Select", nil, fmt.Errorf("select endpoint error")) + defer patch.Reset() + _, err = mid.UnaryInterceptor(metadata.NewIncomingContext(context.Background(), metadata.Pairs("X-Forwarded-For", "")), &hello.HelloRequest{}, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "select endpoint error") + _, err = mid.Info(metadata.NewIncomingContext(context.Background(), metadata.Pairs("X-Forwarded-For", "")), &emptypb.Empty{}) + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "select endpoint error") + patch.Reset() + ep := goloadbalancer.NewGrpcEndpoint("", nil) + patch2 := gomonkey.ApplyMethodReturn(ep, "Get", nil, fmt.Errorf("get connection error")) + defer patch2.Reset() + _, err = mid.UnaryInterceptor(metadata.NewIncomingContext(context.Background(), metadata.Pairs("X-Forwarded-For", "")), &hello.HelloRequest{}, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "get connection error") + _, err = mid.Info(metadata.NewIncomingContext(context.Background(), metadata.Pairs("X-Forwarded-For", "")), &emptypb.Empty{}) + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "get connection error") + patch2.Reset() + patch3 := gomonkey.ApplyFuncReturn(anypb.New, nil, fmt.Errorf("new any to plugin error")) + defer patch3.Reset() + _, err = mid.UnaryInterceptor(metadata.NewIncomingContext(context.Background(), metadata.Pairs("X-Forwarded-For", "")), &hello.HelloRequest{}, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + patch3.Reset() + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "new any to plugin error") + + patch4 := gomonkey.ApplyFuncReturn((*anypb.Any).UnmarshalTo, fmt.Errorf("unmarshal to request error")) + defer patch4.Reset() + _, err = mid.UnaryInterceptor(metadata.NewIncomingContext(context.Background(), metadata.Pairs("X-Forwarded-For", "127.0.0.1:9090")), &hello.HelloRequest{}, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + patch4.Reset() + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "unmarshal to request error") + + }) + +} + +func TestPluginStreamInterceptorErr(t *testing.T) { + c.Convey("test plugin unary interceptor", t, func() { + go example.RunPlugins(":9850") + time.Sleep(2 * time.Second) + lb := goloadbalancer.NewGrpcLoadBalance(&goloadbalancer.Server{ + Name: "test", + Endpoints: []goloadbalancer.EndpointServer{ + { + Addr: "127.0.0.1:9850", + }, + }, + Pool: &goloadbalancer.PoolConfig{ + MaxOpenConns: 10, + MaxIdleConns: 5, + MaxActiveConns: 5, + }, + }) + mid := middleware.NewPluginImpl(lb, "test", 3*time.Second) + c.So(mid.Name(), c.ShouldEqual, "test") + mid.SetPriority(3) + c.So(mid.Priority(), c.ShouldEqual, 3) + patch := gomonkey.ApplyFuncReturn((*testStream).RecvMsg, fmt.Errorf("recv msg error")) + defer patch.Reset() + err := mid.StreamInterceptor(&hello.HelloRequest{}, &testStream{ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("test", "test"))}, &grpc.StreamServerInfo{}, func(srv interface{}, ss grpc.ServerStream) error { + return ss.RecvMsg(srv) + }) + patch.Reset() + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "recv msg error") + patch1 := gomonkey.ApplyMethodReturn(mid, "Apply", nil, fmt.Errorf("call test plugin error")) + defer patch1.Reset() + err = mid.StreamInterceptor(&hello.HelloRequest{}, &testStream{ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("test", "test"))}, &grpc.StreamServerInfo{}, func(srv interface{}, ss grpc.ServerStream) error { + return ss.RecvMsg(srv) + }) + patch1.Reset() + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "call test plugin error") + + patch2 := gomonkey.ApplyFuncReturn((*anypb.Any).UnmarshalTo, fmt.Errorf("unmarshal to request error")) + defer patch2.Reset() + err = mid.StreamInterceptor(&hello.HelloRequest{}, &testStream{ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("test", "test"))}, &grpc.StreamServerInfo{}, func(srv interface{}, ss grpc.ServerStream) error { + return ss.RecvMsg(srv) + }) + patch2.Reset() + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "unmarshal to request error") + + }) + +} diff --git a/internal/middleware/stream.go b/internal/middleware/stream.go index 3fee971..ec3ecda 100644 --- a/internal/middleware/stream.go +++ b/internal/middleware/stream.go @@ -6,20 +6,17 @@ import ( "sync" gosdk "github.com/begonia-org/go-sdk" - api "github.com/begonia-org/go-sdk/api/plugin/v1" common "github.com/begonia-org/go-sdk/common/api/v1" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/types/known/anypb" ) type grpcPluginStream struct { grpc.ServerStream fullName string - plugin gosdk.RemotePlugin + plugin *pluginImpl ctx context.Context } @@ -31,7 +28,7 @@ var streamPool = &sync.Pool{ }, } -func NewGrpcPluginStream(s grpc.ServerStream, fullName string, ctx context.Context, plugin gosdk.RemotePlugin) *grpcPluginStream { +func NewGrpcPluginStream(s grpc.ServerStream, fullName string, ctx context.Context, plugin *pluginImpl) *grpcPluginStream { stream := streamPool.Get().(*grpcPluginStream) stream.ServerStream = s stream.fullName = fullName @@ -54,15 +51,7 @@ func (s *grpcPluginStream) RecvMsg(m interface{}) error { return err } - anyReq, err := anypb.New(m.(protoreflect.ProtoMessage)) - if err != nil { - return gosdk.NewError(fmt.Errorf("new any error: %w", err), int32(common.Code_PARAMS_ERROR), codes.InvalidArgument, "new_any") - - } - rsp, err := s.plugin.Call(s.Context(), &api.PluginRequest{ - FullMethodName: s.fullName, - Request: anyReq, - }) + rsp, err := s.plugin.Apply(s.Context(), m, s.fullName) if err != nil { return gosdk.NewError(fmt.Errorf("call %s plugin error: %w", s.plugin.Name(), err), int32(common.Code_INTERNAL_ERROR), codes.Internal, "call_plugin") diff --git a/internal/middleware/vaildator.go b/internal/middleware/vaildator.go index 224a6a0..c23ccb1 100644 --- a/internal/middleware/vaildator.go +++ b/internal/middleware/vaildator.go @@ -3,7 +3,8 @@ package middleware import ( "context" "fmt" - "log" + "reflect" + "strings" "sync" gosdk "github.com/begonia-org/go-sdk" @@ -52,47 +53,92 @@ func (p *validatePluginStream) RecvMsg(m interface{}) error { return err } + +func getFieldNamesFromJSONTags(input interface{}) map[string]string { + fieldMap := make(map[string]string) + + val := reflect.ValueOf(input) + if val.Kind() == reflect.Ptr { + val = val.Elem() + } + + typ := val.Type() + + for i := 0; i < val.NumField(); i++ { + field := typ.Field(i) + jsonTag := field.Tag.Get("json") + if jsonTag != "" && jsonTag != "-" { + if strings.Contains(jsonTag, ",") { + jsonTag = strings.Split(jsonTag, ",")[0] + } + fieldMap[jsonTag] = field.Name + } + } + + return fieldMap +} + // FiltersFields 从FieldMask中获取过滤字段,获取待验证字段 -func (p *ParamsValidatorImpl) FiltersFields(v interface{}) []string { - fields := make([]string, 0) +func (p *ParamsValidatorImpl) FiltersFields(v interface{}, parent string) []string { + fieldsMap := getFieldNamesFromJSONTags(v) + fieldsName := make([]string, 0) if message, ok := v.(protoreflect.ProtoMessage); ok { md := message.ProtoReflect().Descriptor() // 遍历所有字段 for i := 0; i < md.Fields().Len(); i++ { field := md.Fields().Get(i) - // 检查字段是否是FieldMask类型 - if field.Message() != nil && field.Message().FullName() == "google.protobuf.FieldMask" { + if field.Kind() == protoreflect.MessageKind && !field.IsList() && !field.IsMap() { // 获取字段的值(确保它是FieldMask类型) fieldValue := message.ProtoReflect().Get(field).Message() - mask := fieldValue.Interface().(*fieldmaskpb.FieldMask) - if mask == nil { + mask, ok := fieldValue.Interface().(*fieldmaskpb.FieldMask) + if mask == nil || !ok { continue } for _, path := range mask.Paths { if fd := message.ProtoReflect().Descriptor().Fields().ByJSONName(path); fd != nil { - fields = append(fields, string(fd.Name())) + fieldName := "" + if parent != "" { + fieldName = parent + "." + fieldsMap[fd.JSONName()] + } else { + fieldName = fieldsMap[fd.JSONName()] + } + if fd.Kind() == protoreflect.MessageKind { + if fd.IsList() { + for j := 0; j < message.ProtoReflect().Get(fd).List().Len(); j++ { + if fd.Kind() == protoreflect.MessageKind { + fieldsName = append(fieldsName, p.FiltersFields(message.ProtoReflect().Get(fd).List().Get(j).Message().Interface(), fmt.Sprintf("%s[%d]", fieldName, j))...) + } else { + fieldsName = append(fieldsName, fmt.Sprintf("%s[%d]", fieldName, j)) + } + } + } else { + fieldsName = append(fieldsName, p.FiltersFields(message.ProtoReflect().Get(fd).Message().Interface(), fieldName)...) + } + // fieldsName = append(fieldsName, p.FiltersFields(message.ProtoReflect().Get(fd).Interface(), fieldName)...) + } else { + fieldsName = append(fieldsName, fieldName) + } } } } } - return fields + return fieldsName } return nil } func (p *ParamsValidatorImpl) ValidateParams(v interface{}) error { validate := validator.New() err := validate.Struct(v) - filters := p.FiltersFields(v) + filters := p.FiltersFields(v, "") if len(filters) > 0 { err = validate.StructPartial(v, filters...) } if errs, ok := err.(validator.ValidationErrors); ok { - clientMsg := fmt.Sprintf("params %s validation failed with %v,except %s,%v", errs[0].Field(), errs[0].Value(), errs[0].ActualTag(),filters) - log.Print(clientMsg) + clientMsg := fmt.Sprintf("params %s validation failed with %v,except %s,%v", errs[0].Field(), errs[0].Value(), errs[0].ActualTag(), filters) return gosdk.NewError(fmt.Errorf("params %s validation failed: %v", errs[0].Field(), errs[0].Value()), int32(common.Code_PARAMS_ERROR), codes.InvalidArgument, "params_validation", gosdk.WithClientMessage(clientMsg)) } return nil @@ -119,11 +165,12 @@ func (p *ParamsValidatorImpl) UnaryInterceptor(ctx context.Context, req any, inf func (p *ParamsValidatorImpl) StreamInterceptor(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { validateStream := validatePluginStreamPool.Get().(*validatePluginStream) + defer validatePluginStreamPool.Put(validateStream) + validateStream.ServerStream = ss validateStream.validator = p validateStream.ctx = ss.Context() err := handler(srv, validateStream) - validatePluginStreamPool.Put(validateStream) return err } diff --git a/internal/middleware/vaildator_test.go b/internal/middleware/vaildator_test.go new file mode 100644 index 0000000..187eeb7 --- /dev/null +++ b/internal/middleware/vaildator_test.go @@ -0,0 +1,106 @@ +package middleware_test + +import ( + "context" + "testing" + + "github.com/begonia-org/begonia/internal/middleware" + hello "github.com/begonia-org/go-sdk/api/example/v1" + c "github.com/smartystreets/goconvey/convey" + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/fieldmaskpb" +) + +func TestValidatorUnaryInterceptor(t *testing.T) { + c.Convey("test validator unary interceptor", t, func() { + validator := middleware.NewParamsValidator() + + _, err := validator.UnaryInterceptor(context.Background(), &hello.HelloRequestWithValidator{ + Name: "test", + Msg: "test", + Sub: &hello.HelloSubRequest{ + SubMsg: "test", + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"sub_name", "sub_msg"}}, + }, + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"name", "msg", "sub"}}, + }, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "validation failed") + + validator.SetPriority(1) + c.So(validator.Priority(), c.ShouldEqual, 1) + c.So(validator.Name(), c.ShouldEqual, "ParamsValidator") + + _, err = validator.UnaryInterceptor(context.Background(), &hello.HelloRequestWithValidator{ + Name: "test", + Msg: "test", + Sub: &hello.HelloSubRequest{ + SubMsg: "test", + SubName: "test", + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"sub_name", "sub_msg"}}, + }, + Subs: []*hello.HelloSubRequest{ + { + SubMsg: "test", + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"sub_name", "sub_msg"}}, + }, + { + SubMsg: "test", + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"sub_name", "sub_msg"}}, + }, + }, + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"name", "msg", "sub", "subs"}}, + }, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + c.So(err, c.ShouldNotBeNil) + t.Log(err.Error()) + _, err = validator.UnaryInterceptor(context.Background(), &hello.HelloRequestWithValidator{ + Name: "test", + Msg: "test", + Sub: &hello.HelloSubRequest{ + SubMsg: "test", + SubName: "test", + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"sub_name", "sub_msg"}}, + }, + Subs: []*hello.HelloSubRequest{ + { + SubMsg: "test", + SubName: "test", + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"sub_name", "sub_msg"}}, + }, + }, + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"name", "msg", "sub", "subs"}}, + }, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + c.So(err, c.ShouldBeNil) + _, err = validator.UnaryInterceptor(context.Background(), &struct{}{}, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (interface{}, error) { + return nil, nil + }) + c.So(err, c.ShouldBeNil) + }) +} + +func TestValidatorStreamInterceptor(t *testing.T) { + c.Convey("test stream interceptor", t, func() { + validator := middleware.NewParamsValidator() + + err := validator.StreamInterceptor(&hello.HelloRequestWithValidator{ + Name: "test", + Msg: "test", + Sub: &hello.HelloSubRequest{ + SubMsg: "test", + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"sub_name", "sub_msg"}}, + }, + UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"name", "msg", "sub"}}, + }, &testStream{ctx: context.Background()}, &grpc.StreamServerInfo{}, func(srv interface{}, ss grpc.ServerStream) error { + ss.Context() + + return ss.RecvMsg(srv) + }) + c.So(err, c.ShouldNotBeNil) + }) +} diff --git a/internal/migrate/admin.go b/internal/migrate/admin.go index 1d9e2ec..9c97b36 100644 --- a/internal/migrate/admin.go +++ b/internal/migrate/admin.go @@ -32,14 +32,14 @@ func (m *UsersOperator) InitAdminUser(passwd string, aseKey, ivKey string, name, // 初始化数据 uid := snk.GenerateID() user := &api.Users{ - Uid: fmt.Sprintf("%d", uid), - Name: name, - Password: passwd, - Phone: phone, - Email: email, - Role: api.Role_ADMIN, - Dept: "", - Avatar: "", + Uid: fmt.Sprintf("%d", uid), + Name: name, + Password: passwd, + Phone: phone, + Email: email, + Role: api.Role_ADMIN, + Dept: "", + Avatar: "", Status: api.USER_STATUS_ACTIVE, CreatedAt: timestamppb.New(time.Now()), UpdatedAt: timestamppb.New(time.Now()), diff --git a/internal/migrate/app.go b/internal/migrate/app.go index 3ebc95a..ab73537 100644 --- a/internal/migrate/app.go +++ b/internal/migrate/app.go @@ -75,24 +75,15 @@ func (m *APPOperator) InitAdminAPP(owner string) error { if err != nil { return err } - // ak := os.Getenv("APP_ACCESS_KEY") - // if ak != "" { - // accessKey = ak - // } secret, err := biz.GenerateAppSecret() if err != nil { return err } - // sk := os.Getenv("APP_SECRET") - // if sk != "" { - // secret = sk - // } + appid := biz.GenerateAppid(snk) - // if pid := os.Getenv("APPID"); pid != "" { - // appid = pid - // } + app = &api.Apps{ Appid: appid, AccessKey: accessKey, diff --git a/internal/migrate/operator.go b/internal/migrate/operator.go index c017688..f1722e0 100644 --- a/internal/migrate/operator.go +++ b/internal/migrate/operator.go @@ -9,12 +9,12 @@ import ( type InitOperator struct { migrate *MySQLMigrate user *UsersOperator - app *APPOperator + app *APPOperator config *config.Config } -func NewInitOperator(migrate *MySQLMigrate, user *UsersOperator,app *APPOperator, config *config.Config) *InitOperator { - return &InitOperator{migrate: migrate, user: user, config: config,app:app} +func NewInitOperator(migrate *MySQLMigrate, user *UsersOperator, app *APPOperator, config *config.Config) *InitOperator { + return &InitOperator{migrate: migrate, user: user, config: config, app: app} } func (m *InitOperator) Init() error { @@ -29,7 +29,7 @@ func (m *InitOperator) Init() error { phone := m.config.GetDefaultAdminPhone() aseKey := m.config.GetAesKey() ivKey := m.config.GetAesIv() - uid,err := m.user.InitAdminUser(adminPasswd, aseKey, ivKey, name, email, phone) + uid, err := m.user.InitAdminUser(adminPasswd, aseKey, ivKey, name, email, phone) if err != nil { log.Printf("failed to init admin user: %v", err) return err diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 2a00a9e..90a0d1c 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -3,6 +3,7 @@ package config import ( "fmt" "path/filepath" + "strings" goloadbalancer "github.com/begonia-org/go-loadbalancer" "github.com/spark-lence/tiga" @@ -28,38 +29,43 @@ func NewConfig(config *tiga.Configuration) *Config { } func (c *Config) GetDefaultAdminPasswd() string { - return c.GetString("admin.password") + return c.getWithEnv("admin.password") } func (c *Config) GetDefaultAdminName() string { - return c.GetString("admin.name") + return c.getWithEnv("admin.name") } func (c *Config) GetDefaultAdminPhone() string { - return c.GetString("admin.phone") + return c.getWithEnv("admin.phone") } func (c *Config) GetDefaultAdminEmail() string { - return c.GetString("admin.email") + return c.getWithEnv("admin.email") } func (c *Config) GetAesKey() string { - return c.GetString("auth.aes_key") + return c.getWithEnv("auth.aes_key") } func (c *Config) GetAesIv() string { - return c.GetString("auth.aes_iv") -} -func (c *Config) GetCacheKeyPrefix() string { - return c.GetString("common.cache_key_prefix") + return c.getWithEnv("auth.aes_iv") } +// func (c *Config) GetCachePrefixKey() string { +// return c.getWithEnv("common.cache_key_prefix") +// } + // jwt_secret func (c *Config) GetJWTLockKey(uid string) string { - prefix := c.GetCacheKeyPrefix() + prefix := c.GetCachePrefixKey() return fmt.Sprintf("%s:jwt_lock:%s", prefix, uid) } func (c *Config) GetJWTSecret() string { - return c.GetString("auth.jwt_secret") + return c.getWithEnv("auth.jwt_secret") +} +func (c *Config) GetCachePrefixKey() string { + return fmt.Sprintf("%s:%s", c.GetEnv(), c.getWithEnv("common.cache_prefix_key")) + } func (c *Config) GetWhiteToken(uid string) string { - prefix := c.GetString("common.rdb_key_prefix") + prefix := c.GetCachePrefixKey() return fmt.Sprintf("%s:white:token:%s", prefix, uid) } func (c *Config) GetUserBlackListKey(uid string) string { @@ -75,18 +81,18 @@ func (c *Config) GetAppsLockKey() string { return fmt.Sprintf("%s:lock", prefix) } func (c *Config) GetUserBlackListExpiration() int { - return c.GetInt("auth.blacklist.user.cache_expire") + return c.getIntWithEnv("auth.blacklist.user.cache_expire") } func (c *Config) GetAPPAccessKeyExpiration() int { - return c.GetInt("auth.app.cache_expire") + return c.getIntWithEnv("auth.app.cache_expire") } func (c *Config) GetUserTokenBlackListBloomKey(uid string) string { prefix := c.GetUserTokenBlackListBloom() return fmt.Sprintf("%s:%s", prefix, uid) } func (c *Config) GetUserBlackListPrefix() string { - prefix := c.GetCacheKeyPrefix() + prefix := c.GetCachePrefixKey() return fmt.Sprintf("%s:user:black", prefix) } func (c *Config) GetUserTokenBlackListBloom() string { @@ -94,40 +100,41 @@ func (c *Config) GetUserTokenBlackListBloom() string { return fmt.Sprintf("%s:user:black", prefix) } func (c *Config) GetBlacklistPubSubChannel() string { - return c.GetString("auth.blacklist.pubsub.channel") + return c.getWithEnv("auth.blacklist.pubsub.channel") } func (c *Config) GetKeyValuePubsubKey() string { - prefix := c.GetString("common.pubsub_key_prefix") + prefix := fmt.Sprintf("%s:%s", c.GetCachePrefixKey(), c.getWithEnv("common.pubsub_key_prefix")) return fmt.Sprintf("%s:kv", prefix) } func (c *Config) GetFilterPubsubKey() string { - prefix := c.GetString("common.pubsub_key_channel") + prefix := fmt.Sprintf("%s:%s", c.GetCachePrefixKey(), c.getWithEnv("common.pubsub_key_channel")) return fmt.Sprintf("%s:filter", prefix) } func (c *Config) GetMultiCacheReadStrategy() int { - return c.GetInt("common.multi_cache_strategy") + return c.getIntWithEnv("common.multi_cache_strategy") } func (c *Config) GetKeyValuePrefix() string { - return c.GetString("common.kv_prefix") + return fmt.Sprintf("%s:%s", c.GetCachePrefixKey(), c.getWithEnv("common.kv_prefix")) } func (c *Config) GetFilterPrefix() string { - return c.GetString("common.filter_key_prefix") + prefix := c.GetCachePrefixKey() + return fmt.Sprintf("%s:%s", prefix, c.getWithEnv("common.filter_key_prefix")) } func (c *Config) GetBlacklistPubSubGroup() string { - return c.GetString("auth.blacklist.pubsub.group") + return c.getWithEnv("auth.blacklist.pubsub.group") } func (c *Config) GetBlacklistFilterEntries() int { - return c.GetInt("auth.blacklist.filter.entries") + return c.getIntWithEnv("auth.blacklist.filter.entries") } func (c *Config) GetBlacklistFilterErrorRate() int { - return c.GetInt("auth.blacklist.filter.error_rate") + return c.getIntWithEnv("auth.blacklist.filter.error_rate") } func (c *Config) GetBlacklistBloomErrRate() float64 { return c.GetFloat64(fmt.Sprintf("%s.auth.blacklist.bloom.error_rate", c.GetEnv())) } func (c *Config) GetBlacklistBloomM() int { - return c.GetInt("auth.blacklist.bloom.m") + return c.getIntWithEnv("auth.blacklist.bloom.m") } func (c *Config) GetAPPAccessKey(access string) string { @@ -139,19 +146,20 @@ func (c *Config) GetAppidKey(accessKey string) string { return fmt.Sprintf("%s:%s", prefix, accessKey) } func (c *Config) GetAppPrefix() string { - return c.GetString("common.app_key_prefix") + prefix := c.GetCachePrefixKey() + return fmt.Sprintf("%s:%s", prefix, c.getWithEnv("common.app_key_prefix")) } func (c *Config) GetAPPAccessKeyPrefix() string { - prefix := c.GetString("common.app_key_prefix") + prefix := c.GetAppPrefix() return fmt.Sprintf("%s:access_key", prefix) } func (c *Config) GetAppidPrefix() string { - prefix := c.GetString("common.app_key_prefix") + prefix := c.GetAppPrefix() return fmt.Sprintf("%s:appid", prefix) } func (c *Config) GetAesConfig() (key string, iv string) { - key = c.GetString("auth.aes_key") - iv = c.GetString("auth.aes_iv") + key = c.getWithEnv("auth.aes_key") + iv = c.getWithEnv("auth.aes_iv") return key, iv } @@ -159,19 +167,19 @@ func (c *Config) GetCorsConfig() []string { return c.GetStringSlice(fmt.Sprintf("%s.gateway.cors", c.GetEnv())) } func (c *Config) GetJWTExpiration() int { - return c.GetInt("auth.jwt_expiration") + return c.getIntWithEnv("auth.jwt_expiration") } func (c *Config) GetPluginDir() string { - return c.GetString("endpoints.plugins.dir") + return c.getWithEnv("endpoints.plugins.dir") } func (c *Config) GetUploadDir() string { - return c.GetString("file.upload.dir") + return c.getWithEnv("file.upload.dir") } func (c *Config) GetProtosDir() string { - return c.GetString("file.protos.dir") + return c.getWithEnv("file.protos.dir") } func (c *Config) GetLocalAPIDesc() string { - return c.GetString("file.protos.desc") + return c.getWithEnv("file.protos.desc") } func (c *Config) GetPlugins() map[string]interface{} { @@ -194,19 +202,15 @@ func (c *Config) GetRPCPlugins() ([]*goloadbalancer.Server, error) { return plugins, nil } func (c *Config) GetEndpointsPrefix() string { - key := fmt.Sprintf("%s.etcd.endpoint.prefix", c.GetEnv()) - if val := c.GetString(key); val != "" { - return val - } - return c.GetString("common.etcd.endpoint.prefix") + return fmt.Sprintf("%s%s", c.GetEnv(), c.getWithEnv("common.etcd.endpoint.prefix")) } func (c *Config) GetGatewayDescriptionOut() string { - return c.GetString("gateway.descriptor.out_dir") + return c.getWithEnv("gateway.descriptor.out_dir") } func (c *Config) GetAdminAPIKey() string { - return c.GetString("auth.admin.apikey") + return c.getWithEnv("auth.admin.apikey") } func (c *Config) GetServicePrefix() string { @@ -230,12 +234,8 @@ func (c *Config) GetServiceNameKey(name string) string { return filepath.Join(prefix, name) } func (c *Config) GetAppKeyPrefix() string { - key := fmt.Sprintf("%s.etcd.app.prefix", c.GetEnv()) - if val := c.GetString(key); val != "" { - return val - } - prefix := c.GetString("common.etcd.app.prefix") - return prefix + prefix := c.getWithEnv("common.etcd.app.prefix") + return fmt.Sprintf("%s%s", c.GetEnv(), prefix) } func (c *Config) GetAPPKey(id string) string { prefix := c.GetAppKeyPrefix() @@ -254,20 +254,28 @@ func (c *Config) GetTagsKey(tag, id string) string { prefix := c.GetServiceTagsPrefix() return filepath.Join(prefix, tag, id) } +func (c *Config) getWithEnv(key string) string { + originKey := strings.TrimPrefix(key, "common.") -func (c *Config) GetRSAPriKey() string { - key := fmt.Sprintf("%s.auth.rsa.private_key", c.GetEnv()) - if val := c.GetString(key); val != "" { + envKey := fmt.Sprintf("%s.%s", c.GetEnv(), originKey) + if val := c.GetString(envKey); val != "" { return val - } - return c.GetString("auth.rsa.private_key") - + return c.GetString(key) } -func (c *Config) GetRSAPubKey() string { - key := fmt.Sprintf("%s.auth.rsa.public_key", c.GetEnv()) - if val:= c.GetString(key);val!=""{ +func (c *Config) getIntWithEnv(key string) int { + envKey := fmt.Sprintf("%s.%s", c.GetEnv(), key) + if val := c.GetInt(envKey); val != 0 { return val } - return c.GetString("auth.rsa.public_key") + return c.GetInt(key) +} +func (c *Config) GetRSAPriKey() string { + + return c.getWithEnv("auth.rsa.private_key") + +} +func (c *Config) GetRSAPubKey() string { + + return c.getWithEnv("auth.rsa.public_key") } diff --git a/internal/pkg/config/config_test.go b/internal/pkg/config/config_test.go index 583059a..7a71b6a 100644 --- a/internal/pkg/config/config_test.go +++ b/internal/pkg/config/config_test.go @@ -21,7 +21,7 @@ func TestConfig(t *testing.T) { // log.Printf("env: %s", env) cnf := conf.ReadConfig(env) config := cfg.NewConfig(cnf) - prefix := config.GetCacheKeyPrefix() + prefix := config.GetCachePrefixKey() c.So(config.GetDefaultAdminPasswd(), c.ShouldNotEqual, "") c.So(config.GetDefaultAdminName(), c.ShouldNotEqual, "") c.So(config.GetDefaultAdminPhone(), c.ShouldNotEqual, "") @@ -63,7 +63,7 @@ func TestConfig(t *testing.T) { c.So(config.GetProtosDir(), c.ShouldNotBeEmpty) c.So(config.GetLocalAPIDesc(), c.ShouldNotBeEmpty) c.So(config.GetPlugins(), c.ShouldNotBeEmpty) - ss, err := config.GetRPCPlugins() + _, err := config.GetRPCPlugins() c.So(err, c.ShouldBeNil) // c.So(len(ss), c.ShouldBeGreaterThan, 0) c.So(config.GetEndpointsPrefix(), c.ShouldNotBeEmpty) @@ -72,6 +72,7 @@ func TestConfig(t *testing.T) { c.So(config.GetServicePrefix(), c.ShouldEndWith, "/service") c.So(config.GetServiceNamePrefix(), c.ShouldEndWith, "/service_name") c.So(config.GetServiceTagsPrefix(), c.ShouldEndWith, "/tags") + t.Logf("service prefix: %s", config.GetServicePrefix()) c.So(config.GetServiceKey("test"), c.ShouldStartWith, config.GetServicePrefix()) c.So(config.GetServiceNameKey("test"), c.ShouldStartWith, config.GetServiceNamePrefix()) c.So(config.GetAppKeyPrefix(), c.ShouldNotBeEmpty) @@ -86,7 +87,7 @@ func TestConfig(t *testing.T) { c.So(config.GetAppPrefix(), c.ShouldNotBeEmpty) patch := gomonkey.ApplyFuncReturn((*viper.Viper).UnmarshalKey, fmt.Errorf("error")) defer patch.Reset() - ss, err = config.GetRPCPlugins() + ss, err := config.GetRPCPlugins() c.So(err, c.ShouldNotBeNil) c.So(ss, c.ShouldBeNil) cnf = conf.ReadConfig("dev") diff --git a/internal/pkg/constant.go b/internal/pkg/constant.go index e03783f..3b805c3 100644 --- a/internal/pkg/constant.go +++ b/internal/pkg/constant.go @@ -5,8 +5,6 @@ import ( "fmt" ) - - var ( ErrUserNotFound = errors.New("用户不存在") ErrUserDisabled = errors.New("用户已禁用") diff --git a/internal/pkg/constant_test.go b/internal/pkg/constant_test.go index 72957a1..bcb1b19 100644 --- a/internal/pkg/constant_test.go +++ b/internal/pkg/constant_test.go @@ -6,6 +6,7 @@ import ( "github.com/begonia-org/begonia/internal/pkg" c "github.com/smartystreets/goconvey/convey" ) + func TestConstant(t *testing.T) { t.Log("TestConstant") c.Convey("TestConstant", t, func() { diff --git a/internal/pkg/routers/routers.go b/internal/pkg/routers/routers.go index 35257ae..3e0d861 100644 --- a/internal/pkg/routers/routers.go +++ b/internal/pkg/routers/routers.go @@ -28,10 +28,11 @@ type APIMethodDetails struct { // 服务名 ServiceName string // 方法名 - HttpMethodName string - AuthRequired bool - RequestMethod string - GrpcFullRouter string + HttpMethodName string + AuthRequired bool + UseJsonResponse bool + RequestMethod string + GrpcFullRouter string } type HttpURIRouteToSrvMethod struct { routers map[string]*APIMethodDetails @@ -138,15 +139,16 @@ func (h *HttpURIRouteToSrvMethod) DeleteRouterDetails(fullMethod string, method uri, _ := h.getUri(method) h.deleteRoute(uri, fullMethod) } -func (r *HttpURIRouteToSrvMethod) addRouterDetails(serviceName string, authRequired bool, methodName *descriptorpb.MethodDescriptorProto) { +func (r *HttpURIRouteToSrvMethod) addRouterDetails(serviceName string, useJsonResponse, authRequired bool, methodName *descriptorpb.MethodDescriptorProto) { // 获取并打印 google.api.http 注解 if path, method := r.getUri(methodName); path != "" { r.AddRoute(path, &APIMethodDetails{ - ServiceName: serviceName, - HttpMethodName: string(methodName.GetName()), - AuthRequired: authRequired, - RequestMethod: method, - GrpcFullRouter: serviceName, + ServiceName: serviceName, + HttpMethodName: string(methodName.GetName()), + AuthRequired: authRequired, + RequestMethod: method, + GrpcFullRouter: serviceName, + UseJsonResponse: useJsonResponse, }) } @@ -158,14 +160,18 @@ func (r *HttpURIRouteToSrvMethod) LoadAllRouters(pd gateway.ProtobufDescription) for _, service := range fd.Service { authRequired := false + httpResponse := false // 获取并打印 pb.auth_reqiured 注解 if authRequiredExt := r.getServiceOptionByExt(service, common.E_AuthReqiured); authRequiredExt != nil { authRequired, _ = authRequiredExt.(bool) } + if httpResponseExt := r.getServiceOptionByExt(service, common.E_HttpResponse); httpResponseExt != nil { + httpResponse = true + } // 遍历服务中的所有方法 for _, method := range service.GetMethod() { key := fmt.Sprintf("/%s.%s/%s", fd.GetPackage(), service.GetName(), method.GetName()) - r.addRouterDetails(strings.ToUpper(key), authRequired, method) + r.addRouterDetails(strings.ToUpper(key), httpResponse, authRequired, method) } } diff --git a/internal/pkg/routers/routers_test.go b/internal/pkg/routers/routers_test.go index 8caa314..c07cd8d 100644 --- a/internal/pkg/routers/routers_test.go +++ b/internal/pkg/routers/routers_test.go @@ -27,9 +27,9 @@ func TestLoadAllRouters(t *testing.T) { d = R.GetRouteByGrpcMethod("/INTEGRATION.TESTSERVICE/GET") c.So(d, c.ShouldNotBeNil) - rs:=R.GetAllRoutes() + rs := R.GetAllRoutes() c.So(len(rs), c.ShouldBeGreaterThan, 0) - d,ok:=rs["/test/custom"] + d, ok := rs["/test/custom"] c.So(ok, c.ShouldBeTrue) c.So(d.ServiceName, c.ShouldEqual, "/INTEGRATION.TESTSERVICE/CUSTOM") diff --git a/internal/pkg/utils/utils_test.go b/internal/pkg/utils/utils_test.go index a50e0b0..8e08b3a 100644 --- a/internal/pkg/utils/utils_test.go +++ b/internal/pkg/utils/utils_test.go @@ -43,7 +43,7 @@ func TestLoadPublicKeyFromFile(t *testing.T) { } config := config.ReadConfig(env) cnf := cfg.NewConfig(config) - pub,err=utils.LoadPublicKeyFromFile(cnf.GetRSAPubKey()) + pub, err = utils.LoadPublicKeyFromFile(cnf.GetRSAPubKey()) c.So(err, c.ShouldBeNil) c.So(pub, c.ShouldNotBeNil) patch := gomonkey.ApplyFuncReturn(pem.Decode, nil, nil) diff --git a/internal/server/server.go b/internal/server/server.go index 4af9ba2..3192c43 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -10,8 +10,8 @@ import ( "strconv" "github.com/begonia-org/begonia/gateway" - "github.com/begonia-org/begonia/internal/pkg/config" "github.com/begonia-org/begonia/internal/middleware" + "github.com/begonia-org/begonia/internal/pkg/config" "github.com/begonia-org/begonia/internal/pkg/routers" "github.com/begonia-org/begonia/internal/service" loadbalance "github.com/begonia-org/go-loadbalancer" diff --git a/internal/service/app.go b/internal/service/app.go index fc81cb0..f8e34c7 100644 --- a/internal/service/app.go +++ b/internal/service/app.go @@ -66,7 +66,7 @@ func (app *AppService) Delete(ctx context.Context, in *api.DeleteAppRequest) (*a func (app *AppService) List(ctx context.Context, in *api.AppsListRequest) (*api.AppsListResponse, error) { apps, err := app.biz.List(ctx, in) if err != nil { - return nil, err + return nil, err } return &api.AppsListResponse{Apps: apps}, nil // return nil, nil diff --git a/internal/service/authz.go b/internal/service/authz.go index a692b51..4403aff 100644 --- a/internal/service/authz.go +++ b/internal/service/authz.go @@ -51,8 +51,6 @@ func (u *AuthzService) Logout(ctx context.Context, req *api.LogoutAPIRequest) (* } - - func (u *AuthzService) Desc() *grpc.ServiceDesc { return &api.AuthService_ServiceDesc } diff --git a/internal/service/authz_test.go b/internal/service/authz_test.go index cbcc778..6872780 100644 --- a/internal/service/authz_test.go +++ b/internal/service/authz_test.go @@ -13,9 +13,11 @@ import ( "runtime" "testing" + "github.com/agiledragon/gomonkey/v2" "github.com/begonia-org/begonia" "github.com/begonia-org/begonia/config" "github.com/begonia-org/begonia/gateway" + "github.com/begonia-org/begonia/internal/biz" "github.com/begonia-org/begonia/internal/service" sys "github.com/begonia-org/go-sdk/api/sys/v1" v1 "github.com/begonia-org/go-sdk/api/user/v1" @@ -98,6 +100,11 @@ func testLogout(t *testing.T) { t, func() { apiClient := client.NewAuthzAPI(apiAddr, accessKey, secret) + patch := gomonkey.ApplyFuncReturn((*biz.AuthzUsecase).Logout, fmt.Errorf("logout error")) + defer patch.Reset() + _, err := apiClient.Logout(context.Background(), xtoken) + patch.Reset() + c.So(err, c.ShouldNotBeNil) rsp, err := apiClient.Logout(context.Background(), xtoken) c.So(err, c.ShouldBeNil) c.So(rsp.StatusCode, c.ShouldEqual, common.Code_OK) diff --git a/internal/service/endpoints.go b/internal/service/endpoints.go index 3cfb34a..a0a5345 100644 --- a/internal/service/endpoints.go +++ b/internal/service/endpoints.go @@ -23,7 +23,6 @@ func NewEndpointsService(biz *endpoint.EndpointUsecase, log logger.Logger, confi return &EndpointsService{biz: biz, log: log, config: config} } - func (e *EndpointsService) Update(ctx context.Context, in *api.EndpointSrvUpdateRequest) (*api.UpdateEndpointResponse, error) { timestamp, err := e.biz.Patch(ctx, in) if err != nil { diff --git a/internal/service/file_test.go b/internal/service/file_test.go index 37803b5..506cbdd 100644 --- a/internal/service/file_test.go +++ b/internal/service/file_test.go @@ -145,8 +145,6 @@ func uploadParts(t *testing.T) { conf := cfg.NewConfig(config.ReadConfig(env)) filePath := filepath.Join(conf.GetUploadDir(), rsp.Uri) - // filename := filepath.Base(rsp.Uri) - // filePath := filepath.Join(saveDir, filename) file, err := os.Open(filePath) c.So(err, c.ShouldBeNil) @@ -246,6 +244,7 @@ func testRangeDownload(t *testing.T) { }) } + func testUploadErr(t *testing.T) { c.Convey("test upload file err", t, func() { env := "dev" @@ -290,14 +289,6 @@ func testDownloadErr(t *testing.T) { c.So(err, c.ShouldNotBeNil) c.So(err.Error(), c.ShouldContainSubstring, "test PathUnescape error") - // patch2 := gomonkey.ApplyFuncReturn(grpc.SendHeader, fmt.Errorf("test SendHeader error")) - // defer patch2.Reset() - // ctx = metadata.NewIncomingContext(context.Background(), metadata.Pairs("x-identity", sdkAPPID)) - // _, err = srv.Download(ctx, &api.DownloadRequest{Key: sdkAPPID + "/test/helloworld.pb"}) - // patch2.Reset() - // c.So(err, c.ShouldNotBeNil) - // c.So(err.Error(), c.ShouldContainSubstring, "test SendHeader error") - }) } func testRangeDownloadErr(t *testing.T) { @@ -308,10 +299,6 @@ func testRangeDownloadErr(t *testing.T) { } cnf := config.ReadConfig(env) srv := service.NewFileSvrForTest(cnf, gateway.Log) - // ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("app_id", sdkAPPID)) - // _, err := srv.DownloadForRange(ctx, &api.DownloadRequest{}) - // c.So(err, c.ShouldNotBeNil) - // c.So(err.Error(), c.ShouldContainSubstring, pkg.ErrIdentityMissing.Error()) cases := []struct { rangeStr string @@ -371,6 +358,26 @@ func testRangeDownloadErr(t *testing.T) { }) } + +func testAbortUpload(t *testing.T) { + c.Convey("test range download file", t, func() { + apiClient := client.NewFilesAPI(apiAddr, accessKey, secret) + _, err := apiClient.AbortUpload(context.Background(), "test/tmp.bindddasd") + c.So(err, c.ShouldNotBeNil) + // tmp, err := os.CreateTemp("", "testfile-*.txt") + // c.So(err, c.ShouldBeNil) + // defer tmp.Close() + // defer os.Remove(tmp.Name()) + // rsp, err := apiClient.RangeDownload(context.Background(), sdkAPPID+"/test/tmp.bin", "", -1, 128) + // c.So(err, c.ShouldBeNil) + // c.So(len(rsp), c.ShouldEqual, 129) + + // rsp, err = apiClient.RangeDownload(context.Background(), sdkAPPID+"/test/tmp.bin", "", 128, -1) + // c.So(err, c.ShouldBeNil) + // c.So(len(rsp), c.ShouldEqual, 1024*1024*2-128) + + }) +} func testDelErr(t *testing.T) { c.Convey("test delete file err", t, func() { env := "dev" @@ -415,6 +422,7 @@ func TestFile(t *testing.T) { t.Run("testDownloadErr", testDownloadErr) t.Run("uploadParts", uploadParts) t.Run("testRangeDownload", testRangeDownload) + t.Run("testAbortUpload", testAbortUpload) t.Run("testRangeDownloadErr", testRangeDownloadErr) t.Run("downloadParts", downloadParts) t.Run("deleteFile", deleteFile) diff --git a/internal/service/user_test.go b/internal/service/user_test.go index 5a1e59c..c53dabc 100644 --- a/internal/service/user_test.go +++ b/internal/service/user_test.go @@ -103,8 +103,8 @@ func testRegisterErr(t *testing.T) { }) } -func testUpdateErr(t *testing.T){ - c.Convey("test update user error",t,func(){ +func testUpdateErr(t *testing.T) { + c.Convey("test update user error", t, func() { env := "dev" if begonia.Env != "" { env = begonia.Env @@ -113,14 +113,14 @@ func testUpdateErr(t *testing.T){ srv := service.NewUserSvrForTest(cnf, gateway.Log) patch := gomonkey.ApplyFuncReturn((*biz.UserUsecase).Update, fmt.Errorf("test update user error")) defer patch.Reset() - _,err:=srv.Update(context.Background(),&api.PatchUserRequest{Uid: "",Owner: "test-user-01"}) - c.So(err,c.ShouldNotBeNil) - c.So(err.Error(),c.ShouldContainSubstring,"test update user error") + _, err := srv.Update(context.Background(), &api.PatchUserRequest{Uid: "", Owner: "test-user-01"}) + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "test update user error") patch.Reset() }) } -func testDelUserErr(t *testing.T){ - c.Convey("test delete user error",t,func(){ +func testDelUserErr(t *testing.T) { + c.Convey("test delete user error", t, func() { env := "dev" if begonia.Env != "" { env = begonia.Env @@ -129,9 +129,9 @@ func testDelUserErr(t *testing.T){ srv := service.NewUserSvrForTest(cnf, gateway.Log) patch := gomonkey.ApplyFuncReturn((*biz.UserUsecase).Delete, fmt.Errorf("test delete user error")) defer patch.Reset() - _,err:=srv.Delete(context.Background(),&api.DeleteUserRequest{Uid: ""}) - c.So(err,c.ShouldNotBeNil) - c.So(err.Error(),c.ShouldContainSubstring,"test delete user error") + _, err := srv.Delete(context.Background(), &api.DeleteUserRequest{Uid: ""}) + c.So(err, c.ShouldNotBeNil) + c.So(err.Error(), c.ShouldContainSubstring, "test delete user error") patch.Reset() }) } @@ -142,6 +142,6 @@ func TestUser(t *testing.T) { t.Run("patch user", patchUser) t.Run("delete user", deleteUser) t.Run("test register user error", testRegisterErr) - t.Run("test update user error",testUpdateErr) - t.Run("test delete user error",testDelUserErr) + t.Run("test update user error", testUpdateErr) + t.Run("test delete user error", testDelUserErr) } diff --git a/internal/service/wire.go b/internal/service/wire.go index aa06a9d..9b0b457 100644 --- a/internal/service/wire.go +++ b/internal/service/wire.go @@ -8,36 +8,33 @@ import ( "github.com/begonia-org/begonia/internal/data" "github.com/begonia-org/begonia/internal/pkg" - - "github.com/begonia-org/go-sdk/logger" app "github.com/begonia-org/go-sdk/api/app/v1" ep "github.com/begonia-org/go-sdk/api/endpoint/v1" file "github.com/begonia-org/go-sdk/api/file/v1" sys "github.com/begonia-org/go-sdk/api/sys/v1" user "github.com/begonia-org/go-sdk/api/user/v1" + "github.com/begonia-org/go-sdk/logger" "github.com/google/wire" "github.com/spark-lence/tiga" ) - - -func NewAuthzSvrForTest(config *tiga.Configuration, log logger.Logger)user.AuthServiceServer { +func NewAuthzSvrForTest(config *tiga.Configuration, log logger.Logger) user.AuthServiceServer { panic(wire.Build(biz.ProviderSet, pkg.ProviderSet, data.ProviderSet, NewAuthzService)) } -func NewAPPSvrForTest(config *tiga.Configuration, log logger.Logger)app.AppsServiceServer { +func NewAPPSvrForTest(config *tiga.Configuration, log logger.Logger) app.AppsServiceServer { panic(wire.Build(biz.ProviderSet, pkg.ProviderSet, data.ProviderSet, NewAppService)) } -func NewEndpointSvrForTest(config *tiga.Configuration, log logger.Logger)ep.EndpointServiceServer { +func NewEndpointSvrForTest(config *tiga.Configuration, log logger.Logger) ep.EndpointServiceServer { panic(wire.Build(biz.ProviderSet, pkg.ProviderSet, data.ProviderSet, NewEndpointsService)) } -func NewFileSvrForTest(config *tiga.Configuration, log logger.Logger)file.FileServiceServer { +func NewFileSvrForTest(config *tiga.Configuration, log logger.Logger) file.FileServiceServer { panic(wire.Build(biz.ProviderSet, pkg.ProviderSet, NewFileService)) } -func NewSysSvrForTest(config *tiga.Configuration, log logger.Logger)sys.SystemServiceServer { +func NewSysSvrForTest(config *tiga.Configuration, log logger.Logger) sys.SystemServiceServer { panic(wire.Build(NewSysService)) } -func NewUserSvrForTest(config *tiga.Configuration, log logger.Logger)user.UserServiceServer { +func NewUserSvrForTest(config *tiga.Configuration, log logger.Logger) user.UserServiceServer { panic(wire.Build(biz.ProviderSet, pkg.ProviderSet, data.ProviderSet, NewUserService)) -} \ No newline at end of file +} diff --git a/internal/wire.go b/internal/wire.go index 43e07f2..865f0b5 100644 --- a/internal/wire.go +++ b/internal/wire.go @@ -50,5 +50,5 @@ func NewFileSvr(config *tiga.Configuration, log logger.Logger) file.FileServiceS panic(wire.Build(biz.ProviderSet, pkg.ProviderSet, service.ProviderSet)) } func NewSysSvr(config *tiga.Configuration, log logger.Logger) sys.SystemServiceServer { - panic(wire.Build( service.ProviderSet)) + panic(wire.Build(service.ProviderSet)) } diff --git a/internal/wire_gen.go b/internal/wire_gen.go index c8572ca..26deeab 100644 --- a/internal/wire_gen.go +++ b/internal/wire_gen.go @@ -71,7 +71,7 @@ func New(config2 *tiga.Configuration, log logger.Logger, endpoint2 string) Gatew userServiceServer := service.NewUserService(userUsecase, log, configConfig) v := service.NewServices(fileServiceServer, authServiceServer, endpointServiceServer, appsServiceServer, systemServiceServer, userServiceServer) accessKeyAuth := biz.NewAccessKeyAuth(appRepo, configConfig, log) - pluginsApply := middleware.New(configConfig, redisDao, authzUsecase, log, accessKeyAuth, layeredCache) + pluginsApply := middleware.New(configConfig, redisDao, authzUsecase, log, accessKeyAuth) gatewayServer := server.NewGateway(gatewayConfig, configConfig, v, pluginsApply) gatewayWorker := NewGatewayWorkerImpl(daemonDaemon, gatewayServer) return gatewayWorker