fix: direct-IP fallback when printer_mac unset; force utf-8 in bridge subprocess
Final-review hardening: - discover_printer falls back to direct IP reachability when printer_mac is empty (restores legacy behavior; avoids permanent unreachable on misconfig). Keeps the MAC check when a MAC IS set so we never print to a wrong DHCP tenant. - bridge subprocess decodes child stdout as utf-8 explicitly, so a LANG=C systemd locale can't UnicodeDecodeError on the success checkmark and mis-report error. - add tests for both no-MAC fallback paths (5 passed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -498,6 +498,13 @@ def discover_printer():
|
|||||||
seeds.append(CACHE_FILE.read_text().strip())
|
seeds.append(CACHE_FILE.read_text().strip())
|
||||||
if PRINTER_IP:
|
if PRINTER_IP:
|
||||||
seeds.append(PRINTER_IP)
|
seeds.append(PRINTER_IP)
|
||||||
|
if not PRINTER_MAC:
|
||||||
|
# No MAC configured: fall back to direct IP reachability (legacy behavior).
|
||||||
|
for ip in seeds:
|
||||||
|
if ip and _port_open(ip, PRINTER_PORT):
|
||||||
|
_cache_ip(ip)
|
||||||
|
return ip
|
||||||
|
raise RuntimeError("printer-not-found (no printer_mac configured)")
|
||||||
for ip in seeds:
|
for ip in seeds:
|
||||||
if ip and _mac_of(ip) == PRINTER_MAC and _port_open(ip, PRINTER_PORT):
|
if ip and _mac_of(ip) == PRINTER_MAC and _port_open(ip, PRINTER_PORT):
|
||||||
_cache_ip(ip)
|
_cache_ip(ip)
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ def run_briefing(client):
|
|||||||
client.publish(STATUS_TOPIC, "printing", retain=True)
|
client.publish(STATUS_TOPIC, "printing", retain=True)
|
||||||
log.info("Running briefing...")
|
log.info("Running briefing...")
|
||||||
r = subprocess.run(["/usr/bin/python3", BRIEFING],
|
r = subprocess.run(["/usr/bin/python3", BRIEFING],
|
||||||
capture_output=True, text=True, timeout=PRINT_TIMEOUT)
|
capture_output=True, text=True, encoding="utf-8",
|
||||||
|
timeout=PRINT_TIMEOUT)
|
||||||
if r.returncode == 0 and "Receipt sent" in r.stdout:
|
if r.returncode == 0 and "Receipt sent" in r.stdout:
|
||||||
client.publish(STATUS_TOPIC, "ok", retain=True)
|
client.publish(STATUS_TOPIC, "ok", retain=True)
|
||||||
log.info("Briefing printed OK")
|
log.info("Briefing printed OK")
|
||||||
|
|||||||
@@ -37,3 +37,24 @@ def test_not_found_raises(monkeypatch, tmp_path):
|
|||||||
assert False, "expected RuntimeError"
|
assert False, "expected RuntimeError"
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
assert "printer-not-found" in str(e)
|
assert "printer-not-found" in str(e)
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_mac_falls_back_to_direct_ip(monkeypatch, tmp_path):
|
||||||
|
# When printer_mac is unconfigured, a reachable seed IP is used directly.
|
||||||
|
monkeypatch.setattr(pb, "CACHE_FILE", tmp_path / "last_ip")
|
||||||
|
monkeypatch.setattr(pb, "PRINTER_IP", "192.168.0.184")
|
||||||
|
monkeypatch.setattr(pb, "PRINTER_MAC", "")
|
||||||
|
monkeypatch.setattr(pb, "_port_open", lambda ip, port, timeout=3: ip == "192.168.0.184")
|
||||||
|
assert pb.discover_printer() == "192.168.0.184"
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_mac_unreachable_raises(monkeypatch, tmp_path):
|
||||||
|
monkeypatch.setattr(pb, "CACHE_FILE", tmp_path / "last_ip")
|
||||||
|
monkeypatch.setattr(pb, "PRINTER_IP", "192.168.0.184")
|
||||||
|
monkeypatch.setattr(pb, "PRINTER_MAC", "")
|
||||||
|
monkeypatch.setattr(pb, "_port_open", lambda ip, port, timeout=3: False)
|
||||||
|
try:
|
||||||
|
pb.discover_printer()
|
||||||
|
assert False, "expected RuntimeError"
|
||||||
|
except RuntimeError as e:
|
||||||
|
assert "no printer_mac" in str(e)
|
||||||
|
|||||||
Reference in New Issue
Block a user