wip/experiments
This commit is contained in:
parent
37b1a1ee68
commit
5034115281
3 changed files with 37 additions and 31 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
import asyncio
|
||||||
import functools
|
import functools
|
||||||
from typing import Any
|
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
|
@functools.lru_cache
|
||||||
def webdav_resource(remote_path: Any) -> WebDAVclient.Resource:
|
def webdav_resource(remote_path: Any) -> WebDAVclient.Resource:
|
||||||
return _WEBDAV_CLIENT.resource(remote_path)
|
return _WEBDAV_CLIENT.resource(remote_path)
|
||||||
|
|
||||||
|
|
||||||
|
@run_in_executor
|
||||||
def webdav_list(remote_path: str) -> list:
|
def webdav_list(remote_path: str) -> list:
|
||||||
return _WEBDAV_CLIENT.list(remote_path)
|
return _WEBDAV_CLIENT.list(remote_path)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import asyncio
|
|
||||||
import functools
|
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
@ -8,28 +6,11 @@ from typing import Any, Optional
|
||||||
from async_lru import alru_cache
|
from async_lru import alru_cache
|
||||||
from webdav3.client import Resource
|
from webdav3.client import Resource
|
||||||
|
|
||||||
from . import webdav_resource
|
from . import run_in_executor, webdav_resource
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_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:
|
def _get_ttl_hash(seconds: int = 20) -> int:
|
||||||
"""
|
"""
|
||||||
Return the same value within `seconds` time period
|
Return the same value within `seconds` time period
|
||||||
|
@ -45,7 +26,7 @@ async def _get_buffer(
|
||||||
) -> BytesIO:
|
) -> BytesIO:
|
||||||
del ttl_hash
|
del ttl_hash
|
||||||
|
|
||||||
@_run_in_executor
|
@run_in_executor
|
||||||
def buffer_inner(resource: Resource) -> BytesIO:
|
def buffer_inner(resource: Resource) -> BytesIO:
|
||||||
_logger.info(f"updating {resource}")
|
_logger.info(f"updating {resource}")
|
||||||
print(f"updating {resource}")
|
print(f"updating {resource}")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import re
|
import re
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Iterator
|
from typing import Iterator, Protocol
|
||||||
|
|
||||||
from fastapi import HTTPException, status
|
from fastapi import HTTPException, status
|
||||||
from webdav3.exceptions import RemoteResourceNotFound
|
from webdav3.exceptions import RemoteResourceNotFound
|
||||||
|
@ -9,14 +9,20 @@ from .. import webdav_list
|
||||||
from ..dav_file import DavFile
|
from ..dav_file import DavFile
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class NameLister(Protocol):
|
||||||
|
def __call__(self) -> Iterator[str]:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class FileNameLister:
|
class FileNameLister:
|
||||||
remote_path: str
|
remote_path: str
|
||||||
re: re.Pattern[str]
|
re: re.Pattern[str]
|
||||||
|
|
||||||
def __call__(self) -> Iterator[str]:
|
async def __call__(self) -> Iterator[str]:
|
||||||
try:
|
try:
|
||||||
file_names = webdav_list(self.remote_path)
|
file_names = await webdav_list(self.remote_path)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
name
|
name
|
||||||
|
@ -29,20 +35,20 @@ class FileNameLister:
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class FilePrefixFinder:
|
class PrefixFinder:
|
||||||
lister: FileNameLister
|
lister: NameLister
|
||||||
|
|
||||||
def __call__(self, prefix: str) -> Iterator[str]:
|
async def __call__(self, prefix: str) -> Iterator[str]:
|
||||||
return (
|
return (
|
||||||
file_name
|
file_name
|
||||||
for file_name in self.lister()
|
for file_name in (await self.lister())
|
||||||
if file_name.lower().startswith(prefix.lower())
|
if file_name.lower().startswith(prefix.lower())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class FilePrefixLoader:
|
class FilePrefixLoader:
|
||||||
finder: FilePrefixFinder
|
finder: PrefixFinder
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def responses(self) -> dict:
|
def responses(self) -> dict:
|
||||||
|
@ -62,8 +68,8 @@ class FilePrefixLoader:
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
def __call__(self, prefix: str) -> DavFile:
|
async def __call__(self, prefix: str) -> DavFile:
|
||||||
file_names = list(self.finder(prefix))
|
file_names = list(await self.finder(prefix))
|
||||||
|
|
||||||
if not (file_names):
|
if not (file_names):
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
Loading…
Reference in a new issue