core/internal/app/service_server.go

183 lines
4.7 KiB
Go

package app
import (
"context"
"fmt"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
)
type ServerRepository interface {
CreateOrUpdate(ctx context.Context, params ...domain.CreateServerParams) error
List(ctx context.Context, params domain.ListServersParams) (domain.Servers, error)
Update(ctx context.Context, key string, params domain.UpdateServerParams) error
}
type ServerService struct {
repo ServerRepository
twSvc TWService
publisher ServerPublisher
}
func NewServerService(repo ServerRepository, twSvc TWService, publisher ServerPublisher) *ServerService {
return &ServerService{repo: repo, twSvc: twSvc, publisher: publisher}
}
func (svc *ServerService) Sync(ctx context.Context, payload domain.SyncServersCmdPayload) error {
versionCode := payload.VersionCode()
openServers, err := svc.twSvc.GetOpenServers(ctx, payload.URL())
if err != nil {
return fmt.Errorf("couldn't get open servers for version code %s: %w", versionCode, err)
}
specialServers, err := svc.listAllSpecial(ctx, versionCode)
if err != nil {
return fmt.Errorf("couldn't list special servers with version code %s: %w", versionCode, err)
}
currentlyStoredOpenServers, err := svc.listAllOpen(ctx, versionCode)
if err != nil {
return fmt.Errorf("couldn't list open servers with version code %s: %w", versionCode, err)
}
openServersWithoutSpecial := openServers.FilterOutSpecial(specialServers)
serversToBeClosed, err := currentlyStoredOpenServers.Close(openServersWithoutSpecial)
if err != nil {
return fmt.Errorf("couldn't close servers: %w", err)
}
params, err := domain.NewCreateServerParams(append(openServersWithoutSpecial, serversToBeClosed...), versionCode)
if err != nil {
return err
}
if err = svc.repo.CreateOrUpdate(ctx, params...); err != nil {
return err
}
payloads, err := domain.NewServerSyncedEventPayloads(openServersWithoutSpecial, versionCode)
if err != nil {
return fmt.Errorf("couldn't construct server synced event payloads: %w", err)
}
return svc.publisher.EventSynced(ctx, payloads...)
}
func (svc *ServerService) listAllSpecial(ctx context.Context, versionCode string) (domain.Servers, error) {
params := domain.NewListServersParams()
if err := params.SetVersionCodes([]string{versionCode}); err != nil {
return nil, err
}
if err := params.SetSpecial(domain.NullBool{
Value: true,
Valid: true,
}); err != nil {
return nil, err
}
return svc.ListAll(ctx, params)
}
func (svc *ServerService) listAllOpen(ctx context.Context, versionCode string) (domain.Servers, error) {
params := domain.NewListServersParams()
if err := params.SetVersionCodes([]string{versionCode}); err != nil {
return nil, err
}
if err := params.SetOpen(domain.NullBool{
Value: true,
Valid: true,
}); err != nil {
return nil, err
}
return svc.ListAll(ctx, params)
}
// ListAll retrieves all servers from the database based on the given params in an optimal way.
// You can't specify a custom limit/offset/sort/keyGT for this operation.
func (svc *ServerService) ListAll(ctx context.Context, params domain.ListServersParams) (domain.Servers, error) {
if err := params.SetOffset(0); err != nil {
return nil, err
}
if err := params.SetLimit(domain.ServerListMaxLimit); err != nil {
return nil, err
}
if err := params.SetSort([]domain.ServerSort{domain.ServerSortKeyASC}); err != nil {
return nil, err
}
var servers domain.Servers
for {
ss, err := svc.repo.List(ctx, params)
if err != nil {
return nil, err
}
if len(ss) == 0 {
return servers, nil
}
servers = append(servers, ss...)
if err = params.SetKeyGT(domain.NullString{
Value: ss[len(ss)-1].Key(),
Valid: true,
}); err != nil {
return nil, err
}
}
}
func (svc *ServerService) SyncConfigAndInfo(ctx context.Context, payload domain.ServerSyncedEventPayload) error {
u := payload.URL()
cfg, err := svc.twSvc.GetServerConfig(ctx, u)
if err != nil {
return fmt.Errorf("couldn't get server config for server %s: %w", payload.Key(), err)
}
buildingInfo, err := svc.twSvc.GetBuildingInfo(ctx, u)
if err != nil {
return fmt.Errorf("couldn't get building info for server %s: %w", payload.Key(), err)
}
unitInfo, err := svc.twSvc.GetUnitInfo(ctx, u)
if err != nil {
return fmt.Errorf("couldn't get unit info for server %s: %w", payload.Key(), err)
}
var updateParams domain.UpdateServerParams
if err = updateParams.SetConfig(domain.NullServerConfig{
Value: cfg,
Valid: true,
}); err != nil {
return err
}
if err = updateParams.SetBuildingInfo(domain.NullBuildingInfo{
Value: buildingInfo,
Valid: true,
}); err != nil {
return err
}
if err = updateParams.SetUnitInfo(domain.NullUnitInfo{
Value: unitInfo,
Valid: true,
}); err != nil {
return err
}
return svc.repo.Update(ctx, payload.Key(), updateParams)
}