From 954037b826cb5f75f9968c326eb90af7f209cec6 Mon Sep 17 00:00:00 2001 From: Chubby Granny Chaser Date: Sat, 18 Jan 2025 01:58:42 +0000 Subject: [PATCH] fix: using python http server --- python_rpc/main.py | 271 +++++++++++++++++++++++---------------------- requirements.txt | 1 - 2 files changed, 139 insertions(+), 133 deletions(-) diff --git a/python_rpc/main.py b/python_rpc/main.py index 03df83de..036c44d4 100644 --- a/python_rpc/main.py +++ b/python_rpc/main.py @@ -1,29 +1,29 @@ -from flask import Flask, request, jsonify -import sys, json, urllib.parse, psutil +from http.server import BaseHTTPRequestHandler, HTTPServer +import json +import urllib.parse +import sys +import psutil from torrent_downloader import TorrentDownloader from http_downloader import HttpDownloader from profile_image_processor import ProfileImageProcessor import libtorrent as lt -app = Flask(__name__) - # Retrieve command line arguments torrent_port = sys.argv[1] -http_port = sys.argv[2] +http_port = int(sys.argv[2]) rpc_password = sys.argv[3] start_download_payload = sys.argv[4] start_seeding_payload = sys.argv[5] downloads = {} -# This can be streamed down from Node downloading_game_id = -1 -torrent_session = lt.session({'listen_interfaces': '0.0.0.0:{port}'.format(port=torrent_port)}) +torrent_session = lt.session({'listen_interfaces': f'0.0.0.0:{torrent_port}'}) if start_download_payload: initial_download = json.loads(urllib.parse.unquote(start_download_payload)) downloading_game_id = initial_download['game_id'] - + if initial_download['url'].startswith('magnet'): torrent_downloader = TorrentDownloader(torrent_session) downloads[initial_download['game_id']] = torrent_downloader @@ -49,135 +49,142 @@ if start_seeding_payload: except Exception as e: print("Error starting seeding", e) -def validate_rpc_password(): - """Middleware to validate RPC password.""" - header_password = request.headers.get('x-hydra-rpc-password') - if header_password != rpc_password: - return jsonify({"error": "Unauthorized"}), 401 +class RequestHandler(BaseHTTPRequestHandler): + def validate_rpc_password(self): + header_password = self.headers.get('x-hydra-rpc-password') + if header_password != rpc_password: + self.send_response(401) + self.end_headers() + self.wfile.write(json.dumps({"error": "Unauthorized"}).encode('utf-8')) + return False + return True -@app.route("/status", methods=["GET"]) -def status(): - auth_error = validate_rpc_password() - if auth_error: - return auth_error + def do_GET(self): + if self.path == "/status": + if not self.validate_rpc_password(): + return - downloader = downloads.get(downloading_game_id) - if downloader: - status = downloads.get(downloading_game_id).get_download_status() - return jsonify(status), 200 - else: - return jsonify(None) - -@app.route("/seed-status", methods=["GET"]) -def seed_status(): - auth_error = validate_rpc_password() - if auth_error: - return auth_error - - seed_status = [] - - for game_id, downloader in downloads.items(): - if not downloader: - continue - - response = downloader.get_download_status() - if response is None: - continue - - if response.get('status') == 5: - seed_status.append({ - 'gameId': game_id, - **response, - }) - - return jsonify(seed_status), 200 - -@app.route("/healthcheck", methods=["GET"]) -def healthcheck(): - return "", 200 - -@app.route("/process-list", methods=["GET"]) -def process_list(): - auth_error = validate_rpc_password() - if auth_error: - return auth_error - - process_list = [proc.info for proc in psutil.process_iter(['exe', 'pid', 'name'])] - return jsonify(process_list), 200 - -@app.route("/profile-image", methods=["POST"]) -def profile_image(): - auth_error = validate_rpc_password() - if auth_error: - return auth_error - - data = request.get_json() - image_path = data.get('image_path') - - try: - processed_image_path, mime_type = ProfileImageProcessor.process_image(image_path) - return jsonify({'imagePath': processed_image_path, 'mimeType': mime_type}), 200 - except Exception as e: - return jsonify({"error": str(e)}), 400 - -@app.route("/action", methods=["POST"]) -def action(): - global torrent_session - global downloading_game_id - - auth_error = validate_rpc_password() - if auth_error: - return auth_error - - data = request.get_json() - action = data.get('action') - game_id = data.get('game_id') - - if action == 'start': - url = data.get('url') - - existing_downloader = downloads.get(game_id) - - if url.startswith('magnet'): - if existing_downloader and isinstance(existing_downloader, TorrentDownloader): - existing_downloader.start_download(url, data['save_path'], "") + downloader = downloads.get(downloading_game_id) + if downloader: + status = downloader.get_download_status() + self.send_response(200) + self.end_headers() + self.wfile.write(json.dumps(status).encode('utf-8')) else: - torrent_downloader = TorrentDownloader(torrent_session) + self.send_response(200) + self.end_headers() + self.wfile.write(json.dumps(None).encode('utf-8')) + + elif self.path == "/seed-status": + if not self.validate_rpc_password(): + return + + seed_status = [] + for game_id, downloader in downloads.items(): + if not downloader: + continue + + response = downloader.get_download_status() + if response is None: + continue + + if response.get('status') == 5: + seed_status.append({ + 'gameId': game_id, + **response, + }) + + self.send_response(200) + self.end_headers() + self.wfile.write(json.dumps(seed_status).encode('utf-8')) + + elif self.path == "/healthcheck": + self.send_response(200) + self.end_headers() + + elif self.path == "/process-list": + if not self.validate_rpc_password(): + return + + process_list = [proc.info for proc in psutil.process_iter(['exe', 'pid', 'name'])] + self.send_response(200) + self.end_headers() + self.wfile.write(json.dumps(process_list).encode('utf-8')) + + def do_POST(self): + if not self.validate_rpc_password(): + return + + content_length = int(self.headers['Content-Length']) + post_data = self.rfile.read(content_length) + data = json.loads(post_data.decode('utf-8')) + + if self.path == "/profile-image": + image_path = data.get('image_path') + try: + processed_image_path, mime_type = ProfileImageProcessor.process_image(image_path) + self.send_response(200) + self.end_headers() + self.wfile.write(json.dumps({'imagePath': processed_image_path, 'mimeType': mime_type}).encode('utf-8')) + except Exception as e: + self.send_response(400) + self.end_headers() + self.wfile.write(json.dumps({"error": str(e)}).encode('utf-8')) + + elif self.path == "/action": + global downloading_game_id + action = data.get('action') + game_id = data.get('game_id') + + if action == 'start': + url = data.get('url') + + existing_downloader = downloads.get(game_id) + + if url.startswith('magnet'): + if existing_downloader and isinstance(existing_downloader, TorrentDownloader): + existing_downloader.start_download(url, data['save_path'], "") + else: + torrent_downloader = TorrentDownloader(torrent_session) + downloads[game_id] = torrent_downloader + torrent_downloader.start_download(url, data['save_path'], "") + else: + if existing_downloader and isinstance(existing_downloader, HttpDownloader): + existing_downloader.start_download(url, data['save_path'], data.get('header')) + else: + http_downloader = HttpDownloader() + downloads[game_id] = http_downloader + http_downloader.start_download(url, data['save_path'], data.get('header')) + + downloading_game_id = game_id + + elif action == 'pause': + downloader = downloads.get(game_id) + if downloader: + downloader.pause_download() + downloading_game_id = -1 + elif action == 'cancel': + downloader = downloads.get(game_id) + if downloader: + downloader.cancel_download() + elif action == 'resume_seeding': + torrent_downloader = TorrentDownloader(torrent_session, lt.torrent_flags.upload_mode) downloads[game_id] = torrent_downloader - torrent_downloader.start_download(url, data['save_path'], "") - else: - if existing_downloader and isinstance(existing_downloader, HttpDownloader): - existing_downloader.start_download(url, data['save_path'], data.get('header')) + torrent_downloader.start_download(data['url'], data['save_path'], "") + elif action == 'pause_seeding': + downloader = downloads.get(game_id) + if downloader: + downloader.cancel_download() else: - http_downloader = HttpDownloader() - downloads[game_id] = http_downloader - http_downloader.start_download(url, data['save_path'], data.get('header')) - - downloading_game_id = game_id + self.send_response(400) + self.end_headers() + self.wfile.write(json.dumps({"error": "Invalid action"}).encode('utf-8')) + return - elif action == 'pause': - downloader = downloads.get(game_id) - if downloader: - downloader.pause_download() - downloading_game_id = -1 - elif action == 'cancel': - downloader = downloads.get(game_id) - if downloader: - downloader.cancel_download() - elif action == 'resume_seeding': - torrent_downloader = TorrentDownloader(torrent_session, lt.torrent_flags.upload_mode) - downloads[game_id] = torrent_downloader - torrent_downloader.start_download(data['url'], data['save_path'], "") - elif action == 'pause_seeding': - downloader = downloads.get(game_id) - if downloader: - downloader.cancel_download() - - else: - return jsonify({"error": "Invalid action"}), 400 - - return "", 200 + self.send_response(200) + self.end_headers() if __name__ == "__main__": - app.run(host="0.0.0.0", port=int(http_port)) - \ No newline at end of file + server = HTTPServer(('0.0.0.0', http_port), RequestHandler) + print(f"Server running on port {http_port}") + server.serve_forever() diff --git a/requirements.txt b/requirements.txt index ffdfb59b..6cd9ce34 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,5 +4,4 @@ cx_Logging; sys_platform == 'win32' pywin32; sys_platform == 'win32' psutil Pillow -flask aria2p