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,16 @@ 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:path>" )
118
+ async def single_page_app_files (
119
+ request : request .Request , path : str = ""
120
+ ) -> response .HTTPResponse :
121
+ return await response .file (
122
+ str (CLIENT_BUILD_DIR / client_build_dir_path (path ))
123
+ )
124
+
116
125
blueprint .static ("/modules" , str (IDOM_WEB_MODULES_DIR .current ))
117
126
118
127
if options .redirect_root :
@@ -121,26 +130,44 @@ def _setup_common_routes(blueprint: Blueprint, options: Options) -> None:
121
130
def redirect_to_index (
122
131
request : request .Request ,
123
132
) -> response .HTTPResponse :
124
- return response .redirect (
125
- f"{ blueprint .url_prefix } /client/index.html?{ request .query_string } "
126
- )
133
+ if request .query_string :
134
+ path = f"{ blueprint .url_prefix } /app?{ request .query_string } "
135
+ else :
136
+ path = f"{ blueprint .url_prefix } /app"
137
+ return response .redirect (path )
127
138
128
139
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