Fix: websocket error

This commit is contained in:
ziesorx 2025-09-12 20:25:18 +07:00
parent aacc5145d4
commit f617025e01
4 changed files with 207 additions and 5 deletions

View file

@ -100,6 +100,17 @@ class StreamManager:
self._subscriptions: Dict[str, StreamSubscription] = {}
self._lock = None
@property
def streams(self) -> Dict[str, StreamInfo]:
"""Public access to streams dictionary."""
return self._streams
@property
def streams_lock(self):
"""Public access to streams lock."""
self._ensure_thread_safety()
return self._lock
def _ensure_thread_safety(self):
"""Initialize thread safety if not already done."""
if self._lock is None:
@ -525,6 +536,141 @@ class StreamManager:
self._subscriptions.clear()
logger.info("All streams shut down successfully")
# ===== WEBSOCKET HANDLER COMPATIBILITY METHODS =====
# These methods provide compatibility with the WebSocketHandler interface
def get_active_streams(self) -> Dict[str, Any]:
"""
Get all active streams for WebSocket handler compatibility.
Returns:
Dictionary of active streams with their information
"""
self._ensure_thread_safety()
with self._lock:
active_streams = {}
for camera_id, stream_info in self._streams.items():
if stream_info.thread and stream_info.thread.is_alive():
active_streams[camera_id] = {
'camera_id': camera_id,
'status': 'active',
'stream_type': stream_info.stream_type,
'subscribers': len([sub_id for sub_id, sub in self._subscriptions.items()
if sub.camera_id == camera_id]),
'last_frame_time': getattr(stream_info, 'last_frame_time', None),
'error_count': getattr(stream_info, 'error_count', 0)
}
return active_streams
def get_latest_frame(self, camera_id: str) -> Optional[Any]:
"""
Get the latest frame for a camera for WebSocket handler compatibility.
Args:
camera_id: Camera identifier
Returns:
Latest frame data or None if not available
"""
self._ensure_thread_safety()
with self._lock:
stream_info = self._streams.get(camera_id)
if stream_info and hasattr(stream_info, 'latest_frame'):
return stream_info.latest_frame
return None
async def cleanup_all_streams(self) -> None:
"""
Cleanup all streams asynchronously for WebSocket handler compatibility.
"""
# This is an async wrapper around shutdown_all for compatibility
self.shutdown_all()
async def start_stream(self, camera_id: str, payload: Dict[str, Any]) -> bool:
"""
Start a stream for WebSocket handler compatibility.
Args:
camera_id: Camera identifier
payload: Stream configuration payload
Returns:
True if stream started successfully, False otherwise
"""
try:
# Create a subscription ID for this stream
subscription_id = f"ws_{camera_id}_{int(time.time() * 1000)}"
# Extract stream parameters from payload
rtsp_url = payload.get('rtspUrl')
snapshot_url = payload.get('snapshotUrl')
snapshot_interval = payload.get('snapshotInterval', 5000)
# Create subscription based on available URL type
if rtsp_url:
success = self.create_subscription(
subscription_id=subscription_id,
camera_id=camera_id,
rtsp_url=rtsp_url
)
elif snapshot_url:
success = self.create_subscription(
subscription_id=subscription_id,
camera_id=camera_id,
snapshot_url=snapshot_url,
snapshot_interval_ms=snapshot_interval
)
else:
logger.error(f"No valid stream URL provided for camera {camera_id}")
return False
if success:
logger.info(f"Started stream for camera {camera_id} with subscription {subscription_id}")
return True
else:
logger.error(f"Failed to start stream for camera {camera_id}")
return False
except Exception as e:
logger.error(f"Error starting stream for camera {camera_id}: {e}")
return False
async def stop_stream(self, camera_id: str) -> bool:
"""
Stop a stream for WebSocket handler compatibility.
Args:
camera_id: Camera identifier
Returns:
True if stream stopped successfully, False otherwise
"""
try:
# Find and remove subscriptions for this camera
subscriptions_to_remove = [
sub_id for sub_id, sub in self._subscriptions.items()
if sub.camera_id == camera_id
]
success = True
for sub_id in subscriptions_to_remove:
if not self.remove_subscription(sub_id):
success = False
if success and subscriptions_to_remove:
logger.info(f"Stopped stream for camera {camera_id}")
return True
elif not subscriptions_to_remove:
logger.warning(f"No active subscriptions found for camera {camera_id}")
return True
else:
logger.error(f"Failed to stop some subscriptions for camera {camera_id}")
return False
except Exception as e:
logger.error(f"Error stopping stream for camera {camera_id}: {e}")
return False
# Global stream manager instance