Publish #1

Merged
IgorVolochay merged 29 commits from dev into main 2026-01-10 16:02:13 +00:00
2 changed files with 45 additions and 17 deletions
Showing only changes of commit 997204f414 - Show all commits
+43 -16
View File
@@ -1,5 +1,6 @@
import dotenv import dotenv
import os import os
import sys
import random import random
import string import string
@@ -9,21 +10,31 @@ import uvicorn
from datetime import datetime from datetime import datetime
from fastapi import FastAPI, Response, status, Request from fastapi import FastAPI, Response, status, Request
from starlette.middleware.base import BaseHTTPMiddleware from starlette.middleware.base import BaseHTTPMiddleware
from loguru import logger
from schemas.api_schemas import * from schemas.api_schemas import *
from s3_worker import S3Worker from s3_worker import S3Worker
from redis_worker import RedisWorker from redis_worker import RedisWorker
dotenv.load_dotenv() dotenv.load_dotenv()
logger.remove()
logger.add(f"{os.getenv("LOGS_PATH", "./logs")}/dmf-logs.log",
format="{time:DD-MM-YYYY HH:mm:ss.SSS}; {level}; {message}", level="DEBUG",
rotation="1 MB", compression="zip")
logger.add(sys.stdout,
level="DEBUG",
format="<green>{time:HH:mm:ss}</green> | <level>{level}</level> | {message}",)
disable_docs = os.getenv("DISABLE_DOCS", "true").lower() == "true" disable_docs = os.getenv("DISABLE_DOCS", "true").lower() == "true"
app: FastAPI = FastAPI(title="DropMeFiles analog") app: FastAPI = FastAPI(title="DropMeFiles analog",
# app: FastAPI = FastAPI(title="DropMeFiles analog", summary="OpenAPI schema for \"DropMeFiles analog\" project!",
# summary="OpenAPI schema for \"DropMeFiles analog\" project!", version="0.1",
# version="0.1", contact={"GitHub": "https://github.com/IgorVolochay/Drop-me-files-analog"},
# contact={"GitHub": "https://github.com/IgorVolochay/Drop-me-files-analog"}, docs_url=None if disable_docs else "/docs",
# docs_url=None if disable_docs else "/docs", redoc_url=None if disable_docs else "/redoc",
# redoc_url=None if disable_docs else "/redoc", openapi_url=None if disable_docs else "/openapi.json")
# openapi_url=None if disable_docs else "/openapi.json")
s3_worker = S3Worker() s3_worker = S3Worker()
redis_worker = RedisWorker() redis_worker = RedisWorker()
@@ -39,55 +50,71 @@ class RealIPMiddleware(BaseHTTPMiddleware):
return response return response
app.add_middleware(RealIPMiddleware) app.add_middleware(RealIPMiddleware)
@logger.catch
@app.get("/upload_token", status_code=200) @app.get("/upload_token", status_code=200)
async def get_upload_token(file_name: str, file_type: str, file_size: int, response: Response, request: Request) -> BaseResponse: async def get_upload_token(file_name: str, file_type: str, file_size: int, response: Response, request: Request) -> BaseResponse:
user_ip = request.state.client_ip
logger.debug(f"User IP: {user_ip}; Endpoint: /upload_token; File Name: {file_name}; File Type: {file_type}; File Size: {file_size}")
if file_size > int(os.getenv('MAX_FILES_SIZE')): if file_size > int(os.getenv('MAX_FILES_SIZE')):
response.status_code = status.HTTP_413_CONTENT_TOO_LARGE response.status_code = status.HTTP_413_CONTENT_TOO_LARGE
logger.warning(f"User IP: {user_ip}; File Name: {file_name}; Exception: The file is too large")
return BaseResponse(result="The uploaded file is too large", error=True) return BaseResponse(result="The uploaded file is too large", error=True)
elif file_size <= 0: elif file_size <= 0:
response.status_code = status.HTTP_400_BAD_REQUEST response.status_code = status.HTTP_400_BAD_REQUEST
logger.warning(f"User IP: {user_ip}; File Name: {file_name}; Exception: The file is less than 1 byte")
return BaseResponse(result="The file you are uploading is less than 1 byte, WTF?", error=True) return BaseResponse(result="The file you are uploading is less than 1 byte, WTF?", error=True)
user_ip = request.state.client_ip
print(user_ip)
file_uuid = ''.join(random.choices(string.ascii_letters + string.digits, k=6)) file_uuid = ''.join(random.choices(string.ascii_letters + string.digits, k=6))
try: try:
post_data = await s3_worker.generate_upload_post(file_uuid, content_type=file_type) post_data = await s3_worker.generate_upload_post(file_uuid, content_type=file_type)
except Exception as exception: except Exception as exception:
response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
return BaseResponse(result="Error generating S3 access token. Error: " + str(exception), error=True) logger.error(f"User IP: {user_ip}; File Name: {file_name}; Exception: {exception}")
return BaseResponse(result="Error generating S3 access token", error=True)
redis_worker.create_record(user_ip, file_name, file_uuid, file_type, datetime.now().isoformat(), file_size) redis_worker.create_record(user_ip, file_name, file_uuid, file_type, datetime.now().isoformat(), file_size)
print(post_data)
logger.success(f"User IP: {user_ip}; POST data: {post_data}")
return BaseResponse(result={"data": post_data, "file_uuid": file_uuid, "comment": "Ok"}) return BaseResponse(result={"data": post_data, "file_uuid": file_uuid, "comment": "Ok"})
@app.get("/max_file_size", status_code=200) @app.get("/max_file_size", status_code=200)
def get_max_file_size() -> int: def get_max_file_size() -> int:
logger.debug("Max file size")
return int(os.getenv('MAX_FILES_SIZE')) return int(os.getenv('MAX_FILES_SIZE'))
@logger.catch
@app.get("/get_download_link/{file_uuid}", status_code=200) @app.get("/get_download_link/{file_uuid}", status_code=200)
async def get_file_by_uuid(file_uuid:str, response: Response, request: Request) -> BaseResponse: async def get_file_by_uuid(file_uuid:str, response: Response, request: Request) -> BaseResponse:
user_ip = request.state.client_ip
logger.debug(f"User IP: {user_ip}; Endpoint: /get_download_link/; File UUID: {file_uuid}")
if len(file_uuid) != 6: if len(file_uuid) != 6:
response.status_code = status.HTTP_404_NOT_FOUND response.status_code = status.HTTP_404_NOT_FOUND
logger.warning(f"User IP: {user_ip}; File UUID: {file_uuid}; Exception: Invalid UUID")
return BaseResponse(result="The file UUID must be 6 characters long", error=True) return BaseResponse(result="The file UUID must be 6 characters long", error=True)
redis_data = redis_worker.get_record(file_uuid) redis_data = redis_worker.get_record(file_uuid)
if not redis_data: if not redis_data:
response.status_code = status.HTTP_400_BAD_REQUEST response.status_code = status.HTTP_400_BAD_REQUEST
logger.warning(f"User IP: {user_ip}; File UUID: {file_uuid}; Exception: File with this UUID not found")
return BaseResponse(result={"data": None, "comment": "File with this UUID not found"}, error=True) return BaseResponse(result={"data": None, "comment": "File with this UUID not found"}, error=True)
try: try:
download_url = await s3_worker.generate_download_url(file_uuid, redis_data["file_name"]) download_url = await s3_worker.generate_download_url(file_uuid, redis_data["file_name"])
except Exception as exception: except Exception as exception:
response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR
return BaseResponse(result="Error generating S3 access token. Error: " + str(exception), error=True) logger.error(f"User IP: {user_ip}; File UUID: {file_uuid}; Exception: {exception}")
return BaseResponse(result="Error generating S3 access token", error=True)
logger.success(f"User IP: {user_ip}; File UUID: {file_uuid}")
return BaseResponse(result={"data": {"url": download_url, "file_name": redis_data["file_name"], "file_size": redis_data["file_size"]}, "comment": "Ok"}) return BaseResponse(result={"data": {"url": download_url, "file_name": redis_data["file_name"], "file_size": redis_data["file_size"]}, "comment": "Ok"})
@app.get("/health_check")
def health_check():
logger.debug("Health check")
return True
async def main(): async def main():
config = uvicorn.Config("main:app", port=int(os.getenv('BACKEND_PORT')), host="0.0.0.0", log_level="debug") config = uvicorn.Config("main:app", port=int(os.getenv('BACKEND_PORT')), host="0.0.0.0", log_level="critical")
server = uvicorn.Server(config) server = uvicorn.Server(config)
await server.serve() await server.serve()
+2 -1
View File
@@ -3,11 +3,12 @@ name = "drop-me-files-analog"
version = "0.1.0" version = "0.1.0"
description = "" description = ""
readme = "README.md" readme = "README.md"
requires-python = ">=3.11" requires-python = ">=3.14"
dependencies = [ dependencies = [
"aiobotocore>=2.26.0", "aiobotocore>=2.26.0",
"dotenv>=0.9.9", "dotenv>=0.9.9",
"fastapi>=0.121.1", "fastapi>=0.121.1",
"loguru>=0.7.3",
"minio>=7.2.20", "minio>=7.2.20",
"pydantic>=2.12.5", "pydantic>=2.12.5",
"python-multipart>=0.0.20", "python-multipart>=0.0.20",