90 lines
3.9 KiB
Python
90 lines
3.9 KiB
Python
"""Web API layer — wraps orchestrator with 202+ polling pattern."""
|
|
import uuid, json, sys, os
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from fastapi import FastAPI, UploadFile, File, Form, HTTPException
|
|
from fastapi.responses import HTMLResponse, JSONResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
from config import Config
|
|
from orchestrator import run_pipeline
|
|
|
|
app = FastAPI(title="COBOL->Java Verify")
|
|
BASE = Path(__file__).parent
|
|
app.mount("/static", StaticFiles(directory=str(BASE / "static")), name="static")
|
|
|
|
TASKS_DIR = Path("tasks"); TASKS_DIR.mkdir(exist_ok=True)
|
|
UPLOAD_DIR = Path("uploads"); UPLOAD_DIR.mkdir(exist_ok=True)
|
|
MAX_SIZE = 10 * 1024 * 1024
|
|
|
|
|
|
@app.get("/", response_class=HTMLResponse)
|
|
async def index():
|
|
return (BASE / "templates" / "upload.html").read_text(encoding="utf-8")
|
|
|
|
|
|
@app.post("/verify")
|
|
async def verify(
|
|
copybook: UploadFile = File(...), cobol_src: UploadFile = File(...),
|
|
java_src: UploadFile = File(...), mapping: UploadFile = File(...),
|
|
runner: str = Form("native"),
|
|
):
|
|
task_id = str(uuid.uuid4())[:8]
|
|
task_dir = UPLOAD_DIR / task_id; task_dir.mkdir(parents=True, exist_ok=True)
|
|
for f, name in [(copybook,"copybook.cpy"),(cobol_src,"program.cbl"),
|
|
(java_src,"java"),(mapping,"mapping.yaml")]:
|
|
content = await f.read()
|
|
if len(content) > MAX_SIZE:
|
|
raise HTTPException(413, f"{f.filename} exceeds 10MB")
|
|
(task_dir / name).write_bytes(content)
|
|
(TASKS_DIR / f"{task_id}.json").write_text(json.dumps({
|
|
"id":task_id,"status":"queued","copybook":str(task_dir/"copybook.cpy"),
|
|
"cobol_src":str(task_dir/"program.cbl"),"java_src":str(task_dir/"java"),
|
|
"mapping":str(task_dir/"mapping.yaml"),"runner":runner,
|
|
"created":datetime.now().isoformat()}))
|
|
return JSONResponse({"task_id":task_id,"status":"queued"}, status_code=202)
|
|
|
|
|
|
@app.get("/status/{task_id}")
|
|
async def status(task_id: str):
|
|
tf = TASKS_DIR / f"{task_id}.json"
|
|
if not tf.exists(): raise HTTPException(404, "task not found")
|
|
data = json.loads(tf.read_text())
|
|
return JSONResponse({"task_id":task_id,"status":data.get("status","unknown"),
|
|
"result":data.get("result"),"fields":data.get("fields",[])})
|
|
|
|
|
|
@app.get("/fields/{task_id}")
|
|
async def fields(task_id: str):
|
|
tf = TASKS_DIR / f"{task_id}.json"
|
|
if not tf.exists(): raise HTTPException(404, "task not found")
|
|
data = json.loads(tf.read_text())
|
|
return JSONResponse({"task_id":task_id,"fields":data.get("fields",[]),
|
|
"debug":data.get("debug",{}),
|
|
"build_log":data.get("build_log","")})
|
|
|
|
|
|
@app.get("/result/{task_id}", response_class=HTMLResponse)
|
|
async def result(task_id: str):
|
|
tf = TASKS_DIR / f"{task_id}.json"
|
|
if not tf.exists(): raise HTTPException(404, "task not found")
|
|
data = json.loads(tf.read_text())
|
|
html = (BASE / "templates" / "result.html").read_text(encoding="utf-8")
|
|
html = html.replace("{{ task.id }}", data.get("id", task_id))
|
|
if data.get("status") == "done" and data.get("result"):
|
|
r = data["result"]
|
|
html = html.replace("{{ task.status }}", "done")
|
|
html = html.replace("{{ task.result.status }}", r.get("status",""))
|
|
html = html.replace("{{ task.result.program }}", r.get("program",""))
|
|
html = html.replace("{{ task.result.matched }}", str(r.get("matched",0)))
|
|
html = html.replace("{{ task.result.mismatched }}", str(r.get("mismatched",0)))
|
|
html = html.replace("{{ task.result.runner }}", r.get("runner",""))
|
|
html = html.replace("{{ task.result.duration }}", str(r.get("duration",0)))
|
|
elif data.get("status") == "error":
|
|
html = html.replace("{{ task.status }}", "error")
|
|
html = html.replace("{{ task.result.status }}", data.get("result",""))
|
|
else:
|
|
html = html.replace("{{ task.status }}", data.get("status","queued"))
|
|
return HTMLResponse(html)
|