Commit Graph
4 Commits
Author SHA1 Message Date
maziggy 10c261dcf2 chore(tests): suppress B108 on dummy /tmp test fixtures 2026-04-19 09:48:10 +02:00
maziggy 68920f8c62 Fix virtual printer dropping null-terminated MQTT payloads from OrcaSlicer Linux (#927)
OrcaSlicer's Linux BBLNetworkPlugin publishes MQTT payloads with the
  C-string null terminator included in the length, so decoded messages
  arrived as `{…}\x00`. The strict json.loads() raised JSONDecodeError
  and the publish handler silently returned — pushall, get_version, and
  project_file were never answered, and the slicer hit its 60 s sync
  timeout. Print_queue mode only (proxy mode tunnels MQTT). The b069b521
  serial-adaptation fix was correct but ran past this earlier silent
  failure.

  _handle_publish now strips trailing \x00/whitespace before parsing and
  logs the raw payload on any remaining decode failure so future silent
  variants are visible in support bundles.
2026-04-19 08:04:05 +02:00
maziggy b069b5217c y Fix virtual printer "Synchronizing device information" timeout in Orca (#927)
OrcaSlicer's "Send job" flow sat on "Synchronizing device information…"
  until it gave up, even though FTP upload worked when the user clicked
  "Send job anyway". The virtual printer's MQTT server gated all incoming
  command handling on `f"device/{self.serial}/request" in topic` — if the
  slicer's cached serial for the VP didn't exactly equal the VP's computed
  self.serial (model prefix + per-VP serial_suffix), every get_version,
  pushall, and project_file publish was silently dropped. Nothing was
  logged past the initial "MQTT publish to …" line, so the slicer never
  received a push_status or get_version response on its subscribed
  device/{serial}/report topic and hit its sync timeout. Responses were
  also unconditionally published on device/{self.serial}/report, so even
  when the inbound check happened to pass, replies targeted a topic the
  slicer wasn't listening on if its serial had drifted.

  Both directions are now serial-adaptive:

  - `_handle_publish` accepts any authenticated publish on a
    `device/*/request` topic and extracts the serial from the topic itself
    rather than comparing against self.serial.
  - A per-connection `_client_serials` dict tracks the serial the slicer
    actually uses, populated from the first SUBSCRIBE or PUBLISH seen on
    each connection and cleared on disconnect/stop.
  - `_send_status_report`, `_send_version_response`, `_send_print_response`
    now take an optional `serial` parameter (defaulting to self.serial)
    so every outgoing publish — including the periodic 1-second status
    push — targets the topic the slicer subscribed to.
  - The version response's embedded `module[].sn` fields now also carry
    the client's serial so the payload is internally consistent with the
    topic.
  - When the client's serial differs from self.serial an INFO log records
    the adaptation so it's visible in future support bundles.

  The working case (slicer's cached serial equals self.serial, as in my
  own H2D-1 Proxy setup) is bit-for-bit identical to the old behavior —
  the new check is strictly more permissive and only affects cases the
  old code silently dropped.

  Regression tests cover:
  - `_extract_serial_from_topic` valid/invalid topic shapes
  - mismatched-serial publish → handler runs, response topic and sn field
    both use the client's serial
  - non-`/request` topics → still rejected
  - pushall → status_report routed to the client's subscribed topic
  - `_client_serials` cleared on stop()
2026-04-10 12:13:54 +02:00
maziggy 82d329d85c [Fix] Virtual Printer FTP routed to wrong VP with different access codes (#735)
When running multiple virtual printers with different access codes on
  separate bind IPs, FTP connections were always routed to the wrong VP.

  Root cause: the iptables REDIRECT rule (990→9990) rewrites the
  destination IP to the incoming interface's primary address. With Linux's
  weak host model (arp_filter=0), packets for secondary IPs arrive on the
  primary interface, and REDIRECT sends them all to the first VP's FTP
  server. MQTT was unaffected because port 8883 had no redirect.

  Fix: FTP server now binds directly to port 990 (standard implicit FTPS),
  eliminating the iptables redirect entirely. Requires CAP_NET_BIND_SERVICE
  (already set in the systemd service file and Docker image).

  Also removed a global asyncio set_exception_handler() in the MQTT server
  that was overwritten by each VP instance, causing spurious "Unhandled
  exception in client_connected_cb" errors on startup.

  Changes:
  - FTP_PORT: 9990 → 990 (ftp_server.py)
  - Removed set_exception_handler() from MQTT server
  - Updated Dockerfile, docker-compose.yml port mappings
  - Deprecated --redirect-990 in install script
  - Updated wiki: removed iptables instructions for all platforms
  - Added migration guide (docs/migration-vp-ftp-port.md)
  - Added unit tests for port constant and no-global-state invariant
2026-03-18 09:04:31 +01:00