Fix: websocket error
This commit is contained in:
parent
aacc5145d4
commit
f617025e01
4 changed files with 207 additions and 5 deletions
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue