This repository has been archived on 2024-04-06. You can view files and clone it, but cannot push or open issues or pull requests.
core-old/internal/service/server.go
Dawid Wysokiński cde9990810
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
refactor: refresh servers cmd - send url instead of just host in payload
2023-02-26 10:20:32 +01:00

389 lines
11 KiB
Go

package service
import (
"context"
"fmt"
"time"
"gitea.dwysokinski.me/twhelp/core/internal/domain"
"gitea.dwysokinski.me/twhelp/core/internal/tw"
)
const (
serverMaxLimit = 500
)
//counterfeiter:generate -o internal/mock/server_repository.gen.go . ServerRepository
type ServerRepository interface {
CreateOrUpdate(ctx context.Context, params ...domain.CreateServerParams) ([]domain.Server, error)
List(ctx context.Context, params domain.ListServersParams) ([]domain.Server, error)
ListCount(ctx context.Context, params domain.ListServersParams) ([]domain.Server, int64, error)
Update(ctx context.Context, key string, params domain.UpdateServerParams) (domain.Server, error)
}
//counterfeiter:generate -o internal/mock/open_server_config_info_getter.gen.go . OpenServerConfigInfoGetter
type OpenServerConfigInfoGetter interface {
GetOpenServers(ctx context.Context, baseURL string) ([]tw.Server, error)
GetServerConfig(ctx context.Context, baseURL string) (tw.ServerConfig, error)
GetBuildingInfo(ctx context.Context, baseURL string) (tw.BuildingInfo, error)
GetUnitInfo(ctx context.Context, baseURL string) (tw.UnitInfo, error)
}
type Server struct {
repo ServerRepository
client OpenServerConfigInfoGetter
}
func NewServer(repo ServerRepository, client OpenServerConfigInfoGetter) *Server {
return &Server{repo: repo, client: client}
}
func (s *Server) Refresh(ctx context.Context, url, versionCode string) ([]domain.Server, error) {
openServers, err := s.client.GetOpenServers(ctx, url)
if err != nil {
return nil, fmt.Errorf("TWClient.GetOpenServers: %w", err)
}
specialServers, err := s.repo.List(ctx, domain.ListServersParams{
Special: domain.NullBool{Bool: true, Valid: true},
VersionCodes: []string{versionCode},
})
if err != nil {
return nil, fmt.Errorf("ServerRepository.List: %w", err)
}
currentlyStoredOpenServers, err := s.repo.List(ctx, domain.ListServersParams{
Open: domain.NullBool{Bool: true, Valid: true},
VersionCodes: []string{versionCode},
})
if err != nil {
return nil, fmt.Errorf("ServerRepository.List: %w", err)
}
params := make([]domain.CreateServerParams, 0, len(openServers))
for _, srv := range openServers {
if isSpecialServer(specialServers, srv.Key) {
continue
}
params = append(params, domain.CreateServerParams{
Key: srv.Key,
URL: srv.URL,
Open: true,
VersionCode: versionCode,
})
}
for _, srv := range currentlyStoredOpenServers {
if isInOpen(openServers, srv.Key) {
continue
}
params = append(params, domain.CreateServerParams{
Key: srv.Key,
URL: srv.URL,
Open: false,
VersionCode: versionCode,
})
}
upsertedServers, err := s.repo.CreateOrUpdate(ctx, params...)
if err != nil {
return nil, fmt.Errorf("ServerRepository.CreateOrUpdate: %w", err)
}
return upsertedServers, nil
}
func (s *Server) UpdateInfoAndConfig(ctx context.Context, key, url string) error {
cfg, err := s.client.GetServerConfig(ctx, url)
if err != nil {
return fmt.Errorf("TWClient.GetServerConfig: %w", err)
}
buildingInfo, err := s.client.GetBuildingInfo(ctx, url)
if err != nil {
return fmt.Errorf("TWClient.GetBuildingInfo: %w", err)
}
unitInfo, err := s.client.GetUnitInfo(ctx, url)
if err != nil {
return fmt.Errorf("TWClient.GetUnitInfo: %w", err)
}
_, err = s.repo.Update(ctx, key, domain.UpdateServerParams{
Config: domain.NullServerConfig{
Config: newServerConfig(cfg),
Valid: true,
},
UnitInfo: domain.NullUnitInfo{
Info: newUnitInfo(unitInfo),
Valid: true,
},
BuildingInfo: domain.NullBuildingInfo{
Info: newBuildingInfo(buildingInfo),
Valid: true,
},
})
if err != nil {
return fmt.Errorf("ServerRepository.Update: %w", err)
}
return nil
}
func (s *Server) UpdateNumPlayers(ctx context.Context, key string, numPlayers int64) error {
_, err := s.repo.Update(ctx, key, domain.UpdateServerParams{
NumPlayers: domain.NullInt64{
Valid: true,
Int64: numPlayers,
},
PlayerDataUpdatedAt: time.Now(),
})
if err != nil {
return fmt.Errorf("ServerRepository.Update: %w", err)
}
return nil
}
func (s *Server) UpdateNumTribes(ctx context.Context, key string, numTribes int64) error {
_, err := s.repo.Update(ctx, key, domain.UpdateServerParams{
NumTribes: domain.NullInt64{
Valid: true,
Int64: numTribes,
},
TribeDataUpdatedAt: time.Now(),
})
if err != nil {
return fmt.Errorf("ServerRepository.Update: %w", err)
}
return nil
}
func (s *Server) UpdateNumVillages(ctx context.Context, key string, res domain.RefreshVillagesResult) error {
_, err := s.repo.Update(ctx, key, domain.UpdateServerParams{
NumVillages: domain.NullInt64{
Valid: true,
Int64: res.NumVillages,
},
NumPlayerVillages: domain.NullInt64{
Valid: true,
Int64: res.NumPlayerVillages,
},
NumBarbarianVillages: domain.NullInt64{
Valid: true,
Int64: res.NumBarbarianVillages,
},
NumBonusVillages: domain.NullInt64{
Valid: true,
Int64: res.NumBonusVillages,
},
VillageDataUpdatedAt: time.Now(),
})
if err != nil {
return fmt.Errorf("ServerRepository.Update: %w", err)
}
return nil
}
func (s *Server) UpdateEnnoblementDataUpdatedAt(ctx context.Context, key string) error {
_, err := s.repo.Update(ctx, key, domain.UpdateServerParams{
EnnoblementDataUpdatedAt: time.Now(),
})
if err != nil {
return fmt.Errorf("ServerRepository.Update: %w", err)
}
return nil
}
func (s *Server) UpdatePlayerSnapshotsCreatedAt(ctx context.Context, key string) error {
_, err := s.repo.Update(ctx, key, domain.UpdateServerParams{
PlayerSnapshotsCreatedAt: time.Now(),
})
if err != nil {
return fmt.Errorf("ServerRepository.Update: %w", err)
}
return nil
}
func (s *Server) UpdateTribeSnapshotsCreatedAt(ctx context.Context, key string) error {
_, err := s.repo.Update(ctx, key, domain.UpdateServerParams{
TribeSnapshotsCreatedAt: time.Now(),
})
if err != nil {
return fmt.Errorf("ServerRepository.Update: %w", err)
}
return nil
}
func (s *Server) List(ctx context.Context, params domain.ListServersParams) ([]domain.Server, error) {
params, err := listServersParamsBuilder{params}.build()
if err != nil {
return nil, err
}
servers, err := s.repo.List(ctx, params)
if err != nil {
return nil, fmt.Errorf("ServerRepository.List: %w", err)
}
return servers, nil
}
func (s *Server) ListCount(ctx context.Context, params domain.ListServersParams) ([]domain.Server, int64, error) {
params, err := listServersParamsBuilder{params}.build()
if err != nil {
return nil, 0, err
}
servers, count, err := s.repo.ListCount(ctx, params)
if err != nil {
return nil, 0, fmt.Errorf("ServerRepository.ListCount: %w", err)
}
return servers, count, nil
}
func (s *Server) GetNormalByVersionCodeAndKey(ctx context.Context, versionCode, key string) (domain.Server, error) {
servers, err := s.repo.List(ctx, domain.ListServersParams{
Special: domain.NullBool{
Bool: false,
Valid: true,
},
Keys: []string{key},
VersionCodes: []string{versionCode},
Pagination: domain.Pagination{
Limit: 1,
},
})
if err != nil {
return domain.Server{}, fmt.Errorf("ServerRepository.List: %w", err)
}
if len(servers) == 0 {
return domain.Server{}, domain.ServerNotFoundError{
Key: key,
}
}
return servers[0], nil
}
func isInOpen(servers []tw.Server, key string) bool {
for _, srv := range servers {
if srv.Key == key {
return true
}
}
return false
}
func isSpecialServer(special []domain.Server, key string) bool {
for _, srv := range special {
if srv.Key == key {
return true
}
}
return false
}
func newServerConfig(cfg tw.ServerConfig) domain.ServerConfig {
return domain.ServerConfig{
Speed: cfg.Speed,
UnitSpeed: cfg.UnitSpeed,
Moral: cfg.Moral,
Build: domain.ServerConfigBuild(cfg.Build),
Misc: domain.ServerConfigMisc(cfg.Misc),
Commands: domain.ServerConfigCommands(cfg.Commands),
Newbie: domain.ServerConfigNewbie(cfg.Newbie),
Game: newServerConfigGame(cfg.Game),
Buildings: domain.ServerConfigBuildings(cfg.Buildings),
Snob: domain.ServerConfigSnob(cfg.Snob),
Ally: domain.ServerConfigAlly(cfg.Ally),
Coord: domain.ServerConfigCoord(cfg.Coord),
Sitter: domain.ServerConfigSitter(cfg.Sitter),
Sleep: domain.ServerConfigSleep(cfg.Sleep),
Night: domain.ServerConfigNight(cfg.Night),
Win: domain.ServerConfigWin(cfg.Win),
}
}
func newServerConfigGame(cfg tw.ServerConfigGame) domain.ServerConfigGame {
return domain.ServerConfigGame{
BuildtimeFormula: cfg.BuildtimeFormula,
Knight: cfg.Knight,
KnightNewItems: cfg.KnightNewItems.Int8(),
Archer: cfg.Archer,
Tech: cfg.Tech,
FarmLimit: cfg.FarmLimit,
Church: cfg.Church,
Watchtower: cfg.Watchtower,
Stronghold: cfg.Stronghold,
FakeLimit: cfg.FakeLimit,
BarbarianRise: cfg.BarbarianRise,
BarbarianShrink: cfg.BarbarianShrink,
BarbarianMaxPoints: cfg.BarbarianMaxPoints,
Scavenging: cfg.Scavenging,
Hauls: cfg.Hauls,
HaulsBase: cfg.HaulsBase,
HaulsMax: cfg.HaulsMax,
BaseProduction: cfg.BaseProduction,
Event: cfg.Event,
SuppressEvents: cfg.SuppressEvents,
}
}
func newUnitInfo(info tw.UnitInfo) domain.UnitInfo {
return domain.UnitInfo{
Spear: domain.Unit(info.Spear),
Sword: domain.Unit(info.Sword),
Axe: domain.Unit(info.Axe),
Archer: domain.Unit(info.Archer),
Spy: domain.Unit(info.Spy),
Light: domain.Unit(info.Light),
Marcher: domain.Unit(info.Marcher),
Heavy: domain.Unit(info.Heavy),
Ram: domain.Unit(info.Ram),
Catapult: domain.Unit(info.Catapult),
Knight: domain.Unit(info.Knight),
Snob: domain.Unit(info.Snob),
Militia: domain.Unit(info.Militia),
}
}
func newBuildingInfo(info tw.BuildingInfo) domain.BuildingInfo {
return domain.BuildingInfo{
Main: domain.Building(info.Main),
Barracks: domain.Building(info.Barracks),
Stable: domain.Building(info.Stable),
Garage: domain.Building(info.Garage),
Watchtower: domain.Building(info.Watchtower),
Snob: domain.Building(info.Snob),
Smith: domain.Building(info.Smith),
Place: domain.Building(info.Place),
Statue: domain.Building(info.Statue),
Market: domain.Building(info.Market),
Wood: domain.Building(info.Wood),
Stone: domain.Building(info.Stone),
Iron: domain.Building(info.Iron),
Farm: domain.Building(info.Farm),
Storage: domain.Building(info.Storage),
Hide: domain.Building(info.Hide),
Wall: domain.Building(info.Wall),
}
}
type listServersParamsBuilder struct {
domain.ListServersParams
}
func (l listServersParamsBuilder) build() (domain.ListServersParams, error) {
if l.Pagination.Limit == 0 {
l.Pagination.Limit = serverMaxLimit
}
if err := validatePagination(l.Pagination, serverMaxLimit); err != nil {
return domain.ListServersParams{}, fmt.Errorf("validatePagination: %w", err)
}
return l.ListServersParams, nil
}