import os import logging import time from datetime import datetime from flask import Flask, request, jsonify #from win10toast import ToastNotifier #import asyncio import subprocess import signal import psutil import telegram from telegram import Update from telegram.ext import Updater, CommandHandler, CallbackContext, MessageHandler, filters import telegram.error logging.basicConfig(filename='osiris_listener.log', level=logging.DEBUG, format='%(asctime)s %(message)s') app = Flask(__name__) #toaster = ToastNotifier() #### # Constants #### # Define the scripts and their parameters java_minecraft_servers = [ { 'server_name': 'Vanilla 1.21', 'directory': 'C:/Users/4lexK/Desktop/GameServers/Minecraft/Vanilla_1-21/', 'command': ['C:/Program Files/Java/jdk-22/bin/java.exe', '-Xmx1024M', '-Xms1024M', '-jar', 'minecraft_server.1.21.jar', '--nogui', '--bonusChest'], 'wait_time': 30 }, { 'server_name': 'The 1.12.2 Pack (SanderPack)', 'directory': 'C:/Users/4lexK/Desktop/GameServers/Minecraft/1-12-2-Pack/', 'command': ['C:/Program Files/OpenLogic/jdk-8.0.412.08-hotspot/bin/java.exe', '-Xmx16G', '-XX:+UseG1GC','-Xms4G', '-Dsun.rmi.dgc.server.gcInterval=2147483646', '-XX:+UnlockExperimentalVMOptions', '-XX:G1NewSizePercent=20', '-XX:G1ReservePercent=20', '-XX:MaxGCPauseMillis=50', '-XX:G1HeapRegionSize=32M', '-Dfml.queryResult=confirm', '-Duser.language=en', '-jar', 'forge-1.12.2-14.23.5.2860.jar', '--nogui', '--bonusChest'], 'wait_time': 30 }, { 'server_name': 'GT New Horizons 2.6.0 (SanderHorizons)', 'directory': 'C:/Users/4lexK/Desktop/GameServers/Minecraft/gt_new_horizons_2.6.0/', 'command': ['C:/Program Files/OpenLogic/jdk-8.0.412.08-hotspot/bin/java.exe', '-Xmx12G', '-Xms4G', '-XX:+UseStringDeduplication', '-XX:+UseCompressedOops', '-XX:+UseCodeCacheFlushing', '-Dfml.readTimeout=180', '-jar', 'forge-1.7.10-10.13.4.1614-1.7.10-universal.jar', '--nogui', '--bonusChest'], 'wait_time': 30 }, { 'server_name': 'RLCraft 2.9.3 (SanderHardcore)', 'directory': 'C:/Users/4lexK/Desktop/GameServers/Minecraft/rlcraft/', 'command': ['C:/Program Files/OpenLogic/jdk-8.0.412.08-hotspot/bin/java.exe', '-Xmx16G', '-Xms4G', '-jar', 'forge-1.12.2-14.23.5.2860.jar', '--nogui', '--bonusChest'], 'wait_time': 30 } ] #### # Telegramm Functions #### # Telegram bot token TELEGRAM_BOT_TOKEN = '6984289827:AAHNUM4F_U6233oa75nX5jXyQY6vC0NlZvw' # Create an Bot with a larger connection pool and longer pool timeout bot = telegram.Bot(token=TELEGRAM_BOT_TOKEN) # File to store subscriber chat IDs SUBSCRIBERS_FILE = 'telegramm_subscribers.txt' def load_subscribers(): """Load subscriber chat IDs from the file.""" if os.path.exists(SUBSCRIBERS_FILE): with open(SUBSCRIBERS_FILE, 'r') as file: return [line.strip() for line in file.readlines()] return [] async def send_telegram_message(message): """Send a message to all subscribers.""" subscribers = load_subscribers() for chat_id in subscribers: try: prepped_message = f"{message}" await bot.send_message(chat_id=chat_id, text=prepped_message) except telegram.error.TelegramError as e: logging.error(f"Error sending message to {chat_id}: {e}") #### # Tool Functions #### def read_pid_file(pid_file): """Read the PID from the specified PID file.""" try: with open(pid_file, 'r') as file: pid = int(file.read().strip()) return pid except (FileNotFoundError, ValueError): return None def is_java_process(pid): try: p = psutil.Process(pid) return 'java' in p.name().lower() except psutil.NoSuchProcess: return False #### # Flask Functions #### @app.route('/osiris_execute', methods=['POST']) def execute_script(): logging.info("Commando zur Ausführung erhalten.") data = request.get_json() command = data.get('command') if not command: logging.error("No command provided in request.") return jsonify({'error': 'No command provided'}), 400 logging.debug(f"Commando: {command}") # Hier neue Commands zur Prüfung einpflegen clean_command = command.strip() match clean_command: case 'testcommand': try: #toaster.show_toast("TestCommand", "Verbindung wurde getestet", d)uration=10) #asyncio.run(send_telegram_message("Test command executed.")) return jsonify({'message': 'Test Command abgesetzt und Notification auf bei Host erstellt.'}) except Exception as exc: logging.error(f"Error executing test command: {exc}") #asyncio.run(send_telegram_message(f"Error executing test command: {e}")) return jsonify({'message': f'Error: {str(exc)}'}), 500 case 'shutdown': logging.info("Received request to shutdown.") try: #toaster.show_toast("Shutdown", "Shutdown Command erhalten. Host wird heruntergefahren.", duration=10) os.system("shutdown /s /t 1") #asyncio.run(send_telegram_message("Ich schlafe dann weiter. Bis demnächst :-)")) return jsonify({'message': 'Shutdown command wurde ausgeführt. System fährt herunter.'}) except Exception as e: logging.error(f"Error executing shutdown command: {exc}") #asyncio.run(send_telegram_message(f"Error executing shutdown command: {e}")) return jsonify({"message": "Fehler beim veranlassen des Shutdowns", 'error': str(e)}), 500 case 'start_gameservers_minecraft': logging.info("Received request to start minecraft servers.") #toaster.show_toast("start_gameservers_minecraft", "Starte Minecraft-Server", duration=10) response_msg = "Folgende Minecraft-Server wurden bearbeitet:" for server in java_minecraft_servers: os.chdir(server['directory']) pid_file = os.path.join(server['directory'], 'server.pid') log_file = os.path.join(server['directory'], 'logs', f'server_{datetime.now().strftime("%Y%m%d_%H%M%S")}.log') #wait_time = server['wait_time'] # Create logs directory if it doesn't exist os.makedirs(os.path.dirname(log_file), exist_ok=True) if os.path.exists(pid_file): with open(pid_file, 'r') as file: pid = int(file.read().strip()) if psutil.pid_exists(pid) and is_java_process(pid): response_msg += f"\nServer {server['server_name']} läuft bereits." continue else: os.remove(pid_file) #response_msg += f"Server {server['server_name']} wird gestartet." with open(log_file, 'w') as log: process = subprocess.Popen( server['command'], cwd=server['directory'], stdout=log, stderr=log, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == 'nt' else 0 ) #time.sleep(wait_time) with open(pid_file, 'w') as file: file.write(str(process.pid)) response_msg += f"\nServer {server['server_name']} wurde mit PID '{process.pid}' gestartet." return jsonify({"message": f"{response_msg}"}) #return jsonify({'message': 'Minecraft-Server werden gestartet.'}) case 'stop_gameservers_minecraft': logging.info("Received request to stop minecraft servers.") response_msg = "Folgende Minecraft-Server wurden bearbeitet:" for server in java_minecraft_servers: pid_file = os.path.join(server['directory'], 'server.pid') wait_time = server['wait_time'] flag_delete_pid = False if os.path.exists(pid_file): with open(pid_file, 'r') as file: pid = int(file.read().strip()) if psutil.pid_exists(pid) and is_java_process(pid): p = psutil.Process(pid) if os.name == 'nt': p.terminate() # Use terminate for Windows else: p.send_signal(signal.SIGTERM) try: p.wait(timeout=wait_time) if not psutil.pid_exists(pid): flag_delete_pid = True response_msg += f"\nServer {server['server_name']} mit PID {pid} gestoppt." else: response_msg += f"\nFehler beim Stoppen des Servers {server['server_name']} mit PID {pid}." except psutil.TimeoutExpired: response_msg += f"Timeout während stoppen des Server {server['server_name']} mit PID {pid}." else: flag_delete_pid = True response_msg += f"Stale PID file von Server {server['server_name']} entfernt." if flag_delete_pid: os.remove(pid_file) response_msg += f"PID File gelöscht" flag_delete_pid = False else: response_msg += f"Es existiert kein PID File für Server {server['server_name']}" #asyncio.run(send_telegram_message("Minecraft-Server wurden heruntergefahren.")) return jsonify({'message': response_msg}) case 'start_gameservers_dontstarve': try: #toaster.show_toast("start_gameservers_dontstarve", "Starte Dont Starve Together-Server", duration=10) # hier pgm aufrufen return jsonify({'message': 'Dont Starve Together-Server werden gestartet.'}) except Exception as exc: logging.error(f"Error executing start_gameservers_dontstarve command: {exc}") return jsonify({'error': str(exc)}), 500 case 'stop_gameservers_dontstarve': try: #toaster.show_toast("stop_gameservers_dontstarve", "Stoppe Dont Starve Together-Server", duration=10) # hier pgm aufrufen return jsonify({'message': 'Dont Starve Together-Server wurden angehalten.'}) except Exception as exc: logging.error(f"Error executing stop_gameservers_dontstarve command: {exc}") return jsonify({'error': str(exc)}), 500 case 'start_gameservers_ragnarokonline': try: #toaster.show_toast("start_gameservers_ragnarokonline", "Starte RO-Server", duration=10) # hier pgm aufrufen return jsonify({'message': 'RO-Server werden gestartet.'}) except Exception as exc: logging.error(f"Error executing start_gameservers_ragnarokonline command: {exc}") return jsonify({'error': str(exc)}), 500 case 'stop_gameservers_ragnarokonline': try: #toaster.show_toast("stop_gameservers_ragnarokonline", "Stoppe RO-Server", duration=10) # hier pgm aufrufen return jsonify({'message': 'RO-Server wurden angehalten.'}) except Exception as exc: logging.error(f"Error executing stop_gameservers_ragnarokonline command: {exc}") return jsonify({'error': str(exc)}), 500 case 'start_gameservers_wow': try: #toaster.show_toast("start_gameservers_wow", "Starte WoW-Server", duration=10) # hier pgm aufrufen return jsonify({'message': 'WoW-Server werden gestartet.'}) except Exception as exc: logging.error(f"Error executing start_gameservers_wow command: {exc}") return jsonify({'error': str(exc)}), 500 case 'stop_gameservers_wow': try: #toaster.show_toast("stop_gameservers_wow", "Stoppe WoW-Server", duration=10) # hier pgm aufrufen return jsonify({'message': 'WoW-Server wurden angehalten.'}) except Exception as exc: logging.error(f"Error executing stop_gameservers_wow command: {exc}") return jsonify({'error': str(exc)}), 500 case _: try: result = subprocess.run(['python','-c', command], capture_output=True, text=True, shell=True) #send_telegram_message(f"Script executed with output: {result.stdout}") return jsonify({'output': result.stdout, 'error': result.stderr, 'returncode': result.returncode}) except Exception as exc: logging.error(f"Error executing command: {exc}") #send_telegram_message(f"Error executing script: {e}") return jsonify({'error': str(exc)}), 500 @app.route('/status', methods=['GET']) def status(): logging.info("Status Check received.") #asyncio.run(send_telegram_message(f"Bin da. Wer nohoch?")) return jsonify({'message': 'status = online'}) @app.route('/status_servers', methods=['GET']) def status_gameservers(): logging.info("Check Status der Server") response_msg = "Status Game Server:" for server in java_minecraft_servers: pid_file = os.path.join(server['directory'], 'server.pid') if os.path.exists(pid_file): with open(pid_file, 'r') as file: pid = int(file.read().strip()) if psutil.pid_exists(pid) and is_java_process(pid): response_msg += f"\nServer {server['server_name']} läuft mit PID {pid}." else: response_msg += f"\nServer {server['server_name']} läuft nicht." else: response_msg += f"\nKein PID file für Server {server['server_name']} gefunden." #asyncio.run(send_telegram_message(f"Aktuell laufende Server: {server_list}")) return jsonify({"message": response_msg }) if __name__ == '__main__': #toaster.show_toast("Starte Osiris", "Osiris Listener wurde gestartet. Warte auf Befehle...", duration=30) logging.info("Starte Server.") #asyncio.run(send_telegram_message(f"Nuc_Morroc hier. Bin jetzt wach ;-)")) app.run(host='0.0.0.0', port=9713)