From b2211bcdfd732880df7aca6d5fc9a2975916cb45 Mon Sep 17 00:00:00 2001
From: shamoon <4887959+shamoon@users.noreply.github.com>
Date: Mon, 6 Feb 2023 14:18:30 -0800
Subject: [PATCH] rewrite rutorrent proxy

---
 package.json                   |  1 -
 pnpm-lock.yaml                 | 47 -------------------
 src/widgets/rutorrent/proxy.js | 82 +++++++++++++++++++++++++++-------
 3 files changed, 66 insertions(+), 64 deletions(-)

diff --git a/package.json b/package.json
index 2dddf725..0238c6cd 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,6 @@
     "react-dom": "^18.2.0",
     "react-i18next": "^11.18.6",
     "react-icons": "^4.4.0",
-    "rutorrent-promise": "^2.0.0",
     "shvl": "^3.0.0",
     "swr": "^1.3.0",
     "tough-cookie": "^4.1.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index c2984e5d..e26fee84 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -33,7 +33,6 @@ specifiers:
   react-dom: ^18.2.0
   react-i18next: ^11.18.6
   react-icons: ^4.4.0
-  rutorrent-promise: ^2.0.0
   shvl: ^3.0.0
   swr: ^1.3.0
   tailwind-scrollbar: ^2.0.1
@@ -63,7 +62,6 @@ dependencies:
   react-dom: 18.2.0_react@18.2.0
   react-i18next: 11.18.6_ulhmqqxshznzmtuvahdi5nasbq
   react-icons: 4.4.0_react@18.2.0
-  rutorrent-promise: 2.0.0
   shvl: 3.0.0
   swr: 1.3.0_react@18.2.0
   tough-cookie: 4.1.2
@@ -1582,15 +1580,6 @@ packages:
       mime-types: 2.1.35
     dev: false
 
-  /form-data/3.0.1:
-    resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
-    engines: {node: '>= 6'}
-    dependencies:
-      asynckit: 0.4.0
-      combined-stream: 1.0.8
-      mime-types: 2.1.35
-    dev: false
-
   /fraction.js/4.2.0:
     resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
     dev: true
@@ -2299,18 +2288,6 @@ packages:
       - babel-plugin-macros
     dev: false
 
-  /node-fetch/2.6.7:
-    resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
-    engines: {node: 4.x || >=6.0.0}
-    peerDependencies:
-      encoding: ^0.1.0
-    peerDependenciesMeta:
-      encoding:
-        optional: true
-    dependencies:
-      whatwg-url: 5.0.0
-    dev: false
-
   /node-os-utils/1.3.7:
     resolution: {integrity: sha512-fvnX9tZbR7WfCG5BAy3yO/nCLyjVWD6MghEq0z5FDfN+ZXpLWNITBdbifxQkQ25ebr16G0N7eRWJisOcMEHG3Q==}
     dev: false
@@ -2836,15 +2813,6 @@ packages:
       queue-microtask: 1.2.3
     dev: true
 
-  /rutorrent-promise/2.0.0:
-    resolution: {integrity: sha512-ip6FxYM/BFxRgYSWr+2gZ0ao9LsJ1vJYWyFVnTkSmZrp4Cwa3CFpdxMi/5aZsUf1qve2CY9P4GLvrACx+PZ6yQ==}
-    dependencies:
-      form-data: 3.0.1
-      node-fetch: 2.6.7
-    transitivePeerDependencies:
-      - encoding
-    dev: false
-
   /safe-buffer/5.2.1:
     resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
     dev: false
@@ -3207,10 +3175,6 @@ packages:
       url-parse: 1.5.10
     dev: false
 
-  /tr46/0.0.3:
-    resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
-    dev: false
-
   /triple-beam/1.3.0:
     resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==}
     dev: false
@@ -3346,17 +3310,6 @@ packages:
     engines: {node: '>=0.10.0'}
     dev: false
 
-  /webidl-conversions/3.0.1:
-    resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
-    dev: false
-
-  /whatwg-url/5.0.0:
-    resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
-    dependencies:
-      tr46: 0.0.3
-      webidl-conversions: 3.0.1
-    dev: false
-
   /which-boxed-primitive/1.0.2:
     resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
     dependencies:
diff --git a/src/widgets/rutorrent/proxy.js b/src/widgets/rutorrent/proxy.js
index c7bb5d45..8d4ea5ea 100644
--- a/src/widgets/rutorrent/proxy.js
+++ b/src/widgets/rutorrent/proxy.js
@@ -1,6 +1,48 @@
-import RuTorrent from "rutorrent-promise";
-
 import getServiceWidget from "utils/config/service-helpers";
+import { httpProxy } from "utils/proxy/http";
+import widgets from "widgets/widgets";
+import { formatApiCall } from "utils/proxy/api-helpers";
+import createLogger from "utils/logger";
+
+const logger = createLogger("rutorrentProxyHandler");
+
+// from https://github.com/ctessier/node-rutorrent-promise/blob/next/utils.js
+const getTorrentInfo = (data) => ({
+  'd.is_open': data[0],
+  'd.is_hash_checking': data[1],
+  'd.is_hash_checked': data[2],
+  'd.get_state': data[3],
+  'd.get_name': data[4],
+  'd.get_size_bytes': data[5],
+  'd.get_completed_chunks': data[6],
+  'd.get_size_chunks': data[7],
+  'd.get_bytes_done': data[8],
+  'd.get_up_total': data[9],
+  'd.get_ratio': data[10],
+  'd.get_up_rate': data[11],
+  'd.get_down_rate': data[12],
+  'd.get_chunk_size': data[13],
+  'd.get_custom1': data[14],
+  'd.get_peers_accounted': data[15],
+  'd.get_peers_not_connected': data[16],
+  'd.get_peers_connected': data[17],
+  'd.get_peers_complete': data[18],
+  'd.get_left_bytes': data[19],
+  'd.get_priority': data[20],
+  'd.get_state_changed': data[21],
+  'd.get_skip_total': data[22],
+  'd.get_hashing': data[23],
+  'd.get_chunks_hashed': data[24],
+  'd.get_base_path': data[25],
+  'd.get_creation_date': data[26],
+  'd.get_tracker_focus': data[27],
+  'd.is_active': data[28],
+  'd.get_message': data[29],
+  'd.get_custom2': data[30],
+  'd.get_free_diskspace': data[31],
+  'd.is_private': data[32],
+  'd.is_multi_file': data[33],
+});
 
 export default async function rutorrentProxyHandler(req, res) {
   const { group, service } = req.query;
@@ -9,27 +51,35 @@ export default async function rutorrentProxyHandler(req, res) {
     const widget = await getServiceWidget(group, service);
 
     if (widget) {
-      const constructedUrl = new URL(widget.url);
+      const api = widgets?.[widget.type]?.api;
+      const url = new URL(formatApiCall(api, { ...widget }));
 
-      let rtPort = constructedUrl.port;
-      if (rtPort === '') {
-        rtPort = constructedUrl.protocol === "https:" ? 443 : 80;
+      const headers = {}
+      if (widget.username) {
+        headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`;
       }
 
-      const rutorrent = new RuTorrent({
-        host: constructedUrl.hostname,
-        port: rtPort,
-        path: constructedUrl.pathname,
-        ssl: constructedUrl.protocol === "https:",
-        username: widget.username,
-        password: widget.password,
+      const [status, , data] = await httpProxy(url, {
+        method: "POST",
+        headers,
+        body: 'mode=list'
       });
 
-      const data = await rutorrent.get(["d.get_down_rate", "d.get_up_rate", "d.get_state"]);
+      if (status !== 200) {
+        logger.error("HTTP Error %d calling %s", status, url.toString());
+        return res.status(status).json({error: {message: "HTTP Error", url, data}});
+      }
 
-      return res.status(200).send(data);
+      try {
+        const rawData = JSON.parse(data);
+        const parsedData = Object.keys(rawData.t).map((hashString) => getTorrentInfo(rawData.t[hashString]));
+  
+        return res.status(200).send(parsedData);
+      } catch (e) {
+        return res.status(500).json({error: {message: e?.toString() ?? 'Error parsing rutorrent data', url, data}});
+      }
     }
   }
 
-  return res.status(400).json({ error: "Invalid proxy service type" });
+  return res.status(500).json({ error: "Invalid proxy service type" });
 }