Alexandre Teles 3b418197c2
feat: implements cdn mirrors endpoints, fix docs, move endpoints to custom routers (#18)
* feat: resolves #5, resolves #4 (#7)

* Implements client generation and management

* fix announcements endpoints

* change annoucements model

* bump deps

* sync with main

* refactor: adopt some functional standards in Releases.py

* feat: add new workflows

* chore: remove unused files

* refactor: update build badge

* refactor: move files around and delete unused ones

* feat: add authentication endpoints

* refactor: clean up code on Clients.py controller

* fix: fix the client secret update endpoint

* refactor: clean up authentication code

* feat: add authentication to client endpoints

* chore: bump deps

* feat: add admin user generation

* feature: add /changelogs endpoint (#10)

* feat: move endpoints into custom routers, resolves #12 (#14)

* refactor: import routers from old branch

* refactor: import InternalCache removal

* refactor: move routes into dedicated routers

* fix: fixes entrypoint

* refactor: add documentation and bump libs

* docs: update description (#16)

* feat: implement cdn mirrors endpoints, closes #15 (#17)

* feat: add cdn mirror endpoints

* refactor: change API version in docs

* docs: fix titles on API docs page

Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-10-13 01:48:07 -03:00

158 lines
4.4 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import toml
import binascii
from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse, UJSONResponse
from slowapi.util import get_remote_address
from slowapi.middleware import SlowAPIMiddleware
from slowapi import Limiter, _rate_limit_exceeded_handler
from fastapi_cache import FastAPICache
from fastapi_cache.decorator import cache
from slowapi.errors import RateLimitExceeded
from fastapi_cache.backends.redis import RedisBackend
from fastapi_paseto_auth import AuthPASETO
from fastapi_paseto_auth.exceptions import AuthPASETOException
import app.controllers.Auth as Auth
from app.controllers.Clients import Clients
from app.utils.RedisConnector import RedisConnector
import app.models.GeneralErrors as GeneralErrors
from app.routers import root
from app.routers import ping
from app.routers import auth
from app.routers import tools
from app.routers import clients
from app.routers import patches
from app.routers import mirrors
from app.routers import changelogs
from app.routers import contributors
from app.routers import announcement
"""Get latest ReVanced releases from GitHub API."""
# Load config
config: dict = toml.load("config.toml")
# Create FastAPI instance
app = FastAPI(title=config['docs']['title'],
description=config['docs']['description'],
version=config['docs']['version'],
license_info={"name": config['license']['name'],
"url": config['license']['url']
},
default_response_class=UJSONResponse
)
# Hook up rate limiter
limiter = Limiter(key_func=get_remote_address,
default_limits=[
config['slowapi']['limit']
],
headers_enabled=True,
storage_uri=f"redis://{os.environ['REDIS_URL']}:{os.environ['REDIS_PORT']}/{config['slowapi']['database']}"
)
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
app.add_middleware(SlowAPIMiddleware)
# Setup routes
app.include_router(root.router)
app.include_router(tools.router)
app.include_router(patches.router)
app.include_router(contributors.router)
app.include_router(changelogs.router)
app.include_router(auth.router)
app.include_router(clients.router)
app.include_router(announcement.router)
app.include_router(mirrors.router)
app.include_router(ping.router)
# Setup cache
@cache()
async def get_cache() -> int:
"""Get cache TTL from config.
Returns:
int: Cache TTL
"""
return 1
# Setup PASETO
@AuthPASETO.load_config
def get_config() -> Auth.PasetoSettings:
"""Get PASETO config from Auth module
Returns:
PasetoSettings: PASETO config
"""
return Auth.PasetoSettings()
# Setup custom error handlers
@app.exception_handler(AuthPASETOException)
async def authpaseto_exception_handler(request: Request, exc: AuthPASETOException) -> JSONResponse:
"""Handle AuthPASETOException
Args:
request (Request): Request
exc (AuthPASETOException): Exception
Returns:
JSONResponse: Response
"""
return JSONResponse(status_code=exc.status_code, content={"detail": exc.message})
@app.exception_handler(AttributeError)
async def validation_exception_handler(request, exc) -> JSONResponse:
"""Handle AttributeError
Args:
request (Request): Request
exc (AttributeError): Exception
Returns:
JSONResponse: Response
"""
return JSONResponse(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content={
"error": "Unprocessable Entity"
})
@app.exception_handler(binascii.Error)
async def invalid_token_exception_handler(request, exc) -> JSONResponse:
"""Handle binascii.Error
Args:
request (Request): Request
exc (binascii.Error): Exception
Returns:
JSONResponse: Response
"""
return JSONResponse(status_code=status.HTTP_401_UNAUTHORIZED, content={
"error": GeneralErrors.Unauthorized().error,
"message": GeneralErrors.Unauthorized().message
})
@app.on_event("startup")
async def startup() -> None:
"""Startup event handler"""
clients = Clients()
await clients.setup_admin()
FastAPICache.init(RedisBackend(RedisConnector.connect(config['cache']['database'])),
prefix="fastapi-cache")
return None