From: Joann Mõndresku Date: Mon, 13 May 2024 19:51:58 +0000 (+0300) Subject: "Cloud save" beginnings X-Git-Url: https://git.based.quest/?a=commitdiff_plain;h=6e25ceb89bac314579e82fddc5a9751299cdf719;p=reEgg.git "Cloud save" beginnings --- diff --git a/app.py b/app.py index 157df32..8e48c1c 100644 --- a/app.py +++ b/app.py @@ -12,11 +12,13 @@ from flask import request import contracts import events +import db_store upgrade_cache = {} app = Flask(__name__) contracts.load_contracts() +db_store.create_backups_db() @app.route('/ei/', methods=['POST']) def ei_routes(subpath): @@ -28,7 +30,25 @@ def ei_routes(subpath): ContactReq = EIProto.EggIncFirstContactRequest() ContactReq.ParseFromString(data) ContactResp = EIProto.EggIncFirstContactResponse() - if ContactReq.user_id in upgrade_cache: + Backups = db_store.get_backups(ContactReq.user_id) + if len(Backups) > 0: + # Lets process backups - check for any forced ones first + 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.force_backup = True + SaveBackup.force_offer_backup = True + ContactResp.backup.CopyFrom(SaveBackup) + db_store.update_backup(backup[0], backup[3], False) + break + except: + print("Failed to force serve backup - perhaps some logic error?") + break + # 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") ContactResp.backup.CopyFrom(cache[ContactReq.user_id]) del upgrade_cache[ContactReq.user_id] @@ -41,6 +61,9 @@ def ei_routes(subpath): SaveBackup.force_backup = True SaveBackup.force_offer_backup = True upgrade_cache[SaveBackup.user_id] = SaveBackup + else: + # start storing backups after permit upgrades + db_store.add_backup(SaveBackup.user_id, request.form["data"].replace(" ", "+")) elif subpath == "get_periodicals": PeriodicalResp = EIProto.PeriodicalsResponse() for evt in events.get_active_events(): diff --git a/db/.gitignore b/db/.gitignore new file mode 100644 index 0000000..98e6ef6 --- /dev/null +++ b/db/.gitignore @@ -0,0 +1 @@ +*.db diff --git a/db_store.py b/db_store.py new file mode 100644 index 0000000..9a3b421 --- /dev/null +++ b/db_store.py @@ -0,0 +1,74 @@ +# db_store.py - Providing "cloud saves" and such +import sqlite3 +import time + +# TODO: Truncate last x backups from a given device ID +def get_connection(dbName): + con = sqlite3.connect("db/" + dbName + ".db") + return con + +def create_backups_db(): + FreshInstall = True + con = get_connection("backups") + cur = con.cursor() + try: + cur.execute("CREATE TABLE Backups(BackupID INTEGER PRIMARY KEY AUTOINCREMENT, DeviceID TEXT, BackupStamp BIGINT, ForceOffer BOOL, Payload TEXT)") + except: + FreshInstall = False + con.commit() + con.close() + return FreshInstall + +def get_backup(ref_id): + if not isinstance(ref_id, int): + return None + con = get_connection("backups") + cur = con.cursor() + res = cur.execute("SELECT Payload FROM Backups WHERE BackupID=" + str(ref_id)) + tuple = res.fetchone() + con.close() + if tuple is None: + return tuple + else: + return tuple[0] + +def get_backups(device_id): + if not device_id.isalnum(): + return [] + con = get_connection("backups") + cur = con.cursor() + res = cur.execute("SELECT BackupID, BackupStamp, ForceOffer, Payload FROM Backups WHERE DeviceID=\"" + device_id + "\"") + x = res.fetchall() + if x is None: + return [] + else: + return x + +def add_backup(device_id, b64str): + if not device_id.isalnum(): + 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)) + con.commit() + con.close() + return + +def update_backup(refID, b64str, Force): + con = get_connection("backups") + cur = con.cursor() + res = cur.execute("UPDATE Backups SET ForceOffer=?, Payload=? WHERE BackupID=" + str(refID), (Force, b64str)) + con.commit() + con.close() + return + +def offer_backup_id_to_new_device(refID, device_id): + srcBackup = get_backup(refID) + if srcBackup is None: + return + add_backup(device_id, srcBackup) + return + +## MANUAL TRANSFER EXAMPLE +## TODO: Admin API endpoint for this +# offer_backup_id_to_new_device(2, "f7c9c95ce5f6d06a")