Dawid Wysokiński
d244dc69bf
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: twhelp/core#140
316 lines
8.8 KiB
Go
316 lines
8.8 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, 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, host, versionCode string) ([]domain.Server, error) {
|
|
openServers, err := s.client.GetOpenServers(ctx, host)
|
|
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},
|
|
Count: false,
|
|
})
|
|
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},
|
|
Count: false,
|
|
})
|
|
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, numVillages int64) error {
|
|
_, err := s.repo.Update(ctx, key, domain.UpdateServerParams{
|
|
NumVillages: domain.NullInt64{
|
|
Valid: true,
|
|
Int64: numVillages,
|
|
},
|
|
VillageDataUpdatedAt: 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, int64, error) {
|
|
if params.Pagination.Limit == 0 {
|
|
params.Pagination.Limit = serverMaxLimit
|
|
}
|
|
|
|
if err := validatePagination(params.Pagination, serverMaxLimit); err != nil {
|
|
return nil, 0, fmt.Errorf("validatePagination: %w", err)
|
|
}
|
|
|
|
servers, count, err := s.repo.List(ctx, params)
|
|
if err != nil {
|
|
return nil, 0, fmt.Errorf("ServerRepository.List: %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: domain.ServerConfigGame(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 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),
|
|
}
|
|
}
|