mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 22:59:59 -07:00
Security: - Add input validation for all API endpoints (frequency, lat/lon, device, gain, ppm) - Add HTML escaping utility to prevent XSS attacks - Add path traversal protection for log file configuration - Add proper HTTP status codes for error responses (400, 409, 503) Performance: - Reduce SSE keepalive overhead (30s interval instead of 1s) - Add centralized SSE stream utility with optimized keepalive - Add DataStore class for thread-safe data with automatic cleanup New Features: - Add data export endpoints (/export/aircraft, /export/wifi, /export/bluetooth) - Support for both JSON and CSV export formats - Add process cleanup on application exit (atexit handlers) - Label Iridium module as demo mode with clear warnings Code Quality: - Create utils/validation.py for centralized input validation - Create utils/sse.py for SSE stream utilities - Create utils/cleanup.py for memory management - Add safe_terminate() and register_process() for process management - Improve error handling with proper logging throughout routes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
90 lines
2.1 KiB
Python
90 lines
2.1 KiB
Python
"""Server-Sent Events (SSE) utilities."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import queue
|
|
import time
|
|
from typing import Any, Generator
|
|
|
|
|
|
def sse_stream(
|
|
data_queue: queue.Queue,
|
|
timeout: float = 1.0,
|
|
keepalive_interval: float = 30.0,
|
|
stop_check: callable = None
|
|
) -> Generator[str, None, None]:
|
|
"""
|
|
Generate SSE stream from a queue.
|
|
|
|
Args:
|
|
data_queue: Queue to read messages from
|
|
timeout: Queue get timeout in seconds
|
|
keepalive_interval: Seconds between keepalive messages
|
|
stop_check: Optional callable that returns True to stop the stream
|
|
|
|
Yields:
|
|
SSE formatted strings
|
|
"""
|
|
last_keepalive = time.time()
|
|
|
|
while True:
|
|
# Check if we should stop
|
|
if stop_check and stop_check():
|
|
break
|
|
|
|
try:
|
|
msg = data_queue.get(timeout=timeout)
|
|
last_keepalive = time.time()
|
|
yield format_sse(msg)
|
|
except queue.Empty:
|
|
# Send keepalive if enough time has passed
|
|
now = time.time()
|
|
if now - last_keepalive >= keepalive_interval:
|
|
yield format_sse({'type': 'keepalive'})
|
|
last_keepalive = now
|
|
|
|
|
|
def format_sse(data: dict[str, Any] | str, event: str | None = None) -> str:
|
|
"""
|
|
Format data as SSE message.
|
|
|
|
Args:
|
|
data: Data to send (will be JSON encoded if dict)
|
|
event: Optional event name
|
|
|
|
Returns:
|
|
SSE formatted string
|
|
"""
|
|
if isinstance(data, dict):
|
|
data = json.dumps(data)
|
|
|
|
lines = []
|
|
if event:
|
|
lines.append(f"event: {event}")
|
|
lines.append(f"data: {data}")
|
|
lines.append("")
|
|
lines.append("")
|
|
|
|
return '\n'.join(lines)
|
|
|
|
|
|
def clear_queue(q: queue.Queue) -> int:
|
|
"""
|
|
Clear all items from a queue.
|
|
|
|
Args:
|
|
q: Queue to clear
|
|
|
|
Returns:
|
|
Number of items cleared
|
|
"""
|
|
count = 0
|
|
while True:
|
|
try:
|
|
q.get_nowait()
|
|
count += 1
|
|
except queue.Empty:
|
|
break
|
|
return count
|