Merhabalar hocalarım bir rezervasyon botum rezervasyonu tespiti çok hızlı ama kabul aşamasında çok geç kalıyor yardımcı olabilecek varmı acaba, Chatgpt ve gemini ile sağlıklı cevaplar alamadım ,
import asyncio
import time
import json
import certifi 
import cloudscraper
import random
from fake_useragent import UserAgent
import os
from datetime import datetime



NUM_POLLING_WORKERS = 7 
STATUS_UPDATE_INTERVAL = 0.5
ACCEPT_RETRY_DELAY = 1.5  
MAX_ACCEPT_RETRIES = 2     
ACCEPT_TIMEOUT = 20        


BOOKING_URL = "api1"
ACCEPT_URL = "api2"


LOGIN_HASH = "hash1"
ACCEPT_LOGIN_HASH = "hash2"
VEHICLE_ID = "36979"
TELEGRAM_BOT_TOKEN = "token" 
TELEGRAM_CHAT_ID = "id"


PROXY_FILE = "proxy.txt"


previous_hashes = set()
lock = asyncio.Lock()
success_count = 0 
ua = UserAgent()
loaded_proxies = []


try:
    accept_scraper = cloudscraper.create_scraper(
        browser={"browser": "chrome", "platform": "windows", "mobile": False}
    )
    print("\n✅ Kabul istekleri için Cloudscraper başarıyla başlatıldı.")
except Exception as e:
    print(f"\n❌ Kabul istekleri için Cloudscraper başlatılamadı: {e}")
    accept_scraper = None # Hata durumunda None olarak ayarla
# ---------------------------------------------

# ===================================
#     FONKSİYONLAR
# ===================================

def get_current_time_ms():
  
    return datetime.now().strftime('%H:%M:%S.%f')[:-3]

def load_proxies_from_file(filename=PROXY_FILE):
    """proxy.txt dosyasından ip:port:user:pass formatındaki proxy'leri okur."""
    proxies = []
    if not os.path.exists(filename):
        print(f"\n❌ HATA: Proxy dosyası bulunamadı: {filename}")
        return []
    try:
        with open(filename, 'r') as f:
            for line_num, line in enumerate(f):
                line = line.strip()
                if not line or line.startswith('#'):
                    continue
                parts = line.split(':')
                if len(parts) == 4:
                    ip, port, username, password = parts
                    # IPv6 adresleri için köşeli parantez kontrolü
                    if ':' in ip and not (ip.startswith('[') and ip.endswith(']')):
                        ip = f"[{ip}]" # Köşeli parantez ekle
                    proxy_url = f"http://{username}:{password}@{ip}:{port}"
                    proxy_dict = {"http": proxy_url, "https": proxy_url}
                    proxies.append(proxy_dict)
                else:
                    print(f"\n⚠️ Uyarı: {filename} dosyasındaki {line_num+1}. satır geçersiz formatta: '{line}'. Format ip:port:user:pass olmalı.")
    except Exception as e:
        print(f"\n❌ HATA: Proxy dosyası okunurken hata oluştu ({filename}): {e}")
        return []

    if not proxies:
        print(f"\n❌ HATA: {filename} dosyasından geçerli proxy yüklenemedi.")
    else:
        print(f"\n✅ {len(proxies)} adet proxy başarıyla yüklendi: {filename}")
    return proxies

def get_random_headers():
    """Rastgele User-Agent ile HTTP başlıkları oluşturur."""
    return {
        "Content-Type": "application/json",
        "User-Agent": ua.random
    }

# ==========================================================
# === send_telegram_message (SSL Hatası için Düzeltildi) ===
# ==========================================================
async def send_telegram_message(message):
    """Telegram'a asenkron olarak bildirim gönderir (SSL doğrulaması ile)."""
    if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID:
        # print("\nℹ️ Telegram token veya chat ID ayarlanmadığı için bildirim gönderilmedi.")
        return

    url = f"https://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage"
    payload = {"chat_id": TELEGRAM_CHAT_ID, "text": message, "parse_mode": "Markdown"}
    sender_scraper = None
    try:
        # Telegram için ayrı, basit bir scraper kullan
        sender_scraper = cloudscraper.create_scraper()
        # Cloudscraper doğrudan async context manager desteklemez, to_thread kullanmak daha güvenli
        response = await asyncio.to_thread(
            sender_scraper.post,
            url,
            json=payload,
            timeout=15,
            verify=certifi.where() 
        )
        if response.status_code != 200:
            response_text = response.text
            print(f"\n[{get_current_time_ms()}] ❌ Telegram Hatası: {response.status_code} - {response_text[:200]}")
    except asyncio.TimeoutError:
        print(f"\n[{get_current_time_ms()}] ⚠️ Telegram Bağlantı Hatası: Zaman aşımı (Timeout)")
    except Exception as e:
        
        print(f"\n[{get_current_time_ms()}] ⚠️ Telegram Bağlantı Hatası: {type(e).__name__} - {e}")
    finally:
         if sender_scraper:
             
             pass
# ==========================================================
# === /send_telegram_message ===
# ==========================================================

async def accept_booking(booking_hash):
    """Bir rezervasyonu PROXYSİZ olarak kabul etmeye çalışır (Geliştirilmiş Loglama ile)."""
    global previous_hashes
    global lock
    global accept_scraper # Global scraper'ı kullan

    start_time_accept = get_current_time_ms()

    if accept_scraper is None:
        print(f"\n[{start_time_accept}] 🚫 Kabul Scraper başlatılamadığı için kabul işlemi yapılamıyor: {booking_hash}")
        return False

    # --- Hash Kontrolü (Kilitle) ---
    async with lock:
        if booking_hash in previous_hashes:
            # print(f"\n[{start_time_accept}] ℹ️ Zaten işleniyor/işlendi: {booking_hash}") # Çok sık log olmaması için yorumda
            return False # Zaten işleniyorsa veya işlendiyse çık
        previous_hashes.add(booking_hash)
    # -----------------------------

    print(f"\n[{start_time_accept}] 🚀 Kabul işlemi başlatıldı (PROXYSİZ): {booking_hash}")

    accept_payload = {
        "login_hash": ACCEPT_LOGIN_HASH,
        "booking_hash": booking_hash,
        "vehicle_id": VEHICLE_ID,
        "refuse": "accept"
    }
    headers = get_random_headers()

    for attempt in range(MAX_ACCEPT_RETRIES):
        current_time_attempt = get_current_time_ms()
        print(f"  [{current_time_attempt}] ➡️ Kabul Denemesi {attempt + 1}/{MAX_ACCEPT_RETRIES} gönderiliyor: {booking_hash}")
        try:
            accept_response = await asyncio.to_thread(
                accept_scraper.post, # Global scraper'ı kullan
                ACCEPT_URL,
                headers=headers,
                json=accept_payload,
                verify=certifi.where(), # Burada zaten vardı
                timeout=ACCEPT_TIMEOUT # Ayarlanan timeout
            )

            current_time_response = get_current_time_ms()
            response_text_snippet = accept_response.text[:200] if accept_response.text else "Yanıt yok" # Hata mesajını kısalt

            if accept_response.status_code == 200:
                print(f"  [{current_time_response}] ✅ BAŞARILI KABUL! (PROXYSİZ) - Deneme {attempt + 1}: {booking_hash}")
                message = f"✅ Rezervasyon Kabul Edildi!\n\nHash: `{booking_hash}`\nZaman: {current_time_response}\n\n🔗 [Detay](https://site.com/{booking_hash})"
                asyncio.create_task(send_telegram_message(message)) # Telegram'a gönder
                return True # Başarılı, fonksiyondan çık
            else:
                # --- Detaylı Hata Loglaması ---
                print(f"  [{current_time_response}] ❌ KABUL HATASI (PROXYSİZ) - Durum Kodu: {accept_response.status_code} - Deneme {attempt + 1}/{MAX_ACCEPT_RETRIES}")
                print(f"      Yanıt Başlangıcı: {response_text_snippet}...")
                print(f"      Hash: {booking_hash}")
                # ------------------------------
               
                if 400 <= accept_response.status_code < 500:
                     print(f"  [{current_time_response}] 🛑 4xx hatası alındı, tekrar denenmeyecek: {booking_hash}")
                     return False # Tekrar deneme

                if attempt + 1 < MAX_ACCEPT_RETRIES:
                    wait_time = ACCEPT_RETRY_DELAY * (2 ** attempt) # Exponential backoff
                    print(f"  [{current_time_response}] ⏳ {wait_time:.1f} sn bekleniyor...")
                    await asyncio.sleep(wait_time)

        except Exception as e:
            current_time_exception = get_current_time_ms()
            # --- Detaylı İstisna Loglaması ---
            print(f"  [{current_time_exception}] ⚠️ KABUL BAĞLANTI/İSTİSNA HATASI (PROXYSİZ) - Deneme {attempt + 1}/{MAX_ACCEPT_RETRIES}")
            print(f"      Hata: {type(e).__name__} - {e}")
            print(f"      Hash: {booking_hash}")
            # ------------------------------
            if attempt + 1 < MAX_ACCEPT_RETRIES:
                 wait_time = ACCEPT_RETRY_DELAY * (2 ** attempt) # Exponential backoff
                 print(f"  [{current_time_exception}] ⏳ {wait_time:.1f} sn bekleniyor...")
                 await asyncio.sleep(wait_time)

   
    final_fail_time = get_current_time_ms()
    print(f"\n[{final_fail_time}] 🚫 KABUL BAŞARISIZ (PROXYSİZ) (Tüm denemeler bitti): {booking_hash}")
    return False

# =============================================
# === check_new_bookings FONKSİYONU (await ile güncellendi) ===
# =============================================
async def check_new_bookings(response_text):
    """
    API yanıtını kontrol eder ve yeni rezervasyonları kabul için İŞLEME ALIR.
    (await kullanıldığı için, bu fonksiyon içinde rezervasyonlar sırayla işlenir)
    """
    try:
        data = json.loads(response_text)
        # Anahtar varlık kontrollerini artır
        if not isinstance(data, dict): return
        api_data = data.get("data")
        if not isinstance(api_data, dict): return
        current_bookings = api_data.get("bookings")
        if not isinstance(current_bookings, list): return

    except json.JSONDecodeError as e:
        # print(f"\n[{get_current_time_ms()}] ⚠️ JSON Decode Hatası: {e} - Yanıt: {response_text[:100]}...") # Gürültülü olabilir
        return
    except Exception as e:
        print(f"\n[{get_current_time_ms()}] ❌ Beklenmedik Hata (check_new_bookings): {type(e).__name__} - {e}")
        return

    if current_bookings:
        current_time_check = get_current_time_ms()
        print(f"\n[{current_time_check}] Yeni rezervasyon(lar) bulundu ({len(current_bookings)} adet). Sırayla işleniyor...")

        for booking in current_bookings:
            if isinstance(booking, dict) and "booking_hash_link" in booking:
                booking_hash = booking["booking_hash_link"]

                # Log mesajını güncelle (bekleme olduğunu belirtmek için)
                print(f"  -> [{get_current_time_ms()}] ✨ REZERVASYON: {booking_hash} -> Kabul işlemi başlatılıyor ve bekleniyor (await)...")

                try:
                    # === DEĞİŞİKLİK BURADA (Önceki adımda yapıldı) ===
                    # accept_booking fonksiyonunu çağır ve tamamlanmasını bekle.
                    success = await accept_booking(booking_hash)
                    # ============================================

                 
                    if success:
                       pass
                    else:
                       pass

                except Exception as e:
         
                    print(f"  -> [{get_current_time_ms()}] ❌ KRİTİK HATA (check_new_bookings içinde await sırasında): {booking_hash} - {e}")
            else:
               
                 print(f"  -> [{get_current_time_ms()}] ⚠️ Geçersiz rezervasyon verisi formatı atlandı: {booking}")

       
        print(f"--- [{get_current_time_ms()}] Bulunan rezervasyonların işlenmesi tamamlandı (check_new_bookings). ---")
# =============================================
# === /check_new_bookings FONKSİYONU ===
# =============================================

async def poll_worker(worker_id):

    global success_count
    global lock
    global loaded_proxies

    # Her worker için ayrı scraper instance
    worker_scraper = None # Başlangıçta None
    try:
        worker_scraper = cloudscraper.create_scraper(
            browser={"browser": "chrome", "platform": "windows", "mobile": False}
        )
    except Exception as e:
        print(f"[{get_current_time_ms()}] [Worker {worker_id}] ❌ Başlatılamadı: Scraper oluşturma hatası: {e}")
        return # Scraper oluşturulamazsa worker çalışamaz

    polling_interval = 0 # Başlangıçta bekleme yok
    MAX_POLL_RETRIES = 1 # Sorgu için tekrar deneme sayısı
    POLL_RETRY_DELAY = 1 # Sorgu tekrar deneme gecikmesi

    while True:
        await asyncio.sleep(polling_interval) # Döngüler arası (varsa) bekleme

        if not loaded_proxies:
            await asyncio.sleep(10)
            continue

        # --- Proxy Seçimi ve İstek Hazırlığı ---
        try:
            proxies = random.choice(loaded_proxies)
        except IndexError:
             await asyncio.sleep(5)
             continue

        headers = get_random_headers()
        response = None
        # ------------------------------------

        for attempt in range(MAX_POLL_RETRIES):
            try:
                payload = {"login_hash": LOGIN_HASH}
                response = await asyncio.to_thread(
                    worker_scraper.post,
                    BOOKING_URL,
                    headers=headers,
                    json=payload,
                    verify=certifi.where(), # Sorgulama için de SSL doğrulama ekleyelim
                    proxies=proxies,
                    timeout=15 # Sorgu timeout'u
                )

                if response.status_code == 200:
                    async with lock:
                        success_count += 1

                    response_text = response.text
                    
                    asyncio.create_task(check_new_bookings(response_text))
                    polling_interval = 0 # Başarılı ise hemen tekrar dene
                    break # Başarılı, deneme döngüsünden çık

                else:
                     if 400 <= response.status_code < 500:
                         polling_interval = 0.5 
                         break #

                     if attempt + 1 < MAX_POLL_RETRIES:
                         await asyncio.sleep(POLL_RETRY_DELAY * (2 ** attempt))
                     else:
                          polling_interval = 0.5 # 

            except Exception as e:
                polling_interval = 0.5
                if attempt + 1 < MAX_POLL_RETRIES:
                    await asyncio.sleep(POLL_RETRY_DELAY * (2 ** attempt))


async def status_updater():
   
    global success_count
    global lock
    last_print_time = time.monotonic()

    while True:
        await asyncio.sleep(max(0, STATUS_UPDATE_INTERVAL - (time.monotonic() - last_print_time)))
        last_print_time = time.monotonic()

        async with lock:
            current_count = success_count

        current_time_str = get_current_time_ms()
        print(f"\r🔄 Toplam Başarılı Sorgu: {current_count} | Zaman: {current_time_str}    ", end="")


# ===================================
#     ANA PROGRAM YÖNETİMİ
# ===================================
async def main():
    """Worker ve status task'larını başlatır ve çalışmasını bekler."""
    global loaded_proxies
    global accept_scraper

    if accept_scraper is None:
         print("\n🛑 Kabul Scraper başlatılamadığı için program sonlandırılıyor.")
         return

    loaded_proxies = load_proxies_from_file(PROXY_FILE)
    if not loaded_proxies:
        print("\n🛑 Proxy yüklenemediği için worker'lar başlatılamıyor.")
        return

    print(f"\n🚀 {NUM_POLLING_WORKERS} adet sorgulama worker'ı ve durum güncelleyici başlatılıyor...")
    tasks = []
    for i in range(NUM_POLLING_WORKERS):
        task = asyncio.create_task(poll_worker(i))
        tasks.append(task)

    status_task = asyncio.create_task(status_updater())
    tasks.append(status_task)

    print(f"\n✅ {len(tasks)} görev (worker + status) başarıyla oluşturuldu ve çalışıyor.")
    print("-" * 35)

    try:
        await asyncio.gather(*tasks)
    except asyncio.CancelledError:
         print("\nℹ️ Görevler iptal edildi.")
    except Exception as e:
        print(f"\n❌ Ana görevde beklenmedik hata: {type(e).__name__} - {e}")
    finally:
        print("\n🛑 Program sonlandırılıyor.")


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\nCTRL+C algılandı. Program kapatılıyor...")
    except Exception as e:
         print(f"\n❌ Program başlangıcında kritik hata: {e}")