diff --git a/api/ovkiosk/dav_file.py b/api/ovkiosk/dav_file.py index e802f4e..a279bc8 100644 --- a/api/ovkiosk/dav_file.py +++ b/api/ovkiosk/dav_file.py @@ -1,38 +1,51 @@ import logging -import threading from io import BytesIO +from threading import Lock from typing import Any +from apscheduler.schedulers.asyncio import AsyncIOScheduler from webdav3.client import Client, Resource _logger = logging.getLogger(__name__) class DavFile: + __instances = None + def __init__(self, client: Client, path: Any) -> None: self.__resource: Resource = client.resource(path) self.__buffer = BytesIO() - self.__lock = threading.Lock() + self.__lock = Lock() + + # register + if DavFile.__instances is None: + DavFile.__instances = [] + + DavFile.__instances.append(self) def update(self) -> None: - _logger.debug(f"updating {self.__resource}") + _logger.info(f"updating {self.__resource}") with self.__lock: self.__buffer.seek(0) self.__buffer.truncate(0) self.__resource.write_to(self.__buffer) - def refresh(self, refresh_interval: int = 5) -> threading.Event: - stop_handle = threading.Event() + @classmethod + def refresh(cls, refresh_interval: int = 5) -> AsyncIOScheduler: + scheduler = AsyncIOScheduler() - def refresh_loop() -> None: - while not stop_handle.wait(refresh_interval): - self.update() + def tick() -> None: + for davfile in DavFile.__instances: + davfile.update() - thread = threading.Thread(target=refresh_loop) - thread.daemon = True - thread.start() + scheduler.add_job(tick) + scheduler.add_job( + tick, "interval", + seconds=refresh_interval, + ) + scheduler.start() - return stop_handle + return scheduler @property def bytes(self) -> bytes: diff --git a/api/ovkiosk/routers/text.py b/api/ovkiosk/routers/text.py index 93210ba..416656f 100644 --- a/api/ovkiosk/routers/text.py +++ b/api/ovkiosk/routers/text.py @@ -3,7 +3,8 @@ import logging from fastapi import APIRouter from markdown import Markdown -from .. import CLIENT, SETTINGS +from .. import CLIENT +from ..config import SETTINGS from ..dav_file import DavFile router = APIRouter(prefix="/text", tags=["text"]) @@ -11,18 +12,21 @@ router = APIRouter(prefix="/text", tags=["text"]) _logger = logging.getLogger(__name__) _md = Markdown() -_message = DavFile(client=CLIENT, path="message.txt") -_ticker = DavFile(client=CLIENT, path="ticker.txt") -_title = DavFile(client=CLIENT, path="title.txt") +_message = "" +_ticker = "" +_title = "" @router.on_event("startup") async def on_startup(): - _logger.debug("text router startup") + global _message, _ticker, _title - _message.refresh() - _ticker.refresh() - _title.refresh() + _message = DavFile(client=CLIENT, path="message.txt") + _ticker = DavFile(client=CLIENT, path="ticker.txt") + _title = DavFile(client=CLIENT, path="title.txt") + DavFile.refresh(60) + + _logger.debug("text router started") @router.get("/message") diff --git a/api/poetry.lock b/api/poetry.lock index 69fe29d..bed86de 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -15,6 +15,32 @@ doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] trio = ["trio (>=0.16)"] +[[package]] +name = "apscheduler" +version = "3.9.1" +description = "In-process task scheduler with Cron-like capabilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.dependencies] +pytz = "*" +six = ">=1.4.0" +tzlocal = ">=2.0,<3.0.0 || >=4.0.0" + +[package.extras] +asyncio = ["trollius"] +doc = ["sphinx", "sphinx-rtd-theme"] +gevent = ["gevent"] +mongodb = ["pymongo (>=3.0)"] +redis = ["redis (>=3.0)"] +rethinkdb = ["rethinkdb (>=2.4.0)"] +sqlalchemy = ["sqlalchemy (>=0.8)"] +testing = ["mock", "pytest", "pytest-asyncio", "pytest-asyncio (<0.6)", "pytest-cov", "pytest-tornado5"] +tornado = ["tornado (>=4.3)"] +twisted = ["twisted"] +zookeeper = ["kazoo"] + [[package]] name = "certifi" version = "2022.6.15" @@ -169,6 +195,25 @@ python-versions = ">=3.5" [package.extras] cli = ["click (>=5.0)"] +[[package]] +name = "pytz" +version = "2022.2.1" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pytz-deprecation-shim" +version = "0.1.0.post0" +description = "Shims to make deprecation of pytz easier" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" + +[package.dependencies] +tzdata = {version = "*", markers = "python_version >= \"3.6\""} + [[package]] name = "requests" version = "2.28.1" @@ -226,6 +271,30 @@ category = "main" optional = false python-versions = ">=3.7" +[[package]] +name = "tzdata" +version = "2022.2" +description = "Provider of IANA time zone data" +category = "main" +optional = false +python-versions = ">=2" + +[[package]] +name = "tzlocal" +version = "4.2" +description = "tzinfo object for the local timezone" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pytz-deprecation-shim = "*" +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["black", "pyroma", "pytest-cov", "zest.releaser"] +test = ["pytest (>=4.3)", "pytest-mock (>=3.3)"] + [[package]] name = "urllib3" version = "1.26.12" @@ -282,13 +351,17 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>= [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "a8edb56f5824246d8a490c280bf11318d1efa11d6109b4982b8adf15b391d587" +content-hash = "136b9208bffca16de395a3444ca9d172d7e6d7e40866eea987174fa7b69822c7" [metadata.files] anyio = [ {file = "anyio-3.6.1-py3-none-any.whl", hash = "sha256:cb29b9c70620506a9a8f87a309591713446953302d7d995344d0d7c6c0c9a7be"}, {file = "anyio-3.6.1.tar.gz", hash = "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b"}, ] +apscheduler = [ + {file = "APScheduler-3.9.1-py2.py3-none-any.whl", hash = "sha256:ddc25a0ddd899de44d7f451f4375fb971887e65af51e41e5dcf681f59b8b2c9a"}, + {file = "APScheduler-3.9.1.tar.gz", hash = "sha256:65e6574b6395498d371d045f2a8a7e4f7d50c6ad21ef7313d15b1c7cf20df1e3"}, +] certifi = [ {file = "certifi-2022.6.15-py3-none-any.whl", hash = "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412"}, {file = "certifi-2022.6.15.tar.gz", hash = "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d"}, @@ -442,6 +515,14 @@ python-dotenv = [ {file = "python-dotenv-0.20.0.tar.gz", hash = "sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f"}, {file = "python_dotenv-0.20.0-py3-none-any.whl", hash = "sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938"}, ] +pytz = [ + {file = "pytz-2022.2.1-py2.py3-none-any.whl", hash = "sha256:220f481bdafa09c3955dfbdddb7b57780e9a94f5127e35456a48589b9e0c0197"}, + {file = "pytz-2022.2.1.tar.gz", hash = "sha256:cea221417204f2d1a2aa03ddae3e867921971d0d76f14d87abb4414415bbdcf5"}, +] +pytz-deprecation-shim = [ + {file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"}, + {file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"}, +] requests = [ {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, @@ -462,6 +543,14 @@ typing-extensions = [ {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, ] +tzdata = [ + {file = "tzdata-2022.2-py2.py3-none-any.whl", hash = "sha256:c3119520447d68ef3eb8187a55a4f44fa455f30eb1b4238fa5691ba094f2b05b"}, + {file = "tzdata-2022.2.tar.gz", hash = "sha256:21f4f0d7241572efa7f7a4fdabb052e61b55dc48274e6842697ccdf5253e5451"}, +] +tzlocal = [ + {file = "tzlocal-4.2-py3-none-any.whl", hash = "sha256:89885494684c929d9191c57aa27502afc87a579be5cdd3225c77c463ea043745"}, + {file = "tzlocal-4.2.tar.gz", hash = "sha256:ee5842fa3a795f023514ac2d801c4a81d1743bbe642e3940143326b3a00addd7"}, +] urllib3 = [ {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, diff --git a/api/pyproject.toml b/api/pyproject.toml index d58b7ff..a3565dd 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -11,6 +11,7 @@ python = "^3.9" uvicorn = "^0.18.3" webdavclient3 = "3.14.5" Markdown = "^3.4.1" +APScheduler = "^3.9.1" [tool.poetry.dev-dependencies] # pytest = "^5.2"