freeciv-web icon indicating copy to clipboard operation
freeciv-web copied to clipboard

PBEM fails due to save game compression change from .xz to .zst

Open erichelgeson opened this issue 2 years ago • 13 comments

Using develop branch at 583adba07f1b39509f14a51b97ec191e215dcbbe

... Configure email vagrant up .. provision succeeds Start a PBEM game - welcome email sent.

Take first turn - the savegame/pbem/ dir contains a file ending in .zst

Currently the pbem.py script only handles .xz compressed files and fails to send next turn email to player https://github.com/freeciv/freeciv-web/blob/c5930c2cee01344af8a09dbc8affec641360c846/pbem/pbem.py#L97

erichelgeson avatar Jun 30 '22 21:06 erichelgeson

Thanks for reporting, pull requests welcome.

andreasrosdal avatar Jul 01 '22 09:07 andreasrosdal

diff --git a/pbem/pbem.py b/pbem/pbem.py
index 12fd92b..a4ef18a 100644
--- a/pbem/pbem.py
+++ b/pbem/pbem.py
@@ -20,7 +20,10 @@

 import os, os.path
 import time
-import lzma
+#import lzma
+import zstandard as zstd
+import tempfile
 import mysql.connector
 from mailsender import MailSender
 from mailstatus import *
@@ -94,14 +97,20 @@ def handle_savegame(root, file):
   print("Handling savegame: " + filename);
   txt = None;
   try:
-    with lzma.open(filename,  mode="rt") as f:
-      txt = f.read().split("\n");
-      status.savegames_read += 1;
+    with open(filename, 'rb') as compressed:
+        decomp = zstd.ZstdDecompressor()
+        output_path = tempfile.NamedTemporaryFile().name
+        with open(output_path, 'wb') as destination:
+            decomp.copy_stream(compressed, destination)
+    with open(output_path, "rt") as f:
+        txt = f.read().split("\n");
+        status.savegames_read += 1;
   except Exception as inst:
     print("Error loading savegame: " + str(inst));
     return;

-  new_filename = "pbem_processed_" + str(random.randint(0,10000000000)) + ".xz";
+  new_filename = "pbem_processed_" + str(random.randint(0,10000000000)) + ".zst";
   f.close();
   if not testmode: shutil.move(filename, os.path.join(root,new_filename))
   print("New filename will be: " + new_filename);
@@ -220,7 +229,7 @@ def save_game_result(winner, playerOne, playerTwo):
 def process_savegames():
   for root, subFolders, files in os.walk(savedir):
     for file in files:
-      if (file.endswith(".xz") and file.startswith("pbem") and not file.startswith("pbem_processed")):
+      if (file.endswith(".zst") and file.startswith("pbem") and not file.startswith("pbem_processed")):
         handle_savegame(root, file);

Here is a very trivial patch in that it does not handle any migrations, and creates a temp file - zstandard does not have the same read() like lzma does. It appears the entire file is loaded into memory anyways and I'd think they are small so this may be OK. Any guidance would be appreciated - more of a Java dev then python.

erichelgeson avatar Jul 01 '22 15:07 erichelgeson

Unfortunately this only partially works - while the game saves after the first turn to a zst file - when a player clicks a link to take the next turn it is looking for a xz file... I'm not sure where that is handled.

erichelgeson avatar Jul 01 '22 16:07 erichelgeson

https://github.com/freeciv/freeciv-web/blob/develop/freeciv-web/src/main/webapp/javascript/pbem.js#L514

https://github.com/freeciv/freeciv-web/blob/develop/pbem/pbem.py#L125

Please submit a propser GitHub pull request.

andreasrosdal avatar Jul 01 '22 17:07 andreasrosdal

Or revert to using .xz compression format in Freeciv-web. The differences between the various compession formats is usually minimal these days.

andreasrosdal avatar Jul 01 '22 18:07 andreasrosdal

I'm trying to trace how this all works and as someone unfamiliar with the codebase, it's quite complex. So the pbem.js script is sending a websocket message to a python proxy, which is sending that save game name to an actual freeciv instance. It seems like I could recompile with compresstype set to xz possibly, though I'm not familiar with this build/make/meson setup to know where the correct location is, or even if this is a compile time setting.

erichelgeson avatar Jul 01 '22 18:07 erichelgeson

@cazfi

andreasrosdal avatar Jul 01 '22 19:07 andreasrosdal

I've meant to work on implementing the zstd support, but thought that all game types currently hardcode .xz to use in their .serv files (compresstype server setting). That might not be the case for pbem games? Another quick solution is to revert installing libzstd-dev to freeciv-web, so that the server build will not find it.

cazfi avatar Jul 01 '22 19:07 cazfi

Hmm... publite2/pubscript_pbem.serv has "set compresstype xz" - isn't that one currently used for pbem games?

cazfi avatar Jul 01 '22 19:07 cazfi

Ahh, so that was the issue - I was switching the rule set as I thought (maybe incorrectly) that for web games I should be using Webperimental - if i try to start a game with that ruleset the compression is .zst and attempting to change that setting it says "you are not allowed to change the setting compresstype" - which makes sense for users not to do that.

I guess the fix is to ensure any rulesets used by the web save in the correct compresstype. Though, looking at the rulesets/.serv files - I'm not sure the correct way to go.

Edit: Would adding set compresstype xz to freeciv/freeciv/data/webperimental.serv be the right solution/work around? does freeciv need a recompile to pick up these files?

erichelgeson avatar Jul 01 '22 20:07 erichelgeson

This seems to be a bigger problem than just the compresstype then. Freeciv-web (publite) seems to be designed with the assumption that settings set in the .serv file it initially feeds to the server remain in effect. But that's not the case if user changes ruleset, causing settings to reset to server's defaults. We can't really patch individual ruleset .serv files, as 1) those publite2/*.serv files are different between pbem/singleplayer/multiplayer -> for some settings, there's not a single value that would be correct in all cases, 2) are probably never read anyway (/rulesetdir just changes the ruleset, it does not run any .serv that would do that) To resolve (2) we could change settings list in game.ruleset, but I don't think that's a step toward proper fix.

Maybe we should have some feature in the server for it to reread the initial .serv file when ever the settings get resetted.

cazfi avatar Jul 02 '22 02:07 cazfi

Some of those "game type" .serv files under publite also want to set specific rulesetdir, so in those cases changing the ruleset should not be allowed at all. Likely we should now just disallow changing ruleset, and enable it only when we have a bunch of new server features to support all this.

cazfi avatar Jul 02 '22 18:07 cazfi

we should now just disallow changing ruleset

https://github.com/freeciv/freeciv-web/pull/485

cazfi avatar Jul 02 '22 18:07 cazfi