refactor main __init__
This commit is contained in:
parent
105ca9d1bd
commit
77ee7c22e3
6 changed files with 85 additions and 80 deletions
|
@ -1,76 +0,0 @@
|
||||||
import asyncio
|
|
||||||
import functools
|
|
||||||
import time
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import caldav
|
|
||||||
from async_lru import alru_cache
|
|
||||||
from webdav3 import client as WebDAVclient
|
|
||||||
|
|
||||||
from .settings import SETTINGS
|
|
||||||
|
|
||||||
_WEBDAV_CLIENT = WebDAVclient.Client({
|
|
||||||
"webdav_hostname": SETTINGS.webdav_url,
|
|
||||||
"webdav_login": SETTINGS.dav_username,
|
|
||||||
"webdav_password": SETTINGS.dav_password,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
https://stackoverflow.com/a/55900800
|
|
||||||
"""
|
|
||||||
return round(time.time() / seconds)
|
|
||||||
|
|
||||||
|
|
||||||
def timed_alru_cache(**decorator_kwargs):
|
|
||||||
def decorate(f):
|
|
||||||
@alru_cache(**decorator_kwargs)
|
|
||||||
@functools.wraps(f)
|
|
||||||
async def wrapper(ttl_hash: int, *args, **kwargs):
|
|
||||||
del ttl_hash
|
|
||||||
|
|
||||||
return await f(*args, **kwargs)
|
|
||||||
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
return decorate
|
|
||||||
|
|
||||||
|
|
||||||
@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)
|
|
||||||
|
|
||||||
|
|
||||||
_CALDAV_CLIENT = caldav.DAVClient(
|
|
||||||
url=SETTINGS.caldav_url,
|
|
||||||
username=SETTINGS.dav_username,
|
|
||||||
password=SETTINGS.dav_password,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def caldav_principal() -> caldav.Principal:
|
|
||||||
return _CALDAV_CLIENT.principal()
|
|
44
api/ovdashboard_api/async_helpers.py
Normal file
44
api/ovdashboard_api/async_helpers.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
from asyncio import get_running_loop
|
||||||
|
from functools import partial, wraps
|
||||||
|
from time import time
|
||||||
|
|
||||||
|
from async_lru import alru_cache
|
||||||
|
|
||||||
|
|
||||||
|
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/
|
||||||
|
"""
|
||||||
|
|
||||||
|
@wraps(f)
|
||||||
|
def inner(*args, **kwargs):
|
||||||
|
loop = get_running_loop()
|
||||||
|
return loop.run_in_executor(
|
||||||
|
None,
|
||||||
|
partial(f, *args, **kwargs),
|
||||||
|
)
|
||||||
|
|
||||||
|
return inner
|
||||||
|
|
||||||
|
|
||||||
|
def get_ttl_hash(seconds: int = 20) -> int:
|
||||||
|
"""
|
||||||
|
Return the same value within `seconds` time period
|
||||||
|
https://stackoverflow.com/a/55900800
|
||||||
|
"""
|
||||||
|
return round(time() / seconds)
|
||||||
|
|
||||||
|
|
||||||
|
def timed_alru_cache(**decorator_kwargs):
|
||||||
|
def decorate(f):
|
||||||
|
@alru_cache(**decorator_kwargs)
|
||||||
|
@wraps(f)
|
||||||
|
async def wrapper(ttl_hash: int, *args, **kwargs):
|
||||||
|
del ttl_hash
|
||||||
|
|
||||||
|
return await f(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
return decorate
|
|
@ -9,7 +9,8 @@ from caldav.lib.error import ReportError
|
||||||
from pydantic import BaseModel, validator
|
from pydantic import BaseModel, validator
|
||||||
from vobject.icalendar import VEvent
|
from vobject.icalendar import VEvent
|
||||||
|
|
||||||
from . import caldav_principal, get_ttl_hash, run_in_executor, timed_alru_cache
|
from .async_helpers import get_ttl_hash, run_in_executor, timed_alru_cache
|
||||||
|
from .dav_common import caldav_principal
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
35
api/ovdashboard_api/dav_common.py
Normal file
35
api/ovdashboard_api/dav_common.py
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
from functools import lru_cache
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import caldav
|
||||||
|
from webdav3 import client as WebDAVclient
|
||||||
|
|
||||||
|
from .async_helpers import run_in_executor
|
||||||
|
from .settings import SETTINGS
|
||||||
|
|
||||||
|
_WEBDAV_CLIENT = WebDAVclient.Client({
|
||||||
|
"webdav_hostname": SETTINGS.webdav_url,
|
||||||
|
"webdav_login": SETTINGS.dav_username,
|
||||||
|
"webdav_password": SETTINGS.dav_password,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
||||||
|
|
||||||
|
_CALDAV_CLIENT = caldav.DAVClient(
|
||||||
|
url=SETTINGS.caldav_url,
|
||||||
|
username=SETTINGS.dav_username,
|
||||||
|
password=SETTINGS.dav_password,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def caldav_principal() -> caldav.Principal:
|
||||||
|
return _CALDAV_CLIENT.principal()
|
|
@ -5,7 +5,8 @@ from typing import Any
|
||||||
|
|
||||||
from webdav3.client import Resource
|
from webdav3.client import Resource
|
||||||
|
|
||||||
from . import get_ttl_hash, run_in_executor, timed_alru_cache, webdav_resource
|
from .async_helpers import get_ttl_hash, run_in_executor, timed_alru_cache
|
||||||
|
from .dav_common import webdav_resource
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -34,7 +35,7 @@ class DavFile:
|
||||||
@property
|
@property
|
||||||
async def __buffer(self) -> BytesIO:
|
async def __buffer(self) -> BytesIO:
|
||||||
return await _get_buffer(
|
return await _get_buffer(
|
||||||
ttl_hash=get_ttl_hash(),
|
ttl_hash=get_ttl_hash(20),
|
||||||
remote_path=self.remote_path,
|
remote_path=self.remote_path,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ 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
|
||||||
|
|
||||||
from .. import caldav_principal, webdav_list
|
from ..dav_common import caldav_principal, webdav_list
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
|
|
Loading…
Reference in a new issue