diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/Downloader.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/Downloader.java index 43582c0455..987dedb3e5 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/downloader/Downloader.java +++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/Downloader.java @@ -170,4 +170,6 @@ default void runScheduleTasks() { List getFeatureFlags(); int getMaxConcurrentPeerRequestSlots(); + + void throttlePeer(Torrent torrent, Peer peer, long uploadRate, long downloadRate) throws UnsupportedOperationException; } diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/BiglyBT.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/BiglyBT.java index be89b71ba3..3aa555cb36 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/BiglyBT.java +++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/BiglyBT.java @@ -10,6 +10,7 @@ import com.ghostchu.peerbanhelper.downloader.impl.biglybt.network.ConnectorData; import com.ghostchu.peerbanhelper.downloader.impl.biglybt.network.bean.clientbound.BanBean; import com.ghostchu.peerbanhelper.downloader.impl.biglybt.network.bean.clientbound.BanListReplacementBean; +import com.ghostchu.peerbanhelper.downloader.impl.biglybt.network.bean.clientbound.PeerThrottlingBean; import com.ghostchu.peerbanhelper.downloader.impl.biglybt.network.bean.serverbound.MetadataCallbackBean; import com.ghostchu.peerbanhelper.downloader.impl.biglybt.network.wrapper.DownloadRecord; import com.ghostchu.peerbanhelper.downloader.impl.biglybt.network.wrapper.PeerManagerRecord; @@ -25,6 +26,7 @@ import com.ghostchu.peerbanhelper.torrent.TrackerImpl; import com.ghostchu.peerbanhelper.util.ByteUtil; import com.ghostchu.peerbanhelper.util.HTTPUtil; +import com.ghostchu.peerbanhelper.util.UrlEncoderDecoder; import com.ghostchu.peerbanhelper.util.json.JsonUtil; import com.ghostchu.peerbanhelper.wrapper.BanMetadata; import com.ghostchu.peerbanhelper.wrapper.PeerAddress; @@ -97,7 +99,33 @@ public static BiglyBT loadFromConfig(String name, ConfigurationSection section, @Override public List getFeatureFlags() { - return List.of(DownloaderFeatureFlag.READ_PEER_PROTOCOLS, DownloaderFeatureFlag.UNBAN_IP, DownloaderFeatureFlag.THROTTLING); + List flags = new ArrayList<>(); + flags.add(DownloaderFeatureFlag.READ_PEER_PROTOCOLS); + flags.add(DownloaderFeatureFlag.UNBAN_IP); + if (semver.isGreaterThanOrEqualTo("1.3.0")) { + flags.add(DownloaderFeatureFlag.THROTTLING); + } + return flags; + } + + @Override + public void throttlePeer(Torrent torrent, Peer peer, long uploadRate, long downloadRate) throws UnsupportedOperationException { + if (!getFeatureFlags().contains(DownloaderFeatureFlag.THROTTLING)) { + throw new UnsupportedOperationException("BiglyBT-Adapter version is lower than 1.3.0, throttling is not supported."); + } + PeerThrottlingBean bean = new PeerThrottlingBean((int) uploadRate, (int) downloadRate); + HttpResponse resp; + try { + var urlIp = UrlEncoderDecoder.encodeToLegalPath(peer.getRawIp()); + resp = httpClient.send(MutableRequest.POST(apiEndpoint + "/download/" + torrent.getHash() + "/peer/" + urlIp + "/throttling", + HttpRequest.BodyPublishers.ofString(JsonUtil.getGson().toJson(bean), StandardCharsets.UTF_8)), + HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)); + } catch (Exception e) { + throw new IllegalStateException(e); + } + if (resp.statusCode() != 200) { + throw new IllegalStateException(tlUI(Lang.DOWNLOADER_BIGLYBT_THROTTLE_FAILED, getName(), resp.statusCode(), resp.body())); + } } @Override diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/network/bean/clientbound/PeerThrottlingBean.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/network/bean/clientbound/PeerThrottlingBean.java new file mode 100644 index 0000000000..01b226c906 --- /dev/null +++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/biglybt/network/bean/clientbound/PeerThrottlingBean.java @@ -0,0 +1,13 @@ +package com.ghostchu.peerbanhelper.downloader.impl.biglybt.network.bean.clientbound; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@AllArgsConstructor +@NoArgsConstructor +@Data +public class PeerThrottlingBean { + private int uploadRate; + private int downloadRate; +} diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/bitcomet/BitComet.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/bitcomet/BitComet.java index b3ed06f63a..be96acd7ca 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/bitcomet/BitComet.java +++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/bitcomet/BitComet.java @@ -491,6 +491,11 @@ public int getMaxConcurrentPeerRequestSlots() { return 4; } + @Override + public void throttlePeer(Torrent torrent, Peer peer, long uploadRate, long downloadRate) throws UnsupportedOperationException { + throw new UnsupportedOperationException("BitComet does not support throttling peers"); + } + @NoArgsConstructor @Data public static class Config { diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/deluge/Deluge.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/deluge/Deluge.java index 70542f9242..6ea14c1851 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/deluge/Deluge.java +++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/deluge/Deluge.java @@ -219,6 +219,11 @@ public DownloaderStatistics getStatistics() { return new DownloaderStatistics(0,0); } + @Override + public void throttlePeer(Torrent torrent, Peer peer, long uploadRate, long downloadRate) throws UnsupportedOperationException { + throw new UnsupportedOperationException("Deluge does not support throttling peers"); + } + @Override public void close() { diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/AbstractQbittorrent.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/AbstractQbittorrent.java index b0ce648874..937846b24e 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/AbstractQbittorrent.java +++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/qbittorrent/AbstractQbittorrent.java @@ -403,6 +403,11 @@ public List getPeers(Torrent torrent) { return peersList; } + @Override + public void throttlePeer(Torrent torrent, Peer peer, long uploadRate, long downloadRate) throws UnsupportedOperationException { + throw new UnsupportedOperationException("qBittorrent does not support throttling peers"); + } + protected void setBanListIncrement(Collection added) { Map banTasks = new HashMap<>(); added.forEach(p -> { diff --git a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/transmission/Transmission.java b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/transmission/Transmission.java index faecffe7d1..2ff7e2fc29 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/transmission/Transmission.java +++ b/src/main/java/com/ghostchu/peerbanhelper/downloader/impl/transmission/Transmission.java @@ -205,6 +205,11 @@ public DownloaderStatistics getStatistics() { return new DownloaderStatistics(stats.getCumulativeStats().getUploadedBytes(), stats.getCumulativeStats().getDownloadedBytes()); } + @Override + public void throttlePeer(Torrent torrent, Peer peer, long uploadRate, long downloadRate) throws UnsupportedOperationException { + throw new UnsupportedOperationException("Transmission does not support throttling peer"); + } + @Override public void relaunchTorrentIfNeeded(Collection torrents) { relaunchTorrents(torrents.stream() diff --git a/src/main/java/com/ghostchu/peerbanhelper/text/Lang.java b/src/main/java/com/ghostchu/peerbanhelper/text/Lang.java index 4f265d6cc2..2d71bef7b1 100644 --- a/src/main/java/com/ghostchu/peerbanhelper/text/Lang.java +++ b/src/main/java/com/ghostchu/peerbanhelper/text/Lang.java @@ -506,7 +506,7 @@ public enum Lang { LAB_EXPERIMENT_FILL_MISSING_DATA_IN_TRAFFIC_SUMMARY_DESCRIPTION, GUI_TABBED_WEBUI, JCEF_BROWSER_UNSUPPORTED_PLATFORM, - JCEF_BROWSER_UNSUPPORTED_EXCEPTION, JCEF_DOWNLOAD_TITLE, JCEF_DOWNLOAD_DESCRIPTION, GUI_COMMON_CANCEL, JCEF_DOWNLOAD_UNZIP_DESCRIPTION, IPDB_DOWNLOAD_TITLE, IPDB_DOWNLOAD_DESCRIPTION, PBH_PLUS_THANKS_FOR_DONATION_GUI_TITLE, LAB_EXPERIMENT_MAC_FLATLAF_THEME_TITLE, LAB_EXPERIMENT_MAC_FLATLAF_THEME_DESCRIPTION, GUI_TITLE_DEBUG, DOWNLOADER_DOCKER_INCORRECT_NETWORK_DETECTED_TITLE, DOWNLOADER_DOCKER_INCORRECT_NETWORK_DETECTED_DESCRIPTION, ABOUT_VIEW_CREDIT, INCOMPATIBLE_BITNESS_TITLE, INCOMPATIBLE_BITNESS_DESCRIPTION, TITLE_INCOMPATIBLE_PLATFORM, INCOMPATIBLE_BITNESS_LOG, LAB_EXPERIMENT_TRANSACTION_BATCH_BAN_HISTORY_WRITE_TITLE, LAB_EXPERIMENT_TRANSACTION_BATCH_BAN_HISTORY_WRITE_DESCRIPTION, TITLE_APP_V_CONTAINER; + JCEF_BROWSER_UNSUPPORTED_EXCEPTION, JCEF_DOWNLOAD_TITLE, JCEF_DOWNLOAD_DESCRIPTION, GUI_COMMON_CANCEL, JCEF_DOWNLOAD_UNZIP_DESCRIPTION, IPDB_DOWNLOAD_TITLE, IPDB_DOWNLOAD_DESCRIPTION, PBH_PLUS_THANKS_FOR_DONATION_GUI_TITLE, LAB_EXPERIMENT_MAC_FLATLAF_THEME_TITLE, LAB_EXPERIMENT_MAC_FLATLAF_THEME_DESCRIPTION, GUI_TITLE_DEBUG, DOWNLOADER_DOCKER_INCORRECT_NETWORK_DETECTED_TITLE, DOWNLOADER_DOCKER_INCORRECT_NETWORK_DETECTED_DESCRIPTION, ABOUT_VIEW_CREDIT, INCOMPATIBLE_BITNESS_TITLE, INCOMPATIBLE_BITNESS_DESCRIPTION, TITLE_INCOMPATIBLE_PLATFORM, INCOMPATIBLE_BITNESS_LOG, LAB_EXPERIMENT_TRANSACTION_BATCH_BAN_HISTORY_WRITE_TITLE, LAB_EXPERIMENT_TRANSACTION_BATCH_BAN_HISTORY_WRITE_DESCRIPTION, TITLE_APP_V_CONTAINER, DOWNLOADER_BIGLYBT_THROTTLE_FAILED; public String getKey() { return name(); diff --git a/src/main/resources/lang/en-us/messages.yml b/src/main/resources/lang/en-us/messages.yml index ab1c27144b..1e23edea41 100644 --- a/src/main/resources/lang/en-us/messages.yml +++ b/src/main/resources/lang/en-us/messages.yml @@ -593,4 +593,5 @@ DOWNLOADER_DOCKER_INCORRECT_NETWORK_DETECTED_DESCRIPTION: | For assistance, please join the PeerBanHelper community. **This prompt will only appear once per downloader.** LAB_EXPERIMENT_TRANSACTION_BATCH_BAN_HISTORY_WRITE_TITLE: "Enable transaction batch write ban history" LAB_EXPERIMENT_TRANSACTION_BATCH_BAN_HISTORY_WRITE_DESCRIPTION: "Use transactions to batch write to the database when recording ban history to improve performance and reduce random disk I/O operations." -TITLE_APP_V_CONTAINER: "📦App-V" \ No newline at end of file +TITLE_APP_V_CONTAINER: "📦App-V" +DOWNLOADER_BIGLYBT_THROTTLE_FAILED: "Failed to set Peer throttle property for downloader {}, remote API call failed: {} - {}" \ No newline at end of file diff --git a/src/main/resources/lang/messages_fallback.yml b/src/main/resources/lang/messages_fallback.yml index 4e377cba97..ba0fbb5c8d 100644 --- a/src/main/resources/lang/messages_fallback.yml +++ b/src/main/resources/lang/messages_fallback.yml @@ -599,4 +599,5 @@ INCOMPATIBLE_BITNESS_LOG: "在 32 位操作系统/JVM 上运行 PeerBanHelper TITLE_INCOMPATIBLE_PLATFORM: "⚠不受支持的平台" LAB_EXPERIMENT_TRANSACTION_BATCH_BAN_HISTORY_WRITE_TITLE: "启用事务批量写入封禁历史记录" LAB_EXPERIMENT_TRANSACTION_BATCH_BAN_HISTORY_WRITE_DESCRIPTION: "在记录封禁历史记录时使用事务以批量写入数据库以提高性能和减少随机磁盘 I/O 操作。" -TITLE_APP_V_CONTAINER: "📦App-V" \ No newline at end of file +TITLE_APP_V_CONTAINER: "📦App-V" +DOWNLOADER_BIGLYBT_THROTTLE_FAILED: "无法设置下载器 {} 的 Peer 节流属性,远程 API 调用发生错误: {} - {}" \ No newline at end of file diff --git a/src/main/resources/lang/zh-cn/messages.yml b/src/main/resources/lang/zh-cn/messages.yml index 4c589000c8..153e3231c8 100644 --- a/src/main/resources/lang/zh-cn/messages.yml +++ b/src/main/resources/lang/zh-cn/messages.yml @@ -591,4 +591,5 @@ DOWNLOADER_DOCKER_INCORRECT_NETWORK_DETECTED_DESCRIPTION: | ABOUT_VIEW_CREDIT: "开发人员与社区贡献者..." LAB_EXPERIMENT_TRANSACTION_BATCH_BAN_HISTORY_WRITE_TITLE: "启用事务批量写入封禁历史记录" LAB_EXPERIMENT_TRANSACTION_BATCH_BAN_HISTORY_WRITE_DESCRIPTION: "在记录封禁历史记录时使用事务以批量写入数据库以提高性能和减少随机磁盘 I/O 操作。" -TITLE_APP_V_CONTAINER: "📦App-V" \ No newline at end of file +TITLE_APP_V_CONTAINER: "📦App-V" +DOWNLOADER_BIGLYBT_THROTTLE_FAILED: "无法设置下载器 {} 的 Peer 节流属性,远程 API 调用发生错误: {} - {}" \ No newline at end of file