testing / app.py
webzepetoku's picture
Update app.py
ebd67c4 verified
Raw
History Blame Contribute Delete
6.34 kB
import os
import shutil
import subprocess
import requests
import zipfile
import uuid
import glob
import datetime
from fastapi import FastAPI, BackgroundTasks
from fastapi.responses import FileResponse, JSONResponse
from pydantic import BaseModel
# --- KONFIGURASI PATH ---
os.chdir("/tmp")
os.environ["HOME"] = "/tmp"
os.environ["UNITY_PATH"] = "/opt/unity/Editor/Unity"
BASE_PROJECT_PATH = "/app/UnityProject"
LICENSE_SOURCE = "/app/Unity_lic.ulf"
app = FastAPI()
class ConversionRequest(BaseModel):
transaction_id: str
file_url: str
filename: str
z_id: str
z_pw: str
# --- FUNGSI PEMBANTU ---
def setup_license():
"""Menyiapkan lisensi dan mengecek waktu server untuk debug."""
# 1. Cek Waktu Server (Penting untuk mengatasi 'Time validation failed')
now = datetime.datetime.now()
print(f"⏰ [DEBUG] Waktu Server Sekarang: {now.strftime('%Y-%m-%d %H:%M:%S')}", flush=True)
target_dir = "/tmp/.local/share/unity3d/Unity"
os.makedirs(target_dir, exist_ok=True)
if os.path.exists(LICENSE_SOURCE):
# Bersihkan lisensi lama di folder internal jika ada
internal_license = os.path.join(target_dir, "Unity_lic.ulf")
if os.path.exists(internal_license):
os.remove(internal_license)
shutil.copy2(LICENSE_SOURCE, internal_license)
print("✅ [SYSTEM] Lisensi disalin ke folder internal Unity.", flush=True)
else:
print("⚠️ [WARNING] File Unity_lic.ulf tidak ditemukan di /app/", flush=True)
def run_unity_command(project_path, method, extra_args=None):
"""Menjalankan Unity dengan flag headless dan anti-stuck."""
cmd = [
os.environ["UNITY_PATH"],
"-batchmode",
"-nographics",
"-quit",
"-no-webservices", # Matikan pencarian layanan cloud
"-no-graphics", # Proteksi tambahan mode headless
"-silent-crashes", # Jangan munculkan popup error
"-manualLicenseFile", LICENSE_SOURCE, # Paksa baca file lisensi fisik
"-projectPath", project_path,
"-executeMethod", method,
"-logFile", "-" # Log keluar secara real-time ke console
]
if extra_args:
cmd.extend(extra_args)
# Jalankan perintah dan tunggu sampai selesai
return subprocess.run(cmd, capture_output=False)
# --- ENDPOINTS ---
@app.get("/lisensi")
async def generate_new_alf():
"""Endpoint untuk generate file .alf baru jika lisensi lama Expired."""
# Bersihkan sisa file .alf sebelumnya
for f in glob.glob("/tmp/*.alf"):
try: os.remove(f)
except: pass
print("🛠️ [LICENSE] Meminta file aktivasi (.alf) baru dari Unity...", flush=True)
cmd = [
os.environ["UNITY_PATH"],
"-batchmode", "-nographics",
"-createManualActivationFile",
"-logfile", "/dev/stdout"
]
subprocess.run(cmd, cwd="/tmp", timeout=60)
found_alf = glob.glob("/tmp/*.alf")
if found_alf:
print(f"✅ [LICENSE] File .alf berhasil dibuat: {found_alf[0]}", flush=True)
return FileResponse(path=found_alf[0], filename=os.path.basename(found_alf[0]))
return JSONResponse(status_code=500, content={"error": "Gagal generate .alf. Cek tab Logs."})
@app.post("/convert")
async def api_convert(req: ConversionRequest, background_tasks: BackgroundTasks):
"""Endpoint utama untuk memicu pipeline convert dan upload."""
background_tasks.add_task(process_pipeline, req)
return {"status": "processing", "transaction_id": req.transaction_id}
# --- INTI PROSES (PIPELINE) ---
def process_pipeline(req: ConversionRequest):
setup_license()
# Folder unik untuk setiap transaksi
SESSION_PATH = f"/tmp/Project_{req.transaction_id}"
extract_tmp = f"/tmp/extract_{req.transaction_id}"
zip_tmp = f"/tmp/{req.transaction_id}.zip"
try:
# 1. DOWNLOAD & PREPARE
print(f"📥 [START] Mengambil aset: {req.transaction_id}", flush=True)
r = requests.get(req.file_url, timeout=30)
with open(zip_tmp, 'wb') as f:
f.write(r.content)
os.makedirs(extract_tmp, exist_ok=True)
with zipfile.ZipFile(zip_tmp, 'r') as z:
z.extractall(extract_tmp)
# 2. SETUP PROJECT WORKSPACE
# Salin UnityProject dasar ke folder temporer agar project asli tetap bersih
shutil.copytree(BASE_PROJECT_PATH, SESSION_PATH, ignore=shutil.ignore_patterns("Library", "Temp"))
target_in = os.path.join(SESSION_PATH, "Assets/InputRaw")
os.makedirs(target_in, exist_ok=True)
# Pindahkan file hasil ekstrak ke folder input project
for item in os.listdir(extract_tmp):
shutil.move(os.path.join(extract_tmp, item), os.path.join(target_in, item))
# 3. TAHAP 1: PENYEDERHANAAN MESH
print(f"🛠️ [STEP 1] Menjalankan TestBuilder.SimplifyOnly...", flush=True)
step1 = run_unity_command(SESSION_PATH, "TestBuilder.SimplifyOnly")
if step1.returncode != 0:
print(f"❌ [FAILED] Step 1 Gagal (Exit Code: {step1.returncode}). Cek Logs di atas.", flush=True)
return
# 4. TAHAP 2: UPLOAD KE ZEPETO
print(f"🚀 [STEP 2] Menjalankan Zepeto CLI Upload...", flush=True)
upload_args = [
"-id", req.z_id,
"-password", req.z_pw,
"-upload"
]
step2 = run_unity_command(SESSION_PATH, "ZepetoPackageCliBuilder.BuildWithArgs", upload_args)
if step2.returncode == 0:
print(f"✅ [SUCCESS] Item {req.transaction_id} telah terunggah ke ZEPETO Studio.", flush=True)
else:
print(f"❌ [FAILED] Step 2 Gagal (Exit Code: {step2.returncode}).", flush=True)
except Exception as e:
print(f"🔥 [CRITICAL ERROR] {str(e)}", flush=True)
finally:
# PEMBERSIHAN (Wajib agar disk tidak penuh)
print(f"🧹 [CLEANUP] Menghapus folder sesi {req.transaction_id}...", flush=True)
for p in [SESSION_PATH, extract_tmp, zip_tmp]:
if os.path.exists(p):
if os.path.isdir(p): shutil.rmtree(p)
else: os.remove(p)
if __name__ == "__main__":
import uvicorn
# Jalankan server FastAPI
uvicorn.run(app, host="0.0.0.0", port=7860)