fix: P0+P1 audit — memory leak, hardcoded camera/GPS, lifespan init, background processing, batch validation, ABC interfaces

This commit is contained in:
Yuzviak
2026-03-22 23:35:12 +02:00
parent 8649d13a78
commit ca327034c0
9 changed files with 161 additions and 38 deletions
+17 -2
View File
@@ -1,7 +1,7 @@
from collections.abc import AsyncGenerator
from typing import Annotated
from fastapi import Depends
from fastapi import Depends, Request
from sqlalchemy.ext.asyncio import AsyncSession
from gps_denied.core.processor import FlightProcessor
@@ -12,17 +12,32 @@ from gps_denied.db.repository import FlightRepository
# Singleton instance of SSE Event Streamer
_sse_streamer = SSEEventStreamer()
# Singleton FlightProcessor (one per process, reused across requests)
_processor: FlightProcessor | None = None
def get_sse_streamer() -> SSEEventStreamer:
return _sse_streamer
async def get_repository(session: AsyncSession = Depends(get_session)) -> FlightRepository:
return FlightRepository(session)
async def get_flight_processor(
request: Request,
repo: FlightRepository = Depends(get_repository),
sse: SSEEventStreamer = Depends(get_sse_streamer),
) -> FlightProcessor:
return FlightProcessor(repo, sse)
global _processor
if _processor is None:
_processor = FlightProcessor(repo, sse)
# Attach pipeline components from lifespan (P1#4)
components = getattr(request.app.state, "pipeline_components", None)
if components:
_processor.attach_components(**components)
# Always update repo (new session per request)
_processor.repository = repo
return _processor
# Type aliases for cleaner router definitions
+23 -3
View File
@@ -2,6 +2,7 @@
from __future__ import annotations
import asyncio
import json
from typing import Annotated
@@ -115,11 +116,30 @@ async def upload_image_batch(
if not f_info:
raise HTTPException(status_code=404, detail="Flight not found")
if not (10 <= len(images) <= 50):
# Allow fewer for small tests, but raise bad request based on spec typically
pass
# P1#6: Batch size validation (allow 1-50 for dev, spec says 10-50)
if len(images) < 1 or len(images) > 50:
raise HTTPException(
status_code=422,
detail=f"Batch must contain 1-50 images, got {len(images)}",
)
res = await processor.queue_images(flight_id, meta_obj, len(images))
# P1#5: Spawn background task to process each frame
import cv2
import numpy as np
async def _process_batch():
for idx, upload in enumerate(images):
raw = await upload.read()
arr = np.frombuffer(raw, dtype=np.uint8)
img = cv2.imdecode(arr, cv2.IMREAD_COLOR)
if img is not None:
frame_id = meta_obj.start_frame_id + idx
await processor.process_frame(flight_id, frame_id, img)
asyncio.create_task(_process_batch())
await session.commit()
return res