package extension
import (
"context"
"strings"
"git.perx.ru/perxis/perxis-go/pkg/action"
"git.perx.ru/perxis/perxis-go/pkg/errors"
"git.perx.ru/perxis/perxis-go/pkg/operation"
pb "git.perx.ru/perxis/perxis-go/proto/extensions"
"google.golang.org/protobuf/proto"
)
type Server struct {
extensions map[string]Extension
operations operation.Service
pb.UnimplementedExtensionServiceServer
}
func NewServer(operation operation.Service, extensions ...Extension) *Server {
srv := &Server{
extensions: make(map[string]Extension, len(extensions)),
// todo: нужно как-то неявно создавать и регистрировать сервер операций
operations: operation,
}
for _, s := range extensions {
srv.extensions[s.GetDescriptor().Extension] = s
}
return srv
}
func (s *Server) getExtensions(_ context.Context, extensions []string) ([]Extension, error) {
var res []Extension
for _, ext := range extensions {
e, ok := s.extensions[ext]
if !ok {
return nil, errors.Wrap(ErrUnknownExtension, ext)
}
res = append(res, e)
}
return res, nil
}
func (s *Server) Install(ctx context.Context, req *InstallRequest) (*operation.Proto, error) {
exts, err := s.getExtensions(ctx, req.Extensions)
if err != nil {
return nil, err
}
desc := "Install extensions " + strings.Join(req.Extensions, ", ")
op, err := s.operations.Create(ctx, desc,
func(ctx context.Context) (proto.Message, error) {
for _, ext := range exts {
if err := ext.Install(ctx, req); err != nil {
return nil, errors.Wrap(err, ext.GetDescriptor().Extension)
}
}
return nil, nil
})
return op.Proto(), err
}
func (s *Server) Uninstall(ctx context.Context, req *UninstallRequest) (*operation.Proto, error) {
exts, err := s.getExtensions(ctx, req.Extensions)
if err != nil {
return nil, err
}
desc := "Uninstall extensions " + strings.Join(req.Extensions, ", ")
op, err := s.operations.Create(ctx, desc,
func(ctx context.Context) (proto.Message, error) {
for _, ext := range exts {
if err := ext.Uninstall(ctx, req); err != nil {
return nil, errors.Wrap(err, ext.GetDescriptor().Extension)
}
}
return nil, nil
})
return op.Proto(), err
}
func (s *Server) Check(ctx context.Context, req *CheckRequest) (*operation.Proto, error) {
exts, err := s.getExtensions(ctx, req.Extensions)
if err != nil {
return nil, err
}
desc := "Check extensions " + strings.Join(req.Extensions, ", ")
op, err := s.operations.Create(ctx, desc,
func(ctx context.Context) (proto.Message, error) {
for _, ext := range exts {
if err := ext.Check(ctx, req); err != nil {
return nil, errors.Wrap(err, ext.GetDescriptor().Extension)
}
}
return nil, nil
})
return op.Proto(), err
}
func (s *Server) Action(ctx context.Context, in *pb.ActionRequest) (*pb.ActionResponse, error) {
actionURL, err := action.NewURL(in.Action)
if err != nil {
return nil, err
}
ext := actionURL.Extension()
if ext == "" {
ext = in.Extension
}
if ext == "" {
return nil, errors.New("extension ID required")
}
svc, ok := s.extensions[in.Extension]
if !ok {
return nil, ErrUnknownExtension
}
out, err := svc.Action(ctx, in)
if out == nil {
out = &ActionResponse{}
}
if err != nil {
out.State = ResponseError
out.Error = err.Error()
out.Msg += errors.GetDetail(err)
}
return out, nil
}
func (s *Server) Start() error {
var errs []error
for _, svc := range s.extensions {
if r, ok := svc.(Runnable); ok {
if err := r.Start(); err != nil {
errs = append(errs, err)
}
}
}
if len(errs) > 0 {
return errors.WithErrors(ErrStart, errs...)
}
return nil
}
func (s *Server) Stop() error {
var errs []error
for _, svc := range s.extensions {
if r, ok := svc.(Runnable); ok {
if err := r.Stop(); err != nil {
errs = append(errs, err)
}
}
}
if len(errs) > 0 {
return errors.WithErrors(ErrStop, errs...)
}
return nil
}
// --------------
// Попытки сделать один сервер для расширений и для менеджера
// --------------
type ExtensionsGetter interface {
GetInstalledExtensions(ctx context.Context, extensions ...string) ([]Extension, error)
}
func NewMultiExtensionsGetter(svc ...Extension) ExtensionsGetter {
g := &multiExtensionsGetter{
extensions: make(map[string]Extension, len(svc)),
}
for _, s := range svc {
g.extensions[s.GetDescriptor().Extension] = s
}
return g
}
type multiExtensionsGetter struct {
extensions map[string]Extension
}
func (g *multiExtensionsGetter) GetInstalledExtensions(_ context.Context, extensions ...string) ([]Extension, error) {
var res []Extension
if len(extensions) == 0 {
for _, e := range g.extensions {
res = append(res, e)
}
return res, nil
}
for _, ext := range extensions {
e, ok := g.extensions[ext]
if !ok {
return nil, errors.Wrap(ErrUnknownExtension, ext)
}
res = append(res, e)
}
return res, nil
}
func NewMonoExtensionsGetter(svc Extension) ExtensionsGetter {
return &monoExtensionsGetter{extension: svc}
}
type monoExtensionsGetter struct {
extension Extension
}
func (g *monoExtensionsGetter) GetInstalledExtensions(_ context.Context, _ ...string) ([]Extension, error) {
return []Extension{g.extension}, nil
}