def synchronize(self): if not is_locker_enabled(): return if "locker" not in self.context.meta: # We haven't looked up synchronization information from the server, # that probably means we didn't want to synchronize with the # server now, therefore we just return. return if self.stop_check(): return database = LockerDatabase.instance() sync_version = database.get_sync_version() if sync_version == self.context.meta["locker"]["sync"]: print("[SYNC] Locker data already up to date") return self.set_status(gettext("Fetching locker data...")) data = self.fetch_data("/api/locker-sync/1") assert len(data) % 20 == 0 self.set_status(gettext("Updating locker data...")) database.clear() k = 0 while k < len(data): sha1_bytes = data[k:k + 20] database.add_sha1_binary(sha1_bytes) k += 20 database.set_sync_version(self.context.meta["locker"]["sync"]) self.set_status(gettext("Committing locker data...")) self.update_file_database_timestamps() database.commit()
def synchronize(self): if not is_locker_enabled(): return if "locker" not in self.context.meta: # We haven't looked up synchronization information from the server, # that probably means we didn't want to synchronize with the # server now, therefore we just return. return if self.stop_check(): return database = LockerDatabase.instance() sync_version = database.get_sync_version() if sync_version == self.context.meta["locker"]["sync"]: print("[SYNC] Locker data already up to date") return self.set_status(gettext("Fetching locker data...")) data = self.fetch_data("/api/locker-sync/1") assert len(data) % 20 == 0 self.set_status(gettext("Updating locker data...")) database.clear() k = 0 while k < len(data): sha1_bytes = data[k : k + 20] database.add_sha1_binary(sha1_bytes) k += 20 database.set_sync_version(self.context.meta["locker"]["sync"]) self.set_status(gettext("Committing locker data...")) self.update_file_database_timestamps() database.commit()
def fetch_data(self, url): for i in range(10): try: return self.fetch_data_attempt(url) except Exception as e: print(e) sleep_time = 2.0 + i * 0.3 # FIXME: change second {0} to {1} self.set_status( gettext("Download failed (attempt {0}) - retrying in {0} " "seconds").format(i + 1, int(sleep_time))) time.sleep(sleep_time) self.set_status( gettext("Retrying last operation (attempt {0})").format(i + 1)) return self.fetch_data_attempt(url)
def fetch_data(self, url): for i in range(10): try: return self.fetch_data_attempt(url) except Exception as e: print(e) sleep_time = 2.0 + i * 0.3 # FIXME: change second {0} to {1} self.set_status( gettext("Download failed (attempt {0}) - retrying in {0} " "seconds").format(i + 1, int(sleep_time))) time.sleep(sleep_time) self.set_status( gettext("Retrying last operation (attempt {0})").format( i + 1)) return self.fetch_data_attempt(url)
def synchronize(self): if "game-database-version" not in self.context.meta: # we haven't looked up synchronization information from the server, # that probably means we didn't want to synchronize with the # server now, therefore we just return return self._synchronize() if self.stop_check(): self.client.database.rollback() else: print("committing data") self.set_status(gettext("Updating database"), gettext("Committing data...")) self.database.commit() print("done")
def synchronize(self): if self.stop_check(): return if not app.settings["database_auth"]: # not logged in return self.set_status(gettext("Fetching synchronization information...")) self.context.meta = self.fetch_json("/api/sync")
def synchronize(self): if self.stop_check(): return if "lists" not in self.context.meta: # Haven't looked up synchronization information from the server. return self.set_status(gettext("Updating game lists...")) database = Database.instance() cursor = database.cursor() cursor.execute("SELECT uuid, name, sync FROM game_list") # existing_lists = {} existing_syncs = {} for row in cursor: uuid, name, sync = row # existing_lists[uuid] = { # "name": name, # "sync": sync, # } existing_syncs[uuid] = sync # existing_syncs.sort() for list_uuid, list_info in self.context.meta["lists"].items(): if list_info["sync"] == existing_syncs.get(list_uuid, None): print("[SYNC] List {} already synced".format(list_uuid)) else: self.set_status( gettext("Updating list '{0}'...".format(list_info["name"])) ) self.synchronize_list(database, list_uuid, list_info) for existing_list_uuid in existing_syncs: for list_uuid in self.context.meta["lists"]: if list_uuid == existing_list_uuid: break else: # this old list should be removed self.set_status( gettext("Removing list {0}".format(existing_list_uuid)) ) self.remove_list(database, existing_list_uuid) database.commit()
def synchronize(self): if self.stop_check(): return if not app.settings["database_auth"]: # not logged in return self.set_status(gettext("Fetching synchronization information...")) self.context.meta = self.fetch_json("/api/sync/1")
def synchronize(self): if "database" not in self.context.meta: # we haven't looked up synchronization information from the server, # that probably means we didn't want to synchronize with the # server now, therefore we just return return self._synchronize() if self.stop_check(): self.client.database.rollback() else: print("committing data") self.set_status(gettext("Updating database"), gettext("Committing data...")) self.database.commit() print("done") if os.environ.get("FSGS_WRITE_DAT_FILES", "") == "1": self.write_dat_file()
def prepare_hard_drives(self): print("LaunchHandler.prepare_hard_drives") current_task.set_progress(gettext("Preparing hard drives...")) # self.on_progress(gettext("Preparing hard drives...")) for i in range(0, 10): key = "hard_drive_{0}".format(i) src = self.config.get(key, "") dummy, ext = os.path.splitext(src) ext = ext.lower() if is_http_url(src): name = src.rsplit("/", 1)[-1] name = urllib.parse.unquote(name) self.on_progress(gettext("Downloading {0}...".format(name))) dest = os.path.join(self.temp_dir, name) Downloader.install_file_from_url(src, dest) src = dest elif src.startswith("hd://game/"): self.unpack_game_hard_drive(i, src) self.disable_save_states() return elif src.startswith("hd://template/workbench/"): self.prepare_workbench_hard_drive(i, src) self.disable_save_states() return elif src.startswith("hd://template/empty/"): self.prepare_empty_hard_drive(i, src) self.disable_save_states() return if ext in Archive.extensions: print("zipped hard drive", src) self.unpack_hard_drive(i, src) self.disable_save_states() elif src.endswith("HardDrive"): print("XML-described hard drive", src) self.unpack_hard_drive(i, src) self.disable_save_states() else: src = Paths.expand_path(src) self.config[key] = src
def fetch_json(self, url): for i in range(20): try: return self.fetch_json_attempt(url) except Exception as e: print(e) sleep_time = 2.0 + i * 0.3 # FIXME: change second {0} to {1} self.set_status(gettext("Download failed (attempt {0}) - " "retrying in {1} seconds").format( i + 1, int(sleep_time))) for _ in range(int(sleep_time) * 10): time.sleep(0.1) if self.stop_check(): return self.set_status( gettext("Retrying last operation (attempt {0})").format( i + 1)) return self.fetch_json_attempt(url)
def fetch_game_sync_data(self): last_id = self.database.get_last_game_id() self.set_status( gettext("Fetching database entries ({0})").format(last_id + 1)) url = "{0}/api/sync/{1}/games?v=2&last={2}".format( self.url_prefix(), self.platform_id, last_id) print(url) data = self.fetch_data(url) self.downloaded_size += len(data) return data
def fetch_game_sync_data(self): last_id = self.database.get_last_game_id() if self.context.meta["games"][self.platform_id]["sync"] == last_id: print("[SYNC] Platform {} already synced".format(self.platform_id)) return b"" self.set_status( gettext("Fetching database entries ({0})").format(last_id + 1)) url = "{0}/api/sync/{1}/games?v=3&sync={2}".format( self.url_prefix(), self.platform_id, last_id) print(url) data = self.fetch_data(url) # self.downloaded_size += len(data) return data
def fetch_game_sync_data(self): last_id = self.database.get_last_game_id() if self.context.meta["games"][self.platform_id]["sync"] == last_id: print("[SYNC] Platform {} already synced".format(self.platform_id)) return b"" self.set_status( gettext("Fetching database entries ({0})").format(last_id + 1) ) url = "{0}/api/sync/{1}/games?v=3&sync={2}".format( self.url_prefix(), self.platform_id, last_id ) print(url) data = self.fetch_data(url) self.downloaded_size += len(data) return data
def fetch_rating_entries(self): cursor = self.client.database.cursor() cursor.execute("SELECT max(updated) FROM rating") row = cursor.fetchone() last_time = row[0] if not last_time: last_time = "2012-01-01 00:00:00" self.set_status( gettext("Fetching game ratings ({0})").format(last_time)) url = "{0}/api/sync/{1}/ratings?from={2}".format( self.url_prefix(), self.platform_id, quote_plus(last_time)) print(url) data, json_data = self.fetch_json(url) self.downloaded_size += len(data) return json_data
def cleanup(self): print("LaunchHandler.cleanup") self.on_progress(gettext("Cleaning up...")) # self.delete_tree(self.temp_dir) shutil.rmtree(self.temp_dir, ignore_errors=True) state_dir = self.get_state_dir() try: # this will only succeed if the directory is empty -we don't # want to leave unnecessary empty state directories os.rmdir(state_dir) print("removed", repr(state_dir)) # also try to remove the parent (letter dir) os.rmdir(os.path.dirname(state_dir)) print("removed", repr(os.path.dirname(state_dir))) except OSError: # could not delete directories - ok - probably has content pass
def prepare_floppies(self): print("LaunchHandler.copy_floppies") current_task.set_progress(gettext("Preparing floppy images...")) # self.on_progress(gettext("Preparing floppy images...")) floppies = [] for i in range(Amiga.MAX_FLOPPY_DRIVES): key = "floppy_drive_{0}".format(i) if self.config.get(key, ""): floppies.append(self.config[key]) self.prepare_floppy(key) for i in range(Amiga.MAX_FLOPPY_IMAGES): key = "floppy_image_{0}".format(i) if self.config.get(key, ""): break else: print("floppy image list is empty") for j, floppy in enumerate(floppies): self.config["floppy_image_{0}".format(j)] = floppy max_image = -1 for i in range(Amiga.MAX_FLOPPY_IMAGES): key = "floppy_image_{0}".format(i) self.prepare_floppy(key) if self.config.get(key, ""): max_image = i save_image = max_image + 1 if self.config.get("save_disk", "") != "0": s = Resources("fsgs", "res").stream("amiga/adf_save_disk.dat") data = s.read() data = zlib.decompress(data) save_disk = os.path.join(self.temp_dir, "Save Disk.adf") with open(save_disk, "wb") as f: f.write(data) key = "floppy_image_{0}".format(save_image) self.config[key] = "Save Disk.adf"
def _synchronize(self): if (self.context.meta["database"]["version"] != self.database.get_game_database_version()): self.set_status(gettext("Resetting game database...")) self.database.clear() self.database.set_game_database_version( self.context.meta["database"]["version"]) self.set_status(gettext("Synchronizing game database...")) while True: if self.stop_check(): return data = self.fetch_game_sync_data() if self.stop_check(): return if not data: print("no more changes") break t1 = time.time() k = 0 while k < len(data): game_sync_id = bytes_to_int(data[k:k + 4]) k += 4 game_uuid = data[k:k + 16] k += 16 game_data_size = bytes_to_int(data[k:k + 4]) k += 4 game_data = data[k:k + game_data_size] k += game_data_size # print("game data len:", len(game_data)) if len(game_data) > 0: self.database.add_game(game_sync_id, game_uuid, game_data) else: self.database.delete_game(game_sync_id, game_uuid) t2 = time.time() print(" {0:0.2f} seconds".format(t2 - t1)) last_json_data = "" while True: if self.stop_check(): return json_data = self.fetch_rating_entries() if self.stop_check(): return if json_data == last_json_data: print("no more changes") break last_json_data = json_data num_changes = len(json_data["ratings"]) print(" processing {0} entries".format(num_changes)) t1 = time.time() for update in json_data["ratings"]: cursor = self.client.database.cursor() cursor.execute( "SELECT count(*) FROM rating WHERE game_uuid = " "? AND work_rating = ? AND like_rating = ? " "AND updated = ?", ( update["game"], update["work"], update["like"], update["updated"], ), ) if cursor.fetchone()[0] == 1: # we want to avoid needlessly creating update transactions continue cursor.execute("DELETE FROM rating WHERE game_uuid = ?", (update["game"], )) cursor.execute( "INSERT INTO rating (game_uuid, work_rating, " "like_rating, updated) VALUES (?, ?, ?, ?)", ( update["game"], update["work"], update["like"], update["updated"], ), ) t2 = time.time() print(" {0:0.2f} seconds".format(t2 - t1))
def _synchronize(self): if self.context.meta["game-database-version"] != \ self.database.get_game_database_version(): self.set_status(gettext("Resetting game database...")) self.database.clear() self.database.set_game_database_version( self.context.meta["game-database-version"]) self.set_status(gettext("Synchronizing game database...")) while True: if self.stop_check(): return data = self.fetch_game_sync_data() if self.stop_check(): return if not data: print("no more changes") break t1 = time.time() k = 0 while k < len(data): game_sync_id = bytes_to_int(data[k:k + 4]) k += 4 game_uuid = data[k:k + 16] k += 16 game_data_size = bytes_to_int(data[k:k + 4]) k += 4 game_data = data[k:k + game_data_size] k += game_data_size # print("game data len:", len(game_data)) if len(game_data) > 0: self.database.add_game(game_sync_id, game_uuid, game_data) else: self.database.delete_game(game_sync_id, game_uuid) t2 = time.time() print(" {0:0.2f} seconds".format(t2 - t1)) last_json_data = "" while True: if self.stop_check(): return json_data = self.fetch_rating_entries() if self.stop_check(): return if json_data == last_json_data: print("no more changes") break last_json_data = json_data num_changes = len(json_data["ratings"]) print(" processing {0} entries".format(num_changes)) t1 = time.time() for update in json_data["ratings"]: cursor = self.client.database.cursor() cursor.execute( "SELECT count(*) FROM rating WHERE game_uuid = " "? AND work_rating = ? AND like_rating = ? " "AND updated = ?", (update["game"], update["work"], update["like"], update["updated"])) if cursor.fetchone()[0] == 1: # we want to avoid needlessly creating update transactions continue cursor.execute("DELETE FROM rating WHERE game_uuid = ?", (update["game"],)) cursor.execute( "INSERT INTO rating (game_uuid, work_rating, " "like_rating, updated) VALUES (?, ?, ?, ?)", (update["game"], update["work"], update["like"], update["updated"])) t2 = time.time() print(" {0:0.2f} seconds".format(t2 - t1)) print("downloaded size: {0:0.2f} MiB".format( self.downloaded_size / (1024 * 1024)))
def prepare_hard_drives(self): print("LaunchHandler.prepare_hard_drives") current_task.set_progress(gettext("Preparing hard drives...")) # self.on_progress(gettext("Preparing hard drives...")) for i in range(0, 10): self.prepare_hard_drive(i)
def update_changes(self): print("LaunchHandler.update_changes") self.on_progress(gettext("Saving changes...")) self.change_handler.update(self.get_state_dir())
def init_changes(self): print("LaunchHandler.init_changes") self.on_progress(gettext("Restoring changes...")) self.change_handler.init( self.get_state_dir(), ignore=["*.uss", "*.sdf"])
def copy_whdload_files(self, dest_dir, s_dir): whdload_args = self.config.get("x_whdload_args", "").strip() if not whdload_args: return print("LaunchHandler.copy_whdload_files") current_task.set_progress(gettext("Preparing WHDLoad...")) # self.on_progress(gettext("Preparing WHDLoad...")) print("copy_whdload_files, dest_dir = ", dest_dir) whdload_dir = "" slave = whdload_args.split(" ", 1)[0] slave = slave.lower() found_slave = False for dir_path, dir_names, file_names in os.walk(dest_dir): for name in file_names: # print(name, slave) if name.lower() == slave: print("found", name) found_slave = True whdload_dir = dir_path[len(dest_dir):] whdload_dir = whdload_dir.replace("\\", "/") if not whdload_dir: # slave was found in root directory pass elif whdload_dir[0] == "/": whdload_dir = whdload_dir[1:] break if found_slave: break if not found_slave: raise Exception( "Did not find the specified WHDLoad slave. " "Check the WHDLoad arguments") print("WHDLoad dir:", repr(whdload_dir)) print("WHDLoad args:", whdload_args) self.copy_whdload_kickstart( dest_dir, "kick34005.A500", ["891e9a547772fe0c6c19b610baf8bc4ea7fcb785"]) self.copy_whdload_kickstart( dest_dir, "kick40068.A1200", ["e21545723fe8374e91342617604f1b3d703094f1"]) self.copy_whdload_kickstart( dest_dir, "kick40068.A4000", ["5fe04842d04a489720f0f4bb0e46948199406f49"]) self.create_whdload_prefs_file(os.path.join(s_dir, "WHDLoad.prefs")) whdload_version = self.config["x_whdload_version"] if not whdload_version: whdload_version = DEFAULT_WHDLOAD_VERSION for key, value in whdload_files[whdload_version].items(): self.install_whdload_file(key, dest_dir, value) for key, value in whdload_support_files.items(): self.install_whdload_file(key, dest_dir, value) if self.config.get("__netplay_game", ""): print("WHDLoad key is not copied in net play mode") else: key_file = os.path.join( self.fsgs.amiga.get_base_dir(), "WHDLoad.key") if os.path.exists(key_file): print("found WHDLoad.key at ", key_file) shutil.copy(key_file, os.path.join(s_dir, "WHDLoad.key")) else: print("WHDLoad key not found in base dir (FS-UAE dir)") # temporary feature, at least until it's possible to set more # WHDLoad settings directly in the Launcher prefs_file = os.path.join( self.fsgs.amiga.get_base_dir(), "WHDLoad.prefs") if os.path.exists(prefs_file): print("found WHDLoad.prefs at ", prefs_file) shutil.copy(prefs_file, os.path.join(s_dir, "WHDLoad.prefs")) else: print("WHDLoad key not found in base dir (FS-UAE dir)") if self.config.get("__netplay_game", ""): print("WHDLoad base dir is not copied in net play mode") else: src_dir = self.fsgs.amiga.get_whdload_dir() if src_dir and os.path.exists(src_dir): print("WHDLoad base dir exists, copying resources...") self.copy_folder_tree(src_dir, dest_dir) # icon = self.config.get("__whdload_icon", "") icon = "" if icon: shutil.copy(os.path.expanduser("~/kgiconload"), os.path.join(dest_dir, "C", "kgiconload")) icon_path = os.path.join(dest_dir, icon) print("create icon at ", icon_path) create_slave_icon(icon_path, whdload_args) self.write_startup_sequence( s_dir, "cd \"{0}\"\n" "kgiconload {1}\n" "uae-configuration SPC_QUIT 1\n".format( whdload_dir, os.path.basename(icon))) else: self.write_startup_sequence( s_dir, whdload_sequence.format(whdload_dir, whdload_args))
def install_whdload_file(self, sha1, dest_dir, rel_path): abs_path = os.path.join(dest_dir, rel_path) name = os.path.basename(rel_path) self.on_progress(gettext("Downloading {0}...".format(name))) Downloader.install_file_by_sha1(sha1, name, abs_path)
def prepare_roms(self): print("LaunchHandler.prepare_roms") current_task.set_progress(gettext("Preparing kickstart ROMs...")) amiga_model = self.config.get("amiga_model", "A500") model_config = Amiga.get_model_config(amiga_model) roms = [("kickstart_file", model_config["kickstarts"])] if self.config["kickstart_ext_file"] or model_config["ext_roms"]: # not all Amigas have extended ROMs roms.append(("kickstart_ext_file", model_config["ext_roms"])) if amiga_model.lower() == "cd32/fmv": roms.append(("fvm_rom", [CD32_FMV_ROM])) if self.config["graphics_card"].lower().startswith("picasso-iv"): roms.append(("graphics_card_rom", [PICASSO_IV_74_ROM])) if self.config["accelerator"].lower() == "cyberstorm-ppc": roms.append(("accelerator_rom", ["cyberstormppc.rom"])) if self.config["freezer_cartridge"] == "action-replay-2": # Ideally, we would want to recognize ROMs based on zeroing the # first four bytes, but right now we simply recognize a common # additional version. freezer_cartridge_rom isn't a real option, # we just want to copy the rom file and let FS-UAE find it roms.append(("[freezer_cartridge]", [ACTION_REPLAY_MK_II_2_14_ROM.sha1, ACTION_REPLAY_MK_II_2_14_MOD_ROM.sha1])) elif self.config["freezer_cartridge"] == "action-replay-3": roms.append(("[freezer_cartridge]", [ACTION_REPLAY_MK_III_3_17_ROM.sha1, ACTION_REPLAY_MK_III_3_17_MOD_ROM.sha1])) for config_key, default_roms in roms: print("ROM:", config_key, default_roms) src = self.config[config_key] if not src: for sha1 in default_roms: if is_sha1(sha1): rom_src = self.fsgs.file.find_by_sha1(sha1) if rom_src: src = rom_src break else: # roms_dir = FSGSDirectories.get_kickstarts_dir() # src = os.path.join(roms_dir, sha1) # if os.path.exists(src): # break # loop up file in roms dir instead src = sha1 elif src == "internal": continue elif src: src = Paths.expand_path(src) if not src: raise TaskFailure( gettext("Did not find required Kickstart or " "ROM for {}. Wanted one of these files: {}".format( config_key, repr(default_roms)))) use_temp_kickstarts_dir = False dest = os.path.join(self.temp_dir, os.path.basename(src)) archive = Archive(src) stream = None if not archive.exists(src): dirs = [self.fsgs.amiga.get_kickstarts_dir()] for dir in dirs: path = os.path.join(dir, src) print("checking", repr(path)) archive = Archive(path) if archive.exists(path): src = path break else: try: stream = self.fsgs.file.open(src) if stream is None: raise FileNotFoundError(src) except FileNotFoundError: raise TaskFailure(gettext( "Cannot find required ROM " "file: {name}".format(name=repr(src)))) with open(dest, "wb") as f: if stream: f.write(stream.read()) else: ROMManager.decrypt_archive_rom(archive, src, file=f) if use_temp_kickstarts_dir: self.config[config_key] = os.path.basename(src) else: self.config[config_key] = dest if use_temp_kickstarts_dir: self.config["kickstarts_dir"] = self.temp_dir