From 50341152811fb39b3d9b10b9328989d4da049f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn-Michael=20Miehe?= <40151420+ldericher@users.noreply.github.com> Date: Sat, 3 Sep 2022 15:40:46 +0000 Subject: [PATCH] wip/experiments --- api/ovdashboard_api/__init__.py | 19 +++++++++++++++++++ api/ovdashboard_api/dav_file.py | 23 ++--------------------- api/ovdashboard_api/routers/_common.py | 26 ++++++++++++++++---------- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/api/ovdashboard_api/__init__.py b/api/ovdashboard_api/__init__.py index 66b70fc..4fa6c6e 100644 --- a/api/ovdashboard_api/__init__.py +++ b/api/ovdashboard_api/__init__.py @@ -1,3 +1,4 @@ +import asyncio import functools from typing import Any @@ -13,11 +14,29 @@ _WEBDAV_CLIENT = WebDAVclient.Client({ }) +def run_in_executor(f): + """ + Decorator to make blocking function call asyncio compatible + https://stackoverflow.com/questions/41063331/how-to-use-asyncio-with-existing-blocking-library/ + """ + + @functools.wraps(f) + def inner(*args, **kwargs): + loop = asyncio.get_running_loop() + return loop.run_in_executor( + None, + functools.partial(f, *args, **kwargs), + ) + + return inner + + @functools.lru_cache def webdav_resource(remote_path: Any) -> WebDAVclient.Resource: return _WEBDAV_CLIENT.resource(remote_path) +@run_in_executor def webdav_list(remote_path: str) -> list: return _WEBDAV_CLIENT.list(remote_path) diff --git a/api/ovdashboard_api/dav_file.py b/api/ovdashboard_api/dav_file.py index ac966ed..5a07fe7 100644 --- a/api/ovdashboard_api/dav_file.py +++ b/api/ovdashboard_api/dav_file.py @@ -1,5 +1,3 @@ -import asyncio -import functools import logging import time from io import BytesIO @@ -8,28 +6,11 @@ from typing import Any, Optional from async_lru import alru_cache from webdav3.client import Resource -from . import webdav_resource +from . import run_in_executor, webdav_resource _logger = logging.getLogger(__name__) -def _run_in_executor(f): - """ - Decorator to make blocking function call asyncio compatible - https://stackoverflow.com/questions/41063331/how-to-use-asyncio-with-existing-blocking-library/ - """ - - @functools.wraps(f) - def inner(*args, **kwargs): - loop = asyncio.get_running_loop() - return loop.run_in_executor( - None, - functools.partial(f, *args, **kwargs), - ) - - return inner - - def _get_ttl_hash(seconds: int = 20) -> int: """ Return the same value within `seconds` time period @@ -45,7 +26,7 @@ async def _get_buffer( ) -> BytesIO: del ttl_hash - @_run_in_executor + @run_in_executor def buffer_inner(resource: Resource) -> BytesIO: _logger.info(f"updating {resource}") print(f"updating {resource}") diff --git a/api/ovdashboard_api/routers/_common.py b/api/ovdashboard_api/routers/_common.py index 63f1a54..9c36bd1 100644 --- a/api/ovdashboard_api/routers/_common.py +++ b/api/ovdashboard_api/routers/_common.py @@ -1,6 +1,6 @@ import re from dataclasses import dataclass -from typing import Iterator +from typing import Iterator, Protocol from fastapi import HTTPException, status from webdav3.exceptions import RemoteResourceNotFound @@ -9,14 +9,20 @@ from .. import webdav_list from ..dav_file import DavFile +@dataclass(frozen=True) +class NameLister(Protocol): + def __call__(self) -> Iterator[str]: + ... + + @dataclass(frozen=True) class FileNameLister: remote_path: str re: re.Pattern[str] - def __call__(self) -> Iterator[str]: + async def __call__(self) -> Iterator[str]: try: - file_names = webdav_list(self.remote_path) + file_names = await webdav_list(self.remote_path) return ( name @@ -29,20 +35,20 @@ class FileNameLister: @dataclass(frozen=True) -class FilePrefixFinder: - lister: FileNameLister +class PrefixFinder: + lister: NameLister - def __call__(self, prefix: str) -> Iterator[str]: + async def __call__(self, prefix: str) -> Iterator[str]: return ( file_name - for file_name in self.lister() + for file_name in (await self.lister()) if file_name.lower().startswith(prefix.lower()) ) @dataclass(frozen=True) class FilePrefixLoader: - finder: FilePrefixFinder + finder: PrefixFinder @property def responses(self) -> dict: @@ -62,8 +68,8 @@ class FilePrefixLoader: }, } - def __call__(self, prefix: str) -> DavFile: - file_names = list(self.finder(prefix)) + async def __call__(self, prefix: str) -> DavFile: + file_names = list(await self.finder(prefix)) if not (file_names): raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)