Skip to content

Commit e4ec2a5

Browse files
committed
Handling downloads cancelled on the browser
1 parent afbc239 commit e4ec2a5

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

src/textual_serve/app_service.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ async def start(self, width: int, height: int) -> None:
187187
async def stop(self) -> None:
188188
"""Stop the process and wait for it to complete."""
189189
if self._task is not None:
190+
await self._download_manager.cancel_app_downloads(
191+
app_service_id=self.app_service_id
192+
)
193+
190194
await self.send_meta({"type": "quit"})
191195
await self._task
192196
self._task = None

src/textual_serve/download_manager.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,8 @@ async def download(self, delivery_key: str) -> AsyncGenerator[bytes, None]:
116116
chunk = None
117117

118118
if not chunk:
119-
# Empty chunk - the app process has finished sending the file.
119+
# Empty chunk - the app process has finished sending the file
120+
# or the download has been cancelled.
120121
incoming_chunks.task_done()
121122
del self._active_downloads[delivery_key]
122123
break
@@ -131,7 +132,14 @@ async def chunk_received(self, delivery_key: str, chunk: bytes | str) -> None:
131132
delivery_key: The delivery key that the chunk was received for.
132133
chunk: The chunk that was received.
133134
"""
134-
download = self._active_downloads[delivery_key]
135+
136+
download = self._active_downloads.get(delivery_key)
137+
if not download:
138+
# The download may have been cancelled - e.g. the websocket
139+
# was closed before the download could complete.
140+
log.debug("Chunk received for cancelled download %r", delivery_key)
141+
return
142+
135143
if isinstance(chunk, str):
136144
chunk = chunk.encode(download.encoding or "utf-8")
137145
await download.incoming_chunks.put(chunk)
@@ -155,3 +163,13 @@ async def get_download_metadata(self, delivery_key: str) -> Download:
155163
delivery_key: The delivery key to get the metadata for.
156164
"""
157165
return self._active_downloads[delivery_key]
166+
167+
async def cancel_app_downloads(self, app_service_id: str) -> None:
168+
"""Cancel all downloads for the given app service.
169+
170+
Args:
171+
app_service_id: The app service ID to cancel downloads for.
172+
"""
173+
for download in self._active_downloads.values():
174+
if download.app_service.app_service_id == app_service_id:
175+
await download.incoming_chunks.put(None)

0 commit comments

Comments
 (0)