dcbot/internal/domain/village.go

234 lines
5.5 KiB
Go

package domain
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"math"
"regexp"
"strings"
)
type Village struct {
ID int64
FullName string
ProfileURL string
Points int64
X int64
Y int64
Player NullPlayerMeta
}
func (v Village) Coords() string {
return fmt.Sprintf("%d|%d", v.X, v.Y)
}
type VillageMeta struct {
ID int64
FullName string
ProfileURL string
Player NullPlayerMeta
}
type VillageCoordsStringTooLongError struct {
Str string
Max int
}
var _ TranslatableError = VillageCoordsStringTooLongError{}
func (e VillageCoordsStringTooLongError) Error() string {
return fmt.Sprintf("coords string is too long (%d/%d)", len(e.Str), e.Max)
}
func (e VillageCoordsStringTooLongError) Slug() string {
return "village-coords-string-too-long"
}
func (e VillageCoordsStringTooLongError) Params() map[string]any {
return map[string]any{
"Str": e.Str,
"Max": e.Max,
}
}
type VillageCoordsNotFoundInStringError struct {
Str string
}
var _ TranslatableError = VillageCoordsNotFoundInStringError{}
func (e VillageCoordsNotFoundInStringError) Error() string {
return fmt.Sprintf("no coords found in string: '%s'", e.Str)
}
func (e VillageCoordsNotFoundInStringError) Slug() string {
return "village-coords-not-found-in-string"
}
func (e VillageCoordsNotFoundInStringError) Params() map[string]any {
return map[string]any{
"Str": e.Str,
}
}
type TranslateVillageCoordsParams struct {
versionCode string
serverKey string
coords []string
perPage int32
maxPage int32
sha256 string
}
var villageCoordsRegex = regexp.MustCompile(`(\d+)\|(\d+)`)
const (
VillageCoordsStringMaxLength = 1000
translateVillageCoordsMinPerPage = 1
)
func NewTranslateVillageCoordsParams(versionCode, serverKey, coordsStr string, perPage int32) (TranslateVillageCoordsParams, error) {
if versionCode == "" {
return TranslateVillageCoordsParams{}, RequiredError{Field: "VersionCode"}
}
if serverKey == "" {
return TranslateVillageCoordsParams{}, RequiredError{Field: "ServerKey"}
}
if perPage < translateVillageCoordsMinPerPage {
return TranslateVillageCoordsParams{}, GreaterEqualThanError{
Field: "PerPage",
Threshold: translateVillageCoordsMinPerPage,
}
}
if len(coordsStr) > VillageCoordsStringMaxLength {
return TranslateVillageCoordsParams{}, VillageCoordsStringTooLongError{
Max: VillageCoordsStringMaxLength,
Str: coordsStr,
}
}
coords := uniq(villageCoordsRegex.FindAllString(coordsStr, -1))
if len(coords) == 0 {
return TranslateVillageCoordsParams{}, VillageCoordsNotFoundInStringError{
Str: coordsStr,
}
}
sum256 := sha256.Sum256(fmt.Appendf(nil, "%s-%s-%s-%d", versionCode, serverKey, strings.Join(coords, ","), perPage))
return TranslateVillageCoordsParams{
versionCode: versionCode,
serverKey: serverKey,
coords: coords,
perPage: perPage,
maxPage: int32(math.Ceil(float64(len(coords)) / float64(perPage))),
sha256: hex.EncodeToString(sum256[:]),
}, nil
}
// UnmarshalTranslateVillageCoordsParamsFromDatabase unmarshals TranslateVillageCoordsParams from the database.
//
// It should be used only for unmarshalling from the database!
// You can't use UnmarshalTranslateVillageCoordsParamsFromDatabase as constructor - It may put domain into the invalid state!
func UnmarshalTranslateVillageCoordsParamsFromDatabase(
versionCode string,
serverKey string,
coords []string,
perPage int32,
maxPage int32,
sha256Hash string,
) (TranslateVillageCoordsParams, error) {
if versionCode == "" {
return TranslateVillageCoordsParams{}, RequiredError{Field: "VersionCode"}
}
if serverKey == "" {
return TranslateVillageCoordsParams{}, RequiredError{Field: "ServerKey"}
}
if len(coords) == 0 {
return TranslateVillageCoordsParams{}, LengthTooShortError{
Field: "Coords",
Threshold: 1,
}
}
if perPage < translateVillageCoordsMinPerPage {
return TranslateVillageCoordsParams{}, GreaterEqualThanError{
Field: "PerPage",
Threshold: translateVillageCoordsMinPerPage,
}
}
if sha256Hash == "" {
return TranslateVillageCoordsParams{}, RequiredError{Field: "SHA256"}
}
return TranslateVillageCoordsParams{
versionCode: versionCode,
serverKey: serverKey,
coords: coords,
perPage: perPage,
maxPage: maxPage,
sha256: sha256Hash,
}, nil
}
func (t TranslateVillageCoordsParams) VersionCode() string {
return t.versionCode
}
func (t TranslateVillageCoordsParams) ServerKey() string {
return t.serverKey
}
func (t TranslateVillageCoordsParams) Coords() []string {
return t.coords
}
func (t TranslateVillageCoordsParams) PerPage() int32 {
return t.perPage
}
func (t TranslateVillageCoordsParams) MaxPage() int32 {
return t.maxPage
}
func (t TranslateVillageCoordsParams) SHA256() string {
return t.sha256
}
type TranslateVillageCoordsResult struct {
Villages []Village
NotFound []string
HasNext bool
HasPrev bool
Page int32
MaxPage int32
ParamsSHA256 string
}
type TranslateVillageCoordsParamsNotFoundError struct {
SHA256 string
}
var _ TranslatableError = TranslateVillageCoordsParamsNotFoundError{}
func (e TranslateVillageCoordsParamsNotFoundError) Error() string {
return fmt.Sprintf("params (SHA256=%s) not found", e.SHA256)
}
func (e TranslateVillageCoordsParamsNotFoundError) Slug() string {
return "translate-village-coords-params-not-found"
}
func (e TranslateVillageCoordsParamsNotFoundError) Params() map[string]any {
return map[string]any{
"SHA256": e.SHA256,
}
}