@ -43,7 +43,7 @@ import (
func handleAccountInfo ( w http . ResponseWriter , r * http . Request ) {
func handleAccountInfo ( w http . ResponseWriter , r * http . Request ) {
uuid , err := uuidFromRequest ( r )
uuid , err := uuidFromRequest ( r )
if err != nil {
if err != nil {
httpError ( w , r , err , http . Status BadRequest )
httpError ( w , r , err , http . Status Unauthorized )
return
return
}
}
@ -103,7 +103,7 @@ func handleAccountChangePW(w http.ResponseWriter, r *http.Request) {
uuid , err := uuidFromRequest ( r )
uuid , err := uuidFromRequest ( r )
if err != nil {
if err != nil {
httpError ( w , r , err , http . Status BadRequest )
httpError ( w , r , err , http . Status Unauthorized )
return
return
}
}
@ -125,7 +125,8 @@ func handleAccountLogout(w http.ResponseWriter, r *http.Request) {
err = account . Logout ( token )
err = account . Logout ( token )
if err != nil {
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
// also possible for InternalServerError but that's unlikely unless the server blew up
httpError ( w , r , err , http . StatusUnauthorized )
return
return
}
}
@ -146,20 +147,22 @@ func handleGameClassicSessionCount(w http.ResponseWriter, r *http.Request) {
w . Write ( [ ] byte ( strconv . Itoa ( classicSessionCount ) ) )
w . Write ( [ ] byte ( strconv . Itoa ( classicSessionCount ) ) )
}
}
func handle Get SessionData ( w http . ResponseWriter , r * http . Request ) {
func handle Session( w http . ResponseWriter , r * http . Request ) {
uuid , err := uuidFromRequest ( r )
uuid , err := uuidFromRequest ( r )
if err != nil {
if err != nil {
httpError ( w , r , err , http . Status BadRequest )
httpError ( w , r , err , http . Status Unauthorized )
return
return
}
}
var slot int
slot , err := strconv . Atoi ( r . URL . Query ( ) . Get ( "slot" ) )
if r . URL . Query ( ) . Has ( "slot" ) {
slot , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "slot" ) )
if err != nil {
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
httpError ( w , r , err , http . StatusBadRequest )
return
return
}
}
if slot < 0 || slot >= defs . SessionSlotCount {
httpError ( w , r , fmt . Errorf ( "slot id %d out of range" , slot ) , http . StatusBadRequest )
return
}
}
if ! r . URL . Query ( ) . Has ( "clientSessionId" ) {
if ! r . URL . Query ( ) . Has ( "clientSessionId" ) {
@ -173,58 +176,9 @@ func handleGetSessionData(w http.ResponseWriter, r *http.Request) {
return
return
}
}
var save any
switch r . PathValue ( "action" ) {
save , err = savedata . Get ( uuid , 1 , slot )
case "get" :
if errors . Is ( err , sql . ErrNoRows ) {
save , err := savedata . GetSession ( uuid , slot )
http . Error ( w , err . Error ( ) , http . StatusNotFound )
return
}
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
return
}
writeJSON ( w , r , save )
}
const legacyClientSessionId = "LEGACY_CLIENT"
func legacyHandleGetSaveData ( w http . ResponseWriter , r * http . Request ) {
uuid , err := uuidFromRequest ( r )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
datatype := - 1
if r . URL . Query ( ) . Has ( "datatype" ) {
datatype , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "datatype" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
}
var slot int
if r . URL . Query ( ) . Has ( "slot" ) {
slot , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "slot" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
}
var save any
if datatype == 0 {
err = db . UpdateActiveSession ( uuid , legacyClientSessionId ) // we dont have a client id
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to update active session: %s" , err ) , http . StatusBadRequest )
return
}
}
save , err = savedata . Get ( uuid , datatype , slot )
if errors . Is ( err , sql . ErrNoRows ) {
if errors . Is ( err , sql . ErrNoRows ) {
http . Error ( w , err . Error ( ) , http . StatusNotFound )
http . Error ( w , err . Error ( ) , http . StatusNotFound )
return
return
@ -236,26 +190,7 @@ func legacyHandleGetSaveData(w http.ResponseWriter, r *http.Request) {
}
}
writeJSON ( w , r , save )
writeJSON ( w , r , save )
}
case "update" :
// FIXME UNFINISHED!!!
/ * func clearSessionData ( w http . ResponseWriter , r * http . Request ) {
uuid , err := uuidFromRequest ( r )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
var slot int
if r . URL . Query ( ) . Has ( "slot" ) {
slot , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "slot" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
}
var save any
var session defs . SessionSaveData
var session defs . SessionSaveData
err = json . NewDecoder ( r . Body ) . Decode ( & session )
err = json . NewDecoder ( r . Body ) . Decode ( & session )
if err != nil {
if err != nil {
@ -263,194 +198,25 @@ func legacyHandleGetSaveData(w http.ResponseWriter, r *http.Request) {
return
return
}
}
save = session
existingSave , err := savedata . GetSession ( uuid , slot )
if err != nil && ! errors . Is ( err , sql . ErrNoRows ) {
var active bool
httpError ( w , r , fmt . Errorf ( "failed to retrieve session save data: %s" , err ) , http . StatusInternalServerError )
active , err = db . IsActiveSession ( uuid , legacyClientSessionId ) //TODO unfinished, read token from query
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to check active session: %s" , err ) , http . StatusBadRequest )
return
}
var trainerId , secretId int
if r . URL . Query ( ) . Has ( "trainerId" ) && r . URL . Query ( ) . Has ( "secretId" ) {
trainerId , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "trainerId" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
secretId , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "secretId" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
}
storedTrainerId , storedSecretId , err := db . FetchTrainerIds ( uuid )
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
return
}
if storedTrainerId > 0 || storedSecretId > 0 {
if trainerId != storedTrainerId || secretId != storedSecretId {
httpError ( w , r , fmt . Errorf ( "session out of date: stored trainer or secret ID does not match" ) , http . StatusBadRequest )
return
}
} else {
err = db . UpdateTrainerIds ( trainerId , secretId , uuid )
if err != nil {
httpError ( w , r , fmt . Errorf ( "unable to update trainer ID: %s" , err ) , http . StatusInternalServerError )
return
}
}
if ! active {
save = savedata . ClearResponse { Error : "session out of date: not active" }
}
var seed string
seed , err = db . GetDailyRunSeed ( )
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
return
}
response , err := savedata . Clear ( uuid , slot , seed , save . ( defs . SessionSaveData ) )
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
return
}
jsonResponse ( w , r , response )
}
// FIXME UNFINISHED!!!
func deleteSystemSave ( w http . ResponseWriter , r * http . Request ) {
uuid , err := uuidFromRequest ( r )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
datatype := 0
if r . URL . Query ( ) . Has ( "datatype" ) {
datatype , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "datatype" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
}
var slot int
if r . URL . Query ( ) . Has ( "slot" ) {
slot , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "slot" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
}
var active bool
active , err = db . IsActiveSession ( uuid , legacyClientSessionId ) //TODO unfinished, read token from query
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to check active session: %s" , err ) , http . StatusInternalServerError )
return
}
if ! active {
httpError ( w , r , fmt . Errorf ( "session out of date: not active" ) , http . StatusBadRequest )
return
}
var trainerId , secretId int
if r . URL . Query ( ) . Has ( "trainerId" ) && r . URL . Query ( ) . Has ( "secretId" ) {
trainerId , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "trainerId" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
secretId , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "secretId" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
}
storedTrainerId , storedSecretId , err := db . FetchTrainerIds ( uuid )
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
return
}
if storedTrainerId > 0 || storedSecretId > 0 {
if trainerId != storedTrainerId || secretId != storedSecretId {
httpError ( w , r , fmt . Errorf ( "session out of date: stored trainer or secret ID does not match" ) , http . StatusBadRequest )
return
return
}
} else {
} else {
if err := db . UpdateTrainerIds ( trainerId , secretId , uuid ) ; err != nil {
if existingSave . Seed == session . Seed && existingSave . WaveIndex > session . WaveIndex {
httpError ( w , r , err, http . StatusInternalServerError )
httpError ( w , r , fmt . Errorf ( "session out of date: existing wave index is greater" ) , http . StatusBadRequest )
return
return
}
}
}
}
err = savedata . Delete( uuid , datatype , slot )
err = savedata . UpdateSession ( uuid , slot , session )
if err != nil {
if err != nil {
httpError ( w , r , err, http . StatusInternalServerError )
httpError ( w , r , fmt . Errorf ( "failed to put session data: %s" , err ) , http . StatusInternalServerError )
return
return
}
}
w . WriteHeader ( http . StatusOK )
w . WriteHeader ( http . StatusOK )
} * /
case "clear" :
func legacyHandleSaveData ( w http . ResponseWriter , r * http . Request ) {
uuid , err := uuidFromRequest ( r )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
datatype := - 1
if r . URL . Query ( ) . Has ( "datatype" ) {
datatype , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "datatype" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
}
var slot int
if r . URL . Query ( ) . Has ( "slot" ) {
slot , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "slot" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
}
clientSessionId := r . URL . Query ( ) . Get ( "clientSessionId" )
if clientSessionId == "" {
clientSessionId = legacyClientSessionId
}
var save any
// /savedata/get and /savedata/delete specify datatype, but don't expect data in body
if r . URL . Path != "/savedata/get" && r . URL . Path != "/savedata/delete" {
if datatype == 0 {
var system defs . SystemSaveData
err = json . NewDecoder ( r . Body ) . Decode ( & system )
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to decode request body: %s" , err ) , http . StatusBadRequest )
return
}
save = system
// /savedata/clear doesn't specify datatype, it is assumed to be 1 (session)
} else if datatype == 1 || r . URL . Path == "/savedata/clear" {
var session defs . SessionSaveData
var session defs . SessionSaveData
err = json . NewDecoder ( r . Body ) . Decode ( & session )
err = json . NewDecoder ( r . Body ) . Decode ( & session )
if err != nil {
if err != nil {
@ -458,111 +224,39 @@ func legacyHandleSaveData(w http.ResponseWriter, r *http.Request) {
return
return
}
}
save = session
seed , err := db . GetDailyRunSeed ( )
}
}
var active bool
if r . URL . Path == "/savedata/get" {
if datatype == 0 {
err = db . UpdateActiveSession ( uuid , clientSessionId )
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to update active session: %s" , err ) , http . StatusBadRequest )
return
}
}
} else {
active , err = db . IsActiveSession ( uuid , clientSessionId )
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to check active session: %s" , err ) , http . StatusBadRequest )
return
}
// TODO: make this not suck
if ! active && r . URL . Path != "/savedata/clear" {
httpError ( w , r , fmt . Errorf ( "session out of date: not active" ) , http . StatusBadRequest )
return
}
var trainerId , secretId int
if r . URL . Path != "/savedata/update" || datatype == 1 {
if r . URL . Query ( ) . Has ( "trainerId" ) && r . URL . Query ( ) . Has ( "secretId" ) {
trainerId , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "trainerId" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
secretId , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "secretId" ) )
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
return
}
}
} else {
trainerId = save . ( defs . SystemSaveData ) . TrainerId
secretId = save . ( defs . SystemSaveData ) . SecretId
}
storedTrainerId , storedSecretId , err := db . FetchTrainerIds ( uuid )
if err != nil {
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
httpError ( w , r , err , http . StatusInternalServerError )
return
return
}
}
if storedTrainerId > 0 || storedSecretId > 0 {
resp , err := savedata . Clear ( uuid , slot , seed , session )
if trainerId != storedTrainerId || secretId != storedSecretId {
if err != nil {
httpError ( w , r , fmt . Errorf ( "session out of date: stored trainer or secret ID does not match" ) , http . StatusBadRequest )
return
}
} else {
if err := db . UpdateTrainerIds ( trainerId , secretId , uuid ) ; err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
httpError ( w , r , err , http . StatusInternalServerError )
return
return
}
}
}
}
switch r . URL . Path {
case "/savedata/get" :
save , err = savedata . Get ( uuid , datatype , slot )
if errors . Is ( err , sql . ErrNoRows ) {
http . Error ( w , err . Error ( ) , http . StatusNotFound )
return
}
case "/savedata/update" :
err = savedata . Update ( uuid , slot , save )
case "/savedata/delete" :
err = savedata . Delete ( uuid , datatype , slot )
case "/savedata/clear" :
if ! active {
// TODO: make this not suck
save = savedata . ClearResponse { Error : "session out of date: not active" }
break
}
var seed string
writeJSON ( w , r , resp )
seed , err = db . GetDailyRunSeed ( )
case "newclear" :
resp , err := savedata . NewClear ( uuid , slot )
if err != nil {
if err != nil {
httpError ( w , r , err, http . StatusInternalServerError )
httpError ( w , r , fmt . Errorf ( "failed to read new clear: %s" , err ) , http . StatusInternalServerError )
return
return
}
}
// doesn't return a save, but it works
writeJSON ( w , r , resp )
save , err = savedata . Clear ( uuid , slot , seed , save . ( defs . SessionSaveData ) )
case "delete" :
}
err := savedata . DeleteSession ( uuid , slot )
if err != nil {
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
httpError ( w , r , err , http . StatusInternalServerError )
return
return
}
}
if save == nil || r . URL . Path == "/savedata/update" {
w . WriteHeader ( http . StatusOK )
w . WriteHeader ( http . StatusOK )
default :
httpError ( w , r , fmt . Errorf ( "unknown action" ) , http . StatusBadRequest )
return
return
}
}
writeJSON ( w , r , save )
}
}
//functions for run history
//functions for run history
@ -621,7 +315,7 @@ type CombinedSaveData struct {
func handleUpdateAll ( w http . ResponseWriter , r * http . Request ) {
func handleUpdateAll ( w http . ResponseWriter , r * http . Request ) {
uuid , err := uuidFromRequest ( r )
uuid , err := uuidFromRequest ( r )
if err != nil {
if err != nil {
httpError ( w , r , err , http . Status BadRequest )
httpError ( w , r , err , http . Status Unauthorized )
return
return
}
}
@ -631,8 +325,10 @@ func handleUpdateAll(w http.ResponseWriter, r *http.Request) {
httpError ( w , r , fmt . Errorf ( "failed to decode request body: %s" , err ) , http . StatusBadRequest )
httpError ( w , r , fmt . Errorf ( "failed to decode request body: %s" , err ) , http . StatusBadRequest )
return
return
}
}
if data . ClientSessionId == "" {
if data . ClientSessionId == "" {
data . ClientSessionId = legacyClientSessionId
httpError ( w , r , fmt . Errorf ( "missing clientSessionId" ) , http . StatusBadRequest )
return
}
}
var active bool
var active bool
@ -647,9 +343,6 @@ func handleUpdateAll(w http.ResponseWriter, r *http.Request) {
return
return
}
}
trainerId := data . System . TrainerId
secretId := data . System . SecretId
storedTrainerId , storedSecretId , err := db . FetchTrainerIds ( uuid )
storedTrainerId , storedSecretId , err := db . FetchTrainerIds ( uuid )
if err != nil {
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
httpError ( w , r , err , http . StatusInternalServerError )
@ -657,148 +350,180 @@ func handleUpdateAll(w http.ResponseWriter, r *http.Request) {
}
}
if storedTrainerId > 0 || storedSecretId > 0 {
if storedTrainerId > 0 || storedSecretId > 0 {
if trainerId != storedTrainerId || secretId != storedSecretId {
if da ta. System . T rainerId != storedTrainerId || data. Sy stem. S ecretId != storedSecretId {
httpError ( w , r , fmt . Errorf ( "session out of date: stored trainer or secret ID does not match" ) , http . StatusBadRequest )
httpError ( w , r , fmt . Errorf ( "session out of date: stored trainer or secret ID does not match" ) , http . StatusBadRequest )
return
return
}
}
} else {
} else {
if err = db . UpdateTrainerIds ( trainerId , secretId , uuid ) ; err != nil {
err = db . UpdateTrainerIds ( data . System . TrainerId , data . System . SecretId , uuid )
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
httpError ( w , r , err , http . StatusInternalServerError )
return
return
}
}
}
}
existingPlaytime , err := db . RetrievePlaytime ( uuid )
if err != nil && ! errors . Is ( err , sql . ErrNoRows ) {
httpError ( w , r , fmt . Errorf ( "failed to retrieve playtime: %s" , err ) , http . StatusInternalServerError )
return
} else {
playtime , ok := data . System . GameStats . ( map [ string ] interface { } ) [ "playTime" ] . ( float64 )
if ! ok {
httpError ( w , r , fmt . Errorf ( "no playtime found" ) , http . StatusBadRequest )
return
}
if float64 ( existingPlaytime ) > playtime {
httpError ( w , r , fmt . Errorf ( "session out of date: existing playtime is greater" ) , http . StatusBadRequest )
return
}
}
existingSave , err := savedata . GetSession ( uuid , data . SessionSlotId )
if err != nil && ! errors . Is ( err , sql . ErrNoRows ) {
httpError ( w , r , fmt . Errorf ( "failed to retrieve session save data: %s" , err ) , http . StatusInternalServerError )
return
} else {
if existingSave . Seed == data . Session . Seed && existingSave . WaveIndex > data . Session . WaveIndex {
httpError ( w , r , fmt . Errorf ( "session out of date: existing wave index is greater" ) , http . StatusBadRequest )
return
}
}
err = savedata . Update ( uuid , data . SessionSlotId , data . Session )
err = savedata . Update ( uuid , data . SessionSlotId , data . Session )
if err != nil {
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
httpError ( w , r , err , http . StatusInternalServerError )
return
return
}
}
err = savedata . Update ( uuid , 0 , data . System )
err = savedata . Update ( uuid , 0 , data . System )
if err != nil {
if err != nil {
httpError ( w , r , err , http . StatusInternalServerError )
httpError ( w , r , err , http . StatusInternalServerError )
return
return
}
}
w . WriteHeader ( http . StatusOK )
w . WriteHeader ( http . StatusOK )
}
}
type SystemVerifyResponse struct {
type SystemVerifyResponse struct {
Valid bool ` json:"valid" `
Valid bool ` json:"valid" `
SystemData * defs . SystemSaveData ` json:"systemData" `
SystemData defs . SystemSaveData ` json:"systemData" `
}
}
type SystemVerifyRequest struct {
func handleSystem ( w http . ResponseWriter , r * http . Request ) {
ClientSessionId string ` json:"clientSessionId" `
}
func handleSystemVerify ( w http . ResponseWriter , r * http . Request ) {
uuid , err := uuidFromRequest ( r )
uuid , err := uuidFromRequest ( r )
if err != nil {
if err != nil {
httpError ( w , r , err , http . StatusBadRequest )
httpError ( w , r , err , http . StatusUnauthorized )
return
return
}
}
var input SystemVerifyRequest
var active bool
err = json . NewDecoder ( r . Body ) . Decode ( & input )
if ! r . URL . Query ( ) . Has ( "clientSessionId" ) {
if err != nil {
httpError ( w , r , fmt . Errorf ( "missing clientSessionId" ) , http . StatusBadRequest )
httpError ( w , r , fmt . Errorf ( "failed to decode request body: %s" , err ) , http . StatusBadRequest )
return
return
}
}
var active bool
active , err = db . IsActiveSession ( uuid , r . URL . Query ( ) . Get ( "clientSessionId" ) )
active , err = db . IsActiveSession ( uuid , input . ClientSessionId )
if err != nil {
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to check active session: %s" , err ) , http . StatusBadRequest )
httpError ( w , r , fmt . Errorf ( "failed to check active session: %s" , err ) , http . StatusBadRequest )
return
return
}
}
response := SystemVerifyResponse {
switch r . PathValue ( "action" ) {
Valid : active ,
case "get" :
}
// not valid, send server state
if ! active {
if ! active {
err = db . UpdateActiveSession ( uuid , input. ClientSessionId )
err = db . UpdateActiveSession ( uuid , r . URL . Query ( ) . Get ( "clientSessionId" ) )
if err != nil {
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to update active session: %s" , err ) , http . StatusBadRequest )
httpError ( w , r , fmt . Errorf ( "failed to update active session: %s" , err ) , http . StatusBadRequest )
return
return
}
}
var storedSaveData defs . SystemSaveData
storedSaveData , err = db . ReadSystemSaveData ( uuid )
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to read session save data: %s" , err ) , http . StatusInternalServerError )
return
}
}
response . SystemData = & storedSaveData
save , err := savedata . GetSystem ( uuid )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
http . Error ( w , err . Error ( ) , http . StatusNotFound )
} else {
httpError ( w , r , err , http . StatusInternalServerError )
}
}
err = db . UpdateAccountLastActivity ( uuid )
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to update account last activity: %s" , err ) , http . StatusInternalServerError )
return
return
}
}
writeJSON ( w , r , response )
writeJSON ( w , r , save )
case "update" :
if ! active {
httpError ( w , r , fmt . Errorf ( "session out of date: not active" ) , http . StatusBadRequest )
return
}
}
func handleGetSystemData ( w http . ResponseWriter , r * http . Request ) {
var system defs . SystemSaveData
uuid , err := uuidFromRequest ( r )
err = json . NewDecoder ( r . Body ) . Decode ( & system )
if err != nil {
if err != nil {
httpError ( w , r , err, http . StatusBadRequest )
httpError ( w , r , fmt. Errorf ( "failed to decode request body: %s" , err) , http . StatusBadRequest )
return
return
}
}
if ! r . URL . Query ( ) . Has ( "clientSessionId" ) {
existingPlaytime , err := db . RetrievePlaytime ( uuid )
httpError ( w , r , fmt . Errorf ( "missing clientSessionId" ) , http . StatusBadRequest )
if err != nil && ! errors . Is ( err , sql . ErrNoRows ) {
httpError ( w , r , fmt . Errorf ( "failed to retrieve playtime: %s" , err ) , http . StatusInternalServerError )
return
} else {
playtime , ok := system . GameStats . ( map [ string ] interface { } ) [ "playTime" ] . ( float64 )
if ! ok {
httpError ( w , r , fmt . Errorf ( "no playtime found" ) , http . StatusBadRequest )
return
return
}
}
err = db . UpdateActiveSession ( uuid , r . URL . Query ( ) . Get ( "clientSessionId" ) )
if float64 ( existingPlaytime ) > playtime {
if err != nil {
httpError ( w , r , fmt . Errorf ( "session out of date: existing playtime is greater" ) , http . StatusBadRequest )
httpError ( w , r , fmt . Errorf ( "failed to update active session: %s" , err ) , http . StatusBadRequest )
return
return
}
}
var save any //TODO this is always system save data
save , err = savedata . Get ( uuid , 0 , 0 )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) {
http . Error ( w , err . Error ( ) , http . StatusNotFound )
} else {
httpError ( w , r , err , http . StatusInternalServerError )
}
}
err = savedata . UpdateSystem ( uuid , system )
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to put system data: %s" , err ) , http . StatusInternalServerError )
return
return
}
}
//TODO apply vouchers
writeJSON ( w , r , save )
w . WriteHeader ( http . StatusNoContent )
case "verify" :
response := SystemVerifyResponse {
Valid : active ,
}
}
func legacyHandleNewClear ( w http . ResponseWriter , r * http . Request ) {
// not valid, send server state
uuid , err := uuidFromRequest ( r )
if ! active {
err = db . UpdateActiveSession ( uuid , r . URL . Query ( ) . Get ( "clientSessionId" ) )
if err != nil {
if err != nil {
httpError ( w , r , err, http . StatusBadRequest )
httpError ( w , r , fmt. Errorf ( "failed to update active session: %s" , err) , http . StatusBadRequest )
return
return
}
}
var slot int
var storedSaveData defs . SystemSaveData
if r . URL . Query ( ) . Has ( "slot" ) {
storedSaveData , err = db . ReadSystemSaveData ( uuid )
slot , err = strconv . Atoi ( r . URL . Query ( ) . Get ( "slot" ) )
if err != nil {
if err != nil {
httpError ( w , r , err, http . StatusBadRequest )
httpError ( w , r , fmt. Errorf ( "failed to read session save data: %s" , err ) , http . StatusInternalServerError )
return
return
}
}
response . SystemData = storedSaveData
}
}
newClear , err := savedata . NewClear ( uuid , slot )
writeJSON ( w , r , response )
case "delete" :
err := savedata . DeleteSystem ( uuid )
if err != nil {
if err != nil {
httpError ( w , r , fmt . Errorf ( "failed to read new clear: %s" , err ) , http . StatusInternalServerError )
httpError ( w , r , err, http . StatusInternalServerError )
return
return
}
}
writeJSON ( w , r , newClear )
w . WriteHeader ( http . StatusOK )
default :
httpError ( w , r , fmt . Errorf ( "unknown action" ) , http . StatusBadRequest )
return
}
}
}
// daily
// daily