71 lines
1.8 KiB
Python
71 lines
1.8 KiB
Python
|
|
import logging
|
||
|
|
import os
|
||
|
|
from contextlib import asynccontextmanager
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
from fastapi import FastAPI, Request
|
||
|
|
from fastapi.responses import FileResponse
|
||
|
|
from fastapi.staticfiles import StaticFiles
|
||
|
|
from slowapi import Limiter, _rate_limit_exceeded_handler
|
||
|
|
from slowapi.errors import RateLimitExceeded
|
||
|
|
from slowapi.util import get_remote_address
|
||
|
|
|
||
|
|
from config import settings
|
||
|
|
from database import Base, engine
|
||
|
|
from routes.download import router as download_router
|
||
|
|
from routes.upload import router as upload_router
|
||
|
|
from utils.cleanup import start_scheduler
|
||
|
|
|
||
|
|
logging.basicConfig(
|
||
|
|
level=logging.INFO,
|
||
|
|
format="%(asctime)s %(levelname)s %(name)s — %(message)s",
|
||
|
|
)
|
||
|
|
|
||
|
|
FRONTEND = Path(__file__).parent.parent / "frontend"
|
||
|
|
|
||
|
|
|
||
|
|
@asynccontextmanager
|
||
|
|
async def lifespan(app: FastAPI):
|
||
|
|
os.makedirs(settings.storage_path, exist_ok=True)
|
||
|
|
Base.metadata.create_all(bind=engine)
|
||
|
|
scheduler = start_scheduler()
|
||
|
|
yield
|
||
|
|
scheduler.shutdown(wait=False)
|
||
|
|
|
||
|
|
|
||
|
|
limiter = Limiter(key_func=get_remote_address)
|
||
|
|
|
||
|
|
app = FastAPI(
|
||
|
|
title="dropLake",
|
||
|
|
lifespan=lifespan,
|
||
|
|
docs_url=None, # no Swagger UI exposed
|
||
|
|
redoc_url=None,
|
||
|
|
openapi_url=None,
|
||
|
|
)
|
||
|
|
|
||
|
|
app.state.limiter = limiter
|
||
|
|
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
||
|
|
|
||
|
|
# API routes
|
||
|
|
app.include_router(upload_router, prefix="/api")
|
||
|
|
app.include_router(download_router, prefix="/api")
|
||
|
|
|
||
|
|
# Static assets (CSS, JS)
|
||
|
|
app.mount("/static", StaticFiles(directory=str(FRONTEND / "static")), name="static")
|
||
|
|
|
||
|
|
|
||
|
|
@app.get("/")
|
||
|
|
async def serve_index():
|
||
|
|
return FileResponse(str(FRONTEND / "index.html"))
|
||
|
|
|
||
|
|
|
||
|
|
@app.get("/s/{share_id}")
|
||
|
|
async def serve_share_page(share_id: str):
|
||
|
|
# The JS on this page reads share_id from the URL path and the key from the fragment
|
||
|
|
return FileResponse(str(FRONTEND / "s.html"))
|
||
|
|
|
||
|
|
|
||
|
|
@app.get("/health")
|
||
|
|
async def health():
|
||
|
|
return {"status": "ok"}
|