ChBysk's picture
Create app.py
c33ecdb verified
Raw History Blame Contribute Delete
4.46 kB
"""
Flask-based UI + proxy to the Android build-runner.
Configuration:
- BUILD_RUNNER_URL (env): base URL of your build-runner, e.g. https://runpod-host.example
- DEFAULT_API_KEY (env): optional default API key to send to build-runner
- PORT (env): port (default 8080)
"""
import os
from flask import Flask, send_from_directory, request, jsonify, Response, redirect
import requests
BUILD_RUNNER = os.environ.get("BUILD_RUNNER_URL", "").rstrip("/")
DEFAULT_API_KEY = os.environ.get("DEFAULT_API_KEY", "")
if not BUILD_RUNNER:
# App will still run locally; advise user to set BUILD_RUNNER_URL
print("WARNING: BUILD_RUNNER_URL not set. UI will not be able to trigger builds until set.")
app = Flask(__name__, static_folder="static", static_url_path="/static")
def forward_headers(incoming):
headers = {}
# Accept an API key from the UI (header or form) or fallback to DEFAULT_API_KEY
api_key = incoming.headers.get("X-API-KEY") or incoming.args.get("api_key") or incoming.form.get("api_key") or DEFAULT_API_KEY
if api_key:
headers["X-API-KEY"] = api_key
return headers
@app.route("/", methods=["GET"])
def index():
return send_from_directory("static", "index.html")
# Proxy endpoints
@app.route("/build", methods=["POST"])
def build():
if not BUILD_RUNNER:
return jsonify({"error": "BUILD_RUNNER_URL not configured"}), 500
headers = forward_headers(request)
# If UI sends a file (multipart), forward as-stream
if request.content_type and request.content_type.startswith("multipart/"):
files = {}
data = {}
# forward known fields
for k in request.form:
data[k] = request.form[k]
if 'file' in request.files:
f = request.files['file']
files['file'] = (f.filename, f.stream, f.mimetype)
resp = requests.post(f"{BUILD_RUNNER}/build", headers=headers, data=data, files=files, timeout=300)
else:
# JSON body (repo_url etc)
payload = request.get_json(force=False) or request.form.to_dict()
resp = requests.post(f"{BUILD_RUNNER}/build", headers=headers, json=payload, timeout=300)
return Response(resp.content, status=resp.status_code, content_type=resp.headers.get("content-type", "application/json"))
@app.route("/status/<job_id>", methods=["GET"])
def status(job_id):
if not BUILD_RUNNER:
return jsonify({"error": "BUILD_RUNNER_URL not configured"}), 500
headers = forward_headers(request)
resp = requests.get(f"{BUILD_RUNNER}/status/{job_id}", headers=headers, timeout=30)
return Response(resp.content, status=resp.status_code, content_type=resp.headers.get("content-type", "application/json"))
@app.route("/logs/<job_id>", methods=["GET"])
def logs(job_id):
if not BUILD_RUNNER:
return jsonify({"error": "BUILD_RUNNER_URL not configured"}), 500
headers = forward_headers(request)
resp = requests.get(f"{BUILD_RUNNER}/logs/{job_id}", headers=headers, stream=True, timeout=300)
def stream():
for chunk in resp.iter_content(chunk_size=4096):
if chunk:
yield chunk
return Response(stream(), status=resp.status_code, content_type=resp.headers.get("content-type", "text/plain"))
@app.route("/artifacts/<job_id>/<name>", methods=["GET"])
def artifact(job_id, name):
if not BUILD_RUNNER:
return jsonify({"error": "BUILD_RUNNER_URL not configured"}), 500
headers = forward_headers(request)
# The build-runner returns artifact URLs in status; we can redirect by trying to fetch the status and locating artifact URL.
resp = requests.get(f"{BUILD_RUNNER}/status/{job_id}", headers=headers, timeout=10)
if resp.status_code != 200:
return Response(resp.content, status=resp.status_code, content_type=resp.headers.get("content-type", "application/json"))
data = resp.json()
for a in data.get("artifacts", []):
if a.get("name") == name:
url = a.get("url")
# If url is a relative path on the runner, convert to full URL
if url.startswith("/"):
return redirect(BUILD_RUNNER + url)
else:
return redirect(url)
return jsonify({"error": "artifact not found"}), 404
# Serve static assets under /static/* automatically
# (Flask static_folder handles it)
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8080))
app.run(host="0.0.0.0", port=port)