redis caching for webdav
This commit is contained in:
parent
c284274e75
commit
5524c4094b
15 changed files with 237 additions and 49 deletions
|
@ -13,8 +13,8 @@ from fastapi import FastAPI
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
|
||||||
|
from .core.dav.webdav import WebDAV
|
||||||
from .core.settings import SETTINGS
|
from .core.settings import SETTINGS
|
||||||
from .core.webdav import WebDAV
|
|
||||||
from .routers import v1_router
|
from .routers import v1_router
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -8,9 +8,9 @@ from cachetools import TTLCache, cachedmethod
|
||||||
from caldav import Calendar, DAVClient, Event, Principal
|
from caldav import Calendar, DAVClient, Event, Principal
|
||||||
from vobject.base import Component, toVName
|
from vobject.base import Component, toVName
|
||||||
|
|
||||||
from .calevent import CalEvent
|
from ..calevent import CalEvent
|
||||||
from .config import Config
|
from ..config import Config
|
||||||
from .settings import SETTINGS
|
from ..settings import SETTINGS
|
||||||
from .webdav import davkey
|
from .webdav import davkey
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
54
api/ovdashboard_api/core/dav/helpers.py
Normal file
54
api/ovdashboard_api/core/dav/helpers.py
Normal file
|
@ -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 <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):
|
||||||
|
assert isinstance(s, bytes)
|
||||||
|
return s
|
|
@ -3,53 +3,33 @@ import logging
|
||||||
import re
|
import re
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
import requests
|
|
||||||
from asyncify import asyncify
|
from asyncify import asyncify
|
||||||
from cachetools import TTLCache, cachedmethod
|
from cachetools import cachedmethod
|
||||||
from cachetools.keys import hashkey
|
from redis import Redis
|
||||||
from webdav3.client import Client as WebDAVclient
|
|
||||||
|
|
||||||
from .settings import SETTINGS
|
from ..settings import SETTINGS
|
||||||
|
from .helpers import RedisCache, WebDAVclient, davkey
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_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 WebDAV:
|
||||||
class __WebDAVclient(WebDAVclient):
|
_webdav_client = 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_hostname": SETTINGS.webdav.url,
|
"webdav_hostname": SETTINGS.webdav.url,
|
||||||
"webdav_login": SETTINGS.webdav.username,
|
"webdav_login": SETTINGS.webdav.username,
|
||||||
"webdav_password": SETTINGS.webdav.password,
|
"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,
|
ttl=SETTINGS.webdav.cache_ttl,
|
||||||
maxsize=SETTINGS.webdav.cache_size,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -125,7 +105,7 @@ class WebDAV:
|
||||||
cls._webdav_client.upload_to(buffer, path)
|
cls._webdav_client.upload_to(buffer, path)
|
||||||
|
|
||||||
# invalidate cache entry
|
# invalidate cache entry
|
||||||
cls._cache.pop(hashkey("read_bytes", path))
|
cls._cache.pop(davkey("read_bytes", None, path))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def write_str(cls, path: str, content: str, encoding="utf-8") -> None:
|
async def write_str(cls, path: str, content: str, encoding="utf-8") -> None:
|
|
@ -7,7 +7,7 @@ from os import path
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from .. import __file__ as OVD_INIT
|
from .. import __file__ as OVD_INIT
|
||||||
from .webdav import WebDAV
|
from .dav.webdav import WebDAV
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ class DAVSettings(BaseModel):
|
||||||
password: str | None = None
|
password: str | None = None
|
||||||
|
|
||||||
cache_ttl: int = 60 * 10
|
cache_ttl: int = 60 * 10
|
||||||
cache_size: int = 1024
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self) -> str:
|
def url(self) -> str:
|
||||||
|
@ -66,6 +65,17 @@ class WebDAVSettings(DAVSettings):
|
||||||
return f"{self.protocol}://{self.host}{self.path}{self.prefix}"
|
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):
|
class Settings(BaseSettings):
|
||||||
"""
|
"""
|
||||||
Per-run settings.
|
Per-run settings.
|
||||||
|
@ -123,6 +133,12 @@ class Settings(BaseSettings):
|
||||||
|
|
||||||
caldav: DAVSettings = DAVSettings()
|
caldav: DAVSettings = DAVSettings()
|
||||||
|
|
||||||
|
#####
|
||||||
|
# redis settings
|
||||||
|
#####
|
||||||
|
|
||||||
|
redis: RedisSettings = RedisSettings()
|
||||||
|
|
||||||
@model_validator(mode="before")
|
@model_validator(mode="before")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_dav_settings(cls, data) -> dict[str, Any]:
|
def validate_dav_settings(cls, data) -> dict[str, Any]:
|
||||||
|
|
|
@ -10,10 +10,10 @@ import tomli_w
|
||||||
from fastapi import Depends, HTTPException, params, status
|
from fastapi import Depends, HTTPException, params, status
|
||||||
from webdav3.exceptions import RemoteResourceNotFound
|
from webdav3.exceptions import RemoteResourceNotFound
|
||||||
|
|
||||||
from ...core.caldav import CalDAV
|
|
||||||
from ...core.config import Config
|
from ...core.config import Config
|
||||||
|
from ...core.dav.caldav import CalDAV
|
||||||
|
from ...core.dav.webdav import WebDAV
|
||||||
from ...core.settings import SETTINGS
|
from ...core.settings import SETTINGS
|
||||||
from ...core.webdav import WebDAV
|
|
||||||
from ._list_manager import Dependable, DependableFn, ListManager
|
from ._list_manager import Dependable, DependableFn, ListManager
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -10,9 +10,9 @@ import logging
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
|
|
||||||
from ...core.caldav import CalDAV
|
|
||||||
from ...core.calevent import CalEvent
|
from ...core.calevent import CalEvent
|
||||||
from ...core.config import Config
|
from ...core.config import Config
|
||||||
|
from ...core.dav.caldav import CalDAV
|
||||||
from ._common import LM_AGGREGATE, LM_CALENDAR, get_config
|
from ._common import LM_AGGREGATE, LM_CALENDAR, get_config
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -10,8 +10,8 @@ import logging
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
|
|
||||||
from ...core.caldav import CalDAV, CalEvent
|
|
||||||
from ...core.config import CalendarUIConfig, Config
|
from ...core.config import CalendarUIConfig, Config
|
||||||
|
from ...core.dav.caldav import CalDAV, CalEvent
|
||||||
from ._common import LM_CALENDAR, get_config
|
from ._common import LM_CALENDAR, get_config
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -13,8 +13,8 @@ from fastapi import APIRouter, Depends
|
||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
from magic import Magic
|
from magic import Magic
|
||||||
|
|
||||||
|
from ...core.dav.webdav import WebDAV
|
||||||
from ...core.dav_common import webdav_ensure_files, webdav_ensure_path
|
from ...core.dav_common import webdav_ensure_files, webdav_ensure_path
|
||||||
from ...core.webdav import WebDAV
|
|
||||||
from ._common import LM_FILE, RP_FILE
|
from ._common import LM_FILE, RP_FILE
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -14,8 +14,8 @@ from fastapi.responses import StreamingResponse
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
from ...core.config import Config, ImageUIConfig
|
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.dav_common import webdav_ensure_files, webdav_ensure_path
|
||||||
from ...core.webdav import WebDAV
|
|
||||||
from ._common import LM_IMAGE, RP_IMAGE, get_config
|
from ._common import LM_IMAGE, RP_IMAGE, get_config
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -12,8 +12,8 @@ import logging
|
||||||
import markdown
|
import markdown
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
|
|
||||||
|
from ...core.dav.webdav import WebDAV
|
||||||
from ...core.dav_common import webdav_ensure_files, webdav_ensure_path
|
from ...core.dav_common import webdav_ensure_files, webdav_ensure_path
|
||||||
from ...core.webdav import WebDAV
|
|
||||||
from ._common import LM_TEXT, RP_TEXT
|
from ._common import LM_TEXT, RP_TEXT
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
|
@ -13,8 +13,8 @@ import markdown
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
|
|
||||||
from ...core.config import Config, TickerUIConfig
|
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.dav_common import webdav_ensure_files, webdav_ensure_path
|
||||||
from ...core.webdav import WebDAV
|
|
||||||
from ._common import LM_TEXT, RP_TEXT, get_config
|
from ._common import LM_TEXT, RP_TEXT, get_config
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
140
api/poetry.lock
generated
140
api/poetry.lock
generated
|
@ -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]]
|
[[package]]
|
||||||
name = "annotated-types"
|
name = "annotated-types"
|
||||||
|
@ -97,6 +97,26 @@ files = [
|
||||||
{file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"},
|
{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]]
|
[[package]]
|
||||||
name = "caldav"
|
name = "caldav"
|
||||||
version = "1.3.6"
|
version = "1.3.6"
|
||||||
|
@ -330,6 +350,104 @@ files = [
|
||||||
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
|
{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]]
|
[[package]]
|
||||||
name = "httptools"
|
name = "httptools"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
|
@ -969,6 +1087,24 @@ python-dateutil = ">=2.8.1"
|
||||||
pytz = ">=2023.3"
|
pytz = ">=2023.3"
|
||||||
x-wr-timezone = ">=0.0.5,<1.0.0"
|
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]]
|
[[package]]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
version = "2.31.0"
|
version = "2.31.0"
|
||||||
|
@ -1405,4 +1541,4 @@ typing-extensions = ">=4.4.0"
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.12"
|
python-versions = "^3.12"
|
||||||
content-hash = "ec9e330d56137c0c7cc7b88b894553ada7693ba2902e2064a94355b38affa327"
|
content-hash = "fa02b5cf385dac14ae6e86ea8c33aa960a2a8394d401566b99f7dcece2c66a6a"
|
||||||
|
|
|
@ -10,11 +10,13 @@ Markdown = "^3.5"
|
||||||
Pillow = "^10.1.0"
|
Pillow = "^10.1.0"
|
||||||
asyncify = "^0.9.2"
|
asyncify = "^0.9.2"
|
||||||
cachetools = "^5.3.2"
|
cachetools = "^5.3.2"
|
||||||
|
cachetoolsutils = "^8.2"
|
||||||
caldav = "^1.3.6"
|
caldav = "^1.3.6"
|
||||||
fastapi = "^0.103.2"
|
fastapi = "^0.103.2"
|
||||||
pydantic-settings = "^2.0.3"
|
pydantic-settings = "^2.0.3"
|
||||||
python = "^3.12"
|
python = "^3.12"
|
||||||
python-magic = "^0.4.27"
|
python-magic = "^0.4.27"
|
||||||
|
redis = {extras = ["hiredis"], version = "^5.0.1"}
|
||||||
tomli-w = "^1.0.0"
|
tomli-w = "^1.0.0"
|
||||||
uvicorn = {extras = ["standard"], version = "^0.23.2"}
|
uvicorn = {extras = ["standard"], version = "^0.23.2"}
|
||||||
webdavclient3 = "^3.14.6"
|
webdavclient3 = "^3.14.6"
|
||||||
|
|
Loading…
Reference in a new issue