Skip to content
Snippets Groups Projects
Commit 2a6642c8 authored by Pavel Antonov's avatar Pavel Antonov :asterisk:
Browse files

Обработка Action в расширениях

parent cdfe0757
Branches
Tags
No related merge requests found
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
}
}
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
}
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()")
})
}
......
......@@ -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{}
......
......@@ -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 {
......
......@@ -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")
if in.Extension == s.desc.Extension {
return true
}
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)
}
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")
}
return &extension.ActionResponse{}, nil
return nil, extension.ErrInvalidAction
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment