Commit 82789878 authored by vertighel's avatar vertighel
Browse files

fixing corrupted HDU

parent 8255ad65
Loading
Loading
Loading
Loading
Loading
+13 −5
Original line number Diff line number Diff line
@@ -104,11 +104,19 @@ def _load_data(cam_id: str) -> np.ndarray | None:
    path = _fits_path(cam_id)
    if path is None or not path.exists():
        return None
    try:
        with fits.open(path) as hdul:
            data = hdul[0].data
            if data is None:
                return None
            return data.astype(np.float32)
    except OSError:
        # Reader lost a race with a writer that isn't using an atomic
        # rename yet, or hit a genuinely corrupt file — either way, "no
        # data this round" is the right degradation, not an unhandled
        # exception (this fed straight into an uncaught OSError that used
        # to kill the whole /web/socket connection via _handle_tile_request).
        return None


def get_cached_data(cam_id: str) -> np.ndarray | None:
+7 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ sudo cp ../include/Atik* /usr/include/

# System modules
import ctypes
import os
import threading
import time
import numpy as np
@@ -466,7 +467,11 @@ class Camera(BaseDevice):
                           "Image type")

        log.debug(f"Writing on disk")
        hdu.writeto(filepath, overwrite=True)
        # Atomic write: temp file + os.replace() so a concurrent reader never
        # observes a truncated file mid-write ("Empty or corrupt FITS file").
        tmp_path = f"{filepath}.tmp"
        hdu.writeto(tmp_path, overwrite=True)
        os.replace(tmp_path, filepath)
        log.debug(f"Written")

        return filepath
+6 −1
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
"""Interface with an Atik camera device using the vendor's AtikSDK Python package."""

# System modules
import os
import threading
import time
from ctypes import byref, c_int, string_at
@@ -408,7 +409,11 @@ class Camera(BaseDevice):
                           "Image type")

        log.debug(f"Writing on disk")
        hdu.writeto(filepath, overwrite=True)
        # Atomic write: temp file + os.replace() so a concurrent reader never
        # observes a truncated file mid-write ("Empty or corrupt FITS file").
        tmp_path = f"{filepath}.tmp"
        hdu.writeto(tmp_path, overwrite=True)
        os.replace(tmp_path, filepath)
        log.debug(f"Written")

        return filepath
+9 −1
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@ Camera ID is the IP address (e.g. 10.185.119.111).
"""

# System modules
import os
import threading
import time
from datetime import datetime as dt
@@ -491,7 +492,14 @@ class Guider(Mako):
            hdr['YBINNING'] = (by, 'Y binning factor')
            
        log.debug(f"Writing on disk")
        hdu.writeto(filepath, overwrite=True)
        # Write to a sibling temp file then rename atomically — os.replace()
        # is a single directory-entry swap, so a concurrent reader (guider,
        # tile-request websocket, preview broadcaster) always sees either
        # the previous complete file or the new one, never a truncated /
        # half-written one ("Empty or corrupt FITS file").
        tmp_path = f"{filepath}.tmp"
        hdu.writeto(tmp_path, overwrite=True)
        os.replace(tmp_path, filepath)
        log.debug(f"Written")

        return filepath
+6 −1
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ single "get frame" call.
# System modules
import ctypes
import ctypes.util
import os
import threading
import time
from datetime import datetime as dt
@@ -758,7 +759,11 @@ class Camera(STL):
        ft = self._last_imagetype
        hdr['IMAGETYP'] = (_frame_type.get(ft, str(ft)) if ft is not None else "", "Image type")

        hdu.writeto(filepath, overwrite=True)
        # Atomic write: temp file + os.replace() so a concurrent reader never
        # observes a truncated file mid-write ("Empty or corrupt FITS file").
        tmp_path = f"{filepath}.tmp"
        hdu.writeto(tmp_path, overwrite=True)
        os.replace(tmp_path, filepath)

        return filepath

Loading