Skip to content

Commit

Permalink
适配新的 PBH 更改
Browse files Browse the repository at this point in the history
  • Loading branch information
Ghost-chu committed Aug 30, 2024
1 parent 87418c1 commit e092545
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 96 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ build/
.vscode/

### Mac OS ###
.DS_Store
.DS_Store
dependency-reduced-pom.xml
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
package com.ghostchu.peerbanhelper.downloaderplug.biglybt;

import com.biglybt.core.config.COConfigurationManager;
import com.biglybt.core.networkmanager.Transport;
import com.biglybt.core.peer.impl.PEPeerTransport;
import com.biglybt.pif.PluginException;
import com.biglybt.pif.PluginInterface;
import com.biglybt.pif.UnloadablePlugin;
import com.biglybt.pif.dht.mainline.MainlineDHTManager;
import com.biglybt.pif.download.Download;
import com.biglybt.pif.download.DownloadException;
import com.biglybt.pif.download.DownloadStats;
import com.biglybt.pif.ipfilter.IPBanned;
import com.biglybt.pif.ipfilter.IPFilter;
import com.biglybt.pif.ipfilter.IPFilterException;
import com.biglybt.pif.peers.*;
import com.biglybt.pif.tag.Tag;
import com.biglybt.pif.torrent.Torrent;
Expand All @@ -28,12 +28,17 @@
import io.javalin.Javalin;
import io.javalin.http.Context;
import io.javalin.http.HttpStatus;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

public class Plugin implements UnloadablePlugin {
public static final Gson GSON = new Gson();
private static final String PBH_IDENTIFIER = "<PeerBanHelper>";
private static final Lock BAN_LIST_OPERATION_LOCK = new ReentrantLock();
private PluginInterface pluginInterface;
private IntParameter listenPortParam;
private StringParameter accessKeyParam;
Expand All @@ -58,6 +63,70 @@ private static TorrentRecord getTorrentRecord(Torrent torrent) {
);
}

public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte aByte : bytes) {
String hex = Integer.toHexString(aByte & 0xFF);
if (hex.length() < 2) {
sb.append(0);
}
sb.append(hex);
}
return sb.toString();
}

/**
* hex字符串转byte数组
* @param inHex 待转换的Hex字符串
* @return 转换后的byte数组结果
*/
public static byte[] hexToByteArray(String inHex) {
int hexlen = inHex.length();
byte[] result;
if (hexlen % 2 == 1) {
//奇数
hexlen++;
result = new byte[(hexlen / 2)];
inHex = "0" + inHex;
} else {
//偶数
result = new byte[(hexlen / 2)];
}
int j = 0;
for (int i = 0; i < hexlen; i += 2) {
result[j] = hexToByte(inHex.substring(i, i + 2));
j++;
}
return result;
}

/**
* Hex字符串转byte
* @param inHex 待转换的Hex字符串
* @return 转换后的byte
*/
public static byte hexToByte(String inHex) {
return (byte) Integer.parseInt(inHex, 16);
}

public void runIPFilterOperation(Runnable runnable) throws IPFilterException {
BAN_LIST_OPERATION_LOCK.lock();
try {
var originalPersistentSetting = COConfigurationManager.getBooleanParameter("Ip Filter Banning Persistent" );
try {
COConfigurationManager.setParameter("Ip Filter Banning Persistent", false);
runnable.run();
}finally {
COConfigurationManager.setParameter("Ip Filter Banning Persistent", originalPersistentSetting);
if(originalPersistentSetting){
this.pluginInterface.getIPFilter().save();
}
}
} finally {
BAN_LIST_OPERATION_LOCK.unlock();
}
}

@Override
public void unload() throws PluginException {
if (webContainer != null) {
Expand Down Expand Up @@ -95,7 +164,8 @@ private void reloadPlugin() {
}

private void initEndpoints(Javalin javalin) {
javalin .get("/metadata", this::handleMetadata)
javalin.get("/metadata", this::handleMetadata)
.get("/statistics", this::handleStatistics)
.get("/downloads", this::handleDownloads)
.get("/download/{infoHash}", this::handleDownload)
.get("/download/{infoHash}/peers", this::handlePeers)
Expand All @@ -105,6 +175,29 @@ private void initEndpoints(Javalin javalin) {
.delete("/bans", this::handleBatchUnban);
}

private void handleStatistics(Context context) {
var stats = pluginInterface.getDownloadManager().getStats();
context.json(
new StatisticsRecord(
stats.getOverallDataBytesReceived(),
stats.getOverallDataBytesSent(),
stats.getSessionUptimeSeconds(),
stats.getDataReceiveRate(),
stats.getProtocolReceiveRate(),
stats.getDataAndProtocolReceiveRate(),
stats.getDataSendRate(),
stats.getProtocolSendRate(),
stats.getDataAndProtocolSendRate(),
stats.getDataBytesReceived(),
stats.getProtocolBytesReceived(),
stats.getDataBytesSent(),
stats.getProtocolBytesSent(),
stats.getSmoothedReceiveRate(),
stats.getSmoothedSendRate()
)
);
}

private void handleMetadata(Context context) {
MetadataCallbackBean callbackBean = new MetadataCallbackBean(
pluginInterface.getPluginVersion(),
Expand All @@ -114,31 +207,33 @@ private void handleMetadata(Context context) {
context.json(callbackBean);
}

private void handleBanListApplied(Context context) {
private void handleBanListApplied(Context context) throws IPFilterException {
BanBean banBean = context.bodyAsClass(BanBean.class);
IPFilter ipFilter = pluginInterface.getIPFilter();
int success = 0;
int failed = 0;
for (String s : banBean.getIps()) {
try {
ipFilter.ban(s, PBH_IDENTIFIER);
success++;
} catch (Exception e) {
e.printStackTrace();
failed++;
AtomicInteger success = new AtomicInteger();
AtomicInteger failed = new AtomicInteger();
runIPFilterOperation(()->{
for (String s : banBean.getIps()) {
try {
ipFilter.ban(s, PBH_IDENTIFIER);
success.incrementAndGet();
} catch (Exception e) {
e.printStackTrace();
failed.incrementAndGet();
}
}
}
});
cleanupPeers(banBean.getIps());
context.status(HttpStatus.OK);
context.json(new BatchOperationCallbackBean(success, failed));
context.json(new BatchOperationCallbackBean(success.get(), failed.get()));
}

private void handleDownloads(Context ctx) {
List<DownloadRecord> records = new ArrayList<>();
List<Integer> filter = ctx.queryParams("filter").stream().map(Integer::parseInt).collect(Collectors.toList());
for (Download download : pluginInterface.getDownloadManager().getDownloads()) {
boolean shouldAddToResultSet = filter.isEmpty() || filter.contains(download.getState());
if(shouldAddToResultSet){
if (shouldAddToResultSet) {
records.add(getDownloadRecord(download));
}
}
Expand All @@ -161,21 +256,23 @@ public void handleBans(Context ctx) {
ctx.json(banned);
}

private void handleBatchUnban(Context ctx) {
private void handleBatchUnban(Context ctx) throws IPFilterException {
UnBanBean banBean = ctx.bodyAsClass(UnBanBean.class);
int unbanned = 0;
int failed = 0;
for (String ip : banBean.getIps()) {
try {
pluginInterface.getIPFilter().unban(ip);
unbanned++;
} catch (Exception e) {
e.printStackTrace();
failed++;
AtomicInteger unbanned = new AtomicInteger();
AtomicInteger failed = new AtomicInteger();
runIPFilterOperation(()->{
for (String ip : banBean.getIps()) {
try {
pluginInterface.getIPFilter().unban(ip);
unbanned.incrementAndGet();
} catch (Exception e) {
e.printStackTrace();
failed.incrementAndGet();
}
}
}
});
ctx.status(HttpStatus.OK);
ctx.json(new BatchOperationCallbackBean(unbanned, failed));
ctx.json(new BatchOperationCallbackBean(unbanned.get(), failed.get()));
}

public void handleDownload(Context ctx) {
Expand Down Expand Up @@ -209,28 +306,30 @@ public void handlePeers(Context ctx) {
}
}

public void handleBanListReplacement(Context ctx) {
public void handleBanListReplacement(Context ctx) throws IPFilterException {
BanListReplacementBean replacementBean = ctx.bodyAsClass(BanListReplacementBean.class);
IPFilter ipFilter = pluginInterface.getIPFilter();
for (IPBanned blockedIP : ipFilter.getBannedIPs()) {
if (PBH_IDENTIFIER.equals(blockedIP.getBannedTorrentName()) || replacementBean.isIncludeNonPBHEntries()) {
ipFilter.unban(blockedIP.getBannedIP());
AtomicInteger success = new AtomicInteger();
AtomicInteger failed = new AtomicInteger();
runIPFilterOperation(()->{
IPFilter ipFilter = pluginInterface.getIPFilter();
for (IPBanned blockedIP : ipFilter.getBannedIPs()) {
if (PBH_IDENTIFIER.equals(blockedIP.getBannedTorrentName()) || replacementBean.isIncludeNonPBHEntries()) {
ipFilter.unban(blockedIP.getBannedIP());
}
}
}
int success = 0;
int failed = 0;
for (String s : replacementBean.getReplaceWith()) {
try {
ipFilter.ban(s, PBH_IDENTIFIER);
success++;
} catch (Exception e) {
e.printStackTrace();
failed++;
for (String s : replacementBean.getReplaceWith()) {
try {
ipFilter.ban(s, PBH_IDENTIFIER);
success.incrementAndGet();
} catch (Exception e) {
e.printStackTrace();
failed.incrementAndGet();
}
}
}
});
cleanupPeers(replacementBean.getReplaceWith());
ctx.status(HttpStatus.OK);
ctx.json(new BatchOperationCallbackBean(success, failed));
ctx.json(new BatchOperationCallbackBean(success.get(), failed.get()));
}

private void cleanupPeers(List<String> peers) {
Expand Down Expand Up @@ -297,7 +396,7 @@ private DownloadRecord getDownloadRecord(Download download) {
download.isComplete(),
download.isChecking(),
download.isMoving(),
download.getDownloadPeerId() == null ? null :bytesToHex(download.getDownloadPeerId()).toLowerCase(Locale.ROOT),
download.getDownloadPeerId() == null ? null : bytesToHex(download.getDownloadPeerId()).toLowerCase(Locale.ROOT),
download.isRemoved());
}

Expand Down Expand Up @@ -342,7 +441,7 @@ private PeerDescriptorRecord getDescriptorRecord(PeerDescriptor peerDescriptor)
private PeerRecord getPeerRecord(Peer peer) {
if (peer == null) return null;
String client = peer.getClient();
if(peer instanceof PeerImpl){
if (peer instanceof PeerImpl) {
client = ((PeerImpl) peer).getDelegate().getClientNameFromExtensionHandshake();
}
return new PeerRecord(
Expand Down Expand Up @@ -390,52 +489,4 @@ private PeerStatsRecord getPeerStatsRecord(PeerStats stats) {
stats.getOverallBytesRemaining()
);
}


public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte aByte : bytes) {
String hex = Integer.toHexString(aByte & 0xFF);
if (hex.length() < 2) {
sb.append(0);
}
sb.append(hex);
}
return sb.toString();
}

/**
* hex字符串转byte数组
* @param inHex 待转换的Hex字符串
* @return 转换后的byte数组结果
*/
public static byte[] hexToByteArray(String inHex) {
int hexlen = inHex.length();
byte[] result;
if (hexlen % 2 == 1) {
//奇数
hexlen++;
result = new byte[(hexlen / 2)];
inHex = "0" + inHex;
} else {
//偶数
result = new byte[(hexlen / 2)];
}
int j = 0;
for (int i = 0; i < hexlen; i += 2) {
result[j] = hexToByte(inHex.substring(i, i + 2));
j++;
}
return result;
}

/**
* Hex字符串转byte
* @param inHex 待转换的Hex字符串
* @return 转换后的byte
*/
public static byte hexToByte(String inHex) {
return (byte) Integer.parseInt(inHex, 16);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.ghostchu.peerbanhelper.downloaderplug.biglybt.network.wrapper;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@Data
@NoArgsConstructor
public class StatisticsRecord {
private Long overallDataBytesReceived;
private Long overallDataBytesSent;
private Long sessionUptimeSeconds;
private Integer dataReceiveRate;
private Integer protocolReceiveRate;
private Integer dataAndProtocolReceiveRate;
private Integer dataSendRate;
private Integer protocolSendRate;
private Integer dataAndProtocolSendRate;
private Long dataBytesReceived;
private Long protocolBytesReceived;
private Long dataBytesSent;
private Long protocolBytesSent;
private Long smoothedReceiveRate;
private Long smoothedSendRate;
}
Loading

0 comments on commit e092545

Please sign in to comment.