Browse Source

More robust On Air reconnect (#2818)

* on air: more robust connection retries

* on air: ensure we stay connected no matter what

* avoid cyclic import

---------

Co-authored-by: Falko Schindler <falko@zauberzeug.com>
Rodja Trappe 1 năm trước cách đây
mục cha
commit
9bbf846686
1 tập tin đã thay đổi với 28 bổ sung24 xóa
  1. 28 24
      nicegui/air.py

+ 28 - 24
nicegui/air.py

@@ -2,7 +2,6 @@ import asyncio
 import gzip
 import json
 import re
-import signal
 from dataclasses import dataclass
 from typing import Any, AsyncIterator, Dict, Optional
 from uuid import uuid4
@@ -14,6 +13,7 @@ import socketio.exceptions
 from . import background_tasks, core
 from .client import Client
 from .dataclasses import KWONLY_SLOTS
+from .elements.timer import Timer as timer
 from .logging import log
 
 RELAY_HOST = 'https://on-air.nicegui.io/'
@@ -36,6 +36,8 @@ class Air:
         self.streams: Dict[str, Stream] = {}
         self.remote_url: Optional[str] = None
 
+        timer(5, self.connect)  # ensure we stay connected
+
         @self.relay.on('http')
         async def _handle_http(data: Dict[str, Any]) -> Dict[str, Any]:
             headers: Dict[str, Any] = data['headers']
@@ -162,38 +164,40 @@ class Air:
 
     async def connect(self) -> None:
         """Connect to the NiceGUI On Air server."""
-        if self.connecting:
+        if self.connecting or self.relay.connected:
             return
         self.connecting = True
         backoff_time = 1
-        while True:
-            try:
-                if self.relay.connected:
-                    await self.relay.disconnect()
-                await self.relay.connect(
-                    f'{RELAY_HOST}?device_token={self.token}',
-                    socketio_path='/on_air/socket.io',
-                    transports=['websocket', 'polling'],  # favor websocket over polling
-                )
-                break
-            except socketio.exceptions.ConnectionError:
-                pass
-            except ValueError:  # NOTE this sometimes happens when the internal socketio client is not yet ready
-                await self.relay.disconnect()
-            except Exception:
-                log.exception('Could not connect to NiceGUI On Air server.')
-
-            await asyncio.sleep(backoff_time)
-            backoff_time = min(backoff_time * 2, 32)
-        self.connecting = False
+        try:
+            while True:
+                try:
+                    if self.relay.connected:
+                        await self.relay.disconnect()
+                    await self.relay.connect(
+                        f'{RELAY_HOST}?device_token={self.token}',
+                        socketio_path='/on_air/socket.io',
+                        transports=['websocket', 'polling'],  # favor websocket over polling
+                    )
+                    break
+                except socketio.exceptions.ConnectionError:
+                    pass
+                except ValueError:  # NOTE this sometimes happens when the internal socketio client is not yet ready
+                    pass
+                except Exception:
+                    log.exception('Could not connect to NiceGUI On Air server.')
+
+                await asyncio.sleep(backoff_time)
+                backoff_time = min(backoff_time * 2, 32)
+        finally:
+            self.connecting = False
 
     async def disconnect(self) -> None:
         """Disconnect from the NiceGUI On Air server."""
-        await self.relay.disconnect()
+        if self.relay.connected:
+            await self.relay.disconnect()
         for stream in self.streams.values():
             await stream.response.aclose()
         self.streams.clear()
-        await self.relay.disconnect()
 
     async def emit(self, message_type: str, data: Dict[str, Any], room: str) -> None:
         """Emit a message to the NiceGUI On Air server."""