feat: preconnection assistant (WIP)

This commit is contained in:
aclist 2026-05-04 01:18:09 +09:00
parent 139b226959
commit 33fbf765ed
8 changed files with 78 additions and 23 deletions

View File

@ -154,7 +154,12 @@ def remove_stale_signatures(config: Path, versions: Path) -> None:
def find_stale_mods(config: Path) -> list[int]:
def push_record(rec: str) -> list:
record = fqip_to_record(rec)
return [mod.workshop_id for mod in get_rules(record)]
try:
mods = get_rules(record)
print(mods)
except Exception:
return []
return [mod.workshop_id for mod in mods]
steam = lookup(config, Preferences.DEFAULT)
steam_path = Path(steam)

View File

@ -438,6 +438,7 @@ def get_rules(record: Record) -> list["DayzMod"]:
return [mod for mod in mods]
except Exception as e:
logger.critical(e)
# TODO: supposed to skip failing servers for highlight action
return []

View File

@ -109,6 +109,7 @@ class NotebookPage(EnumWithAttrs):
OPTIONS = {"crumbs": strings.crumbs.options, "statusbar": False}
SERVERS = {"crumbs": strings.crumbs.servers, "statusbar": True}
THANKS = {"crumbs": strings.crumbs.thanks, "statusbar": True}
CONNECTION = {"crumbs": "Connect", "statusbar": False}
class RowType(EnumWithAttrs):

View File

@ -27,6 +27,7 @@ from dzgui.util.format import format_player_count
from dzgui.util.open_links import open_user_workshop, open_workshop_page
from dzgui.views.dialogs.filepicker import FilePicker
from dzgui.views.dialogs.generic import ExceptionDialog
from dzgui.views.dialogs.servers import ServerModDialog
import gi
@ -38,6 +39,7 @@ logger = logging.getLogger(APP_NAME)
if TYPE_CHECKING:
from dzgui.api.servers import Record
from dzgui.const.enum import ServerTab
from dzgui.lib.dayzquery import DayzMod
from dzgui.managers.filter import FilterManager
from dzgui.util.dist import Haversine
from dzgui.views.base import Notebook, Grid, OuterWindow
@ -139,7 +141,9 @@ class Controller(GObject.GObject):
def remove_statusbar(self, context: "NotebookPage | ServerTab") -> None:
self.mediator.statusbar.pop(context)
def set_statusbar_dist(self, haversine: Union["Haversine", None], enum: "ServerTab") -> None:
def set_statusbar_dist(
self, haversine: Union["Haversine", None], enum: "ServerTab"
) -> None:
"""
NOTE: prevents race condition when server tab changed,
but allows caching the distance in the background
@ -400,7 +404,7 @@ class Controller(GObject.GObject):
ConnectionManager(self).query_details(record)
def get_modlist(self, record: "Record") -> None:
ConnectionManager(self).query_modlist(record)
ConnectionManager(self).query_modlist_and_present(record)
def get_server_name(self) -> str:
tv = self.get_active_treeview()
@ -448,8 +452,14 @@ class Controller(GObject.GObject):
def get_modtreeview(self) -> "ModTreeView":
return self.mediator.modtreeview
def get_exit_event(self) -> None:
return self.exit_event
def set_exit_event(self) -> None:
self.exit_event.set()
def get_exit_event(self) -> threading.Event:
return self.exit_event
def open_connection_assistant(self, res: dict[Any], mods: list["DayzMod"]) -> None:
self.open_page(NotebookPage.CONNECTION)
# TODO: populate assistant
# TODO: embed dialogs
# dialog = ServerModDialog(self, mods)

View File

@ -55,11 +55,18 @@ class ConnectionManager:
self.thread_man.set_cleanup_func(
StoredFunc(self._server_timeout), destroy_first=True
)
rules = Servers.get_rules(record)
# TODO: proper error handling (currently returns empty list)
try:
mods = self.query_modlist(record)
except Exception:
self.thread_man.set_cleanup_func(
StoredFunc(self._server_timeout), destroy_first=True
)
self.controller.open_connection_assistant(res, mods)
# TODO: add to history if successful
print(res)
print(rules)
# print(res)
# print(rules)
@call_on_thread(dialog.querying)
def query_details(self, record: Servers.Record) -> None:
@ -73,18 +80,17 @@ class ConnectionManager:
StoredFunc(self._present_details_dialog, details), destroy_first=True
)
@call_on_thread(dialog.querying)
def query_modlist(self, record: Servers.Record) -> None:
mods = Servers.get_rules(record)
steam_path = self.controller.query_config(Preferences.DEFAULT)
local = get_local_mod_ids(steam_path)
if len(mods) == 0:
# TODO: separate message for no mods
# TODO: separate message for actual timeout
self.thread_man.set_cleanup_func(
StoredFunc(self._server_timeout), destroy_first=True
)
return
# if len(mods) == 0:
# # TODO: separate message for no mods
# # TODO: separate message for actual timeout
# self.thread_man.set_cleanup_func(
# StoredFunc(self._server_timeout), destroy_first=True
# )
# return
alpha_mods = [
[
mod.name,
@ -94,9 +100,19 @@ class ConnectionManager:
for mod in mods
]
alpha_mods.sort(key=lambda x: x[0])
return alpha_mods
@call_on_thread(dialog.querying)
def query_modlist_and_present(self, record: Servers.Record) -> None:
try:
mods = self.query_modlist(record)
except Exception:
self.thread_man.set_cleanup_func(
StoredFunc(self._server_timeout), destroy_first=True
)
return
self.thread_man.set_cleanup_func(
StoredFunc(self._present_modlist_dialog, alpha_mods),
StoredFunc(self._present_modlist_dialog, mods),
destroy_first=True,
)

View File

@ -16,6 +16,9 @@ from dzgui.const.enum import Preferences
from dzgui.managers.threading import call_on_thread, StoredFunc, ThreadingManager
from dzgui.model.model_factory import FastInsertListStore, ModelFactory
from dzgui.util.format import format_mods
from dzgui.util.strings import server_timeout
from dzgui.views.dialogs.generic import ExceptionDialog
import dzgui.api.pefile as PeFile
@ -34,11 +37,9 @@ class ModManager:
"""
Because mods may be dynamically updated on the system,
this manager is instantiated each time the Mods page is opened
and persists until the next time the page is opened
"""
def __init__(self, controller: "Controller") -> None:
self.controller = controller
self.emitter = controller.get_emitter()
self.prefs = controller.get_prefs()
@ -50,6 +51,7 @@ class ModManager:
self.thread_man = ThreadingManager(controller)
self._get_mods()
# TODO: strings
@call_on_thread("getting mods")
def _get_mods(self) -> None:
mods = get_delimited_mods(self.path)
@ -69,11 +71,12 @@ class ModManager:
total_mods = len(self.store)
self.emitter.emit("mods_updated", msg, total_mods)
# TODO: strings
@call_on_thread("deleting mods")
def delete_mods(self) -> None:
sel = self.treeview.get_selection()
model, pathlist = sel.get_selected_rows()
# NOTE reverse when multiple selection
# NOTE: reverse when multiple selection
iters = []
for path in reversed(pathlist):
_iter = self.delete_single_mod(path)
@ -174,13 +177,24 @@ class ModManager:
model[path][4] = True
self.emitter.emit("mods_highlighted")
# TODO: strings
@call_on_thread("working")
def highlight_stale(self) -> None:
# TODO: set progress bar for number of mods
# try:
stale = find_stale_mods(self.prefs.paths.config)
# except Exception:
# # TODO: clearer error message
# func = StoredFunc(self._server_timeout)
# self.thread_man.set_cleanup_func(func)
# return
func = StoredFunc(self._on_stale_mods_found, stale)
self.thread_man.set_cleanup_func(func)
def _server_timeout(self) -> None:
dialog = ExceptionDialog(self.controller, server_timeout)
dialog.run()
def select_colorized(self) -> None:
model = self.treeview.get_model()
if model is None:

View File

@ -53,7 +53,7 @@ class ThreadingManager:
def __init__(self, controller: "Controller") -> None:
self.controller = controller
self.jobs = 1
self.cleanup_func: StoredFunc | None
self.cleanup_func: StoredFunc | None = None
self.destroy_first = False
def call_on_thread(self, dialog_str: str, func: StoredFunc) -> None:
@ -75,7 +75,9 @@ class ThreadingManager:
def increment_dialog_with_str(self, text: str) -> None:
GLib.idle_add(lambda: self.wait_dialog.increment(text))
def set_cleanup_func(self, func: StoredFunc | None, destroy_first: bool = False) -> None:
def set_cleanup_func(
self, func: StoredFunc | None, destroy_first: bool = False
) -> None:
if type(func) not in (StoredFunc, type(None)):
msg = f"Callback function '{func}' is not of type StoredFunc or None"
logger.critical(msg)

View File

@ -23,6 +23,7 @@ from dzgui.views.pages.keys import Keybindings
from dzgui.views.pages.log import Log
from dzgui.views.pages.mods import Mods
from dzgui.views.pages.options import Options
from dzgui.views.pages.preconnect import PreConnectionAssistant
from dzgui.views.pages.servers import ServerNotebook
from dzgui.views.pages.thanks import Thanks
@ -62,6 +63,8 @@ warnings.filterwarnings("ignore", ".*g_value_get_int", Warning)
# return f"{record.ip}:{record.gameport}:{record.qport}"
#
#
class OuterWindow(Gtk.Window):
def __init__(self) -> None:
super().__init__(title=APP_NAME, border_width=10, icon_name=APP_NAME_LOWER)
@ -125,6 +128,8 @@ class Notebook(ScrollableMixin, Gtk.Notebook): # type: ignore
self.log = Log(MainController)
self.developers = Developers(MainController)
self.connection = PreConnectionAssistant(MainController)
self.pages = {
self.help: NotebookPage.HELP,
self.clog: NotebookPage.CHANGELOG,
@ -135,6 +140,7 @@ class Notebook(ScrollableMixin, Gtk.Notebook): # type: ignore
self.log: NotebookPage.LOG,
self.thanks: NotebookPage.THANKS,
self.developers: NotebookPage.DEVELOPERS,
self.connection: NotebookPage.CONNECTION,
}
self.indexes = {}