From c89d2f5e3e4259b2a866f658d01d6b8834346ae8 Mon Sep 17 00:00:00 2001 From: Darren Burns Date: Wed, 7 Aug 2024 17:01:46 +0100 Subject: [PATCH] Progress on delivering files --- examples/download_screenshot.py | 25 +++++++++++++++++++++++++ examples/serve_any.py | 2 +- pyproject.toml | 4 +++- requirements-dev.lock | 7 +++++++ src/textual_serve/app_service.py | 9 +-------- src/textual_serve/download_manager.py | 14 +++++++++----- 6 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 examples/download_screenshot.py diff --git a/examples/download_screenshot.py b/examples/download_screenshot.py new file mode 100644 index 0000000..2ae3c19 --- /dev/null +++ b/examples/download_screenshot.py @@ -0,0 +1,25 @@ +from textual import on +from textual.app import App, ComposeResult +from textual.binding import Binding +from textual.widgets import Button + + +class ScreenshotApp(App[None]): + BINDINGS = [Binding("s", "deliver_screenshot", "Screenshot")] + + def compose(self) -> ComposeResult: + yield Button("Hello, World!") + + @on(Button.Pressed) + def on_button_pressed(self) -> None: + self.action_deliver_screenshot() + + def action_deliver_screenshot(self) -> None: + print("Delivering screenshot action!") + filename = self.save_screenshot("screenshot.svg") + self.deliver_text(filename) + + +app = ScreenshotApp() +if __name__ == "__main__": + app.run() diff --git a/examples/serve_any.py b/examples/serve_any.py index 1ebdeaa..3481e50 100644 --- a/examples/serve_any.py +++ b/examples/serve_any.py @@ -3,4 +3,4 @@ from textual_serve.server import Server if __name__ == "__main__": server = Server(sys.argv[1]) - server.serve(debug=False) + server.serve(debug=True) diff --git a/pyproject.toml b/pyproject.toml index a755a7d..74d6f94 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,9 @@ build-backend = "hatchling.build" [tool.rye] managed = true dev-dependencies = [ - "httpx", # required to run the dictionary example + "httpx", + "textual-dev>=1.5.1", + # required to run the dictionary example ] [tool.hatch.metadata] diff --git a/requirements-dev.lock b/requirements-dev.lock index 6b21b99..8df2ab0 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -11,6 +11,7 @@ -e file:. aiohttp==3.9.5 # via aiohttp-jinja2 + # via textual-dev # via textual-serve aiohttp-jinja2==1.6 # via textual-serve @@ -25,6 +26,8 @@ attrs==23.2.0 certifi==2024.7.4 # via httpcore # via httpx +click==8.1.7 + # via textual-dev exceptiongroup==1.2.2 # via anyio frozenlist==1.4.1 @@ -55,6 +58,7 @@ mdit-py-plugins==0.4.1 mdurl==0.1.2 # via markdown-it-py msgpack==1.0.8 + # via textual-dev # via textual-serve msgpack-types==0.3.0 # via textual-serve @@ -70,11 +74,14 @@ sniffio==1.3.1 # via anyio # via httpx textual==0.75.1 + # via textual-dev # via textual-serve +textual-dev==1.5.1 typing-extensions==4.12.2 # via anyio # via rich # via textual + # via textual-dev uc-micro-py==1.0.3 # via linkify-it-py yarl==1.9.4 diff --git a/src/textual_serve/app_service.py b/src/textual_serve/app_service.py index f730939..559cae7 100644 --- a/src/textual_serve/app_service.py +++ b/src/textual_serve/app_service.py @@ -307,6 +307,7 @@ class AppService: ) await self.remote_write_str(payload) elif meta_type == "deliver_file_start": + log.info("deliver_file_start, %s", meta_data) try: # Record this delivery key as available for download. delivery_key = str(meta_data["key"]) @@ -325,14 +326,6 @@ class AppService: # to start the download. json_string = json.dumps(["deliver_file_start", delivery_key]) await self.remote_write_str(json_string) - # TODO - Request chunks in the handler for "/download/{key}" instead - # await self.send_meta( - # { - # "type": "deliver_chunk_request", - # "key": delivery_key, - # "size": 1024 * 64, # Request 64KB chunks - # } - # ) elif meta_type == "deliver_file_end": try: delivery_key = str(meta_data["key"]) diff --git a/src/textual_serve/download_manager.py b/src/textual_serve/download_manager.py index 9ed7538..ab71d83 100644 --- a/src/textual_serve/download_manager.py +++ b/src/textual_serve/download_manager.py @@ -1,10 +1,13 @@ +from __future__ import annotations + import asyncio from contextlib import suppress from dataclasses import dataclass, field import logging -from typing import AsyncGenerator +from typing import AsyncGenerator, TYPE_CHECKING -from textual_serve.app_service import AppService +if TYPE_CHECKING: + from textual_serve.app_service import AppService log = logging.getLogger("textual-serve") @@ -13,7 +16,7 @@ DOWNLOAD_TIMEOUT = 4 @dataclass class Download: - app_service: AppService + app_service: "AppService" delivery_key: str file_name: str open_method: str @@ -45,7 +48,7 @@ class DownloadManager: async def create_download( self, *, - app_service: AppService, + app_service: "AppService", delivery_key: str, file_name: str, open_method: str, @@ -93,6 +96,7 @@ class DownloadManager: """Download a file from the given app service. Args: + app_service: The app service to download from. delivery_key: The delivery key to download. """ @@ -129,7 +133,7 @@ class DownloadManager: download = self._active_downloads[delivery_key] await download.incoming_chunks.put(chunk) - async def _get_app_service(self, delivery_key: str) -> AppService: + async def _get_app_service(self, delivery_key: str) -> "AppService": """Get the app service that the given delivery key is linked to. Args: