From 09fd6fd21d2c5018862262ccf5d4173f08bdbe9d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Joann=20M=C3=B5ndresku?= Date: Thu, 16 May 2024 19:50:51 +0300 Subject: [PATCH] Compress saves and cleanup older than 48h saves --- app.py | 17 +++++++++++++---- db_store.py | 41 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/app.py b/app.py index 02a91bd..eaef3d5 100644 --- a/app.py +++ b/app.py @@ -5,6 +5,7 @@ import base64 import datetime import time +import zlib import ei_pb2 as EIProto @@ -38,12 +39,14 @@ def ei_routes(subpath): Backups = db_store.get_backups(ContactReq.user_id) if len(Backups) > 0: # Lets process backups - check for any forced ones first + now = datetime.datetime.now() + cleanup_ids = [] for backup in Backups: if backup[2] == True: # Force backup found - lets serialize the payload SaveBackup = EIProto.Backup() try: - SaveBackup.ParseFromString(base64.b64decode(backup[3])) + SaveBackup.ParseFromString(base64.b64decode(zlib.decompress(backup[3]))) SaveBackup.force_backup = True SaveBackup.force_offer_backup = True ContactResp.backup.CopyFrom(SaveBackup) @@ -52,6 +55,12 @@ def ei_routes(subpath): except: print("Failed to force serve backup - perhaps some logic error?") break + else: + then = datetime.datetime.fromtimestamp(backup[1]) + if (now - then).days > 1: + cleanup_ids.append(backup[0]) + if len(cleanup_ids) > 0: + db_store.cleanup_backups(cleanup_ids) # TODO: Check for soul eggs/eggs of prophecy and determine algorithm for "is it worth offering?" elif ContactReq.user_id in upgrade_cache: print("Found an unupgraded save - lets upgrade the permit level to Pro") @@ -69,7 +78,7 @@ def ei_routes(subpath): upgrade_cache[SaveBackup.user_id] = SaveBackup else: # start storing backups after permit upgrades - db_store.add_backup(SaveBackup.user_id, request.form["data"].replace(" ", "+")) + db_store.add_backup(SaveBackup.user_id, base64.b64encode(zlib.compress(SaveBackup.SerializeToString()))) elif subpath == "get_periodicals": PeriodicalResp = EIProto.PeriodicalsResponse() for evt in events.get_active_events(): @@ -108,7 +117,7 @@ def ei_ps_routes(userid, method): if len(Backups) == 0: return "No such user found", 404 SaveBackup = EIProto.Backup() - SaveBackup.ParseFromString(base64.b64decode(Backups[-1][3])) + SaveBackup.ParseFromString(base64.b64decode(zlib.decompress(Backups[-1][3]))) if method == "break_piggy": if not SaveBackup.stats.piggy_full: return "Piggy Bank not full.", 403 @@ -124,7 +133,7 @@ def ei_ps_routes(userid, method): # BEFORE ENABLING - Piggy bank doesn't reset, need to find a way to trigger that. SaveBackup.game.piggy_bank = 1 SaveBackup.game.piggy_full_alert_shown = False - db_store.update_backup(Backups[-1][0], base64.b64encode(SaveBackup.SerializeToString()), True) + db_store.update_backup(Backups[-1][0], base64.b64encode(zlib.compress(SaveBackup.SerializeToString())), True) return "Broke the piggy bank - accept the backup offer when restarting your game.", 200 else: return "You need to have waited at least a week since filling the piggy bank before breaking it.", 403 diff --git a/db_store.py b/db_store.py index 9a3b421..45db008 100644 --- a/db_store.py +++ b/db_store.py @@ -32,6 +32,14 @@ def get_backup(ref_id): else: return tuple[0] +def cleanup_backups(numids): + con = get_connection("backups") + cur = con.cursor() + cur.execute("DELETE FROM Backups WHERE BackupID IN(" + (", ".join(map(str, numids))) + ")") + con.commit() + con.close() + return + def get_backups(device_id): if not device_id.isalnum(): return [] @@ -39,17 +47,32 @@ def get_backups(device_id): cur = con.cursor() res = cur.execute("SELECT BackupID, BackupStamp, ForceOffer, Payload FROM Backups WHERE DeviceID=\"" + device_id + "\"") x = res.fetchall() + con.close() if x is None: return [] else: return x +def get_last_backup(device_id): + if not device_id.isalnum(): + return None + con = get_connection("backups") + cur = con.cursor() + res = cur.execute("SELECT BackupID, BackupStamp, ForceOffer, Payload FROM Backups WHERE DeviceID=\"" + device_id + "\" ORDER BY BackupID DESC LIMIT 1") + x = res.fetchall() + con.close() + if x is None: + return [] + else: + return x[0] + def add_backup(device_id, b64str): if not device_id.isalnum(): - return + return con = get_connection("backups") cur = con.cursor() - res = cur.execute("INSERT INTO Backups(DeviceID, BackupStamp, ForceOffer, Payload) VALUES(?, ?, ?, ?)", (device_id, int(time.time()), False, b64str)) + stamp = int(time.time()) + res = cur.execute("INSERT INTO Backups(DeviceID, BackupStamp, ForceOffer, Payload) VALUES(?, ?, ?, ?)", (device_id, stamp, False, b64str)) con.commit() con.close() return @@ -69,6 +92,20 @@ def offer_backup_id_to_new_device(refID, device_id): add_backup(device_id, srcBackup) return +# If you used my server prior to zlib saves, uncomment and run once. +#import zlib +#import base64 +#def compress_to_zlib(): +# con = get_connection("backups") +# cur = con.cursor() +# res = cur.execute("SELECT BackupID, ForceOffer, Payload FROM Backups"); +# x = res.fetchall() +# con.close() +# for backup in x: +# print(backup[0]) +# update_backup(backup[0], base64.b64encode(zlib.compress(base64.b64decode(backup[2]))), backup[1]) +#compress_to_zlib() + ## MANUAL TRANSFER EXAMPLE ## TODO: Admin API endpoint for this # offer_backup_id_to_new_device(2, "f7c9c95ce5f6d06a") -- 2.25.1