mirror of
https://github.com/pagefaultgames/rogueserver.git
synced 2025-04-02 02:57:15 +08:00
Merge branch 'master' into test-deployment
This commit is contained in:
commit
a5277c9d39
@ -22,6 +22,7 @@ import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/pagefaultgames/rogueserver/db"
|
||||
@ -43,7 +44,7 @@ func Login(username, password string) (LoginResponse, error) {
|
||||
|
||||
key, salt, err := db.FetchAccountKeySaltFromUsername(username)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return response, fmt.Errorf("account doesn't exist")
|
||||
}
|
||||
|
||||
|
@ -21,18 +21,22 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/pagefaultgames/rogueserver/api/account"
|
||||
"github.com/pagefaultgames/rogueserver/api/daily"
|
||||
"github.com/pagefaultgames/rogueserver/db"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func Init(mux *http.ServeMux) error {
|
||||
if err := scheduleStatRefresh(); err != nil {
|
||||
err := scheduleStatRefresh()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := daily.Init(); err != nil {
|
||||
|
||||
err = daily.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -56,7 +60,7 @@ func Init(mux *http.ServeMux) error {
|
||||
|
||||
// new session
|
||||
mux.HandleFunc("POST /savedata/updateall", handleUpdateAll)
|
||||
mux.HandleFunc("POST /savedata/verify", handleSessionVerify)
|
||||
mux.HandleFunc("POST /savedata/system/verify", handleSystemVerify)
|
||||
mux.HandleFunc("GET /savedata/system", handleGetSystemData)
|
||||
mux.HandleFunc("GET /savedata/session", handleGetSessionData)
|
||||
|
||||
@ -64,6 +68,7 @@ func Init(mux *http.ServeMux) error {
|
||||
mux.HandleFunc("GET /daily/seed", handleDailySeed)
|
||||
mux.HandleFunc("GET /daily/rankings", handleDailyRankings)
|
||||
mux.HandleFunc("GET /daily/rankingpagecount", handleDailyRankingPageCount)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -86,7 +91,11 @@ func tokenFromRequest(r *http.Request) ([]byte, error) {
|
||||
|
||||
func uuidFromRequest(r *http.Request) ([]byte, error) {
|
||||
_, uuid, err := tokenAndUuidFromRequest(r)
|
||||
return uuid, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
func tokenAndUuidFromRequest(r *http.Request) ([]byte, []byte, error) {
|
||||
@ -108,7 +117,7 @@ func httpError(w http.ResponseWriter, r *http.Request, err error, code int) {
|
||||
http.Error(w, err.Error(), code)
|
||||
}
|
||||
|
||||
func jsonResponse(w http.ResponseWriter, r *http.Request, data any) {
|
||||
func writeJSON(w http.ResponseWriter, r *http.Request, data any) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
|
@ -18,8 +18,6 @@
|
||||
package daily
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/pagefaultgames/rogueserver/db"
|
||||
"github.com/pagefaultgames/rogueserver/defs"
|
||||
)
|
||||
@ -28,7 +26,7 @@ import (
|
||||
func Rankings(category, page int) ([]defs.DailyRanking, error) {
|
||||
rankings, err := db.FetchRankings(category, page)
|
||||
if err != nil {
|
||||
log.Print("failed to retrieve rankings")
|
||||
return rankings, err
|
||||
}
|
||||
|
||||
return rankings, nil
|
||||
|
@ -18,8 +18,6 @@
|
||||
package daily
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/pagefaultgames/rogueserver/db"
|
||||
)
|
||||
|
||||
@ -27,7 +25,7 @@ import (
|
||||
func RankingPageCount(category int) (int, error) {
|
||||
pageCount, err := db.FetchRankingPageCount(category)
|
||||
if err != nil {
|
||||
log.Print("failed to retrieve ranking page count")
|
||||
return pageCount, err
|
||||
}
|
||||
|
||||
return pageCount, nil
|
||||
|
@ -61,7 +61,7 @@ func handleAccountInfo(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(w, r, response)
|
||||
writeJSON(w, r, response)
|
||||
}
|
||||
|
||||
func handleAccountRegister(w http.ResponseWriter, r *http.Request) {
|
||||
@ -93,7 +93,7 @@ func handleAccountLogin(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(w, r, response)
|
||||
writeJSON(w, r, response)
|
||||
}
|
||||
|
||||
func handleAccountChangePW(w http.ResponseWriter, r *http.Request) {
|
||||
@ -141,7 +141,7 @@ func handleGameTitleStats(w http.ResponseWriter, r *http.Request) {
|
||||
BattleCount: battleCount,
|
||||
}
|
||||
|
||||
jsonResponse(w, r, stats)
|
||||
writeJSON(w, r, stats)
|
||||
}
|
||||
|
||||
func handleGameClassicSessionCount(w http.ResponseWriter, r *http.Request) {
|
||||
@ -189,7 +189,7 @@ func handleGetSessionData(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(w, r, save)
|
||||
writeJSON(w, r, save)
|
||||
}
|
||||
|
||||
const legacyClientSessionId = "LEGACY_CLIENT"
|
||||
@ -239,11 +239,11 @@ func legacyHandleGetSaveData(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(w, r, save)
|
||||
writeJSON(w, r, save)
|
||||
}
|
||||
|
||||
// FIXME UNFINISHED!!!
|
||||
func clearSessionData(w http.ResponseWriter, r *http.Request) {
|
||||
/*func clearSessionData(w http.ResponseWriter, r *http.Request) {
|
||||
uuid, err := uuidFromRequest(r)
|
||||
if err != nil {
|
||||
httpError(w, r, err, http.StatusBadRequest)
|
||||
@ -299,19 +299,19 @@ func clearSessionData(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if storedTrainerId > 0 || storedSecretId > 0 {
|
||||
if trainerId != storedTrainerId || secretId != storedSecretId {
|
||||
httpError(w, r, fmt.Errorf("session out of date"), http.StatusBadRequest)
|
||||
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 traienr ID: %s", err), http.StatusInternalServerError)
|
||||
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"}
|
||||
save = savedata.ClearResponse{Error: "session out of date: not active"}
|
||||
}
|
||||
|
||||
var seed string
|
||||
@ -364,7 +364,7 @@ func deleteSystemSave(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if !active {
|
||||
httpError(w, r, fmt.Errorf("session out of date"), http.StatusBadRequest)
|
||||
httpError(w, r, fmt.Errorf("session out of date: not active"), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@ -392,7 +392,7 @@ func deleteSystemSave(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if storedTrainerId > 0 || storedSecretId > 0 {
|
||||
if trainerId != storedTrainerId || secretId != storedSecretId {
|
||||
httpError(w, r, fmt.Errorf("session out of date"), http.StatusBadRequest)
|
||||
httpError(w, r, fmt.Errorf("session out of date: stored trainer or secret ID does not match"), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@ -409,7 +409,7 @@ func deleteSystemSave(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
}*/
|
||||
|
||||
func legacyHandleSaveData(w http.ResponseWriter, r *http.Request) {
|
||||
uuid, err := uuidFromRequest(r)
|
||||
@ -487,7 +487,7 @@ func legacyHandleSaveData(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// TODO: make this not suck
|
||||
if !active && r.URL.Path != "/savedata/clear" {
|
||||
httpError(w, r, fmt.Errorf("session out of date"), http.StatusBadRequest)
|
||||
httpError(w, r, fmt.Errorf("session out of date: not active"), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@ -520,7 +520,7 @@ func legacyHandleSaveData(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if storedTrainerId > 0 || storedSecretId > 0 {
|
||||
if trainerId != storedTrainerId || secretId != storedSecretId {
|
||||
httpError(w, r, fmt.Errorf("session out of date"), http.StatusBadRequest)
|
||||
httpError(w, r, fmt.Errorf("session out of date: stored trainer or secret ID does not match"), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@ -534,7 +534,7 @@ func legacyHandleSaveData(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/savedata/get":
|
||||
save, err = savedata.Get(uuid, datatype, slot)
|
||||
if err == sql.ErrNoRows {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
@ -545,7 +545,7 @@ func legacyHandleSaveData(w http.ResponseWriter, r *http.Request) {
|
||||
case "/savedata/clear":
|
||||
if !active {
|
||||
// TODO: make this not suck
|
||||
save = savedata.ClearResponse{Error: "session out of date"}
|
||||
save = savedata.ClearResponse{Error: "session out of date: not active"}
|
||||
break
|
||||
}
|
||||
|
||||
@ -570,7 +570,7 @@ func legacyHandleSaveData(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(w, r, save)
|
||||
writeJSON(w, r, save)
|
||||
}
|
||||
|
||||
type CombinedSaveData struct {
|
||||
@ -588,30 +588,25 @@ func handleUpdateAll(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var clientSessionId string
|
||||
if r.URL.Query().Has("clientSessionId") {
|
||||
clientSessionId = r.URL.Query().Get("clientSessionId")
|
||||
}
|
||||
if clientSessionId == "" {
|
||||
clientSessionId = legacyClientSessionId
|
||||
}
|
||||
|
||||
var data CombinedSaveData
|
||||
err = json.NewDecoder(r.Body).Decode(&data)
|
||||
if err != nil {
|
||||
httpError(w, r, fmt.Errorf("failed to decode request body: %s", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if data.ClientSessionId == "" {
|
||||
data.ClientSessionId = legacyClientSessionId
|
||||
}
|
||||
|
||||
var active bool
|
||||
active, err = db.IsActiveSession(uuid, clientSessionId)
|
||||
active, err = db.IsActiveSession(uuid, data.ClientSessionId)
|
||||
if err != nil {
|
||||
httpError(w, r, fmt.Errorf("failed to check active session: %s", err), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if !active {
|
||||
httpError(w, r, fmt.Errorf("session out of date"), http.StatusBadRequest)
|
||||
httpError(w, r, fmt.Errorf("session out of date: not active"), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@ -626,11 +621,11 @@ func handleUpdateAll(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
if storedTrainerId > 0 || storedSecretId > 0 {
|
||||
if trainerId != storedTrainerId || secretId != storedSecretId {
|
||||
httpError(w, r, fmt.Errorf("session out of date"), http.StatusBadRequest)
|
||||
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 {
|
||||
if err = db.UpdateTrainerIds(trainerId, secretId, uuid); err != nil {
|
||||
httpError(w, r, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@ -649,24 +644,23 @@ func handleUpdateAll(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
type SessionVerifyResponse struct {
|
||||
Valid bool `json:"valid"`
|
||||
SessionData *defs.SessionSaveData `json:"sessionData"`
|
||||
type SystemVerifyResponse struct {
|
||||
Valid bool `json:"valid"`
|
||||
SystemData *defs.SystemSaveData `json:"systemData"`
|
||||
}
|
||||
|
||||
type SessionVerifyRequest struct {
|
||||
type SystemVerifyRequest struct {
|
||||
ClientSessionId string `json:"clientSessionId"`
|
||||
Slot int `json:"slot"`
|
||||
}
|
||||
|
||||
func handleSessionVerify(w http.ResponseWriter, r *http.Request) {
|
||||
func handleSystemVerify(w http.ResponseWriter, r *http.Request) {
|
||||
uuid, err := uuidFromRequest(r)
|
||||
if err != nil {
|
||||
httpError(w, r, err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
var input SessionVerifyRequest
|
||||
var input SystemVerifyRequest
|
||||
err = json.NewDecoder(r.Body).Decode(&input)
|
||||
if err != nil {
|
||||
httpError(w, r, fmt.Errorf("failed to decode request body: %s", err), http.StatusBadRequest)
|
||||
@ -680,7 +674,7 @@ func handleSessionVerify(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
response := SessionVerifyResponse{
|
||||
response := SystemVerifyResponse{
|
||||
Valid: active,
|
||||
}
|
||||
|
||||
@ -692,17 +686,23 @@ func handleSessionVerify(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var storedSaveData defs.SessionSaveData
|
||||
storedSaveData, err = db.ReadSessionSaveData(uuid, input.Slot)
|
||||
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.SessionData = &storedSaveData
|
||||
response.SystemData = &storedSaveData
|
||||
}
|
||||
|
||||
jsonResponse(w, r, response)
|
||||
err = db.UpdateAccountLastActivity(uuid)
|
||||
if err != nil {
|
||||
httpError(w, r, fmt.Errorf("failed to update account last activity: %s", err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
writeJSON(w, r, response)
|
||||
}
|
||||
|
||||
func handleGetSystemData(w http.ResponseWriter, r *http.Request) {
|
||||
@ -736,8 +736,9 @@ func handleGetSystemData(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
return
|
||||
}
|
||||
//TODO apply vouchers
|
||||
|
||||
jsonResponse(w, r, save)
|
||||
writeJSON(w, r, save)
|
||||
}
|
||||
|
||||
func legacyHandleNewClear(w http.ResponseWriter, r *http.Request) {
|
||||
@ -762,7 +763,7 @@ func legacyHandleNewClear(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(w, r, newClear)
|
||||
writeJSON(w, r, newClear)
|
||||
}
|
||||
|
||||
// daily
|
||||
@ -806,7 +807,7 @@ func handleDailyRankings(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
jsonResponse(w, r, rankings)
|
||||
writeJSON(w, r, rankings)
|
||||
}
|
||||
|
||||
func handleDailyRankingPageCount(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -50,6 +50,10 @@ func Clear(uuid []byte, slot int, seed string, save defs.SessionSaveData) (Clear
|
||||
waveCompleted--
|
||||
}
|
||||
|
||||
if save.Score >= 20000 {
|
||||
db.SetAccountBanned(uuid, true)
|
||||
}
|
||||
|
||||
err = db.AddOrUpdateAccountDailyRun(uuid, save.Score, waveCompleted)
|
||||
if err != nil {
|
||||
log.Printf("failed to add or update daily run record: %s", err)
|
||||
|
@ -19,9 +19,10 @@ package savedata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/pagefaultgames/rogueserver/db"
|
||||
"github.com/pagefaultgames/rogueserver/defs"
|
||||
"log"
|
||||
)
|
||||
|
||||
// /savedata/delete - delete save data
|
||||
@ -33,14 +34,20 @@ func Delete(uuid []byte, datatype, slot int) error {
|
||||
|
||||
switch datatype {
|
||||
case 0: // System
|
||||
return db.DeleteSystemSaveData(uuid)
|
||||
err = db.DeleteSystemSaveData(uuid)
|
||||
case 1: // Session
|
||||
if slot < 0 || slot >= defs.SessionSlotCount {
|
||||
return fmt.Errorf("slot id %d out of range", slot)
|
||||
err = fmt.Errorf("slot id %d out of range", slot)
|
||||
break
|
||||
}
|
||||
|
||||
return db.DeleteSessionSaveData(uuid, slot)
|
||||
err = db.DeleteSessionSaveData(uuid, slot)
|
||||
default:
|
||||
return fmt.Errorf("invalid data type")
|
||||
err = fmt.Errorf("invalid data type")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ func Get(uuid []byte, datatype, slot int) (any, error) {
|
||||
return nil, fmt.Errorf("failed to fetch compensations: %s", err)
|
||||
}
|
||||
|
||||
needsUpdate := false
|
||||
var needsUpdate bool
|
||||
for compensationType, amount := range compensations {
|
||||
system.VoucherCounts[strconv.Itoa(compensationType)] += amount
|
||||
if amount > 0 {
|
||||
@ -57,6 +57,10 @@ func Get(uuid []byte, datatype, slot int) (any, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update system save data: %s", err)
|
||||
}
|
||||
err = db.DeleteClaimedAccountCompensations(uuid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to delete claimed compensations: %s", err)
|
||||
}
|
||||
|
||||
err = db.UpdateAccountStats(uuid, system.GameStats, system.VoucherCounts)
|
||||
if err != nil {
|
||||
|
@ -42,6 +42,13 @@ func Update(uuid []byte, slot int, save any) error {
|
||||
return fmt.Errorf("client version out of date")
|
||||
}
|
||||
|
||||
if save.VoucherCounts["0"] > 300 ||
|
||||
save.VoucherCounts["1"] > 150 ||
|
||||
save.VoucherCounts["2"] > 100 ||
|
||||
save.VoucherCounts["3"] > 10 {
|
||||
db.SetAccountBanned(uuid, true)
|
||||
}
|
||||
|
||||
err = db.UpdateAccountStats(uuid, save.GameStats, save.VoucherCounts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update account stats: %s", err)
|
||||
|
@ -145,6 +145,15 @@ func UpdateAccountStats(uuid []byte, stats defs.GameStats, voucherCounts map[str
|
||||
return nil
|
||||
}
|
||||
|
||||
func SetAccountBanned(uuid []byte, banned bool) error {
|
||||
_, err := handle.Exec("UPDATE accounts SET banned = ? WHERE uuid = ?", banned, uuid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func FetchAndClaimAccountCompensations(uuid []byte) (map[int]int, error) {
|
||||
var compensations = make(map[int]int)
|
||||
|
||||
@ -210,28 +219,27 @@ func UpdateTrainerIds(trainerId, secretId int, uuid []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsActiveSession(uuid []byte, clientSessionId string) (bool, error) {
|
||||
var storedId string
|
||||
err := handle.QueryRow("SELECT clientSessionId FROM activeClientSessions WHERE sessions.uuid = ?", uuid).Scan(&storedId)
|
||||
func IsActiveSession(uuid []byte, sessionId string) (bool, error) {
|
||||
var id string
|
||||
err := handle.QueryRow("SELECT clientSessionId FROM activeClientSessions WHERE uuid = ?", uuid).Scan(&id)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return false, nil
|
||||
err = UpdateActiveSession(uuid, sessionId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, err
|
||||
}
|
||||
if storedId == "" {
|
||||
err = UpdateActiveSession(uuid, clientSessionId)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return storedId == clientSessionId, nil
|
||||
return id == "" || id == sessionId, nil
|
||||
}
|
||||
|
||||
func UpdateActiveSession(uuid []byte, clientSessionId string) error {
|
||||
_, err := handle.Exec("REPLACE INTO activeClientSessions VALUES (?, ?)", uuid, clientSessionId)
|
||||
_, err := handle.Exec("INSERT INTO activeClientSessions (uuid, clientSessionId) VALUES (?, ?) ON DUPLICATE KEY UPDATE clientSessionId = ?", uuid, clientSessionId, clientSessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ func GetDailyRunSeed() (string, error) {
|
||||
}
|
||||
|
||||
return seed, nil
|
||||
|
||||
}
|
||||
|
||||
func AddOrUpdateAccountDailyRun(uuid []byte, score int, wave int) error {
|
||||
|
95
db/db.go
95
db/db.go
@ -19,11 +19,8 @@ package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
@ -38,15 +35,10 @@ func Init(username, password, protocol, address, database string) error {
|
||||
return fmt.Errorf("failed to open database connection: %s", err)
|
||||
}
|
||||
|
||||
conns := 1024
|
||||
if protocol != "unix" {
|
||||
conns = 256
|
||||
}
|
||||
conns := 64
|
||||
|
||||
handle.SetMaxOpenConns(conns)
|
||||
handle.SetMaxIdleConns(conns / 4)
|
||||
|
||||
handle.SetConnMaxIdleTime(time.Second * 10)
|
||||
handle.SetMaxIdleConns(conns)
|
||||
|
||||
tx, err := handle.Begin()
|
||||
if err != nil {
|
||||
@ -56,7 +48,7 @@ func Init(username, password, protocol, address, database string) error {
|
||||
|
||||
err = setupDb(tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
tx.Rollback()
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
@ -65,83 +57,6 @@ func Init(username, password, protocol, address, database string) error {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// TODO temp code
|
||||
_, err = os.Stat("userdata")
|
||||
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) { // not found, do not migrate
|
||||
log.Fatalf("failed to stat userdata directory: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir("userdata")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
uuidString := entry.Name()
|
||||
uuid, err := hex.DecodeString(uuidString)
|
||||
if err != nil {
|
||||
log.Printf("failed to decode uuid: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
var count int
|
||||
err = handle.QueryRow("SELECT COUNT(*) FROM systemSaveData WHERE uuid = ?", uuid).Scan(&count)
|
||||
if err != nil || count != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// store new system data
|
||||
systemData, err := LegacyReadSystemSaveData(uuid)
|
||||
if err != nil {
|
||||
log.Printf("failed to read system save data for %v: %s", uuidString, err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = StoreSystemSaveData(uuid, systemData)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to store system save data for %v: %s\n", uuidString, err)
|
||||
}
|
||||
|
||||
// delete old system data
|
||||
err = os.Remove("userdata/" + uuidString + "/system.pzs")
|
||||
if err != nil {
|
||||
log.Fatalf("failed to remove legacy system save data for %v: %s", uuidString, err)
|
||||
}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
sessionData, err := LegacyReadSessionSaveData(uuid, i)
|
||||
if err != nil {
|
||||
log.Printf("failed to read session save data %v for %v: %s", i, uuidString, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// store new session data
|
||||
err = StoreSessionSaveData(uuid, sessionData, i)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to store session save data for %v: %s\n", uuidString, err)
|
||||
}
|
||||
|
||||
// delete old session data
|
||||
filename := "session"
|
||||
if i != 0 {
|
||||
filename += fmt.Sprintf("%d", i)
|
||||
}
|
||||
err = os.Remove(fmt.Sprintf("userdata/%s/%s.pzs", uuidString, filename))
|
||||
if err != nil {
|
||||
log.Fatalf("failed to remove legacy session save data %v for %v: %s", i, uuidString, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -169,9 +84,9 @@ func setupDb(tx *sql.Tx) error {
|
||||
`CREATE TABLE IF NOT EXISTS accountDailyRuns (uuid BINARY(16) NOT NULL, date DATE NOT NULL, score INT(11) NOT NULL DEFAULT 0, wave INT(11) NOT NULL DEFAULT 0, timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (uuid, date), CONSTRAINT accountDailyRuns_ibfk_1 FOREIGN KEY (uuid) REFERENCES accounts (uuid) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT accountDailyRuns_ibfk_2 FOREIGN KEY (date) REFERENCES dailyRuns (date) ON DELETE NO ACTION ON UPDATE NO ACTION)`,
|
||||
`CREATE INDEX IF NOT EXISTS accountDailyRunsByDate ON accountDailyRuns (date)`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS systemSaveData (uuid BINARY(16) PRIMARY KEY, data LONGBLOB, timestamp TIMESTAMP)`,
|
||||
`CREATE TABLE IF NOT EXISTS systemSaveData (uuid BINARY(16) PRIMARY KEY, data LONGBLOB, timestamp TIMESTAMP, FOREIGN KEY (uuid) REFERENCES accounts (uuid) ON DELETE CASCADE ON UPDATE CASCADE)`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS sessionSaveData (uuid BINARY(16), slot TINYINT, data LONGBLOB, timestamp TIMESTAMP, PRIMARY KEY (uuid, slot))`,
|
||||
`CREATE TABLE IF NOT EXISTS sessionSaveData (uuid BINARY(16), slot TINYINT, data LONGBLOB, timestamp TIMESTAMP, PRIMARY KEY (uuid, slot), FOREIGN KEY (uuid) REFERENCES accounts (uuid) ON DELETE CASCADE ON UPDATE CASCADE)`,
|
||||
|
||||
// ----------------------------------
|
||||
// MIGRATION 001
|
||||
|
@ -29,7 +29,7 @@ func FetchPlayerCount() (int, error) {
|
||||
|
||||
func FetchBattleCount() (int, error) {
|
||||
var battleCount int
|
||||
err := handle.QueryRow("SELECT COALESCE(SUM(battles), 0) FROM accountStats").Scan(&battleCount)
|
||||
err := handle.QueryRow("SELECT COALESCE(SUM(s.battles), 0) FROM accountStats s JOIN accounts a ON a.uuid = s.uuid WHERE a.banned = 0").Scan(&battleCount)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -39,7 +39,7 @@ func FetchBattleCount() (int, error) {
|
||||
|
||||
func FetchClassicSessionCount() (int, error) {
|
||||
var classicSessionCount int
|
||||
err := handle.QueryRow("SELECT COALESCE(SUM(classicSessionsPlayed), 0) FROM accountStats").Scan(&classicSessionCount)
|
||||
err := handle.QueryRow("SELECT COALESCE(SUM(s.classicSessionsPlayed), 0) FROM accountStats s JOIN accounts a ON a.uuid = s.uuid WHERE a.banned = 0").Scan(&classicSessionCount)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
84
db/legacy.go
84
db/legacy.go
@ -1,84 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2024 Pagefault Games
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"encoding/gob"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"github.com/pagefaultgames/rogueserver/defs"
|
||||
)
|
||||
|
||||
func LegacyReadSystemSaveData(uuid []byte) (defs.SystemSaveData, error) {
|
||||
var system defs.SystemSaveData
|
||||
|
||||
file, err := os.Open("userdata/" + hex.EncodeToString(uuid) + "/system.pzs")
|
||||
if err != nil {
|
||||
return system, fmt.Errorf("failed to open save file for reading: %s", err)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
zstdDecoder, err := zstd.NewReader(file)
|
||||
if err != nil {
|
||||
return system, fmt.Errorf("failed to create zstd decoder: %s", err)
|
||||
}
|
||||
|
||||
defer zstdDecoder.Close()
|
||||
|
||||
err = gob.NewDecoder(zstdDecoder).Decode(&system)
|
||||
if err != nil {
|
||||
return system, fmt.Errorf("failed to deserialize save: %s", err)
|
||||
}
|
||||
|
||||
return system, nil
|
||||
}
|
||||
|
||||
func LegacyReadSessionSaveData(uuid []byte, slotID int) (defs.SessionSaveData, error) {
|
||||
var session defs.SessionSaveData
|
||||
|
||||
fileName := "session"
|
||||
if slotID != 0 {
|
||||
fileName += strconv.Itoa(slotID)
|
||||
}
|
||||
|
||||
file, err := os.Open(fmt.Sprintf("userdata/%s/%s.pzs", hex.EncodeToString(uuid), fileName))
|
||||
if err != nil {
|
||||
return session, fmt.Errorf("failed to open save file for reading: %s", err)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
zstdDecoder, err := zstd.NewReader(file)
|
||||
if err != nil {
|
||||
return session, fmt.Errorf("failed to create zstd decoder: %s", err)
|
||||
}
|
||||
|
||||
defer zstdDecoder.Close()
|
||||
|
||||
err = gob.NewDecoder(zstdDecoder).Decode(&session)
|
||||
if err != nil {
|
||||
return session, fmt.Errorf("failed to deserialize save: %s", err)
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
1
go.mod
1
go.mod
@ -4,7 +4,6 @@ go 1.22
|
||||
|
||||
require (
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/klauspost/compress v1.17.4
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
golang.org/x/crypto v0.16.0
|
||||
)
|
||||
|
2
go.sum
2
go.sum
@ -1,7 +1,5 @@
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4=
|
||||
github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
|
Loading…
x
Reference in New Issue
Block a user