feat: lazy load WIP

This commit is contained in:
aclist committed 2026-01-24 15:56:04 +09:00
1 parent 6141145fbe
commit ab9c97234e
6 files changed
+94 -22

No files matched your search

+4 -4
View File
@@ -124,7 +124,7 @@ def parse_json(json: list) -> list:
view = strings.filter_3pp view = strings.filter_3pp
if "external" in r: if "external" in r:
provider = strings.filter_unoffiical provider = strings.filter_unofficial
else: else:
provider = strings.filter_official provider = strings.filter_official
@@ -396,16 +396,16 @@ def query_api(key: str, appid: int, param: str) -> Res:
"limit": LIMIT, "limit": LIMIT,
"key": key, "key": key,
} }
try: try:
res = requests.get(STEAM_SERVERS, params=payload, timeout=REQUEST_TIMEOUT) res = requests.get(STEAM_SERVERS, params=payload, timeout=5)
res.raise_for_status() res.raise_for_status()
parsed = True parsed = True
status = 200
data = res.json() data = res.json()
except Exception: except Exception:
status = res.status_code
parsed = False parsed = False
data = None data = None
status = 403
finally: finally:
return Res(status, parsed, data) return Res(status, parsed, data)
+1 -1
View File
@@ -4,7 +4,7 @@ UDP_PORT = 27016
VM_FILE = "/proc/sys/vm/max_map_count" VM_FILE = "/proc/sys/vm/max_map_count"
MIN_COUNT = 1048576 MIN_COUNT = 1048576
REQUEST_TIMEOUT = 1 REQUEST_TIMEOUT = 5
APPNAME_DAYZ = "DayZ" APPNAME_DAYZ = "DayZ"
APPNAME_DAYZ_EXP = "DayZ Experimental" APPNAME_DAYZ_EXP = "DayZ Experimental"
+53 -14
View File
@@ -4,10 +4,13 @@ import threading
import traceback import traceback
from warnings import deprecated from warnings import deprecated
from concurrent.futures import wait
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Literal, TYPE_CHECKING from typing import Any, Callable, Literal, TYPE_CHECKING
import dzgui.api.pefile as PeFile import dzgui.api.pefile as PeFile
import dzgui.api.servers as Servers
import dzgui.util._json as JSON # noqa import dzgui.util._json as JSON # noqa
from dzgui.views.dialogs.generic import ExceptionDialog from dzgui.views.dialogs.generic import ExceptionDialog
@@ -353,6 +356,42 @@ class Controller(GObject.GObject):
self.mediator.notebook.set_page_by_enum(button.opens) self.mediator.notebook.set_page_by_enum(button.opens)
def _dump_api(self):
key = self.query_config(Preferences.STEAM)
job = Servers.query_api
params = Servers.params
serv = []
with ThreadPoolExecutor() as executor:
futures = [
executor.submit(job, key, APPID_DAYZ, param)
for param in params
]
wait(futures)
for future in futures:
res = future.result()
if res.status != 200 or not res.parsed:
# ModelManager.set_store(None)
# ModelManager.set_success(False)
# GLib.idle_add(self._filter_cleanup)
print("status error")
return
j = res.json
serv += j["response"]["servers"]
res = Servers.query_api(key, APPID_DAYZ_EXP, "")
if res.status == 200 and res.parsed is True:
j = res.json
serv += j["response"]["servers"]
parsed = Servers.parse_json(serv)
self.data = parsed
self.get_func_data()
self.destroy_on_idle()
# try:
# except Exception as e:
# print(e)
# return parsed
def get_help_row(self) -> str: def get_help_row(self) -> str:
tv = self.mediator.menu tv = self.mediator.menu
model = self.get_help_store() model = self.get_help_store()
@@ -538,20 +577,6 @@ class Controller(GObject.GObject):
self.data = ( self.data = (
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "172.111.51.156:2302", 0, 0, "a", False], ["BAR", "a", "a", "a", 1, 1, 1, "172.111.51.156:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
) )
# TODO: refer to prior implementation--should need to load data into model while in thread # TODO: refer to prior implementation--should need to load data into model while in thread
self.get_func_data() self.get_func_data()
@@ -562,6 +587,16 @@ class Controller(GObject.GObject):
time.sleep(1) time.sleep(1)
self.data = ( self.data = (
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], ["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "172.111.51.156:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
["BAR", "a", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False],
) )
# TODO: refer to prior implementation--should need to load data into model while in thread # TODO: refer to prior implementation--should need to load data into model while in thread
self.get_func_data() self.get_func_data()
@@ -572,8 +607,11 @@ class Controller(GObject.GObject):
# NOTE: do not insert model until main thread is idle # NOTE: do not insert model until main thread is idle
# TODO: grab from model manager and insert entire model # TODO: grab from model manager and insert entire model
# TODO: do not start refresh button count until load finished # TODO: do not start refresh button count until load finished
# TODO: append rows into filtered model
# when complete, destroy dialog and set model
for row in data: for row in data:
manager.append_row(row) manager.append_row(row)
treeview.set_model(manager.get_model())
treeview.set_loaded(True) treeview.set_loaded(True)
self.mediator.statusbar.emit("server_page_changed", context) self.mediator.statusbar.emit("server_page_changed", context)
treeview.grab_focus() treeview.grab_focus()
@@ -699,6 +737,7 @@ class Controller(GObject.GObject):
return return
manager = treeview.get_filter_man() manager = treeview.get_filter_man()
# TODO: this may lag? # TODO: this may lag?
treeview.set_model(None)
manager.clear_model() manager.clear_model()
self.set_callback(None, None) self.set_callback(None, None)
self.call_on_thread(func) self.call_on_thread(func)
+7 -1
View File
@@ -46,17 +46,23 @@ class FilteredModelManager:
self.ping_cache: dict[str, int] = {} self.ping_cache: dict[str, int] = {}
self.model = self.new_model_from_class(ServerColumns) self.model = self.new_model_from_class(ServerColumns)
self.real_model = self.new_model_from_class(ServerColumns)
self.control_model = None self.control_model = None
self.filtered = None self.filtered = None
self.success = True self.success = True
def append_row(self, row: list) -> None: def append_row(self, row: list) -> None:
self.model.append(row) self.real_model.append(row)
# NOTE: append null rows to thin client
self.model.append()
def clear_model(self) -> None: def clear_model(self) -> None:
self.model.clear() self.model.clear()
def get_real_model(self) -> ListStore:
return self.real_model
def get_model(self) -> ListStore: def get_model(self) -> ListStore:
return self.model return self.model
+2 -1
View File
@@ -34,8 +34,9 @@ class ServerNotebook(Gtk.ScrolledWindow):
) )
self.lan = ServerTreeView(controller, ServerTab.LAN, ContextMenuGroup.SCAN_LAN) self.lan = ServerTreeView(controller, ServerTab.LAN, ContextMenuGroup.SCAN_LAN)
self.browser.set_query_func(self.controller.dump_test_1) # self.browser.set_query_func(self.controller.dump_test_2)
self.lan.set_query_func(self.controller.dump_test_2) self.lan.set_query_func(self.controller.dump_test_2)
self.browser.set_query_func(self.controller._dump_api)
tabs = [ tabs = [
(self.browser, server_labels.browser), (self.browser, server_labels.browser),
+27 -1
View File
@@ -1,6 +1,6 @@
import logging import logging
import multiprocessing import multiprocessing
from typing import Self from typing import Any, Self
from dzgui.const.enum import ContextMenu, ContextMenuGroup, FilterMode, ServerTab from dzgui.const.enum import ContextMenu, ContextMenuGroup, FilterMode, ServerTab
from dzgui.api.servers import Record from dzgui.api.servers import Record
@@ -76,6 +76,7 @@ class ServerTreeView(TreeView):
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn(column_title, renderer, text=i) column = Gtk.TreeViewColumn(column_title, renderer, text=i)
column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) column.set_sizing(Gtk.TreeViewColumnSizing.FIXED)
column.set_cell_data_func(renderer, self._lazy_load, func_data=i)
column.set_resizable(True) column.set_resizable(True)
column.set_sort_column_id(i) column.set_sort_column_id(i)
@@ -335,6 +336,8 @@ class ServerTreeView(TreeView):
print(self.get_value_at_index(0)) print(self.get_value_at_index(0))
def _parent_selection_changed(self, base_class: TreeView, sel: Gtk.TreeSelection): def _parent_selection_changed(self, base_class: TreeView, sel: Gtk.TreeSelection):
# TODO: lazy load
# https://stackoverflow.com/questions/3164262/lazy-loaded-list-view-in-gtk
self.terminate_process() self.terminate_process()
self.emit("distcalc_started") self.emit("distcalc_started")
@@ -348,6 +351,7 @@ class ServerTreeView(TreeView):
select = self.get_selection() select = self.get_selection()
sels = select.get_selected_rows() sels = select.get_selected_rows()
(model, pathlist) = sels (model, pathlist) = sels
# TODO: clean up per lazy load logic
if len(pathlist) < 1: if len(pathlist) < 1:
return None return None
path = pathlist[0] path = pathlist[0]
@@ -355,6 +359,8 @@ class ServerTreeView(TreeView):
if not model: if not model:
return None return None
addr = model[path][7] addr = model[path][7]
if addr is None:
return
qport = model[path][8] qport = model[path][8]
ip = addr.split(":")[0] ip = addr.split(":")[0]
gameport = int(addr.split(":")[1]) gameport = int(addr.split(":")[1])
@@ -365,3 +371,23 @@ class ServerTreeView(TreeView):
def set_loaded(self, status: bool) -> None: def set_loaded(self, status: bool) -> None:
self.loaded = status self.loaded = status
def _lazy_load(
self,
column: Gtk.TreeViewColumn,
cell: Gtk.CellRendererText,
model: Gtk.TreeModel,
it: Gtk.TreeIter,
col_index: int,
) -> Any:
# TODO: initially load empty rows
# TODO: if cell is in visible range
path = model.get_path(it)
row_index = path.get_indices()[0]
start, end = self.get_visible_range()
if row_index >= start[0] <= end[0]:
real_model = self.filter_man.get_real_model()
value = real_model[row_index][col_index]
cell.set_property("text", str(value))
else:
return