diff --git a/README.md b/README.md index 90c0df2..12b8cf3 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ +# ReVanced Releases API + ![License: AGPLv3](https://img.shields.io/github/license/alexandreteles/revanced-releases-api) ![GitHub last commit](https://img.shields.io/github/last-commit/alexandreteles/revanced-releases-api) ![GitHub Workflow Status](https://img.shields.io/github/workflow/status/alexandreteles/revanced-releases-api/Main%20build) -# ReVanced Releases API - This is a simple API that returns the latest ReVanced releases. ## Usage The API is available at [https://revanced-releases-api.afterst0rm.xyz/](https://revanced-releases-api.afterst0rm.xyz/). -For development purposes, you can run the API locally by cloning this repository and running `docker-compose up` or `docker-compose up --build` if you want to rebuild the image. Optionally you can run the application without Docker by running `pip -U install -r ./requirements.txt` and `python ./main.py`. Remember to set the environment variable `GITHUB_TOKEN` to a valid token if you want to run the API locally. +For development purposes, you can run the API locally by cloning this repository and running `docker-compose up` or `docker-compose up --build` if you want to rebuild the image. Optionally you can run the application without Docker by running `pip -U install -r ./requirements.txt` and `python ./main.py`. Remember to set the environment variable `GITHUB_TOKEN` to a valid token if you want to run the API locally and make sure to have a `redis` instance running. ### API Endpoints diff --git a/config.toml b/config.toml index deb27af..2b483cd 100644 --- a/config.toml +++ b/config.toml @@ -8,15 +8,22 @@ Changelogs are not included but can be found on the [ReVanced Repositories](http The team also have a [Discord Server](https://revanced.app/discord) if you need help. -### API Endpoints +## API Endpoints * [apps](/apps) - Returns all currently patchable apps * [tools](/tools) - Returns the latest version of all ReVanced tools and Vanced MicroG * [patches](/patches) - Returns the latest version of all ReVanced patches -There is no cache on this API because we trust our fellow developers to implement a cache on their end. +## Additional Information -So please be kind and don't blow up the API with requests or we will have to block your IP address. +* Rate Limiting - 15 requests per minute +* Cache - 1 minute + +## Important Notes + +1. Although we will try to avoid breaking changes, we can't guarantee that it won't happen. +2. Okay, the api is now cached and rate limited (per endpoint). But please don't abuse it, we don't want to have to block you. +3. Make sure to implement a cache system on your end to avoid unnecessary requests. Godspeed 💀 @@ -37,6 +44,9 @@ port = 8000 limit = "15/minute" +[cache] +expire = 60 + [app] repositories = ["TeamVanced/VancedMicroG", "revanced/revanced-cli", "revanced/revanced-patches", "revanced/revanced-integrations"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index c84108a..b9cea9c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,27 @@ version: "3.8" services: + redis: + container_name: revanced-releases-api-redis + image: redis:latest + volumes: + - redis-data:/data + networks: + - infra + restart: always revanced-releases-api: container_name: revanced-releases-api image: alexandreteles/revanced-releases-api:latest - restart: always + environment: + - REDIS_HOST=revanced-releases-api-redis + - REDIS_PORT=6379 + - GITHUB_TOKEN=YOUR_GITHUB_TOKEN + ports: + - 127.0.0.1:7934:8000 + networks: + - infra + restart: unless-stopped + +networks: + infra: + external: true \ No newline at end of file diff --git a/main.py b/main.py index 03518c0..7af90e1 100755 --- a/main.py +++ b/main.py @@ -1,7 +1,9 @@ #!/usr/bin/env python3 +import os import toml import uvicorn +import aioredis from fastapi import FastAPI, Request, Response from modules.Releases import Releases from fastapi.responses import RedirectResponse @@ -12,13 +14,20 @@ from slowapi.errors import RateLimitExceeded from fastapi_cache import FastAPICache from fastapi_cache.backends.redis import RedisBackend from fastapi_cache.decorator import cache -import aioredis """Get latest ReVanced releases from GitHub API.""" # Load config -config = toml.load("config.toml") +config: dict = toml.load("config.toml") + +# Redis connection parameters + +redis_config: dict[ str, str | int ] = { + "url": f"redis://{os.environ['REDIS_URL']}", + "port": os.environ['REDIS_PORT'], + "collection": 0 +} # Create releases instance @@ -42,7 +51,7 @@ app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler) # Setup cache @cache() -async def get_cache(): +async def get_cache() -> int: return 1 # Routes @@ -59,7 +68,7 @@ async def root(request: Request, response: Response) -> RedirectResponse: @app.get('/tools', response_model=ResponseModels.ToolsResponseModel) @limiter.limit(config['slowapi']['limit']) -@cache(expire=60) +@cache(config['cache']['expire']) async def tools(request: Request, response: Response) -> dict: """Get patching tools' latest version. @@ -70,7 +79,7 @@ async def tools(request: Request, response: Response) -> dict: @app.get('/apps', response_model=ResponseModels.AppsResponseModel) @limiter.limit(config['slowapi']['limit']) -@cache(expire=60) +@cache(config['cache']['expire']) async def apps(request: Request, response: Response) -> dict: """Get patchable apps. @@ -81,7 +90,7 @@ async def apps(request: Request, response: Response) -> dict: @app.get('/patches', response_model=ResponseModels.PatchesResponseModel) @limiter.limit(config['slowapi']['limit']) -@cache(expire=60) +@cache(config['cache']['expire']) async def patches(request: Request, response: Response) -> dict: """Get latest patches. @@ -92,9 +101,12 @@ async def patches(request: Request, response: Response) -> dict: return await releases.get_patches_json() @app.on_event("startup") -async def startup(): - redis = aioredis.from_url("redis://localhost", encoding="utf8", decode_responses=True) +async def startup() -> None: + redis_url = f"{redis_config['url']}:{redis_config['port']}/{redis_config['collection']}" + redis = aioredis.from_url(redis_url, encoding="utf8", decode_responses=True) FastAPICache.init(RedisBackend(redis), prefix="fastapi-cache") + + return None # Run app if __name__ == '__main__': diff --git a/modules/ResponseFields.py b/modules/ResponseFields.py index d5e3088..ba71048 100644 --- a/modules/ResponseFields.py +++ b/modules/ResponseFields.py @@ -18,7 +18,7 @@ class CompatiblePackagesResponseFields(BaseModel): BaseModel (pydantic.BaseModel): BaseModel from pydantic """ name: str - verstions: list[ str ] | None + versions: list[ str ] | None class PatchesResponseFields(BaseModel): """Implements the fields for the /patches endpoint. diff --git a/portainer-stack.yml b/portainer-stack.yml index 1a778b1..c7423d1 100644 --- a/portainer-stack.yml +++ b/portainer-stack.yml @@ -1,13 +1,24 @@ --- version: "3.8" + services: + redis: + container_name: revanced-releases-api-redis + image: redis:latest + volumes: + - redis-data:/data + networks: + - infra + restart: always revanced-releases-api: - image: alexandreteles/revanced-releases-api:latest container_name: revanced-releases-api + image: alexandreteles/revanced-releases-api:latest environment: - - GITHUB_TOKEN= + - REDIS_HOST=revanced-releases-api-redis + - REDIS_PORT=6379 + - GITHUB_TOKEN=YOUR_GITHUB_TOKEN ports: - - 127.0.0.1:8000:8000 + - 127.0.0.1:7934:8000 networks: - infra restart: unless-stopped