2026-02-22 16:36:35 +00:00
|
|
|
from itertools import chain
|
2023-10-29 16:08:16 +00:00
|
|
|
from json import JSONDecodeError
|
2026-02-22 16:36:35 +00:00
|
|
|
from typing import Any, Callable
|
2023-10-29 16:08:16 +00:00
|
|
|
|
|
|
|
|
import requests
|
|
|
|
|
from CacheToolsUtils import RedisCache as __RedisCache
|
2026-02-15 18:27:29 +00:00
|
|
|
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),
|
2026-02-22 16:36:35 +00:00
|
|
|
) -> 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
|
|
|
|
2026-02-22 16:36:35 +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)
|
|
|
|
|
|
2026-02-18 02:19:22 +00:00
|
|
|
except UnicodeDecodeError, JSONDecodeError:
|
2023-10-29 16:08:16 +00:00
|
|
|
assert isinstance(s, bytes)
|
|
|
|
|
return s
|