fix(bot): correct combat estimates and enforce client and runner failures
This commit is contained in:
parent
62693618db
commit
3f243eaeee
10 changed files with 859 additions and 273 deletions
30
sts2.py
30
sts2.py
|
|
@ -18,6 +18,7 @@ Never precompute an action list.
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import http.client
|
||||
import json
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
|
@ -78,7 +79,7 @@ class ActionResult:
|
|||
return self.status == "ok"
|
||||
|
||||
|
||||
def _request(path: str, payload: dict | None = None, timeout: float = TIMEOUT) -> dict:
|
||||
def _read(path: str, payload: dict | None = None, timeout: float = TIMEOUT) -> bytes:
|
||||
url = BASE + path
|
||||
if payload is None:
|
||||
request = urllib.request.Request(url, method="GET")
|
||||
|
|
@ -93,17 +94,30 @@ def _request(path: str, payload: dict | None = None, timeout: float = TIMEOUT) -
|
|||
with urllib.request.urlopen(request, timeout=timeout) as response:
|
||||
body = response.read()
|
||||
except urllib.error.HTTPError as exc:
|
||||
detail = exc.read().decode("utf-8", "replace")
|
||||
try:
|
||||
detail = exc.read().decode("utf-8", "replace")
|
||||
except (OSError, http.client.HTTPException):
|
||||
detail = "could not read the error body"
|
||||
raise Sts2Error(f"HTTP {exc.code} on {path}: {detail[:300]}") from exc
|
||||
except urllib.error.URLError as exc:
|
||||
raise Sts2Error(
|
||||
f"cannot reach the game on {BASE}. Is STS2 running with the mod loaded? ({exc})"
|
||||
) from exc
|
||||
except (OSError, http.client.HTTPException) as exc:
|
||||
# A failed POST may already have reached the game. Never retry it here.
|
||||
raise Sts2Error(f"transport failure on {path}: {type(exc).__name__}: {exc}") from exc
|
||||
return body
|
||||
|
||||
|
||||
def _request(path: str, payload: dict | None = None, timeout: float = TIMEOUT) -> dict:
|
||||
body = _read(path, payload, timeout)
|
||||
try:
|
||||
return json.loads(body)
|
||||
except json.JSONDecodeError as exc:
|
||||
data = json.loads(body)
|
||||
except (json.JSONDecodeError, UnicodeDecodeError) as exc:
|
||||
raise Sts2Error(f"non-JSON response from {path}: {body[:200]!r}") from exc
|
||||
if not isinstance(data, dict):
|
||||
raise Sts2Error(f"expected a JSON object from {path}, got {type(data).__name__}")
|
||||
return data
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
|
|
@ -121,9 +135,11 @@ def is_up() -> bool:
|
|||
def state(fmt: str = "json") -> dict:
|
||||
"""Current game state. fmt: 'json' or 'markdown' (markdown returns text)."""
|
||||
if fmt == "markdown":
|
||||
req = urllib.request.Request(f"{BASE}/api/v1/singleplayer?format=markdown")
|
||||
with urllib.request.urlopen(req, timeout=TIMEOUT) as response:
|
||||
return {"markdown": response.read().decode("utf-8")}
|
||||
body = _read("/api/v1/singleplayer?format=markdown")
|
||||
try:
|
||||
return {"markdown": body.decode("utf-8")}
|
||||
except UnicodeDecodeError as exc:
|
||||
raise Sts2Error("invalid UTF-8 markdown response") from exc
|
||||
return _request("/api/v1/singleplayer?format=json")
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue