Skip to content

Commit 2546cfa

Browse files
committed
Unfinished component dispatcher
1 parent 252489e commit 2546cfa

File tree

1 file changed

+54
-1
lines changed
  • src/py/reactpy/reactpy/backend

1 file changed

+54
-1
lines changed

src/py/reactpy/reactpy/backend/asgi.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
1+
import asyncio
12
import logging
23
import mimetypes
34
import os
45
import re
6+
import urllib.parse
7+
from collections.abc import Sequence
58
from pathlib import Path
6-
from typing import Sequence
79

810
import aiofiles
11+
import orjson
912
from asgiref.compatibility import guarantee_single_callable
1013

1114
from reactpy.backend._common import (
1215
CLIENT_BUILD_DIR,
1316
traversal_safe_path,
1417
vdom_head_elements_to_html,
1518
)
19+
from reactpy.backend.hooks import ConnectionContext
1620
from reactpy.backend.mimetypes import DEFAULT_MIME_TYPES
21+
from reactpy.backend.types import Connection, Location
1722
from reactpy.config import REACTPY_WEB_MODULES_DIR
23+
from reactpy.core.layout import Layout
24+
from reactpy.core.serve import serve_layout
1825
from reactpy.core.types import VdomDict
1926

2027
DEFAULT_STATIC_PATH = f"{os.getcwd()}/static"
@@ -89,6 +96,43 @@ async def __call__(self, scope, receive, send) -> None:
8996
async def component_dispatch_app(self, scope, receive, send) -> None:
9097
"""The ASGI application for ReactPy Python components."""
9198

99+
self._reactpy_recv_queue: asyncio.Queue = asyncio.Queue()
100+
parsed_url = urllib.parse.urlparse(scope["path"])
101+
102+
# TODO: Get the component via URL attached to template tag
103+
parsed_url_query = urllib.parse.parse_qs(parsed_url.query)
104+
component = lambda _: None
105+
106+
while True:
107+
event = await receive()
108+
109+
if event["type"] == "websocket.connect":
110+
await send({"type": "websocket.accept"})
111+
112+
await serve_layout(
113+
Layout(
114+
ConnectionContext(
115+
component(),
116+
value=Connection(
117+
scope=scope,
118+
location=Location(
119+
parsed_url.path,
120+
f"?{parsed_url.query}" if parsed_url.query else "",
121+
),
122+
carrier=self,
123+
),
124+
)
125+
),
126+
send_json(send),
127+
self._reactpy_recv_queue.get,
128+
)
129+
130+
if event["type"] == "websocket.disconnect":
131+
break
132+
133+
if event["type"] == "websocket.receive":
134+
await self._reactpy_recv_queue.put(orjson.loads(event["text"]))
135+
92136
async def js_modules_app(self, scope, receive, send) -> None:
93137
"""The ASGI application for ReactPy web modules."""
94138

@@ -166,6 +210,15 @@ async def index_html_app(self, scope, receive, send) -> None:
166210
)
167211

168212

213+
def send_json(send) -> None:
214+
"""Use orjson to send JSON over an ASGI websocket."""
215+
216+
async def _send_json(value) -> None:
217+
await send({"type": "websocket.send", "text": orjson.dumps(value)})
218+
219+
return _send_json
220+
221+
169222
async def simple_response(
170223
send,
171224
code: int,

0 commit comments

Comments
 (0)