1313import websockets
1414import asyncio
1515from collections .abc import Callable
16- from concurrent .futures import CancelledError , TimeoutError
16+ from concurrent .futures import CancelledError , TimeoutError , Future
1717
1818from arduino .app_internal .core .peripherals import BPPCodec
1919from arduino .app_utils import Logger
@@ -138,37 +138,33 @@ def security_mode(self) -> str:
138138
139139 def _open_camera (self ) -> None :
140140 """Start the WebSocket server."""
141- self ._server_thread = threading .Thread (target = self ._start_server_thread , daemon = True )
142- self ._server_thread .start ()
143-
144- # Wait for server to start
145- start_time = time .time ()
146- while time .time () - start_time < self .timeout :
147- if self ._server is not None :
148- self .logger .info (f"WebSocket camera server started on { self .url } , security: { self .security_mode } " )
149- return
150- time .sleep (0.1 )
141+ server_future = Future ()
151142
152- # Cleanup server thread if it failed to start in time
153- if self ._server_thread .is_alive ():
154- self ._server_thread .join (timeout = 1.0 )
155-
156- raise CameraOpenError (f"Failed to start WebSocket server on { self .url } " )
143+ self ._server_thread = threading .Thread (target = self ._start_server_thread , args = (server_future ,), daemon = True )
144+ self ._server_thread .start ()
157145
158- def _start_server_thread (self ) -> None :
146+ try :
147+ server_future .result (timeout = self .timeout )
148+ self .logger .info (f"WebSocket camera server available on { self .url } , security: { self .security_mode } " )
149+ except (PermissionError , Exception ) as e :
150+ if self ._server_thread .is_alive ():
151+ self ._server_thread .join (timeout = 1.0 )
152+ if isinstance (e , PermissionError ):
153+ raise CameraOpenError (f"Permission denied when attempting to bind WebSocket server on { self .url } " )
154+ raise
155+
156+ def _start_server_thread (self , future : Future ) -> None :
159157 """Run WebSocket server in its own thread with event loop."""
160158 try :
161159 self ._loop = asyncio .new_event_loop ()
162160 asyncio .set_event_loop (self ._loop )
163- self ._loop .run_until_complete (self ._start_server ())
164- except Exception as e :
165- self .logger .error (f"WebSocket server thread error: { e } " )
161+ self ._loop .run_until_complete (self ._start_server (future ))
166162 finally :
167163 if self ._loop and not self ._loop .is_closed ():
168164 self ._loop .close ()
169165 self ._loop = None
170166
171- async def _start_server (self ) -> None :
167+ async def _start_server (self , future : Future ) -> None :
172168 """Start the WebSocket server."""
173169 try :
174170 self ._server = await asyncio .wait_for (
@@ -191,14 +187,12 @@ async def _start_server(self) -> None:
191187 server_socket = list (self ._server .sockets )[0 ]
192188 self .port = server_socket .getsockname ()[1 ]
193189
190+ future .set_result (True )
191+
194192 await self ._server .wait_closed ()
195193
196- except TimeoutError as e :
197- self .logger .error (f"Failed to start WebSocket server within { self .timeout } s: { e } " )
198- raise
199194 except Exception as e :
200- self .logger .error (f"Failed to start WebSocket server: { e } " )
201- raise
195+ future .set_exception (e )
202196 finally :
203197 self ._server = None
204198
0 commit comments