25
25
from idom .core .types import RootComponentConstructor
26
26
27
27
from ._asgi import serve_development_asgi
28
- from .utils import CLIENT_BUILD_DIR
28
+ from .utils import CLIENT_BUILD_DIR , client_build_dir_path
29
29
30
30
31
31
logger = logging .getLogger (__name__ )
32
32
33
- RequestContext : type [Context [request .Request | None ]] = create_context (
33
+ ConnectionContext : type [Context [request .Request | None ]] = create_context (
34
34
None , "RequestContext"
35
35
)
36
36
@@ -65,9 +65,9 @@ async def serve_development_app(
65
65
await serve_development_asgi (app , host , port , started )
66
66
67
67
68
- def use_request () -> request . Request :
68
+ def use_connection () -> Connection :
69
69
"""Get the current ``Request``"""
70
- request = use_context (RequestContext )
70
+ request = use_context (ConnectionContext )
71
71
if request is None :
72
72
raise RuntimeError ( # pragma: no cover
73
73
"No request. Are you running with a Sanic server?"
@@ -77,7 +77,7 @@ def use_request() -> request.Request:
77
77
78
78
def use_scope () -> ASGIScope :
79
79
"""Get the current ASGI scope"""
80
- app = use_request () .app
80
+ app = use_connection (). request .app
81
81
try :
82
82
asgi_app = app ._asgi_app
83
83
except AttributeError : # pragma: no cover
@@ -112,7 +112,18 @@ def _setup_common_routes(blueprint: Blueprint, options: Options) -> None:
112
112
CORS (blueprint , ** cors_params )
113
113
114
114
if options .serve_static_files :
115
- blueprint .static ("/app" , str (CLIENT_BUILD_DIR ))
115
+
116
+ @blueprint .route ("/app" )
117
+ @blueprint .route ("/app/<path>" )
118
+ async def single_page_app_files (
119
+ request : request .Request , path : str
120
+ ) -> response .HTTPResponse :
121
+ try :
122
+ path = client_build_dir_path (path )
123
+ except ValueError :
124
+ return response .HTTPResponse ("File not found" , status = 404 )
125
+ return await response .file (str (CLIENT_BUILD_DIR / path ))
126
+
116
127
blueprint .static ("/modules" , str (IDOM_WEB_MODULES_DIR .current ))
117
128
118
129
if options .redirect_root :
@@ -129,18 +140,34 @@ def redirect_to_index(
129
140
def _setup_single_view_dispatcher_route (
130
141
blueprint : Blueprint , constructor : RootComponentConstructor
131
142
) -> None :
132
- @blueprint .websocket ("/app<path:path>/_stream" ) # type: ignore
143
+ @blueprint .websocket ("/app/_stream" )
144
+ @blueprint .websocket ("/app/<path:path>/_stream" ) # type: ignore
133
145
async def model_stream (
134
- request : request .Request , socket : WebSocketCommonProtocol
146
+ request : request .Request , socket : WebSocketCommonProtocol , path : str = ""
135
147
) -> None :
136
148
send , recv = _make_send_recv_callbacks (socket )
149
+ conn = Connection (request , socket , path )
137
150
await serve_json_patch (
138
- Layout (RequestContext (constructor (), value = request )),
151
+ Layout (ConnectionContext (constructor (), value = conn )),
139
152
send ,
140
153
recv ,
141
154
)
142
155
143
156
157
+ @dataclass
158
+ class Connection :
159
+ """A simple wrapper for holding"""
160
+
161
+ request : request .Request
162
+ """The current request object"""
163
+
164
+ socket : WebSocketCommonProtocol
165
+ """A handle to the current websocket"""
166
+
167
+ path : str
168
+ """The current path being served"""
169
+
170
+
144
171
def _make_send_recv_callbacks (
145
172
socket : WebSocketCommonProtocol ,
146
173
) -> Tuple [SendCoroutine , RecvCoroutine ]:
0 commit comments