mirror of
https://github.com/aclist/dztui.git
synced 2026-08-28 10:47:15 +02:00
change: simplify routes between query API
This commit is contained in:
parent
a9863ff86b
commit
7523bffbd8
@ -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]:
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user