1
0
Эх сурвалжийг харах

#519 automatically discover the port

Rodja Trappe 2 жил өмнө
parent
commit
ac2f1ace0d

+ 0 - 2
nicegui/globals.py

@@ -31,8 +31,6 @@ log: logging.Logger = logging.getLogger('nicegui')
 state: State = State.STOPPED
 ui_run_has_been_called: bool = False
 
-host: str
-port: int
 reload: bool
 title: str
 viewport: str

+ 2 - 1
nicegui/nicegui.py

@@ -1,4 +1,5 @@
 import asyncio
+import os
 import time
 import urllib.parse
 from pathlib import Path
@@ -71,7 +72,7 @@ def handle_startup(with_welcome_message: bool = True) -> None:
     background_tasks.create(prune_slot_stacks())
     globals.state = globals.State.STARTED
     if with_welcome_message:
-        print(f'NiceGUI ready to go on http://{globals.host}:{globals.port}')
+        print(f'NiceGUI ready to go on {os.environ["NICEGUI_URL"]}')
 
 
 @app.on_event('shutdown')

+ 4 - 2
nicegui/run.py

@@ -57,8 +57,6 @@ def run(*,
     :param kwargs: additional keyword arguments are passed to `uvicorn.run`
     '''
     globals.ui_run_has_been_called = True
-    globals.host = host
-    globals.port = port
     globals.reload = reload
     globals.title = title
     globals.viewport = viewport
@@ -75,9 +73,13 @@ def run(*,
         standalone = True
     if standalone:
         show = False
+        port = standalone_mode.find_open_port()
         width, height = (800, 600) if standalone is True else standalone
         standalone_mode.activate(f'http://localhost:{port}', title, width, height, fullscreen)
 
+    # NOTE we save the url in an environment variable so the subprocess started in reload mode can access it.
+    os.environ['NICEGUI_URL'] = f'http://localhost:{port}'
+
     if show:
         webbrowser.open(f'http://{host if host != "0.0.0.0" else "127.0.0.1"}:{port}/')
 

+ 17 - 0
nicegui/standalone_mode.py

@@ -1,6 +1,7 @@
 import multiprocessing
 import os
 import signal
+import socket
 import tempfile
 import time
 import warnings
@@ -30,3 +31,19 @@ def activate(url: str, title: str, width: int, height: int, fullscreen: bool) ->
     args = url, title, width, height, fullscreen, shutdown
     multiprocessing.Process(target=open_window, args=args, daemon=False).start()
     Thread(target=check_shutdown, daemon=True).start()
+
+
+def find_open_port(start_port: int = 8000, end_port: int = 8999) -> int:
+    '''Reliable finding of an open port in a given range.
+
+    It will actually try to open the port to ensure no firewall blocks it.
+    This is better than passing for port "0" to uvicorn for example.
+    '''
+    for port in range(start_port, end_port + 1):
+        try:
+            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
+                s.bind(('localhost', port))
+                return port
+        except OSError:
+            pass
+    raise OSError('No open port found')