dfr / app.py
UNUSUALxd's picture
Update app.py
e1a678f verified
Raw
History Blame Contribute Delete
6.44 kB
import os
import asyncio
import random
from collections import deque
from aiohttp import web
# 1. PRE-IMPORT CONFIGURATION: Inject environment variables first
from dotenv import load_dotenv
load_dotenv()
# ⚑ Import 'idle' correctly to keep the bot listening
from pyrogram import idle
# Strict Environment Validation Framework
REQUIRED_ENV_VARS = ["SESSION_GIST_URL", "BOT_TOKEN", "ADMIN_IDS", "CHECK_FILE_URL", "SNIPE_FILE_URL", "MONGO_URI", "API_ID", "API_HASH"]
for var in REQUIRED_ENV_VARS:
if not os.environ.get(var):
raise ValueError(f"🚨 CRITICAL BOOT FAILURE: Missing Environment Variable: {var}")
# 2. MODULE IMPORTS
from utils.logger import log
from utils.loader import fetch_txt_file, fetch_json_file
from bot.database import db
from bot.state import state
from bot.client import bot, init_clients
from bot.scheduler import scheduler, shutdown_campers
from bot.scraper import scraper
async def handle_ping(request):
"""OPSEC Decoy server to satisfy PaaS port requirements."""
return web.json_response({"error": "Forbidden", "status": 403}, status=403)
async def keep_alive_server():
app = web.Application()
app.router.add_get('/', handle_ping)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, '0.0.0.0', 7860)
await site.start()
log("πŸ›‘οΈ Enterprise Keep-alive server started on port 7860.")
async def safe_boot_sequence():
"""⚑ ENTERPRISE STABILIZATION: Fault-Tolerant Boot Sequence"""
log("πŸ”„ Initiating Enterprise Boot Sequence...")
try:
# Initialize DB and Settings
await db.init_db()
await db.load_settings(state)
# ⚑ Load Admins from Environment and Database
if "admin_ids" not in state:
state["admin_ids"] = set()
env_admins = os.environ.get("ADMIN_IDS", "")
if env_admins:
for x in env_admins.split(","):
if x.strip().lstrip('-').isdigit():
state["admin_ids"].add(int(x.strip()))
db_admins = await db.get_admins()
for adm in db_admins:
state["admin_ids"].add(adm)
log(f"πŸ”‘ Authorization loaded for {len(state['admin_ids'])} admins.")
# Boot up the Scraper's HTTP pool
await scraper.init_session()
# Load Target Queues
temp_c = list(set(await fetch_txt_file(os.environ.get("CHECK_FILE_URL"))))
temp_s = list(set(await fetch_txt_file(os.environ.get("SNIPE_FILE_URL"))))
state["unavailable_set"] = await db.get_unavailable_set()
custom_snipes = await db.get_custom_snipes()
for u in custom_snipes:
if u not in temp_s: temp_s.append(u)
# ⚑ Restore Watchdog and Fragment Lists from MongoDB
if "watch_submitters" not in state:
state["watch_submitters"] = {}
if "watchdog_queue" not in state:
state["watchdog_queue"] = set()
if "fragcheck_queue" not in state:
state["fragcheck_queue"] = set()
watchdog_data = await db.get_watchdog()
for u, user_id in watchdog_data.items():
state["watchdog_queue"].add(u)
state["watch_submitters"][u] = user_id
frag_data = await db.get_fragcheck()
for u in frag_data:
state["fragcheck_queue"].add(u)
log(f"πŸ“₯ Restored {len(state['watchdog_queue'])} Watchdog targets & {len(state['fragcheck_queue'])} Fragment targets from Database.")
if state["db_filter_on"]:
before = len(temp_c)
temp_c = [u for u in temp_c if u not in state["unavailable_set"]]
state["skipped_by_filter"] = before - len(temp_c)
else:
state["skipped_by_filter"] = 0
random.shuffle(temp_c)
random.shuffle(temp_s)
accounts_data = await fetch_json_file(os.environ.get("SESSION_GIST_URL"))
if not accounts_data or "accounts" not in accounts_data:
raise ValueError("Failed to fetch Session Gist. Boot aborted.")
state["check_queue"] = deque(temp_c)
state["snipe_queue"] = deque(temp_s)
# Initialize UI Bot
await bot.start()
# Alias handlers to link your commands and buttons to the active bot
import bot.handlers as ui_handlers
# Initialize Snipe Fleet
await init_clients(accounts_data["accounts"])
log(f"βœ… Boot Successful: Loaded {len(state['account_pool'])} accounts. Check: {len(temp_c)} | Snipe: {len(temp_s)}")
return True
except Exception as e:
log(f"🚨 BOOT FAILURE: {e}")
return False
async def main():
try:
boot_success = await safe_boot_sequence()
if not boot_success:
return
from bot.scheduler import account_status_job, schedule_next, watchdog_cycle, reset_hourly_counters, flush_stats_to_db
# Start Background Engines
scheduler.add_job(account_status_job, "interval", minutes=1)
scheduler.add_job(watchdog_cycle, "interval", seconds=3)
scheduler.add_job(reset_hourly_counters, "cron", minute=0)
scheduler.add_job(flush_stats_to_db, "interval", minutes=1)
schedule_next("check", state["check_interval"])
schedule_next("snipe", state["snipe_interval"])
scheduler.start()
from bot.handlers import sync_fleet
await sync_fleet()
from bot.alerts import alert_admin
await alert_admin("🟒 <b>Enterprise System Online</b>\nAll modules restored and listening.")
# ⚑ ENTERPRISE FIX: Run both concurrently so the bot actively listens to buttons
await asyncio.gather(
keep_alive_server(),
idle()
)
except KeyboardInterrupt:
pass
finally:
log("πŸ›‘ Initiating Graceful Shutdown...")
shutdown_campers()
for acc in state["account_pool"]:
if getattr(acc.client, "is_connected", False):
await acc.client.stop()
if getattr(bot, "is_connected", False):
await bot.stop()
await scraper.close_session()
if __name__ == "__main__":
asyncio.run(main())