change: simplify routes between query API

This commit is contained in:
aclist 2026-05-07 00:19:01 +09:00
parent a9863ff86b
commit 7523bffbd8
7 changed files with 94 additions and 110 deletions

View File

@ -20,6 +20,7 @@ import a2s
import dayzquery
if TYPE_CHECKING:
from a2s import SourceInfo
from dayzquery import DayzMod
logger = logging.getLogger(APP_NAME)
@ -40,18 +41,54 @@ params = [
]
#class BmAPIError(Exception):
# pass
#
#
#class BmIdError(Exception):
# pass
class InvalidIpError(Exception):
pass
@dataclass(slots=True, frozen=True)
class Res:
status: int
parsed: bool
json: Union[dict[str, Any], None]
@dataclass(slots=True, frozen=True)
class Details:
data: Union[list, None]
description: str
success: bool
@dataclass(slots=True)
class Record:
"""
The gameport field is manipulated by the RowType.CONN_BY_IP method
"""
ip: str
gameport: int
qport: int
class A2SInfo:
def __init__(self, record: Record, info: a2s.SourceInfo | None) -> None:
self.record = record
self.info = info
def get_record(self) -> Record:
return self.record
def get_info(self) -> a2s.SourceInfo | None:
return self.info
def as_row(self) -> dict[str, Any] | None:
if self.info is None:
return None
ip = self.record.ip
qport = self.record.qport
return source_info_to_dict(ip, qport, self.info)
def get_netmask() -> str:
hostname = os.uname()[1]
i = socket.gethostbyname(hostname)
@ -191,11 +228,8 @@ def parse_json(json: list) -> list:
return rows
def query_direct(ip: str, qport: int, timeout: float = 3.0) -> dict | None:
def source_info_to_dict(ip: str, qport: int, info: "SourceInfo") -> dict[str, Any]:
try:
info = a2s.info((ip, qport), timeout)
name = info.server_name
mapname = info.map_name
address = ip + ":" + str(qport)
@ -221,61 +255,18 @@ def query_direct(ip: str, qport: int, timeout: float = 3.0) -> dict | None:
res["ping"] = ping
return res
except Exception as e:
# TODO: generalized function
logger.critical(f"{type(e).__name__}: {e} ({ip}:{qport})")
return None
@dataclass(slots=True, frozen=True)
class Res:
status: int
parsed: bool
json: Union[dict[str, Any], None]
@dataclass(slots=True, frozen=True)
class Details:
data: Union[list, None]
description: str
success: bool
#@dataclass(slots=True, frozen=True)
#class Prereqs:
# password: bool
# gameport: int
# appid: Union[int, None]
# version: Union[str, None]
@dataclass(slots=True)
class Record:
"""
The gameport field is manipulated by the RowType.CONN_BY_IP method
"""
ip: str
gameport: int
qport: int
@dataclass(frozen=True, slots=True)
class PreReqs:
record: Record
source: a2s.SourceInfo
#def get_prereqs(ip: str, qport: int) -> Prereqs:
# try:
# info = a2s.info((ip, qport))
# except TimeoutError:
# return Prereqs(False, 0, None, None)
#
# gameport = getattr(info, "port", 0)
# is_password = getattr(info, "password_protected", False)
# appid = getattr(info, "game_id", None)
# version = getattr(info, "version", None)
#
# return Prereqs(is_password, gameport, appid, version)
def query_direct(ip: str, qport: int, timeout: float = 3.0) -> dict[str, Any] | None:
try:
info = a2s.info((ip, qport), timeout)
return source_info_to_dict(ip, qport, info)
except Exception as e:
logger.critical(e)
return None
def get_details(record: Record) -> Details:
@ -443,18 +434,6 @@ def get_rules(record: Record) -> list["DayzMod"]:
return [mod for mod in mods]
def query_by_id(server_id: int, key: str, full: bool = False) -> dict[Any] | None:
"""
Used with numeric Battlemetrics IDs
"""
try:
resolved = map_id_to_record(key, server_id)
return query_direct(resolved.ip, resolved.qport, full)
except Exception as e:
logger.critical(e)
return None
def query_playercount(record: Record) -> tuple[int, int] | None:
try:
res = query_direct(record.ip, record.qport)
@ -470,24 +449,25 @@ def query_playercount(record: Record) -> tuple[int, int] | None:
return None
def query_by_ip(addr: str, full: bool = False) -> dict[str, Any] | PreReqs | None:
def query_by_ip(addr: str) -> A2SInfo:
record = short_ip_to_record(addr)
return query_by_record(record, full)
return query_by_record(record)
def query_by_record(record: Record, full: bool = False) -> dict[str, Any] | PreReqs | None:
if full:
try:
info = a2s.info((record.ip, record.qport), 3.0)
return PreReqs(record, info)
except Exception as e:
logger.critical(e)
return None
def query_by_id(server_id: int, key: str) -> dict[Any] | None:
"""
Used with numeric Battlemetrics IDs
"""
record = map_id_to_record(key, server_id)
return query_by_record(record)
def query_by_record(record: Record) -> A2SInfo:
try:
return query_direct(record.ip, record.qport)
info = a2s.info((record.ip, record.qport), 3.0)
return A2SInfo(record, info)
except Exception as e:
logger.critical(e)
return None
logger.warning(e)
return A2SInfo(record, None)
def short_ip_to_record(addr: str) -> Optional[Record]:

View File

@ -37,7 +37,7 @@ logger = logging.getLogger(APP_NAME)
if TYPE_CHECKING:
from dayzquery import DayzMod
from dzgui.api.servers import PreReqs, Record
from dzgui.api.servers import A2SInfo, Record
from dzgui.const.enum import ServerTab
from dzgui.managers.filter import FilterManager
from dzgui.util.dist import Haversine
@ -458,7 +458,7 @@ class Controller(GObject.GObject):
def set_exit_event(self) -> None:
self.exit_event.set()
def open_connection_assistant(self, res: "PreReqs", mods: list["DayzMod"]) -> None:
def open_connection_assistant(self, res: "A2SInfo", mods: list["DayzMod"]) -> None:
self.open_page(NotebookPage.CONNECTION)
self.mediator.preconnect.populate(res, mods)

View File

@ -2,7 +2,7 @@ import logging
import shutil
from pathlib import Path
from typing import Union, TYPE_CHECKING
from typing import TYPE_CHECKING
import dzgui.api.pefile as PeFile
import dzgui.api.servers as Servers
@ -22,7 +22,7 @@ gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa E402
if TYPE_CHECKING:
from dzgui.api.servers import PreReqs
from dzgui.api.servers import A2SInfo
from dzgui.controllers.mc import Controller
logger = logging.getLogger(APP_NAME)
@ -36,26 +36,26 @@ class ConnectionManager:
@call_on_thread(dialog.querying)
def connect_by_id(self, _id: int, key: str) -> None:
res = Servers.query_by_id(_id, key, full=True)
res = Servers.query_by_id(_id, key)
self._prepare_connection(res)
@call_on_thread(dialog.querying)
def connect_by_ip(self, addr: str) -> None:
res = Servers.query_by_ip(addr, full=True)
res = Servers.query_by_ip(addr)
self._prepare_connection(res)
@call_on_thread(dialog.querying)
def connect_by_record(self, record: Servers.Record) -> None:
res = Servers.query_by_record(record, full=True)
res = Servers.query_by_record(record)
self._prepare_connection(res)
def _prepare_connection(self, res: Union["PreReqs", None]) -> None:
def _prepare_connection(self, res: "A2SInfo") -> None:
failure_func = StoredFunc(self._server_timeout)
if res is None:
if res.get_info() is None:
self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
return
record = res.record
record = res.get_record()
try:
remote_mods = self._query_modlist(record)
remote_mod_ids = [mod[1] for mod in remote_mods]
@ -79,7 +79,7 @@ class ConnectionManager:
# TODO: when downloading mods, create symlinks if missing
# TODO: get missing mod sizes, warn if not enough space
info = res.source
info = res.get_info()
try:
dayz_path = PeFile.get_pefile_path(steam_path, info.game_id)
# TODO: handle missing path; do not calculate size if appid is missing

View File

@ -23,6 +23,7 @@ gi.require_version("Gtk", "3.0")
from gi.repository import Gtk # noqa E402
if TYPE_CHECKING:
from dzgui.api.servers import A2SInfo
from dzgui.controllers.mc import Controller
from dzgui.model.proxy_model import ProxyModelManager
from dzgui.views.trees.tree_servers import ServerTreeView
@ -39,6 +40,7 @@ class NewPlayerCount:
queue: int
class ServerModelManager:
def __init__(self, controller: "Controller", tv: "ServerTreeView") -> None:
@ -256,23 +258,24 @@ class ServerModelManager:
proxy_man.update_playercount(self.playercount)
def _parse_single_record(
self, response: dict[Any, Any] | None, delete: bool = False
self, response: "A2SInfo", delete: bool = False
) -> None:
self.preserve_on_fail = True
if response is None:
row = response.as_row()
if row is None:
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure))
return
# NOTE: expected to only contain one item
records = Servers.parse_json([response])
records = Servers.parse_json([row])
server = records[0]
if server is None:
return
proxy_man = self._get_proxy_man()
config_man = self.controller.get_config_man()
fqip = Servers.response_to_fqip(response)
record = Servers.response_to_record(response)
fqip = Servers.response_to_fqip(row)
record = response.get_record() #Servers.response_to_record(row)
# TODO: less convoluted
if delete:

View File

@ -57,7 +57,7 @@ copy_ip = "Copy IP to clipboard"
copy_log = "Copy record(s) to clipboard"
add = "Add to Saved Servers"
add_fav = "Set as favorite"
remove = "Remove from my servers"
remove = "Remove from Saved Servers"
remove_history = "Remove from history"
connect = "Connect"

View File

@ -22,7 +22,7 @@ from gi.repository import Gdk, Gtk # type: ignore # noqa E402
if TYPE_CHECKING:
from dzgui.api.servers import PreReqs
from dzgui.api.servers import A2SInfo
from dzgui.controllers.mc import Controller
@ -142,7 +142,7 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
self.add(self.box)
# self.connect("key-press-event", self._on_keypress)
self.connect("key-press-event", self._on_keypress)
self.connect("map", self._on_map)
def _on_map(self, widget: Self) -> None:
@ -162,13 +162,14 @@ class PreConnectionAssistant(Gtk.ScrolledWindow):
page = self.controller.get_prior_page()
self.controller.open_page(page)
def populate(self, res: "PreReqs", mods: list["DayzMod"]) -> None:
def populate(self, res: "A2SInfo", mods: list["DayzMod"]) -> None:
self.tree.populate(mods)
total = len(mods)
self._set_warnings()
name = res.source.server_name
info = res.get_info()
name = info.server_name
self.title.set_text(name)
if total < 1:
self.tree_frame.set_visible(False)

View File

@ -144,7 +144,7 @@ class TreeView(CursorMixin, Gtk.TreeView): # type: ignore
path = pathlist[0]
tree_iter = model.get_iter(path)
value = model.get_value(tree_iter, index)
return str(value)
return value
def get_name(self) -> str:
name = self.get_value_at_index(0)