Skip to content

Commit e6f60ab

Browse files
committed
feat: use local static when CND is not available
1 parent f137c41 commit e6f60ab

File tree

7 files changed

+69
-29
lines changed

7 files changed

+69
-29
lines changed

pywebio/platform/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,8 @@
170170
from . import tornado_http
171171
except Exception:
172172
pass
173+
174+
try:
175+
from . import aiohttp
176+
except Exception:
177+
pass

pywebio/platform/aiohttp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ async def wshandle(request: web.Request):
6161

6262
app_name = request.query.getone('app', 'index')
6363
app = applications.get(app_name) or applications['index']
64-
html = render_page(app, protocol='ws', cdn=cdn)
64+
no_cdn = cdn is True and request.query.getone('_pywebio_cdn', '') == 'false'
65+
html = render_page(app, protocol='ws', cdn=False if no_cdn else cdn)
6566
return web.Response(body=html, content_type='text/html')
6667

6768
ws = web.WebSocketResponse(**websocket_settings)

pywebio/platform/fastapi.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from .remote_access import start_remote_access_service
1616
from .tornado import open_webbrowser_on_server_started
1717
from .page import make_applications, render_page
18-
from .utils import cdn_validation, OriginChecker, deserialize_binary_event
18+
from .utils import cdn_validation, OriginChecker, deserialize_binary_event, print_listen_address
1919
from ..session import CoroutineBasedSession, ThreadBasedSession, register_session_implement_for_target, Session
2020
from ..session.base import get_session_info_from_headers
2121
from ..utils import get_free_port, STATIC_PATH, iscoroutinefunction, isgeneratorfunction, strip_space
@@ -41,7 +41,8 @@ async def http_endpoint(request: Request):
4141

4242
app_name = request.query_params.get('app', 'index')
4343
app = applications.get(app_name) or applications['index']
44-
html = render_page(app, protocol='ws', cdn=cdn)
44+
no_cdn = cdn is True and request.query_params.get('_pywebio_cdn', '') == 'false'
45+
html = render_page(app, protocol='ws', cdn=False if no_cdn else cdn)
4546
return HTMLResponse(content=html)
4647

4748
async def websocket_endpoint(websocket: WebSocket):
@@ -167,6 +168,8 @@ def start_server(applications, port=0, host='', cdn=True,
167168
if port == 0:
168169
port = get_free_port()
169170

171+
print_listen_address(host, port)
172+
170173
if remote_access:
171174
start_remote_access_service(local_port=port)
172175

pywebio/platform/httpbased.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ async def handle_request_async(self, context: HttpContext):
193193

194194
return context.get_response()
195195

196+
def get_cdn(self, context):
197+
if self.cdn is True and context.request_url_parameter('_pywebio_cdn', '') == 'false':
198+
return False
199+
return self.cdn
200+
196201
@contextmanager
197202
def handle_request_context(self, context: HttpContext):
198203
"""called when every http request"""
@@ -220,7 +225,7 @@ def handle_request_context(self, context: HttpContext):
220225
# 对首页HTML的请求
221226
if 'webio-session-id' not in request_headers:
222227
app = self.app_loader(context)
223-
html = render_page(app, protocol='http', cdn=self.cdn)
228+
html = render_page(app, protocol='http', cdn=self.get_cdn(context))
224229
context.set_content(html)
225230
return context.get_response()
226231

pywebio/platform/path_deploy.py

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from ..session import register_session_implement, CoroutineBasedSession, ThreadBasedSession, Session
1818
from ..utils import get_free_port, STATIC_PATH, parse_file_size
1919

20+
LOCAL_STATIC_URL = '/_pywebio_static'
2021

2122
def filename_ok(f):
2223
return not f.startswith(('.', '_'))
@@ -183,7 +184,7 @@ def get_app_from_path(request_path, base, index, reload=False):
183184
return 'error', 404
184185

185186

186-
def _path_deploy(base, port=0, host='', static_dir=None, cdn=True, max_payload_size=2 ** 20 * 200,
187+
def _path_deploy(base, port=0, host='', static_dir=None, max_payload_size=2 ** 20 * 200,
187188
**tornado_app_settings):
188189
if not host:
189190
host = '0.0.0.0'
@@ -195,19 +196,15 @@ def _path_deploy(base, port=0, host='', static_dir=None, cdn=True, max_payload_s
195196

196197
abs_base = os.path.normpath(os.path.abspath(base))
197198

198-
cdn = cdn_validation(cdn, 'warn', stacklevel=4) # if CDN is not available, warn user and disable CDN
199-
cdn_url = '/_pywebio_static/' if not cdn else cdn
200-
201199
register_session_implement(CoroutineBasedSession)
202200
register_session_implement(ThreadBasedSession)
203201

204-
RequestHandler = yield cdn_url, abs_base
202+
RequestHandler = yield abs_base
205203

206204
handlers = []
207205
if static_dir is not None:
208206
handlers.append((r"/static/(.*)", StaticFileHandler, {"path": static_dir}))
209-
if not cdn:
210-
handlers.append((r"/_pywebio_static/(.*)", StaticFileHandler, {"path": STATIC_PATH}))
207+
handlers.append((LOCAL_STATIC_URL+r"/(.*)", StaticFileHandler, {"path": STATIC_PATH}))
211208
handlers.append((r"/.*", RequestHandler))
212209

213210
print_listen_address(host, port)
@@ -254,20 +251,27 @@ def path_deploy(base, port=0, host='',
254251
tornado_app_settings.setdefault('websocket_max_message_size', max_payload_size) # Backward compatible
255252
tornado_app_settings['websocket_max_message_size'] = parse_file_size(tornado_app_settings['websocket_max_message_size'])
256253
gen = _path_deploy(base, port=port, host=host,
257-
static_dir=static_dir,
258-
cdn=cdn, debug=debug,
254+
static_dir=static_dir, debug=debug,
259255
max_payload_size=max_payload_size,
260256
**tornado_app_settings)
261257

262-
cdn_url, abs_base = next(gen)
258+
cdn = cdn_validation(cdn, 'warn', stacklevel=3) # if CDN is not available, warn user and disable CDN
259+
260+
abs_base = next(gen)
263261

264262
index_func = {True: partial(default_index_page, base=abs_base), False: lambda p: '403 Forbidden'}.get(index, index)
265263

266-
Handler = webio_handler(lambda: None, cdn_url, allowed_origins=allowed_origins,
264+
Handler = webio_handler(lambda: None, cdn=cdn, allowed_origins=allowed_origins,
267265
check_origin=check_origin, reconnect_timeout=reconnect_timeout)
268266

269267
class WSHandler(Handler):
270268

269+
def get_cdn(self):
270+
_cdn = super().get_cdn()
271+
if not _cdn:
272+
return LOCAL_STATIC_URL
273+
return _cdn
274+
271275
def get_app(self):
272276
reload = self.get_query_argument('reload', None) is not None
273277
type, res = get_app_from_path(self.request.path, abs_base, index=index_func, reload=reload)
@@ -307,12 +311,13 @@ def path_deploy_http(base, port=0, host='',
307311
page.MAX_PAYLOAD_SIZE = max_payload_size = parse_file_size(max_payload_size)
308312

309313
gen = _path_deploy(base, port=port, host=host,
310-
static_dir=static_dir,
311-
cdn=cdn, debug=debug,
314+
static_dir=static_dir, debug=debug,
312315
max_payload_size=max_payload_size,
313316
**tornado_app_settings)
314317

315-
cdn_url, abs_base = next(gen)
318+
cdn = cdn_validation(cdn, 'warn', stacklevel=3) # if CDN is not available, warn user and disable CDN
319+
320+
abs_base = next(gen)
316321
index_func = {True: partial(default_index_page, base=abs_base), False: lambda p: '403 Forbidden'}.get(index, index)
317322

318323
def get_app(context: TornadoHttpContext):
@@ -327,11 +332,18 @@ def get_app(context: TornadoHttpContext):
327332
app_name = context.request_url_parameter('app', 'index')
328333
return res.get(app_name) or res['index']
329334

330-
handler = HttpHandler(app_loader=get_app, cdn=cdn_url,
331-
session_expire_seconds=session_expire_seconds,
332-
session_cleanup_interval=session_cleanup_interval,
333-
allowed_origins=allowed_origins,
334-
check_origin=check_origin)
335+
class HttpPathDeployHandler(HttpHandler):
336+
def get_cdn(self, context):
337+
_cdn = super().get_cdn(context)
338+
if not _cdn:
339+
return LOCAL_STATIC_URL
340+
return _cdn
341+
342+
handler = HttpPathDeployHandler(app_loader=get_app, cdn=cdn,
343+
session_expire_seconds=session_expire_seconds,
344+
session_cleanup_interval=session_cleanup_interval,
345+
allowed_origins=allowed_origins,
346+
check_origin=check_origin)
335347

336348
class ReqHandler(tornado.web.RequestHandler):
337349
def options(self):

pywebio/platform/tornado.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ def get_app(self):
9494
app = applications.get(app_name) or applications['index']
9595
return app
9696

97+
def get_cdn(self):
98+
if cdn is True and self.get_query_argument('_pywebio_cdn', '') == 'false':
99+
return False
100+
return cdn
101+
97102
async def get(self, *args, **kwargs) -> None:
98103
# It's a simple http GET request
99104
if self.request.headers.get("Upgrade", "").lower() != "websocket":
@@ -103,7 +108,8 @@ async def get(self, *args, **kwargs) -> None:
103108
return self.write('')
104109

105110
app = self.get_app()
106-
html = render_page(app, protocol='ws', cdn=cdn)
111+
112+
html = render_page(app, protocol='ws', cdn=self.get_cdn())
107113
return self.write(html)
108114
else:
109115
await super().get()

pywebio/platform/tpl/index.html

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,6 @@
4141
</div>
4242
</div>
4343

44-
45-
<footer class="footer">
46-
Powered by <a href="https://www.pyweb.io/" target="_blank">PyWebIO</a>
47-
</footer>
48-
4944
<script src="{{ base_url }}js/mustache.min.js"></script> <!--template system-->
5045
<script src="{{ base_url }}js/codemirror.min.js"></script> <!--code textarea editor-->
5146
<script src="{{ base_url }}codemirror/addons.js"></script> <!--codemirror addons: matchbrackets, python mode, active line, auto refresh, mode/meta and loadmode -->
@@ -70,6 +65,15 @@
7065
<script src="{{ base_url }}js/require.min.js"></script> <!-- JS module loader -->
7166

7267
<script>
68+
if (window.WebIO === undefined) { // resource load failed
69+
let url = new URL(window.location.href);
70+
if (url.searchParams.get('_pywebio_cdn') === 'false') {
71+
alert("Failed to load resource")
72+
} else {
73+
url.searchParams.set('_pywebio_cdn', 'false');
74+
window.location.href = url.href;
75+
}
76+
}
7377

7478
require.config({
7579
paths: {
@@ -101,5 +105,9 @@
101105
{% if js_code %}
102106
<script>{% raw js_code %}</script>
103107
{% end %}
108+
109+
<footer class="footer">
110+
Powered by <a href="https://www.pyweb.io/" target="_blank">PyWebIO</a>
111+
</footer>
104112
</body>
105113
</html>

0 commit comments

Comments
 (0)