2024-01-02 09:54:11 +00:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
2024-03-15 07:21:43 +00:00
|
|
|
"golang.org/x/sync/errgroup"
|
2024-01-02 09:54:11 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type VillageRepository interface {
|
|
|
|
CreateOrUpdate(ctx context.Context, params ...domain.CreateVillageParams) error
|
2024-03-05 06:14:41 +00:00
|
|
|
List(ctx context.Context, params domain.ListVillagesParams) (domain.ListVillagesResult, error)
|
2024-03-06 06:35:26 +00:00
|
|
|
ListWithRelations(
|
|
|
|
ctx context.Context,
|
|
|
|
params domain.ListVillagesParams,
|
|
|
|
) (domain.ListVillagesWithRelationsResult, error)
|
2024-01-02 09:54:11 +00:00
|
|
|
Delete(ctx context.Context, serverKey string, ids ...int) error
|
|
|
|
}
|
|
|
|
|
|
|
|
type VillageService struct {
|
|
|
|
repo VillageRepository
|
|
|
|
twSvc TWService
|
2024-01-02 10:47:02 +00:00
|
|
|
pub VillagePublisher
|
2024-01-02 09:54:11 +00:00
|
|
|
}
|
|
|
|
|
2024-01-02 10:47:02 +00:00
|
|
|
func NewVillageService(repo VillageRepository, twSvc TWService, pub VillagePublisher) *VillageService {
|
|
|
|
return &VillageService{repo: repo, twSvc: twSvc, pub: pub}
|
2024-01-02 09:54:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (svc *VillageService) Sync(ctx context.Context, serverSyncedPayload domain.ServerSyncedEventPayload) error {
|
|
|
|
serverKey := serverSyncedPayload.Key()
|
|
|
|
serverURL := serverSyncedPayload.URL()
|
|
|
|
|
|
|
|
villages, err := svc.twSvc.GetVillages(ctx, serverURL)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("%s: couldn't get villages: %w", serverKey, err)
|
|
|
|
}
|
|
|
|
|
2024-03-15 07:21:43 +00:00
|
|
|
g, ctx := errgroup.WithContext(ctx)
|
|
|
|
|
|
|
|
g.Go(func() error {
|
|
|
|
if createOrUpdateErr := svc.createOrUpdate(ctx, serverKey, villages); createOrUpdateErr != nil {
|
|
|
|
return fmt.Errorf("couldn't create/update villages: %w", createOrUpdateErr)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
2024-01-02 09:54:11 +00:00
|
|
|
|
2024-03-15 07:21:43 +00:00
|
|
|
g.Go(func() error {
|
|
|
|
if deleteErr := svc.delete(ctx, serverKey, villages); deleteErr != nil {
|
|
|
|
return fmt.Errorf("couldn't delete villages: %w", deleteErr)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
if err = g.Wait(); err != nil {
|
|
|
|
return fmt.Errorf("%s: %w", serverKey, err)
|
2024-01-02 09:54:11 +00:00
|
|
|
}
|
|
|
|
|
2024-01-02 10:47:02 +00:00
|
|
|
villagesSyncedPayload, err := domain.NewVillagesSyncedEventPayloadFromVillages(
|
|
|
|
serverKey,
|
|
|
|
serverURL,
|
|
|
|
serverSyncedPayload.VersionCode(),
|
|
|
|
villages,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("%s: couldn't construct domain.PlayersSyncedEventPayload: %w", serverKey, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err = svc.pub.EventSynced(ctx, villagesSyncedPayload); err != nil {
|
|
|
|
return fmt.Errorf("%s: %w", serverKey, err)
|
|
|
|
}
|
|
|
|
|
2024-01-02 09:54:11 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
const villageCreateOrUpdateChunkSize = domain.VillageListMaxLimit
|
|
|
|
|
|
|
|
func (svc *VillageService) createOrUpdate(ctx context.Context, serverKey string, villages domain.BaseVillages) error {
|
|
|
|
for i := 0; i < len(villages); i += villageCreateOrUpdateChunkSize {
|
|
|
|
end := i + villageCreateOrUpdateChunkSize
|
|
|
|
if end > len(villages) {
|
|
|
|
end = len(villages)
|
|
|
|
}
|
|
|
|
|
2024-01-04 10:44:36 +00:00
|
|
|
createParams, err := domain.NewCreateVillageParams(serverKey, villages[i:end])
|
|
|
|
if err != nil {
|
2024-01-02 09:54:11 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-01-04 10:44:36 +00:00
|
|
|
if err = svc.repo.CreateOrUpdate(ctx, createParams...); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-01-02 09:54:11 +00:00
|
|
|
}
|
|
|
|
|
2024-01-04 10:44:36 +00:00
|
|
|
return nil
|
2024-01-02 09:54:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (svc *VillageService) delete(ctx context.Context, serverKey string, villages domain.BaseVillages) error {
|
|
|
|
listParams := domain.NewListVillagesParams()
|
|
|
|
if err := listParams.SetServerKeys([]string{serverKey}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := listParams.SetSort([]domain.VillageSort{domain.VillageSortIDASC}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := listParams.SetLimit(domain.VillageListMaxLimit); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var toDelete []int
|
|
|
|
|
|
|
|
for {
|
2024-03-05 06:14:41 +00:00
|
|
|
res, err := svc.repo.List(ctx, listParams)
|
2024-01-02 09:54:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2024-03-05 06:14:41 +00:00
|
|
|
toDelete = append(toDelete, res.Villages().Delete(serverKey, villages)...)
|
|
|
|
|
|
|
|
if res.Next().IsZero() {
|
2024-01-02 09:54:11 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2024-03-05 06:14:41 +00:00
|
|
|
if err = listParams.SetCursor(res.Next()); err != nil {
|
2024-01-02 09:54:11 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return svc.repo.Delete(ctx, serverKey, toDelete...)
|
|
|
|
}
|
2024-03-05 06:14:41 +00:00
|
|
|
|
|
|
|
func (svc *VillageService) List(
|
|
|
|
ctx context.Context,
|
|
|
|
params domain.ListVillagesParams,
|
|
|
|
) (domain.ListVillagesResult, error) {
|
|
|
|
return svc.repo.List(ctx, params)
|
|
|
|
}
|
2024-03-06 06:35:26 +00:00
|
|
|
|
|
|
|
func (svc *VillageService) ListWithRelations(
|
|
|
|
ctx context.Context,
|
|
|
|
params domain.ListVillagesParams,
|
|
|
|
) (domain.ListVillagesWithRelationsResult, error) {
|
|
|
|
return svc.repo.ListWithRelations(ctx, params)
|
|
|
|
}
|
2024-03-07 05:52:03 +00:00
|
|
|
|
|
|
|
func (svc *VillageService) GetWithRelations(
|
|
|
|
ctx context.Context,
|
|
|
|
id int,
|
|
|
|
serverKey string,
|
|
|
|
) (domain.VillageWithRelations, error) {
|
|
|
|
params := domain.NewListVillagesParams()
|
|
|
|
if err := params.SetIDs([]int{id}); err != nil {
|
|
|
|
return domain.VillageWithRelations{}, err
|
|
|
|
}
|
|
|
|
if err := params.SetServerKeys([]string{serverKey}); err != nil {
|
|
|
|
return domain.VillageWithRelations{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
res, err := svc.repo.ListWithRelations(ctx, params)
|
|
|
|
if err != nil {
|
|
|
|
return domain.VillageWithRelations{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
villages := res.Villages()
|
|
|
|
if len(villages) == 0 {
|
|
|
|
return domain.VillageWithRelations{}, domain.VillageNotFoundError{
|
|
|
|
ID: id,
|
|
|
|
ServerKey: serverKey,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return villages[0], nil
|
|
|
|
}
|