diff --git a/plugin_store/api/__init__.py b/plugin_store/api/__init__.py index ea69cdf..7282c01 100644 --- a/plugin_store/api/__init__.py +++ b/plugin_store/api/__init__.py @@ -13,7 +13,7 @@ from cdn import upload_image, upload_version from constants import SortDirection, SortType, TEMPLATES_DIR -from database.database import database, Database +from database.database import database, Database, database_fake, fill_cache from database.models import Announcement from discord import post_announcement @@ -45,6 +45,9 @@ increment_limit_per_plugin = parse("2/day") rate_limit = strategies.FixedWindowRateLimiter(rate_limit_storage) +@app.on_event("startup") +async def startup_event(): + await fill_cache() @app.exception_handler(HTTPException) async def http_exception_handler(request: "Request", exc: "HTTPException") -> "Response": @@ -140,18 +143,17 @@ async def delete_announcement( ): await db.delete_announcement(announcement_id) - @app.get("/plugins", response_model=list[api_list.ListPluginResponse]) async def plugins_list( query: str = "", tags: list[str] = fastapi.Query(default=[]), hidden: bool = False, sort_by: Optional[SortType] = None, - sort_direction: SortDirection = SortDirection.ASC, - db: "Database" = Depends(database), + sort_direction: SortDirection = SortDirection.DESC, + db: "Database" = Depends(database_fake), ): tags = list(filter(None, reduce(add, (el.split(",") for el in tags), []))) - plugins = await db.search(db.session, query, tags, hidden, sort_by, sort_direction) + plugins = await db.search(query, hidden, sort_by, sort_direction) return plugins diff --git a/plugin_store/database/database.py b/plugin_store/database/database.py index 058359b..905e656 100644 --- a/plugin_store/database/database.py +++ b/plugin_store/database/database.py @@ -5,6 +5,7 @@ from typing import Optional, TYPE_CHECKING from uuid import UUID from zoneinfo import ZoneInfo +from time import time from alembic import command from alembic.config import Config @@ -39,7 +40,8 @@ AsyncSessionLocal = async_sessionmaker(bind=async_engine, autoflush=False, future=True, expire_on_commit=False) db_lock = Lock() - +plugin_cache = [] +last_time = 0 async def get_session() -> "AsyncIterator[AsyncSession]": try: @@ -47,9 +49,8 @@ async def get_session() -> "AsyncIterator[AsyncSession]": except SQLAlchemyError as e: logger.exception(e) - async def database(session: "AsyncSession" = Depends(get_session)) -> "AsyncIterator[Database]": - db = Database(session, db_lock) + db = Database(session, db_lock, plugin_cache) try: yield db except Exception: @@ -58,11 +59,23 @@ async def database(session: "AsyncSession" = Depends(get_session)) -> "AsyncIter else: await session.close() +async def database_fake() -> "AsyncIterator[Database]": + db = Database(None, db_lock, plugin_cache) + try: + yield db + except Exception: + raise + +async def fill_cache(): + db = Database(AsyncSessionLocal(), db_lock, plugin_cache) + await db.update_cache(db.session) + await db.session.close() class Database: - def __init__(self, session, lock): + def __init__(self, session, lock, plugin_cache): self.session = session self.lock = lock + self.plugin_cache: list = plugin_cache @sync_to_async() def init(self): @@ -166,6 +179,7 @@ async def insert_artifact( await nested.rollback() raise await session.commit() + await self.update_cache(session) return await self.get_plugin_by_id(session, plugin.id) async def update_artifact(self, session: "AsyncSession", plugin: "Artifact", **kwargs) -> "Artifact": @@ -185,6 +199,7 @@ async def update_artifact(self, session: "AsyncSession", plugin: "Artifact", **k await nested.rollback() raise await session.commit() + await self.update_cache(session) return await self.get_plugin_by_id(session, plugin.id) async def insert_version( @@ -201,7 +216,7 @@ async def insert_version( await session.commit() return version - async def search( + async def _search( self, session: "AsyncSession", name: "str | None" = None, @@ -237,6 +252,21 @@ async def search( result = (await session.execute(statement)).scalars().all() return result or [] + + async def update_cache(self, session): + self.plugin_cache.clear() + self.plugin_cache.extend(await self._search(session, limit=500, include_hidden=True)) + + async def search( + self, + name: "str | None" = "", + include_hidden: "bool" = False, + sort_by: Optional[SortType] = None, + sort_direction: SortDirection = SortDirection.DESC + ) -> "Sequence[Artifact]": + sort_key = {SortType.NAME: "name", SortType.DOWNLOADS: "downloads", SortType.DATE: "created", "id": "id"}[sort_by or "id"] + return sorted([i for i in self.plugin_cache if i.visible is not include_hidden and name.lower() in i.name.lower()], + key=lambda x: getattr(x, sort_key), reverse=sort_direction==SortDirection.ASC) async def get_plugin_by_name(self, session: "AsyncSession", name: str) -> "Artifact | None": statement = select(Artifact).where(Artifact.name == name) @@ -253,7 +283,9 @@ async def delete_plugin(self, session: "AsyncSession", id: int): await session.execute(delete(PluginTag).where(PluginTag.c.artifact_id == id)) await session.execute(delete(Version).where(Version.artifact_id == id)) await session.execute(delete(Artifact).where(Artifact.id == id)) - return await session.commit() + r = await session.commit() + await self.update_cache(session) + return r async def increment_installs( self, session: "AsyncSession", plugin_name: str, version_name: str, isUpdate: bool @@ -269,4 +301,7 @@ async def increment_installs( r = await session.execute(statement.where((Version.name == version_name) & (Version.artifact_id == plugin_id))) await session.commit() # if rowcount is zero then the version wasn't found - return r.rowcount == 1 # type: ignore[attr-defined] + v = r.rowcount == 1 # type: ignore[attr-defined] +# if v: +# await self.update_cache(session) + return v \ No newline at end of file