mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-22 21:26:38 +00:00
feat: stage6 — Image Pipeline (F05) and Rotation Manager (F06)
This commit is contained in:
@@ -5,6 +5,8 @@ from __future__ import annotations
|
||||
import asyncio
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from gps_denied.core.pipeline import ImageInputPipeline
|
||||
from gps_denied.core.results import ResultManager
|
||||
from gps_denied.core.sse import SSEEventStreamer
|
||||
from gps_denied.db.repository import FlightRepository
|
||||
from gps_denied.schemas import GPSPoint
|
||||
@@ -23,17 +25,20 @@ from gps_denied.schemas.flight import (
|
||||
UserFixResponse,
|
||||
Waypoint,
|
||||
)
|
||||
from gps_denied.schemas.image import ImageBatch
|
||||
|
||||
|
||||
class FlightProcessor:
|
||||
"""Orchestrates flight business logic."""
|
||||
"""Manages business logic and background processing for flights."""
|
||||
|
||||
def __init__(self, repo: FlightRepository, sse: SSEEventStreamer) -> None:
|
||||
self.repo = repo
|
||||
self.sse = sse
|
||||
def __init__(self, repository: FlightRepository, streamer: SSEEventStreamer) -> None:
|
||||
self.repository = repository
|
||||
self.streamer = streamer
|
||||
self.result_manager = ResultManager(repository, streamer)
|
||||
self.pipeline = ImageInputPipeline(storage_dir=".image_storage", max_queue_size=50)
|
||||
|
||||
async def create_flight(self, req: FlightCreateRequest) -> FlightResponse:
|
||||
flight = await self.repo.insert_flight(
|
||||
flight = await self.repository.insert_flight(
|
||||
name=req.name,
|
||||
description=req.description,
|
||||
start_lat=req.start_gps.lat,
|
||||
@@ -42,7 +47,7 @@ class FlightProcessor:
|
||||
camera_params=req.camera_params.model_dump(),
|
||||
)
|
||||
for poly in req.geofences.polygons:
|
||||
await self.repo.insert_geofence(
|
||||
await self.repository.insert_geofence(
|
||||
flight.id,
|
||||
nw_lat=poly.north_west.lat,
|
||||
nw_lon=poly.north_west.lon,
|
||||
@@ -50,7 +55,7 @@ class FlightProcessor:
|
||||
se_lon=poly.south_east.lon,
|
||||
)
|
||||
for w in req.rough_waypoints:
|
||||
await self.repo.insert_waypoint(flight.id, lat=w.lat, lon=w.lon)
|
||||
await self.repository.insert_waypoint(flight.id, lat=w.lat, lon=w.lon)
|
||||
|
||||
return FlightResponse(
|
||||
flight_id=flight.id,
|
||||
@@ -60,11 +65,11 @@ class FlightProcessor:
|
||||
)
|
||||
|
||||
async def get_flight(self, flight_id: str) -> FlightDetailResponse | None:
|
||||
flight = await self.repo.get_flight(flight_id)
|
||||
flight = await self.repository.get_flight(flight_id)
|
||||
if not flight:
|
||||
return None
|
||||
wps = await self.repo.get_waypoints(flight_id)
|
||||
state = await self.repo.load_flight_state(flight_id)
|
||||
wps = await self.repository.get_waypoints(flight_id)
|
||||
state = await self.repository.load_flight_state(flight_id)
|
||||
|
||||
waypoints = [
|
||||
Waypoint(
|
||||
@@ -103,13 +108,13 @@ class FlightProcessor:
|
||||
)
|
||||
|
||||
async def delete_flight(self, flight_id: str) -> DeleteResponse:
|
||||
deleted = await self.repo.delete_flight(flight_id)
|
||||
deleted = await self.repository.delete_flight(flight_id)
|
||||
return DeleteResponse(deleted=deleted, flight_id=flight_id)
|
||||
|
||||
async def update_waypoint(
|
||||
self, flight_id: str, waypoint_id: str, waypoint: Waypoint
|
||||
) -> UpdateResponse:
|
||||
ok = await self.repo.update_waypoint(
|
||||
ok = await self.repository.update_waypoint(
|
||||
flight_id,
|
||||
waypoint_id,
|
||||
lat=waypoint.lat,
|
||||
@@ -126,7 +131,7 @@ class FlightProcessor:
|
||||
failed = []
|
||||
updated = 0
|
||||
for wp in waypoints:
|
||||
ok = await self.repo.update_waypoint(
|
||||
ok = await self.repository.update_waypoint(
|
||||
flight_id,
|
||||
wp.id,
|
||||
lat=wp.lat,
|
||||
@@ -144,10 +149,10 @@ class FlightProcessor:
|
||||
async def queue_images(
|
||||
self, flight_id: str, metadata: BatchMetadata, file_count: int
|
||||
) -> BatchResponse:
|
||||
state = await self.repo.load_flight_state(flight_id)
|
||||
state = await self.repository.load_flight_state(flight_id)
|
||||
if state:
|
||||
total = state.frames_total + file_count
|
||||
await self.repo.save_flight_state(flight_id, frames_total=total, status="processing")
|
||||
await self.repository.save_flight_state(flight_id, frames_total=total, status="processing")
|
||||
|
||||
next_seq = metadata.end_sequence + 1
|
||||
seqs = list(range(metadata.start_sequence, metadata.end_sequence + 1))
|
||||
@@ -159,13 +164,13 @@ class FlightProcessor:
|
||||
)
|
||||
|
||||
async def handle_user_fix(self, flight_id: str, req: UserFixRequest) -> UserFixResponse:
|
||||
await self.repo.save_flight_state(flight_id, blocked=False, status="processing")
|
||||
await self.repository.save_flight_state(flight_id, blocked=False, status="processing")
|
||||
return UserFixResponse(
|
||||
accepted=True, processing_resumed=True, message="Fix applied."
|
||||
)
|
||||
|
||||
async def get_flight_status(self, flight_id: str) -> FlightStatusResponse | None:
|
||||
state = await self.repo.load_flight_state(flight_id)
|
||||
state = await self.repository.load_flight_state(flight_id)
|
||||
if not state:
|
||||
return None
|
||||
return FlightStatusResponse(
|
||||
@@ -194,5 +199,5 @@ class FlightProcessor:
|
||||
async def stream_events(self, flight_id: str, client_id: str):
|
||||
"""Async generator for SSE stream."""
|
||||
# Yield from the real SSE streamer generator
|
||||
async for event in self.sse.stream_generator(flight_id, client_id):
|
||||
async for event in self.streamer.stream_generator(flight_id, client_id):
|
||||
yield event
|
||||
|
||||
Reference in New Issue
Block a user