Pārlūkot izejas kodu

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 gadu atpakaļ
vecāks
revīzija
9bbf846686
1 mainītis faili ar 28 papildinājumiem un 24 dzēšanām
  1. 28 24
      nicegui/air.py

+ 28 - 24
nicegui/air.py

@@ -2,7 +2,6 @@ import asyncio
 import gzip
 import gzip
 import json
 import json
 import re
 import re
-import signal
 from dataclasses import dataclass
 from dataclasses import dataclass
 from typing import Any, AsyncIterator, Dict, Optional
 from typing import Any, AsyncIterator, Dict, Optional
 from uuid import uuid4
 from uuid import uuid4
@@ -14,6 +13,7 @@ import socketio.exceptions
 from . import background_tasks, core
 from . import background_tasks, core
 from .client import Client
 from .client import Client
 from .dataclasses import KWONLY_SLOTS
 from .dataclasses import KWONLY_SLOTS
+from .elements.timer import Timer as timer
 from .logging import log
 from .logging import log
 
 
 RELAY_HOST = 'https://on-air.nicegui.io/'
 RELAY_HOST = 'https://on-air.nicegui.io/'
@@ -36,6 +36,8 @@ class Air:
         self.streams: Dict[str, Stream] = {}
         self.streams: Dict[str, Stream] = {}
         self.remote_url: Optional[str] = None
         self.remote_url: Optional[str] = None
 
 
+        timer(5, self.connect)  # ensure we stay connected
+
         @self.relay.on('http')
         @self.relay.on('http')
         async def _handle_http(data: Dict[str, Any]) -> Dict[str, Any]:
         async def _handle_http(data: Dict[str, Any]) -> Dict[str, Any]:
             headers: Dict[str, Any] = data['headers']
             headers: Dict[str, Any] = data['headers']
@@ -162,38 +164,40 @@ class Air:
 
 
     async def connect(self) -> None:
     async def connect(self) -> None:
         """Connect to the NiceGUI On Air server."""
         """Connect to the NiceGUI On Air server."""
-        if self.connecting:
+        if self.connecting or self.relay.connected:
             return
             return
         self.connecting = True
         self.connecting = True
         backoff_time = 1
         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:
     async def disconnect(self) -> None:
         """Disconnect from the NiceGUI On Air server."""
         """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():
         for stream in self.streams.values():
             await stream.response.aclose()
             await stream.response.aclose()
         self.streams.clear()
         self.streams.clear()
-        await self.relay.disconnect()
 
 
     async def emit(self, message_type: str, data: Dict[str, Any], room: str) -> None:
     async def emit(self, message_type: str, data: Dict[str, Any], room: str) -> None:
         """Emit a message to the NiceGUI On Air server."""
         """Emit a message to the NiceGUI On Air server."""