chore: clean up server threading

This commit is contained in:
aclist committed 2026-05-16 01:55:41 +09:00
1 parent ef459c2fd1
commit fa759f4714
2 files changed
+28 -34

No files matched your search

+5 -2
View File
@@ -51,13 +51,14 @@ class ModManager:
self.thread_man = ThreadingManager(controller) self.thread_man = ThreadingManager(controller)
self._get_mods() self._get_mods()
# TODO: strings # TODO: dialog strings
@call_on_thread("getting mods") @call_on_thread("getting mods")
def _get_mods(self) -> None: def _get_mods(self) -> None:
mods = get_delimited_mods(self.path) mods = get_delimited_mods(self.path)
if len(mods) < 1: if len(mods) < 1:
msg = self.format_mod_statusbar() msg = self.format_mod_statusbar()
self.emitter.emit("mods_updated", msg, 0) func = StoredFunc(lambda: self.emitter.emit("mods_updated", msg, 0))
self.thread_man.set_cleanup_func(func)
return return
func = StoredFunc(self._on_mods_loaded, mods) func = StoredFunc(self._on_mods_loaded, mods)
@@ -74,6 +75,8 @@ class ModManager:
# TODO: strings # TODO: strings
@call_on_thread("deleting mods") @call_on_thread("deleting mods")
def delete_mods(self) -> None: def delete_mods(self) -> None:
# FIXME: do not read from GTK in worker thread
# break into function that iterates through paths and one that is threaded
sel = self.treeview.get_selection() sel = self.treeview.get_selection()
model, pathlist = sel.get_selected_rows() model, pathlist = sel.get_selected_rows()
# NOTE: reverse when multiple selection # NOTE: reverse when multiple selection
+23 -32
View File
@@ -83,7 +83,8 @@ class ServerModelManager:
@call_on_thread(dialog.fetching) @call_on_thread(dialog.fetching)
def _dump_api(self) -> None: def _dump_api(self) -> None:
# TODO: pass api key a priori in .load() call # TODO: pass api key a priori in .load() call?
failure_func = StoredFunc(self._cleanup_on_failure)
config_man = self.controller.get_config_man() config_man = self.controller.get_config_man()
key = config_man.lookup(Preferences.STEAM) key = config_man.lookup(Preferences.STEAM)
job = Servers.query_api job = Servers.query_api
@@ -101,7 +102,7 @@ class ServerModelManager:
res = future.result(timeout=API_TIMEOUT) res = future.result(timeout=API_TIMEOUT)
if res.status != 200 or not res.parsed: if res.status != 200 or not res.parsed:
self.thread_man.set_cleanup_func( self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure) failure_func, destroy_first=True
) )
return return
j = res.json j = res.json
@@ -109,9 +110,7 @@ class ServerModelManager:
servers.extend(j["response"]["servers"]) servers.extend(j["response"]["servers"])
except Exception as e: except Exception as e:
logger.critical(e) logger.critical(e)
self.thread_man.set_cleanup_func( self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
StoredFunc(self._cleanup_on_failure)
)
return return
# NOTE: this step is allowed to fail, since this metadata is incidental # NOTE: this step is allowed to fail, since this metadata is incidental
@@ -128,6 +127,7 @@ class ServerModelManager:
def dump_lan(self, port: int, early_abort: bool) -> None: def dump_lan(self, port: int, early_abort: bool) -> None:
servers = [] servers = []
ports = range(1, 256) ports = range(1, 256)
failure_func = StoredFunc(self._cleanup_on_failure)
event = threading.Event() event = threading.Event()
with ThreadPoolExecutor() as executor: with ThreadPoolExecutor() as executor:
@@ -135,7 +135,9 @@ class ServerModelManager:
for future in as_completed(futures): for future in as_completed(futures):
try: try:
res = future.result(timeout=LAN_TIMEOUT) res = future.result(timeout=LAN_TIMEOUT)
if res is not None and early_abort is True: if res is None:
continue
if early_abort is True:
# NOTE: on first non-empty hit, flag pending threads to close # NOTE: on first non-empty hit, flag pending threads to close
event.set() event.set()
servers.append(res) servers.append(res)
@@ -143,16 +145,12 @@ class ServerModelManager:
StoredFunc(self._cleanup_on_success) StoredFunc(self._cleanup_on_success)
) )
return return
if res is None:
continue
servers.append(res) servers.append(res)
except Exception as e: except Exception as e:
logger.critical(e) logger.critical(e)
self.thread_man.set_cleanup_func( self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
StoredFunc(self._cleanup_on_failure)
)
if len(servers) == 0: if len(servers) == 0:
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure)) self.thread_man.set_cleanup_func(failure_func, destroy_first=True)
return return
parsed = Servers.parse_json(servers) parsed = Servers.parse_json(servers)
self._push_data(parsed) self._push_data(parsed)
@@ -181,7 +179,7 @@ class ServerModelManager:
servers.append(res) servers.append(res)
if len(servers) == 0: if len(servers) == 0:
self.thread_man.set_cleanup_func( self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure) StoredFunc(self._cleanup_on_failure), destroy_first=True
) )
return return
@@ -202,9 +200,7 @@ class ServerModelManager:
@call_on_thread(dialog.querying) @call_on_thread(dialog.querying)
def add_by_record(self, record: Servers.Record) -> None: def add_by_record(self, record: Servers.Record) -> None:
""" # NOTE: rationale: a raw Record as shown in server browser may resolve to a different IP
Rationale: a Record as shown in server browser may resolve to a different IP
"""
res = Servers.query_by_record(record) res = Servers.query_by_record(record)
self._parse_single_record(res) self._parse_single_record(res)
@@ -271,7 +267,9 @@ class ServerModelManager:
row = response.as_row() row = response.as_row()
except Exception as e: except Exception as e:
logger.warning(e) logger.warning(e)
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure)) self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure), destroy_first=True
)
return return
# NOTE: expected to only contain one item # NOTE: expected to only contain one item
@@ -302,9 +300,9 @@ class ServerModelManager:
return return
config_man.add_saved_server(fqip) config_man.add_saved_server(fqip)
# FIXME: this is valid if saved servers tab is already open, # FIXME: this is valid if saved servers tab is already open,
# but not if app was just booted # but not if app was just booted; causes single row to appear prematurely
if proxy_man.has_control_model() is False: if proxy_man.has_control_model() is False:
self._get_proxy_man().push(records) proxy_man.push(records)
else: else:
proxy_man.append_row_to_control(server) proxy_man.append_row_to_control(server)
@@ -322,14 +320,13 @@ class ServerModelManager:
rows = [row.rstrip("\n") for row in f] rows = [row.rstrip("\n") for row in f]
except OSError: except OSError:
self.thread_man.set_cleanup_func( self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure, False) StoredFunc(self._cleanup_on_failure, False), destroy_first=True
) )
return return
if len(rows) == 0: if len(rows) == 0:
# TODO: customize statusbar to mention how records are added after connecting # TODO: customize statusbar to mention how records are added after connecting
# cf. cleanup on empty
self.thread_man.set_cleanup_func( self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure, False) StoredFunc(self._cleanup_on_failure, False), destroy_first=True
) )
return return
self.thread_man.set_job_count(len(rows)) self.thread_man.set_job_count(len(rows))
@@ -343,7 +340,7 @@ class ServerModelManager:
if len(ips) == 0: if len(ips) == 0:
# TODO: customize statusbar to mention how records can be added via contextmenu # TODO: customize statusbar to mention how records can be added via contextmenu
self.thread_man.set_cleanup_func( self.thread_man.set_cleanup_func(
StoredFunc(self._cleanup_on_failure, False) StoredFunc(self._cleanup_on_failure, False), destroy_first=True
) )
return return
self._dump_ips(ips) self._dump_ips(ips)
@@ -381,21 +378,15 @@ class ServerModelManager:
def _cleanup_on_failure(self, show_dialog: bool = True) -> None: def _cleanup_on_failure(self, show_dialog: bool = True) -> None:
# TODO: disable map, keyword, and filter widgets if model is None # TODO: disable map, keyword, and filter widgets if model is None
# -> signal driven (servers_empty, servers_failed_to_load) # signal driven (servers_empty, servers_failed_to_load)
if self.preserve_on_fail is False: if self.preserve_on_fail is False:
# CHORE: test if maps are cleared on failure
self.tv.set_model(None) self.tv.set_model(None)
# filter_man = self.tv.get_filter_man() filter_man = self.tv.get_filter_man()
# filter_man.set_unique_maps([]) filter_man.set_unique_maps([])
# TODO: emit signal to not disable widget sensitivity
# TODO: distinguish signals, e.g. "servers_failed_to_load", "servers_loaded_empty" # TODO: distinguish signals, e.g. "servers_failed_to_load", "servers_loaded_empty"
# customize statusbar and dialog accordingly # customize statusbar and dialog accordingly
# TODO: drop, causes errors
# self.emitter.emit("servers_loaded", self.enum)
# FIXME: destroy wait dialog first
# see threadman.set_cleanup_func(_, destroy_first=True)
if show_dialog: if show_dialog:
dialog = ExceptionDialog(self.controller, api_warn_msg) dialog = ExceptionDialog(self.controller, api_warn_msg)
dialog.run() dialog.run()