119 lines
3.5 KiB
Python
119 lines
3.5 KiB
Python
from fastapi import FastAPI, File, UploadFile, Depends, HTTPException, Security
|
|
from fastapi.responses import FileResponse, PlainTextResponse, StreamingResponse
|
|
from fastapi.security import APIKeyHeader
|
|
from sqlalchemy import exists
|
|
import hashlib
|
|
from ftplib import FTP
|
|
from io import BytesIO
|
|
from . import db
|
|
from dotenv import load_dotenv
|
|
import os
|
|
|
|
load_dotenv()
|
|
|
|
FILES_DIR = os.getenv("FILES_DIR")
|
|
API_KEY = os.getenv("API_KEY")
|
|
api_key_header = APIKeyHeader(name="X-API-Key")
|
|
|
|
FTP_URL = os.getenv("FTP_URL")
|
|
FTP_LOGIN = os.getenv("FTP_LOGIN")
|
|
FTP_PASSWORD = os.getenv("FTP_PASSWORD")
|
|
CACHE_DIR = "cache"
|
|
|
|
def verify_api_key(api_key: str = Security(api_key_header)):
|
|
if api_key != API_KEY:
|
|
raise HTTPException(status_code=403, detail="Forbidden")
|
|
return api_key
|
|
|
|
def compute_hash(data: bytes, algorithm="sha256") -> str:
|
|
h = hashlib.new(algorithm)
|
|
h.update(data)
|
|
return h.hexdigest()
|
|
|
|
app = FastAPI()
|
|
|
|
|
|
@app.get("/")
|
|
async def root():
|
|
return {"message": "hiii from sfs"}
|
|
|
|
@app.post("/file")
|
|
async def save_file(file: UploadFile = File(...), api_key: str = Depends(verify_api_key)):
|
|
contents = await file.read()
|
|
|
|
hash = compute_hash(contents)
|
|
|
|
existed_url = db.file_exists(file.size, hash)
|
|
|
|
if not existed_url:
|
|
file_url = db.add_file(file.filename, file.content_type, file.size, hash)
|
|
|
|
try:
|
|
ftp = FTP(FTP_URL)
|
|
ftp.login(FTP_LOGIN, FTP_PASSWORD)
|
|
buffer = BytesIO(contents)
|
|
try:
|
|
ftp.mkd(FILES_DIR)
|
|
except:
|
|
pass
|
|
|
|
ftp.storbinary(f"STOR {FILES_DIR}/{file_url}", buffer)
|
|
ftp.quit()
|
|
|
|
cached = os.path.join(CACHE_DIR, file_url)
|
|
if os.path.exists(cached):
|
|
os.remove(cached)
|
|
|
|
return {"status": "saved", "filename": file_url}
|
|
except Exception as e:
|
|
db.remove_file(file_url)
|
|
|
|
return {"status": "error", "message": f"Could not save file {file_url}: {e}"}
|
|
else:
|
|
return {"status": "file_exists", "filename": existed_url}
|
|
|
|
@app.get("/file/{filename}")
|
|
async def get_file(filename: str, raw: bool = False, api_key: str = Depends(verify_api_key)):
|
|
local_path = os.path.join(CACHE_DIR, filename)
|
|
|
|
if not os.path.exists(local_path):
|
|
try:
|
|
ftp = FTP(FTP_URL)
|
|
ftp.login(FTP_LOGIN, FTP_PASSWORD)
|
|
with open(local_path, "wb") as f:
|
|
ftp.retrbinary(f"RETR {FILES_DIR}/{filename}", f.write)
|
|
ftp.quit()
|
|
except Exception as e:
|
|
raise HTTPException(status_code=404, detail=f"File not found: {e}")
|
|
|
|
if raw:
|
|
with open(local_path, "r", encoding="utf-8", errors="ignore") as f:
|
|
return PlainTextResponse(f.read())
|
|
|
|
return FileResponse(local_path, filename=filename)
|
|
|
|
|
|
from ftplib import FTP
|
|
|
|
@app.delete("/file/{filename}")
|
|
async def delete_file(filename: str, api_key: str = Depends(verify_api_key)):
|
|
if not db.remove_file(filename):
|
|
return {"status": "error", "message": "no file like that"}
|
|
|
|
try:
|
|
ftp = FTP(FTP_URL)
|
|
ftp.login(FTP_LOGIN, FTP_PASSWORD)
|
|
ftp.delete(f"{FILES_DIR}/{filename}")
|
|
ftp.quit()
|
|
return {"status": "deleted"}
|
|
except Exception as e:
|
|
return {"status": "error", "message": f"Could not delete file {filename}: {e}"}
|
|
|
|
@app.get("/files/")
|
|
async def get_list_of_files(api_key: str = Depends(verify_api_key)):
|
|
return db.get_all_files()
|
|
|
|
@app.get("/healthchecker")
|
|
async def healthchecker():
|
|
return {"message": "Howdy, all is fine :3"}
|