Grotti 3.0 Phase 1: Migrationen, Pool, Queue- und Abzug-Fixes.

Nummerierte SQL-Migrationen, psycopg-Pool, waitress, hängende Queue-Jobs,
sichere History-Abzüge, Chargen-Locks, Upload-/Host-Validierung, ProxyFix.
This commit is contained in:
Dominic Gundel committed 2026-10-18 00:47:23 +02:00
1 parent 9e22cebb81
commit 0236278929
19 files changed
+986 -81

No files matched your search

+21 -1
View File
@@ -17,6 +17,16 @@ SLOT_CACHE = {}
MESH_CACHE = {}
OBJECT_CACHE = {}
THUMB_RE_LIMIT = 180_000
_CACHE_MAX = 128
def _trim_cache(cache, max_items=_CACHE_MAX):
"""Einfache Größenbegrenzung (älteste Keys zuerst bei dict-Reihenfolge)."""
while len(cache) > max_items:
try:
cache.pop(next(iter(cache)))
except StopIteration:
break
def matrix_rows(points):
@@ -343,6 +353,11 @@ def steuern(host, action, params=None):
"""Whitelist-Steuerung ohne freie Konsole."""
params = params if isinstance(params, dict) else {}
action = (action or "").strip()
# MCP und ältere Clients schicken "value" statt temp/percent.
if "temp" not in params and params.get("value") is not None and action in ("nozzle", "bed", "dryer_start"):
params = {**params, "temp": params["value"]}
if "percent" not in params and params.get("value") is not None and action in ("speed", "flow", "fan"):
params = {**params, "percent": params["value"]}
def pct(key, default=100, lo=0, hi=200):
try:
@@ -492,6 +507,7 @@ def metadata(host, path):
except (urllib.error.URLError, TimeoutError, json.JSONDecodeError, KeyError):
data = {}
META_CACHE[key] = (now, data)
_trim_cache(META_CACHE)
return data
@@ -518,9 +534,11 @@ def embedded_preview(host, path):
text = response.read().decode("utf-8", "replace")
except (urllib.error.URLError, TimeoutError):
EMBEDDED[key] = None
_trim_cache(EMBEDDED)
return None
png = embedded_png(text)
EMBEDDED[key] = png
_trim_cache(EMBEDDED)
return png
@@ -1117,7 +1135,9 @@ def snapshot(printers):
}
try:
card.update(query(printer["host"]))
except (urllib.error.URLError, TimeoutError, json.JSONDecodeError, KeyError) as error:
except Exception as error:
# Auch RemoteDisconnected / IncompleteRead / ValueError — sonst fällt der ganze Tick aus.
print("snapshot %s: %s" % (printer.get("host"), error), flush=True)
card.update({
"ok": False,
"state": "offline",