fix: using python http server

This commit is contained in:
Chubby Granny Chaser 2025-01-18 01:58:42 +00:00
parent 8a30e946e3
commit 954037b826
No known key found for this signature in database
2 changed files with 139 additions and 133 deletions

View File

@ -1,29 +1,29 @@
from flask import Flask, request, jsonify from http.server import BaseHTTPRequestHandler, HTTPServer
import sys, json, urllib.parse, psutil import json
import urllib.parse
import sys
import psutil
from torrent_downloader import TorrentDownloader from torrent_downloader import TorrentDownloader
from http_downloader import HttpDownloader from http_downloader import HttpDownloader
from profile_image_processor import ProfileImageProcessor from profile_image_processor import ProfileImageProcessor
import libtorrent as lt import libtorrent as lt
app = Flask(__name__)
# Retrieve command line arguments # Retrieve command line arguments
torrent_port = sys.argv[1] torrent_port = sys.argv[1]
http_port = sys.argv[2] http_port = int(sys.argv[2])
rpc_password = sys.argv[3] rpc_password = sys.argv[3]
start_download_payload = sys.argv[4] start_download_payload = sys.argv[4]
start_seeding_payload = sys.argv[5] start_seeding_payload = sys.argv[5]
downloads = {} downloads = {}
# This can be streamed down from Node
downloading_game_id = -1 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: if start_download_payload:
initial_download = json.loads(urllib.parse.unquote(start_download_payload)) initial_download = json.loads(urllib.parse.unquote(start_download_payload))
downloading_game_id = initial_download['game_id'] downloading_game_id = initial_download['game_id']
if initial_download['url'].startswith('magnet'): if initial_download['url'].startswith('magnet'):
torrent_downloader = TorrentDownloader(torrent_session) torrent_downloader = TorrentDownloader(torrent_session)
downloads[initial_download['game_id']] = torrent_downloader downloads[initial_download['game_id']] = torrent_downloader
@ -49,135 +49,142 @@ if start_seeding_payload:
except Exception as e: except Exception as e:
print("Error starting seeding", e) print("Error starting seeding", e)
def validate_rpc_password(): class RequestHandler(BaseHTTPRequestHandler):
"""Middleware to validate RPC password.""" def validate_rpc_password(self):
header_password = request.headers.get('x-hydra-rpc-password') header_password = self.headers.get('x-hydra-rpc-password')
if header_password != rpc_password: if header_password != rpc_password:
return jsonify({"error": "Unauthorized"}), 401 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 do_GET(self):
def status(): if self.path == "/status":
auth_error = validate_rpc_password() if not self.validate_rpc_password():
if auth_error: return
return auth_error
downloader = downloads.get(downloading_game_id) downloader = downloads.get(downloading_game_id)
if downloader: if downloader:
status = downloads.get(downloading_game_id).get_download_status() status = downloader.get_download_status()
return jsonify(status), 200 self.send_response(200)
else: self.end_headers()
return jsonify(None) self.wfile.write(json.dumps(status).encode('utf-8'))
@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'], "")
else: 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 downloads[game_id] = torrent_downloader
torrent_downloader.start_download(url, data['save_path'], "") torrent_downloader.start_download(data['url'], data['save_path'], "")
else: elif action == 'pause_seeding':
if existing_downloader and isinstance(existing_downloader, HttpDownloader): downloader = downloads.get(game_id)
existing_downloader.start_download(url, data['save_path'], data.get('header')) if downloader:
downloader.cancel_download()
else: else:
http_downloader = HttpDownloader() self.send_response(400)
downloads[game_id] = http_downloader self.end_headers()
http_downloader.start_download(url, data['save_path'], data.get('header')) self.wfile.write(json.dumps({"error": "Invalid action"}).encode('utf-8'))
return
downloading_game_id = game_id
elif action == 'pause': self.send_response(200)
downloader = downloads.get(game_id) self.end_headers()
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
if __name__ == "__main__": if __name__ == "__main__":
app.run(host="0.0.0.0", port=int(http_port)) server = HTTPServer(('0.0.0.0', http_port), RequestHandler)
print(f"Server running on port {http_port}")
server.serve_forever()

View File

@ -4,5 +4,4 @@ cx_Logging; sys_platform == 'win32'
pywin32; sys_platform == 'win32' pywin32; sys_platform == 'win32'
psutil psutil
Pillow Pillow
flask
aria2p aria2p