worker4 / app.py
worker-3's picture
Update app.py
a4319d2 verified
Raw
History Blame Contribute Delete
9.66 kB
import os
import logging
import subprocess
import time
import threading
import requests
import json
import zipfile
import shutil
from pathlib import Path
from flask import Flask, request, jsonify
from huggingface_hub import HfApi
# --- AYARLAR ---
app = Flask(__name__)
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
logger = logging.getLogger(__name__)
# Hugging Face Environment Variables
SPACE_ID = os.getenv('SPACE_ID') # Örn: kullaniciadi/space-adi
HF_TOKEN = os.getenv('HF_TOKEN') # Write yetkili token
MEGA_ACCOUNTS_JSON = os.getenv('MEGA_ACCOUNTS_JSON', '[]') # Hesap listesi
# Hesapları Yükle
try:
MEGA_ACCOUNTS = json.loads(MEGA_ACCOUNTS_JSON)
logger.info(f"✅ {len(MEGA_ACCOUNTS)} Mega hesabı sisteme yüklendi.")
except Exception as e:
MEGA_ACCOUNTS = []
logger.warning(f"⚠️ Hesaplar yüklenemedi: {str(e)}")
current_account_index = 0
current_task = None
task_lock = threading.Lock()
DOWNLOAD_DIR = Path("/tmp/downloads")
DOWNLOAD_DIR.mkdir(exist_ok=True, parents=True)
# 2 Saat Timeout (Büyük dosyalar için)
MEGACMD_TIMEOUT = 7200
# --- YARDIMCI FONKSİYONLAR ---
def run_megacmd(command, timeout=30):
"""MegaCMD komutlarını çalıştırır ve çıktıları analiz eder."""
try:
if isinstance(command, str):
command = command.split()
logger.info(f"🔧 Komut: {' '.join(command)}")
result = subprocess.run(command, capture_output=True, text=True, timeout=timeout)
output = result.stdout.strip()
error = result.stderr.strip()
combined = (output + " " + error).lower()
# IP BAN KONTROLÜ
if any(k in combined for k in ['api_eblocked', 'temporary ban', 'connection refused', 'blocked', 'bus error']):
logger.error(f"🚨 IP BAN ALGILANDI: {error}")
return {'success': False, 'critical': True, 'error': error}
# KOTA KONTROLÜ
if 'bandwidth quota exceeded' in combined or 'transfer quota exceeded' in combined:
logger.warning(f"📊 KOTA DOLDU: {error}")
return {'success': False, 'bandwidth_exceeded': True, 'error': error}
if result.returncode != 0:
return {'success': False, 'error': error}
return {'success': True, 'output': output}
except subprocess.TimeoutExpired:
return {'success': False, 'timeout': True, 'error': f'Timeout {timeout}s'}
except Exception as e:
return {'success': False, 'error': str(e)}
def init_megacmd_server():
"""Mega sunucusunu arka planda başlatır."""
try:
logger.info("🚀 MegaCMD server başlatılıyor...")
subprocess.Popen(['mega-cmd-server'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
time.sleep(7) # Serverın kendine gelmesi için bekle
return True
except Exception as e:
logger.error(f"❌ MegaCMD server hatası: {str(e)}")
return False
def mega_login(email, password):
"""Mega hesabına giriş yapar."""
try:
logger.info(f"🔐 Giriş yapılıyor: {email}")
run_megacmd(['mega-logout'], timeout=10)
time.sleep(2)
result = run_megacmd(['mega-login', email, password], timeout=45)
if result['success']:
logger.info(f"✅ Giriş başarılı: {email}")
return True
return False
except:
return False
def get_next_account():
"""Sıradaki hesabı getirir (Zombie Mode)."""
global current_account_index
if not MEGA_ACCOUNTS: return None
account = MEGA_ACCOUNTS[current_account_index]
current_account_index = (current_account_index + 1) % len(MEGA_ACCOUNTS)
return account
def rotate_account():
"""Hesap değiştirir."""
logger.warning("🔄 HESAP ROTASYONU BAŞLATILIYOR...")
account = get_next_account()
if not account: return False
return mega_login(account['email'], account['password'])
def phoenix_restart():
"""IP Ban yiyince Space'i yeniden başlatır (Phoenix Mode)."""
try:
if not SPACE_ID or not HF_TOKEN:
logger.error("❌ SPACE_ID veya HF_TOKEN eksik, restart atılamıyor!")
return False
logger.warning("🔥 PHOENIX MODE: IP Banlandı, Space restart ediliyor...")
api = HfApi(token=HF_TOKEN)
api.restart_space(repo_id=SPACE_ID)
return True
except Exception as e:
logger.error(f"❌ Restart hatası: {str(e)}")
return False
def send_webhook(webhook_url, data):
"""Render tarafına durum bildirir."""
if not webhook_url: return
try:
requests.post(webhook_url, json=data, timeout=10)
except:
pass
# --- İŞLEM FONKSİYONU ---
def process_task(task_data):
global current_task
task_id = task_data['task_id']
mega_url = task_data['mega_url']
webhook_url = task_data.get('webhook_url')
try:
logger.info(f"🚀 İşlem Başladı: {task_id}")
send_webhook(webhook_url, {'status': 'started', 'progress': 0})
# 1. İlk hesapla giriş
if MEGA_ACCOUNTS:
acc = MEGA_ACCOUNTS[0]
mega_login(acc['email'], acc['password'])
# 2. İndirme Klasörü
target_dir = DOWNLOAD_DIR / task_id
target_dir.mkdir(exist_ok=True)
# 3. İndirme Döngüsü
max_retries = 10
retry_count = 0
success = False
while retry_count < max_retries:
send_webhook(webhook_url, {'status': 'downloading', 'progress': 10 + (retry_count * 2)})
# mega-get komutu (Klasörler için recursive çalışır)
result = run_megacmd(['mega-get', mega_url, str(target_dir)], timeout=MEGACMD_TIMEOUT)
# 3.1 IP Ban Durumu
if result.get('critical'):
send_webhook(webhook_url, {'status': 'error', 'error': 'IP Ban - Restarting System'})
phoenix_restart()
return # Space kapanacak zaten
# 3.2 Kota Dolma Durumu
if result.get('bandwidth_exceeded'):
logger.warning("📊 Kota doldu, hesap değiştiriliyor...")
if rotate_account():
retry_count += 1
time.sleep(3)
continue # Döngüye devam et, kaldığı yerden indirir
else:
raise Exception("Hesap rotasyonu başarısız, hesap kalmadı!")
# 3.3 Başarılı
if result['success']:
success = True
break
# 3.4 Diğer Hatalar
logger.error(f"İndirme hatası: {result.get('error')}")
break # Bilinmeyen hatada döngüden çık
if not success:
raise Exception("İndirme tamamlanamadı.")
# 4. ZIPLEME
logger.info("📦 Zipleniyor...")
send_webhook(webhook_url, {'status': 'zipping', 'progress': 80})
zip_path = DOWNLOAD_DIR / f"{task_id}.zip"
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
for root, dirs, files in os.walk(target_dir):
for file in files:
file_path = os.path.join(root, file)
arcname = os.path.relpath(file_path, target_dir)
zipf.write(file_path, arcname)
# 5. UPLOAD (BURAYI KENDİNE GÖRE DÜZENLE!)
# Şu anlık sadece başarılı mesajı dönüyoruz. Dosya /tmp içinde.
# Buraya Google Drive, Telegram veya AWS S3 upload kodu eklenmeli.
upload_url = "https://dosya-yuklendi-varsayildi.com"
send_webhook(webhook_url, {
'status': 'completed',
'progress': 100,
'download_url': upload_url
})
logger.info(f"✅ İşlem Tamam: {task_id}")
# Temizlik
shutil.rmtree(target_dir, ignore_errors=True)
if os.path.exists(zip_path):
os.remove(zip_path)
except Exception as e:
logger.error(f"🔥 Kritik Hata: {str(e)}")
send_webhook(webhook_url, {'status': 'failed', 'error': str(e)})
finally:
with task_lock:
current_task = None
# --- FLASK ENDPOINTS ---
@app.route('/health', methods=['GET'])
def health():
"""Render bu adrese ping atar, worker yaşıyor mu bakar."""
with task_lock:
is_busy = current_task is not None
return jsonify({'status': 'healthy', 'busy': is_busy}), 200
@app.route('/process', methods=['POST'])
def process():
"""Render'dan gelen iş emrini alır."""
try:
with task_lock:
if current_task is not None:
return jsonify({'error': 'Worker şu an meşgul'}), 503
data = request.get_json()
task_id = f"task_{int(time.time())}"
task_data = {
'task_id': task_id,
'mega_url': data['mega_url'],
'webhook_url': data.get('webhook_url')
}
with task_lock:
current_task = task_data
# Arka planda başlat
t = threading.Thread(target=process_task, args=(task_data,))
t.daemon = True
t.start()
return jsonify({'success': True, 'task_id': task_id}), 200
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
# MegaCMD'yi başlat
if not init_megacmd_server():
exit(1)
# Flask'ı başlat
app.run(host='0.0.0.0', port=7860)