File size: 4,023 Bytes
baf6302
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# main.py
import os
import logging
import asyncio
from concurrent.futures import ThreadPoolExecutor

from hydrogram import Client, idle
from hydrogram.errors import AuthKeyUnregistered

from config import Config
import handlers # To access register_handlers

# --- Global Executor ---
# Defined here so it can be imported by handlers if structured that way,
# or simply passed/used within main_async_logic.
# max_workers can be adjusted based on CPU cores or expected load.
executor = ThreadPoolExecutor(max_workers=(os.cpu_count() or 1) + 4)


# --- Logging Setup ---
def setup_logging():
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(name)s - %(levelname)s - [%(module)s.%(funcName)s:%(lineno)d] - %(message)s',
    )
    logging.getLogger("hydrogram").setLevel(logging.WARNING) # Reduce hydrogram verbosity
    return logging.getLogger(__name__)

logger = setup_logging()


# --- Directory and Font Checks ---
def run_startup_checks():
    logger.info("Running startup checks...")
    # Check directories (expected to be created by Dockerfile or COPY . .)
    if not os.path.isdir(Config.PREDEFINED_TEMPLATES_DIR):
        logger.error(f"FATAL: Templates directory '{Config.PREDEFINED_TEMPLATES_DIR}' not found or is not a directory in the repository root.")
        return False
    if not os.path.isdir(Config.OUTPUT_DIR): # This one is created by Dockerfile if not present
        logger.info(f"Output directory '{Config.OUTPUT_DIR}' not found, will be created by Dockerfile.")
        # It's okay if this one is missing initially, Dockerfile handles it.
        # But templates dir *must* come from repo.

    # Check if templates directory has content (optional but good)
    try:
        if os.path.isdir(Config.PREDEFINED_TEMPLATES_DIR) and not os.listdir(Config.PREDEFINED_TEMPLATES_DIR):
            logger.warning(f"Templates directory '{Config.PREDEFINED_TEMPLATES_DIR}' is empty. Predefined templates will not work.")
    except Exception as e:
        logger.warning(f"Could not check contents of templates directory: {e}")


    logger.info("Required directories check complete.")
    logger.info(f"Attempting to use font: '{Config.FONT_PATH}' (requires system font access).")
    return True

# --- Main Application Logic ---
async def main_async_logic():
    logger.info("Initializing Hydrogram Bot Client...")

    app = Client(
        name=Config.SESSION_NAME,
        api_id=Config.API_ID,
        api_hash=Config.API_HASH,
        bot_token=Config.BOT_TOKEN,
        workdir="/app" # Ensures .session file is stored in /app (writable)
    )

    handlers.register_handlers(app)
    logger.info("Message handlers registered.")

    try:
        logger.info("Starting Hydrogram client (as BOT)...")
        await app.start()
        me = await app.get_me()
        logger.info(f"Successfully started. Bot: {me.first_name} (Username: @{me.username}, ID: {me.id})")
        logger.info("Bot is up and listening for messages from admins!")
        await idle()
    except AuthKeyUnregistered:
        logger.critical("BOT TOKEN INVALID or REVOKED. Please check your BOT_TOKEN secret in Hugging Face.")
    except Exception as e:
        logger.critical(f"Error starting or running Hydrogram client: {e}", exc_info=True)
    finally:
        logger.info("Shutting down executor...")
        executor.shutdown(wait=True)
        if app.is_initialized and app.is_connected: # Check if client was started
            logger.info("Stopping Hydrogram client...")
            await app.stop()
        logger.info("Shutdown complete.")

if __name__ == "__main__":
    if not run_startup_checks():
        logger.critical("Startup checks failed. Exiting.")
        exit(1)

    try:
        asyncio.run(main_async_logic())
    except KeyboardInterrupt:
        logger.info("Bot stopped by KeyboardInterrupt.")
    except Exception as e:
        logger.critical(f"Unhandled exception in main: {e}", exc_info=True)
    finally:
        logger.info("Application terminated.")