diff --git a/backend/cmd/server/save_format_test.go b/backend/cmd/server/save_format_test.go new file mode 100644 index 0000000..e621471 --- /dev/null +++ b/backend/cmd/server/save_format_test.go @@ -0,0 +1,26 @@ +package main + +import "testing" + +func TestSaveRecordFormat(t *testing.T) { + cases := []struct { + name string + payloadFile string + want string + }{ + {"gb battery save", "payload.srm", "srm"}, + {"gb rtc save", "payload.rtc", "rtc"}, + {"uppercase extension is normalized", "payload.SRM", "srm"}, + {"no extension", "payload", ""}, + {"empty payload file", "", ""}, + {"multi-dot keeps final ext", "payload.tar.gz", "gz"}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := saveRecordFormat(saveRecord{PayloadFile: tc.payloadFile}) + if got != tc.want { + t.Fatalf("saveRecordFormat(%q) = %q, want %q", tc.payloadFile, got, tc.want) + } + }) + } +} diff --git a/backend/cmd/server/save_handlers.go b/backend/cmd/server/save_handlers.go index fad4aec..6548ece 100755 --- a/backend/cmd/server/save_handlers.go +++ b/backend/cmd/server/save_handlers.go @@ -11,6 +11,7 @@ import ( "io" "net/http" "os" + "path/filepath" "sort" "strconv" "strings" @@ -107,6 +108,15 @@ func latestReadableSaveRecordByTrackContext(records []saveRecord, filename, syst return latestSaveRecordForKey(records, trackKey, canonicalDuplicateTrackKeyForRecord) } +// saveRecordFormat returns the bare lowercase payload extension (e.g. "rtc", +// "srm"), or "" when unknown. Helpers use it to distinguish co-slotted save +// components that share a slotName — notably Game Boy battery saves (.srm) and +// RTC saves (.rtc) — so a smaller, newer companion file is not mistaken for a +// newer revision of the other and allowed to clobber it as "latest". +func saveRecordFormat(rec saveRecord) string { + return strings.TrimPrefix(strings.ToLower(filepath.Ext(rec.PayloadFile)), ".") +} + func (a *app) handleSaveLatest(w http.ResponseWriter, r *http.Request) { _ = requestPrincipal(r) helperCtx, ok := a.authorizeHelperSyncRequest(w, r, nil) @@ -139,6 +149,7 @@ func (a *app) handleSaveLatest(w http.ResponseWriter, r *http.Request) { "sha256": latest.Summary.SHA256, "version": latest.Summary.Version, "id": latest.Summary.ID, + "format": saveRecordFormat(latest), }) return } @@ -154,6 +165,7 @@ func (a *app) handleSaveLatest(w http.ResponseWriter, r *http.Request) { "sha256": latest.Summary.SHA256, "version": latest.Summary.Version, "id": latest.Summary.ID, + "format": saveRecordFormat(latest), }) return } @@ -217,6 +229,7 @@ func (a *app) handleSaveLatest(w http.ResponseWriter, r *http.Request) { "sha256": shaValue, "version": latest.Summary.Version, "id": latest.Summary.ID, + "format": saveRecordFormat(latest), }) return }