Files
fb2converter_server/app/main.py
2022-06-25 21:20:25 +03:00

115 lines
2.7 KiB
Python

import asyncio
import os
import os.path
import shutil
import time
from typing import AsyncIterator
import uuid
from fastapi import FastAPI, APIRouter, File, UploadFile, Form, HTTPException, status
from fastapi.responses import StreamingResponse
import aiofiles
import aiofiles.os
import aiofiles.ospath
from fastapi_utils.tasks import repeat_every
import sentry_sdk
from config import env_config
sentry_sdk.init(
env_config.SENTRY_DSN,
)
router = APIRouter(tags=["converter"])
@router.post("/")
async def convert(
file: UploadFile = File({}),
format: str = Form({}),
):
format_lower = format.lower()
if format_lower not in ["epub", "mobi"]:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)
temp_uuid = uuid.uuid1()
temp_filename = str(temp_uuid) + ".fb2"
converted_temp_filename = str(temp_uuid) + "." + format_lower
try:
async with aiofiles.open(temp_filename, "wb") as f:
while content := await file.read(1024):
if isinstance(content, str):
content = content.encode()
await f.write(content)
proc = await asyncio.create_subprocess_exec(
"./bin/fb2c",
"convert",
"--to",
format,
temp_filename,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
_, stderr = await proc.communicate()
finally:
await aiofiles.os.remove(temp_filename)
if proc.returncode != 0 or len(stderr) != 0:
try:
await aiofiles.os.remove(converted_temp_filename)
except FileNotFoundError:
pass
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST)
async def result_iterator() -> AsyncIterator[bytes]:
try:
async with aiofiles.open(converted_temp_filename, "rb") as f:
while data := await f.read(2048):
yield data
finally:
await aiofiles.os.remove(converted_temp_filename)
return StreamingResponse(result_iterator())
@router.get("/healthcheck")
async def healthcheck():
return "Ok!"
app = FastAPI()
app.include_router(router)
@app.on_event("startup")
@repeat_every(seconds=5 * 60, raise_exceptions=True)
def remove_temp_files():
current_time = time.time()
try:
os.remove("./conversion.log")
except IOError:
pass
for f in os.listdir("/tmp/"):
target_path = f"/tmp/{f}"
is_file = os.path.isfile(target_path)
creation_time = os.path.getctime(target_path)
if (current_time - creation_time) // 3600 >= 3:
if is_file:
os.remove(target_path)
else:
shutil.rmtree(target_path)