espilon-source/tools/c2/streams/server.py

135 lines
4.1 KiB
Python

"""Main camera server combining UDP receiver and unified web server."""
from typing import Optional, Callable
from .config import (
UDP_HOST, UDP_PORT, WEB_HOST, WEB_PORT, IMAGE_DIR,
DEFAULT_USERNAME, DEFAULT_PASSWORD, FLASK_SECRET_KEY, MULTILAT_AUTH_TOKEN
)
from .udp_receiver import UDPReceiver
from web.server import UnifiedWebServer
from web.mlat import MlatEngine
class CameraServer:
"""
Combined camera server that manages both:
- UDP receiver for incoming camera frames from ESP devices
- Unified web server for dashboard, cameras, and trilateration
"""
def __init__(self,
udp_host: str = UDP_HOST,
udp_port: int = UDP_PORT,
web_host: str = WEB_HOST,
web_port: int = WEB_PORT,
image_dir: str = IMAGE_DIR,
username: str = DEFAULT_USERNAME,
password: str = DEFAULT_PASSWORD,
device_registry=None,
on_frame: Optional[Callable] = None):
"""
Initialize the camera server.
Args:
udp_host: Host to bind UDP receiver
udp_port: Port for UDP receiver
web_host: Host to bind web server
web_port: Port for web server
image_dir: Directory to store camera frames
username: Web interface username
password: Web interface password
device_registry: DeviceRegistry instance for device listing
on_frame: Optional callback when frame is received (camera_id, frame, addr)
"""
self.mlat_engine = MlatEngine()
self.udp_receiver = UDPReceiver(
host=udp_host,
port=udp_port,
image_dir=image_dir,
on_frame=on_frame
)
self.web_server = UnifiedWebServer(
host=web_host,
port=web_port,
image_dir=image_dir,
username=username,
password=password,
secret_key=FLASK_SECRET_KEY,
multilat_token=MULTILAT_AUTH_TOKEN,
device_registry=device_registry,
mlat_engine=self.mlat_engine
)
@property
def is_running(self) -> bool:
"""Check if both servers are running."""
return self.udp_receiver.is_running and self.web_server.is_running
@property
def udp_running(self) -> bool:
return self.udp_receiver.is_running
@property
def web_running(self) -> bool:
return self.web_server.is_running
def start(self) -> dict:
"""
Start both UDP receiver and web server.
Returns:
dict with status of each server
"""
results = {
"udp": {"started": False, "host": self.udp_receiver.host, "port": self.udp_receiver.port},
"web": {"started": False, "host": self.web_server.host, "port": self.web_server.port}
}
if self.udp_receiver.start():
results["udp"]["started"] = True
if self.web_server.start():
results["web"]["started"] = True
results["web"]["url"] = self.web_server.get_url()
return results
def stop(self) -> dict:
"""
Stop both servers.
Returns:
dict with stop status
"""
self.udp_receiver.stop()
self.web_server.stop()
return {
"udp": {"stopped": True},
"web": {"stopped": True}
}
def get_status(self) -> dict:
"""Get status of both servers."""
return {
"udp": {
"running": self.udp_receiver.is_running,
"host": self.udp_receiver.host,
"port": self.udp_receiver.port,
**self.udp_receiver.get_stats()
},
"web": {
"running": self.web_server.is_running,
"host": self.web_server.host,
"port": self.web_server.port,
"url": self.web_server.get_url() if self.web_server.is_running else None
}
}
def get_active_cameras(self) -> list:
"""Get list of active camera IDs."""
return self.udp_receiver.active_cameras