diff --git a/osiris_listener.py b/osiris_listener.py index 1ac8419..36c7809 100644 --- a/osiris_listener.py +++ b/osiris_listener.py @@ -1,15 +1,27 @@ from flask import Flask, request, jsonify import subprocess -#from win10toast import ToastNotifier import os import logging import signal +import psutil +#from win10toast import ToastNotifier +import telegram +from telegram.ext import Updater, CommandHandler, MessageHandler, Filters + + logging.basicConfig(filename='osiris_listener.log', level=logging.DEBUG, format='%(asctime)s %(message)s') app = Flask(__name__) #toaster = ToastNotifier() +# Telegram bot token +TELEGRAM_BOT_TOKEN = '5103145116:AAE_sVgkx8atxgizMuE38ClwbRLAyDUMSeM' +bot = telegram.Bot(token=TELEGRAM_BOT_TOKEN) + +# File to store subscriber chat IDs +SUBSCRIBERS_FILE = 'subscribers.txt' + # Global list to store process handles processes = [] processes_info = [] @@ -18,18 +30,61 @@ processes_info = [] SCRIPTS = { "start_gameservers_minecraft": [ # Vanilla (Port 25565) - {"name": "Minecraft Vanilla 1.21", "path": "C:\\Users\\4lexK\\Desktop\\GameServers\\Minecraft\\Vanilla_1-21\\start_server.py", "params": ["--java_path", "'C:\\Program Files\\Java\\jdk-22\\bin'", 'minecraft_server.1.21']}, + {"name": "Minecraft Vanilla 1.21", "path": "C:/Users/4lexK/Desktop/GameServers/Minecraft/Vanilla_1-21/start_server.py", "params": ["--java_path", "C:/Program Files/Java/jdk-22/bin", "minecraft_server.1.21"]}, # The 1.12.2 Pack (SanderPack) (Port 25566) - {"name": "Minecraft The 1.12.2 Pack (SanderPack)", "path": "C:\\Users\\4lexK\\Desktop\\GameServers\\Minecraft\\1-12-2-Pack\\start_server.py", "params": ["--java_path", "'C:\\Program Files\\OpenLogic\\jdk-8.0.412.08-hotspot\\bin'", 'forge-1.12.2-14.23.5.2860']}, + {"name": "Minecraft The 1.12.2 Pack (SanderPack)", "path": "C:/Users/4lexK/Desktop/GameServers/Minecraft/1-12-2-Pack/start_server.py", "params": ["--java_path", "C:/Program Files/OpenLogic/jdk-8.0.412.08-hotspot/bin", 'forge-1.12.2-14.23.5.2860']}, # GT New Horizon (SanderHorizon) (Port 25567) - {"name": "Minecraft GT New Horizon 2.6.0 (SanderHorizon)", "path": "C:\\Users\\4lexK\\Desktop\\GameServers\\Minecraft\\gt_new_horizons_2.6.0\\start_server.py", "params": ["--java_path", "'C:\\Program Files\\OpenLogic\\jdk-8.0.412.08-hotspot\\bin'", 'forge-1.7.10-10.13.4.1614-1.7.10-universal']}, + {"name": "Minecraft GT New Horizon 2.6.0 (SanderHorizon)", "path": "C:/Users/4lexK/Desktop/GameServers/Minecraft/gt_new_horizons_2.6.0/start_server.py", "params": ["--java_path", "C:/Program Files/OpenLogic/jdk-8.0.412.08-hotspot/bin'", 'forge-1.7.10-10.13.4.1614-1.7.10-universal']}, # rlcraft (SanderHardcore) (Port 25568) - {"name": "Minecraft rlcraft 2.9.3 (SanderHardcore)", "path": "C:\\Users\\4lexK\\Desktop\\GameServers\\Minecraft\\rlcraft\\start_server.py", "params": ["--java_path", "'C:\\Program Files\\OpenLogic\\jdk-8.0.412.08-hotspot\\\bin'", 'forge-1.12.2-14.23.5.2860']}, + {"name": "Minecraft rlcraft 2.9.3 (SanderHardcore)", "path": "C:/Users/4lexK/Desktop/GameServers/Minecraft/rlcraft/start_server.py", "params": ["--java_path", "C:/Program Files/OpenLogic/jdk-8.0.412.08-hotspot/bin'", 'forge-1.12.2-14.23.5.2860']}, # Add more scripts and their parameters as needed ] } +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_running(pid): + """Check if a Java process with the given PID is running.""" + try: + proc = psutil.Process(pid) + if 'java' in proc.name().lower(): + return True + except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): + return False + return False + +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 [] + +def save_subscriber(chat_id): + """Save a new subscriber chat ID to the file.""" + with open(SUBSCRIBERS_FILE, 'a') as file: + file.write(f"{chat_id}\n") + +def send_telegram_message(message): + """Send a message to all subscribers.""" + subscribers = load_subscribers() + for chat_id in subscribers: + try: + prepped_message = f"[nuc_morroc]{message}" + bot.send_message(chat_id=chat_id, text=message) + except telegram.error.TelegramError as e: + logging.error(f"Error sending message to {chat_id}: {e}") + + + @app.route('/osiris_execute', methods=['POST']) def execute_script(): logging.info("Commando zur Ausführung erhalten.") @@ -38,129 +93,160 @@ def execute_script(): data = request.get_json() command = data.get('command') - if command: - logging.info(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", duration=10) - return jsonify({'message': 'Test Command abgesetzt und Notification auf bei Host erstellt.'}) - except Exception as exc: - logging.error(f"Error executing test command: {exc}") - 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") - return jsonify({'message': 'Shutdown command wurde ausgeführt. System fährt herunter.'}) - except Exception as e: - logging.error(f"Error executing shutdown command: {exc}") - return jsonify({'error': str(e)}), 500 + 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", duration=10) + 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}") + 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") + 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}") + 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) + results = [] + for script_info in SCRIPTS['start_gameservers_minecraft']: + path = script_info["path"] + params = script_info["params"] + script_name = script_info["name"] + command = ['python', path] + params + pid_file = os.path.join(os.path.dirname(path), 'server.pid') + + pid = read_pid_file(pid_file) + if is_java_process_running(command): + logging.info(f"Script {script_name} is already running.") + results.append({ + "script": path, + "params": params, + "status": "already running" + }) + continue - case 'start_gameservers_minecraft': - logging.info("Received request to start minecraft servers.") - #toaster.show_toast("start_gameservers_minecraft", "Starte Minecraft-Server", duration=10) - results = [] - for script_info in SCRIPTS['start_gameservers_minecraft']: - path = script_info["path"] - params = script_info["params"] - script_name = script_info["name"] - try: - process = subprocess.Popen(['python', path] + params, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - processes.append(process) - processes_info.append({"process": process, "name": script_name}) - results.append({ - "script": path, - "params": params, - "pid": process.pid - #"returncode": result.returncode - }) - except Exception as e: - logging.error(f"Error executing script {path}: {e}") - results.append({ - "script": path, - "params": params, - "error": str(e) - }) - return jsonify(results) - #return jsonify({'message': 'Minecraft-Server werden gestartet.'}) - - case 'stop_gameservers_minecraft': - logging.info("Received request to stop minecraft servers.") - for process in processes: - try: - #toaster.show_toast("stop_gameservers_minecraft", "Stoppe Minecraft-Server", duration=10) - process.send_signal(signal.SIGINT) - logging.info(f"Sent SIGINT to process with PID: {process.pid}") - except Exception as exc: - logging.error(f"Error sending DIGINT to process with PID {process.pid}") - processes = [] # clear process list - processes_info = [] - return jsonify({'message': "Sent SIGINT to all running minecraft server scripts"}) - 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: + logging.info(f"Starting script: {command}") + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + psutil_process = psutil.Process(process.pid) + processes.append(psutil_process) + processes_info.append({"process": psutil_process, "name": script_name}) + logging.info(f"Started {script_name} with PID: {psutil_process.pid}") + results.append({ + "script": path, + "params": params, + "pid": psutil_process.pid + }) + except Exception as e: + logging.error(f"Error starting script {path}: {e}") + results.append({ + "script": path, + "params": params, + "error": str(e) + }) + send_telegram_message("Minecraft-Server wurden gestartet.") + return jsonify({"message": "Start der Server wurde veranlasst", "results": results}) + #return jsonify({'message': 'Minecraft-Server werden gestartet.'}) + + case 'stop_gameservers_minecraft': + logging.info("Received request to stop minecraft servers.") + for process in processes: try: - result = subprocess.run(['python','-c', command], capture_output=True, text=True, shell=True) - return jsonify({'output': result.stdout, 'error': result.stderr, 'returncode': result.returncode}) + #toaster.show_toast("stop_gameservers_minecraft", "Stoppe Minecraft-Server", duration=10) + #process.send_signal(signal.SIGINT) + process.terminate() + logging.info(f"Sent SIGINT to process with PID: {process.pid}") + process.wait() + logging.info(f"Process with PID {process.pid} terminated.") + except Exception as exc: - logging.error(f"Error executing command: {exc}") - return jsonify({'error': str(exc)}), 500 + logging.error(f"Error sending SIGINT to process with PID {process.pid}") + processes = [] # clear process list + processes_info = [] + send_telegram_message("Minecraft-Server wurden heruntergefahren.") + return jsonify({'message': "SIGINT (CTRL-C an alle laufenden Minecraft server gesendet."}) + 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.") + send_telegram_message(f"Bin da. Wer nohoch?") return jsonify({'status': 'online'}) @@ -172,10 +258,23 @@ def status_gameservers(): for process in processes_info: running_servers.append(process['name']) server_list = "\n - ".join(running_servers) + send_telegram_message(f"Aktuell laufende Server: {server_list}") + return jsonify({"message": f"Aktuell laufende Server: {server_list}" }) +# Endpoint to add subscribers | Note: aktuell nur händisch mittels Übertrag der ID aus IOBroker heraus +@app.route('/subscribe', methods=['POST']) +def subscribe(): + data = request.get_json() + chat_id = data.get('chat_id') + if chat_id: + save_subscriber(chat_id) + return jsonify({'message': 'Subscribed successfully.'}) + return jsonify({'error': 'No chat_id provided'}), 400 + if __name__ == '__main__': #toaster.show_toast("Starte Osiris", "Osiris Listener wurde gestartet. Warte auf Befehle...", duration=30) logging.info("Starte Server.") + send_telegram_message(f"Nuc_Morroc hier. Bin jetzt wach ;-)") app.run(host='0.0.0.0', port=9713) \ No newline at end of file