Merge pull request #53 from revanced/dev

New Feature Pack
This commit is contained in:
Alexandre Teles 2022-12-26 19:41:41 -03:00 committed by GitHub
commit 6060dd744a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 801 additions and 614 deletions

View File

@ -1,4 +1,4 @@
ARG VARIANT="3.10-bullseye" ARG VARIANT="3.11-bullseye"
FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT} FROM mcr.microsoft.com/vscode/devcontainers/python:0-${VARIANT}
ARG NODE_VERSION="none" ARG NODE_VERSION="none"

View File

@ -9,7 +9,7 @@
// Update 'VARIANT' to pick a Python version: 3, 3.10, 3.9, 3.8, 3.7, 3.6 // Update 'VARIANT' to pick a Python version: 3, 3.10, 3.9, 3.8, 3.7, 3.6
// Append -bullseye or -buster to pin to an OS version. // Append -bullseye or -buster to pin to an OS version.
// Use -bullseye variants on local on arm64/Apple Silicon. // Use -bullseye variants on local on arm64/Apple Silicon.
"VARIANT": "3.10-bullseye", "VARIANT": "3.11-bullseye",
// Options // Options
"NODE_VERSION": "lts/*" "NODE_VERSION": "lts/*"
} }

View File

@ -35,7 +35,7 @@ jobs:
- name: Set up Python - name: Set up Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: '3.10.7' python-version: '3.11.0'
- name: Install dependencies - name: Install dependencies
run: | run: |
python -m pip install --upgrade pip python -m pip install --upgrade pip

View File

@ -12,7 +12,7 @@ jobs:
- name: Setup Python - name: Setup Python
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: 3.10.8 python-version: 3.11.0
architecture: x64 architecture: x64
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3

View File

@ -1,4 +1,4 @@
FROM python:3.10-slim FROM python:3.11-slim
ARG GITHUB_TOKEN ARG GITHUB_TOKEN
ENV GITHUB_TOKEN $GITHUB_TOKEN ENV GITHUB_TOKEN $GITHUB_TOKEN

View File

@ -8,7 +8,7 @@ This is a simple API that returns the latest ReVanced releases, patches and cont
## Usage ## Usage
The API is available at [https://releases.rvcd.win/](https://releases.rvcd.win/). The API is available at [https://releases.revanced.app/](https://releases.revanced.app/).
You can deploy your own instance by cloning this repository, editing the `docker-compose.yml` file to include your GitHub token and running `docker-compose up` or `docker-compose up --build` if you want to build the image locally instead of pulling from GHCR. Optionally you can run the application without Docker by running `poetry install` and `poetry run ./run.sh`. In this case, you'll also need a redis server and setup the following environment variables on your system. You can deploy your own instance by cloning this repository, editing the `docker-compose.yml` file to include your GitHub token and running `docker-compose up` or `docker-compose up --build` if you want to build the image locally instead of pulling from GHCR. Optionally you can run the application without Docker by running `poetry install` and `poetry run ./run.sh`. In this case, you'll also need a redis server and setup the following environment variables on your system.
@ -27,10 +27,10 @@ If you don't have a Sentry instance, we recommend using [GlitchTip](https://glit
### API Endpoints ### API Endpoints
* [tools](https://releases.rvcd.win/tools) - Returns the latest version of all ReVanced tools and Vanced MicroG * [tools](https://releases.revanced.app/tools) - Returns the latest version of all ReVanced tools and Vanced MicroG
* [patches](https://releases.rvcd.win/patches) - Returns the latest version of all ReVanced patches * [patches](https://releases.revanced.app/patches) - Returns the latest version of all ReVanced patches
* [contributors](https://releases.rvcd.win/contributors) - Returns contributors for all ReVanced projects * [contributors](https://releases.revanced.app/contributors) - Returns contributors for all ReVanced projects
* [announcement](https://releases.rvcd.win/announcement) - Returns the latest announcement for the ReVanced projects * [announcement](https://releases.revanced.app/announcement) - Returns the latest announcement for the ReVanced projects
## Clients ## Clients

View File

@ -1,4 +1,4 @@
import toml
from redis import asyncio as aioredis from redis import asyncio as aioredis
import app.utils.Logger as Logger import app.utils.Logger as Logger
@ -6,7 +6,9 @@ from app.utils.Generators import Generators
from app.models.AnnouncementModels import AnnouncementCreateModel from app.models.AnnouncementModels import AnnouncementCreateModel
from app.utils.RedisConnector import RedisConnector from app.utils.RedisConnector import RedisConnector
config: dict = toml.load("config.toml") from app.dependencies import load_config
config: dict = load_config()
class Announcements: class Announcements:
"""Implements the announcements class for the ReVanced API""" """Implements the announcements class for the ReVanced API"""

View File

@ -1,11 +1,13 @@
from datetime import timedelta from datetime import timedelta
import os import os
import toml
from datetime import timedelta from datetime import timedelta
from pydantic import BaseModel from pydantic import BaseModel
from fastapi_paseto_auth import AuthPASETO from fastapi_paseto_auth import AuthPASETO
config: dict = toml.load("config.toml") from app.dependencies import load_config
config: dict = load_config()
class PasetoSettings(BaseModel): class PasetoSettings(BaseModel):
authpaseto_secret_key: str = os.environ['SECRET_KEY'] authpaseto_secret_key: str = os.environ['SECRET_KEY']

View File

@ -1,5 +1,5 @@
from time import sleep from time import sleep
import toml
import orjson import orjson
from typing import Optional from typing import Optional
import argon2 import argon2
@ -12,7 +12,9 @@ from app.utils.Generators import Generators
from app.models.ClientModels import ClientModel from app.models.ClientModels import ClientModel
from app.utils.RedisConnector import RedisConnector from app.utils.RedisConnector import RedisConnector
config: dict = toml.load("config.toml") from app.dependencies import load_config
config: dict = load_config()
class Clients: class Clients:

View File

@ -1,10 +1,12 @@
import toml
from redis import asyncio as aioredis from redis import asyncio as aioredis
import app.utils.Logger as Logger import app.utils.Logger as Logger
from app.models.MirrorModels import MirrorModel, MirrorStoreModel from app.models.MirrorModels import MirrorModel, MirrorStoreModel
from app.utils.RedisConnector import RedisConnector from app.utils.RedisConnector import RedisConnector
config: dict = toml.load("config.toml") from app.dependencies import load_config
config: dict = load_config()
class Mirrors: class Mirrors:
"""Implements the Mirror class for the ReVanced API""" """Implements the Mirror class for the ReVanced API"""

View File

@ -1,11 +1,11 @@
from toolz.dicttoolz import keyfilter
import asyncio import asyncio
import uvloop import uvloop
import orjson import orjson
from base64 import b64decode from base64 import b64decode
from toolz.dicttoolz import keyfilter
import asyncstdlib.builtins as a
from app.utils.HTTPXClient import HTTPXClient from app.utils.HTTPXClient import HTTPXClient
class Releases: class Releases:
"""Implements the methods required to get the latest releases and patches from revanced repositories.""" """Implements the methods required to get the latest releases and patches from revanced repositories."""
@ -15,13 +15,14 @@ class Releases:
httpx_client = HTTPXClient.create() httpx_client = HTTPXClient.create()
async def __get_release(self, repository: str) -> list: async def __get_release(self, repository: str) -> list:
# Get assets from latest release in a given repository. """Get assets from latest release in a given repository.
#
# Args: Args:
# repository (str): Github's standard username/repository notation repository (str): Github's standard username/repository notation
#
# Returns: Returns:
# dict: dictionary of filename and download url dict: dictionary of filename and download url
"""
assets: list = [] assets: list = []
response = await self.httpx_client.get(f"https://api.github.com/repos/{repository}/releases/latest") response = await self.httpx_client.get(f"https://api.github.com/repos/{repository}/releases/latest")
@ -32,24 +33,28 @@ class Releases:
release_tarball: str = response.json()['tarball_url'] release_tarball: str = response.json()['tarball_url']
release_timestamp: str = response.json()['published_at'] release_timestamp: str = response.json()['published_at']
if release_assets: async def get_asset_data(asset: dict) -> dict:
for asset in release_assets: return {'repository': repository,
assets.append({ 'repository': repository,
'version': release_version, 'version': release_version,
'timestamp': asset['updated_at'], 'timestamp': asset['updated_at'],
'name': asset['name'], 'name': asset['name'],
'size': asset['size'], 'size': asset['size'],
'browser_download_url': asset['browser_download_url'], 'browser_download_url': asset['browser_download_url'],
'content_type': asset['content_type'] 'content_type': asset['content_type']
}) }
if release_assets:
assets = await asyncio.gather(*[get_asset_data(asset) for asset in release_assets])
else: else:
assets.append({ 'repository': repository, no_release_assets_data: dict = {'repository': repository,
'version': release_version, 'version': release_version,
'timestamp': release_timestamp, 'timestamp': release_timestamp,
'name': f"{repository.split('/')[1]}-{release_version}.tar.gz", 'name': f"{repository.split('/')[1]}-{release_version}.tar.gz",
'browser_download_url': release_tarball, 'browser_download_url': release_tarball,
'content_type': 'application/gzip' 'content_type': 'application/gzip'
}) }
assets.append(no_release_assets_data)
return assets return assets
async def get_latest_releases(self, repositories: list) -> dict: async def get_latest_releases(self, repositories: list) -> dict:
@ -67,21 +72,20 @@ class Releases:
results: list = await asyncio.gather(*[self.__get_release(repository) for repository in repositories]) results: list = await asyncio.gather(*[self.__get_release(repository) for repository in repositories])
for result in results: releases['tools'] = [asset for result in results for asset in result]
for asset in result:
releases['tools'].append(asset)
return releases return releases
async def __get_patches_json(self) -> dict: async def __get_patches_json(self) -> dict:
# Get revanced-patches repository's README.md. """Get revanced-patches repository's README.md.
#
# Returns: Returns:
# dict: JSON content dict: JSON content
# """
response = await self.httpx_client.get(f"https://api.github.com/repos/revanced/revanced-patches/contents/patches.json") response = await self.httpx_client.get(f"https://api.github.com/repos/revanced/revanced-patches/contents/patches.json")
content = orjson.loads(b64decode(response.json()['content']).decode('utf-8')) content = orjson.loads(
b64decode(response.json()['content']).decode('utf-8'))
return content return content
@ -91,26 +95,29 @@ class Releases:
Returns: Returns:
dict: Patches available for a given app dict: Patches available for a given app
""" """
patches: dict = await self.__get_patches_json() patches: dict = await self.__get_patches_json()
return patches return patches
async def __get_contributors(self, repository: str) -> list: async def __get_contributors(self, repository: str) -> list:
# Get contributors from a given repository. """Get contributors from a given repository.
#
# Args:
# repository (str): Github's standard username/repository notation
#
# Returns:
# list: a list of dictionaries containing the repository's contributors
keep: set = {'login', 'avatar_url', 'html_url'} Args:
repository (str): Github's standard username/repository notation
Returns:
list: a list of dictionaries containing the repository's contributors
"""
keep: set = {'login', 'avatar_url', 'html_url', 'contributions'}
response = await self.httpx_client.get(f"https://api.github.com/repos/{repository}/contributors") response = await self.httpx_client.get(f"https://api.github.com/repos/{repository}/contributors")
# Looping over each contributor, filtering each contributor so that
# keyfilter() returns a dictionary with only the key-value pairs that are in the "keep" set.
contributors: list = [keyfilter(lambda k: k in keep, contributor) for contributor in response.json()] contributors: list = [keyfilter(lambda k: k in keep, contributor) for contributor in response.json()]
return contributors return contributors
async def get_contributors(self, repositories: list) -> dict: async def get_contributors(self, repositories: list) -> dict:
@ -128,11 +135,12 @@ class Releases:
contributors = {} contributors = {}
contributors['repositories'] = [] contributors['repositories'] = []
revanced_repositories = [repository for repository in repositories if 'revanced' in repository] revanced_repositories = [
repository for repository in repositories if 'revanced' in repository]
results: list[dict] = await asyncio.gather(*[self.__get_contributors(repository) for repository in revanced_repositories]) results: list[dict] = await asyncio.gather(*[self.__get_contributors(repository) for repository in revanced_repositories])
for key, value in zip(revanced_repositories, results): async for key, value in a.zip(revanced_repositories, results):
data = {'name': key, 'contributors': value} data = {'name': key, 'contributors': value}
contributors['repositories'].append(data) contributors['repositories'].append(data)
@ -165,25 +173,35 @@ class Releases:
f"https://api.github.com/repos/{org}/{repository}/releases?per_page=2" f"https://api.github.com/repos/{org}/{repository}/releases?per_page=2"
) )
if _releases.status_code == 200:
releases = _releases.json() releases = _releases.json()
if any(releases):
since = releases[1]['created_at'] since = releases[1]['created_at']
until = releases[0]['created_at'] until = releases[0]['created_at']
else:
raise ValueError("No releases found")
_response = await self.httpx_client.get( _response = await self.httpx_client.get(
f"https://api.github.com/repos/{org}/{repository}/commits?path={path}&since={since}&until={until}" f"https://api.github.com/repos/{org}/{repository}/commits?path={path}&since={since}&until={until}"
) )
if _response.status_code == 200:
response = _response.json() response = _response.json()
for commit in response: async def get_commit_data(commit: dict) -> dict:
data: dict[str, str] = {} return {'sha': commit['sha'],
data["sha"] = commit["sha"] 'author': commit['commit']['author']['name'],
data["author"] = commit["commit"]["author"]["name"] 'date': commit['commit']['author']['date'],
data["message"] = commit["commit"]["message"] 'message': commit['commit']['message'],
data["html_url"] = commit["html_url"] 'url': commit['html_url']
}
data: list = await asyncio.gather(*[get_commit_data(commit) for commit in response])
payload['commits'].append(data) payload['commits'].append(data)
else:
raise ValueError("Error retrieving commits")
else:
raise ValueError("Invalid organization.")
return payload return payload
else:
raise Exception("Invalid organization.")

View File

@ -0,0 +1,18 @@
from app.dependencies import load_config
config: dict = load_config()
class Socials:
"""Implements the code infrastructure for the socials page."""
async def get_socials(self) -> dict:
"""Get socials from config.toml.
Returns:
dict: A dictionary containing socials from config.toml
"""
socials: dict = config['socials']
return socials

View File

@ -1,4 +1,4 @@
import toml import tomllib as toml
def load_config() -> dict: def load_config() -> dict:
"""Loads the config.toml file. """Loads the config.toml file.
@ -6,4 +6,7 @@ def load_config() -> dict:
Returns: Returns:
dict: the config.toml file as a dict dict: the config.toml file as a dict
""" """
return toml.load("config.toml")
with open('config.toml', 'rb') as config_file:
return toml.load(config_file)

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import toml
import binascii import binascii
from redis import Redis from redis import Redis
@ -34,15 +34,18 @@ from app.routers import tools
from app.routers import clients from app.routers import clients
from app.routers import patches from app.routers import patches
from app.routers import mirrors from app.routers import mirrors
from app.routers import socials
from app.routers import changelogs from app.routers import changelogs
from app.routers import contributors from app.routers import contributors
from app.routers import announcement from app.routers import announcement
from app.dependencies import load_config
"""Get latest ReVanced releases from GitHub API.""" """Get latest ReVanced releases from GitHub API."""
# Load config # Load config
config: dict = toml.load("config.toml") config: dict = load_config()
# Create FastAPI instance # Create FastAPI instance
@ -74,6 +77,7 @@ app.include_router(tools.router)
app.include_router(patches.router) app.include_router(patches.router)
app.include_router(contributors.router) app.include_router(contributors.router)
app.include_router(changelogs.router) app.include_router(changelogs.router)
app.include_router(socials.router)
app.include_router(auth.router) app.include_router(auth.router)
app.include_router(clients.router) app.include_router(clients.router)
app.include_router(announcement.router) app.include_router(announcement.router)

View File

@ -53,6 +53,7 @@ class ContributorFields(BaseModel):
login: str login: str
avatar_url: str avatar_url: str
html_url: str html_url: str
contributions: int
class ContributorsResponseFields(BaseModel): class ContributorsResponseFields(BaseModel):
"""Implements the fields for each repository in the /contributors endpoint """Implements the fields for each repository in the /contributors endpoint

View File

@ -107,3 +107,12 @@ class RevokedTokenResponse(BaseModel):
""" """
revoked: bool revoked: bool
class SocialsResponseModel(BaseModel):
"""Implements the JSON response model for the /socials endpoint.
Args:
BaseModel (pydantic.BaseModel): BaseModel from pydantic
"""
__root__: dict[ str, str ]

24
app/routers/socials.py Normal file
View File

@ -0,0 +1,24 @@
from fastapi_cache.decorator import cache
from fastapi import APIRouter, Request, Response
import app.models.ResponseModels as ResponseModels
from app.controllers.Socials import Socials
from app.dependencies import load_config
router = APIRouter()
socials = Socials()
config: dict = load_config()
@router.get('/socials', response_model=ResponseModels.SocialsResponseModel, tags=['ReVanced Socials'])
@cache(config['cache']['expire'])
async def get_socials(request: Request, response: Response) -> dict:
"""Get ReVanced social links.
Returns:
json: dictionary of ReVanced social links
"""
return await socials.get_socials()

View File

@ -1,10 +1,12 @@
import os import os
import toml
from redis import asyncio as aioredis from redis import asyncio as aioredis
from app.dependencies import load_config
# Load config # Load config
config: dict = toml.load("config.toml") config: dict = load_config()
# Redis connection parameters # Redis connection parameters

View File

@ -1,5 +1,4 @@
[docs] [docs]
title = "ReVanced Releases API" title = "ReVanced Releases API"
description = """ description = """
## The official JSON API for ReVanced Releases 🚀 ## The official JSON API for ReVanced Releases 🚀
@ -22,10 +21,9 @@ description = """
3. Abuse of the API will result in IP blocks 3. Abuse of the API will result in IP blocks
""" """
version = "1.0.0" version = "1.1.0"
[license] [license]
name = "AGPL-3.0" name = "AGPL-3.0"
url = "https://www.gnu.org/licenses/agpl-3.0.en.html" url = "https://www.gnu.org/licenses/agpl-3.0.en.html"
@ -57,6 +55,13 @@ database = 5
access_token_expires = false access_token_expires = false
[app] [app]
repositories = ["TeamVanced/VancedMicroG", "revanced/revanced-patcher", "revanced/revanced-patches", "revanced/revanced-integrations", "revanced/revanced-manager", "revanced/revanced-cli", "revanced/revanced-website", "revanced/revanced-releases-api"]
repositories = ["TeamVanced/VancedMicroG", "revanced/revanced-cli", "revanced/revanced-patcher", "revanced/revanced-patches", "revanced/revanced-integrations", "revanced/revanced-manager", "revanced/revanced-website", "revanced/revanced-releases-api"] [socials]
website = "https://revanced.app"
github = "https://github.com/revanced"
twitter = "https://twitter.com/revancedapp"
discord = "https://revanced.app/discord"
reddit = "https://www.reddit.com/r/revancedapp"
telegram = "https://t.me/app_revanced"
youtube = "https://www.youtube.com/@ReVanced"

View File

@ -3,7 +3,7 @@ version: "3.8"
services: services:
redis: redis:
container_name: revanced-releases-api-redis container_name: revanced-releases-api-redis
image: redis-stack-server:latest image: redis/redis-stack-server:latest
environment: environment:
- REDIS_ARGS=--save 60 1 --appendonly yes - REDIS_ARGS=--save 60 1 --appendonly yes
volumes: volumes:
@ -13,7 +13,7 @@ services:
restart: always restart: always
revanced-releases-api: revanced-releases-api:
container_name: revanced-releases-api container_name: revanced-releases-api
image: ghcr.io/alexandreteles/revanced-releases-api:latest image: ghcr.io/revanced/revanced-releases-api:latest
environment: environment:
- GITHUB_TOKEN=YOUR_GITHUB_TOKEN - GITHUB_TOKEN=YOUR_GITHUB_TOKEN
- REDIS_URL=revanced-releases-api-redis - REDIS_URL=revanced-releases-api-redis

View File

@ -4,7 +4,7 @@ version: "3.8"
services: services:
redis: redis:
container_name: revanced-releases-api-redis container_name: revanced-releases-api-redis
image: redis-stack-server:latest image: redis/redis-stack-server:latest
environment: environment:
- REDIS_ARGS=--save 60 1 --appendonly yes - REDIS_ARGS=--save 60 1 --appendonly yes
volumes: volumes:
@ -14,7 +14,7 @@ services:
restart: always restart: always
revanced-releases-api: revanced-releases-api:
container_name: revanced-releases-api container_name: revanced-releases-api
image: ghcr.io/alexandreteles/revanced-releases-api:latest image: ghcr.io/revanced/revanced-releases-api:latest
environment: environment:
- GITHUB_TOKEN=YOUR_GITHUB_TOKEN - GITHUB_TOKEN=YOUR_GITHUB_TOKEN
- REDIS_URL=revanced-releases-api-redis - REDIS_URL=revanced-releases-api-redis

View File

@ -1,5 +1,5 @@
[mypy] [mypy]
python_version = 3.10 python_version = 3.11
pretty = true pretty = true
follow_imports = normal follow_imports = normal
namespace_packages = true namespace_packages = true
@ -76,3 +76,7 @@ ignore_missing_imports = True
[mypy-asgiref.*] [mypy-asgiref.*]
# No stubs available # No stubs available
ignore_missing_imports = True ignore_missing_imports = True
[mypy-tomllib.*]
# No stubs available
ignore_missing_imports = True

912
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
[tool.poetry] [tool.poetry]
name = "revanced-releases-api" name = "revanced-releases-api"
version = "0.1.0" version = "1.1.0"
description = "JSON API for ReVanced Releases" description = "JSON API for ReVanced Releases"
authors = ["Alexandre Teles <alexandre.teles@ufba.br>"] authors = ["Alexandre Teles <alexandre.teles@ufba.br>"]
license = "AGPLv3" license = "AGPLv3"
[tool.poetry.dependencies] [tool.poetry.dependencies]
python = "^3.10" python = "^3.11"
fastapi = ">=0.85.0" fastapi = ">=0.85.0"
httpx = {version = ">=0.23.0", extras = ["http2"]} httpx = {version = ">=0.23.0", extras = ["http2"]}
httpx-cache = ">=0.6.0" httpx-cache = ">=0.6.0"
@ -18,7 +18,7 @@ redis = ">=4.3.4"
loguru = ">=0.6.0" loguru = ">=0.6.0"
sentry-sdk = ">=1.9.8" sentry-sdk = ">=1.9.8"
argon2-cffi = ">=21.3.0" argon2-cffi = ">=21.3.0"
hypercorn = {extras = ["uvloop"], version = ">=0.14.3"} uvloop = ">=0.17.0"
cytoolz = ">=0.12.0" cytoolz = ">=0.12.0"
fastapi-paseto-auth = "^0.6.0" fastapi-paseto-auth = "^0.6.0"
ujson = ">=5.5.0" ujson = ">=5.5.0"
@ -26,6 +26,7 @@ hiredis = ">=2.0.0"
aiofiles = ">=22.1.0" aiofiles = ">=22.1.0"
uvicorn = ">=0.18.3" uvicorn = ">=0.18.3"
gunicorn = ">=20.1.0" gunicorn = ">=20.1.0"
asyncstdlib = ">=3.10.5"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
mypy = ">=0.971" mypy = ">=0.971"

View File

@ -1,63 +1,61 @@
aiofiles==22.1.0 ; python_version >= "3.10" and python_version < "4.0" aiofiles==22.1.0 ; python_version >= "3.11" and python_version < "4.0"
aiorwlock==1.3.0 ; python_version >= "3.10" and python_version < "4.0" aiorwlock==1.3.0 ; python_version >= "3.11" and python_version < "4.0"
anyio==3.6.2 ; python_version >= "3.11" and python_version < "4.0"
anyio==3.6.2 ; python_version >= "3.10" and python_version < "4.0" argon2-cffi-bindings==21.2.0 ; python_version >= "3.11" and python_version < "4.0"
argon2-cffi-bindings==21.2.0 ; python_version >= "3.10" and python_version < "4.0" argon2-cffi==21.3.0 ; python_version >= "3.11" and python_version < "4.0"
argon2-cffi==21.3.0 ; python_version >= "3.10" and python_version < "4.0" async-timeout==4.0.2 ; python_version >= "3.11" and python_version < "4.0"
async-timeout==4.0.2 ; python_version >= "3.10" and python_version < "4.0" asyncstdlib==3.10.5 ; python_version >= "3.11" and python_version < "4.0"
attrs==21.4.0 ; python_version >= "3.10" and python_version < "4.0" attrs==22.2.0 ; python_version >= "3.11" and python_version < "4.0"
certifi==2022.9.24 ; python_version >= "3.10" and python_version < "4.0" certifi==2022.12.7 ; python_version >= "3.11" and python_version < "4.0"
cffi==1.15.1 ; python_version >= "3.10" and python_version < "4.0" cffi==1.15.1 ; python_version >= "3.11" and python_version < "4.0"
click==8.1.3 ; python_version >= "3.10" and python_version < "4.0" click==8.1.3 ; python_version >= "3.11" and python_version < "4.0"
colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows" colorama==0.4.6 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.11" and python_version < "4.0" and platform_system == "Windows"
cryptography==37.0.4 ; python_version >= "3.10" and python_version < "4.0" cryptography==37.0.4 ; python_version >= "3.11" and python_version < "4.0"
cytoolz==0.12.0 ; python_version >= "3.10" and python_version < "4.0" cytoolz==0.12.1 ; python_version >= "3.11" and python_version < "4.0"
fastapi-cache2==0.1.9 ; python_version >= "3.10" and python_version < "4.0" deprecated==1.2.13 ; python_version >= "3.11" and python_version < "4.0"
fastapi-paseto-auth==0.6.0 ; python_version >= "3.10" and python_version < "4.0" fastapi-cache2==0.1.9 ; python_version >= "3.11" and python_version < "4.0"
fastapi==0.85.0 ; python_version >= "3.10" and python_version < "4.0" fastapi-paseto-auth==0.6.0 ; python_version >= "3.11" and python_version < "4.0"
fasteners==0.17.3 ; python_version >= "3.10" and python_version < "4.0" fastapi==0.85.0 ; python_version >= "3.11" and python_version < "4.0"
gunicorn==20.1.0 ; python_version >= "3.10" and python_version < "4.0" fasteners==0.17.3 ; python_version >= "3.11" and python_version < "4.0"
h11==0.14.0 ; python_version >= "3.10" and python_version < "4.0" gunicorn==20.1.0 ; python_version >= "3.11" and python_version < "4.0"
h2==4.1.0 ; python_version >= "3.10" and python_version < "4.0" h11==0.14.0 ; python_version >= "3.11" and python_version < "4.0"
hiredis==2.0.0 ; python_version >= "3.10" and python_version < "4.0" h2==4.1.0 ; python_version >= "3.11" and python_version < "4.0"
hpack==4.0.0 ; python_version >= "3.10" and python_version < "4.0" hiredis==2.1.0 ; python_version >= "3.11" and python_version < "4.0"
httpcore==0.16.1 ; python_version >= "3.10" and python_version < "4.0" hpack==4.0.0 ; python_version >= "3.11" and python_version < "4.0"
httpx-cache==0.6.1 ; python_version >= "3.10" and python_version < "4.0" httpcore==0.16.3 ; python_version >= "3.11" and python_version < "4.0"
httpx==0.23.1 ; python_version >= "3.10" and python_version < "4.0" httpx-cache==0.7.0 ; python_version >= "3.11" and python_version < "4.0"
httpx[http2]==0.23.1 ; python_version >= "3.10" and python_version < "4.0" httpx==0.23.1 ; python_version >= "3.11" and python_version < "4.0"
hypercorn[uvloop]==0.14.3 ; python_version >= "3.10" and python_version < "4.0" httpx[http2]==0.23.1 ; python_version >= "3.11" and python_version < "4.0"
hyperframe==6.0.1 ; python_version >= "3.10" and python_version < "4.0" hyperframe==6.0.1 ; python_version >= "3.11" and python_version < "4.0"
idna==3.4 ; python_version >= "3.10" and python_version < "4.0" idna==3.4 ; python_version >= "3.11" and python_version < "4.0"
iso8601==1.1.0 ; python_version >= "3.10" and python_version < "4.0" iso8601==1.1.0 ; python_version >= "3.11" and python_version < "4.0"
limits==1.6 ; python_version >= "3.10" and python_version < "4.0" limits==2.8.0 ; python_version >= "3.11" and python_version < "4.0"
loguru==0.6.0 ; python_version >= "3.10" and python_version < "4.0" loguru==0.6.0 ; python_version >= "3.11" and python_version < "4.0"
msgpack==1.0.4 ; python_version >= "3.10" and python_version < "4.0" msgpack==1.0.4 ; python_version >= "3.11" and python_version < "4.0"
orjson==3.8.2 ; python_version >= "3.10" and python_version < "4.0" orjson==3.8.3 ; python_version >= "3.11" and python_version < "4.0"
packaging==21.3 ; python_version >= "3.10" and python_version < "4.0" packaging==22.0 ; python_version >= "3.11" and python_version < "4.0"
passlib[argon2]==1.7.4 ; python_version >= "3.10" and python_version < "4.0" passlib[argon2]==1.7.4 ; python_version >= "3.11" and python_version < "4.0"
pendulum==2.1.2 ; python_version >= "3.10" and python_version < "4.0" pendulum==2.1.2 ; python_version >= "3.11" and python_version < "4.0"
priority==2.0.0 ; python_version >= "3.10" and python_version < "4.0" pycparser==2.21 ; python_version >= "3.11" and python_version < "4.0"
pycparser==2.21 ; python_version >= "3.10" and python_version < "4.0" pycryptodomex==3.16.0 ; python_version >= "3.11" and python_version < "4.0"
pycryptodomex==3.15.0 ; python_version >= "3.10" and python_version < "4.0" pydantic==1.10.2 ; python_version >= "3.11" and python_version < "4.0"
pydantic==1.10.2 ; python_version >= "3.10" and python_version < "4.0" pyseto==1.6.10 ; python_version >= "3.11" and python_version < "4.0"
pyparsing==3.0.9 ; python_version >= "3.10" and python_version < "4.0" python-dateutil==2.8.2 ; python_version >= "3.11" and python_version < "4.0"
pyseto==1.6.10 ; python_version >= "3.10" and python_version < "4.0" pytzdata==2020.1 ; python_version >= "3.11" and python_version < "4.0"
python-dateutil==2.8.2 ; python_version >= "3.10" and python_version < "4.0" redis==4.4.0 ; python_version >= "3.11" and python_version < "4.0"
pytzdata==2020.1 ; python_version >= "3.10" and python_version < "4.0" rfc3986[idna2008]==1.5.0 ; python_version >= "3.11" and python_version < "4.0"
redis==4.3.5 ; python_version >= "3.10" and python_version < "4.0" sentry-sdk==1.12.1 ; python_version >= "3.11" and python_version < "4.0"
rfc3986[idna2008]==1.5.0 ; python_version >= "3.10" and python_version < "4.0" setuptools==65.6.3 ; python_version >= "3.11" and python_version < "4.0"
sentry-sdk==1.11.1 ; python_version >= "3.10" and python_version < "4.0" six==1.16.0 ; python_version >= "3.11" and python_version < "4.0"
setuptools==65.6.0 ; python_version >= "3.10" and python_version < "4.0" slowapi==0.1.7 ; python_version >= "3.11" and python_version < "4.0"
six==1.16.0 ; python_version >= "3.10" and python_version < "4.0" sniffio==1.3.0 ; python_version >= "3.11" and python_version < "4.0"
slowapi==0.1.6 ; python_version >= "3.10" and python_version < "4.0" starlette==0.20.4 ; python_version >= "3.11" and python_version < "4.0"
sniffio==1.3.0 ; python_version >= "3.10" and python_version < "4.0" toml==0.10.2 ; python_version >= "3.11" and python_version < "4.0"
starlette==0.20.4 ; python_version >= "3.10" and python_version < "4.0" toolz==0.12.0 ; python_version >= "3.11" and python_version < "4.0"
toml==0.10.2 ; python_version >= "3.10" and python_version < "4.0" typing-extensions==4.4.0 ; python_version >= "3.11" and python_version < "4.0"
toolz==0.12.0 ; python_version >= "3.10" and python_version < "4.0" ujson==5.6.0 ; python_version >= "3.11" and python_version < "4.0"
typing-extensions==4.4.0 ; python_version >= "3.10" and python_version < "4.0" urllib3==1.26.13 ; python_version >= "3.11" and python_version < "4.0"
ujson==5.5.0 ; python_version >= "3.10" and python_version < "4.0" uvicorn==0.20.0 ; python_version >= "3.11" and python_version < "4.0"
urllib3==1.26.12 ; python_version >= "3.10" and python_version < "4" uvloop==0.17.0 ; python_version >= "3.11" and python_version < "4.0"
uvicorn==0.20.0 ; python_version >= "3.10" and python_version < "4.0" win32-setctime==1.1.0 ; python_version >= "3.11" and python_version < "4.0" and sys_platform == "win32"
uvloop==0.17.0 ; platform_system != "Windows" and python_version >= "3.10" and python_version < "4.0" wrapt==1.14.1 ; python_version >= "3.11" and python_version < "4.0"
win32-setctime==1.1.0 ; python_version >= "3.10" and python_version < "4.0" and sys_platform == "win32"
wsproto==1.2.0 ; python_version >= "3.10" and python_version < "4.0"

8
run.py
View File

@ -1,13 +1,13 @@
import os import os
import sys import sys
import toml
import logging import logging
import sentry_sdk import sentry_sdk
from app.main import app from app.main import app
from loguru import logger from loguru import logger
from fastapi import FastAPI from fastapi import FastAPI
from types import FrameType from types import FrameType
from typing import Any, Optional from typing import Any
from multiprocessing import cpu_count from multiprocessing import cpu_count
from gunicorn.glogging import Logger from gunicorn.glogging import Logger
from gunicorn.app.base import BaseApplication from gunicorn.app.base import BaseApplication
@ -15,7 +15,9 @@ from sentry_sdk.integrations.redis import RedisIntegration
from sentry_sdk.integrations.httpx import HttpxIntegration from sentry_sdk.integrations.httpx import HttpxIntegration
from sentry_sdk.integrations.gnu_backtrace import GnuBacktraceIntegration from sentry_sdk.integrations.gnu_backtrace import GnuBacktraceIntegration
config: dict = toml.load("config.toml") from app.dependencies import load_config
config: dict = load_config()
# Enable sentry logging # Enable sentry logging