mirror of
https://github.com/aclist/dztui.git
synced 2026-11-01 15:42:51 +01:00
feat: refresh player count
This commit is contained in:
1 parent
06450ddadc
commit
e1f54bd75d
6 files changed
+105
-32
No files matched your search
+14
-1
@@ -453,11 +453,24 @@ def query_by_id(addr: str, key: str) -> Optional[dict]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def query_playercount(record: Record) -> Optional[tuple[int]]:
|
||||||
|
try:
|
||||||
|
res = query_direct(record.ip, record.qport)
|
||||||
|
players = int(res["players"])
|
||||||
|
r = res["gametype"].split("lqs")
|
||||||
|
try:
|
||||||
|
queue = int(r[1].split(",")[0])
|
||||||
|
except IndexError:
|
||||||
|
queue = 0
|
||||||
|
return (players, queue)
|
||||||
|
except Exception as e:
|
||||||
|
logger.critical(e)
|
||||||
|
return None
|
||||||
|
|
||||||
def query_by_ip(addr: str) -> Optional[dict]:
|
def query_by_ip(addr: str) -> Optional[dict]:
|
||||||
record = short_ip_to_record(addr)
|
record = short_ip_to_record(addr)
|
||||||
return query_by_record(record)
|
return query_by_record(record)
|
||||||
|
|
||||||
|
|
||||||
def query_by_record(record: Record) -> Optional[dict]:
|
def query_by_record(record: Record) -> Optional[dict]:
|
||||||
try:
|
try:
|
||||||
return query_direct(record.ip, record.qport)
|
return query_direct(record.ip, record.qport)
|
||||||
|
|||||||
@@ -604,6 +604,10 @@ class Controller(GObject.GObject):
|
|||||||
saved_tree = self.get_servers().get_saved()
|
saved_tree = self.get_servers().get_saved()
|
||||||
ServerModelManager(self, saved_tree).add_by_record(record)
|
ServerModelManager(self, saved_tree).add_by_record(record)
|
||||||
|
|
||||||
|
def remove_by_record(self, record: "Record") -> None:
|
||||||
|
saved_tree = self.get_servers().get_saved()
|
||||||
|
ServerModelManager(self, saved_tree).remove_by_record(record)
|
||||||
|
|
||||||
def connect_by_str(self, addr: str) -> None:
|
def connect_by_str(self, addr: str) -> None:
|
||||||
if addr.isdigit():
|
if addr.isdigit():
|
||||||
config_man = self.get_config_man()
|
config_man = self.get_config_man()
|
||||||
@@ -652,3 +656,8 @@ class Controller(GObject.GObject):
|
|||||||
tv = self.get_active_treeview()
|
tv = self.get_active_treeview()
|
||||||
record = tv.get_record_string()
|
record = tv.get_record_string()
|
||||||
self.notes_man.delete_note(record)
|
self.notes_man.delete_note(record)
|
||||||
|
|
||||||
|
def refresh_players(self, record: "Record") -> None:
|
||||||
|
treeview = self.get_active_treeview()
|
||||||
|
model, treeiter = treeview.get_selection().get_selected()
|
||||||
|
ServerModelManager(self, treeview).update_playercount(treeiter, record)
|
||||||
@@ -48,6 +48,11 @@ class ConfigManager:
|
|||||||
ips.append(record)
|
ips.append(record)
|
||||||
self.update_config(Preferences.IP_LIST, ips)
|
self.update_config(Preferences.IP_LIST, ips)
|
||||||
|
|
||||||
|
def remove_saved_server(self, record: str) -> None:
|
||||||
|
ips = self.lookup(Preferences.IP_LIST)
|
||||||
|
ips.remove(record)
|
||||||
|
self.update_config(Preferences.IP_LIST, ips)
|
||||||
|
|
||||||
# TODO: drop/reroute
|
# TODO: drop/reroute
|
||||||
def update_config(self, key: Preferences, value: str) -> None:
|
def update_config(self, key: Preferences, value: str) -> None:
|
||||||
self.write_config(key, value)
|
self.write_config(key, value)
|
||||||
|
|||||||
@@ -66,7 +66,10 @@ class ContextMenuManager:
|
|||||||
|
|
||||||
case ContextMenu.REFRESH_PLAYERS:
|
case ContextMenu.REFRESH_PLAYERS:
|
||||||
print("DEBUG: unimplemented")
|
print("DEBUG: unimplemented")
|
||||||
# get record
|
record = self.treeview.get_record()
|
||||||
|
self.controller.refresh_players(record)
|
||||||
|
|
||||||
|
# TODO: just updates proxy model, this info is ephemeral
|
||||||
# call a2s on thread
|
# call a2s on thread
|
||||||
pass
|
pass
|
||||||
case ContextMenu.REMOVE_HISTORY:
|
case ContextMenu.REMOVE_HISTORY:
|
||||||
@@ -75,9 +78,8 @@ class ContextMenuManager:
|
|||||||
# see dq.py
|
# see dq.py
|
||||||
pass
|
pass
|
||||||
case ContextMenu.REMOVE_SERVER:
|
case ContextMenu.REMOVE_SERVER:
|
||||||
print("DEBUG: unimplemented")
|
record = self.treeview.get_record()
|
||||||
# reverse of ADD_SERVER
|
self.controller.remove_by_record(record)
|
||||||
pass
|
|
||||||
case ContextMenu.SHOW_DETAILS:
|
case ContextMenu.SHOW_DETAILS:
|
||||||
record = self.treeview.get_record()
|
record = self.treeview.get_record()
|
||||||
self.controller.get_details(record)
|
self.controller.get_details(record)
|
||||||
|
|||||||
@@ -10,7 +10,12 @@ from dzgui.util import strings
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dzgui.managers.filter_man import FilterManager
|
from dzgui.managers.filter_man import FilterManager
|
||||||
from dzgui.model.model_factory import FastInsertListStore
|
from dzgui.model.model_factory import FastInsertListStore
|
||||||
|
from dzgui.model.servers import NewPlayerCount
|
||||||
|
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version("Gtk", "3.0")
|
||||||
|
from gi.repository.Gtk import TreeIter
|
||||||
|
|
||||||
class ProxyModelManager:
|
class ProxyModelManager:
|
||||||
"""
|
"""
|
||||||
@@ -35,9 +40,27 @@ class ProxyModelManager:
|
|||||||
self.filtered: list = None
|
self.filtered: list = None
|
||||||
self.success = True
|
self.success = True
|
||||||
|
|
||||||
|
def has_control_model(self) -> bool:
|
||||||
|
pass
|
||||||
|
|
||||||
def append_row(self, row: list) -> None:
|
def append_row(self, row: list) -> None:
|
||||||
self.proxy_model.append(row)
|
self.proxy_model.append(row)
|
||||||
|
|
||||||
|
def append_row_to_control(self, row: list) -> None:
|
||||||
|
self.control_model.append(row)
|
||||||
|
self.filter(FilterMode.INITIAL, skip_cache=True)
|
||||||
|
|
||||||
|
def remove_row_from_control(self, row: list) -> None:
|
||||||
|
for record in self.control_model:
|
||||||
|
if row[7] == record[7] and row[8] == record[8]:
|
||||||
|
self.control_model.remove(record)
|
||||||
|
self.filter(FilterMode.INITIAL, skip_cache=True)
|
||||||
|
|
||||||
|
def update_playercount(self, playercount: "NewPlayerCount") -> None:
|
||||||
|
treeiter = playercount.treeiter
|
||||||
|
self.proxy_model[treeiter][4] = playercount.players
|
||||||
|
self.proxy_model[treeiter][6] = playercount.queue
|
||||||
|
|
||||||
def clear_proxy_model(self) -> None:
|
def clear_proxy_model(self) -> None:
|
||||||
self.proxy_model.clear()
|
self.proxy_model.clear()
|
||||||
|
|
||||||
|
|||||||
+48
-27
@@ -1,7 +1,9 @@
|
|||||||
import logging
|
import logging
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
from concurrent.futures import as_completed
|
from concurrent.futures import as_completed
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
from dataclasses import dataclass
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import dzgui.api.servers as Servers
|
import dzgui.api.servers as Servers
|
||||||
@@ -29,9 +31,15 @@ if TYPE_CHECKING:
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# TODO: failure: spawns error dialog
|
# TODO: failure should spawn error dialog
|
||||||
# TODO: non failure with empty model: updates statusbar with help text
|
# TODO: non failure with empty model: updates statusbar with help text
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class NewPlayerCount:
|
||||||
|
treeiter: Gtk.TreeIter
|
||||||
|
players: int
|
||||||
|
queue: int
|
||||||
|
|
||||||
|
|
||||||
class ServerModelManager:
|
class ServerModelManager:
|
||||||
def __init__(self, controller: "Controller", tv: Gtk.TreeView) -> None:
|
def __init__(self, controller: "Controller", tv: Gtk.TreeView) -> None:
|
||||||
@@ -207,50 +215,65 @@ class ServerModelManager:
|
|||||||
# FIXME: use "adding server" string
|
# FIXME: use "adding server" string
|
||||||
@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:
|
||||||
|
"""
|
||||||
|
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)
|
||||||
|
|
||||||
|
@call_on_thread(dialog.querying)
|
||||||
|
def remove_by_record(self, record: Servers.Record) -> None:
|
||||||
|
res = Servers.query_by_record(record)
|
||||||
|
self._parse_single_record(res, delete=True)
|
||||||
|
|
||||||
def add_by_str(self, addr: str) -> None:
|
def add_by_str(self, addr: str) -> None:
|
||||||
if addr.isdigit():
|
if addr.isdigit():
|
||||||
self.add_by_id(addr)
|
self.add_by_id(addr)
|
||||||
else:
|
else:
|
||||||
self.add_by_ip(addr)
|
self.add_by_ip(addr)
|
||||||
|
|
||||||
def _parse_single_record(self, response: dict) -> None:
|
@call_on_thread(dialog.querying)
|
||||||
|
def update_playercount(self, treeiter: Gtk.TreeIter, record: Servers.Record) -> None:
|
||||||
|
proxy_man = self._get_proxy_man()
|
||||||
|
res = Servers.query_playercount(record)
|
||||||
|
if res is None:
|
||||||
|
return
|
||||||
|
players, queue = res
|
||||||
|
|
||||||
|
self.playercount = NewPlayerCount(treeiter, players, queue)
|
||||||
|
self.thread_man.set_cleanup_func(StoredFunc(self._push_playercount))
|
||||||
|
|
||||||
|
def _push_playercount(self) -> None:
|
||||||
|
proxy_man = self._get_proxy_man()
|
||||||
|
proxy_man.update_playercount(self.playercount)
|
||||||
|
|
||||||
|
def _parse_single_record(self, response: dict, delete: bool = False) -> None:
|
||||||
if response is None:
|
if response is None:
|
||||||
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure))
|
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_on_failure))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# NOTE: expected to only contain one item
|
||||||
records = Servers.parse_json([response])
|
records = Servers.parse_json([response])
|
||||||
record = records[0]
|
record = records[0]
|
||||||
|
|
||||||
proxy_man = self._get_proxy_man()
|
proxy_man = self._get_proxy_man()
|
||||||
raw_model = proxy_man.get_control()
|
|
||||||
|
|
||||||
fqip = Servers.response_to_fq_ip(response)
|
fqip = Servers.response_to_fq_ip(response)
|
||||||
config_man = self.controller.get_config_man()
|
config_man = self.controller.get_config_man()
|
||||||
config_man.add_saved_server(fqip)
|
|
||||||
|
|
||||||
# NOTE: abort early if Saved Servers tab was not loaded yet
|
if delete:
|
||||||
if raw_model is None:
|
# NOTE: abort early if Saved Servers tab was not loaded yet
|
||||||
return
|
config_man.remove_saved_server(fqip)
|
||||||
|
if proxy_man.has_control_model() is False:
|
||||||
|
return
|
||||||
|
proxy_man.remove_row_from_control(record)
|
||||||
|
else:
|
||||||
|
config_man.add_saved_server(fqip)
|
||||||
|
if proxy_man.has_control_model() is False:
|
||||||
|
return
|
||||||
|
proxy_man.append_row_to_control(record)
|
||||||
|
|
||||||
# NOTE: expected to only contain one item
|
control_model = proxy_man.get_control()
|
||||||
raw_model.append(record)
|
self._sort_unique_maps(control_model)
|
||||||
|
|
||||||
# TODO: if all filters are already applied, strange behavior may occur
|
|
||||||
# -> need to insert and reupdate tree per current filters
|
|
||||||
# for example, non-empty will only show up in empty because it is not cached
|
|
||||||
|
|
||||||
# FIXME: new results are not being shown when tabbing over to Saved Servers
|
|
||||||
proxy_man.filter(FilterMode.INITIAL, skip_cache=True)
|
|
||||||
|
|
||||||
filter_man = self.tv.get_filter_man()
|
|
||||||
old_maps = filter_man.get_unique_maps()
|
|
||||||
cur_map = record[1]
|
|
||||||
if cur_map not in old_maps:
|
|
||||||
old_maps.append(cur_map)
|
|
||||||
self._set_new_maps(old_maps)
|
|
||||||
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_single_ip))
|
self.thread_man.set_cleanup_func(StoredFunc(self._cleanup_single_ip))
|
||||||
|
|
||||||
def _dump_history(self) -> None:
|
def _dump_history(self) -> None:
|
||||||
@@ -295,8 +318,8 @@ class ServerModelManager:
|
|||||||
# TODO: animate saved servers tab if we are on other tab
|
# TODO: animate saved servers tab if we are on other tab
|
||||||
self.emitter.emit("servers_loaded", self.enum)
|
self.emitter.emit("servers_loaded", self.enum)
|
||||||
|
|
||||||
# TODO: consolidate methods and handle multi/single map addition
|
|
||||||
filter_man = self.tv.get_filter_man()
|
filter_man = self.tv.get_filter_man()
|
||||||
|
# NOTE: maps are set outside of thread because it triggers map changed signals
|
||||||
maps = self._get_new_maps()
|
maps = self._get_new_maps()
|
||||||
filter_man.set_unique_maps(maps)
|
filter_man.set_unique_maps(maps)
|
||||||
|
|
||||||
@@ -314,8 +337,6 @@ class ServerModelManager:
|
|||||||
self.tv.set_model(proxy)
|
self.tv.set_model(proxy)
|
||||||
|
|
||||||
# TODO: make sure control model len is N + 1
|
# TODO: make sure control model len is N + 1
|
||||||
# inserting a row serializes file on disk, updates control model for that tab, and updates model
|
|
||||||
# NOTE: when inserting new rows, the entire control model is wiped and rebuilt, then proxy model is swapped in
|
|
||||||
# TODO: signals or other approach to deferring map
|
# TODO: signals or other approach to deferring map
|
||||||
# model insertion after thread closes
|
# model insertion after thread closes
|
||||||
# cf. servers_loaded signal
|
# cf. servers_loaded signal
|
||||||
|
|||||||
Reference in new issue
Block a user