Skip to content

Commit 22774ae

Browse files
committed
Initial sketch of {websockets} 14.0 support
Some types changed, and process_request is totally different. However, this still leaves a spurious, scary-looking error when using the Run App button from the current version of the Shiny VS Code extension.
1 parent 8d0f72e commit 22774ae

File tree

1 file changed

+27
-7
lines changed

1 file changed

+27
-7
lines changed

shiny/_autoreload.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def reload_end():
7070

7171
async def _() -> None:
7272
options = {
73-
"extra_headers": {
73+
"additional_headers": {
7474
"Shiny-Autoreload-Secret": os.getenv("SHINY_AUTORELOAD_SECRET", ""),
7575
}
7676
}
@@ -186,6 +186,8 @@ async def _coro_main(
186186
port: int, app_url: str, secret: str, launch_browser: bool
187187
) -> None:
188188
import websockets
189+
import websockets.asyncio.server
190+
import websockets.http11
189191

190192
reload_now: asyncio.Event = asyncio.Event()
191193

@@ -198,18 +200,22 @@ def nudge():
198200
reload_now.set()
199201
reload_now.clear()
200202

201-
async def reload_server(conn: websockets.server.WebSocketServerProtocol):
203+
async def reload_server(conn: websockets.asyncio.server.ServerConnection):
202204
try:
203-
if conn.path == "/autoreload":
205+
if conn.request is None:
206+
raise RuntimeError(
207+
"Autoreload server received a connection with no request"
208+
)
209+
elif conn.request.path == "/autoreload":
204210
# The client wants to be notified when the app has reloaded. The client
205211
# in this case is the web browser, specifically shiny-autoreload.js.
206212
while True:
207213
await reload_now.wait()
208214
await conn.send("autoreload")
209-
elif conn.path == "/notify":
215+
elif conn.request.path == "/notify":
210216
# The client is notifying us that the app has reloaded. The client in
211217
# this case is the uvicorn worker process (see reload_end(), above).
212-
req_secret = conn.request_headers.get("Shiny-Autoreload-Secret", "")
218+
req_secret = conn.request.headers.get("Shiny-Autoreload-Secret", "")
213219
if req_secret != secret:
214220
# The client couldn't prove that they were from a child process
215221
return
@@ -224,7 +230,7 @@ async def reload_server(conn: websockets.server.WebSocketServerProtocol):
224230
# about only WebSockets being supported. This is not an academic problem as the
225231
# VSCode extension used in RSW sniffs out ports that are being listened on, which
226232
# leads to confusion if all you get is an error.
227-
async def process_request(
233+
async def process_request_legacy(
228234
path: str, request_headers: websockets.datastructures.Headers
229235
) -> Optional[tuple[http.HTTPStatus, websockets.datastructures.HeadersLike, bytes]]:
230236
# If there's no Upgrade header, it's not a WebSocket request.
@@ -236,8 +242,22 @@ async def process_request(
236242
await asyncio.sleep(1)
237243
return (http.HTTPStatus.MOVED_PERMANENTLY, [("Location", app_url)], b"")
238244

245+
async def process_request_new(
246+
connection: websockets.asyncio.server.ServerConnection,
247+
request: websockets.http11.Request,
248+
) -> websockets.http11.Response | None:
249+
if request.headers.get("Upgrade") is None:
250+
return websockets.http11.Response(
251+
status_code=http.HTTPStatus.MOVED_PERMANENTLY,
252+
reason_phrase="Moved Permanently",
253+
headers=websockets.Headers(Location=app_url),
254+
body=None,
255+
)
256+
else:
257+
return None
258+
239259
async with websockets.serve(
240-
reload_server, "127.0.0.1", port, process_request=process_request
260+
reload_server, "127.0.0.1", port, process_request=process_request_new
241261
):
242262
await asyncio.Future() # wait forever
243263

0 commit comments

Comments
 (0)