"""Keep confirmed task heads and locally starred uploads; never retry deletion.""" import json import time from datetime import UTC, datetime class CloudLibrary: def __init__(self, service): self.service = service self.db = service.db self.checked = 0.0 def register(self, device_id, image_id, asset_id, operation_id): meta = self.service.assets.info(asset_id) self.db.execute( "INSERT INTO managed_cloud_uploads VALUES(?,?,?,?,?,?,NULL,NULL)", ( device_id, image_id, asset_id, meta.get("job_id"), operation_id, datetime.now(UTC).isoformat(), ), ) def confirm(self, operation_id): self.db.execute( "UPDATE managed_cloud_uploads SET confirmed_at=? WHERE operation_id=?", (datetime.now(UTC).isoformat(), operation_id), ) self.checked = 0.0 def retained(self, row): meta = self.db.one( "SELECT starred FROM asset_metadata WHERE asset_id=?", (row["asset_id"],) ) if meta and meta["starred"]: head = self.db.one( "SELECT image_id FROM managed_cloud_uploads WHERE device_id=? AND asset_id=? AND confirmed_at IS NOT NULL ORDER BY uploaded_at DESC,image_id DESC LIMIT 1", (row["device_id"], row["asset_id"]), ) if not head or head["image_id"] == row["image_id"]: return True if row["job_id"]: head = self.db.one( "SELECT image_id FROM managed_cloud_uploads WHERE device_id=? AND job_id=? AND confirmed_at IS NOT NULL ORDER BY uploaded_at DESC,image_id DESC LIMIT 1", (row["device_id"], row["job_id"]), ) if head and head["image_id"] == row["image_id"]: return True return False def eligible(self, device_id, image_id): row = self.db.one( "SELECT * FROM managed_cloud_uploads WHERE device_id=? AND image_id=?", (device_id, image_id), ) if not row or self.retained(row): return False # A confirmed replacement is mandatory; failed/unknown uploads cannot # evict the last known usable cloud image. newer = self.db.one( "SELECT image_id FROM managed_cloud_uploads WHERE device_id=? AND confirmed_at IS NOT NULL AND uploaded_at>? LIMIT 1", (device_id, row["uploaded_at"]), ) if not newer: return False state = self.service.state(device_id) if state["base_image_id"] == image_id: return False if self.db.one( "SELECT id FROM overrides WHERE device_id=? AND image_id=?", (device_id, image_id), ): return False for r in self.db.all( "SELECT payload FROM playlists UNION ALL SELECT payload FROM jobs" ): data = json.loads(r["payload"]) if data.get("device_id") == device_id and ( image_id in data.get("image_ids", []) or data.get("source", {}).get("image_id") == image_id ): return False return True def sweep(self): if time.monotonic() - self.checked < 60: return self.checked = time.monotonic() with self.service.lock: if ( not self.service.settings.mock and not self.service.settings.write_enabled ): return for row in self.db.all( "SELECT * FROM managed_cloud_uploads WHERE cleanup_operation IS NULL ORDER BY uploaded_at" ): device_id, image_id = row["device_id"], row["image_id"] if self.service.blocked(device_id) or not self.eligible( device_id, image_id ): continue device = self.service.registry.get(device_id).device(refresh=True) if ( device.status != "online" or not device.current_content.synced or device.current_content.id == image_id ): continue id = self.service.submit( "delete", { "image_id": image_id, "confirm_current": False, "cloud_cleanup": True, }, device_id, "cloud-library", "cloud-cleanup-" + row["operation_id"], "cloud-cleanup-" + row["operation_id"] + "-" + datetime.now(UTC).strftime("%Y%m%d%H%M"), ) self.db.execute( "UPDATE managed_cloud_uploads SET cleanup_operation=? WHERE device_id=? AND image_id=?", (id, device_id, image_id), )