| import os, subprocess, threading, time, shutil |
| from flask import Flask, render_template_string, request, Response, jsonify |
|
|
| app = Flask(__name__) |
| log_queue = [] |
| |
| BOT_ROOT = os.path.join(os.getcwd(), "bot_workdir") |
|
|
| |
| HTML_TEMPLATE = """ |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <title>AQSO DEPLOYER v6</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <style> |
| body { background: #0b0f1a; color: #cbd5e1; font-family: 'Fira Code', monospace; } |
| .terminal { background: #000; color: #10b981; padding: 12px; border-radius: 8px 8px 0 0; height: 350px; overflow-y: auto; font-size: 11px; border: 1px solid #1e293b; } |
| .term-input { background: #000; color: #fff; border: 1px solid #1e293b; border-top: none; width: 100%; padding: 10px; font-size: 11px; border-radius: 0 0 8px 8px; outline: none; } |
| .btn-gacor { transition: all 0.2s; font-weight: bold; border-radius: 8px; } |
| .btn-gacor:active { transform: scale(0.95); } |
| </style> |
| </head> |
| <body class="p-4 md:p-10"> |
| <div class="max-w-4xl mx-auto"> |
| <div class="flex justify-between items-center mb-6"> |
| <h1 class="text-2xl font-bold text-blue-500">AQSO CLOUD v6 ⚡</h1> |
| <div class="text-[10px] bg-slate-800 px-3 py-1 rounded text-slate-400">PATH: /bot_workdir</div> |
| </div> |
| |
| <div class="bg-slate-900 p-6 rounded-2xl border border-slate-800 shadow-2xl space-y-4"> |
| <div class="flex gap-2"> |
| <button onclick="setLang('node')" id="tag-node" class="flex-1 py-2 rounded bg-green-900 text-green-300 border border-green-500">NODE JS MODE</button> |
| <button onclick="setLang('python')" id="tag-py" class="flex-1 py-2 rounded bg-slate-800 text-slate-500">PYTHON MODE</button> |
| </div> |
| |
| <div class="flex gap-2"> |
| <input id="repo" type="text" class="flex-1 p-3 bg-black rounded-lg border border-slate-700 text-xs outline-none focus:border-blue-500" placeholder="Paste URL Github Lu..."> |
| <button onclick="runCmd('clone')" class="bg-blue-600 px-6 rounded-lg text-xs btn-gacor">CLONE</button> |
| </div> |
| |
| <div class="terminal" id="logs">Sistem Siap. Terminal manual di bawah otomatis jalan di folder bot lu.</div> |
| <input type="text" id="term-box" class="term-input" placeholder="Ketik command manual (contoh: ls -la atau npm install) lalu Enter..." onkeypress="handleTerm(event)"> |
| |
| <div class="grid grid-cols-3 gap-3 mt-4"> |
| <button onclick="runCmd('install')" class="bg-purple-700 py-3 text-xs btn-gacor">INSTALL DEPS</button> |
| <button onclick="runCmd('start')" class="bg-red-600 py-3 text-xs btn-gacor text-white">START BOT</button> |
| <button onclick="runCmd('clear')" class="bg-slate-700 py-3 text-xs btn-gacor">WIPE & RESET</button> |
| </div> |
| </div> |
| </div> |
| |
| <script> |
| let lang = 'node'; |
| function setLang(l) { |
| lang = l; |
| document.getElementById('tag-node').className = l === 'node' ? 'flex-1 py-2 rounded bg-green-900 text-green-300 border border-green-500' : 'flex-1 py-2 rounded bg-slate-800 text-slate-500'; |
| document.getElementById('tag-py').className = l === 'python' ? 'flex-1 py-2 rounded bg-yellow-900 text-yellow-300 border border-yellow-500' : 'flex-1 py-2 rounded bg-slate-800 text-slate-500'; |
| } |
| |
| function handleTerm(e) { |
| if (e.key === 'Enter') { |
| const cmd = e.target.value; |
| runCmd('manual', cmd); |
| e.target.value = ''; |
| } |
| } |
| |
| function runCmd(type, manualCmd = '') { |
| const repo = document.getElementById('repo').value; |
| fetch('/execute', { |
| method: 'POST', |
| headers: {'Content-Type': 'application/json'}, |
| body: JSON.stringify({type, repo, lang, manual: manualCmd}) |
| }); |
| } |
| |
| const source = new EventSource("/stream"); |
| source.onmessage = (e) => { |
| const logDiv = document.getElementById('logs'); |
| logDiv.innerHTML += e.data + '<br>'; |
| logDiv.scrollTop = logDiv.scrollHeight; |
| }; |
| </script> |
| </body> |
| </html> |
| """ |
|
|
| def run_command(command, cwd=None): |
| global log_queue |
| if not os.path.exists(cwd): os.makedirs(cwd) |
| |
| full_cmd = f"bash -c \"{command}\"" |
| process = subprocess.Popen(full_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, cwd=cwd) |
| for line in process.stdout: |
| log_queue.append(f"> {line.strip()}") |
| process.wait() |
|
|
| @app.route('/') |
| def index(): return render_template_string(HTML_TEMPLATE) |
|
|
| @app.route('/execute', methods=['POST']) |
| def execute(): |
| data = request.json |
| cmd_type, repo, lang, manual = data['type'], data['repo'], data['lang'], data.get('manual', '') |
|
|
| if cmd_type == 'manual': |
| log_queue.append(f"<span class='text-blue-400'>[MANUAL] {manual}</span>") |
| threading.Thread(target=run_command, args=(manual, BOT_ROOT)).start() |
|
|
| elif cmd_type == 'clear': |
| if os.path.exists(BOT_ROOT): shutil.rmtree(BOT_ROOT) |
| log_queue.append("<span class='text-orange-400'>[SYSTEM] Workspace Cleaned.</span>") |
| |
| elif cmd_type == 'clone': |
| if os.path.exists(BOT_ROOT): shutil.rmtree(BOT_ROOT) |
| os.makedirs(BOT_ROOT) |
| log_queue.append(f"[SYSTEM] Cloning ke folder khusus...") |
| threading.Thread(target=run_command, args=(f"git clone {repo} .", BOT_ROOT)).start() |
| |
| elif cmd_type == 'install': |
| cmd = "npm install" if lang == 'node' else "pip install -r requirements.txt" |
| threading.Thread(target=run_command, args=(cmd, BOT_ROOT)).start() |
| |
| elif cmd_type == 'start': |
| |
| cmd = "exec -a 'python3_inference' node ." if lang == 'node' else "exec -a 'python3_inference' python3 main.py" |
| log_queue.append(f"<span class='text-red-400'>[SYSTEM] Menjalankan bot (Masking Bash)...</span>") |
| threading.Thread(target=run_command, args=(cmd, BOT_ROOT)).start() |
| |
| return {"status": "ok"} |
|
|
| @app.route('/stream') |
| def stream(): |
| def generate(): |
| while True: |
| if log_queue: yield f"data: {log_queue.pop(0)}\n\n" |
| else: time.sleep(0.5) |
| return Response(generate(), mimetype='text/event-stream') |
|
|
| if __name__ == "__main__": |
| app.run(host='0.0.0.0', port=7860) |
| |