chore: refactor pefile methods

This commit is contained in:
aclist committed 2025-09-11 16:58:58 +09:00
1 parent b92e337016
commit 0d52c83ed9
2 files changed
+110 -93

No files matched your search

+35 -46
View File
@@ -24,7 +24,6 @@ class VersionMatch(Enum):
LOCAL_OLDER = 1 LOCAL_OLDER = 1
LOCAL_NEWER = 2 LOCAL_NEWER = 2
SAME_VERSION = 3 SAME_VERSION = 3
FAIL = 4
class u8: class u8:
@@ -288,17 +287,24 @@ def seek_to_pe_stub(data: BinaryIO) -> None:
raise PeFileError("missing PE header data") raise PeFileError("missing PE header data")
def get_dayz_version(file: Path) -> DayZVersion: def get_dayz_version(file: Path) -> DayZVersion | Exception:
version = get_version(file) try:
version = get_version(file)
except Exception as e:
return e
patch = str(version.build) + str(version.revision) patch = str(version.build) + str(version.revision)
dz_vers = DayZVersion(version.major, version.minor, int(patch)) dz_vers = DayZVersion(version.major, version.minor, int(patch))
return dz_vers return dz_vers
def get_dayz_version_str(file: Path) -> str: def dayz_version_to_str(v: DayZVersion) -> str:
v = get_dayz_version(file) return ".".join(str(el) for el in [v.major, v.minor, v.patch])
concat = ".".join(str(el) for el in [v.major, v.minor, v.patch])
return concat
def dayz_version_from_str(v: str) -> DayZVersion:
vers = v.split(".")
assert len(vers) == 3
return DayZVersion(*[int(el) for el in vers])
def get_version(file): def get_version(file):
@@ -389,14 +395,6 @@ def get_version(file):
return version return version
def is_older_version(local: str, remote: str) -> bool:
return Version(local) < Version(remote)
def is_newer_version(local: str, remote: str) -> bool:
return Version(local) > Version(remote)
def get_pefile_path(path: str, appid: int) -> Path: def get_pefile_path(path: str, appid: int) -> Path:
binary = "DayZ_x64.exe" binary = "DayZ_x64.exe"
identifier = {221100: "DayZ", 1024020: "DayZ Exp"} identifier = {221100: "DayZ", 1024020: "DayZ Exp"}
@@ -431,38 +429,29 @@ def get_pefile_path(path: str, appid: int) -> Path:
return pe_path return pe_path
def compare_versions(remote: str, appid: int, path: str): def compare_versions(local: DayZVersion, remote: DayZVersion):
if appid == 221100: """
build = "DayZ" packaging.version module is not available OOTB on some distributions
else: """
build = "DayZ Experimental" if dayz_version_to_str(local) == dayz_version_to_str(remote):
return VersionMatch.SAME_VERSION
local = None if local.major < remote.major:
pe_filepath = None return VersionMatch.LOCAL_OLDER
error = None if local.major > remote.major:
return VersionMatch.LOCAL_NEWER
try: if local.major == remote.major:
pe_filepath = get_pefile_path(path, appid) if local.minor < remote.minor:
except Exception as e: return VersionMatch.LOCAL_OLDER
return Result( if local.minor > remote.minor:
local, remote, build, pe_filepath, VersionMatch.FAIL, e return VersionMatch.LOCAL_NEWER
) if local.minor == remote.minor:
if local.patch < remote.patch:
try: return VersionMatch.LOCAL_OLDER
local = get_dayz_version_str(pe_filepath) if local.patch > remote.patch:
except PeFileError: return VersionMatch.LOCAL_NEWER
return Result( if local.patch == remote.patch:
local, remote, build, pe_filepath, VersionMatch.FAIL, error return VersionMatch.SAME_VERSION
)
if is_older_version(local, remote):
res = VersionMatch.LOCAL_OLDER
elif is_newer_version(local, remote):
res = VersionMatch.LOCAL_NEWER
else:
res = VersionMatch.SAME_VERSION
return Result(local, remote, build, pe_filepath, res, error)
def vdf_to_json(stream): def vdf_to_json(stream):
+75 -47
View File
@@ -24,7 +24,7 @@ import servers as Servers # noqa E402
import pefile as PeFile # noqa E402 import pefile as PeFile # noqa E402
from pefile import VDFLoadError, AppNotInstalledError, AppMovedError, PeFileError from pefile import VDFLoadError, AppNotInstalledError, AppMovedError, PeFileError
from pefile import VersionMatch from pefile import VersionMatch, DayZVersion
locale.setlocale(locale.LC_ALL, "") locale.setlocale(locale.LC_ALL, "")
@@ -2861,56 +2861,83 @@ class TreeView(Gtk.TreeView):
""" """
prereqs = Servers.get_prereqs(record.ip, record.qport) prereqs = Servers.get_prereqs(record.ip, record.qport)
if prereqs.appid is None: if prereqs.appid is None:
logger.warning(f"Query to '{record.ip}:{record.qport}' timed out")
msg = "Timed out when querying server, check IP or try again later" msg = "Timed out when querying server, check IP or try again later"
spawn_dialog(msg, Popup.NOTIFY) spawn_dialog(msg, Popup.NOTIFY)
return None return None
if prereqs.version is not None: build = "DayZ" if prereqs.appid == APPID_DAYZ else "DayZ Experimental"
path = query_config("default_steam_path")[0] steam_path = query_config("default_steam_path")[0]
result = PeFile.compare_versions(prereqs.version, prereqs.appid, path)
if result.error is not None: if len(steam_path) < 1:
logger.warning(result.error) logger.critical("Config file has no value set for 'default_steam_path'")
msg = f"Local Steam installation is not set, possibly malformed config file."
spawn_dialog(msg, Popup.NOTIFY)
return None
if result.match == VersionMatch.FAIL: try:
if isinstance(result.error, VDFLoadError) or isinstance(result.error, PeFileError): pefile_path = PeFile.get_pefile_path(steam_path, prereqs.appid)
# permissive; file exists, but could not determine version except AppNotInstalledError:
pass logger.critical(f"'{prereqs.appid}' not found in user's libraryfolders")
if isinstance(result.error, AppNotInstalledError): msg = (
if prereqs.appid == 1024020: f"This server is running {build}. "
msg = ( f"You can install {build} by searching for it in "
"This server is running DayZ Experimental, a beta build. " "your Steam library."
"You can install DayZ Experimental by searching for it in " )
"your Steam library." spawn_dialog(msg, Popup.NOTIFY)
) return None
spawn_dialog(msg, Popup.NOTIFY) except AppMovedError:
return None logger.critical(f"Library folder synch error for '{prereqs.appid}'")
if isinstance(result.error, AppMovedError): msg = (
f"Steam is reporting that {build} is installed at a non-existent location. "
f"If you recently installed {build} or moved it to a different drive, "
"restart Steam to allow these changes to synchronize, then try again."
)
spawn_dialog(msg, Popup.NOTIFY)
return None
except (VDFLoadError, PeFileError, Exception) as e:
logger.critical(e)
msg = "Steam settings or DayZ installation may be corrupted. Try restarting Steam."
spawn_dialog(msg, Popup.NOTIFY)
return None
try:
local_vers = PeFile.get_dayz_version(pefile_path)
except (PeFileError, Exception) as e:
"""
Currently permissive; file exists, but was unparseable.
"""
logger.warning(f"Failed to parse PE file: {e}")
local_vers = None
try:
remote_vers = PeFile.dayz_version_from_str(prereqs.version)
except Exception:
remote_vers = None
if (local_vers is not None and
remote_vers is not None):
match = PeFile.compare_versions(local_vers, remote_vers)
match match:
case VersionMatch.LOCAL_OLDER:
msg = ( msg = (
f"Steam is reporting that {result.build} is installed at a non-existent location. " f"This server is running a newer build ({prereqs.version}) of {build} than "
f"If you recently installed {result.build} or moved it to a different drive, " f"your local version. You may be unable to connect. Proceed anyway?"
"restart Steam to allow these changes to synchronize, then try again."
) )
spawn_dialog(msg, Popup.NOTIFY) res = spawn_dialog(msg, Popup.CONFIRM)
return None if res is True:
return None
if result.match == VersionMatch.LOCAL_OLDER: case VersionMatch.LOCAL_NEWER:
msg = ( msg = (
f"This server is running a newer build ({result.remote}) of {result.build} than " f"This server is running an out-of-date build ({prereqs.version}) of {build}. "
f"your local version ({result.local}). You may be unable to connect. Proceed anyway?" "You may be unable to connect. Proceed anyway?"
) )
res = spawn_dialog(msg, Popup.CONFIRM) res = spawn_dialog(msg, Popup.CONFIRM)
if res is True: if res is True:
return None return None
case VersionMatch.SAME_VERSION:
if result.match == VersionMatch.LOCAL_NEWER: pass
msg = (
f"This server is running an out-of-date build ({result.remote}) of {result.build}. "
"You may be unable to connect. Proceed anyway?"
)
res = spawn_dialog(msg, Popup.CONFIRM)
if res is True:
return None
if prereqs.password is True: if prereqs.password is True:
msg = ( msg = (
@@ -2924,14 +2951,13 @@ class TreeView(Gtk.TreeView):
""" """
When using RowType.CONN_BY_IP, the gameport needs to be interpolated When using RowType.CONN_BY_IP, the gameport needs to be interpolated
""" """
record.gameport = prereqs.gameport record.gameport = prereqs.gameport
addr = record_to_str(record) addr = record_to_str(record)
proc = call_out( proc = call_out(
"try_connect", "try_connect",
addr, addr,
str(prereqs.appid), str(prereqs.appid),
str(result.path) str(pefile_path)
) )
return proc return proc
@@ -4017,13 +4043,15 @@ class Options(Gtk.Box):
try: try:
pe_file_path = PeFile.get_pefile_path(default_steam_path, APPID_DAYZ) pe_file_path = PeFile.get_pefile_path(default_steam_path, APPID_DAYZ)
dayz_version = PeFile.get_dayz_version_str(pe_file_path) vers = PeFile.get_dayz_version(pe_file_path)
dayz_version = PeFile.dayz_version_to_str(vers)
except Exception: except Exception:
dayz_version = "-" dayz_version = "-"
try: try:
exp_file_path = PeFile.get_pefile_path(default_steam_path, APPID_DAYZ_EXP) exp_file_path = PeFile.get_pefile_path(default_steam_path, APPID_DAYZ_EXP)
dayz_exp_version = PeFile.get_dayz_version_str(exp_file_path) vers = PeFile.get_dayz_version(exp_file_path)
dayz_exp_version = PeFile.dayz_version_to_str(vers)
except Exception: except Exception:
dayz_exp_version = "-" dayz_exp_version = "-"