Select Git revision
timestamp.go
storage.go 5.09 KiB
package extension
import (
"context"
"fmt"
"strings"
"git.perx.ru/perxis/perxis-go/pkg/collections"
"git.perx.ru/perxis/perxis-go/pkg/data"
"git.perx.ru/perxis/perxis-go/pkg/errors"
"git.perx.ru/perxis/perxis-go/pkg/setup"
pb "git.perx.ru/perxis/perxis-go/proto/extensions"
"go.uber.org/zap"
"git.perx.ru/perxis/perxis-go/pkg/content"
"git.perx.ru/perxis/perxis-go/pkg/items"
)
type (
Info = pb.ListExtensionsResponse_ExtensionInfo
)
// Storage описывает интерфейс хранилища состояний расширений
type Storage interface {
GetExtension(ctx context.Context, spaceID, envID string, extension string) (*Info, error)
FindExtensions(ctx context.Context, spaceID, envID string, extensions ...string) ([]*Info, error)
SetExtension(ctx context.Context, spaceID, envID string, extension string, status *Info) error
DeleteExtension(ctx context.Context, spaceID, envID string, extension string) error
}
type storage struct {
content *content.Content
logger *zap.Logger
}
func NewStorage(content *content.Content, logger *zap.Logger) Storage {
return &storage{content: content, logger: logger}
}
func infoFromItem(extension string, item *items.Item) *Info {
if item == nil {
return &Info{
Extension: extension,
State: StateNotInstalled,
}
}
d := item.Data
id, _ := d["id"].(string) // чтобы при получении списка расширений было возможно понять, что коллекция `space_extensions` еще не была мигрирована (v0.0.19)
title, _ := d["title"].(string)
state, _ := d["extension_state"].(int64)
ver, _ := d["version"].(string)
msg, _ := d["status_msg"].(string)
errmsg, _ := d["status_error"].(string)
return &Info{
Extension: id,
Title: title,
State: State(state),
Msg: msg,
Error: errmsg,
InstalledVersion: ver,
}
}
// GetExtension возвращает состояние расширения в пространстве
func (s *storage) GetExtension(ctx context.Context, spaceID, envID string, extension string) (*Info, error) {
res, err := s.content.Items.Get(ctx, spaceID, envID, ExtensionsCollectionID, extension)
if err != nil && !strings.Contains(err.Error(), "not found") {
return nil, err
}
return infoFromItem(extension, res), nil
}
// FindExtensions возвращает состояния расширений в пространстве
func (s *storage) FindExtensions(ctx context.Context, spaceID, envID string, extensions ...string) ([]*Info, error) {
var itemsFilter *items.Filter
if len(extensions) != 0 {
q := make([]interface{}, 0, len(extensions)+1)
for _, e := range extensions {
q = append(q, fmt.Sprintf("id contains '%s'", e))
}
}
itms, _, err := s.content.Items.Find(ctx, spaceID, envID, ExtensionsCollectionID, itemsFilter)
if err != nil && !strings.Contains(err.Error(), collections.ErrNotFound.Error()) {
return nil, err
}
res := make([]*Info, len(itms))
for i, item := range itms {
res[i] = infoFromItem(item.ID, item)
}
return res, nil
}
// SetExtension устанавливает состояние расширения в пространстве
func (s *storage) SetExtension(ctx context.Context, spaceID, envID string, extension string, status *Info) error {
if err := s.init(ctx, spaceID, envID); err != nil {
return errors.Wrap(err, "prepare collections")
}
item := &items.Item{
ID: extension,
SpaceID: spaceID,
EnvID: envID,
CollectionID: ExtensionsCollectionID,
Data: make(map[string]interface{}),
}
_ = data.Set("id", item.Data, extension) // item.Set устанавливает идентификатор записи
_ = item.Set("title", status.Title)
_ = item.Set("extension_state", float64(status.State))
_ = item.Set("version", status.InstalledVersion)
_ = item.Set("status_msg", status.Msg)
_ = item.Set("status_error", status.Error)
i, _ := s.content.Items.Get(ctx, spaceID, envID, ExtensionsCollectionID, extension)
if i == nil {
_, err := s.content.Items.Create(ctx, item)
return err
}
return s.content.Items.Update(ctx, item)
}
// DeleteExtension удаляет состояние расширения в пространстве (при удалении расширения)
func (s *storage) DeleteExtension(ctx context.Context, spaceID, envID string, extension string) error {
item := &items.Item{
ID: extension,
SpaceID: spaceID,
EnvID: envID,
CollectionID: ExtensionsCollectionID,
}
return s.content.Items.Delete(ctx, item)
}
func (s *storage) init(ctx context.Context, spaceID, envID string) error {
// миграция окружения не должна запуститься, поскольку окружение может быть сломано
// расширениями - нужно дать возможность восстановиться
stp := setup.NewSetup(s.content, spaceID, envID, s.logger).AddCollections([]*collections.Collection{
NewExtensionsCollection(spaceID, envID),
NewActionsCollection(spaceID, envID),
}, setup.SkipMigration())
return stp.Install(ctx)
}