main.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. import os
  2. import shutil
  3. import logging
  4. import tempfile
  5. from fastapi import FastAPI, Request, File, UploadFile, Form
  6. from fastapi.responses import HTMLResponse, RedirectResponse, FileResponse
  7. from fastapi.templating import Jinja2Templates
  8. from fastapi.staticfiles import StaticFiles
  9. # Setup logging
  10. logging.basicConfig(level=logging.INFO)
  11. logger = logging.getLogger("overlay-manager")
  12. # root_path ensures FastAPI knows it lives at /patch-manager/
  13. app = FastAPI(root_path="/patch-manager")
  14. os.makedirs("static", exist_ok=True)
  15. app.mount("/static", StaticFiles(directory="static"), name="static")
  16. templates = Jinja2Templates(directory="templates")
  17. OVERLAY_DIR = "/srv"
  18. @app.get("/", response_class=HTMLResponse)
  19. async def index(request: Request):
  20. files = []
  21. dirs = set([""])
  22. if os.path.exists(OVERLAY_DIR):
  23. for root, dirnames, filenames in os.walk(OVERLAY_DIR):
  24. rel_root = os.path.relpath(root, OVERLAY_DIR)
  25. if rel_root != ".":
  26. dirs.add(rel_root)
  27. for filename in filenames:
  28. rel_path = os.path.relpath(os.path.join(root, filename), OVERLAY_DIR)
  29. files.append(rel_path)
  30. return templates.TemplateResponse("index.html", {
  31. "request": request,
  32. "files": sorted(files),
  33. "dirs": sorted(list(dirs))
  34. })
  35. @app.get("/download-all")
  36. async def download_all():
  37. """Zips the entire /srv directory and serves it as a backup."""
  38. with tempfile.TemporaryDirectory() as tmpdir:
  39. zip_base = os.path.join(tmpdir, "backup")
  40. shutil.make_archive(zip_base, 'zip', OVERLAY_DIR)
  41. return FileResponse(
  42. path=f"{zip_base}.zip",
  43. filename="ardupilot_overlays_backup.zip",
  44. media_type='application/zip'
  45. )
  46. @app.post("/upload")
  47. async def upload_file(file: UploadFile = File(...), target_path: str = Form("")):
  48. save_dir = os.path.join(OVERLAY_DIR, target_path.strip("/"))
  49. os.makedirs(save_dir, exist_ok=True)
  50. file_location = os.path.join(save_dir, file.filename)
  51. with open(file_location, "wb+") as file_object:
  52. shutil.copyfileobj(file.file, file_object)
  53. return RedirectResponse(url="./", status_code=303)
  54. @app.post("/create_folder")
  55. async def create_folder(folder_path: str = Form(...)):
  56. save_dir = os.path.join(OVERLAY_DIR, folder_path.strip("/"))
  57. os.makedirs(save_dir, exist_ok=True)
  58. return RedirectResponse(url="./", status_code=303)
  59. @app.post("/delete")
  60. async def delete_file(filepath: str = Form(...)):
  61. target = os.path.join(OVERLAY_DIR, filepath.lstrip("/"))
  62. if os.path.exists(target):
  63. if os.path.isdir(target):
  64. shutil.rmtree(target)
  65. else:
  66. os.remove(target)
  67. return RedirectResponse(url="./", status_code=303)
  68. @app.get("/edit", response_class=HTMLResponse)
  69. async def edit_file(request: Request, filepath: str):
  70. clean_path = filepath.lstrip("/")
  71. target = os.path.join(OVERLAY_DIR, clean_path)
  72. logger.info(f"Attempting to edit: {target}")
  73. if not os.path.exists(target):
  74. return HTMLResponse(content=f"<h1>404 Not Found</h1><p>File {target} missing.</p><a href='./'>Back</a>", status_code=404)
  75. try:
  76. with open(target, "r", encoding="utf-8", errors="ignore") as f:
  77. content = f.read()
  78. except Exception as e:
  79. return HTMLResponse(content=f"<h1>Error</h1><p>{str(e)}</p>", status_code=500)
  80. return templates.TemplateResponse("edit.html", {
  81. "request": request,
  82. "filepath": filepath,
  83. "content": content
  84. })
  85. @app.post("/edit")
  86. async def save_file(filepath: str = Form(...), content: str = Form(...)):
  87. target = os.path.join(OVERLAY_DIR, filepath.lstrip("/"))
  88. if os.path.exists(target):
  89. with open(target, "w", encoding="utf-8") as f:
  90. f.write(content)
  91. return RedirectResponse(url="./", status_code=303)