2023-12-27 08:07:40 +00:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
|
|
|
)
|
|
|
|
|
2023-12-28 10:56:59 +00:00
|
|
|
type TribeRepository interface {
|
|
|
|
CreateOrUpdate(ctx context.Context, params ...domain.CreateTribeParams) error
|
|
|
|
List(ctx context.Context, params domain.ListTribesParams) (domain.Tribes, error)
|
2024-01-01 10:20:30 +00:00
|
|
|
// Delete marks players with the given serverKey and ids as deleted (sets deleted at to now).
|
|
|
|
//
|
|
|
|
// https://en.wiktionary.org/wiki/soft_deletion
|
2023-12-28 10:56:59 +00:00
|
|
|
Delete(ctx context.Context, serverKey string, ids ...int) error
|
|
|
|
}
|
|
|
|
|
2023-12-27 08:07:40 +00:00
|
|
|
type TribeService struct {
|
2023-12-28 10:56:59 +00:00
|
|
|
repo TribeRepository
|
2023-12-27 08:07:40 +00:00
|
|
|
twSvc TWService
|
2023-12-30 08:38:32 +00:00
|
|
|
pub TribePublisher
|
2023-12-27 08:07:40 +00:00
|
|
|
}
|
|
|
|
|
2023-12-30 08:38:32 +00:00
|
|
|
func NewTribeService(repo TribeRepository, twSvc TWService, pub TribePublisher) *TribeService {
|
|
|
|
return &TribeService{repo: repo, twSvc: twSvc, pub: pub}
|
2023-12-27 08:07:40 +00:00
|
|
|
}
|
|
|
|
|
2023-12-30 08:38:32 +00:00
|
|
|
func (svc *TribeService) Sync(ctx context.Context, serverSyncedPayload domain.ServerSyncedEventPayload) error {
|
|
|
|
serverKey := serverSyncedPayload.Key()
|
|
|
|
serverURL := serverSyncedPayload.URL()
|
2023-12-29 08:23:05 +00:00
|
|
|
|
2023-12-30 08:38:32 +00:00
|
|
|
tribes, err := svc.twSvc.GetTribes(ctx, serverURL)
|
2023-12-27 08:07:40 +00:00
|
|
|
if err != nil {
|
2023-12-29 08:23:05 +00:00
|
|
|
return fmt.Errorf("%s: couldn't get tribes: %w", serverKey, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = svc.createOrUpdate(ctx, serverKey, tribes); err != nil {
|
|
|
|
return fmt.Errorf("%s: couldn't create/update tribes: %w", serverKey, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = svc.delete(ctx, serverKey, tribes); err != nil {
|
|
|
|
return fmt.Errorf("%s: couldn't delete tribes: %w", serverKey, err)
|
2023-12-27 08:07:40 +00:00
|
|
|
}
|
|
|
|
|
2023-12-30 08:38:32 +00:00
|
|
|
tribesSyncedPayload, err := domain.NewTribesSyncedEventPayload(
|
|
|
|
serverKey,
|
|
|
|
serverURL,
|
|
|
|
serverSyncedPayload.VersionCode(),
|
|
|
|
len(tribes),
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("%s: couldn't construct domain.TribesSyncedEventPayload: %w", serverKey, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = svc.pub.EventSynced(ctx, tribesSyncedPayload); err != nil {
|
|
|
|
return fmt.Errorf("%s: %w", serverKey, err)
|
|
|
|
}
|
|
|
|
|
2023-12-29 08:23:05 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
const tribeCreateOrUpdateChunkSize = domain.TribeListMaxLimit
|
|
|
|
|
|
|
|
func (svc *TribeService) createOrUpdate(ctx context.Context, serverKey string, tribes domain.BaseTribes) error {
|
|
|
|
for i := 0; i < len(tribes); i += tribeCreateOrUpdateChunkSize {
|
|
|
|
end := i + tribeCreateOrUpdateChunkSize
|
|
|
|
if end > len(tribes) {
|
|
|
|
end = len(tribes)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := svc.createOrUpdateChunk(ctx, serverKey, tribes[i:end]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2023-12-27 08:07:40 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2023-12-29 08:23:05 +00:00
|
|
|
|
|
|
|
func (svc *TribeService) createOrUpdateChunk(ctx context.Context, serverKey string, tribes domain.BaseTribes) error {
|
|
|
|
ids := make([]int, 0, len(tribes))
|
|
|
|
for _, t := range tribes {
|
|
|
|
ids = append(ids, t.ID())
|
|
|
|
}
|
|
|
|
|
|
|
|
listParams := domain.NewListTribesParams()
|
|
|
|
if err := listParams.SetServerKeys([]string{serverKey}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := listParams.SetIDs(ids); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := listParams.SetSort([]domain.TribeSort{domain.TribeSortIDASC}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := listParams.SetLimit(domain.TribeListMaxLimit); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
storedTribes, err := svc.repo.List(ctx, listParams)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
createParams, err := domain.NewCreateTribeParams(serverKey, tribes, storedTribes)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return svc.repo.CreateOrUpdate(ctx, createParams...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (svc *TribeService) delete(ctx context.Context, serverKey string, tribes domain.BaseTribes) error {
|
|
|
|
listParams := domain.NewListTribesParams()
|
|
|
|
if err := listParams.SetServerKeys([]string{serverKey}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := listParams.SetDeleted(domain.NullBool{
|
|
|
|
Value: false,
|
|
|
|
Valid: true,
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := listParams.SetSort([]domain.TribeSort{domain.TribeSortIDASC}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := listParams.SetLimit(domain.TribeListMaxLimit); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var toDelete []int
|
|
|
|
|
|
|
|
for {
|
|
|
|
storedTribes, err := svc.repo.List(ctx, listParams)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(storedTribes) == 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
toDelete = append(toDelete, storedTribes.Delete(tribes)...)
|
|
|
|
|
|
|
|
if err = listParams.SetIDGT(domain.NullInt{
|
|
|
|
Value: storedTribes[len(storedTribes)-1].ID(),
|
|
|
|
Valid: true,
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return svc.repo.Delete(ctx, serverKey, toDelete...)
|
|
|
|
}
|