diff --git a/core/scripts/telegrambot/runbot.py b/core/scripts/telegrambot/runbot.py index 2279018..0da841e 100644 --- a/core/scripts/telegrambot/runbot.py +++ b/core/scripts/telegrambot/runbot.py @@ -3,6 +3,7 @@ import sys import subprocess from pathlib import Path +import os core_scripts_dir = Path(__file__).resolve().parents[1] if str(core_scripts_dir) not in sys.path: @@ -10,12 +11,10 @@ if str(core_scripts_dir) not in sys.path: from paths import TELEGRAM_ENV - - - -def update_env_file(api_token, admin_user_ids): +def update_env_file(api_token, admin_user_ids, backup_interval): TELEGRAM_ENV.write_text(f"""API_TOKEN={api_token} ADMIN_USER_IDS=[{admin_user_ids}] +BACKUP_INTERVAL_HOUR={backup_interval} """) def create_service_file(): @@ -32,12 +31,12 @@ Restart=always WantedBy=multi-user.target """) -def start_service(api_token, admin_user_ids): +def start_service(api_token, admin_user_ids, backup_interval=12): if subprocess.run(["systemctl", "is-active", "--quiet", "hysteria-telegram-bot.service"]).returncode == 0: print("The hysteria-telegram-bot.service is already running.") return - update_env_file(api_token, admin_user_ids) + update_env_file(api_token, admin_user_ids, backup_interval) create_service_file() subprocess.run(["systemctl", "daemon-reload"]) @@ -55,20 +54,60 @@ def stop_service(): TELEGRAM_ENV.unlink(missing_ok=True) print("\nHysteria bot service stopped and disabled. .env file removed.") +def set_backup_interval(backup_interval): + if not os.path.exists(TELEGRAM_ENV): + print("Error: The .env file does not exist. Please start the bot first.") + sys.exit(1) + + with open(TELEGRAM_ENV, 'r') as f: + lines = f.readlines() + + with open(TELEGRAM_ENV, 'w') as f: + found = False + for line in lines: + if line.strip().startswith("BACKUP_INTERVAL_HOUR"): + f.write(f"BACKUP_INTERVAL_HOUR={backup_interval}\n") + found = True + else: + f.write(line) + if not found: + f.write(f"BACKUP_INTERVAL_HOUR={backup_interval}\n") + + print(f"Backup interval has been set to {backup_interval} hour(s). Restarting the bot to apply changes...") + subprocess.run(["systemctl", "restart", "hysteria-telegram-bot.service"]) + +def print_usage(): + print("Usage:") + print(" python3 runbot.py start [BACKUP_INTERVAL_HOUR]") + print(" python3 runbot.py stop") + print(" python3 runbot.py set_backup_interval ") + print("\nDefault BACKUP_INTERVAL_HOUR is 12.") + sys.exit(1) + if __name__ == "__main__": if len(sys.argv) < 2: - print("Usage: python3 runbot.py {start|stop} ") - sys.exit(1) + print_usage() action = sys.argv[1] if action == "start": - if len(sys.argv) != 4: - print("Usage: python3 runbot.py start ") - sys.exit(1) - start_service(sys.argv[2], sys.argv[3]) + if not (4 <= len(sys.argv) <= 5): + print_usage() + + api_token = sys.argv[2] + admin_user_ids = sys.argv[3] + + if len(sys.argv) == 5: + backup_interval = sys.argv[4] + start_service(api_token, admin_user_ids, backup_interval) + else: + start_service(api_token, admin_user_ids) + elif action == "stop": stop_service() + elif action == "set_backup_interval": + if len(sys.argv) != 3: + print_usage() + set_backup_interval(sys.argv[2]) else: - print("Usage: python3 runbot.py {start|stop} ") - sys.exit(1) + print_usage() \ No newline at end of file diff --git a/core/scripts/telegrambot/utils/backup.py b/core/scripts/telegrambot/utils/backup.py index 6899d0f..6debecb 100644 --- a/core/scripts/telegrambot/utils/backup.py +++ b/core/scripts/telegrambot/utils/backup.py @@ -6,10 +6,13 @@ import json import os import shlex import re +import time +import threading from dotenv import load_dotenv from telebot import types from utils.command import * +load_dotenv() @bot.message_handler(func=lambda message: is_admin(message.from_user.id) and message.text == '💾 Backup Server') def backup_server(message): @@ -21,10 +24,10 @@ def backup_server(message): if "Error" in result: bot.reply_to(message, f"Backup failed: {result}") - else: - bot.reply_to(message, "Backup completed successfully!") + return + + # bot.reply_to(message, "Backup completed successfully!") - try: files = [f for f in os.listdir(BACKUP_DIRECTORY) if f.endswith('.zip')] files.sort(key=lambda x: os.path.getctime(os.path.join(BACKUP_DIRECTORY, x)), reverse=True) @@ -36,6 +39,61 @@ def backup_server(message): if latest_backup_file: backup_file_path = os.path.join(BACKUP_DIRECTORY, latest_backup_file) with open(backup_file_path, 'rb') as f: - bot.send_document(message.chat.id, f, caption=f"Backup completed: {latest_backup_file}") + bot.send_document(message.chat.id, f, caption=f"Manual backup completed: {latest_backup_file}") else: - bot.reply_to(message, "No backup file found after the backup process.") \ No newline at end of file + bot.reply_to(message, "No backup file found after the backup process.") + +def perform_and_send_backup(): + # print("Starting automatic backup...") + + backup_command = f"python3 {CLI_PATH} backup-hysteria" + result = run_cli_command(backup_command) + + if "Error" in result: + print(f"Automatic backup failed: {result}") + return + + try: + files = [f for f in os.listdir(BACKUP_DIRECTORY) if f.endswith('.zip')] + files.sort(key=lambda x: os.path.getctime(os.path.join(BACKUP_DIRECTORY, x)), reverse=True) + latest_backup_file = files[0] if files else None + except Exception as e: + print(f"Failed to locate the backup file during automatic backup: {str(e)}") + return + + if latest_backup_file: + backup_file_path = os.path.join(BACKUP_DIRECTORY, latest_backup_file) + admin_ids_str = os.getenv("ADMIN_USER_IDS", "[]").strip('[]') + admin_ids = [int(uid.strip()) for uid in admin_ids_str.split(',') if uid.strip()] + + if not admin_ids: + print("No admin user IDs found for automatic backup.") + return + + for admin_id in admin_ids: + try: + with open(backup_file_path, 'rb') as f: + bot.send_document(admin_id, f, caption=f"Automatic hourly backup: {latest_backup_file}") + print(f"Automatic backup sent to admin: {admin_id}") + except Exception as e: + print(f"Failed to send automatic backup to admin {admin_id}: {e}") + else: + print("No backup file found after automatic backup process.") + + +def backup_scheduler(): + interval_hours_str = os.getenv("BACKUP_INTERVAL_HOUR") + if not interval_hours_str or not interval_hours_str.isdigit() or int(interval_hours_str) <= 0: + print("Automatic backup interval is not set or is invalid. Scheduler will not run.") + return + + interval_hours = int(interval_hours_str) + interval_seconds = interval_hours * 3600 + print(f"Automatic backup scheduler started. Interval: {interval_hours} hour(s).") + + while True: + time.sleep(interval_seconds) + perform_and_send_backup() + +scheduler_thread = threading.Thread(target=backup_scheduler, daemon=True) +scheduler_thread.start() \ No newline at end of file