Equip Item; Refactor Loadouts; Move Cache System; ...

Change up attribrutes again.
Fix indent bug.
This commit is contained in:
eccentric 2023-11-05 01:58:00 +00:00
parent 113c68a38d
commit db9f92bd91
23 changed files with 727 additions and 478 deletions

View File

@ -1,6 +1,7 @@
package aid package aid
import ( import (
"encoding/json"
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
@ -10,4 +11,15 @@ func WaitForExit() {
sc := make(chan os.Signal, 1) sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
<-sc <-sc
}
func JSONStringify(input interface{}) string {
json, _ := json.Marshal(input)
return string(json)
}
func JSONParse(input string) interface{} {
var output interface{}
json.Unmarshal([]byte(input), &output)
return output
} }

View File

@ -2,6 +2,8 @@ package aid
import ( import (
"os" "os"
"strconv"
"strings"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
) )
@ -22,6 +24,10 @@ type CS struct {
JWT struct { JWT struct {
Secret string Secret string
} }
Fortnite struct {
Season int
Build float64
}
} }
var ( var (
@ -74,4 +80,28 @@ func LoadConfig() {
if Config.JWT.Secret == "" { if Config.JWT.Secret == "" {
panic("JWT Secret is empty") panic("JWT Secret is empty")
} }
build, err := cfg.Section("fortnite").Key("build").Float64()
if err != nil {
panic("Fortnite Build is empty")
}
Config.Fortnite.Build = build
buildStr := strconv.FormatFloat(build, 'f', -1, 64)
if buildStr == "" {
panic("Fortnite Build is empty")
}
buildInfo := strings.Split(buildStr, ".")
if len(buildInfo) < 2 {
panic("Fortnite Build is invalid")
}
parsedSeason, err := strconv.Atoi(buildInfo[0])
if err != nil {
panic("Fortnite Season is invalid")
}
Config.Fortnite.Season = parsedSeason
} }

15
aid/time.go Normal file
View File

@ -0,0 +1,15 @@
package aid
import "time"
func TimeStartOfDay() string {
return time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 0, 0, 0, time.Now().Location()).Format("2006-01-02T15:04:05.999Z")
}
func TimeEndOfDay() string {
return time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 23, 59, 59, 999999999, time.Now().Location()).Format("2006-01-02T15:04:05.999Z")
}
func TimeEndOfWeekString() string {
return time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 23, 59, 59, 999999999, time.Now().Location()).AddDate(0, 0, 7).Format("2006-01-02T15:04:05.999Z")
}

View File

@ -22,4 +22,8 @@ host="0.0.0.0"
[jwt] [jwt]
; secret for jwt signing ; secret for jwt signing
secret="secret" secret="secret"
[fortnite]
; the game build to use
build=2.5

View File

@ -40,14 +40,14 @@ func PostOAuthToken(c *fiber.Ctx) error {
func PostOAuthTokenClientCredentials(c *fiber.Ctx, body *OAuthTokenBody) error { func PostOAuthTokenClientCredentials(c *fiber.Ctx, body *OAuthTokenBody) error {
credentials, err := aid.JWTSign(aid.JSON{ credentials, err := aid.JWTSign(aid.JSON{
"snow_id": 0, // custom "snow_id": 0, // custom
"t": "s", "t": "s",
"am": "client_credentials", // authorization method "am": "client_credentials", // authorization method
"ic": true, // internal client "ic": true, // internal client
"mver": false, // mobile version "mver": false, // mobile version
"clsvc": "snow", // client service "clsvc": "snow", // client service
"clid": c.IP(), // client id "clid": c.IP(), // client id
"jti": rand.Int63(), // jwt id "jti": rand.Int63(), // jwt id
"p": base64.StdEncoding.EncodeToString([]byte(c.IP())), // payload "p": base64.StdEncoding.EncodeToString([]byte(c.IP())), // payload
"hours_expire": 1, "hours_expire": 1,
"creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"), "creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"),
@ -86,20 +86,20 @@ func PostOAuthTokenPassword(c *fiber.Ctx, body *OAuthTokenBody) error {
} }
access, err := aid.JWTSign(aid.JSON{ access, err := aid.JWTSign(aid.JSON{
"snow_id": person.ID, // custom "snow_id": person.ID, // custom
"iai": person.ID, // account id "iai": person.ID, // account id
"dn": person.DisplayName, // display name "dn": person.DisplayName, // display name
"t": "s", "t": "s",
"am": "password", // authorization method "am": "password", // authorization method
"ic": true, // internal client "ic": true, // internal client
"mver": false, // mobile version "mver": false, // mobile version
"clsvc": "snow", // client service "clsvc": "snow", // client service
"app": "com.epicgames.fortnite", // app name "app": "com.epicgames.fortnite", // app name
"clid": c.IP(), // client id "clid": c.IP(), // client id
"dvid": "default", // device id "dvid": "default", // device id
"jti": rand.Int63(), // jwt id "jti": rand.Int63(), // jwt id
"p": base64.StdEncoding.EncodeToString([]byte(c.IP())), // payload "p": base64.StdEncoding.EncodeToString([]byte(c.IP())), // payload
"sec": 1, // security level "sec": 1, // security level
"hours_expire": 24, "hours_expire": 24,
"creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"), "creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"),
}) })
@ -108,12 +108,12 @@ func PostOAuthTokenPassword(c *fiber.Ctx, body *OAuthTokenBody) error {
} }
refresh, err := aid.JWTSign(aid.JSON{ refresh, err := aid.JWTSign(aid.JSON{
"snow_id": person.ID, // custom "snow_id": person.ID, // custom
"sub": person.ID, // account id "sub": person.ID, // account id
"clid": c.IP(), // client id "clid": c.IP(), // client id
"jti": rand.Int63(), // jwt id "jti": rand.Int63(), // jwt id
"t": "s", "t": "s",
"am": "refresh_token", // authorization method "am": "refresh_token", // authorization method
"hours_expire": 24, "hours_expire": 24,
"creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"), "creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"),
}) })

View File

@ -33,4 +33,46 @@ func GetVersionCheck(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(aid.JSON{ return c.Status(fiber.StatusOK).JSON(aid.JSON{
"type": "NO_UPDATE", "type": "NO_UPDATE",
}) })
}
func GetContentPages(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(aid.JSON{
"battlepassaboutmessages": aid.JSON{
"news": aid.JSON{
"messages": []aid.JSON{},
},
"lastModified": "0000-00-00T00:00:00.000Z",
},
"subgameselectdata": aid.JSON{
"saveTheWorldUnowned": aid.JSON{
"message": aid.JSON{
"title": "Co-op PvE",
"body": "Cooperative PvE storm-fighting adventure!",
"spotlight": false,
"hidden": true,
"messagetype": "normal",
},
},
"battleRoyale": aid.JSON{
"message": aid.JSON{
"title": "100 Player PvP",
"body": "100 Player PvP Battle Royale.\n\nPvE progress does not affect Battle Royale.",
"spotlight": false,
"hidden": true,
"messagetype": "normal",
},
},
"creative": aid.JSON{
"message": aid.JSON{
"title": "New Featured Islands!",
"body": "Your Island. Your Friends. Your Rules.\n\nDiscover new ways to play Fortnite, play community made games with friends and build your dream island.",
"spotlight": false,
"hidden": true,
"messagetype": "normal",
},
},
"lastModified": "0000-00-00T00:00:00.000Z",
},
"lastModified": "0000-00-00T00:00:00.000Z",
})
} }

View File

@ -1,6 +1,9 @@
package handlers package handlers
import ( import (
"strconv"
"time"
"github.com/ectrc/snow/aid" "github.com/ectrc/snow/aid"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
) )
@ -11,4 +14,51 @@ func GetLightswitchBulkStatus(c *fiber.Ctx) error {
"status": "UP", "status": "UP",
"banned": false, "banned": false,
}}) }})
}
func GetTimelineCalendar(c *fiber.Ctx) error {
events := []aid.JSON{
{
"activeUntil": aid.TimeEndOfWeekString(),
"activeSince": "0001-01-01T00:00:00Z",
"activeEventId": "EventFlag.Season" + strconv.Itoa(aid.Config.Fortnite.Season),
},
{
"activeUntil": aid.TimeEndOfWeekString(),
"activeSince": "0001-01-01T00:00:00Z",
"activeEventId": "EventFlag.LobbySeason" + strconv.Itoa(aid.Config.Fortnite.Season),
},
}
state := aid.JSON{
"seasonNumber": aid.Config.Fortnite.Season,
"seasonTemplateId": "AthenaSeason:AthenaSeason" + strconv.Itoa(aid.Config.Fortnite.Season),
"seasonBegin": time.Now().Add(-time.Hour * 24 * 7).Format("2006-01-02T15:04:05.000Z"),
"seasonEnd": time.Now().Add(time.Hour * 24 * 7).Format("2006-01-02T15:04:05.000Z"),
"seasonDisplayedEnd": time.Now().Add(time.Hour * 24 * 7).Format("2006-01-02T15:04:05.000Z"),
"activeStorefronts": []aid.JSON{},
"dailyStoreEnd": aid.TimeEndOfDay(),
"weeklyStoreEnd": aid.TimeEndOfWeekString(),
"sectionStoreEnds": aid.JSON{},
"stwEventStoreEnd": aid.TimeEndOfWeekString(),
"stwWeeklyStoreEnd": aid.TimeEndOfWeekString(),
}
client := aid.JSON{
"states": []aid.JSON{{
"activeEvents": events,
"state": state,
"validFrom": "0001-01-01T00:00:00Z",
}},
"cacheExpire": "9999-12-31T23:59:59.999Z",
}
return c.Status(fiber.StatusOK).JSON(aid.JSON{
"channels": aid.JSON{
"client-events": client,
},
"currentTime": time.Now().Format("2006-01-02T15:04:05.000Z"),
"cacheIntervalMins": 5,
"eventsTimeOffsetHrs": 0,
})
} }

View File

@ -1,6 +1,8 @@
package handlers package handlers
import ( import (
"strconv"
"strings"
"time" "time"
"github.com/ectrc/snow/aid" "github.com/ectrc/snow/aid"
@ -13,6 +15,8 @@ var (
profileActions = map[string]func(c *fiber.Ctx, person *p.Person, profile *p.Profile) error { profileActions = map[string]func(c *fiber.Ctx, person *p.Person, profile *p.Profile) error {
"QueryProfile": PostQueryProfileAction, "QueryProfile": PostQueryProfileAction,
"ClientQuestLogin": PostQueryProfileAction, "ClientQuestLogin": PostQueryProfileAction,
"MarkItemSeen": PostMarkItemSeenAction,
"EquipBattleRoyaleCustomization": PostEquipBattleRoyaleCustomizationAction,
} }
) )
@ -21,27 +25,33 @@ func PostProfileAction(c *fiber.Ctx) error {
if person == nil { if person == nil {
return c.Status(404).JSON(aid.ErrorBadRequest("No Account Found")) return c.Status(404).JSON(aid.ErrorBadRequest("No Account Found"))
} }
defer person.Save()
profile := person.GetProfileFromType(c.Query("profileId")) profile := person.GetProfileFromType(c.Query("profileId"))
if profile == nil { defer profile.ClearProfileChanges()
return c.Status(404).JSON(aid.ErrorBadRequest("No Profile Found"))
}
snapshot := profile.Snapshot() before := profile.Snapshot()
if action, ok := profileActions[c.Params("action")]; ok { if action, ok := profileActions[c.Params("action")]; ok {
err := action(c, person, profile) if err := action(c, person, profile); err != nil {
if err != nil {
return err return err
} }
} }
profile.Diff(snapshot) changes := profile.Diff(before)
profile.Revision++
aid.Print("Changes: " + strconv.Itoa(len(changes)))
aid.PrintJSON(changes)
revision, _ := strconv.Atoi(c.Query("rvn"))
if revision == -1 {
revision = profile.Revision
}
revision++
return c.Status(200).JSON(aid.JSON{ return c.Status(200).JSON(aid.JSON{
"profileId": profile.Type, "profileId": profile.Type,
"profileRevision": profile.Revision, "profileRevision": revision,
"profileCommandRevision": profile.Revision, "profileCommandRevision": revision,
"profileChangesBaseRevision": profile.Revision - 1, "profileChangesBaseRevision": revision - 1,
"profileChanges": profile.Changes, "profileChanges": profile.Changes,
"multiUpdate": []aid.JSON{}, "multiUpdate": []aid.JSON{},
"notifications": []aid.JSON{}, "notifications": []aid.JSON{},
@ -51,7 +61,66 @@ func PostProfileAction(c *fiber.Ctx) error {
} }
func PostQueryProfileAction(c *fiber.Ctx, person *p.Person, profile *p.Profile) error { func PostQueryProfileAction(c *fiber.Ctx, person *p.Person, profile *p.Profile) error {
profile.Changes = []interface{}{}
profile.CreateFullProfileUpdateChange() profile.CreateFullProfileUpdateChange()
return nil
}
func PostMarkItemSeenAction(c *fiber.Ctx, person *p.Person, profile *p.Profile) error {
var body struct {
ItemIds []string `json:"itemIds"`
}
err := c.BodyParser(&body)
if err != nil {
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Body"))
}
for _, itemId := range body.ItemIds {
item := profile.Items.GetItem(itemId)
if item == nil {
continue
}
item.HasSeen = true
}
return nil
}
func PostEquipBattleRoyaleCustomizationAction(c *fiber.Ctx, person *p.Person, profile *p.Profile) error {
var body struct {
SlotName string `json:"slotName"`
ItemToSlot string `json:"itemToSlot"`
IndexWithinSlot int `json:"indexWithinSlot"`
}
err := c.BodyParser(&body)
if err != nil {
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Body"))
}
item := profile.Items.GetItem(body.ItemToSlot)
if item == nil {
return c.Status(400).JSON(aid.ErrorBadRequest("Item not found"))
}
attr := profile.Attributes.GetAttributeByKey("favorite_" + strings.ToLower(body.SlotName))
if attr == nil {
return c.Status(400).JSON(aid.ErrorBadRequest("Attribute not found"))
}
switch body.SlotName {
case "Dance":
value := aid.JSONParse(attr.ValueJSON)
value.([]any)[body.IndexWithinSlot] = item.ID
attr.ValueJSON = aid.JSONStringify(value)
case "ItemWrap":
value := aid.JSONParse(attr.ValueJSON)
value.([]any)[body.IndexWithinSlot] = item.ID
attr.ValueJSON = aid.JSONStringify(value)
default:
attr.ValueJSON = aid.JSONStringify(item.ID)
}
return nil return nil
} }

View File

@ -17,7 +17,7 @@ func GetCloudStorageConfig(c *fiber.Ctx) error {
"epicAppName": "Live", "epicAppName": "Live",
"isAuthenticated": true, "isAuthenticated": true,
"disableV2": true, "disableV2": true,
"lastUpdated": "2021-01-01T00:00:00Z", "lastUpdated": "0000-00-00T00:00:00.000Z",
"transports": []string{}, "transports": []string{},
}) })
} }
@ -28,5 +28,17 @@ func GetCloudStorageFile(c *fiber.Ctx) error {
return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest) return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest)
} }
return c.Status(fiber.StatusOK).JSON(aid.JSON{})
}
func GetUserStorageFiles(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON([]aid.JSON{})
}
func GetUserStorageFile(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(aid.JSON{})
}
func PutUserStorageFile(c *fiber.Ctx) error {
return c.Status(fiber.StatusOK).JSON(aid.JSON{}) return c.Status(fiber.StatusOK).JSON(aid.JSON{})
} }

12
main.go
View File

@ -22,7 +22,6 @@ func init() {
} }
postgresStorage.Migrate(&storage.DB_Person{}, "Persons") postgresStorage.Migrate(&storage.DB_Person{}, "Persons")
postgresStorage.Migrate(&storage.DB_Loadout{}, "Loadouts")
postgresStorage.Migrate(&storage.DB_Profile{}, "Profiles") postgresStorage.Migrate(&storage.DB_Profile{}, "Profiles")
postgresStorage.Migrate(&storage.DB_Item{}, "Items") postgresStorage.Migrate(&storage.DB_Item{}, "Items")
postgresStorage.Migrate(&storage.DB_Gift{}, "Gifts") postgresStorage.Migrate(&storage.DB_Gift{}, "Gifts")
@ -35,12 +34,11 @@ func init() {
} }
storage.Repo = storage.NewStorage(device) storage.Repo = storage.NewStorage(device)
storage.Cache = storage.NewPersonsCacheMutex()
} }
func init() { func init() {
if aid.Config.Database.DropAllTables { if aid.Config.Database.DropAllTables {
person.NewFortnitePerson("ac", "ket") person.NewFortnitePerson("ac", "1")
} }
aid.PrintTime("Loading all persons from database", func() { aid.PrintTime("Loading all persons from database", func() {
@ -49,7 +47,7 @@ func init() {
} }
}) })
go storage.Cache.CacheKiller() // go storage.Cache.CacheKiller()
} }
func main() { func main() {
@ -59,6 +57,8 @@ func main() {
r.Use(aid.FiberLimiter()) r.Use(aid.FiberLimiter())
r.Use(aid.FiberCors()) r.Use(aid.FiberCors())
r.Get("/content/api/pages/fortnite-game", handlers.GetContentPages)
account := r.Group("/account/api") account := r.Group("/account/api")
account.Get("/public/account/:accountId", handlers.GetPublicAccount) account.Get("/public/account/:accountId", handlers.GetPublicAccount)
account.Get("/public/account/:accountId/externalAuths", handlers.GetPublicAccountExternalAuths) account.Get("/public/account/:accountId/externalAuths", handlers.GetPublicAccountExternalAuths)
@ -68,6 +68,7 @@ func main() {
fortnite := r.Group("/fortnite/api") fortnite := r.Group("/fortnite/api")
fortnite.Get("/receipts/v1/account/:accountId/receipts", handlers.GetAccountReceipts) fortnite.Get("/receipts/v1/account/:accountId/receipts", handlers.GetAccountReceipts)
fortnite.Get("/versioncheck/*", handlers.GetVersionCheck) fortnite.Get("/versioncheck/*", handlers.GetVersionCheck)
fortnite.Get("/calendar/v1/timeline", handlers.GetTimelineCalendar)
matchmaking := fortnite.Group("/matchmaking") matchmaking := fortnite.Group("/matchmaking")
matchmaking.Get("/session/findPlayer/:accountId", handlers.GetSessionFindPlayer) matchmaking.Get("/session/findPlayer/:accountId", handlers.GetSessionFindPlayer)
@ -76,6 +77,9 @@ func main() {
storage.Get("/system", handlers.GetCloudStorageFiles) storage.Get("/system", handlers.GetCloudStorageFiles)
storage.Get("/system/config", handlers.GetCloudStorageConfig) storage.Get("/system/config", handlers.GetCloudStorageConfig)
storage.Get("/system/:fileName", handlers.GetCloudStorageFile) storage.Get("/system/:fileName", handlers.GetCloudStorageFile)
storage.Get("/user/:accountId", handlers.GetUserStorageFiles)
storage.Get("/user/:accountId/:fileName", handlers.GetUserStorageFile)
storage.Put("/user/:accountId/:fileName", handlers.PutUserStorageFile)
game := fortnite.Group("/game/v2") game := fortnite.Group("/game/v2")
game.Post("/tryPlayOnPlatform/account/:accountId", handlers.PostTryPlayOnPlatform) game.Post("/tryPlayOnPlatform/account/:accountId", handlers.PostTryPlayOnPlatform)

View File

@ -1,59 +1,58 @@
package person package person
import ( import (
"encoding/json"
"reflect" "reflect"
"github.com/ectrc/snow/aid"
"github.com/ectrc/snow/storage" "github.com/ectrc/snow/storage"
"github.com/google/uuid" "github.com/google/uuid"
) )
type Attribute struct { type Attribute struct {
ID string ID string
Key string ProfileID string
Value interface{} Key string
ValueJSON string
Type string Type string
} }
func NewAttribute(key string, value interface{}) *Attribute { func NewAttribute(key string, value interface{}) *Attribute {
return &Attribute{ return &Attribute{
ID: uuid.New().String(), ID: uuid.New().String(),
Key: key, Key: key,
Value: value, ValueJSON: aid.JSONStringify(value),
Type: reflect.TypeOf(value).String(), Type: reflect.TypeOf(value).String(),
} }
} }
func FromDatabaseAttribute(db *storage.DB_PAttribute) *Attribute { func FromDatabaseAttribute(db *storage.DB_PAttribute) *Attribute {
var value interface{}
err := json.Unmarshal([]byte(db.ValueJSON), &value)
if err != nil {
return nil
}
return &Attribute{ return &Attribute{
ID: db.ID, ID: db.ID,
Key: db.Key, ProfileID: db.ProfileID,
Value: value, Key: db.Key,
Type: db.Type, ValueJSON: db.ValueJSON,
Type: db.Type,
} }
} }
func (a *Attribute) ToDatabase(profileId string) *storage.DB_PAttribute { func (a *Attribute) ToDatabase(profileId string) *storage.DB_PAttribute {
value, err := json.Marshal(a.Value)
if err != nil {
return nil
}
return &storage.DB_PAttribute{ return &storage.DB_PAttribute{
ID: a.ID, ID: a.ID,
ProfileID: profileId, ProfileID: profileId,
Key: a.Key, Key: a.Key,
ValueJSON: string(value), ValueJSON: a.ValueJSON,
Type: a.Type, Type: a.Type,
} }
} }
func (a *Attribute) Delete() { func (a *Attribute) Delete() {
storage.Repo.DeleteAttribute(a.ID) storage.Repo.DeleteAttribute(a.ID)
}
func (a *Attribute) Save() {
if a.ProfileID == "" {
aid.Print("error saving attribute", a.Key, "profile id is empty")
return
}
storage.Repo.SaveAttribute(a.ToDatabase(a.ProfileID))
} }

View File

@ -1,12 +1,17 @@
package storage package person
import ( import (
"fmt"
"sync" "sync"
"time" "time"
) )
var (
cache *PersonsCache
)
type CacheEntry struct { type CacheEntry struct {
Entry interface{} Entry *Person
LastAccessed time.Time LastAccessed time.Time
} }
@ -20,15 +25,15 @@ func NewPersonsCacheMutex() *PersonsCache {
func (m *PersonsCache) CacheKiller() { func (m *PersonsCache) CacheKiller() {
for { for {
if Cache.Count() == 0 { if m.Count() == 0 {
continue continue
} }
Cache.Range(func(key, value interface{}) bool { m.Range(func(key, value interface{}) bool {
cacheEntry := value.(*CacheEntry) cacheEntry := value.(*CacheEntry)
if time.Since(cacheEntry.LastAccessed) >= 30 * time.Minute { if time.Since(cacheEntry.LastAccessed) >= 30 * time.Minute {
Cache.Delete(key) m.Delete(key)
} }
return true return true
@ -38,20 +43,21 @@ func (m *PersonsCache) CacheKiller() {
} }
} }
func (m *PersonsCache) GetPerson(id string) *DB_Person { func (m *PersonsCache) GetPerson(id string) *Person {
if p, ok := m.Load(id); ok { if p, ok := m.Load(id); ok {
fmt.Println("Cache hit", id)
cacheEntry := p.(*CacheEntry) cacheEntry := p.(*CacheEntry)
return cacheEntry.Entry.(*DB_Person) return cacheEntry.Entry
} }
return nil return nil
} }
func (m *PersonsCache) GetPersonByDisplay(displayName string) *DB_Person { func (m *PersonsCache) GetPersonByDisplay(displayName string) *Person {
var person *DB_Person var person *Person
m.Range(func(key, value interface{}) bool { m.RangeEntry(func(key string, value *CacheEntry) bool {
if value.(*CacheEntry).Entry.(*DB_Person).DisplayName == displayName { if value.Entry.DisplayName == displayName {
person = value.(*CacheEntry).Entry.(*DB_Person) person = value.Entry
return false return false
} }
@ -61,7 +67,7 @@ func (m *PersonsCache) GetPersonByDisplay(displayName string) *DB_Person {
return person return person
} }
func (m *PersonsCache) SavePerson(p *DB_Person) { func (m *PersonsCache) SavePerson(p *Person) {
m.Store(p.ID, &CacheEntry{ m.Store(p.ID, &CacheEntry{
Entry: p, Entry: p,
LastAccessed: time.Now(), LastAccessed: time.Now(),
@ -72,9 +78,9 @@ func (m *PersonsCache) DeletePerson(id string) {
m.Delete(id) m.Delete(id)
} }
func (m *PersonsCache) RangePersons(f func(key string, value *DB_Person) bool) { func (m *PersonsCache) RangeEntry(f func(key string, value *CacheEntry) bool) {
m.Range(func(key, value interface{}) bool { m.Range(func(key, value interface{}) bool {
return f(key.(string), value.(*CacheEntry).Entry.(*DB_Person)) return f(key.(string), value.(*CacheEntry))
}) })
} }

View File

@ -7,22 +7,14 @@ func NewFortnitePerson(displayName string, key string) {
person.DisplayName = displayName person.DisplayName = displayName
person.AccessKey = key person.AccessKey = key
character := NewItem("AthenaCharacter:CID_001_Athena_Commando_F_Default", 1) person.AthenaProfile.Items.AddItem(NewItem("AthenaCharacter:CID_001_Athena_Commando_F_Default", 1))
pickaxe := NewItem("AthenaPickaxe:DefaultPickaxe", 1) person.AthenaProfile.Items.AddItem(NewItem("AthenaCharacter:CID_032_Athena_Commando_M_Medieval", 1))
glider := NewItem("AthenaGlider:DefaultGlider", 1) person.AthenaProfile.Items.AddItem(NewItem("AthenaCharacter:CID_033_Athena_Commando_F_Medieval", 1))
default_dance := NewItem("AthenaDance:EID_DanceMoves", 1) person.AthenaProfile.Items.AddItem(NewItem("AthenaPickaxe:DefaultPickaxe", 1))
person.AthenaProfile.Items.AddItem(NewItem("AthenaGlider:DefaultGlider", 1))
person.AthenaProfile.Items.AddItem(character) person.AthenaProfile.Items.AddItem(NewItem("AthenaDance:EID_DanceMoves", 1))
person.AthenaProfile.Items.AddItem(pickaxe)
person.AthenaProfile.Items.AddItem(glider)
person.AthenaProfile.Items.AddItem(default_dance)
person.CommonCoreProfile.Items.AddItem(NewItem("Currency:MtxPurchased", 0)) person.CommonCoreProfile.Items.AddItem(NewItem("Currency:MtxPurchased", 0))
person.Loadout.Character = character.ID
person.Loadout.Pickaxe = pickaxe.ID
person.Loadout.Glider = glider.ID
person.Loadout.Dances[0] = default_dance.ID
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("mfa_reward_claimed", true)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("mfa_reward_claimed", true))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp_overflow", 0)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("rested_xp_overflow", 0))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("lifetime_wins", 0)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("lifetime_wins", 0))
@ -32,7 +24,7 @@ func NewFortnitePerson(displayName string, key string) {
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("daily_rewards", []aid.JSON{})) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("daily_rewards", []aid.JSON{}))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("competitive_identity", aid.JSON{})) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("competitive_identity", aid.JSON{}))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_update", 0)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_update", 0))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_num", 2)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("season_num", aid.Config.Fortnite.Season))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("permissions", []aid.JSON{})) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("permissions", []aid.JSON{}))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("loadouts", []aid.JSON{})) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("loadouts", []aid.JSON{}))
@ -51,17 +43,17 @@ func NewFortnitePerson(displayName string, key string) {
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_level", 1)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_level", 1))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_xp", 0)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("book_xp", 0))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_character", person.Loadout.Character)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_character", person.AthenaProfile.Items.GetItemByTemplateID("AthenaCharacter:CID_001_Athena_Commando_F_Default").ID))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_backpack", person.Loadout.Backpack)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_backpack", ""))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_pickaxe", person.Loadout.Pickaxe)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_pickaxe", person.AthenaProfile.Items.GetItemByTemplateID("AthenaPickaxe:DefaultPickaxe").ID))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_glider", person.Loadout.Glider)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_glider", person.AthenaProfile.Items.GetItemByTemplateID("AthenaGlider:DefaultGlider").ID))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_skydivecontrail", person.Loadout.SkyDiveContrail)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_skydivecontrail", ""))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_dance", person.Loadout.Dances)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_dance", make([]string, 6)))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_itemwraps", person.Loadout.ItemWraps)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_itemwraps", make([]string, 7)))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_loadingscreen", person.Loadout.LoadingScreen)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_loadingscreen", ""))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_musicpack", person.Loadout.MusicPack)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("favorite_musicpack", ""))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("banner_icon", person.Loadout.BannerIcon)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("banner_icon", ""))
person.AthenaProfile.Attributes.AddAttribute(NewAttribute("banner_color", person.Loadout.BannerColor)) person.AthenaProfile.Attributes.AddAttribute(NewAttribute("banner_color", ""))
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mfa_enabled", true)) person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mfa_enabled", true))
person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mtx_affiliate", "")) person.CommonCoreProfile.Attributes.AddAttribute(NewAttribute("mtx_affiliate", ""))

View File

@ -9,24 +9,25 @@ import (
) )
type Gift struct { type Gift struct {
ID string ID string
ProfileID string
TemplateID string TemplateID string
Quantity int Quantity int
FromID string FromID string
GiftedAt int64 GiftedAt int64
Message string Message string
Loot []*Item Loot []*Item
} }
func NewGift(templateID string, quantity int, fromID string, message string) *Gift { func NewGift(templateID string, quantity int, fromID string, message string) *Gift {
return &Gift{ return &Gift{
ID: uuid.New().String(), ID: uuid.New().String(),
TemplateID: templateID, TemplateID: templateID,
Quantity: quantity, Quantity: quantity,
FromID: fromID, FromID: fromID,
GiftedAt: time.Now().Unix(), GiftedAt: time.Now().Unix(),
Message: message, Message: message,
Loot: []*Item{}, Loot: []*Item{},
} }
} }
@ -38,13 +39,14 @@ func FromDatabaseGift(gift *storage.DB_Gift) *Gift {
} }
return &Gift{ return &Gift{
ID: gift.ID, ID: gift.ID,
ProfileID: gift.ProfileID,
TemplateID: gift.TemplateID, TemplateID: gift.TemplateID,
Quantity: gift.Quantity, Quantity: gift.Quantity,
FromID: gift.FromID, FromID: gift.FromID,
GiftedAt: gift.GiftedAt, GiftedAt: gift.GiftedAt,
Message: gift.Message, Message: gift.Message,
Loot: loot, Loot: loot,
} }
} }
@ -101,19 +103,24 @@ func (g *Gift) ToDatabase(profileId string) *storage.DB_Gift {
} }
return &storage.DB_Gift{ return &storage.DB_Gift{
ID: g.ID,
ProfileID: profileId, ProfileID: profileId,
ID: g.ID,
TemplateID: g.TemplateID, TemplateID: g.TemplateID,
Quantity: g.Quantity, Quantity: g.Quantity,
FromID: g.FromID, FromID: g.FromID,
GiftedAt: g.GiftedAt, GiftedAt: g.GiftedAt,
Message: g.Message, Message: g.Message,
Loot: profileLoot, Loot: profileLoot,
} }
} }
func (g *Gift) Save() { func (g *Gift) Save() {
//storage.Repo.SaveGift(g.ToDatabase()) if g.ProfileID == "" {
aid.Print("error saving gift", g.ID, "no profile id")
return
}
storage.Repo.SaveGift(g.ToDatabase(g.ProfileID))
} }
func (g *Gift) Snapshot() GiftSnapshot { func (g *Gift) Snapshot() GiftSnapshot {
@ -124,12 +131,12 @@ func (g *Gift) Snapshot() GiftSnapshot {
} }
return GiftSnapshot{ return GiftSnapshot{
ID: g.ID, ID: g.ID,
TemplateID: g.TemplateID, TemplateID: g.TemplateID,
Quantity: g.Quantity, Quantity: g.Quantity,
FromID: g.FromID, FromID: g.FromID,
GiftedAt: g.GiftedAt, GiftedAt: g.GiftedAt,
Message: g.Message, Message: g.Message,
Loot: loot, Loot: loot,
} }
} }

View File

@ -7,39 +7,40 @@ import (
) )
type Item struct { type Item struct {
ID string ID string
TemplateID string ProfileID string
Quantity int TemplateID string
Favorite bool Quantity int
HasSeen bool Favorite bool
Variants []*VariantChannel HasSeen bool
Variants []*VariantChannel
ProfileType string ProfileType string
} }
func NewItem(templateID string, quantity int) *Item { func NewItem(templateID string, quantity int) *Item {
return &Item{ return &Item{
ID: uuid.New().String(), ID: uuid.New().String(),
TemplateID: templateID, TemplateID: templateID,
Quantity: quantity, Quantity: quantity,
Favorite: false, Favorite: false,
HasSeen: false, HasSeen: false,
Variants: []*VariantChannel{}, Variants: []*VariantChannel{},
} }
} }
func NewItemWithType(templateID string, quantity int, profile string) *Item { func NewItemWithType(templateID string, quantity int, profile string) *Item {
return &Item{ return &Item{
ID: uuid.New().String(), ID: uuid.New().String(),
TemplateID: templateID, TemplateID: templateID,
Quantity: quantity, Quantity: quantity,
Favorite: false, Favorite: false,
HasSeen: false, HasSeen: false,
Variants: []*VariantChannel{}, Variants: []*VariantChannel{},
ProfileType: profile, ProfileType: profile,
} }
} }
func FromDatabaseItem(item *storage.DB_Item, profileType *string) *Item { func FromDatabaseItem(item *storage.DB_Item) *Item {
variants := []*VariantChannel{} variants := []*VariantChannel{}
for _, variant := range item.Variants { for _, variant := range item.Variants {
@ -47,13 +48,12 @@ func FromDatabaseItem(item *storage.DB_Item, profileType *string) *Item {
} }
return &Item{ return &Item{
ID: item.ID, ID: item.ID,
TemplateID: item.TemplateID, TemplateID: item.TemplateID,
Quantity: item.Quantity, Quantity: item.Quantity,
Favorite: item.Favorite, Favorite: item.Favorite,
HasSeen: item.HasSeen, HasSeen: item.HasSeen,
Variants: variants, Variants: variants,
ProfileType: *profileType,
} }
} }
@ -114,10 +114,10 @@ func (i *Item) DeleteLoot() {
func (i *Item) NewChannel(channel string, owned []string, active string) *VariantChannel { func (i *Item) NewChannel(channel string, owned []string, active string) *VariantChannel {
return &VariantChannel{ return &VariantChannel{
ItemID: i.ID, ItemID: i.ID,
Channel: channel, Channel: channel,
Owned: owned, Owned: owned,
Active: active, Active: active,
} }
} }
@ -160,27 +160,32 @@ func (i *Item) ToDatabase(profileId string) *storage.DB_Item {
} }
return &storage.DB_Item{ return &storage.DB_Item{
ProfileID: profileId, ProfileID: profileId,
ID: i.ID, ID: i.ID,
TemplateID: i.TemplateID, TemplateID: i.TemplateID,
Quantity: i.Quantity, Quantity: i.Quantity,
Favorite: i.Favorite, Favorite: i.Favorite,
HasSeen: i.HasSeen, HasSeen: i.HasSeen,
Variants: variants, Variants: variants,
} }
} }
func (i *Item) Save() { func (i *Item) Save() {
//storage.Repo.SaveItem(i.ToDatabase()) if i.ProfileID == "" {
aid.Print("error saving item", i.ID, "no profile id")
return
}
storage.Repo.SaveItem(i.ToDatabase(i.ProfileID))
} }
func (i *Item) ToLootDatabase(giftId string) *storage.DB_Loot { func (i *Item) ToLootDatabase(giftId string) *storage.DB_Loot {
return &storage.DB_Loot{ return &storage.DB_Loot{
GiftID: giftId, GiftID: giftId,
ProfileType: i.ProfileType, ProfileType: i.ProfileType,
ID: i.ID, ID: i.ID,
TemplateID: i.TemplateID, TemplateID: i.TemplateID,
Quantity: i.Quantity, Quantity: i.Quantity,
} }
} }
@ -196,12 +201,12 @@ func (i *Item) Snapshot() ItemSnapshot {
} }
return ItemSnapshot{ return ItemSnapshot{
ID: i.ID, ID: i.ID,
TemplateID: i.TemplateID, TemplateID: i.TemplateID,
Quantity: i.Quantity, Quantity: i.Quantity,
Favorite: i.Favorite, Favorite: i.Favorite,
HasSeen: i.HasSeen, HasSeen: i.HasSeen,
Variants: variants, Variants: variants,
ProfileType: i.ProfileType, ProfileType: i.ProfileType,
} }
} }
@ -216,21 +221,21 @@ type VariantChannel struct {
func FromDatabaseVariant(variant *storage.DB_VariantChannel) *VariantChannel { func FromDatabaseVariant(variant *storage.DB_VariantChannel) *VariantChannel {
return &VariantChannel{ return &VariantChannel{
ID: variant.ID, ID: variant.ID,
ItemID: variant.ItemID, ItemID: variant.ItemID,
Channel: variant.Channel, Channel: variant.Channel,
Owned: variant.Owned, Owned: variant.Owned,
Active: variant.Active, Active: variant.Active,
} }
} }
func (v *VariantChannel) ToDatabase() *storage.DB_VariantChannel { func (v *VariantChannel) ToDatabase() *storage.DB_VariantChannel {
return &storage.DB_VariantChannel{ return &storage.DB_VariantChannel{
ID: v.ID, ID: v.ID,
ItemID: v.ItemID, ItemID: v.ItemID,
Channel: v.Channel, Channel: v.Channel,
Owned: v.Owned, Owned: v.Owned,
Active: v.Active, Active: v.Active,
} }
} }

View File

@ -1,19 +1,20 @@
package person package person
import ( import (
"time"
"github.com/ectrc/snow/storage" "github.com/ectrc/snow/storage"
"github.com/google/uuid" "github.com/google/uuid"
) )
type Person struct { type Person struct {
ID string ID string
DisplayName string DisplayName string
AccessKey string AccessKey string
AthenaProfile *Profile AthenaProfile *Profile
CommonCoreProfile *Profile CommonCoreProfile *Profile
CommonPublicProfile *Profile CommonPublicProfile *Profile
Profile0 *Profile Profile0 *Profile
Loadout *Loadout
} }
type Option struct { type Option struct {
@ -30,69 +31,52 @@ func NewPerson() *Person {
CommonCoreProfile: NewProfile("common_core"), CommonCoreProfile: NewProfile("common_core"),
CommonPublicProfile: NewProfile("common_public"), CommonPublicProfile: NewProfile("common_public"),
Profile0: NewProfile("profile0"), Profile0: NewProfile("profile0"),
Loadout: NewLoadout(),
} }
} }
func Find(personId string) *Person { func Find(personId string) *Person {
person := storage.Repo.GetPerson(personId) if cache == nil {
cache = NewPersonsCacheMutex()
}
cachedPerson := cache.GetPerson(personId)
if cachedPerson != nil {
return cachedPerson
}
person := storage.Repo.GetPersonFromDB(personId)
if person == nil { if person == nil {
return nil return nil
} }
loadout := FromDatabaseLoadout(&person.Loadout) return findHelper(person)
athenaProfile := NewProfile("athena")
commonCoreProfile := NewProfile("common_core")
commonPublicProfile := NewProfile("common_public")
profile0 := NewProfile("profile0")
for _, profile := range person.Profiles {
if profile.Type == "athena" {
athenaProfile.ID = profile.ID
athenaProfile = FromDatabaseProfile(&profile)
}
if profile.Type == "common_core" {
commonCoreProfile.ID = profile.ID
commonCoreProfile = FromDatabaseProfile(&profile)
}
if profile.Type == "common_public" {
commonPublicProfile.ID = profile.ID
commonPublicProfile = FromDatabaseProfile(&profile)
}
if profile.Type == "profile0" {
profile0.ID = profile.ID
profile0 = FromDatabaseProfile(&profile)
}
}
return &Person{
ID: person.ID,
DisplayName: person.DisplayName,
AccessKey: person.AccessKey,
AthenaProfile: athenaProfile,
CommonCoreProfile: commonCoreProfile,
CommonPublicProfile: commonPublicProfile,
Profile0: profile0,
Loadout: loadout,
}
} }
func FindByDisplay(displayName string) *Person { func FindByDisplay(displayName string) *Person {
person := storage.Repo.GetPersonByDisplay(displayName) if cache == nil {
cache = NewPersonsCacheMutex()
}
person := storage.Repo.GetPersonByDisplayFromDB(displayName)
if person == nil { if person == nil {
return nil return nil
} }
loadout := FromDatabaseLoadout(&person.Loadout) cachedPerson := cache.GetPerson(person.ID)
if cachedPerson != nil {
return cachedPerson
}
return findHelper(person)
}
func findHelper(databasePerson *storage.DB_Person) *Person {
athenaProfile := NewProfile("athena") athenaProfile := NewProfile("athena")
commonCoreProfile := NewProfile("common_core") commonCoreProfile := NewProfile("common_core")
commonPublicProfile := NewProfile("common_public") commonPublicProfile := NewProfile("common_public")
profile0 := NewProfile("profile0") profile0 := NewProfile("profile0")
for _, profile := range person.Profiles { for _, profile := range databasePerson.Profiles {
if profile.Type == "athena" { if profile.Type == "athena" {
athenaProfile.ID = profile.ID athenaProfile.ID = profile.ID
athenaProfile = FromDatabaseProfile(&profile) athenaProfile = FromDatabaseProfile(&profile)
@ -113,17 +97,23 @@ func FindByDisplay(displayName string) *Person {
profile0 = FromDatabaseProfile(&profile) profile0 = FromDatabaseProfile(&profile)
} }
} }
return &Person{ person := &Person{
ID: person.ID, ID: databasePerson.ID,
DisplayName: person.DisplayName, DisplayName: databasePerson.DisplayName,
AccessKey: person.AccessKey, AccessKey: databasePerson.AccessKey,
AthenaProfile: athenaProfile, AthenaProfile: athenaProfile,
CommonCoreProfile: commonCoreProfile, CommonCoreProfile: commonCoreProfile,
CommonPublicProfile: commonPublicProfile, CommonPublicProfile: commonPublicProfile,
Profile0: profile0, Profile0: profile0,
Loadout: loadout,
} }
cache.Store(person.ID, &CacheEntry{
Entry: person,
LastAccessed: time.Now(),
})
return person
} }
func AllFromDatabase() []*Person { func AllFromDatabase() []*Person {
@ -152,7 +142,8 @@ func (p *Person) GetProfileFromType(profileType string) *Profile {
} }
func (p *Person) Save() { func (p *Person) Save() {
storage.Repo.SavePerson(p.ToDatabase()) dbPerson := p.ToDatabase()
storage.Repo.SavePerson(dbPerson)
} }
func (p *Person) ToDatabase() *storage.DB_Person { func (p *Person) ToDatabase() *storage.DB_Person {
@ -160,7 +151,6 @@ func (p *Person) ToDatabase() *storage.DB_Person {
ID: p.ID, ID: p.ID,
DisplayName: p.DisplayName, DisplayName: p.DisplayName,
Profiles: []storage.DB_Profile{}, Profiles: []storage.DB_Profile{},
Loadout: *p.Loadout.ToDatabase(),
AccessKey: p.AccessKey, AccessKey: p.AccessKey,
} }
@ -178,7 +168,9 @@ func (p *Person) ToDatabase() *storage.DB_Person {
Type: profileType, Type: profileType,
Items: []storage.DB_Item{}, Items: []storage.DB_Item{},
Gifts: []storage.DB_Gift{}, Gifts: []storage.DB_Gift{},
Quests: []storage.DB_Quest{},
Attributes: []storage.DB_PAttribute{}, Attributes: []storage.DB_PAttribute{},
Revision: profile.Revision,
} }
profile.Items.RangeItems(func(id string, item *Item) bool { profile.Items.RangeItems(func(id string, item *Item) bool {
@ -225,7 +217,6 @@ func (p *Person) Snapshot() *PersonSnapshot {
ID: p.ID, ID: p.ID,
DisplayName: p.DisplayName, DisplayName: p.DisplayName,
AthenaProfile: *p.AthenaProfile.Snapshot(), AthenaProfile: *p.AthenaProfile.Snapshot(),
CommonCoreProfile:* p.CommonCoreProfile.Snapshot(), CommonCoreProfile: *p.CommonCoreProfile.Snapshot(),
Loadout: *p.Loadout,
} }
} }

View File

@ -10,10 +10,10 @@ import (
) )
type Profile struct { type Profile struct {
ID string ID string
PersonID string PersonID string
Items *ItemMutex Items *ItemMutex
Gifts *GiftMutex Gifts *GiftMutex
Quests *QuestMutex Quests *QuestMutex
Attributes *AttributeMutex Attributes *AttributeMutex
Type string Type string
@ -22,27 +22,28 @@ type Profile struct {
} }
func NewProfile(profile string) *Profile { func NewProfile(profile string) *Profile {
id := uuid.New().String()
return &Profile{ return &Profile{
ID: uuid.New().String(), ID: id,
PersonID: "", PersonID: "",
Items: NewItemMutex(profile), Items: NewItemMutex(&storage.DB_Profile{ID: id, Type: profile}),
Gifts: NewGiftMutex(), Gifts: NewGiftMutex(&storage.DB_Profile{ID: id, Type: profile}),
Quests: NewQuestMutex(), Quests: NewQuestMutex(&storage.DB_Profile{ID: id, Type: profile}),
Attributes: NewAttributeMutex(), Attributes: NewAttributeMutex(&storage.DB_Profile{ID: id, Type: profile}),
Type: profile, Type: profile,
Revision: 0, Revision: 0,
Changes: []interface{}{}, Changes: []interface{}{},
} }
} }
func FromDatabaseProfile(profile *storage.DB_Profile) *Profile { func FromDatabaseProfile(profile *storage.DB_Profile) *Profile {
items := NewItemMutex(profile.Type) items := NewItemMutex(profile)
gifts := NewGiftMutex() gifts := NewGiftMutex(profile)
quests := NewQuestMutex() quests := NewQuestMutex(profile)
attributes := NewAttributeMutex() attributes := NewAttributeMutex(profile)
for _, item := range profile.Items { for _, item := range profile.Items {
items.AddItem(FromDatabaseItem(&item, &profile.Type)) items.AddItem(FromDatabaseItem(&item))
} }
for _, gift := range profile.Gifts { for _, gift := range profile.Gifts {
@ -50,7 +51,7 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile {
} }
for _, quest := range profile.Quests { for _, quest := range profile.Quests {
quests.AddQuest(FromDatabaseQuest(&quest, &profile.Type)) quests.AddQuest(FromDatabaseQuest(&quest))
} }
for _, attribute := range profile.Attributes { for _, attribute := range profile.Attributes {
@ -64,14 +65,15 @@ func FromDatabaseProfile(profile *storage.DB_Profile) *Profile {
} }
return &Profile{ return &Profile{
ID: profile.ID, ID: profile.ID,
PersonID: profile.PersonID, PersonID: profile.PersonID,
Items: items, Items: items,
Gifts: gifts, Gifts: gifts,
Quests: quests, Quests: quests,
Attributes: attributes, Attributes: attributes,
Type: profile.Type, Type: profile.Type,
Revision: profile.Revision, Revision: profile.Revision,
Changes: []interface{}{},
} }
} }
@ -95,7 +97,7 @@ func (p *Profile) GenerateFortniteProfileEntry() aid.JSON {
}) })
p.Attributes.RangeAttributes(func(id string, attribute *Attribute) bool { p.Attributes.RangeAttributes(func(id string, attribute *Attribute) bool {
attributes[attribute.Key] = attribute.Value attributes[attribute.Key] = aid.JSONParse(attribute.ValueJSON)
return true return true
}) })
@ -114,7 +116,7 @@ func (p *Profile) GenerateFortniteProfileEntry() aid.JSON {
} }
func (p *Profile) Save() { func (p *Profile) Save() {
//storage.Repo.SaveProfile(p.ToDatabase()) // storage.Repo.SaveProfile(p.ToDatabase())
} }
func (p *Profile) Snapshot() *ProfileSnapshot { func (p *Profile) Snapshot() *ProfileSnapshot {
@ -144,18 +146,18 @@ func (p *Profile) Snapshot() *ProfileSnapshot {
}) })
return &ProfileSnapshot{ return &ProfileSnapshot{
ID: p.ID, ID: p.ID,
Items: items, Items: items,
Gifts: gifts, Gifts: gifts,
Quests: quests, Quests: quests,
Attributes: attributes, Attributes: attributes,
Type: p.Type, Type: p.Type,
Revision: p.Revision, Revision: p.Revision,
} }
} }
func (p *Profile) Diff(snapshot *ProfileSnapshot) []diff.Change { func (p *Profile) Diff(b *ProfileSnapshot) []diff.Change {
changes, err := diff.Diff(snapshot, p.Snapshot()) changes, err := diff.Diff(*b, *p.Snapshot())
if err != nil { if err != nil {
fmt.Printf("error diffing profile: %v\n", err) fmt.Printf("error diffing profile: %v\n", err)
return nil return nil
@ -200,7 +202,7 @@ func (p *Profile) Diff(snapshot *ProfileSnapshot) []diff.Change {
p.CreateStatModifiedChange(p.Attributes.GetAttribute(change.Path[1])) p.CreateStatModifiedChange(p.Attributes.GetAttribute(change.Path[1]))
} }
if change.Type == "update" && change.Path[2] == "Value" { if change.Type == "update" && change.Path[2] == "ValueJSON" {
p.CreateStatModifiedChange(p.Attributes.GetAttribute(change.Path[1])) p.CreateStatModifiedChange(p.Attributes.GetAttribute(change.Path[1]))
} }
} }
@ -209,6 +211,11 @@ func (p *Profile) Diff(snapshot *ProfileSnapshot) []diff.Change {
return changes return changes
} }
func (p *Profile) CreateAttribute(key string, value interface{}) *Attribute {
p.Attributes.AddAttribute(NewAttribute(key, value))
return p.Attributes.GetAttribute(key)
}
func (p *Profile) CreateStatModifiedChange(attribute *Attribute) { func (p *Profile) CreateStatModifiedChange(attribute *Attribute) {
if attribute == nil { if attribute == nil {
fmt.Println("error getting attribute from profile", attribute.ID) fmt.Println("error getting attribute from profile", attribute.ID)
@ -218,7 +225,7 @@ func (p *Profile) CreateStatModifiedChange(attribute *Attribute) {
p.Changes = append(p.Changes, StatModified{ p.Changes = append(p.Changes, StatModified{
ChangeType: "statModified", ChangeType: "statModified",
Name: attribute.Key, Name: attribute.Key,
Value: attribute.Value, Value: aid.JSONParse(attribute.ValueJSON),
}) })
} }
@ -302,78 +309,12 @@ func (p *Profile) CreateItemAttributeChangedChange(item *Item, attribute string)
} }
func (p *Profile) CreateFullProfileUpdateChange() { func (p *Profile) CreateFullProfileUpdateChange() {
p.Changes = append(p.Changes, FullProfileUpdate{ p.Changes = []interface{}{FullProfileUpdate{
ChangeType: "fullProfileUpdate", ChangeType: "fullProfileUpdate",
Profile: p.GenerateFortniteProfileEntry(), Profile: p.GenerateFortniteProfileEntry(),
}) }}
} }
type Loadout struct { func (p *Profile) ClearProfileChanges() {
ID string p.Changes = []interface{}{}
Character string
Backpack string
Pickaxe string
Glider string
Dances []string
ItemWraps []string
LoadingScreen string
SkyDiveContrail string
MusicPack string
BannerIcon string
BannerColor string
}
func NewLoadout() *Loadout {
return &Loadout{
ID: uuid.New().String(),
Character: "",
Backpack: "",
Pickaxe: "",
Glider: "",
Dances: make([]string, 6),
ItemWraps: make([]string, 7),
LoadingScreen: "",
SkyDiveContrail: "",
MusicPack: "",
BannerIcon: "",
BannerColor: "",
}
}
func FromDatabaseLoadout(l *storage.DB_Loadout) *Loadout {
return &Loadout{
ID: l.ID,
Character: l.Character,
Backpack: l.Backpack,
Pickaxe: l.Pickaxe,
Glider: l.Glider,
Dances: l.Dances,
ItemWraps: l.ItemWraps,
LoadingScreen: l.LoadingScreen,
SkyDiveContrail: l.SkyDiveContrail,
MusicPack: l.MusicPack,
BannerIcon: l.BannerIcon,
BannerColor: l.BannerColor,
}
}
func (l *Loadout) ToDatabase() *storage.DB_Loadout {
return &storage.DB_Loadout{
ID: l.ID,
Character: l.Character,
Backpack: l.Backpack,
Pickaxe: l.Pickaxe,
Glider: l.Glider,
Dances: l.Dances,
ItemWraps: l.ItemWraps,
LoadingScreen: l.LoadingScreen,
SkyDiveContrail: l.SkyDiveContrail,
MusicPack: l.MusicPack,
BannerIcon: l.BannerIcon,
BannerColor: l.BannerColor,
}
}
func (l *Loadout) Save() {
//storage.Repo.SaveLoadout(l.ToDatabase())
} }

View File

@ -7,46 +7,48 @@ import (
) )
type Quest struct { type Quest struct {
ID string ID string
TemplateID string ProfileID string
State string TemplateID string
Objectives []string State string
Objectives []string
ObjectiveCounts []int64 ObjectiveCounts []int64
BundleID string BundleID string
ScheduleID string ScheduleID string
} }
func NewQuest(templateID string, bundleID string, scheduleID string) *Quest { func NewQuest(templateID string, bundleID string, scheduleID string) *Quest {
return &Quest{ return &Quest{
ID: uuid.New().String(), ID: uuid.New().String(),
TemplateID: templateID, TemplateID: templateID,
State: "Active", State: "Active",
Objectives: []string{}, Objectives: []string{},
ObjectiveCounts: []int64{}, ObjectiveCounts: []int64{},
BundleID: bundleID, BundleID: bundleID,
ScheduleID: scheduleID, ScheduleID: scheduleID,
} }
} }
func NewDailyQuest(templateID string) *Quest { func NewDailyQuest(templateID string) *Quest {
return &Quest{ return &Quest{
ID: uuid.New().String(), ID: uuid.New().String(),
TemplateID: templateID, TemplateID: templateID,
State: "Active", State: "Active",
Objectives: []string{}, Objectives: []string{},
ObjectiveCounts: []int64{}, ObjectiveCounts: []int64{},
} }
} }
func FromDatabaseQuest(quest *storage.DB_Quest, profileType *string) *Quest { func FromDatabaseQuest(quest *storage.DB_Quest) *Quest {
return &Quest{ return &Quest{
ID: quest.ID, ID: quest.ID,
TemplateID: quest.TemplateID, ProfileID: quest.ProfileID,
State: quest.State, TemplateID: quest.TemplateID,
Objectives: quest.Objectives, State: quest.State,
Objectives: quest.Objectives,
ObjectiveCounts: quest.ObjectiveCounts, ObjectiveCounts: quest.ObjectiveCounts,
BundleID: quest.BundleID, BundleID: quest.BundleID,
ScheduleID: quest.ScheduleID, ScheduleID: quest.ScheduleID,
} }
} }
@ -126,17 +128,17 @@ func (q *Quest) RemoveObjective(objective string) {
func (q *Quest) ToDatabase(profileId string) *storage.DB_Quest { func (q *Quest) ToDatabase(profileId string) *storage.DB_Quest {
return &storage.DB_Quest{ return &storage.DB_Quest{
ProfileID: profileId, ID: q.ID,
ID: q.ID, ProfileID: profileId,
TemplateID: q.TemplateID, TemplateID: q.TemplateID,
State: q.State, State: q.State,
Objectives: q.Objectives, Objectives: q.Objectives,
ObjectiveCounts: q.ObjectiveCounts, ObjectiveCounts: q.ObjectiveCounts,
BundleID: q.BundleID, BundleID: q.BundleID,
ScheduleID: q.ScheduleID, ScheduleID: q.ScheduleID,
} }
} }
func (q *Quest) Save() { func (q *Quest) Save() {
//storage.Repo.SaveQuest(q.ToDatabase()) storage.Repo.SaveQuest(q.ToDatabase(q.ProfileID))
} }

View File

@ -5,7 +5,6 @@ type PersonSnapshot struct {
DisplayName string DisplayName string
AthenaProfile ProfileSnapshot AthenaProfile ProfileSnapshot
CommonCoreProfile ProfileSnapshot CommonCoreProfile ProfileSnapshot
Loadout Loadout
} }
type ProfileSnapshot struct { type ProfileSnapshot struct {

View File

@ -2,23 +2,28 @@ package person
import ( import (
"sync" "sync"
"github.com/ectrc/snow/storage"
) )
type ItemMutex struct { type ItemMutex struct {
sync.Map sync.Map
ProfileType string ProfileType string
ProfileID string
} }
func NewItemMutex(profile string) *ItemMutex { func NewItemMutex(profile *storage.DB_Profile) *ItemMutex {
return &ItemMutex{ return &ItemMutex{
ProfileType: profile, ProfileType: profile.Type,
ProfileID: profile.ID,
} }
} }
func (m *ItemMutex) AddItem(item *Item) { func (m *ItemMutex) AddItem(item *Item) {
item.ProfileType = m.ProfileType item.ProfileType = m.ProfileType
item.ProfileID = m.ProfileID
m.Store(item.ID, item) m.Store(item.ID, item)
// storage.Repo.SaveItem(item) storage.Repo.SaveItem(item.ToDatabase(m.ProfileID))
} }
func (m *ItemMutex) DeleteItem(id string) { func (m *ItemMutex) DeleteItem(id string) {
@ -29,7 +34,7 @@ func (m *ItemMutex) DeleteItem(id string) {
item.Delete() item.Delete()
m.Delete(id) m.Delete(id)
// storage.Repo.DeleteItem(id) storage.Repo.DeleteItem(id)
} }
func (m *ItemMutex) GetItem(id string) *Item { func (m *ItemMutex) GetItem(id string) *Item {
@ -74,20 +79,25 @@ func (m *ItemMutex) Count() int {
type GiftMutex struct { type GiftMutex struct {
sync.Map sync.Map
ProfileType string ProfileType string
ProfileID string
} }
func NewGiftMutex() *GiftMutex { func NewGiftMutex(profile *storage.DB_Profile) *GiftMutex {
return &GiftMutex{} return &GiftMutex{
ProfileType: profile.Type,
ProfileID: profile.ID,
}
} }
func (m *GiftMutex) AddGift(gift *Gift) { func (m *GiftMutex) AddGift(gift *Gift) {
gift.ProfileID = m.ProfileID
m.Store(gift.ID, gift) m.Store(gift.ID, gift)
// storage.Repo.SaveGift(gift) storage.Repo.SaveGift(gift.ToDatabase(m.ProfileID))
} }
func (m *GiftMutex) DeleteGift(id string) { func (m *GiftMutex) DeleteGift(id string) {
m.Delete(id) m.Delete(id)
// storage.Repo.DeleteGift(id) storage.Repo.DeleteGift(id)
} }
func (m *GiftMutex) GetGift(id string) *Gift { func (m *GiftMutex) GetGift(id string) *Gift {
@ -116,20 +126,26 @@ func (m *GiftMutex) Count() int {
type QuestMutex struct { type QuestMutex struct {
sync.Map sync.Map
ProfileType string
ProfileID string
} }
func NewQuestMutex() *QuestMutex { func NewQuestMutex(profile *storage.DB_Profile) *QuestMutex {
return &QuestMutex{} return &QuestMutex{
ProfileType: profile.Type,
ProfileID: profile.ID,
}
} }
func (m *QuestMutex) AddQuest(quest *Quest) { func (m *QuestMutex) AddQuest(quest *Quest) {
quest.ProfileID = m.ProfileID
m.Store(quest.ID, quest) m.Store(quest.ID, quest)
// storage.Repo.SaveQuest(quest) storage.Repo.SaveQuest(quest.ToDatabase(m.ProfileID))
} }
func (m *QuestMutex) DeleteQuest(id string) { func (m *QuestMutex) DeleteQuest(id string) {
m.Delete(id) m.Delete(id)
// storage.Repo.DeleteQuest(id) storage.Repo.DeleteQuest(id)
} }
func (m *QuestMutex) GetQuest(id string) *Quest { func (m *QuestMutex) GetQuest(id string) *Quest {
@ -158,20 +174,25 @@ func (m *QuestMutex) Count() int {
type AttributeMutex struct { type AttributeMutex struct {
sync.Map sync.Map
ProfileType string
ProfileID string
} }
func NewAttributeMutex() *AttributeMutex { func NewAttributeMutex(profile *storage.DB_Profile) *AttributeMutex {
return &AttributeMutex{} return &AttributeMutex{
ProfileID: profile.ID,
}
} }
func (m *AttributeMutex) AddAttribute(attribute *Attribute) { func (m *AttributeMutex) AddAttribute(attribute *Attribute) {
attribute.ProfileID = m.ProfileID
m.Store(attribute.ID, attribute) m.Store(attribute.ID, attribute)
// storage.Repo.SaveAttribute(key, value) storage.Repo.SaveAttribute(attribute.ToDatabase(m.ProfileID))
} }
func (m *AttributeMutex) DeleteAttribute(id string) { func (m *AttributeMutex) DeleteAttribute(id string) {
m.Delete(id) m.Delete(id)
// storage.Repo.DeleteAttribute(key) storage.Repo.DeleteAttribute(id)
} }
func (m *AttributeMutex) GetAttribute(id string) *Attribute { func (m *AttributeMutex) GetAttribute(id string) *Attribute {

View File

@ -88,26 +88,63 @@ func (s *PostgresStorage) SavePerson(person *DB_Person) {
s.Postgres.Save(person) s.Postgres.Save(person)
} }
func (s *PostgresStorage) DeletePerson(personId string) {
s.Postgres.Delete(&DB_Person{}, "id = ?", personId)
}
func (s *PostgresStorage) SaveProfile(profile *DB_Profile) {
s.Postgres.Save(profile)
}
func (s *PostgresStorage) DeleteProfile(profileId string) {
s.Postgres.Delete(&DB_Profile{}, "id = ?", profileId)
}
func (s *PostgresStorage) SaveItem(item *DB_Item) {
s.Postgres.Save(item)
}
func (s *PostgresStorage) DeleteItem(itemId string) { func (s *PostgresStorage) DeleteItem(itemId string) {
s.Postgres.Delete(&DB_Item{}, "id = ?", itemId) s.Postgres.Delete(&DB_Item{}, "id = ?", itemId)
} }
func (s *PostgresStorage) SaveVariant(variant *DB_VariantChannel) {
s.Postgres.Save(variant)
}
func (s *PostgresStorage) DeleteVariant(variantId string) { func (s *PostgresStorage) DeleteVariant(variantId string) {
s.Postgres.Delete(&DB_VariantChannel{}, "id = ?", variantId) s.Postgres.Delete(&DB_VariantChannel{}, "id = ?", variantId)
} }
func (s *PostgresStorage) SaveQuest(quest *DB_Quest) {
s.Postgres.Save(quest)
}
func (s *PostgresStorage) DeleteQuest(questId string) { func (s *PostgresStorage) DeleteQuest(questId string) {
s.Postgres.Delete(&DB_Quest{}, "id = ?", questId) s.Postgres.Delete(&DB_Quest{}, "id = ?", questId)
} }
func (s *PostgresStorage) SaveLoot(loot *DB_Loot) {
s.Postgres.Save(loot)
}
func (s *PostgresStorage) DeleteLoot(lootId string) { func (s *PostgresStorage) DeleteLoot(lootId string) {
s.Postgres.Delete(&DB_Loot{}, "id = ?", lootId) s.Postgres.Delete(&DB_Loot{}, "id = ?", lootId)
} }
func (s *PostgresStorage) SaveGift(gift *DB_Gift) {
s.Postgres.Save(gift)
}
func (s *PostgresStorage) DeleteGift(giftId string) { func (s *PostgresStorage) DeleteGift(giftId string) {
s.Postgres.Delete(&DB_Gift{}, "id = ?", giftId) s.Postgres.Delete(&DB_Gift{}, "id = ?", giftId)
} }
func (s *PostgresStorage) DeleteAttribute(attributeId string) { func (s *PostgresStorage) DeleteAttribute(attributeId string) {
s.Postgres.Delete(&DB_PAttribute{}, "id = ?", attributeId) s.Postgres.Delete(&DB_PAttribute{}, "id = ?", attributeId)
}
func (s *PostgresStorage) SaveAttribute(attribute *DB_PAttribute) {
aid.Print("saving attribute", attribute.Key, attribute.ValueJSON)
s.Postgres.Save(attribute)
} }

View File

@ -1,8 +1,7 @@
package storage package storage
var ( var (
Repo *Repository Repo *Repository
Cache *PersonsCache
) )
type Storage interface { type Storage interface {
@ -13,11 +12,25 @@ type Storage interface {
GetAllPersons() []*DB_Person GetAllPersons() []*DB_Person
SavePerson(person *DB_Person) SavePerson(person *DB_Person)
SaveProfile(profile *DB_Profile)
DeleteProfile(profileId string)
SaveItem(item *DB_Item)
DeleteItem(itemId string) DeleteItem(itemId string)
SaveVariant(variant *DB_VariantChannel)
DeleteVariant(variantId string) DeleteVariant(variantId string)
SaveQuest(quest *DB_Quest)
DeleteQuest(questId string) DeleteQuest(questId string)
SaveLoot(loot *DB_Loot)
DeleteLoot(lootId string) DeleteLoot(lootId string)
SaveGift(gift *DB_Gift)
DeleteGift(giftId string) DeleteGift(giftId string)
SaveAttribute(attribute *DB_PAttribute)
DeleteAttribute(attributeId string) DeleteAttribute(attributeId string)
} }
@ -31,30 +44,18 @@ func NewStorage(s Storage) *Repository {
} }
} }
func (r *Repository) GetPerson(personId string) *DB_Person { func (r *Repository) GetPersonFromDB(personId string) *DB_Person {
cachePerson := Cache.GetPerson(personId)
if cachePerson != nil {
return cachePerson
}
storagePerson := r.Storage.GetPerson(personId) storagePerson := r.Storage.GetPerson(personId)
if storagePerson != nil { if storagePerson != nil {
Cache.SavePerson(storagePerson)
return storagePerson return storagePerson
} }
return nil return nil
} }
func (r *Repository) GetPersonByDisplay(displayName string) *DB_Person { func (r *Repository) GetPersonByDisplayFromDB(displayName string) *DB_Person {
cachePerson := Cache.GetPersonByDisplay(displayName)
if cachePerson != nil {
return cachePerson
}
storagePerson := r.Storage.GetPersonByDisplay(displayName) storagePerson := r.Storage.GetPersonByDisplay(displayName)
if storagePerson != nil { if storagePerson != nil {
Cache.SavePerson(storagePerson)
return storagePerson return storagePerson
} }
@ -66,30 +67,61 @@ func (r *Repository) GetAllPersons() []*DB_Person {
} }
func (r *Repository) SavePerson(person *DB_Person) { func (r *Repository) SavePerson(person *DB_Person) {
Cache.SavePerson(person)
r.Storage.SavePerson(person) r.Storage.SavePerson(person)
} }
func (r *Repository) SaveProfile(profile *DB_Profile) {
r.Storage.SaveProfile(profile)
}
func (r *Repository) DeleteProfile(profileId string) {
r.Storage.DeleteProfile(profileId)
}
func (r *Repository) SaveItem(item *DB_Item) {
r.Storage.SaveItem(item)
}
func (r *Repository) DeleteItem(itemId string) { func (r *Repository) DeleteItem(itemId string) {
r.Storage.DeleteItem(itemId) r.Storage.DeleteItem(itemId)
} }
func (r *Repository) SaveVariant(variant *DB_VariantChannel) {
r.Storage.SaveVariant(variant)
}
func (r *Repository) DeleteVariant(variantId string) { func (r *Repository) DeleteVariant(variantId string) {
r.Storage.DeleteVariant(variantId) r.Storage.DeleteVariant(variantId)
} }
func (r *Repository) SaveQuest(quest *DB_Quest) {
r.Storage.SaveQuest(quest)
}
func (r *Repository) DeleteQuest(questId string) { func (r *Repository) DeleteQuest(questId string) {
r.Storage.DeleteQuest(questId) r.Storage.DeleteQuest(questId)
} }
func (r *Repository) SaveLoot(loot *DB_Loot) {
r.Storage.SaveLoot(loot)
}
func (r *Repository) DeleteLoot(lootId string) { func (r *Repository) DeleteLoot(lootId string) {
r.Storage.DeleteLoot(lootId) r.Storage.DeleteLoot(lootId)
} }
func (r *Repository) SaveGift(gift *DB_Gift) {
r.Storage.SaveGift(gift)
}
func (r *Repository) DeleteGift(giftId string) { func (r *Repository) DeleteGift(giftId string) {
r.Storage.DeleteGift(giftId) r.Storage.DeleteGift(giftId)
} }
func (r *Repository) SaveAttribute(attribute *DB_PAttribute) {
r.Storage.SaveAttribute(attribute)
}
func (r *Repository) DeleteAttribute(attributeId string) { func (r *Repository) DeleteAttribute(attributeId string) {
r.Storage.DeleteAttribute(attributeId) r.Storage.DeleteAttribute(attributeId)
} }

View File

@ -7,45 +7,24 @@ type Tabler interface {
} }
type DB_Person struct { type DB_Person struct {
ID string ID string
DisplayName string DisplayName string
AccessKey string AccessKey string
Profiles []DB_Profile `gorm:"foreignkey:PersonID"` Profiles []DB_Profile `gorm:"foreignkey:PersonID"`
Loadout DB_Loadout `gorm:"foreignkey:PersonID"`
} }
func (DB_Person) TableName() string { func (DB_Person) TableName() string {
return "Persons" return "Persons"
} }
type DB_Loadout struct {
ID string `gorm:"primary_key"`
PersonID string
Character string
Backpack string
Pickaxe string
Glider string
Dances pq.StringArray `gorm:"type:text[]"`
ItemWraps pq.StringArray `gorm:"type:text[]"`
LoadingScreen string
SkyDiveContrail string
MusicPack string
BannerIcon string
BannerColor string
}
func (DB_Loadout) TableName() string {
return "Loadouts"
}
type DB_Profile struct { type DB_Profile struct {
ID string `gorm:"primary_key"` ID string `gorm:"primary_key"`
PersonID string PersonID string
Items []DB_Item `gorm:"foreignkey:ProfileID"` Items []DB_Item `gorm:"foreignkey:ProfileID"`
Gifts []DB_Gift `gorm:"foreignkey:ProfileID"` Gifts []DB_Gift `gorm:"foreignkey:ProfileID"`
Quests []DB_Quest `gorm:"foreignkey:ProfileID"` Quests []DB_Quest `gorm:"foreignkey:ProfileID"`
Attributes []DB_PAttribute `gorm:"foreignkey:ProfileID"` Attributes []DB_PAttribute `gorm:"foreignkey:ProfileID"`
Type string Type string
Revision int Revision int
} }
@ -54,11 +33,11 @@ func (DB_Profile) TableName() string {
} }
type DB_PAttribute struct { type DB_PAttribute struct {
ID string `gorm:"primary_key"` ID string `gorm:"primary_key"`
ProfileID string ProfileID string
Key string Key string
ValueJSON string ValueJSON string
Type string Type string
} }
func (DB_PAttribute) TableName() string { func (DB_PAttribute) TableName() string {
@ -66,13 +45,13 @@ func (DB_PAttribute) TableName() string {
} }
type DB_Item struct { type DB_Item struct {
ID string `gorm:"primary_key"` ID string `gorm:"primary_key"`
ProfileID string ProfileID string
TemplateID string TemplateID string
Quantity int Quantity int
Favorite bool Favorite bool
HasSeen bool HasSeen bool
Variants []DB_VariantChannel `gorm:"foreignkey:ItemID"` Variants []DB_VariantChannel `gorm:"foreignkey:ItemID"`
} }
func (DB_Item) TableName() string { func (DB_Item) TableName() string {
@ -80,11 +59,11 @@ func (DB_Item) TableName() string {
} }
type DB_VariantChannel struct { type DB_VariantChannel struct {
ID string `gorm:"primary_key"` ID string `gorm:"primary_key"`
ItemID string ItemID string
Channel string Channel string
Owned pq.StringArray `gorm:"type:text[]"` Owned pq.StringArray `gorm:"type:text[]"`
Active string Active string
} }
func (DB_VariantChannel) TableName() string { func (DB_VariantChannel) TableName() string {
@ -92,13 +71,13 @@ func (DB_VariantChannel) TableName() string {
} }
type DB_Quest struct { type DB_Quest struct {
ID string `gorm:"primary_key"` ID string `gorm:"primary_key"`
ProfileID string ProfileID string
TemplateID string TemplateID string
State string State string
Objectives pq.StringArray `gorm:"type:text[]"` Objectives pq.StringArray `gorm:"type:text[]"`
ObjectiveCounts pq.Int64Array `gorm:"type:bigint[]"` ObjectiveCounts pq.Int64Array `gorm:"type:bigint[]"`
BundleID string BundleID string
ScheduleID string ScheduleID string
} }
@ -107,14 +86,14 @@ func (DB_Quest) TableName() string {
} }
type DB_Gift struct { type DB_Gift struct {
ID string `gorm:"primary_key"` ID string `gorm:"primary_key"`
ProfileID string ProfileID string
TemplateID string TemplateID string
Quantity int Quantity int
FromID string FromID string
GiftedAt int64 GiftedAt int64
Message string Message string
Loot []DB_Loot `gorm:"foreignkey:GiftID"` Loot []DB_Loot `gorm:"foreignkey:GiftID"`
} }
func (DB_Gift) TableName() string { func (DB_Gift) TableName() string {
@ -122,11 +101,11 @@ func (DB_Gift) TableName() string {
} }
type DB_Loot struct { type DB_Loot struct {
ID string `gorm:"primary_key"` ID string `gorm:"primary_key"`
GiftID string GiftID string
TemplateID string TemplateID string
Quantity int Quantity int
ProfileType string ProfileType string
} }
func (DB_Loot) TableName() string { func (DB_Loot) TableName() string {