SAKE: Fix CreateRecord response

This commit is contained in:
Palapeli 2026-04-01 06:29:07 -04:00
parent 5fed8960dc
commit 4f281ef7cc
No known key found for this signature in database
GPG Key ID: 1FFE8F556A474925
2 changed files with 38 additions and 25 deletions

View File

@ -47,6 +47,7 @@ const (
AND table_id = $2
AND (cardinality($4::integer[]) = 0 OR record_id = ANY($4::integer[]))
AND (cardinality($3::integer[]) = 0 OR owner_id = ANY($3::integer[]))`
updateSakeRecordQuery = `
UPDATE sake_records
SET
@ -56,9 +57,11 @@ const (
AND table_id = $2
AND record_id = $3
RETURNING owner_id`
insertSakeRecordQuery = `
INSERT INTO sake_records (game_id, table_id, owner_id, fields)
VALUES ($1, $2, $3, $4)`
VALUES ($1, $2, $3, $4)
RETURNING record_id`
)
var (
@ -152,14 +155,14 @@ func UpdateSakeRecord(pool *pgxpool.Pool, ctx context.Context, record SakeRecord
return nil
}
func InsertSakeRecord(pool *pgxpool.Pool, ctx context.Context, record SakeRecord) error {
func InsertSakeRecord(pool *pgxpool.Pool, ctx context.Context, record SakeRecord) (recordId int32, err error) {
fieldsJson, err := json.Marshal(record.Fields)
if err != nil {
return err
return 0, err
}
for i := 0; i < 10; i++ {
_, err = pool.Exec(ctx, insertSakeRecordQuery, record.GameId, record.TableId, record.OwnerId, fieldsJson)
err = pool.QueryRow(ctx, insertSakeRecordQuery, record.GameId, record.TableId, record.OwnerId, fieldsJson).Scan(&recordId)
if err == nil {
break
}
@ -172,5 +175,5 @@ func InsertSakeRecord(pool *pgxpool.Pool, ctx context.Context, record SakeRecord
}
// Retry if unique violation occurred, as the record ID is generated randomly
}
return nil
return recordId, err
}

View File

@ -105,16 +105,12 @@ type StorageResponseEnvelope struct {
}
type StorageResponseBody struct {
GetMyRecordsResponse *StorageGetMyRecordsResponse `xml:"http://gamespy.net/sake GetMyRecordsResponse"`
CreateRecordResponse *StorageCreateRecordResponse `xml:"http://gamespy.net/sake CreateRecordResponse"`
UpdateRecordResponse *StorageUpdateRecordResponse `xml:"http://gamespy.net/sake UpdateRecordResponse"`
GetMyRecordsResponse *StorageGetMyRecordsResponse `xml:"http://gamespy.net/sake GetMyRecordsResponse"`
SearchForRecordsResponse *StorageSearchForRecordsResponse `xml:"http://gamespy.net/sake SearchForRecordsResponse"`
}
type StorageGetMyRecordsResponse struct {
GetMyRecordsResult string
Values StorageResponseValues `xml:"values"`
}
type StorageResponseValues struct {
ArrayOfRecordValue []StorageArrayOfRecordValue `xml:"ArrayOfRecordValue"`
}
@ -123,10 +119,20 @@ type StorageArrayOfRecordValue struct {
RecordValues []StorageRecordValue `xml:"RecordValue"`
}
type StorageCreateRecordResponse struct {
CreateRecordResult string
RecordID int32 `xml:"recordid"`
}
type StorageUpdateRecordResponse struct {
UpdateRecordResult string
}
type StorageGetMyRecordsResponse struct {
GetMyRecordsResult string
Values StorageResponseValues `xml:"values"`
}
type StorageSearchForRecordsResponse struct {
XMLName xml.Name
SearchForRecordsResult string
@ -208,6 +214,8 @@ func handleStorageRequest(moduleName string, w http.ResponseWriter, r *http.Requ
panic(err)
}
logging.Info(moduleName, "Responding with body:", aurora.Cyan(string(out)))
payload := append([]byte(xml.Header), out...)
w.Header().Set("Content-Type", "text/xml")
@ -250,7 +258,7 @@ func getInputFields(moduleName string, request StorageRequestData) (map[string]d
logging.Error(moduleName, "Invalid field type tag:", aurora.Cyan(field.Value.Value.XMLName.Local))
return nil, ResultFieldTypeInvalid
}
if field.Name == "ownerid" || field.Name == "recordid" {
if field.Name == "ownerid" || field.Name == "recordid" || field.Name == "gameid" || field.Name == "tableid" {
logging.Error(moduleName, "Attempt to set reserved field:", aurora.Cyan(field.Name))
return nil, ResultNoPermission
}
@ -262,15 +270,15 @@ func getInputFields(moduleName string, request StorageRequestData) (map[string]d
func createRecord(moduleName string, profileId uint32, gameInfo common.GameInfo, request StorageRequestData) StorageResponseBody {
if request.TableID == "" {
logging.Error(moduleName, "No table ID provided")
return StorageResponseBody{UpdateRecordResponse: &StorageUpdateRecordResponse{
UpdateRecordResult: ResultTableNotFound,
return StorageResponseBody{CreateRecordResponse: &StorageCreateRecordResponse{
CreateRecordResult: ResultTableNotFound,
}}
}
if gameInfo.Name == "mariokartwii" && (request.TableID == "GhostData" || request.TableID == "StoredGhostData") {
// Reserved for special handler
return StorageResponseBody{UpdateRecordResponse: &StorageUpdateRecordResponse{
UpdateRecordResult: ResultTableNotFound,
return StorageResponseBody{CreateRecordResponse: &StorageCreateRecordResponse{
CreateRecordResult: ResultTableNotFound,
}}
}
@ -278,8 +286,8 @@ func createRecord(moduleName string, profileId uint32, gameInfo common.GameInfo,
var result string
record.Fields, result = getInputFields(moduleName, request)
if result != ResultSuccess {
return StorageResponseBody{UpdateRecordResponse: &StorageUpdateRecordResponse{
UpdateRecordResult: result,
return StorageResponseBody{CreateRecordResponse: &StorageCreateRecordResponse{
CreateRecordResult: result,
}}
}
@ -289,17 +297,19 @@ func createRecord(moduleName string, profileId uint32, gameInfo common.GameInfo,
record.OwnerId = int32(profileId)
// TODO: Limit number of records or fields a user can have
err := database.InsertSakeRecord(pool, ctx, record)
recordId, err := database.InsertSakeRecord(pool, ctx, record)
if err != nil {
return StorageResponseBody{UpdateRecordResponse: &StorageUpdateRecordResponse{
UpdateRecordResult: ResultDatabaseUnavailable,
return StorageResponseBody{CreateRecordResponse: &StorageCreateRecordResponse{
CreateRecordResult: ResultDatabaseUnavailable,
}}
}
return StorageResponseBody{UpdateRecordResponse: &StorageUpdateRecordResponse{
UpdateRecordResult: ResultSuccess,
}}
logging.Info(moduleName, "Created record in table", aurora.Cyan(record.TableId), "with ID", aurora.Cyan(recordId), "for profile", aurora.Cyan(profileId))
return StorageResponseBody{CreateRecordResponse: &StorageCreateRecordResponse{
CreateRecordResult: ResultSuccess,
RecordID: recordId,
}}
}
func getMyRecords(moduleName string, profileId uint32, gameInfo common.GameInfo, request StorageRequestData) StorageResponseBody {
@ -474,7 +484,7 @@ func searchForRecords(moduleName string, profileId uint32, gameInfo common.GameI
SearchForRecordsResult: "Success",
Values: fillResponseValues(records, request),
}
logging.Info(moduleName, "Searched for records in table", aurora.Cyan(request.TableID), "for profile", aurora.Cyan(profileId), "with filter", aurora.Cyan(request.Filter), "and got", aurora.Cyan(len(records)), "records")
logging.Info(moduleName, "Found", aurora.Cyan(len(records)), "records in table", aurora.Cyan(request.TableID), "for profile", aurora.Cyan(profileId), "with filter", aurora.Cyan(request.Filter))
return StorageResponseBody{SearchForRecordsResponse: &response}
}