core/internal/app/service_ennoblement.go

139 lines
3.6 KiB
Go

package app
import (
"context"
"errors"
"fmt"
"time"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
)
type EnnoblementRepository interface {
Create(ctx context.Context, params ...domain.CreateEnnoblementParams) error
List(ctx context.Context, params domain.ListEnnoblementsParams) (domain.ListEnnoblementsResult, error)
ListWithRelations(
ctx context.Context,
params domain.ListEnnoblementsParams,
) (domain.ListEnnoblementsWithRelationsResult, error)
}
type EnnoblementService struct {
repo EnnoblementRepository
twSvc TWService
pub EnnoblementPublisher
}
func NewEnnoblementService(repo EnnoblementRepository, twSvc TWService, pub EnnoblementPublisher) *EnnoblementService {
return &EnnoblementService{repo: repo, twSvc: twSvc, pub: pub}
}
func (svc *EnnoblementService) Sync(
ctx context.Context,
syncEnnoblementsCmdPayload domain.SyncEnnoblementsCmdPayload,
) error {
serverURL := syncEnnoblementsCmdPayload.ServerURL()
serverKey := syncEnnoblementsCmdPayload.ServerKey()
latestEnnoblement, err := svc.getLatest(ctx, serverKey)
if err != nil && !errors.Is(err, errEnnoblementNotFound) {
return fmt.Errorf("%s: %w", serverKey, err)
}
var since time.Time
if err == nil {
since = latestEnnoblement.CreatedAt()
}
ennoblements, err := svc.twSvc.GetEnnoblements(ctx, serverURL, since)
if err != nil {
return fmt.Errorf("%s: couldn't get ennoblements: %w", serverKey, err)
}
if err = svc.create(ctx, serverKey, ennoblements); err != nil {
return fmt.Errorf("%s: couldn't create ennoblements: %w", serverKey, err)
}
payload, err := domain.NewEnnoblementsSyncedEventPayload(
serverKey,
serverURL,
syncEnnoblementsCmdPayload.VersionCode(),
)
if err != nil {
return fmt.Errorf("%s: couldn't construct domain.EnnoblementsSyncedEventPayload %w", serverKey, err)
}
if err = svc.pub.EventSynced(ctx, payload); err != nil {
return fmt.Errorf("%s: %w", serverKey, err)
}
return nil
}
var errEnnoblementNotFound = errors.New("ennoblement not found")
func (svc *EnnoblementService) getLatest(ctx context.Context, serverKey string) (domain.Ennoblement, error) {
params := domain.NewListEnnoblementsParams()
if err := params.SetLimit(1); err != nil {
return domain.Ennoblement{}, err
}
if err := params.SetServerKeys([]string{serverKey}); err != nil {
return domain.Ennoblement{}, err
}
if err := params.SetSort([]domain.EnnoblementSort{domain.EnnoblementSortCreatedAtDESC}); err != nil {
return domain.Ennoblement{}, err
}
res, err := svc.repo.List(ctx, params)
if err != nil {
return domain.Ennoblement{}, err
}
ennoblements := res.Ennoblements()
if len(ennoblements) == 0 {
return domain.Ennoblement{}, errEnnoblementNotFound
}
return ennoblements[0], nil
}
const ennoblementCreateChunkSize = 500
func (svc *EnnoblementService) create(
ctx context.Context,
serverKey string,
ennoblements domain.BaseEnnoblements,
) error {
for i := 0; i < len(ennoblements); i += ennoblementCreateChunkSize {
end := i + ennoblementCreateChunkSize
if end > len(ennoblements) {
end = len(ennoblements)
}
createParams, err := domain.NewCreateEnnoblementParams(serverKey, ennoblements[i:end])
if err != nil {
return err
}
if err = svc.repo.Create(ctx, createParams...); err != nil {
return err
}
}
return nil
}
func (svc *EnnoblementService) List(
ctx context.Context,
params domain.ListEnnoblementsParams,
) (domain.ListEnnoblementsResult, error) {
return svc.repo.List(ctx, params)
}
func (svc *EnnoblementService) ListWithRelations(
ctx context.Context,
params domain.ListEnnoblementsParams,
) (domain.ListEnnoblementsWithRelationsResult, error) {
return svc.repo.ListWithRelations(ctx, params)
}