diff --git a/api/common.go b/api/common.go index 080b5dd..d67f0bf 100644 --- a/api/common.go +++ b/api/common.go @@ -52,16 +52,23 @@ func Init(mux *http.ServeMux) error { mux.HandleFunc("GET /game/classicsessioncount", handleGameClassicSessionCount) // savedata - mux.HandleFunc("POST /savedata/update", legacyHandleSaveData) - mux.HandleFunc("GET /savedata/delete", legacyHandleSaveData) // TODO: use deleteSystemSave + mux.HandleFunc("POST /savedata/update", legacyHandleSaveData) // DEPRECATED: use PUT method + mux.HandleFunc("GET /savedata/delete", legacyHandleSaveData) // DEPRECATED: use DELETE method mux.HandleFunc("POST /savedata/clear", legacyHandleSaveData) // TODO: use clearSessionData mux.HandleFunc("GET /savedata/newclear", legacyHandleNewClear) // new session - mux.HandleFunc("POST /savedata/updateall", handleUpdateAll) + mux.HandleFunc("POST /savedata/updateall", handleUpdateAll) // DEPRECATED: use PUT method + mux.HandleFunc("PUT /savedata/updateall", handleUpdateAll) + + mux.HandleFunc("GET /savedata/system", handleSystem) + mux.HandleFunc("PUT /savedata/system", handleSystem) + mux.HandleFunc("DELETE /savedata/system", handleSystem) mux.HandleFunc("POST /savedata/system/verify", handleSystemVerify) - mux.HandleFunc("GET /savedata/system", handleGetSystemData) - mux.HandleFunc("GET /savedata/session", handleGetSessionData) + + mux.HandleFunc("GET /savedata/session", handleSession) + mux.HandleFunc("PUT /savedata/session", handleSession) + mux.HandleFunc("DELETE /savedata/session", handleSession) // daily mux.HandleFunc("GET /daily/seed", handleDailySeed) diff --git a/api/endpoints.go b/api/endpoints.go index 50bb040..a4aa8fa 100644 --- a/api/endpoints.go +++ b/api/endpoints.go @@ -146,7 +146,7 @@ func handleGameClassicSessionCount(w http.ResponseWriter, r *http.Request) { w.Write([]byte(strconv.Itoa(classicSessionCount))) } -func handleGetSessionData(w http.ResponseWriter, r *http.Request) { +func handleSession(w http.ResponseWriter, r *http.Request) { uuid, err := uuidFromRequest(r) if err != nil { httpError(w, r, err, http.StatusBadRequest) @@ -173,18 +173,44 @@ func handleGetSessionData(w http.ResponseWriter, r *http.Request) { return } - save, err := savedata.Session(uuid, slot) - if errors.Is(err, sql.ErrNoRows) { - http.Error(w, err.Error(), http.StatusNotFound) - return - } + switch r.Method { + case "GET": + save, err := savedata.GetSession(uuid, slot) + if errors.Is(err, sql.ErrNoRows) { + http.Error(w, err.Error(), http.StatusNotFound) + return + } + + if err != nil { + httpError(w, r, err, http.StatusInternalServerError) + return + } + + writeJSON(w, r, save) + case "PUT": + var session defs.SessionSaveData + err = json.NewDecoder(r.Body).Decode(&session) + if err != nil { + httpError(w, r, fmt.Errorf("failed to decode request body: %s", err), http.StatusBadRequest) + return + } - if err != nil { - httpError(w, r, err, http.StatusInternalServerError) - return - } + err = savedata.PutSession(uuid, slot, session) + if err != nil { + httpError(w, r, fmt.Errorf("failed to put session data: %s", err), http.StatusInternalServerError) + return + } - writeJSON(w, r, save) + w.WriteHeader(http.StatusOK) + case "DELETE": + err := savedata.DeleteSession(uuid, slot) + if err != nil { + httpError(w, r, err, http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + } } const legacyClientSessionId = "LEGACY_CLIENT" @@ -276,87 +302,7 @@ const legacyClientSessionId = "LEGACY_CLIENT" 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 - } - } else { - if err := db.UpdateTrainerIds(trainerId, secretId, uuid); err != nil { - httpError(w, r, err, http.StatusInternalServerError) - return - } - } - - err = savedata.Delete(uuid, datatype, slot) - if err != nil { - httpError(w, r, err, http.StatusInternalServerError) - return - } - - w.WriteHeader(http.StatusOK) -}*/ +*/ func legacyHandleSaveData(w http.ResponseWriter, r *http.Request) { uuid, err := uuidFromRequest(r) @@ -633,7 +579,7 @@ func handleSystemVerify(w http.ResponseWriter, r *http.Request) { writeJSON(w, r, response) } -func handleGetSystemData(w http.ResponseWriter, r *http.Request) { +func handleSystem(w http.ResponseWriter, r *http.Request) { uuid, err := uuidFromRequest(r) if err != nil { httpError(w, r, err, http.StatusBadRequest) @@ -651,20 +597,46 @@ func handleGetSystemData(w http.ResponseWriter, r *http.Request) { return } - save, err := savedata.System(uuid) - if err != nil { - if errors.Is(err, sql.ErrNoRows) { - http.Error(w, err.Error(), http.StatusNotFound) - } else { - httpError(w, r, err, http.StatusInternalServerError) + switch r.Method { + case "GET": + 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) + } + + return + } + + // TODO: apply vouchers + + writeJSON(w, r, save) + case "PUT": + 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 } - return - } + err = savedata.PutSystem(uuid, system) + if err != nil { + httpError(w, r, fmt.Errorf("failed to put system data: %s", err), http.StatusInternalServerError) + return + } - // TODO: apply vouchers + w.WriteHeader(http.StatusOK) + case "DELETE": + err := savedata.DeleteSystem(uuid) + if err != nil { + httpError(w, r, err, http.StatusInternalServerError) + return + } - writeJSON(w, r, save) + w.WriteHeader(http.StatusOK) + } } func legacyHandleNewClear(w http.ResponseWriter, r *http.Request) { diff --git a/api/savedata/delete.go b/api/savedata/delete.go index 71ac023..5d98756 100644 --- a/api/savedata/delete.go +++ b/api/savedata/delete.go @@ -33,8 +33,6 @@ func Delete(uuid []byte, datatype, slot int) error { } switch datatype { - case 0: // System - err = db.DeleteSystemSaveData(uuid) case 1: // Session if slot < 0 || slot >= defs.SessionSlotCount { err = fmt.Errorf("slot id %d out of range", slot) diff --git a/api/savedata/session.go b/api/savedata/session.go index d6d54a8..ae91c5b 100644 --- a/api/savedata/session.go +++ b/api/savedata/session.go @@ -7,7 +7,7 @@ import ( "github.com/pagefaultgames/rogueserver/defs" ) -func Session(uuid []byte, slot int) (defs.SessionSaveData, error) { +func GetSession(uuid []byte, slot int) (defs.SessionSaveData, error) { var session defs.SessionSaveData if slot < 0 || slot >= defs.SessionSlotCount { @@ -22,3 +22,29 @@ func Session(uuid []byte, slot int) (defs.SessionSaveData, error) { return session, nil } + +func PutSession(uuid []byte, slot int, data defs.SessionSaveData) error { + if slot < 0 || slot >= defs.SessionSlotCount { + return fmt.Errorf("slot id %d out of range", slot) + } + + err := db.StoreSessionSaveData(uuid, data, slot) + if err != nil { + return err + } + + return nil +} + +func DeleteSession(uuid []byte, slot int) error { + if slot < 0 || slot >= defs.SessionSlotCount { + return fmt.Errorf("slot id %d out of range", slot) + } + + err := db.DeleteSessionSaveData(uuid, slot) + if err != nil { + return err + } + + return nil +} diff --git a/api/savedata/system.go b/api/savedata/system.go index 75735e6..1f9c5d2 100644 --- a/api/savedata/system.go +++ b/api/savedata/system.go @@ -8,7 +8,7 @@ import ( "github.com/pagefaultgames/rogueserver/defs" ) -func System(uuid []byte) (defs.SystemSaveData, error) { +func GetSystem(uuid []byte) (defs.SystemSaveData, error) { system, err := db.ReadSystemSaveData(uuid) if err != nil { return system, err @@ -46,3 +46,34 @@ func System(uuid []byte) (defs.SystemSaveData, error) { return system, nil } + +func PutSystem(uuid []byte, data defs.SystemSaveData) error { + if data.TrainerId == 0 && data.SecretId == 0 { + return fmt.Errorf("invalid system data") + } + + if data.GameVersion != "1.0.4" { + return fmt.Errorf("client version out of date") + } + + err := db.UpdateAccountStats(uuid, data.GameStats, data.VoucherCounts) + if err != nil { + return fmt.Errorf("failed to update account stats: %s", err) + } + + err = db.DeleteClaimedAccountCompensations(uuid) + if err != nil { + return fmt.Errorf("failed to delete claimed compensations: %s", err) + } + + return db.StoreSystemSaveData(uuid, data) +} + +func DeleteSystem(uuid []byte) error { + err := db.DeleteSystemSaveData(uuid) + if err != nil { + return err + } + + return nil +}