This commit is contained in:
IgorVolochay
2026-01-06 17:27:59 +03:00
parent c11fb3d9b7
commit 6920ff381c
3 changed files with 59 additions and 80 deletions
+11 -13
View File
@@ -38,12 +38,11 @@ async def get_upload_token(file_name: str, file_type: str, file_size: int, respo
user_ip = request.client.host user_ip = request.client.host
file_uuid = ''.join(random.choices(string.ascii_letters + string.digits, k=6)) file_uuid = ''.join(random.choices(string.ascii_letters + string.digits, k=6))
async with s3_worker as worker: try:
try: post_data = await s3_worker.generate_upload_post(file_uuid, content_type=file_type)
post_data = await worker.generate_upload_post(file_name, 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)
return BaseResponse(result="Error generating S3 access token. Error: " + str(exception), 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) print(post_data)
@@ -64,18 +63,17 @@ async def get_file_by_uuid(file_uuid:str, response: Response, request: Request)
response.status_code = status.HTTP_400_BAD_REQUEST response.status_code = status.HTTP_400_BAD_REQUEST
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)
async with s3_worker as worker: try:
try: download_url = await s3_worker.generate_download_url(file_uuid, redis_data["file_name"])
download_url = await 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)
return BaseResponse(result="Error generating S3 access token. Error: " + str(exception), error=True)
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"})
async def main(): async def main():
config = uvicorn.Config("main:app", port=5000, 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="debug")
server = uvicorn.Server(config) server = uvicorn.Server(config)
await server.serve() await server.serve()
+43 -64
View File
@@ -1,6 +1,7 @@
import os import os
import asyncio import asyncio
from contextlib import asynccontextmanager
from dotenv import load_dotenv from dotenv import load_dotenv
from aiobotocore.session import get_session from aiobotocore.session import get_session
@@ -10,84 +11,62 @@ class S3Worker:
def __init__(self): def __init__(self):
load_dotenv() load_dotenv()
self._S3_ACCESS_KEY_ID = os.getenv('S3_ACCESS_KEY_ID') self._s3_config = {
self._S3_SECRET_ACCESS_KEY = os.getenv('S3_SECRET_ACCESS_KEY') "aws_access_key_id": os.getenv('S3_ACCESS_KEY_ID'),
self._S3_ENDPOINT_URL = os.getenv('S3_ENDPOINT_URL') "aws_secret_access_key": os.getenv('S3_SECRET_ACCESS_KEY'),
"endpoint_url": os.getenv('S3_ENDPOINT_URL')
}
self._s3_session = get_session() self._s3_session = get_session()
self._s3_client = None
self.bucket = os.getenv('BUCKET_NAME') self.bucket = os.getenv('BUCKET_NAME')
self.max_file_size = os.getenv('MAX_FILES_SIZE') self.max_file_size = os.getenv('MAX_FILES_SIZE')
async def __aenter__(self): @asynccontextmanager
self._client = await self._s3_session.create_client( async def get_client(self):
"s3", async with self._s3_session.create_client("s3", **self._s3_config) as client:
region_name="us-east-1", yield client
aws_access_key_id=self._S3_ACCESS_KEY_ID,
aws_secret_access_key=self._S3_SECRET_ACCESS_KEY,
endpoint_url=self._S3_ENDPOINT_URL,
).__aenter__()
return self
async def __aexit__(self, exc_type, exc, tb):
await self._client.__aexit__(exc_type, exc, tb)
async def upload_file(self, key: str, data: bytes):
await self._client.put_object(
Bucket=self.bucket,
Key=key,
Body=data,
)
async def generate_upload_post(self, key: str, content_type: str, expires_in: int = 300) -> dict: async def generate_upload_post(self, key: str, content_type: str, expires_in: int = 300) -> dict:
return await self._client.generate_presigned_post( async with self.get_client() as client:
Bucket=self.bucket, return await client.generate_presigned_post(
Key=key, Bucket=self.bucket,
Fields={ Key=key,
"Content-Type": content_type, Fields={
"acl": "private", "Content-Type": content_type,
}, "acl": "private",
Conditions=[ },
["content-length-range", 0, self.max_file_size], Conditions=[
{"acl": "private"}, ["content-length-range", 0, self.max_file_size],
], {"acl": "private"},
ExpiresIn=expires_in, ],
) ExpiresIn=expires_in,
)
async def download_file(self, key: str):
return await self._client.get_object(
Bucket=self.bucket,
Key=key,
)
async def generate_download_url(self, key: str, filename: str, expires_in: int = 300) -> str: async def generate_download_url(self, key: str, filename: str, expires_in: int = 300) -> str:
return await self._client.generate_presigned_url("get_object", async with self.get_client() as client:
Params={ return await client.generate_presigned_url("get_object",
"Bucket": self.bucket, Params={
"Key": key, "Bucket": self.bucket,
"ResponseContentDisposition": ( "Key": key,
f'attachment; filename="{filename}"' "ResponseContentDisposition": (
), f'attachment; filename="{filename}"'
}, ),
ExpiresIn=expires_in, },
) ExpiresIn=expires_in,
)
s3_worker = S3Worker()
async def test_run(): async def test_run():
async with s3_worker as worker: worker = S3Worker()
await worker.upload_file("test.txt", b"hello")
file = await worker.download_file("test.txt")
file_text = await file["Body"].read()
print(file_text)
url = await worker.generate_download_url("test.txt", "hello.txt") url = await worker.generate_download_url("test.txt", "hello.txt")
print(url) print(url)
url = await worker.generate_upload_post("some.jpg", content_type="image/jpeg") url = await worker.generate_upload_post("some.jpg", content_type="image/jpeg")
print(url) print(url)
url = await worker.generate_download_url("some.jpg", "image.jpg") url = await worker.generate_download_url("some.jpg", "image.jpg")
print(url) print(url)
if __name__ == "__main__": if __name__ == "__main__":
+5 -3
View File
@@ -33,7 +33,7 @@ async function handleDownloadPage(fileUuid) {
const downloadContent = document.getElementById('downloadContent'); const downloadContent = document.getElementById('downloadContent');
try { try {
const response = await fetch(`/get_download_link/${fileUuid}`); const response = await fetch(`/api/get_download_link/${fileUuid}`);
const data = await response.json(); const data = await response.json();
if (data.error || !data.result || !data.result.data) { if (data.error || !data.result || !data.result.data) {
@@ -73,7 +73,7 @@ function initUploadPage() {
// Fetch max file size on page load // Fetch max file size on page load
async function loadMaxFileSize() { async function loadMaxFileSize() {
try { try {
const response = await fetch('/max_file_size'); const response = await fetch('/api/max_file_size');
if (!response.ok) { if (!response.ok) {
throw new Error(`Ошибка сервера: ${response.status}`); throw new Error(`Ошибка сервера: ${response.status}`);
} }
@@ -160,7 +160,7 @@ function initUploadPage() {
try { try {
// Step 1: Get upload token // Step 1: Get upload token
const tokenUrl = `/upload_token?file_name=${encodeURIComponent(file.name)}&file_type=${encodeURIComponent(file.type)}&file_size=${file.size}`; const tokenUrl = `/api/upload_token?file_name=${encodeURIComponent(file.name)}&file_type=${encodeURIComponent(file.type)}&file_size=${file.size}`;
const tokenResponse = await fetch(tokenUrl); const tokenResponse = await fetch(tokenUrl);
if (!tokenResponse.ok) { if (!tokenResponse.ok) {
@@ -176,6 +176,8 @@ function initUploadPage() {
const uploadData = tokenData.result.data; const uploadData = tokenData.result.data;
const fileUuid = tokenData.result.file_uuid; const fileUuid = tokenData.result.file_uuid;
uploadData.fields["key"] = fileUuid;
delete uploadData.fields["Content-Type"];
setStatus('Загрузка файла на сервер...', ''); setStatus('Загрузка файла на сервер...', '');