diff --git a/api/ovkiosk/dav_file.py b/api/ovkiosk/dav_file.py index 1e80c2e..549f352 100644 --- a/api/ovkiosk/dav_file.py +++ b/api/ovkiosk/dav_file.py @@ -1,3 +1,5 @@ +import asyncio +import functools import logging from io import BytesIO from threading import Lock @@ -9,6 +11,20 @@ from webdav3.client import 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 + + class DavFile: __instances: Optional[list["DavFile"]] = None __scheduler = None @@ -25,12 +41,17 @@ class DavFile: if refresh: DavFile.__instances.append(self) - def download(self) -> None: + async def download(self) -> None: + + @run_in_executor + def download_inner() -> None: + self.__resource.write_to(self.__buffer) + _logger.info(f"updating {self.__resource}") with self.__lock: self.__buffer.seek(0) self.__buffer.truncate(0) - self.__resource.write_to(self.__buffer) + await download_inner() @classmethod def refresh(cls, refresh_interval: int = 60) -> None: @@ -42,9 +63,9 @@ class DavFile: ) return - def tick() -> None: + async def tick() -> None: for davfile in DavFile.__instances: - davfile.download() + await davfile.download() cls.__scheduler = AsyncIOScheduler() cls.__scheduler.start()