from pathlib import Path from fastapi import FastAPI, Response, status from fastapi.responses import JSONResponse from pydantic import BaseModel app = FastAPI() data_path = Path(__file__).parent.resolve() / "data" class Files(BaseModel): files: list[str] class Log(BaseModel): start: int size: int total: int content: str end: bool class Error(BaseModel): error: str @app.get("/", response_model=Files) def list_logs(): return {"files": [path.name for path in data_path.glob("*.txt") if path.is_file()]} @app.get( "/log/{name}/", response_model=Log, responses={ 400: {"model": Error}, 404: {"model": Error}, }, ) def get_log(name: str, start: int = 0, size: int = 100): path = data_path.joinpath(name) # Prevent path traversal if not path.is_relative_to(data_path): return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, content={"error": "Bad Request"} ) if not path.is_file(): return JSONResponse( status_code=status.HTTP_400_BAD_REQUEST, content={"error": "Log not found"} ) with open(path) as f: f.seek(start) content = f.read(size) total = path.stat().st_size return { "start": start, "size": len(content), "total": total, "content": content, "end": size + start >= total, }