advent22/api/advent22_api/core/dav/helpers.py

67 lines
1.7 KiB
Python
Raw Normal View History

from itertools import chain
2023-10-29 16:08:16 +00:00
from json import JSONDecodeError
from typing import Any, Callable
2023-10-29 16:08:16 +00:00
import requests
from CacheToolsUtils import RedisCache as __RedisCache
from redis.typing import EncodableT, ResponseT
2023-10-29 16:08:16 +00:00
from webdav3.client import Client as __WebDAVclient
2023-11-09 11:55:10 +00:00
def davkey(
name: str,
slice: slice = slice(1, None),
) -> Callable[..., str]:
def func(*args: Any, **kwargs: Any) -> str:
2023-11-09 11:55:10 +00:00
"""Return a cache key for use with cached methods."""
2023-10-29 16:08:16 +00:00
call_args = chain(
# positional args
(f"{arg!r}" for arg in args[slice]),
# keyword args
(f"{k}:{v!r}" for k, v in kwargs.items()),
)
return f"{name}({', '.join(call_args)})"
2023-11-09 11:55:10 +00:00
return func
2023-10-29 16:08:16 +00:00
class WebDAVclient(__WebDAVclient):
def execute_request(
self,
action,
path,
data=None,
headers_ext=None,
) -> requests.Response:
res = super().execute_request(action, path, data, headers_ext)
# the "Content-Length" header can randomly be missing on txt files,
# this should fix that (probably serverside bug)
if action == "download" and "Content-Length" not in res.headers:
res.headers["Content-Length"] = str(len(res.text))
return res
class RedisCache(__RedisCache):
"""
Redis handles <bytes>, so ...
"""
def _serialize(self, s) -> EncodableT:
if isinstance(s, bytes):
return s
else:
return super()._serialize(s)
def _deserialize(self, s: ResponseT):
try:
return super()._deserialize(s)
except UnicodeDecodeError, JSONDecodeError:
2023-10-29 16:08:16 +00:00
assert isinstance(s, bytes)
return s