core/internal/domain/server_snapshot.go
Dawid Wysokiński 9d5987f74c
All checks were successful
ci/woodpecker/push/govulncheck Pipeline was successful
ci/woodpecker/push/test Pipeline was successful
ci/woodpecker/tag/release Pipeline was successful
ci/woodpecker/tag/deployment Pipeline was successful
ci/woodpecker/cron/govulncheck Pipeline was successful
feat: new endpoint GET /api/v2/versions/{versionCode}/servers/{serverKey}/snapshots (#52)
Reviewed-on: #52
2024-05-13 05:12:05 +00:00

659 lines
15 KiB
Go

package domain
import (
"errors"
"math"
"time"
)
type ServerSnapshot struct {
id int
serverKey string
numPlayers int
numActivePlayers int
numInactivePlayers int
numTribes int
numActiveTribes int
numInactiveTribes int
numVillages int
numPlayerVillages int
numBarbarianVillages int
numBonusVillages int
date time.Time
createdAt time.Time
}
const serverSnapshotModelName = "ServerSnapshot"
// UnmarshalServerSnapshotFromDatabase unmarshals ServerSnapshot from the database.
//
// It should be used only for unmarshalling from the database!
// You can't use UnmarshalServerSnapshotFromDatabase as constructor - It may put domain into the invalid state!
func UnmarshalServerSnapshotFromDatabase(
id int,
serverKey string,
numPlayers int,
numActivePlayers int,
numInactivePlayers int,
numTribes int,
numActiveTribes int,
numInactiveTribes int,
numVillages int,
numPlayerVillages int,
numBarbarianVillages int,
numBonusVillages int,
date time.Time,
createdAt time.Time,
) (ServerSnapshot, error) {
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
return ServerSnapshot{}, ValidationError{
Model: serverSnapshotModelName,
Field: "id",
Err: err,
}
}
if err := validateServerKey(serverKey); err != nil {
return ServerSnapshot{}, ValidationError{
Model: serverSnapshotModelName,
Field: "serverKey",
Err: err,
}
}
return ServerSnapshot{
id: id,
serverKey: serverKey,
numPlayers: numPlayers,
numActivePlayers: numActivePlayers,
numInactivePlayers: numInactivePlayers,
numTribes: numTribes,
numActiveTribes: numActiveTribes,
numInactiveTribes: numInactiveTribes,
numVillages: numVillages,
numPlayerVillages: numPlayerVillages,
numBarbarianVillages: numBarbarianVillages,
numBonusVillages: numBonusVillages,
date: date,
createdAt: createdAt,
}, nil
}
func (ss ServerSnapshot) ID() int {
return ss.id
}
func (ss ServerSnapshot) ServerKey() string {
return ss.serverKey
}
func (ss ServerSnapshot) NumPlayers() int {
return ss.numPlayers
}
func (ss ServerSnapshot) NumActivePlayers() int {
return ss.numActivePlayers
}
func (ss ServerSnapshot) NumInactivePlayers() int {
return ss.numInactivePlayers
}
func (ss ServerSnapshot) NumTribes() int {
return ss.numTribes
}
func (ss ServerSnapshot) NumActiveTribes() int {
return ss.numActiveTribes
}
func (ss ServerSnapshot) NumInactiveTribes() int {
return ss.numInactiveTribes
}
func (ss ServerSnapshot) NumVillages() int {
return ss.numVillages
}
func (ss ServerSnapshot) NumPlayerVillages() int {
return ss.numPlayerVillages
}
func (ss ServerSnapshot) NumBarbarianVillages() int {
return ss.numBarbarianVillages
}
func (ss ServerSnapshot) NumBonusVillages() int {
return ss.numBonusVillages
}
func (ss ServerSnapshot) Date() time.Time {
return ss.date
}
func (ss ServerSnapshot) CreatedAt() time.Time {
return ss.createdAt
}
func (ss ServerSnapshot) WithRelations(server ServerMeta) ServerSnapshotWithRelations {
return ServerSnapshotWithRelations{
snapshot: ss,
server: server,
}
}
func (ss ServerSnapshot) ToCursor() (ServerSnapshotCursor, error) {
return NewServerSnapshotCursor(ss.id, ss.serverKey, ss.date)
}
func (ss ServerSnapshot) IsZero() bool {
return ss == ServerSnapshot{}
}
type ServerSnapshots []ServerSnapshot
type ServerSnapshotWithRelations struct {
snapshot ServerSnapshot
server ServerMeta
}
func (ts ServerSnapshotWithRelations) ServerSnapshot() ServerSnapshot {
return ts.snapshot
}
func (ts ServerSnapshotWithRelations) Server() ServerMeta {
return ts.server
}
func (ts ServerSnapshotWithRelations) IsZero() bool {
return ts.snapshot.IsZero()
}
type ServerSnapshotsWithRelations []ServerSnapshotWithRelations
type CreateServerSnapshotParams struct {
serverKey string
numPlayers int
numActivePlayers int
numInactivePlayers int
numTribes int
numActiveTribes int
numInactiveTribes int
numVillages int
numPlayerVillages int
numBarbarianVillages int
numBonusVillages int
date time.Time
}
func NewCreateServerSnapshotParams(server Server, date time.Time) (CreateServerSnapshotParams, error) {
if server.IsZero() {
return CreateServerSnapshotParams{}, errors.New("given server is an empty struct")
}
if !server.Open() {
return CreateServerSnapshotParams{}, errors.New("given server is closed")
}
return CreateServerSnapshotParams{
serverKey: server.Key(),
numPlayers: server.NumPlayers(),
numActivePlayers: server.NumActivePlayers(),
numInactivePlayers: server.NumInactivePlayers(),
numTribes: server.NumTribes(),
numActiveTribes: server.NumActiveTribes(),
numInactiveTribes: server.NumInactiveTribes(),
numVillages: server.NumVillages(),
numPlayerVillages: server.NumPlayerVillages(),
numBarbarianVillages: server.NumBarbarianVillages(),
numBonusVillages: server.NumBonusVillages(),
date: date,
}, nil
}
func (params CreateServerSnapshotParams) ServerKey() string {
return params.serverKey
}
func (params CreateServerSnapshotParams) NumPlayers() int {
return params.numPlayers
}
func (params CreateServerSnapshotParams) NumActivePlayers() int {
return params.numActivePlayers
}
func (params CreateServerSnapshotParams) NumInactivePlayers() int {
return params.numInactivePlayers
}
func (params CreateServerSnapshotParams) NumTribes() int {
return params.numTribes
}
func (params CreateServerSnapshotParams) NumActiveTribes() int {
return params.numActiveTribes
}
func (params CreateServerSnapshotParams) NumInactiveTribes() int {
return params.numInactiveTribes
}
func (params CreateServerSnapshotParams) NumVillages() int {
return params.numVillages
}
func (params CreateServerSnapshotParams) NumPlayerVillages() int {
return params.numPlayerVillages
}
func (params CreateServerSnapshotParams) NumBarbarianVillages() int {
return params.numBarbarianVillages
}
func (params CreateServerSnapshotParams) NumBonusVillages() int {
return params.numBonusVillages
}
func (params CreateServerSnapshotParams) Date() time.Time {
return params.date
}
type ServerSnapshotSort uint8
const (
ServerSnapshotSortDateASC ServerSnapshotSort = iota + 1
ServerSnapshotSortDateDESC
ServerSnapshotSortIDASC
ServerSnapshotSortIDDESC
ServerSnapshotSortServerKeyASC
ServerSnapshotSortServerKeyDESC
)
// IsInConflict returns true if two sorts can't be used together
// (e.g. ServerSnapshotSortIDASC and ServerSnapshotSortIDDESC).
func (s ServerSnapshotSort) IsInConflict(s2 ServerSnapshotSort) bool {
return isSortInConflict(s, s2)
}
//nolint:gocyclo
func (s ServerSnapshotSort) String() string {
switch s {
case ServerSnapshotSortDateASC:
return "date:ASC"
case ServerSnapshotSortDateDESC:
return "date:DESC"
case ServerSnapshotSortIDASC:
return "id:ASC"
case ServerSnapshotSortIDDESC:
return "id:DESC"
case ServerSnapshotSortServerKeyASC:
return "serverKey:ASC"
case ServerSnapshotSortServerKeyDESC:
return "serverKey:DESC"
default:
return "unknown server snapshot sort"
}
}
type ServerSnapshotCursor struct {
id int
serverKey string
date time.Time
}
const serverSnapshotCursorModelName = "ServerSnapshotCursor"
func NewServerSnapshotCursor(id int, serverKey string, date time.Time) (ServerSnapshotCursor, error) {
if err := validateIntInRange(id, 1, math.MaxInt); err != nil {
return ServerSnapshotCursor{}, ValidationError{
Model: serverSnapshotCursorModelName,
Field: "id",
Err: err,
}
}
if err := validateServerKey(serverKey); err != nil {
return ServerSnapshotCursor{}, ValidationError{
Model: serverSnapshotCursorModelName,
Field: "serverKey",
Err: err,
}
}
return ServerSnapshotCursor{
id: id,
serverKey: serverKey,
date: date,
}, nil
}
func decodeServerSnapshotCursor(encoded string) (ServerSnapshotCursor, error) {
m, err := decodeCursor(encoded)
if err != nil {
return ServerSnapshotCursor{}, err
}
id, err := m.int("id")
if err != nil {
return ServerSnapshotCursor{}, ErrInvalidCursor
}
serverKey, err := m.string("serverKey")
if err != nil {
return ServerSnapshotCursor{}, ErrInvalidCursor
}
date, err := m.time("date")
if err != nil {
return ServerSnapshotCursor{}, ErrInvalidCursor
}
tsc, err := NewServerSnapshotCursor(
id,
serverKey,
date,
)
if err != nil {
return ServerSnapshotCursor{}, ErrInvalidCursor
}
return tsc, nil
}
func (ssc ServerSnapshotCursor) ID() int {
return ssc.id
}
func (ssc ServerSnapshotCursor) ServerKey() string {
return ssc.serverKey
}
func (ssc ServerSnapshotCursor) Date() time.Time {
return ssc.date
}
func (ssc ServerSnapshotCursor) IsZero() bool {
return ssc == ServerSnapshotCursor{}
}
func (ssc ServerSnapshotCursor) Encode() string {
if ssc.IsZero() {
return ""
}
return encodeCursor([]keyValuePair{
{"id", ssc.id},
{"serverKey", ssc.serverKey},
{"date", ssc.date},
})
}
type ListServerSnapshotsParams struct {
serverKeys []string
sort []ServerSnapshotSort
cursor ServerSnapshotCursor
limit int
}
const (
ServerSnapshotListMaxLimit = 500
listServerSnapshotsParamsModelName = "ListServerSnapshotsParams"
)
func NewListServerSnapshotsParams() ListServerSnapshotsParams {
return ListServerSnapshotsParams{
sort: []ServerSnapshotSort{
ServerSnapshotSortServerKeyASC,
ServerSnapshotSortDateASC,
ServerSnapshotSortIDASC,
},
limit: ServerSnapshotListMaxLimit,
}
}
func (params *ListServerSnapshotsParams) ServerKeys() []string {
return params.serverKeys
}
func (params *ListServerSnapshotsParams) SetServerKeys(serverKeys []string) error {
for i, sk := range serverKeys {
if err := validateServerKey(sk); err != nil {
return SliceElementValidationError{
Model: listServerSnapshotsParamsModelName,
Field: "serverKeys",
Index: i,
Err: err,
}
}
}
params.serverKeys = serverKeys
return nil
}
func (params *ListServerSnapshotsParams) Sort() []ServerSnapshotSort {
return params.sort
}
const (
serverSnapshotSortMinLength = 0
serverSnapshotSortMaxLength = 3
)
func (params *ListServerSnapshotsParams) SetSort(sort []ServerSnapshotSort) error {
if err := validateSort(sort, serverSnapshotSortMinLength, serverSnapshotSortMaxLength); err != nil {
return ValidationError{
Model: listServerSnapshotsParamsModelName,
Field: "sort",
Err: err,
}
}
params.sort = sort
return nil
}
func (params *ListServerSnapshotsParams) PrependSort(sort []ServerSnapshotSort) error {
if len(sort) == 0 {
return nil
}
if err := validateSliceLen(sort, 0, max(serverSnapshotSortMaxLength-len(params.sort), 0)); err != nil {
return ValidationError{
Model: listServerSnapshotsParamsModelName,
Field: "sort",
Err: err,
}
}
return params.SetSort(append(sort, params.sort...))
}
func (params *ListServerSnapshotsParams) PrependSortString(
sort []string,
allowed []ServerSnapshotSort,
maxLength int,
) error {
if len(sort) == 0 {
return nil
}
if err := validateSliceLen(sort, 0, max(min(serverSnapshotSortMaxLength-len(params.sort), maxLength), 0)); err != nil {
return ValidationError{
Model: listServerSnapshotsParamsModelName,
Field: "sort",
Err: err,
}
}
toPrepend := make([]ServerSnapshotSort, 0, len(sort))
for i, s := range sort {
converted, err := newSortFromString(s, allowed...)
if err != nil {
return SliceElementValidationError{
Model: listServerSnapshotsParamsModelName,
Field: "sort",
Index: i,
Err: err,
}
}
toPrepend = append(toPrepend, converted)
}
return params.SetSort(append(toPrepend, params.sort...))
}
func (params *ListServerSnapshotsParams) Cursor() ServerSnapshotCursor {
return params.cursor
}
func (params *ListServerSnapshotsParams) SetCursor(cursor ServerSnapshotCursor) error {
params.cursor = cursor
return nil
}
func (params *ListServerSnapshotsParams) SetEncodedCursor(encoded string) error {
decoded, err := decodeServerSnapshotCursor(encoded)
if err != nil {
return ValidationError{
Model: listServerSnapshotsParamsModelName,
Field: "cursor",
Err: err,
}
}
params.cursor = decoded
return nil
}
func (params *ListServerSnapshotsParams) Limit() int {
return params.limit
}
func (params *ListServerSnapshotsParams) SetLimit(limit int) error {
if err := validateIntInRange(limit, 1, ServerSnapshotListMaxLimit); err != nil {
return ValidationError{
Model: listServerSnapshotsParamsModelName,
Field: "limit",
Err: err,
}
}
params.limit = limit
return nil
}
type ListServerSnapshotsResult struct {
snapshots ServerSnapshots
self ServerSnapshotCursor
next ServerSnapshotCursor
}
const listServerSnapshotsResultModelName = "ListServerSnapshotsResult"
func NewListServerSnapshotsResult(
snapshots ServerSnapshots,
next ServerSnapshot,
) (ListServerSnapshotsResult, error) {
var err error
res := ListServerSnapshotsResult{
snapshots: snapshots,
}
if len(snapshots) > 0 {
res.self, err = snapshots[0].ToCursor()
if err != nil {
return ListServerSnapshotsResult{}, ValidationError{
Model: listServerSnapshotsResultModelName,
Field: "self",
Err: err,
}
}
}
if !next.IsZero() {
res.next, err = next.ToCursor()
if err != nil {
return ListServerSnapshotsResult{}, ValidationError{
Model: listServerSnapshotsResultModelName,
Field: "next",
Err: err,
}
}
}
return res, nil
}
func (res ListServerSnapshotsResult) ServerSnapshots() ServerSnapshots {
return res.snapshots
}
func (res ListServerSnapshotsResult) Self() ServerSnapshotCursor {
return res.self
}
func (res ListServerSnapshotsResult) Next() ServerSnapshotCursor {
return res.next
}
type ListServerSnapshotsWithRelationsResult struct {
snapshots ServerSnapshotsWithRelations
self ServerSnapshotCursor
next ServerSnapshotCursor
}
const listServerSnapshotsWithRelationsResultModelName = "ListServerSnapshotsWithRelationsResult"
func NewListServerSnapshotsWithRelationsResult(
snapshots ServerSnapshotsWithRelations,
next ServerSnapshotWithRelations,
) (ListServerSnapshotsWithRelationsResult, error) {
var err error
res := ListServerSnapshotsWithRelationsResult{
snapshots: snapshots,
}
if len(snapshots) > 0 {
res.self, err = snapshots[0].ServerSnapshot().ToCursor()
if err != nil {
return ListServerSnapshotsWithRelationsResult{}, ValidationError{
Model: listServerSnapshotsWithRelationsResultModelName,
Field: "self",
Err: err,
}
}
}
if !next.IsZero() {
res.next, err = next.ServerSnapshot().ToCursor()
if err != nil {
return ListServerSnapshotsWithRelationsResult{}, ValidationError{
Model: listServerSnapshotsWithRelationsResultModelName,
Field: "next",
Err: err,
}
}
}
return res, nil
}
func (res ListServerSnapshotsWithRelationsResult) ServerSnapshots() ServerSnapshotsWithRelations {
return res.snapshots
}
func (res ListServerSnapshotsWithRelationsResult) Self() ServerSnapshotCursor {
return res.self
}
func (res ListServerSnapshotsWithRelationsResult) Next() ServerSnapshotCursor {
return res.next
}