aboutsummaryrefslogtreecommitdiff
path: root/internal/game/cmd_swapid.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/cmd_swapid.go')
-rw-r--r--internal/game/cmd_swapid.go41
1 files changed, 25 insertions, 16 deletions
diff --git a/internal/game/cmd_swapid.go b/internal/game/cmd_swapid.go
index bbcc79c..ef862b9 100644
--- a/internal/game/cmd_swapid.go
+++ b/internal/game/cmd_swapid.go
@@ -76,26 +76,35 @@ func (g *Game) executeSwapID(sess *net.Session, args []string, rawInput string)
}
}
- // Swap the two files first. After this, path1 holds the old room id2's
- // content and path2 holds the old room id1's content. Rebuilding the index
- // then makes LoadRoom(id1)/LoadRoom(id2) return the swapped content, so the
- // reference rewrite below operates on the correctly-positioned rooms and
- // re-marshaling writes an `id:` field matching the new filename (keeping
- // the file's id field consistent with its name, as the old regex did).
- tempPath := path1 + ".swapid-tmp"
- if rerr := os.Rename(path1, tempPath); rerr != nil {
- sess.WriteLine(fmt.Sprintf("Error renaming room %d: %v", id1, rerr))
+ // Swap the two files' contents first. After this, path1 holds the old room
+ // id2's content and path2 holds the old room id1's content. Rebuilding the
+ // index then makes LoadRoom(id1)/LoadRoom(id2) return the swapped content,
+ // so the reference rewrite below operates on the correctly-positioned rooms
+ // and re-marshaling writes an `id:` field matching the new filename. The
+ // swap runs as one journal transaction (like handleRoomRename/the account
+ // lifecycle), so a crash mid-swap is rolled back at the next startup
+ // instead of leaving both rooms at wrong paths with no recovery record.
+ data1, rerr := os.ReadFile(path1)
+ if rerr != nil {
+ sess.WriteLine(fmt.Sprintf("Error reading room %d: %v", id1, rerr))
return
}
- if rerr := os.Rename(path2, path1); rerr != nil {
- os.Rename(tempPath, path1)
- sess.WriteLine(fmt.Sprintf("Error renaming room %d: %v", id2, rerr))
+ data2, rerr := os.ReadFile(path2)
+ if rerr != nil {
+ sess.WriteLine(fmt.Sprintf("Error reading room %d: %v", id2, rerr))
return
}
- if rerr := os.Rename(tempPath, path2); rerr != nil {
- os.Rename(path2, path1)
- os.Rename(tempPath, path1)
- sess.WriteLine(fmt.Sprintf("Error finishing rename: %v", rerr))
+ txn := g.newTxn()
+ if rerr := txn.Replace(path1, data2, 0644); rerr != nil {
+ sess.WriteLine(fmt.Sprintf("Error swapping rooms: %v", rerr))
+ return
+ }
+ if rerr := txn.Replace(path2, data1, 0644); rerr != nil {
+ sess.WriteLine(fmt.Sprintf("Error swapping rooms: %v", rerr))
+ return
+ }
+ if rerr := txn.Commit(); rerr != nil {
+ sess.WriteLine(fmt.Sprintf("Error swapping rooms: %v", rerr))
return
}