parent
9668c23cc8
commit
ff2e578d0d
|
@ -28,38 +28,38 @@ func (svc *ServerService) Sync(ctx context.Context, payload domain.SyncServersCm
|
||||||
|
|
||||||
openServers, err := svc.twSvc.GetOpenServers(ctx, payload.URL())
|
openServers, err := svc.twSvc.GetOpenServers(ctx, payload.URL())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("couldn't get open servers for version code %s: %w", versionCode, err)
|
return fmt.Errorf("%s: couldn't get open servers: %w", versionCode, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
specialServers, err := svc.listAllSpecial(ctx, versionCode)
|
specialServers, err := svc.listAllSpecial(ctx, versionCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("couldn't list special servers with version code %s: %w", versionCode, err)
|
return fmt.Errorf("%s: couldn't list special servers: %w", versionCode, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentlyStoredOpenServers, err := svc.listAllOpen(ctx, versionCode)
|
currentlyStoredOpenServers, err := svc.listAllOpen(ctx, versionCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("couldn't list open servers with version code %s: %w", versionCode, err)
|
return fmt.Errorf("%s: couldn't list open servers: %w", versionCode, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
openServersWithoutSpecial := openServers.FilterOutSpecial(specialServers)
|
openServersWithoutSpecial := openServers.FilterOutSpecial(specialServers)
|
||||||
|
|
||||||
serversToBeClosed, err := currentlyStoredOpenServers.Close(openServersWithoutSpecial)
|
serversToBeClosed, err := currentlyStoredOpenServers.Close(openServersWithoutSpecial)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("couldn't close servers: %w", err)
|
return fmt.Errorf("%s: couldn't close servers: %w", versionCode, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
params, err := domain.NewCreateServerParams(append(openServersWithoutSpecial, serversToBeClosed...), versionCode)
|
params, err := domain.NewCreateServerParams(append(openServersWithoutSpecial, serversToBeClosed...), versionCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("%s: %w", versionCode, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = svc.repo.CreateOrUpdate(ctx, params...); err != nil {
|
if err = svc.repo.CreateOrUpdate(ctx, params...); err != nil {
|
||||||
return err
|
return fmt.Errorf("%s: couldn't create/update servers: %w", versionCode, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
payloads, err := domain.NewServerSyncedEventPayloads(openServersWithoutSpecial, versionCode)
|
payloads, err := domain.NewServerSyncedEventPayloads(openServersWithoutSpecial, versionCode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("couldn't construct server synced event payloads: %w", err)
|
return fmt.Errorf("%s: couldn't construct server synced event payloads: %w", versionCode, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return svc.publisher.EventSynced(ctx, payloads...)
|
return svc.publisher.EventSynced(ctx, payloads...)
|
||||||
|
@ -67,11 +67,12 @@ func (svc *ServerService) Sync(ctx context.Context, payload domain.SyncServersCm
|
||||||
|
|
||||||
func (svc *ServerService) listAllSpecial(ctx context.Context, versionCode string) (domain.Servers, error) {
|
func (svc *ServerService) listAllSpecial(ctx context.Context, versionCode string) (domain.Servers, error) {
|
||||||
params := domain.NewListServersParams()
|
params := domain.NewListServersParams()
|
||||||
|
|
||||||
if err := params.SetVersionCodes([]string{versionCode}); err != nil {
|
if err := params.SetVersionCodes([]string{versionCode}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err := params.SetSort([]domain.ServerSort{domain.ServerSortKeyASC}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if err := params.SetSpecial(domain.NullBool{
|
if err := params.SetSpecial(domain.NullBool{
|
||||||
Value: true,
|
Value: true,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
|
@ -84,11 +85,12 @@ func (svc *ServerService) listAllSpecial(ctx context.Context, versionCode string
|
||||||
|
|
||||||
func (svc *ServerService) listAllOpen(ctx context.Context, versionCode string) (domain.Servers, error) {
|
func (svc *ServerService) listAllOpen(ctx context.Context, versionCode string) (domain.Servers, error) {
|
||||||
params := domain.NewListServersParams()
|
params := domain.NewListServersParams()
|
||||||
|
|
||||||
if err := params.SetVersionCodes([]string{versionCode}); err != nil {
|
if err := params.SetVersionCodes([]string{versionCode}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err := params.SetSort([]domain.ServerSort{domain.ServerSortKeyASC}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if err := params.SetOpen(domain.NullBool{
|
if err := params.SetOpen(domain.NullBool{
|
||||||
Value: true,
|
Value: true,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
|
@ -105,11 +107,9 @@ func (svc *ServerService) ListAll(ctx context.Context, params domain.ListServers
|
||||||
if err := params.SetOffset(0); err != nil {
|
if err := params.SetOffset(0); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := params.SetLimit(domain.ServerListMaxLimit); err != nil {
|
if err := params.SetLimit(domain.ServerListMaxLimit); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := params.SetSort([]domain.ServerSort{domain.ServerSortKeyASC}); err != nil {
|
if err := params.SetSort([]domain.ServerSort{domain.ServerSortKeyASC}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -156,21 +156,18 @@ func (svc *ServerService) SyncConfigAndInfo(ctx context.Context, payload domain.
|
||||||
}
|
}
|
||||||
|
|
||||||
var updateParams domain.UpdateServerParams
|
var updateParams domain.UpdateServerParams
|
||||||
|
|
||||||
if err = updateParams.SetConfig(domain.NullServerConfig{
|
if err = updateParams.SetConfig(domain.NullServerConfig{
|
||||||
Value: cfg,
|
Value: cfg,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = updateParams.SetBuildingInfo(domain.NullBuildingInfo{
|
if err = updateParams.SetBuildingInfo(domain.NullBuildingInfo{
|
||||||
Value: buildingInfo,
|
Value: buildingInfo,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = updateParams.SetUnitInfo(domain.NullUnitInfo{
|
if err = updateParams.SetUnitInfo(domain.NullUnitInfo{
|
||||||
Value: unitInfo,
|
Value: unitInfo,
|
||||||
Valid: true,
|
Valid: true,
|
||||||
|
|
|
@ -23,12 +23,113 @@ func NewTribeService(repo TribeRepository, twSvc TWService) *TribeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *TribeService) Sync(ctx context.Context, payload domain.ServerSyncedEventPayload) error {
|
func (svc *TribeService) Sync(ctx context.Context, payload domain.ServerSyncedEventPayload) error {
|
||||||
|
serverKey := payload.Key()
|
||||||
|
|
||||||
tribes, err := svc.twSvc.GetTribes(ctx, payload.URL())
|
tribes, err := svc.twSvc.GetTribes(ctx, payload.URL())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("couldn't get tribes for server %s: %w", payload.Key(), err)
|
return fmt.Errorf("%s: couldn't get tribes: %w", serverKey, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(payload.URL(), len(tribes))
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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...)
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -208,6 +209,26 @@ func (t Tribe) Base() BaseTribe {
|
||||||
|
|
||||||
type Tribes []Tribe
|
type Tribes []Tribe
|
||||||
|
|
||||||
|
// Delete finds all tribes that are not in the given slice with active tribes and returns their ids.
|
||||||
|
// Both slices must be sorted in ascending order by ID.
|
||||||
|
func (ts Tribes) Delete(active BaseTribes) []int {
|
||||||
|
//nolint:prealloc
|
||||||
|
var toDelete []int
|
||||||
|
|
||||||
|
for _, t := range ts {
|
||||||
|
_, found := slices.BinarySearchFunc(active, t, func(a BaseTribe, b Tribe) int {
|
||||||
|
return cmp.Compare(a.ID(), b.ID())
|
||||||
|
})
|
||||||
|
if found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
toDelete = append(toDelete, t.ID())
|
||||||
|
}
|
||||||
|
|
||||||
|
return toDelete
|
||||||
|
}
|
||||||
|
|
||||||
type CreateTribeParams struct {
|
type CreateTribeParams struct {
|
||||||
base BaseTribe
|
base BaseTribe
|
||||||
serverKey string
|
serverKey string
|
||||||
|
@ -221,6 +242,10 @@ type CreateTribeParams struct {
|
||||||
|
|
||||||
const createTribeParamsModelName = "CreateTribeParams"
|
const createTribeParamsModelName = "CreateTribeParams"
|
||||||
|
|
||||||
|
// NewCreateTribeParams constructs a slice of CreateTribeParams based on the given parameters.
|
||||||
|
// Both slices must be sorted in ascending order by ID
|
||||||
|
// + if storedTribes contains tribes from different servers. they must be sorted in ascending order by server key.
|
||||||
|
//
|
||||||
//nolint:gocyclo
|
//nolint:gocyclo
|
||||||
func NewCreateTribeParams(serverKey string, tribes BaseTribes, storedTribes Tribes) ([]CreateTribeParams, error) {
|
func NewCreateTribeParams(serverKey string, tribes BaseTribes, storedTribes Tribes) ([]CreateTribeParams, error) {
|
||||||
if err := validateServerKey(serverKey); err != nil {
|
if err := validateServerKey(serverKey); err != nil {
|
||||||
|
@ -239,10 +264,14 @@ func NewCreateTribeParams(serverKey string, tribes BaseTribes, storedTribes Trib
|
||||||
}
|
}
|
||||||
|
|
||||||
var old Tribe
|
var old Tribe
|
||||||
if oldIdx := slices.IndexFunc(storedTribes, func(old Tribe) bool {
|
idx, found := slices.BinarySearchFunc(storedTribes, t, func(a Tribe, b BaseTribe) int {
|
||||||
return old.ID() == t.ID() && old.ServerKey() == serverKey
|
if res := cmp.Compare(a.ServerKey(), serverKey); res != 0 {
|
||||||
}); oldIdx >= 0 {
|
return res
|
||||||
old = storedTribes[oldIdx]
|
}
|
||||||
|
return cmp.Compare(a.ID(), b.ID())
|
||||||
|
})
|
||||||
|
if found {
|
||||||
|
old = storedTribes[idx]
|
||||||
}
|
}
|
||||||
|
|
||||||
p := CreateTribeParams{
|
p := CreateTribeParams{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package domain_test
|
package domain_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmp"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"slices"
|
"slices"
|
||||||
|
@ -14,6 +15,44 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestTribes_Delete(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
server := domaintest.NewServer(t)
|
||||||
|
|
||||||
|
active := domain.BaseTribes{
|
||||||
|
domaintest.NewBaseTribe(t),
|
||||||
|
domaintest.NewBaseTribe(t),
|
||||||
|
domaintest.NewBaseTribe(t),
|
||||||
|
}
|
||||||
|
slices.SortFunc(active, func(a, b domain.BaseTribe) int {
|
||||||
|
return cmp.Compare(a.ID(), b.ID())
|
||||||
|
})
|
||||||
|
|
||||||
|
tribes := domain.Tribes{
|
||||||
|
domaintest.NewTribe(t, func(cfg *domaintest.TribeConfig) {
|
||||||
|
cfg.ID = active[0].ID()
|
||||||
|
cfg.ServerKey = server.Key()
|
||||||
|
}),
|
||||||
|
domaintest.NewTribe(t, func(cfg *domaintest.TribeConfig) {
|
||||||
|
cfg.ServerKey = server.Key()
|
||||||
|
}),
|
||||||
|
domaintest.NewTribe(t, func(cfg *domaintest.TribeConfig) {
|
||||||
|
cfg.ID = active[1].ID()
|
||||||
|
cfg.ServerKey = server.Key()
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
expectedIDs := []int{tribes[1].ID()}
|
||||||
|
slices.SortFunc(tribes, func(a, b domain.Tribe) int {
|
||||||
|
if res := cmp.Compare(a.ServerKey(), b.ServerKey()); res != 0 {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
return cmp.Compare(a.ID(), b.ID())
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.Equal(t, expectedIDs, tribes.Delete(active))
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewCreateTribeParams(t *testing.T) {
|
func TestNewCreateTribeParams(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
@ -26,8 +65,21 @@ func TestNewCreateTribeParams(t *testing.T) {
|
||||||
domaintest.NewBaseTribe(t),
|
domaintest.NewBaseTribe(t),
|
||||||
domaintest.NewBaseTribe(t),
|
domaintest.NewBaseTribe(t),
|
||||||
}
|
}
|
||||||
|
slices.SortFunc(tribes, func(a, b domain.BaseTribe) int {
|
||||||
|
return cmp.Compare(a.ID(), b.ID())
|
||||||
|
})
|
||||||
|
|
||||||
storedTribes := domain.Tribes{
|
storedTribes := domain.Tribes{
|
||||||
|
domaintest.NewTribe(t, func(cfg *domaintest.TribeConfig) {
|
||||||
|
cfg.ID = tribes[0].ID()
|
||||||
|
cfg.ServerKey = server.Key()[:len(server.Key())-1]
|
||||||
|
cfg.BestRank = tribes[0].Rank() + 1
|
||||||
|
cfg.BestRankAt = now.Add(-time.Hour)
|
||||||
|
cfg.MostPoints = tribes[0].AllPoints() - 1
|
||||||
|
cfg.MostPointsAt = now.Add(-time.Hour)
|
||||||
|
cfg.MostVillages = tribes[0].NumVillages() - 1
|
||||||
|
cfg.MostVillagesAt = now.Add(-time.Hour)
|
||||||
|
}),
|
||||||
domaintest.NewTribe(t, func(cfg *domaintest.TribeConfig) {
|
domaintest.NewTribe(t, func(cfg *domaintest.TribeConfig) {
|
||||||
cfg.ID = tribes[0].ID()
|
cfg.ID = tribes[0].ID()
|
||||||
cfg.ServerKey = server.Key()
|
cfg.ServerKey = server.Key()
|
||||||
|
@ -49,6 +101,12 @@ func TestNewCreateTribeParams(t *testing.T) {
|
||||||
cfg.MostVillagesAt = now.Add(-time.Hour)
|
cfg.MostVillagesAt = now.Add(-time.Hour)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
slices.SortFunc(storedTribes, func(a, b domain.Tribe) int {
|
||||||
|
if res := cmp.Compare(a.ServerKey(), b.ServerKey()); res != 0 {
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
return cmp.Compare(a.ID(), b.ID())
|
||||||
|
})
|
||||||
|
|
||||||
expectedParams := []struct {
|
expectedParams := []struct {
|
||||||
base domain.BaseTribe
|
base domain.BaseTribe
|
||||||
|
@ -70,12 +128,12 @@ func TestNewCreateTribeParams(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
base: tribes[1],
|
base: tribes[1],
|
||||||
bestRank: storedTribes[1].BestRank(),
|
bestRank: storedTribes[2].BestRank(),
|
||||||
bestRankAt: storedTribes[1].BestRankAt(),
|
bestRankAt: storedTribes[2].BestRankAt(),
|
||||||
mostPoints: storedTribes[1].MostPoints(),
|
mostPoints: storedTribes[2].MostPoints(),
|
||||||
mostPointsAt: storedTribes[1].MostPointsAt(),
|
mostPointsAt: storedTribes[2].MostPointsAt(),
|
||||||
mostVillages: storedTribes[1].MostVillages(),
|
mostVillages: storedTribes[2].MostVillages(),
|
||||||
mostVillagesAt: storedTribes[1].MostVillagesAt(),
|
mostVillagesAt: storedTribes[2].MostVillagesAt(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
base: tribes[2],
|
base: tribes[2],
|
||||||
|
|
Loading…
Reference in New Issue