Dev: add simple HTTPS static server (serves client/). Enabled in WT mode by default via STATIC=1; uses same cert/key as QUIC/WT
This commit is contained in:
17
run.py
17
run.py
@@ -25,13 +25,28 @@ async def run_quic():
|
|||||||
|
|
||||||
async def run_webtransport():
|
async def run_webtransport():
|
||||||
from server.webtransport_server import WebTransportServer
|
from server.webtransport_server import WebTransportServer
|
||||||
|
from server.static_server import start_https_static
|
||||||
cfg = ServerConfig()
|
cfg = ServerConfig()
|
||||||
host = os.environ.get("WT_HOST", os.environ.get("QUIC_HOST", "0.0.0.0"))
|
host = os.environ.get("WT_HOST", os.environ.get("QUIC_HOST", "0.0.0.0"))
|
||||||
port = int(os.environ.get("WT_PORT", os.environ.get("QUIC_PORT", "4433")))
|
port = int(os.environ.get("WT_PORT", os.environ.get("QUIC_PORT", "4433")))
|
||||||
cert = os.environ.get("WT_CERT") or os.environ["QUIC_CERT"]
|
cert = os.environ.get("WT_CERT") or os.environ["QUIC_CERT"]
|
||||||
key = os.environ.get("WT_KEY") or os.environ["QUIC_KEY"]
|
key = os.environ.get("WT_KEY") or os.environ["QUIC_KEY"]
|
||||||
|
# Optional static HTTPS server for client assets
|
||||||
|
static = os.environ.get("STATIC", "1")
|
||||||
|
static_host = os.environ.get("STATIC_HOST", host)
|
||||||
|
static_port = int(os.environ.get("STATIC_PORT", "8443"))
|
||||||
|
static_root = os.environ.get("STATIC_ROOT", "client")
|
||||||
|
httpd = None
|
||||||
|
if static == "1":
|
||||||
|
httpd, _t = start_https_static(static_host, static_port, cert, key, static_root)
|
||||||
|
print(f"HTTPS static server: https://{static_host}:{static_port}/ serving '{static_root}'")
|
||||||
server = GameServer(transport=WebTransportServer(host, port, cert, key, lambda d, p: server.on_datagram(d, p)), config=cfg)
|
server = GameServer(transport=WebTransportServer(host, port, cert, key, lambda d, p: server.on_datagram(d, p)), config=cfg)
|
||||||
await asyncio.gather(server.transport.run(), server.tick_loop())
|
print(f"WebTransport server: https://{host}:{port}/ (HTTP/3)")
|
||||||
|
try:
|
||||||
|
await asyncio.gather(server.transport.run(), server.tick_loop())
|
||||||
|
finally:
|
||||||
|
if httpd is not None:
|
||||||
|
httpd.shutdown()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
35
server/static_server.py
Normal file
35
server/static_server.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import ssl
|
||||||
|
import threading
|
||||||
|
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
|
||||||
|
class _Handler(SimpleHTTPRequestHandler):
|
||||||
|
# Allow passing a base directory at construction time
|
||||||
|
def __init__(self, *args, directory: str | None = None, **kwargs):
|
||||||
|
super().__init__(*args, directory=directory, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def start_https_static(host: str, port: int, certfile: str, keyfile: str, docroot: str) -> Tuple[ThreadingHTTPServer, threading.Thread]:
|
||||||
|
"""Start a simple HTTPS static file server in a background thread.
|
||||||
|
|
||||||
|
Returns the (httpd, thread). Caller is responsible for calling httpd.shutdown()
|
||||||
|
to stop the server on application exit.
|
||||||
|
"""
|
||||||
|
docroot_path = str(Path(docroot).resolve())
|
||||||
|
|
||||||
|
def handler(*args, **kwargs):
|
||||||
|
return _Handler(*args, directory=docroot_path, **kwargs)
|
||||||
|
|
||||||
|
httpd = ThreadingHTTPServer((host, port), handler)
|
||||||
|
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||||
|
ctx.load_cert_chain(certfile=certfile, keyfile=keyfile)
|
||||||
|
httpd.socket = ctx.wrap_socket(httpd.socket, server_side=True)
|
||||||
|
|
||||||
|
t = threading.Thread(target=httpd.serve_forever, name="https-static", daemon=True)
|
||||||
|
t.start()
|
||||||
|
return httpd, t
|
||||||
|
|
||||||
Reference in New Issue
Block a user