Spaces:
Runtime error
Runtime error
Update main.py
Browse files
main.py
CHANGED
|
@@ -14,79 +14,43 @@ logger = logging.getLogger(__name__)
|
|
| 14 |
# Retrieve Session String from Hugging Face secrets
|
| 15 |
SESSION_STRING = os.environ.get('SESSION_STRING')
|
| 16 |
|
| 17 |
-
# ---
|
| 18 |
-
#
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
Path("."), # Current working directory (e.g., /app if WORKDIR is /app)
|
| 22 |
-
]
|
| 23 |
-
APP_STORAGE_SUBDIR_NAME = "app_template_storage" # Subdirectory to hold our template
|
| 24 |
TEMPLATE_FILENAME = "user_template_content.txt"
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
|
|
|
|
|
|
| 28 |
|
| 29 |
-
|
| 30 |
-
"""Tries to find/create a writable directory for the template file."""
|
| 31 |
-
global DATA_DIR, TEMPLATE_FILE_PATH
|
| 32 |
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
logger.warning(f"Failed to create/use directory {potential_data_dir} due to {type(e).__name__}: {e}. Trying next candidate.")
|
| 52 |
-
|
| 53 |
-
# 2. If subdirectory creation failed, try to place the file directly in a candidate base directory
|
| 54 |
-
logger.warning("Could not create/use a dedicated subdirectory. Attempting to use a base directory directly for the file.")
|
| 55 |
-
for base_candidate in PERSISTENT_STORAGE_CANDIDATES:
|
| 56 |
-
potential_template_file_path = base_candidate / TEMPLATE_FILENAME
|
| 57 |
-
try:
|
| 58 |
-
# Test writability by trying to open the file in append mode (creates if not exists)
|
| 59 |
-
with open(potential_template_file_path, 'a'):
|
| 60 |
-
pass # Just testing if open works without error
|
| 61 |
-
# If we are here, it means we can probably write the file directly.
|
| 62 |
-
DATA_DIR = base_candidate # The "data directory" is now the base itself
|
| 63 |
-
TEMPLATE_FILE_PATH = potential_template_file_path
|
| 64 |
-
logger.info(f"Using base directory {DATA_DIR.resolve()} directly for template file: {TEMPLATE_FILE_PATH}")
|
| 65 |
-
return
|
| 66 |
-
except PermissionError:
|
| 67 |
-
logger.warning(f"Permission denied to write template file directly in {base_candidate.resolve()}. Trying next candidate.")
|
| 68 |
-
except Exception as e:
|
| 69 |
-
logger.warning(f"Failed to write template file in {base_candidate.resolve()} due to {type(e).__name__}: {e}. Trying next candidate.")
|
| 70 |
-
|
| 71 |
-
# If all attempts fail
|
| 72 |
-
logger.error("CRITICAL: Unable to find or create a writable location for the template file.")
|
| 73 |
-
# Set paths to None to indicate failure; the app might crash or malfunction later.
|
| 74 |
-
# A more robust solution would be to exit here.
|
| 75 |
-
DATA_DIR = None
|
| 76 |
-
TEMPLATE_FILE_PATH = None
|
| 77 |
-
# Consider exiting: exit("Failed to initialize storage.")
|
| 78 |
-
|
| 79 |
-
# Call this ONCE at the start of the script
|
| 80 |
-
initialize_storage_paths()
|
| 81 |
-
|
| 82 |
-
# Global variable to hold the loaded template content
|
| 83 |
-
current_template_content = None
|
| 84 |
|
| 85 |
# --- Helper Functions for Template Management ---
|
| 86 |
async def load_template_from_file():
|
| 87 |
"""Loads template content from the persistent file."""
|
| 88 |
global current_template_content
|
| 89 |
-
if not TEMPLATE_FILE_PATH:
|
| 90 |
logger.error("Template file path is not configured. Cannot load template.")
|
| 91 |
current_template_content = None
|
| 92 |
return
|
|
@@ -106,15 +70,12 @@ async def load_template_from_file():
|
|
| 106 |
async def save_template_to_file(content: str):
|
| 107 |
"""Saves template content to the persistent file."""
|
| 108 |
global current_template_content
|
| 109 |
-
if not TEMPLATE_FILE_PATH:
|
| 110 |
logger.error("Template file path is not configured. Cannot save template.")
|
| 111 |
return False
|
| 112 |
-
|
| 113 |
try:
|
| 114 |
-
#
|
| 115 |
-
|
| 116 |
-
TEMPLATE_FILE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
| 117 |
-
|
| 118 |
with open(TEMPLATE_FILE_PATH, "w", encoding="utf-8") as f:
|
| 119 |
f.write(content)
|
| 120 |
current_template_content = content
|
|
@@ -129,15 +90,15 @@ if not SESSION_STRING:
|
|
| 129 |
logger.error("SESSION_STRING environment variable not found. Please set it in Hugging Face secrets.")
|
| 130 |
exit(1)
|
| 131 |
|
| 132 |
-
|
| 133 |
-
|
|
|
|
| 134 |
exit(1)
|
| 135 |
|
| 136 |
-
|
| 137 |
logger.info("Initializing Hydrogram Client with session string...")
|
| 138 |
try:
|
| 139 |
app = Client(
|
| 140 |
-
name="
|
| 141 |
session_string=SESSION_STRING,
|
| 142 |
)
|
| 143 |
logger.info("Hydrogram Client initialized.")
|
|
@@ -146,13 +107,14 @@ except Exception as e:
|
|
| 146 |
exit(1)
|
| 147 |
|
| 148 |
|
| 149 |
-
# --- Bot Event Handlers (Unchanged
|
| 150 |
@app.on_message(filters.command("start") & filters.private)
|
| 151 |
async def start_handler(client: Client, message: Message):
|
| 152 |
sender_name = message.from_user.first_name if message.from_user else "User"
|
| 153 |
logger.info(f"Received /start command from {sender_name} (ID: {message.from_user.id})")
|
| 154 |
welcome_text = f"Hello {sender_name}!\n"
|
| 155 |
welcome_text += "I am ready to manage your template.\n"
|
|
|
|
| 156 |
welcome_text += "Use /settemplate <your text> to set a new template.\n"
|
| 157 |
welcome_text += "Use /gettemplate to view the current template."
|
| 158 |
if current_template_content:
|
|
@@ -187,7 +149,7 @@ async def get_template_handler(client: Client, message: Message):
|
|
| 187 |
response_text = "ℹ️ No template is currently set. Use `/settemplate <your text>` to set one."
|
| 188 |
await message.reply_text(response_text)
|
| 189 |
|
| 190 |
-
# --- Main Execution ---
|
| 191 |
async def main():
|
| 192 |
await load_template_from_file()
|
| 193 |
logger.info("Attempting to connect and start the bot...")
|
|
@@ -204,7 +166,7 @@ async def main():
|
|
| 204 |
except Exception as e:
|
| 205 |
logger.error(f"An unexpected error occurred during bot startup or runtime: {type(e).__name__} - {e}", exc_info=True)
|
| 206 |
finally:
|
| 207 |
-
if app.is_initialized and app.is_connected:
|
| 208 |
logger.info("Stopping the bot...")
|
| 209 |
await app.stop()
|
| 210 |
logger.info("Bot stopped.")
|
|
@@ -216,7 +178,7 @@ if __name__ == '__main__':
|
|
| 216 |
asyncio.run(main())
|
| 217 |
except KeyboardInterrupt:
|
| 218 |
logger.info("Bot manually interrupted. Exiting...")
|
| 219 |
-
except SystemExit as e:
|
| 220 |
logger.info(f"Application exiting with status: {e.code}")
|
| 221 |
except Exception as e:
|
| 222 |
logger.critical(f"Critical error in main execution block: {type(e).__name__} - {e}", exc_info=True)
|
|
|
|
| 14 |
# Retrieve Session String from Hugging Face secrets
|
| 15 |
SESSION_STRING = os.environ.get('SESSION_STRING')
|
| 16 |
|
| 17 |
+
# --- Storage Path Initialization (Aligned with Dockerfile) ---
|
| 18 |
+
# This name MUST match the directory created in the Dockerfile
|
| 19 |
+
# (either the default in ARG or how you set it in `RUN mkdir -p ./${APP_TEMPLATE_DIR_NAME}`)
|
| 20 |
+
APP_TEMPLATE_SUBDIR_NAME = "app_template_storage"
|
|
|
|
|
|
|
|
|
|
| 21 |
TEMPLATE_FILENAME = "user_template_content.txt"
|
| 22 |
|
| 23 |
+
# The data directory is now relative to the WORKDIR (e.g., /app/app_template_storage)
|
| 24 |
+
# This path is prepared by the Dockerfile.
|
| 25 |
+
DATA_DIR = Path(".") / APP_TEMPLATE_SUBDIR_NAME
|
| 26 |
+
TEMPLATE_FILE_PATH = DATA_DIR / TEMPLATE_FILENAME
|
| 27 |
|
| 28 |
+
current_template_content = None # Global variable for template
|
|
|
|
|
|
|
| 29 |
|
| 30 |
+
def verify_storage_path_is_writable():
|
| 31 |
+
"""Verifies that the pre-configured DATA_DIR is writable."""
|
| 32 |
+
try:
|
| 33 |
+
# The Dockerfile should have created DATA_DIR.
|
| 34 |
+
# Python's mkdir with exist_ok=True is safe even if it exists.
|
| 35 |
+
# More importantly, we test if we can write into it.
|
| 36 |
+
DATA_DIR.mkdir(parents=True, exist_ok=True)
|
| 37 |
+
|
| 38 |
+
test_file = DATA_DIR / ".writable_test_py"
|
| 39 |
+
with open(test_file, "w") as f:
|
| 40 |
+
f.write("test")
|
| 41 |
+
test_file.unlink() # Clean up test file
|
| 42 |
+
logger.info(f"Successfully verified writable data directory: {DATA_DIR.resolve()}")
|
| 43 |
+
return True
|
| 44 |
+
except Exception as e:
|
| 45 |
+
logger.error(f"CRITICAL: Data directory {DATA_DIR.resolve()} (expected to be created and permissioned by Dockerfile) is not writable or accessible.")
|
| 46 |
+
logger.error(f"Error details: {type(e).__name__} - {e}")
|
| 47 |
+
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
# --- Helper Functions for Template Management ---
|
| 50 |
async def load_template_from_file():
|
| 51 |
"""Loads template content from the persistent file."""
|
| 52 |
global current_template_content
|
| 53 |
+
if not TEMPLATE_FILE_PATH: # Should not happen if verify_storage_path_is_writable passes
|
| 54 |
logger.error("Template file path is not configured. Cannot load template.")
|
| 55 |
current_template_content = None
|
| 56 |
return
|
|
|
|
| 70 |
async def save_template_to_file(content: str):
|
| 71 |
"""Saves template content to the persistent file."""
|
| 72 |
global current_template_content
|
| 73 |
+
if not TEMPLATE_FILE_PATH: # Should not happen
|
| 74 |
logger.error("Template file path is not configured. Cannot save template.")
|
| 75 |
return False
|
|
|
|
| 76 |
try:
|
| 77 |
+
# DATA_DIR.mkdir(parents=True, exist_ok=True) # Dockerfile should handle this.
|
| 78 |
+
# verify_storage_path_is_writable also calls it.
|
|
|
|
|
|
|
| 79 |
with open(TEMPLATE_FILE_PATH, "w", encoding="utf-8") as f:
|
| 80 |
f.write(content)
|
| 81 |
current_template_content = content
|
|
|
|
| 90 |
logger.error("SESSION_STRING environment variable not found. Please set it in Hugging Face secrets.")
|
| 91 |
exit(1)
|
| 92 |
|
| 93 |
+
# Verify the storage path *before* initializing the client or doing anything else
|
| 94 |
+
if not verify_storage_path_is_writable():
|
| 95 |
+
logger.critical("Exiting due to storage path issues. Check Dockerfile and permissions.")
|
| 96 |
exit(1)
|
| 97 |
|
|
|
|
| 98 |
logger.info("Initializing Hydrogram Client with session string...")
|
| 99 |
try:
|
| 100 |
app = Client(
|
| 101 |
+
name="user_session_hgs_v3", # Slightly new name again
|
| 102 |
session_string=SESSION_STRING,
|
| 103 |
)
|
| 104 |
logger.info("Hydrogram Client initialized.")
|
|
|
|
| 107 |
exit(1)
|
| 108 |
|
| 109 |
|
| 110 |
+
# --- Bot Event Handlers (Unchanged) ---
|
| 111 |
@app.on_message(filters.command("start") & filters.private)
|
| 112 |
async def start_handler(client: Client, message: Message):
|
| 113 |
sender_name = message.from_user.first_name if message.from_user else "User"
|
| 114 |
logger.info(f"Received /start command from {sender_name} (ID: {message.from_user.id})")
|
| 115 |
welcome_text = f"Hello {sender_name}!\n"
|
| 116 |
welcome_text += "I am ready to manage your template.\n"
|
| 117 |
+
welcome_text += "Template storage is at: " + str(TEMPLATE_FILE_PATH.resolve()) + "\n"
|
| 118 |
welcome_text += "Use /settemplate <your text> to set a new template.\n"
|
| 119 |
welcome_text += "Use /gettemplate to view the current template."
|
| 120 |
if current_template_content:
|
|
|
|
| 149 |
response_text = "ℹ️ No template is currently set. Use `/settemplate <your text>` to set one."
|
| 150 |
await message.reply_text(response_text)
|
| 151 |
|
| 152 |
+
# --- Main Execution (Unchanged) ---
|
| 153 |
async def main():
|
| 154 |
await load_template_from_file()
|
| 155 |
logger.info("Attempting to connect and start the bot...")
|
|
|
|
| 166 |
except Exception as e:
|
| 167 |
logger.error(f"An unexpected error occurred during bot startup or runtime: {type(e).__name__} - {e}", exc_info=True)
|
| 168 |
finally:
|
| 169 |
+
if app.is_initialized and app.is_connected:
|
| 170 |
logger.info("Stopping the bot...")
|
| 171 |
await app.stop()
|
| 172 |
logger.info("Bot stopped.")
|
|
|
|
| 178 |
asyncio.run(main())
|
| 179 |
except KeyboardInterrupt:
|
| 180 |
logger.info("Bot manually interrupted. Exiting...")
|
| 181 |
+
except SystemExit as e:
|
| 182 |
logger.info(f"Application exiting with status: {e.code}")
|
| 183 |
except Exception as e:
|
| 184 |
logger.critical(f"Critical error in main execution block: {type(e).__name__} - {e}", exc_info=True)
|