|
5 | 5 | import secrets
|
6 | 6 | import time
|
7 | 7 | import urllib.parse as urlparse
|
8 |
| -from typing import Any, Generator, Sequence |
| 8 | +from typing import Any, Generator, Iterable, Sequence |
9 | 9 | from urllib import request as urllib_request
|
10 | 10 | from urllib.error import URLError
|
11 | 11 |
|
@@ -268,10 +268,7 @@ def ui_stream() -> Response:
|
268 | 268 | ui_request = pb.UiRequest()
|
269 | 269 | ui_request.ParseFromString(base64.urlsafe_b64decode(data))
|
270 | 270 |
|
271 |
| - response = Response( |
272 |
| - stream_with_context(generate_data(ui_request)), |
273 |
| - content_type="text/event-stream", |
274 |
| - ) |
| 271 | + response = make_sse_response(stream_with_context(generate_data(ui_request))) |
275 | 272 | return response
|
276 | 273 |
|
277 | 274 | @flask_app.before_request
|
@@ -408,7 +405,7 @@ def generate():
|
408 | 405 | }
|
409 | 406 | yield f"data: {json.dumps(sse_data)}\n\n"
|
410 | 407 |
|
411 |
| - return Response(generate(), content_type="text/event-stream") |
| 408 | + return make_sse_response(generate()) |
412 | 409 |
|
413 | 410 | @flask_app.route("/__hot-reload__")
|
414 | 411 | def hot_reload() -> Response:
|
@@ -513,3 +510,16 @@ def sse_request(
|
513 | 510 | if decoded_line.startswith(SSE_DATA_PREFIX):
|
514 | 511 | event_data = json.loads(decoded_line[len(SSE_DATA_PREFIX) :])
|
515 | 512 | yield event_data
|
| 513 | + |
| 514 | + |
| 515 | +def make_sse_response( |
| 516 | + response: Iterable[bytes] | bytes | Iterable[str] | str | None = None, |
| 517 | +): |
| 518 | + return Response( |
| 519 | + response, |
| 520 | + content_type="text/event-stream", |
| 521 | + # "X-Accel-Buffering" impacts SSE responses due to response buffering (i.e. |
| 522 | + # individual events may get batched together instead of being sent right away). |
| 523 | + # See https://nginx.org/en/docs/http/ngx_http_proxy_module.html |
| 524 | + headers={"X-Accel-Buffering": "no"}, |
| 525 | + ) |
0 commit comments