#!/usr/bin/env python3 """ Update Server for Bots Serves version information to bots checking for updates. """ from flask import Flask, jsonify, request, render_template_string from flask_cors import CORS import json import os from datetime import datetime import threading # Load version data from JSON file VERSIONS_FILE = 'versions.json' LOG_FILE = 'update_checks.log' # Create API app api_app = Flask(__name__, static_folder=None) CORS(api_app) # Enable CORS for cross-origin requests from admin GUI # Create Admin app admin_app = Flask(__name__) def load_versions(): """Load version info from file.""" if os.path.exists(VERSIONS_FILE): try: with open(VERSIONS_FILE, 'r') as f: return json.load(f) except Exception as e: print(f"Error loading versions.json: {e}") return {} return {} def save_versions(versions): """Save version info to file.""" try: with open(VERSIONS_FILE, 'w') as f: json.dump(versions, f, indent=2) return True except Exception as e: print(f"Error saving versions.json: {e}") return False def log_check(bot_name): """Log update check requests.""" try: with open(LOG_FILE, 'a') as f: f.write(f"{datetime.now().isoformat()} - {bot_name}\n") except Exception as e: print(f"Error logging check: {e}") # ====== API ROUTES (Port 5555) ====== @api_app.route('/api/version/', methods=['GET']) def get_version(bot_name): """Get latest version for a specific bot.""" log_check(bot_name) versions = load_versions() if bot_name in versions: return jsonify(versions[bot_name]) return jsonify({"error": "Bot not found"}), 404 @api_app.route('/api/versions', methods=['GET']) def get_all_versions(): """Get all bot versions.""" return jsonify(load_versions()) @api_app.route('/health', methods=['GET']) def health(): """Health check endpoint.""" return jsonify({"status": "ok"}) @api_app.route('/', methods=['GET']) def index(): """Index page with server info.""" versions = load_versions() bot_count = len(versions) return jsonify({ "service": "Update Server", "status": "running", "bots_tracked": bot_count, "endpoints": { "/health": "Health check", "/api/versions": "Get all bot versions", "/api/version/": "Get specific bot version" } }) @api_app.errorhandler(404) def api_not_found(error): """Handle 404 errors.""" return jsonify({"error": "Endpoint not found"}), 404 @api_app.errorhandler(500) def api_internal_error(error): """Handle 500 errors.""" return jsonify({"error": "Internal server error"}), 500 # ====== ADMIN ROUTES (Port 5566) ====== ADMIN_HTML = """ Update Server Admin

🤖 Update Server Admin

Manage bot versions easily

Add/Edit Version

Current Versions

  • Loading...
""" @admin_app.route('/', methods=['GET']) def admin_index(): """Admin dashboard.""" return render_template_string(ADMIN_HTML) @admin_app.route('/admin/api/add', methods=['POST']) def admin_add_version(): """Add or update a bot version.""" try: data = request.get_json() bot_name = data.get('bot_name', '').strip() version = data.get('version', '').strip() changelog_url = data.get('changelog_url', '').strip() if not bot_name or not version: return jsonify({"success": False, "message": "Bot name and version are required"}), 400 versions = load_versions() versions[bot_name] = { "version": version, "changelog_url": changelog_url if changelog_url else versions.get(bot_name, {}).get('changelog_url', '') } if save_versions(versions): return jsonify({"success": True, "message": f"Version saved for {bot_name}"}) else: return jsonify({"success": False, "message": "Failed to save version"}), 500 except Exception as e: return jsonify({"success": False, "message": f"Error: {str(e)}"}), 500 @admin_app.route('/admin/api/delete', methods=['POST']) def admin_delete_version(): """Delete a bot version.""" try: data = request.get_json() bot_name = data.get('bot_name', '').strip() if not bot_name: return jsonify({"success": False, "message": "Bot name is required"}), 400 versions = load_versions() if bot_name in versions: del versions[bot_name] if save_versions(versions): return jsonify({"success": True, "message": f"{bot_name} deleted"}) return jsonify({"success": False, "message": "Bot not found"}), 404 except Exception as e: return jsonify({"success": False, "message": f"Error: {str(e)}"}), 500 @admin_app.errorhandler(404) def admin_not_found(error): """Handle 404 errors.""" return jsonify({"error": "Endpoint not found"}), 404 @admin_app.errorhandler(500) def admin_internal_error(error): """Handle 500 errors.""" return jsonify({"error": "Internal server error"}), 500 # ====== RUN BOTH APPS ====== def run_api(): """Run API on port 5555.""" print("[API] Starting on port 5555...") api_app.run(host='0.0.0.0', port=5555, debug=False) def run_admin(): """Run Admin on port 5566.""" print("[ADMIN] Starting on port 5566...") admin_app.run(host='0.0.0.0', port=5566, debug=False) if __name__ == '__main__': versions_count = len(load_versions()) print(f"[STARTUP] Loaded {versions_count} bots from versions.json") # Run both apps in separate threads api_thread = threading.Thread(target=run_api, daemon=True) admin_thread = threading.Thread(target=run_admin, daemon=True) api_thread.start() admin_thread.start() # Keep main thread alive try: api_thread.join() except KeyboardInterrupt: print("\n[SHUTDOWN] Stopping servers...")