From 2a6642c8512a067c96050fed94afd75a6b38bb71 Mon Sep 17 00:00:00 2001 From: Pavel Antonov <antonov@perx.ru> Date: Mon, 9 Oct 2023 17:09:20 +0400 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=BA=D0=B0=20Action=20=D0=B2=20=D1=80=D0=B0=D1=81=D1=88=D0=B8?= =?UTF-8?q?=D1=80=D0=B5=D0=BD=D0=B8=D1=8F=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/extension/action_handler.go | 39 +++++++++++++++ .../action.go => extension/action_url.go} | 14 +++--- .../action_url_test.go} | 20 ++++---- pkg/extension/server.go | 26 ++++++---- pkg/extension/server_test.go | 8 ++-- pkg/extension/service/extension.go | 48 ++++++++++++------- 6 files changed, 109 insertions(+), 46 deletions(-) create mode 100644 pkg/extension/action_handler.go rename pkg/{action/action.go => extension/action_url.go} (68%) rename pkg/{action/action_test.go => extension/action_url_test.go} (90%) diff --git a/pkg/extension/action_handler.go b/pkg/extension/action_handler.go new file mode 100644 index 00000000..3079b885 --- /dev/null +++ b/pkg/extension/action_handler.go @@ -0,0 +1,39 @@ +package extension + +import ( + "context" + + "git.perx.ru/perxis/perxis-go/pkg/errors" +) + +var ( + ErrInvalidAction = errors.New("invalid action") +) + +// ActionHandler выполняет действие в url +type ActionHandler func(ctx context.Context, url *ActionURL, req *ActionRequest) (*ActionResponse, error) + +// ActionRouter возвращает ActionHandler для указанного действия +type ActionRouter func(ctx context.Context, url *ActionURL, req *ActionRequest) (ActionHandler, error) + +// Chain возвращает ActionRouter, который последовательно вызывает переданные ActionRouter +func Chain(chain ...ActionRouter) ActionRouter { + return func(ctx context.Context, url *ActionURL, req *ActionRequest) (ActionHandler, error) { + for _, f := range chain { + if h, err := f(ctx, url, req); err == nil && h != nil { + return h, nil + } + } + return nil, ErrInvalidAction + } +} + +// Named возвращает ActionRouter, который возвращает ActionHandler для указанного действия по имени +func Named(name string, handler ActionHandler) ActionRouter { + return func(ctx context.Context, url *ActionURL, req *ActionRequest) (ActionHandler, error) { + if url.Action() == name { + return handler, nil + } + return nil, ErrInvalidAction + } +} diff --git a/pkg/action/action.go b/pkg/extension/action_url.go similarity index 68% rename from pkg/action/action.go rename to pkg/extension/action_url.go index 4233d986..463ac68f 100644 --- a/pkg/action/action.go +++ b/pkg/extension/action_url.go @@ -1,4 +1,4 @@ -package action +package extension import ( "net/url" @@ -6,20 +6,20 @@ import ( ) // URL структура для хранения данных о переданном действии. -type URL struct { +type ActionURL struct { *url.URL } // NewURL возвращает структуру ActionURL -func NewURL(action string) (*URL, error) { +func NewActionURL(action string) (*ActionURL, error) { u, err := url.Parse(action) if err != nil { return nil, err } - return &URL{URL: u}, nil + return &ActionURL{URL: u}, nil } -func (u *URL) actionParts() (string, string) { +func (u *ActionURL) actionParts() (string, string) { if u.URL != nil && u.URL.Scheme == "grpc" { splitPath := strings.Split(strings.TrimLeft(u.Path, "/"), "/") if len(splitPath) >= 2 { @@ -29,12 +29,12 @@ func (u *URL) actionParts() (string, string) { return "", "" } -func (u *URL) Action() string { +func (u *ActionURL) Action() string { _, action := u.actionParts() return action } -func (u *URL) Extension() string { +func (u *ActionURL) Extension() string { ext, _ := u.actionParts() return ext } diff --git a/pkg/action/action_test.go b/pkg/extension/action_url_test.go similarity index 90% rename from pkg/action/action_test.go rename to pkg/extension/action_url_test.go index 2988744f..be9a924b 100644 --- a/pkg/action/action_test.go +++ b/pkg/extension/action_url_test.go @@ -1,4 +1,4 @@ -package action +package extension import ( "fmt" @@ -12,13 +12,13 @@ func TestActionURL_New(t *testing.T) { tests := []struct { name string action string - want *URL + want *ActionURL url string wantErr assert.ErrorAssertionFunc }{ { name: "Without action", - want: &URL{ + want: &ActionURL{ URL: &url.URL{}, }, wantErr: assert.NoError, @@ -26,7 +26,7 @@ func TestActionURL_New(t *testing.T) { { name: "Without deprecated action call", action: "build-site", - want: &URL{ + want: &ActionURL{ URL: &url.URL{ Path: "build-site", }, @@ -37,7 +37,7 @@ func TestActionURL_New(t *testing.T) { { name: "With grpc action", action: "grpc:///perxisweb/build-site", - want: &URL{ + want: &ActionURL{ URL: &url.URL{ Scheme: "grpc", Path: "/perxisweb/build-site", @@ -49,7 +49,7 @@ func TestActionURL_New(t *testing.T) { { name: "With ui action", action: "ui:///space/env/coll", - want: &URL{ + want: &ActionURL{ URL: &url.URL{ Scheme: "ui", Path: "/space/env/coll", @@ -61,7 +61,7 @@ func TestActionURL_New(t *testing.T) { { name: "With http action", action: "https://perx.ru", - want: &URL{ + want: &ActionURL{ URL: &url.URL{ Scheme: "https", Host: "perx.ru", @@ -79,7 +79,7 @@ func TestActionURL_New(t *testing.T) { { name: "With no action id", action: "grpc:///perxisweb", - want: &URL{ + want: &ActionURL{ URL: &url.URL{ Scheme: "grpc", Path: "/perxisweb", @@ -90,7 +90,7 @@ func TestActionURL_New(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := NewURL(tt.action) + got, err := NewActionURL(tt.action) if !tt.wantErr(t, err, fmt.Sprintf("NewURL(%v)", tt.action)) { return } @@ -128,7 +128,7 @@ func TestActionURL_String(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - p, _ := NewURL(tt.url) + p, _ := NewActionURL(tt.url) assert.Equalf(t, tt.url, p.String(), "String()") }) } diff --git a/pkg/extension/server.go b/pkg/extension/server.go index f9b603f5..467b4396 100644 --- a/pkg/extension/server.go +++ b/pkg/extension/server.go @@ -3,7 +3,6 @@ package extension import ( "context" - "git.perx.ru/perxis/perxis-go/pkg/action" "git.perx.ru/perxis/perxis-go/pkg/errors" pb "git.perx.ru/perxis/perxis-go/proto/extensions" ) @@ -80,25 +79,36 @@ func (srv *Server) Update(ctx context.Context, request *UpdateRequest) (*UpdateR return &UpdateResponse{Results: res}, nil } -func (srv *Server) Action(ctx context.Context, in *pb.ActionRequest) (*pb.ActionResponse, error) { - actionURL, err := action.NewURL(in.Action) +func (srv *Server) getExtensionService(ctx context.Context, in *pb.ActionRequest) (Extension, error) { + actionURL, err := NewActionURL(in.Action) + if err != nil { - return nil, err + return nil, ErrInvalidAction } + ext := actionURL.Extension() if ext == "" { ext = in.Extension } if ext == "" { - return nil, errors.New("extension ID required") + return nil, ErrInvalidAction } svc, ok := srv.services[ext] - if !ok { - return nil, ErrUnknownExtension + if ok { + return svc, nil + } + + return nil, ErrInvalidAction +} + +func (srv *Server) Action(ctx context.Context, in *pb.ActionRequest) (out *pb.ActionResponse, err error) { + svc, err := srv.getExtensionService(ctx, in) + if err != nil { + return nil, err } - out, err := svc.Action(ctx, in) + out, err = svc.Action(ctx, in) if out == nil { out = &ActionResponse{} diff --git a/pkg/extension/server_test.go b/pkg/extension/server_test.go index bee68b1a..64f10e98 100644 --- a/pkg/extension/server_test.go +++ b/pkg/extension/server_test.go @@ -142,7 +142,7 @@ func TestServer_Action(t *testing.T) { EnvId: "env", }, want: &ActionResponse{State: ResponseDone}, - wantErr: "extension ID required", + wantErr: "invalid action", }, { name: "Deprecated call", @@ -164,7 +164,7 @@ func TestServer_Action(t *testing.T) { EnvId: "env", }, want: nil, - wantErr: ErrUnknownExtension.Error(), + wantErr: "invalid action", }, { name: "Deprecated call, without extension", @@ -175,7 +175,7 @@ func TestServer_Action(t *testing.T) { EnvId: "env", }, want: nil, - wantErr: "extension ID required", + wantErr: "invalid action", }, { name: "Deprecated call, without action and extension)", @@ -185,7 +185,7 @@ func TestServer_Action(t *testing.T) { EnvId: "env", }, want: nil, - wantErr: "extension ID required", + wantErr: "invalid action", }, } for _, tt := range tests { diff --git a/pkg/extension/service/extension.go b/pkg/extension/service/extension.go index 6d9608ab..a92d1623 100644 --- a/pkg/extension/service/extension.go +++ b/pkg/extension/service/extension.go @@ -4,10 +4,8 @@ import ( "context" "fmt" - "git.perx.ru/perxis/perxis-go/pkg/action" "git.perx.ru/perxis/perxis-go/pkg/clients" "git.perx.ru/perxis/perxis-go/pkg/content" - "git.perx.ru/perxis/perxis-go/pkg/errors" "git.perx.ru/perxis/perxis-go/pkg/extension" "git.perx.ru/perxis/perxis-go/pkg/roles" "git.perx.ru/perxis/perxis-go/pkg/setup" @@ -32,6 +30,7 @@ type Extension struct { Content *content.Content Logger *zap.Logger manager extension.Manager + router extension.ActionRouter withClient bool role *roles.Role @@ -155,25 +154,40 @@ func (s *Extension) Uninstall(ctx context.Context, in *extension.UninstallReques return s.GetSetup(in.SpaceId, in.EnvId).WithForce(in.Force).WithRemove(in.Remove).Uninstall(ctx) } -func (s *Extension) Action(ctx context.Context, in *extension.ActionRequest) (*extension.ActionResponse, error) { - actionURL, err := action.NewURL(in.Action) - if err != nil { - return nil, err - } - ext := actionURL.Extension() +// isCorrectExtension проверяет что расширение в url совпадает с расширением расширения +func (s *Extension) isCorrectExtension(ctx context.Context, url *extension.ActionURL, in *extension.ActionRequest) bool { + ext := url.Extension() if ext == "" { ext = in.Extension } - if ext == "" { - return nil, errors.New("extension ID required") - } - ok, err := extension.CheckInstalled(ctx, s.Content, in.SpaceId, in.EnvId, ext) - if err != nil { - return nil, errors.Wrap(err, "check extension installed") + + if in.Extension == s.desc.Extension { + return true } - if !ok { - return nil, errors.New("extension not installed") + return false +} + +func (s *Extension) Action(ctx context.Context, in *extension.ActionRequest) (*extension.ActionResponse, error) { + // TBD: нужно ли проверять что действие установлено в пространство + // мы так и не договорились, но проверка появилась + // пусть решает каждое расширение само + // + //ok, err := extension.CheckInstalled(ctx, s.Content, in.SpaceId, in.EnvId, ext) + //if err != nil { + // return nil, errors.Wrap(err, "check extension installed") + //} + //if !ok { + // return nil, errors.New("extension not installed") + //} + + if s.router == nil { + url, err := extension.NewActionURL(in.Action) + if err == nil && url != nil && s.isCorrectExtension(ctx, url, in) { + if h, err := s.router(ctx, url, in); err == nil && h != nil { + return h(ctx, url, in) + } + } } - return &extension.ActionResponse{}, nil + return nil, extension.ErrInvalidAction } -- GitLab