ovdashboard/api/ovdashboard_api/dav_file.py

98 lines
2 KiB
Python

"""
Definition of an asyncio compatible WebDAV file.
Caches files using `timed_alru_cache`.
"""
from dataclasses import dataclass
from io import BytesIO
from logging import getLogger
from typing import Any
from webdav3.client import Resource
from .async_helpers import get_ttl_hash, run_in_executor, timed_alru_cache
from .dav_common import webdav_resource
from .settings import SETTINGS
_logger = getLogger(__name__)
@timed_alru_cache(maxsize=SETTINGS.cache_size)
async def _get_buffer(
remote_path: Any,
) -> BytesIO:
"""
Download file contents into a new `BytesIO` object.
"""
@run_in_executor
def _inner() -> BytesIO:
_logger.info(f"downloading {remote_path!r} ...")
resource = webdav_resource(remote_path)
buffer = BytesIO()
resource.write_to(buffer)
return buffer
return await _inner()
@dataclass(frozen=True)
class DavFile:
"""
Object representation of a WebDAV file.
"""
remote_path: str
@property
def resource(self) -> Resource:
"""
WebDAV file handle.
"""
return webdav_resource(self.remote_path)
@property
async def __buffer(self) -> BytesIO:
"""
File contents as binary stream.
"""
return await _get_buffer(
ttl_hash=get_ttl_hash(), # type: ignore
remote_path=self.remote_path,
)
@property
async def as_bytes(self) -> bytes:
"""
File contents as binary data.
"""
buffer = await self.__buffer
buffer.seek(0)
return buffer.read()
@property
async def as_string(self) -> str:
"""
File contents as string.
"""
bytes = await self.as_bytes
return bytes.decode(encoding="utf-8")
async def write(self, content: bytes) -> None:
"""
Write bytes into file.
"""
@run_in_executor
def _inner() -> None:
buffer = BytesIO(content)
self.resource.read_from(buffer)
await _inner()