Reworked UI for easier workflow.
This commit is contained in:
122
ptlinux/ui/viewmodels/health.py
Normal file
122
ptlinux/ui/viewmodels/health.py
Normal file
@@ -0,0 +1,122 @@
|
||||
"""Official server-health presentation and request state."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
import time
|
||||
from typing import Callable
|
||||
|
||||
from ...server_status import RealmServerStatus, ServerStatusError, fetch_server_status
|
||||
|
||||
|
||||
SERVER_STATUS_STALE_SECONDS = 5 * 60
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ServerStatusPresentation:
|
||||
"""Text and Tk style for one official realm-health result."""
|
||||
|
||||
text: str
|
||||
style: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ServerStatusCheck:
|
||||
"""One measured attempt to retrieve official realm health."""
|
||||
|
||||
statuses: tuple[RealmServerStatus, ...] | None
|
||||
checked_at: float
|
||||
duration_seconds: float
|
||||
error: str | None = None
|
||||
|
||||
|
||||
def perform_server_status_check(
|
||||
*,
|
||||
fetcher: Callable[[], tuple[RealmServerStatus, ...]] = fetch_server_status,
|
||||
monotonic: Callable[[], float] = time.monotonic,
|
||||
wall_clock: Callable[[], float] = time.time,
|
||||
) -> ServerStatusCheck:
|
||||
"""Measure one official status request without leaking its endpoint."""
|
||||
|
||||
started_at = monotonic()
|
||||
try:
|
||||
statuses = fetcher()
|
||||
except ServerStatusError as error:
|
||||
duration_seconds = max(0.0, monotonic() - started_at)
|
||||
return ServerStatusCheck(
|
||||
statuses=None,
|
||||
checked_at=wall_clock(),
|
||||
duration_seconds=duration_seconds,
|
||||
error=str(error),
|
||||
)
|
||||
duration_seconds = max(0.0, monotonic() - started_at)
|
||||
return ServerStatusCheck(
|
||||
statuses=statuses,
|
||||
checked_at=wall_clock(),
|
||||
duration_seconds=duration_seconds,
|
||||
)
|
||||
|
||||
|
||||
def server_status_check_text(
|
||||
check: ServerStatusCheck,
|
||||
*,
|
||||
timestamp: float | None = None,
|
||||
) -> str:
|
||||
"""Render fetch age, latency, and freshness for the hidden debug view."""
|
||||
|
||||
now = time.time() if timestamp is None else timestamp
|
||||
age_seconds = max(0.0, now - check.checked_at)
|
||||
whole_seconds = int(age_seconds)
|
||||
if whole_seconds < 60:
|
||||
age = f"{whole_seconds}s"
|
||||
elif whole_seconds < 60 * 60:
|
||||
age = f"{whole_seconds // 60}m"
|
||||
elif whole_seconds < 24 * 60 * 60:
|
||||
age = f"{whole_seconds // (60 * 60)}h"
|
||||
else:
|
||||
age = f"{whole_seconds // (24 * 60 * 60)}d"
|
||||
latency_milliseconds = max(0, round(check.duration_seconds * 1000))
|
||||
timing = f"checked {age} ago · {latency_milliseconds} ms"
|
||||
if check.error is not None:
|
||||
return f"failed · {timing} · {check.error}"
|
||||
freshness = "stale" if age_seconds >= SERVER_STATUS_STALE_SECONDS else "fresh"
|
||||
return f"{freshness} · {timing}"
|
||||
|
||||
|
||||
def _server_component_text(name: str, online: bool | None) -> str:
|
||||
if online is True:
|
||||
state = "up"
|
||||
elif online is False:
|
||||
state = "down"
|
||||
else:
|
||||
state = "unknown"
|
||||
return f"{name} {state}"
|
||||
|
||||
|
||||
def server_status_presentation(
|
||||
status: RealmServerStatus,
|
||||
*,
|
||||
show_debug_details: bool = False,
|
||||
) -> ServerStatusPresentation:
|
||||
if status.online is True:
|
||||
text = f"● {status.name}"
|
||||
style = "ServerOnline.TLabel"
|
||||
elif status.online is False:
|
||||
text = f"● {status.name} · offline"
|
||||
style = "ServerOffline.TLabel"
|
||||
else:
|
||||
text = f"○ {status.name} · status unknown"
|
||||
style = "ServerUnknown.TLabel"
|
||||
if show_debug_details:
|
||||
details: list[str] = []
|
||||
if status.players_online is not None:
|
||||
label = "player" if status.players_online == 1 else "players"
|
||||
details.append(f"{status.players_online} {label}")
|
||||
details.extend(
|
||||
(
|
||||
_server_component_text("login", status.login_online),
|
||||
_server_component_text("game", status.game_online),
|
||||
)
|
||||
)
|
||||
text = " · ".join((text, *details))
|
||||
return ServerStatusPresentation(text=text, style=style)
|
||||
Reference in New Issue
Block a user