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:
1 parent
9e22cebb81
commit
0236278929
19 files changed
+986
-81
No files matched your search
+36
-21
@@ -43,14 +43,7 @@ def _targets_from_ace(conn, host, ace):
|
||||
targets = []
|
||||
for item in ace:
|
||||
slot = int(item["ams_index"]) + 1
|
||||
row = conn.execute(
|
||||
"""
|
||||
SELECT * FROM spools
|
||||
WHERE printer_host = %s AND ace_slot = %s
|
||||
ORDER BY id LIMIT 1
|
||||
""",
|
||||
(host, slot),
|
||||
).fetchone()
|
||||
row = store.spool_at_slot(conn, host, slot)
|
||||
if row:
|
||||
targets.append(row)
|
||||
return targets
|
||||
@@ -62,12 +55,18 @@ def unix_to_dt(value):
|
||||
return datetime.fromtimestamp(float(value), timezone.utc)
|
||||
|
||||
|
||||
def choose_spool(conn, host, material, hinted_id):
|
||||
def choose_spool(conn, host, material, hinted_id, ended_at=None):
|
||||
"""Spule für History-Abzug. Ohne Hint nur Rollen, die vor Druckende existierten."""
|
||||
if hinted_id:
|
||||
row = store.get_spool_row(conn, hinted_id)
|
||||
if row:
|
||||
if row and _spool_valid_for_end(row, ended_at):
|
||||
return row
|
||||
rows = store.spools_for_printer(conn, host)
|
||||
if row and not _spool_valid_for_end(row, ended_at):
|
||||
return None
|
||||
rows = [
|
||||
row for row in store.spools_for_printer(conn, host)
|
||||
if _spool_valid_for_end(row, ended_at)
|
||||
]
|
||||
if len(rows) == 1:
|
||||
return rows[0]
|
||||
if material:
|
||||
@@ -77,6 +76,24 @@ def choose_spool(conn, host, material, hinted_id):
|
||||
return None
|
||||
|
||||
|
||||
def _spool_valid_for_end(spool, ended_at):
|
||||
"""Verhindert Abzug alter Moonraker-Jobs auf neu eingelegte Spulen."""
|
||||
if ended_at is None or not spool:
|
||||
return True
|
||||
created = spool.get("created_at")
|
||||
if created is None:
|
||||
return True
|
||||
end = ended_at
|
||||
if getattr(created, "tzinfo", None) is None and getattr(end, "tzinfo", None) is not None:
|
||||
created = created.replace(tzinfo=timezone.utc)
|
||||
if getattr(end, "tzinfo", None) is None and getattr(created, "tzinfo", None) is not None:
|
||||
end = end.replace(tzinfo=timezone.utc)
|
||||
try:
|
||||
return created <= end
|
||||
except TypeError:
|
||||
return True
|
||||
|
||||
|
||||
def file_material_types(file_row):
|
||||
types = []
|
||||
for item in (file_row or {}).get("filaments") or []:
|
||||
@@ -93,14 +110,7 @@ def resolve_spools_at_host(conn, host, ace_map=None):
|
||||
if mapping:
|
||||
for item in mapping:
|
||||
slot = int(item["ams_index"]) + 1
|
||||
row = conn.execute(
|
||||
"""
|
||||
SELECT * FROM spools
|
||||
WHERE printer_host = %s AND ace_slot = %s
|
||||
ORDER BY id LIMIT 1
|
||||
""",
|
||||
(host, slot),
|
||||
).fetchone()
|
||||
row = store.spool_at_slot(conn, host, slot)
|
||||
if row:
|
||||
found.append(row)
|
||||
return found
|
||||
@@ -329,7 +339,12 @@ def sync_history(conn, cfg):
|
||||
file_id = (sent or {}).get("file_id") or (known or {}).get("id")
|
||||
project_id = (sent or {}).get("project_id") or (known or {}).get("project_id")
|
||||
hinted = (sent or {}).get("spool_id") or (known or {}).get("spool_id")
|
||||
spool = choose_spool(conn, printer["host"], material, hinted)
|
||||
ended_at = unix_to_dt(job.get("end_time"))
|
||||
# Ohne Send-Eintrag keine Rate — sonst zieht eine neue Spule alle alten Jobs ab.
|
||||
if not sent and not hinted:
|
||||
spool = None
|
||||
else:
|
||||
spool = choose_spool(conn, printer["host"], material, hinted, ended_at=ended_at)
|
||||
terminal = state in TERMINAL
|
||||
live = store.find_live_run(conn, printer["host"], filename)
|
||||
progress = float((live or {}).get("progress_last") or 0)
|
||||
@@ -503,7 +518,7 @@ def send_file(
|
||||
progress("pruefen", 15, "Drucker prüfen…")
|
||||
try:
|
||||
live = moonraker.query(host)
|
||||
except (urllib.error.URLError, TimeoutError, json.JSONDecodeError, KeyError) as exc:
|
||||
except (urllib.error.URLError, TimeoutError, json.JSONDecodeError, KeyError, OSError, ValueError) as exc:
|
||||
raise GrottiError("Der Drucker ist nicht erreichbar.", "offline") from exc
|
||||
if live.get("state") in ("printing", "paused"):
|
||||
raise GrottiError("Der Drucker druckt schon.", "belegt", 409)
|
||||
|
||||
Reference in new issue
Block a user