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 d244dc69bf
All checks were successful
continuous-integration/drone/push Build is passing
refactor: remove otel (#140)
Reviewed-on: twhelp/core#140
2022-12-20 07:27:13 +00:00

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),
}
}