diff --git a/api/ovdashboard_api/app.py b/api/ovdashboard_api/app.py index 648ecc9..ef683c3 100644 --- a/api/ovdashboard_api/app.py +++ b/api/ovdashboard_api/app.py @@ -13,8 +13,8 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles +from .core.dav.webdav import WebDAV from .core.settings import SETTINGS -from .core.webdav import WebDAV from .routers import v1_router _logger = logging.getLogger(__name__) diff --git a/api/ovdashboard_api/core/caldav.py b/api/ovdashboard_api/core/dav/caldav.py similarity index 96% rename from api/ovdashboard_api/core/caldav.py rename to api/ovdashboard_api/core/dav/caldav.py index 128b9eb..d85413f 100644 --- a/api/ovdashboard_api/core/caldav.py +++ b/api/ovdashboard_api/core/dav/caldav.py @@ -8,9 +8,9 @@ from cachetools import TTLCache, cachedmethod from caldav import Calendar, DAVClient, Event, Principal from vobject.base import Component, toVName -from .calevent import CalEvent -from .config import Config -from .settings import SETTINGS +from ..calevent import CalEvent +from ..config import Config +from ..settings import SETTINGS from .webdav import davkey _logger = logging.getLogger(__name__) diff --git a/api/ovdashboard_api/core/dav/helpers.py b/api/ovdashboard_api/core/dav/helpers.py new file mode 100644 index 0000000..e15617d --- /dev/null +++ b/api/ovdashboard_api/core/dav/helpers.py @@ -0,0 +1,54 @@ +from json import JSONDecodeError + +import requests +from cachetools.keys import hashkey +from CacheToolsUtils import RedisCache as __RedisCache +from redis.commands.core import ResponseT +from redis.typing import EncodableT +from webdav3.client import Client as __WebDAVclient + + +def davkey(name, _, *args, **kwargs): + """Return a cache key for use with cached methods.""" + + key = hashkey(name, *args, **kwargs) + return hashkey(*(str(key_item) for key_item in key)) + + +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 , 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): + assert isinstance(s, bytes) + return s diff --git a/api/ovdashboard_api/core/webdav.py b/api/ovdashboard_api/core/dav/webdav.py similarity index 69% rename from api/ovdashboard_api/core/webdav.py rename to api/ovdashboard_api/core/dav/webdav.py index 305785f..4c316a5 100644 --- a/api/ovdashboard_api/core/webdav.py +++ b/api/ovdashboard_api/core/dav/webdav.py @@ -3,53 +3,33 @@ import logging import re from io import BytesIO -import requests from asyncify import asyncify -from cachetools import TTLCache, cachedmethod -from cachetools.keys import hashkey -from webdav3.client import Client as WebDAVclient +from cachetools import cachedmethod +from redis import Redis -from .settings import SETTINGS +from ..settings import SETTINGS +from .helpers import RedisCache, WebDAVclient, davkey _logger = logging.getLogger(__name__) -def davkey(name, _, *args, **kwargs): - """Return a cache key for use with cached methods.""" - - return hashkey(name, *args, **kwargs) - - class WebDAV: - 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 - - _webdav_client = __WebDAVclient( + _webdav_client = WebDAVclient( { "webdav_hostname": SETTINGS.webdav.url, "webdav_login": SETTINGS.webdav.username, "webdav_password": SETTINGS.webdav.password, - "disable_check": SETTINGS.webdav.disable_check, } ) - _cache = TTLCache( + _cache = RedisCache( + cache=Redis( + host=SETTINGS.redis.host, + port=SETTINGS.redis.port, + db=SETTINGS.redis.db, + protocol=SETTINGS.redis.protocol, + ), ttl=SETTINGS.webdav.cache_ttl, - maxsize=SETTINGS.webdav.cache_size, ) @classmethod @@ -125,7 +105,7 @@ class WebDAV: cls._webdav_client.upload_to(buffer, path) # invalidate cache entry - cls._cache.pop(hashkey("read_bytes", path)) + cls._cache.pop(davkey("read_bytes", None, path)) @classmethod async def write_str(cls, path: str, content: str, encoding="utf-8") -> None: diff --git a/api/ovdashboard_api/core/dav_common.py b/api/ovdashboard_api/core/dav_common.py index c8c66e7..7255783 100644 --- a/api/ovdashboard_api/core/dav_common.py +++ b/api/ovdashboard_api/core/dav_common.py @@ -7,7 +7,7 @@ from os import path from pathlib import Path from .. import __file__ as OVD_INIT -from .webdav import WebDAV +from .dav.webdav import WebDAV _logger = logging.getLogger(__name__) diff --git a/api/ovdashboard_api/core/settings.py b/api/ovdashboard_api/core/settings.py index 6cc11fa..477eb32 100644 --- a/api/ovdashboard_api/core/settings.py +++ b/api/ovdashboard_api/core/settings.py @@ -26,7 +26,6 @@ class DAVSettings(BaseModel): password: str | None = None cache_ttl: int = 60 * 10 - cache_size: int = 1024 @property def url(self) -> str: @@ -66,6 +65,17 @@ class WebDAVSettings(DAVSettings): return f"{self.protocol}://{self.host}{self.path}{self.prefix}" +class RedisSettings(BaseModel): + """ + Connection to a redis server. + """ + + host: str = "redis" + port: int = 6379 + db: int = 0 + protocol: int = 3 + + class Settings(BaseSettings): """ Per-run settings. @@ -123,6 +133,12 @@ class Settings(BaseSettings): caldav: DAVSettings = DAVSettings() + ##### + # redis settings + ##### + + redis: RedisSettings = RedisSettings() + @model_validator(mode="before") @classmethod def validate_dav_settings(cls, data) -> dict[str, Any]: diff --git a/api/ovdashboard_api/routers/v1/_common.py b/api/ovdashboard_api/routers/v1/_common.py index 97b6af3..1ddf9ef 100644 --- a/api/ovdashboard_api/routers/v1/_common.py +++ b/api/ovdashboard_api/routers/v1/_common.py @@ -10,10 +10,10 @@ import tomli_w from fastapi import Depends, HTTPException, params, status from webdav3.exceptions import RemoteResourceNotFound -from ...core.caldav import CalDAV from ...core.config import Config +from ...core.dav.caldav import CalDAV +from ...core.dav.webdav import WebDAV from ...core.settings import SETTINGS -from ...core.webdav import WebDAV from ._list_manager import Dependable, DependableFn, ListManager _logger = logging.getLogger(__name__) diff --git a/api/ovdashboard_api/routers/v1/aggregate.py b/api/ovdashboard_api/routers/v1/aggregate.py index 281d90a..ac7d1ce 100644 --- a/api/ovdashboard_api/routers/v1/aggregate.py +++ b/api/ovdashboard_api/routers/v1/aggregate.py @@ -10,9 +10,9 @@ import logging from fastapi import APIRouter, Depends -from ...core.caldav import CalDAV from ...core.calevent import CalEvent from ...core.config import Config +from ...core.dav.caldav import CalDAV from ._common import LM_AGGREGATE, LM_CALENDAR, get_config _logger = logging.getLogger(__name__) diff --git a/api/ovdashboard_api/routers/v1/calendar.py b/api/ovdashboard_api/routers/v1/calendar.py index 39165f8..f0db10a 100644 --- a/api/ovdashboard_api/routers/v1/calendar.py +++ b/api/ovdashboard_api/routers/v1/calendar.py @@ -10,8 +10,8 @@ import logging from fastapi import APIRouter, Depends -from ...core.caldav import CalDAV, CalEvent from ...core.config import CalendarUIConfig, Config +from ...core.dav.caldav import CalDAV, CalEvent from ._common import LM_CALENDAR, get_config _logger = logging.getLogger(__name__) diff --git a/api/ovdashboard_api/routers/v1/file.py b/api/ovdashboard_api/routers/v1/file.py index 0e1a847..4baea55 100644 --- a/api/ovdashboard_api/routers/v1/file.py +++ b/api/ovdashboard_api/routers/v1/file.py @@ -13,8 +13,8 @@ from fastapi import APIRouter, Depends from fastapi.responses import StreamingResponse from magic import Magic +from ...core.dav.webdav import WebDAV from ...core.dav_common import webdav_ensure_files, webdav_ensure_path -from ...core.webdav import WebDAV from ._common import LM_FILE, RP_FILE _logger = logging.getLogger(__name__) diff --git a/api/ovdashboard_api/routers/v1/image.py b/api/ovdashboard_api/routers/v1/image.py index 891d9ed..e05f9d8 100644 --- a/api/ovdashboard_api/routers/v1/image.py +++ b/api/ovdashboard_api/routers/v1/image.py @@ -14,8 +14,8 @@ from fastapi.responses import StreamingResponse from PIL import Image from ...core.config import Config, ImageUIConfig +from ...core.dav.webdav import WebDAV from ...core.dav_common import webdav_ensure_files, webdav_ensure_path -from ...core.webdav import WebDAV from ._common import LM_IMAGE, RP_IMAGE, get_config _logger = logging.getLogger(__name__) diff --git a/api/ovdashboard_api/routers/v1/text.py b/api/ovdashboard_api/routers/v1/text.py index 6d822ac..d073d30 100644 --- a/api/ovdashboard_api/routers/v1/text.py +++ b/api/ovdashboard_api/routers/v1/text.py @@ -12,8 +12,8 @@ import logging import markdown from fastapi import APIRouter, Depends +from ...core.dav.webdav import WebDAV from ...core.dav_common import webdav_ensure_files, webdav_ensure_path -from ...core.webdav import WebDAV from ._common import LM_TEXT, RP_TEXT _logger = logging.getLogger(__name__) diff --git a/api/ovdashboard_api/routers/v1/ticker.py b/api/ovdashboard_api/routers/v1/ticker.py index 21135c5..6ddd27e 100644 --- a/api/ovdashboard_api/routers/v1/ticker.py +++ b/api/ovdashboard_api/routers/v1/ticker.py @@ -13,8 +13,8 @@ import markdown from fastapi import APIRouter, Depends from ...core.config import Config, TickerUIConfig +from ...core.dav.webdav import WebDAV from ...core.dav_common import webdav_ensure_files, webdav_ensure_path -from ...core.webdav import WebDAV from ._common import LM_TEXT, RP_TEXT, get_config _logger = logging.getLogger(__name__) diff --git a/api/poetry.lock b/api/poetry.lock index 5344c5d..f401e97 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. [[package]] name = "annotated-types" @@ -97,6 +97,26 @@ files = [ {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, ] +[[package]] +name = "cachetoolsutils" +version = "8.2" +description = "Cachetools Utilities" +optional = false +python-versions = ">=3.10" +files = [ + {file = "CacheToolsUtils-8.2-py3-none-any.whl", hash = "sha256:721cd4d63477f4de3ba2108f6b8e5b1a9708075eeb72e4770e814f4826815846"}, + {file = "CacheToolsUtils-8.2.tar.gz", hash = "sha256:a8ece7af5fcc221dfec747dffce4bbfd7e6b45ef315c3aefedb844790c9d1f59"}, +] + +[package.dependencies] +cachetools = "*" + +[package.extras] +dev = ["black", "coverage", "flake8", "mypy", "pymarkdownlnt", "pytest", "types-cachetools", "types-redis"] +doc = ["myst-parser", "sphinx", "sphinx-autoapi", "sphinx-lint", "sphinx-rtd-theme"] +pub = ["build", "twine", "wheel"] +tests = ["pymemcache", "redis"] + [[package]] name = "caldav" version = "1.3.6" @@ -330,6 +350,104 @@ files = [ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] +[[package]] +name = "hiredis" +version = "2.2.3" +description = "Python wrapper for hiredis" +optional = false +python-versions = ">=3.7" +files = [ + {file = "hiredis-2.2.3-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:9a1a80a8fa767f2fdc3870316a54b84fe9fc09fa6ab6a2686783de6a228a4604"}, + {file = "hiredis-2.2.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3f006c28c885deb99b670a5a66f367a175ab8955b0374029bad7111f5357dcd4"}, + {file = "hiredis-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ffaf841546905d90ff189de7397aa56413b1ce5e54547f17a98f0ebf3a3b0a3b"}, + {file = "hiredis-2.2.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cadb0ac7ba3babfd804e425946bec9717b320564a1390f163a54af9365a720a"}, + {file = "hiredis-2.2.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33bc4721632ef9708fa44e5df0066053fccc8e65410a2c48573192517a533b48"}, + {file = "hiredis-2.2.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:227c5b4bcb60f89008c275d596e4a7b6625a6b3c827b8a66ae582eace7051f71"}, + {file = "hiredis-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61995eb826009d99ed8590747bc0da683a5f4fbb4faa8788166bf3810845cd5c"}, + {file = "hiredis-2.2.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f969edc851efe23010e0f53a64269f2629a9364135e9ec81c842e8b2277d0c1"}, + {file = "hiredis-2.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27e560eefb57914d742a837f1da98d3b29cb22eff013c8023b7cf52ae6e051d"}, + {file = "hiredis-2.2.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3759f4789ae1913b7df278dfc9e8749205b7a106f888cd2903d19461e24a7697"}, + {file = "hiredis-2.2.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c6cb613148422c523945cdb8b6bed617856f2602fd8750e33773ede2616e55d5"}, + {file = "hiredis-2.2.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:1d274d5c511dfc03f83f997d3238eaa9b6ee3f982640979f509373cced891e98"}, + {file = "hiredis-2.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3b7fe075e91b9d9cff40eba4fb6a8eff74964d3979a39be9a9ef58b1b4cb3604"}, + {file = "hiredis-2.2.3-cp310-cp310-win32.whl", hash = "sha256:77924b0d32fd1f493d3df15d9609ddf9d94c31a364022a6bf6b525ce9da75bea"}, + {file = "hiredis-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:dcb0569dd5bfe6004658cd0f229efa699a3169dcb4f77bd72e188adda302063d"}, + {file = "hiredis-2.2.3-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:d115790f18daa99b5c11a506e48923b630ef712e9e4b40482af942c3d40638b8"}, + {file = "hiredis-2.2.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c3b8be557e08b234774925622e196f0ee36fe4eab66cd19df934d3efd8f3743"}, + {file = "hiredis-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f5446068197b35a11ccc697720c41879c8657e2e761aaa8311783aac84cef20"}, + {file = "hiredis-2.2.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa17a3b22b3726d54d7af20394f65d4a1735a842a4e0f557dc67a90f6965c4bc"}, + {file = "hiredis-2.2.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7df645b6b7800e8b748c217fbd6a4ca8361bcb9a1ae6206cc02377833ec8a1aa"}, + {file = "hiredis-2.2.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2fb9300959a0048138791f3d68359d61a788574ec9556bddf1fec07f2dbc5320"}, + {file = "hiredis-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d7e459fe7313925f395148d36d9b7f4f8dac65be06e45d7af356b187cef65fc"}, + {file = "hiredis-2.2.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8eceffca3941775b646cd585cd19b275d382de43cc3327d22f7c75d7b003d481"}, + {file = "hiredis-2.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b17baf702c6e5b4bb66e1281a3efbb1d749c9d06cdb92b665ad81e03118f78fc"}, + {file = "hiredis-2.2.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e43e2b5acaad09cf48c032f7e4926392bb3a3f01854416cf6d82ebff94d5467"}, + {file = "hiredis-2.2.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a7205497d7276a81fe92951a29616ef96562ed2f91a02066f72b6f93cb34b40e"}, + {file = "hiredis-2.2.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:126623b03c31cb6ac3e0d138feb6fcc36dd43dd34fc7da7b7a0c38b5d75bc896"}, + {file = "hiredis-2.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:071c5814b850574036506a8118034f97c3cbf2fe9947ff45a27b07a48da56240"}, + {file = "hiredis-2.2.3-cp311-cp311-win32.whl", hash = "sha256:d1be9e30e675f5bc1cb534633324578f6f0944a1bcffe53242cf632f554f83b6"}, + {file = "hiredis-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9a7c987e161e3c58f992c63b7e26fea7fe0777f3b975799d23d65bbb8cb5899"}, + {file = "hiredis-2.2.3-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:f2dcb8389fa3d453927b1299f46bdb38473c293c8269d5c777d33ea0e526b610"}, + {file = "hiredis-2.2.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2df98f5e071320c7d84e8bd07c0542acdd0a7519307fc31774d60e4b842ec4f"}, + {file = "hiredis-2.2.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61a72e4a523cdfc521762137559c08dfa360a3caef63620be58c699d1717dac1"}, + {file = "hiredis-2.2.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9b9e5bde7030cae83aa900b5bd660decc65afd2db8c400f3c568c815a47ca2a"}, + {file = "hiredis-2.2.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2614f17e261f72efc2f19f5e5ff2ee19e2296570c0dcf33409e22be30710de"}, + {file = "hiredis-2.2.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46525fbd84523cac75af5bf524bc74aaac848beaf31b142d2df8a787d9b4bbc4"}, + {file = "hiredis-2.2.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d1a4ce40ba11da9382c14da31f4f9e88c18f7d294f523decd0fadfb81f51ad18"}, + {file = "hiredis-2.2.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:5cda592405bbd29d53942e0389dc3fa77b49c362640210d7e94a10c14a677d4d"}, + {file = "hiredis-2.2.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:5e6674a017629284ef373b50496d9fb1a89b85a20a7fa100ecd109484ec748e5"}, + {file = "hiredis-2.2.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:e62ec131816c6120eff40dffe43424e140264a15fa4ab88c301bd6a595913af3"}, + {file = "hiredis-2.2.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:17e938d9d3ee92e1adbff361706f1c36cc60eeb3e3eeca7a3a353eae344f4c91"}, + {file = "hiredis-2.2.3-cp37-cp37m-win32.whl", hash = "sha256:95d2305fd2a7b179cacb48b10f618872fc565c175f9f62b854e8d1acac3e8a9e"}, + {file = "hiredis-2.2.3-cp37-cp37m-win_amd64.whl", hash = "sha256:8f9dbe12f011a9b784f58faecc171d22465bb532c310bd588d769ba79a59ef5a"}, + {file = "hiredis-2.2.3-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:5a4bcef114fc071d5f52c386c47f35aae0a5b43673197b9288a15b584da8fa3a"}, + {file = "hiredis-2.2.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:232d0a70519865741ba56e1dfefd160a580ae78c30a1517bad47b3cf95a3bc7d"}, + {file = "hiredis-2.2.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9076ce8429785c85f824650735791738de7143f61f43ae9ed83e163c0ca0fa44"}, + {file = "hiredis-2.2.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec58fb7c2062f835595c12f0f02dcda76d0eb0831423cc191d1e18c9276648de"}, + {file = "hiredis-2.2.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f2b34a6444b8f9c1e9f84bd2c639388e5d14f128afd14a869dfb3d9af893aa2"}, + {file = "hiredis-2.2.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:818dfd310aa1020a13cd08ee48e116dd8c3bb2e23b8161f8ac4df587dd5093d7"}, + {file = "hiredis-2.2.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96d9ea6c8d4cbdeee2e0d43379ce2881e4af0454b00570677c59f33f2531cd38"}, + {file = "hiredis-2.2.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1eadbcd3de55ac42310ff82550d3302cb4efcd4e17d76646a17b6e7004bb42b"}, + {file = "hiredis-2.2.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:477c34c4489666dc73cb5e89dafe2617c3e13da1298917f73d55aac4696bd793"}, + {file = "hiredis-2.2.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:14824e457e4f5cda685c3345d125da13949bcf3bb1c88eb5d248c8d2c3dee08f"}, + {file = "hiredis-2.2.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:9cd32326dfa6ce87edf754153b0105aca64486bebe93b9600ccff74fa0b224df"}, + {file = "hiredis-2.2.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:51341e70b467004dcbec3a6ce8c478d2d6241e0f6b01e4c56764afd5022e1e9d"}, + {file = "hiredis-2.2.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2443659c76b226267e2a04dbbb21bc2a3f91aa53bdc0c22964632753ae43a247"}, + {file = "hiredis-2.2.3-cp38-cp38-win32.whl", hash = "sha256:4e3e3e31423f888d396b1fc1f936936e52af868ac1ec17dd15e3eeba9dd4de24"}, + {file = "hiredis-2.2.3-cp38-cp38-win_amd64.whl", hash = "sha256:20f509e3a1a20d6e5f5794fc37ceb21f70f409101fcfe7a8bde783894d51b369"}, + {file = "hiredis-2.2.3-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:d20891e3f33803b26d54c77fd5745878497091e33f4bbbdd454cf6e71aee8890"}, + {file = "hiredis-2.2.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:50171f985e17970f87d5a29e16603d1e5b03bdbf5c2691a37e6c912942a6b657"}, + {file = "hiredis-2.2.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9944a2cac25ffe049a7e89f306e11b900640837d1ef38d9be0eaa4a4e2b73a52"}, + {file = "hiredis-2.2.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a5c8019ff94988d56eb49b15de76fe83f6b42536d76edeb6565dbf7fe14b973"}, + {file = "hiredis-2.2.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a286ded34eb16501002e3713b3130c987366eee2ba0d58c33c72f27778e31676"}, + {file = "hiredis-2.2.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b3e974ad15eb32b1f537730dea70b93a4c3db7b026de3ad2b59da49c6f7454d"}, + {file = "hiredis-2.2.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08415ea74c1c29b9d6a4ca3dd0e810dc1af343c1d1d442e15ba133b11ab5be6a"}, + {file = "hiredis-2.2.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e17d04ea58ab8cf3f2dc52e875db16077c6357846006780086fff3189fb199d"}, + {file = "hiredis-2.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6ccdcb635dae85b006592f78e32d97f4bc7541cb27829d505f9c7fefcef48298"}, + {file = "hiredis-2.2.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69536b821dd1bc78058a6e7541743f8d82bf2d981b91280b14c4daa6cdc7faba"}, + {file = "hiredis-2.2.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:3753df5f873d473f055e1f8837bfad0bd3b277c86f3c9bf058c58f14204cd901"}, + {file = "hiredis-2.2.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:6f88cafe46612b6fa68e6dea49e25bebf160598bba00101caa51cc8c1f18d597"}, + {file = "hiredis-2.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33ee3ea5cad3a8cb339352cd230b411eb437a2e75d7736c4899acab32056ccdb"}, + {file = "hiredis-2.2.3-cp39-cp39-win32.whl", hash = "sha256:b4f3d06dc16671b88a13ae85d8ca92534c0b637d59e49f0558d040a691246422"}, + {file = "hiredis-2.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:4f674e309cd055ee7a48304ceb8cf43265d859faf4d7d01d270ce45e976ae9d3"}, + {file = "hiredis-2.2.3-pp37-pypy37_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8f280ab4e043b089777b43b4227bdc2035f88da5072ab36588e0ccf77d45d058"}, + {file = "hiredis-2.2.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15c2a551f3b8a26f7940d6ee10b837810201754b8d7e6f6b1391655370882c5a"}, + {file = "hiredis-2.2.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60c4e3c258eafaab21b174b17270a0cc093718d61cdbde8c03f85ec4bf835343"}, + {file = "hiredis-2.2.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc36a9dded458d4e37492fe3e619c6c83caae794d26ad925adbce61d592f8428"}, + {file = "hiredis-2.2.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:4ed68a3b1ccb4313d2a42546fd7e7439ad4745918a48b6c9bcaa61e1e3e42634"}, + {file = "hiredis-2.2.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3bf4b5bae472630c229518e4a814b1b68f10a3d9b00aeaec45f1a330f03a0251"}, + {file = "hiredis-2.2.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33a94d264e6e12a79d9bb8af333b01dc286b9f39c99072ab5fef94ce1f018e17"}, + {file = "hiredis-2.2.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fa6811a618653164f918b891a0fa07052bd71a799defa5c44d167cac5557b26"}, + {file = "hiredis-2.2.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:af33f370be90b48bbaf0dab32decbdcc522b1fa95d109020a963282086518a8e"}, + {file = "hiredis-2.2.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b9953d87418ac228f508d93898ab572775e4d3b0eeb886a1a7734553bcdaf291"}, + {file = "hiredis-2.2.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5e7bb4dd524f50b71c20ef5a12bd61da9b463f8894b18a06130942fe31509881"}, + {file = "hiredis-2.2.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89a258424158eb8b3ed9f65548d68998da334ef155d09488c5637723eb1cd697"}, + {file = "hiredis-2.2.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f4a65276f6ecdebe75f2a53f578fbc40e8d2860658420d5e0611c56bbf5054c"}, + {file = "hiredis-2.2.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:334f2738700b20faa04a0d813366fb16ed17287430a6b50584161d5ad31ca6d7"}, + {file = "hiredis-2.2.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d194decd9608f11c777946f596f31d5aacad13972a0a87829ae1e6f2d26c1885"}, + {file = "hiredis-2.2.3.tar.gz", hash = "sha256:e75163773a309e56a9b58165cf5a50e0f84b755f6ff863b2c01a38918fe92daa"}, +] + [[package]] name = "httptools" version = "0.6.1" @@ -969,6 +1087,24 @@ python-dateutil = ">=2.8.1" pytz = ">=2023.3" x-wr-timezone = ">=0.0.5,<1.0.0" +[[package]] +name = "redis" +version = "5.0.1" +description = "Python client for Redis database and key-value store" +optional = false +python-versions = ">=3.7" +files = [ + {file = "redis-5.0.1-py3-none-any.whl", hash = "sha256:ed4802971884ae19d640775ba3b03aa2e7bd5e8fb8dfaed2decce4d0fc48391f"}, + {file = "redis-5.0.1.tar.gz", hash = "sha256:0dab495cd5753069d3bc650a0dde8a8f9edde16fc5691b689a566eda58100d0f"}, +] + +[package.dependencies] +hiredis = {version = ">=1.0.0", optional = true, markers = "extra == \"hiredis\""} + +[package.extras] +hiredis = ["hiredis (>=1.0.0)"] +ocsp = ["cryptography (>=36.0.1)", "pyopenssl (==20.0.1)", "requests (>=2.26.0)"] + [[package]] name = "requests" version = "2.31.0" @@ -1405,4 +1541,4 @@ typing-extensions = ">=4.4.0" [metadata] lock-version = "2.0" python-versions = "^3.12" -content-hash = "ec9e330d56137c0c7cc7b88b894553ada7693ba2902e2064a94355b38affa327" +content-hash = "fa02b5cf385dac14ae6e86ea8c33aa960a2a8394d401566b99f7dcece2c66a6a" diff --git a/api/pyproject.toml b/api/pyproject.toml index 7ad0861..c899f68 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -10,11 +10,13 @@ Markdown = "^3.5" Pillow = "^10.1.0" asyncify = "^0.9.2" cachetools = "^5.3.2" +cachetoolsutils = "^8.2" caldav = "^1.3.6" fastapi = "^0.103.2" pydantic-settings = "^2.0.3" python = "^3.12" python-magic = "^0.4.27" +redis = {extras = ["hiredis"], version = "^5.0.1"} tomli-w = "^1.0.0" uvicorn = {extras = ["standard"], version = "^0.23.2"} webdavclient3 = "^3.14.6"