Skip to content

Commit

Permalink
feat: adding aria2c
Browse files Browse the repository at this point in the history
  • Loading branch information
thegrannychaseroperation committed Nov 28, 2024
1 parent c6d4b65 commit d7e06d6
Show file tree
Hide file tree
Showing 11 changed files with 844 additions and 0 deletions.
Binary file added aria2/aria2c
Binary file not shown.
47 changes: 47 additions & 0 deletions python_rpc/http_downloader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import aria2p

class HttpDownloader:
def __init__(self):
self.download = None
self.aria2 = aria2p.API(
aria2p.Client(
host="http://localhost",
port=6800,
secret=""
)
)

def start_download(self, url: str, save_path: str, header: str):
if self.download:
self.aria2.resume([self.download])
else:
downloads = self.aria2.add(url, options={"header": header, "dir": save_path})
self.download = downloads[0]

def pause_download(self):
if self.download:
self.aria2.pause([self.download])

def cancel_download(self):
if self.download:
self.aria2.remove([self.download])
self.download = None

def get_download_status(self):
if self.download == None:
return None

download = self.aria2.get_download(self.download.gid)

response = {
'folderName': str(download.dir) + "/" + download.name,
'fileSize': download.total_length,
'progress': download.completed_length / download.total_length if download.total_length else 0,
'downloadSpeed': download.download_speed,
'numPeers': 0,
'numSeeds': 0,
'status': download.status,
'bytesDownloaded': download.completed_length,
}

return response
136 changes: 136 additions & 0 deletions python_rpc/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
from flask import Flask, request, jsonify
import sys, json, urllib.parse, 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]
rpc_password = sys.argv[3]

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)})

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

@app.route("/status", methods=["GET"])
def status():
auth_error = validate_rpc_password()
if auth_error:
return auth_error

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

status = torrent_downloader.get_seed_status()
return jsonify(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', 'username'])]
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')

print(data)

if action == 'start':
url = data.get('url')

existing_downloader = downloads.get(game_id)

if existing_downloader:
# This will resume the download
existing_downloader.start_download(url, data['save_path'], data.get('header'))
else:
if url.startswith('magnet'):
torrent_downloader = TorrentDownloader(torrent_session)
downloads[game_id] = torrent_downloader
torrent_downloader.start_download(url, data['save_path'], "")
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 == 'kill-torrent':
# torrent_downloader.abort_session()
# torrent_downloader = None
# elif action == 'pause-seeding':
# torrent_downloader.pause_seeding(game_id)
# elif action == 'resume-seeding':
# torrent_downloader.resume_seeding(game_id, data['url'], data['save_path'])
else:
return jsonify({"error": "Invalid action"}), 400

return "", 200

if __name__ == "__main__":
app.run(host="0.0.0.0", port=int(http_port))

30 changes: 30 additions & 0 deletions python_rpc/profile_image_processor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from PIL import Image
import os, uuid, tempfile

class ProfileImageProcessor:

@staticmethod
def get_parsed_image_data(image_path):
Image.MAX_IMAGE_PIXELS = 933120000

image = Image.open(image_path)

try:
image.seek(1)
except EOFError:
mime_type = image.get_format_mimetype()
return image_path, mime_type
else:
newUUID = str(uuid.uuid4())
new_image_path = os.path.join(tempfile.gettempdir(), newUUID) + ".webp"
image.save(new_image_path)

new_image = Image.open(new_image_path)
mime_type = new_image.get_format_mimetype()

return new_image_path, mime_type


@staticmethod
def process_image(image_path):
return ProfileImageProcessor.get_parsed_image_data(image_path)
20 changes: 20 additions & 0 deletions python_rpc/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from cx_Freeze import setup, Executable

# Dependencies are automatically detected, but it might need fine tuning.
build_exe_options = {
"packages": ["libtorrent"],
"build_exe": "hydra-python-rpc",
"include_msvcr": True
}

setup(
name="hydra-python-rpc",
version="0.1",
description="Hydra",
options={"build_exe": build_exe_options},
executables=[Executable(
"python_rpc/main.py",
target_name="hydra-python-rpc",
icon="build/icon.ico"
)]
)
Loading

0 comments on commit d7e06d6

Please sign in to comment.