From cdc20457f1f05d15d90953455eccc3849dc36274 Mon Sep 17 00:00:00 2001 From: x01dc Date: Mon, 27 Jul 2026 16:15:04 +0200 Subject: [PATCH] feat(OMNY): upload tomo PDF report to the samples web folder Replaces the old, already-broken upload_last_pon.sh shell-out (and assorted other dead/abandoned upload attempts left commented out in flomni.py) with a direct HTTP upload: POSTs the just-written PDF, base64-encoded, to omny-test.psi.ch/samples/upload.php with filename="new.pdf" so the server assigns the number itself from its own counter file -- the same counter newmeasurement.php (TomoIDManager.register(), called via add_sample_database() just before write_pdf_report()) already incremented and returned as self.tomo_id. Runs in a background thread so a slow/unreachable host never delays the calling tomo_scan(), and cross-checks the response against the expected filename to flag a possible race with a concurrent registration. Added to TomoQueueMixin (OMNY_shared) rather than duplicated in both LamNI and Flomni, following add_sample_database()'s existing pattern of shared, setup-agnostic tomo-id/database logic. --- .../bec_ipython_client/plugins/LamNI/lamni.py | 9 +-- .../plugins/OMNY_shared/tomo_queue_mixin.py | 77 +++++++++++++++++++ .../plugins/flomni/flomni.py | 14 +--- 3 files changed, 83 insertions(+), 17 deletions(-) diff --git a/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py b/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py index f2be986..576bccf 100644 --- a/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py +++ b/csaxs_bec/bec_ipython_client/plugins/LamNI/lamni.py @@ -2,7 +2,6 @@ import builtins import datetime import json import os -import subprocess import time from pathlib import Path @@ -2124,11 +2123,9 @@ class LamNI(TomoQueueMixin, LamNIAlignmentMixin, LamNIOpticsMixin, LamniGuiTools file.write( f"\nAt-each-angle hook source ('{self.at_each_angle_hook}'):\n{hook_source}" ) - # upload_last_pon.sh no longer works and needs a rewrite -- disabled - # for now (mirrors Flomni, which already has this commented out). - # subprocess.run( - # "xterm /work/sls/spec/local/XOMNY/bin/upload/upload_last_pon.sh &", shell=True - # ) + # Replaces the old upload_last_pon.sh script (broken, never rewritten -- + # see git history) with a direct HTTP upload to the samples web folder. + self._upload_pdf_report_to_samples(user_target) # Same tolerance as write_to_scilog(): a session without scilog/logbook # configured (e.g. a dev/sim session) must not crash report generation # over the logbook upload -- the PDF itself is already written above. diff --git a/csaxs_bec/bec_ipython_client/plugins/OMNY_shared/tomo_queue_mixin.py b/csaxs_bec/bec_ipython_client/plugins/OMNY_shared/tomo_queue_mixin.py index f351f5d..f91f71a 100644 --- a/csaxs_bec/bec_ipython_client/plugins/OMNY_shared/tomo_queue_mixin.py +++ b/csaxs_bec/bec_ipython_client/plugins/OMNY_shared/tomo_queue_mixin.py @@ -39,6 +39,7 @@ import builtins import datetime import inspect import json +import threading import uuid from typing import Callable @@ -390,6 +391,82 @@ class TomoQueueMixin: user=user, ) + # Only omny-test.psi.ch, not v1p0zyg2w9n2k9c1.myfritz.net (the host + # TomoIDManager.OMNY_URL registers measurements against, and the + # webpage generators mirror their own content to): only + # omny-test.psi.ch has the sample counter that actually matches + # self.tomo_id. + _SAMPLES_UPLOAD_HOSTS = ("https://omny-test.psi.ch",) + + def _upload_pdf_report_to_samples(self, pdf_path: str) -> None: + """Upload a just-written PDF report to the OMNY samples web folder + (see _SAMPLES_UPLOAD_HOSTS). Identical for every setup that uses + ``self.tomo_id`` (set via add_sample_database() just before + write_pdf_report() calls this) -- shared here so LamNI/Flomni don't + each carry their own copy. Replaces the old, broken + upload_last_pon.sh script both used to shell out to. + + POSTs to /samples/upload.php with filename="new.pdf" so the + server assigns the number itself from its own counter file + (countersaver.txt) -- the same counter newmeasurement.php + (TomoIDManager.register()) already incremented and returned as + self.tomo_id. Any other filename would be saved under samples/png/ + instead of directly in samples/, per upload.php's own branching, so + "new.pdf" is the only way to land the PDF at samples/.pdf + (matching the link newmeasurement.php writes into + the samples listing). + + Runs in a background daemon thread so a slow/unreachable host never + delays the calling tomo_scan(). + """ + + def _run(): + try: + import base64 + + import requests + import urllib3 + + urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + except ImportError: + print("Could not upload PDF report: 'requests' library not installed.") + return + + try: + with open(pdf_path, "rb") as f: + filedata = base64.b64encode(f.read()).decode("ascii") + except OSError as exc: + print(f"Could not read PDF report for upload ({pdf_path}): {exc}") + return + + expected_name = f"{self.tomo_id}.pdf" + for host in self._SAMPLES_UPLOAD_HOSTS: + url = f"{host}/samples/upload.php" + try: + r = requests.post( + url, + data={"filename": "new.pdf", "filedata": filedata}, + timeout=20, + verify=False, # accept self-signed certs + allow_redirects=False, # SSRF hardening + ) + if r.status_code != 200: + print(f"PDF upload to {url} -> HTTP {r.status_code}: {r.text[:120]}") + continue + if expected_name not in r.text: + print( + f"PDF upload to {url} succeeded but the server-assigned " + f"filename doesn't match tomo_id {self.tomo_id} (response: " + f"{r.text[:120]!r}) -- a concurrent measurement " + "registration may have raced this upload." + ) + else: + print(f"Uploaded PDF report to {url} as {expected_name}.") + except Exception as exc: + print(f"PDF upload to {url} failed: {exc}") + + threading.Thread(target=_run, name="PdfUpload", daemon=True).start() + # ── command-job action registry / dispatch ────────────────────────────── def _validate_action_kwargs(self, action_name: str, kwargs: dict) -> None: diff --git a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py index cdd3958..bf66e7a 100644 --- a/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py +++ b/csaxs_bec/bec_ipython_client/plugins/flomni/flomni.py @@ -3,7 +3,6 @@ import datetime import json import os import random -import subprocess import time from pathlib import Path @@ -3817,16 +3816,9 @@ class Flomni( file.write( f"\nAt-each-angle hook source ('{self.at_each_angle_hook}'):\n{hook_source}" ) - # subprocess.run( - # "xterm /work/sls/spec/local/XOMNY/bin/upload/upload_last_pon.sh &", shell=True - # ) - # status = subprocess.run(f"cp /tmp/spec-e20131-specES1.pdf {user_target}", shell=True) - # msg = bec.tomo_progress.tomo_progressMessage() - # logo_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "LamNI_logo.png") - # msg.add_file(logo_path).add_text("".join(content).replace("\n", "

")).add_tag( - # ["BEC", "tomo_parameters", f"dataset_id_{dataset_id}", "flOMNI", self.sample_name] - # ) - # self.client.tomo_progress.send_tomo_progress_message("~/data/raw/documentation/tomo_scan_ID_{self.tomo_id}.pdf").send() + # Replaces the old upload_last_pon.sh script (broken, never rewritten) + # with a direct HTTP upload to the samples web folder. + self._upload_pdf_report_to_samples(user_target) import csaxs_bec # Ensure this is a Path object, not a string